Skip to content

Commit 8249f39

Browse files
committed
Implement the new indexerLedgerForEval interface in go-algorand.
1 parent 9053c11 commit 8249f39

File tree

5 files changed

+345
-257
lines changed

5 files changed

+345
-257
lines changed

idb/postgres/internal/ledger_for_evaluator/ledger_for_evaluator.go

Lines changed: 81 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@ package ledgerforevaluator
22

33
import (
44
"context"
5-
"errors"
65
"fmt"
76

8-
"github.com/algorand/go-algorand/config"
9-
"github.com/algorand/go-algorand/crypto"
107
"github.com/algorand/go-algorand/data/basics"
118
"github.com/algorand/go-algorand/data/bookkeeping"
129
"github.com/algorand/go-algorand/data/transactions"
@@ -44,26 +41,24 @@ var statements = map[string]string{
4441
"WHERE addr = $1 AND NOT deleted",
4542
}
4643

47-
// LedgerForEvaluator implements the ledgerForEvaluator interface from
44+
// LedgerForEvaluator implements the indexerLedgerForEval interface from
4845
// go-algorand ledger/eval.go and is used for accounting.
4946
type LedgerForEvaluator struct {
50-
tx pgx.Tx
51-
genesisHash crypto.Digest
47+
tx pgx.Tx
5248
// Indexer currently does not store the balances of special account, but
5349
// go-algorand's eval checks that they satisfy the minimum balance. We thus return
5450
// a fake amount.
5551
// TODO: remove.
5652
specialAddresses transactions.SpecialAddresses
57-
// Value is nil if account was looked up but not found.
58-
preloadedAccountData map[basics.Address]*basics.AccountData
53+
latestRound basics.Round
5954
}
6055

6156
// MakeLedgerForEvaluator creates a LedgerForEvaluator object.
62-
func MakeLedgerForEvaluator(tx pgx.Tx, genesisHash crypto.Digest, specialAddresses transactions.SpecialAddresses) (LedgerForEvaluator, error) {
57+
func MakeLedgerForEvaluator(tx pgx.Tx, specialAddresses transactions.SpecialAddresses, latestRound basics.Round) (LedgerForEvaluator, error) {
6358
l := LedgerForEvaluator{
6459
tx: tx,
65-
genesisHash: genesisHash,
6660
specialAddresses: specialAddresses,
61+
latestRound: latestRound,
6762
}
6863

6964
for name, query := range statements {
@@ -84,9 +79,9 @@ func (l *LedgerForEvaluator) Close() {
8479
}
8580
}
8681

87-
// BlockHdr is part of go-algorand's ledgerForEvaluator interface.
88-
func (l LedgerForEvaluator) BlockHdr(round basics.Round) (bookkeeping.BlockHeader, error) {
89-
row := l.tx.QueryRow(context.Background(), blockHeaderStmtName, uint64(round))
82+
// LatestBlockHdr is part of go-algorand's indexerLedgerForEval interface.
83+
func (l LedgerForEvaluator) LatestBlockHdr() (bookkeeping.BlockHeader, error) {
84+
row := l.tx.QueryRow(context.Background(), blockHeaderStmtName, uint64(l.latestRound))
9085

9186
var header []byte
9287
err := row.Scan(&header)
@@ -102,12 +97,6 @@ func (l LedgerForEvaluator) BlockHdr(round basics.Round) (bookkeeping.BlockHeade
10297
return res, nil
10398
}
10499

105-
// CheckDup is part of go-algorand's ledgerForEvaluator interface.
106-
func (l LedgerForEvaluator) CheckDup(config.ConsensusParams, basics.Round, basics.Round, basics.Round, transactions.Txid, ledger.TxLease) error {
107-
// This function is not used by evaluator.
108-
return errors.New("CheckDup() not implemented")
109-
}
110-
111100
func (l *LedgerForEvaluator) isSpecialAddress(address basics.Address) bool {
112101
return (address == l.specialAddresses.FeeSink) ||
113102
(address == l.specialAddresses.RewardsPool)
@@ -252,8 +241,8 @@ func (l *LedgerForEvaluator) parseAccountAppTable(rows pgx.Rows) (map[basics.App
252241
return res, nil
253242
}
254243

255-
// Load rows from the account table for the given addresses. nil is stored for those
256-
// accounts that were not found. Uses batching.
244+
// Load rows from the account table for the given addresses except the special accounts.
245+
// nil is stored for those accounts that were not found. Uses batching.
257246
func (l *LedgerForEvaluator) loadAccountTable(addresses map[basics.Address]struct{}) (map[basics.Address]*basics.AccountData, error) {
258247
addressesArr := make([]basics.Address, 0, len(addresses))
259248
for address := range addresses {
@@ -375,9 +364,8 @@ func (l *LedgerForEvaluator) loadCreatables(accountDataMap *map[basics.Address]*
375364
return nil
376365
}
377366

378-
// Return a map with all accounts for the given addresses, with nil for those accounts
379-
// that do not exist.
380-
func (l *LedgerForEvaluator) loadAccounts(addresses map[basics.Address]struct{}) (map[basics.Address]*basics.AccountData, error) {
367+
// LookupWithoutRewards is part of go-algorand's indexerLedgerForEval interface.
368+
func (l LedgerForEvaluator) LookupWithoutRewards(addresses map[basics.Address]struct{}) (map[basics.Address]*basics.AccountData, error) {
381369
res, err := l.loadAccountTable(addresses)
382370
if err != nil {
383371
return nil, fmt.Errorf("loadAccounts() err: %w", err)
@@ -388,96 +376,101 @@ func (l *LedgerForEvaluator) loadAccounts(addresses map[basics.Address]struct{})
388376
return nil, fmt.Errorf("loadAccounts() err: %w", err)
389377
}
390378

379+
// Add special accounts if needed.
380+
for address := range addresses {
381+
if l.isSpecialAddress(address) {
382+
// The balance of a special address must pass the minimum balance check in
383+
// go-algorand's evaluator, so return a sufficiently large balance.
384+
var balance uint64 = 1000 * 1000 * 1000 * 1000 * 1000
385+
accountData := new(basics.AccountData)
386+
*accountData = basics.AccountData{
387+
MicroAlgos: basics.MicroAlgos{Raw: balance},
388+
}
389+
res[address] = accountData
390+
}
391+
}
392+
391393
return res, nil
392394
}
393395

394-
// PreloadAccounts loads the account data for the given addresses and stores them
395-
// in the internal cache.
396-
func (l *LedgerForEvaluator) PreloadAccounts(addresses map[basics.Address]struct{}) error {
397-
accountData, err := l.loadAccounts(addresses)
396+
func (l *LedgerForEvaluator) parseAddress(row pgx.Row) (basics.Address, bool /*exists*/, error) {
397+
var buf []byte
398+
err := row.Scan(&buf)
399+
if err == pgx.ErrNoRows {
400+
return basics.Address{}, false, nil
401+
}
398402
if err != nil {
399-
return err
403+
return basics.Address{}, false, fmt.Errorf("parseAddress() err: %w", err)
400404
}
401405

402-
l.preloadedAccountData = accountData
403-
return nil
406+
var address basics.Address
407+
copy(address[:], buf)
408+
409+
return address, true, nil
404410
}
405411

406-
// LookupWithoutRewards is part of go-algorand's ledgerForEvaluator interface.
407-
func (l LedgerForEvaluator) LookupWithoutRewards(round basics.Round, address basics.Address) (basics.AccountData, basics.Round, error) {
408-
// The balance of a special address must pass the minimum balance check in
409-
// go-algorand's evaluator, so return a sufficiently large balance.
410-
if l.isSpecialAddress(address) {
411-
var balance uint64 = 1000 * 1000 * 1000 * 1000 * 1000
412-
accountData := basics.AccountData{
413-
MicroAlgos: basics.MicroAlgos{Raw: balance},
414-
}
415-
return accountData, round, nil
412+
// GetAssetCreator is part of go-algorand's indexerLedgerForEval interface.
413+
func (l LedgerForEvaluator) GetAssetCreator(indices map[basics.AssetIndex]struct{}) (map[basics.AssetIndex]ledger.FoundAddress, error) {
414+
indicesArr := make([]basics.AssetIndex, 0, len(indices))
415+
for index := range indices {
416+
indicesArr = append(indicesArr, index)
416417
}
417418

418-
if accountData, ok := l.preloadedAccountData[address]; ok {
419-
if accountData == nil {
420-
return basics.AccountData{}, round, nil
421-
}
422-
return *accountData, round, nil
419+
var batch pgx.Batch
420+
for _, index := range indicesArr {
421+
batch.Queue(assetCreatorStmtName, uint64(index))
423422
}
424423

425-
// Account was not preloaded.
426-
accountDataMap, err := l.loadAccounts(map[basics.Address]struct{}{address: {}})
427-
if err != nil {
428-
return basics.AccountData{}, basics.Round(0), err
429-
}
430-
accountData := accountDataMap[address]
424+
results := l.tx.SendBatch(context.Background(), &batch)
425+
res := make(map[basics.AssetIndex]ledger.FoundAddress, len(indices))
426+
for _, index := range indicesArr {
427+
row := results.QueryRow()
428+
429+
address, exists, err := l.parseAddress(row)
430+
if err != nil {
431+
return nil, fmt.Errorf("GetAssetCreator() err: %w", err)
432+
}
431433

432-
if accountData == nil {
433-
return basics.AccountData{}, round, nil
434+
res[index] = ledger.FoundAddress{Address: address, Exists: exists}
434435
}
435-
return *accountData, round, nil
436-
}
436+
results.Close()
437437

438-
// GetCreatorForRound is part of go-algorand's ledgerForEvaluator interface.
439-
func (l LedgerForEvaluator) GetCreatorForRound(_ basics.Round, cindex basics.CreatableIndex, ctype basics.CreatableType) (basics.Address, bool, error) {
440-
var row pgx.Row
438+
return res, nil
439+
}
441440

442-
switch ctype {
443-
case basics.AssetCreatable:
444-
row = l.tx.QueryRow(context.Background(), assetCreatorStmtName, uint64(cindex))
445-
case basics.AppCreatable:
446-
row = l.tx.QueryRow(context.Background(), appCreatorStmtName, uint64(cindex))
447-
default:
448-
panic("unknown creatable type")
441+
// GetAppCreator is part of go-algorand's indexerLedgerForEval interface.
442+
func (l LedgerForEvaluator) GetAppCreator(indices map[basics.AppIndex]struct{}) (map[basics.AppIndex]ledger.FoundAddress, error) {
443+
indicesArr := make([]basics.AppIndex, 0, len(indices))
444+
for index := range indices {
445+
indicesArr = append(indicesArr, index)
449446
}
450447

451-
var buf []byte
452-
err := row.Scan(&buf)
453-
if err == pgx.ErrNoRows {
454-
return basics.Address{}, false, nil
455-
}
456-
if err != nil {
457-
return basics.Address{}, false, fmt.Errorf("GetCreatorForRound() err: %w", err)
448+
var batch pgx.Batch
449+
for _, index := range indicesArr {
450+
batch.Queue(appCreatorStmtName, uint64(index))
458451
}
459452

460-
var address basics.Address
461-
copy(address[:], buf)
453+
results := l.tx.SendBatch(context.Background(), &batch)
454+
res := make(map[basics.AppIndex]ledger.FoundAddress, len(indices))
455+
for _, index := range indicesArr {
456+
row := results.QueryRow()
462457

463-
return address, true, nil
464-
}
458+
address, exists, err := l.parseAddress(row)
459+
if err != nil {
460+
return nil, fmt.Errorf("GetAppCreator() err: %w", err)
461+
}
462+
463+
res[index] = ledger.FoundAddress{Address: address, Exists: exists}
464+
}
465+
results.Close()
465466

466-
// GenesisHash is part of go-algorand's ledgerForEvaluator interface.
467-
func (l LedgerForEvaluator) GenesisHash() crypto.Digest {
468-
return l.genesisHash
467+
return res, nil
469468
}
470469

471-
// Totals is part of go-algorand's ledgerForEvaluator interface.
472-
func (l LedgerForEvaluator) Totals(round basics.Round) (ledgercore.AccountTotals, error) {
470+
// Totals is part of go-algorand's indexerLedgerForEval interface.
471+
func (l LedgerForEvaluator) Totals() (ledgercore.AccountTotals, error) {
473472
// The evaluator uses totals only for recomputing the rewards pool balance. Indexer
474473
// does not currently compute this balance, and we can return an empty struct
475474
// here.
476475
return ledgercore.AccountTotals{}, nil
477476
}
478-
479-
// CompactCertVoters is part of go-algorand's ledgerForEvaluator interface.
480-
func (l LedgerForEvaluator) CompactCertVoters(basics.Round) (*ledger.VotersForRound, error) {
481-
// This function is not used by evaluator.
482-
return nil, errors.New("CompactCertVoters() not implemented")
483-
}

0 commit comments

Comments
 (0)