diff options
Diffstat (limited to 'ledger/accountdb_test.go')
-rw-r--r-- | ledger/accountdb_test.go | 361 |
1 files changed, 37 insertions, 324 deletions
diff --git a/ledger/accountdb_test.go b/ledger/accountdb_test.go index 38dcf996b..ab64fe48f 100644 --- a/ledger/accountdb_test.go +++ b/ledger/accountdb_test.go @@ -35,320 +35,19 @@ import ( "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/ledger/ledgercore" + ledgertesting "github.com/algorand/go-algorand/ledger/testing" "github.com/algorand/go-algorand/logging" "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" "github.com/algorand/go-algorand/util/db" ) -func randomAddress() basics.Address { - var addr basics.Address - crypto.RandBytes(addr[:]) - return addr -} - -func randomNote() []byte { - var note [16]byte - crypto.RandBytes(note[:]) - return note[:] -} - -func randomAccountData(rewardsLevel uint64) basics.AccountData { - var data basics.AccountData - - // Avoid overflowing totals - data.MicroAlgos.Raw = crypto.RandUint64() % (1 << 32) - - switch crypto.RandUint64() % 3 { - case 0: - data.Status = basics.Online - case 1: - data.Status = basics.Offline - default: - data.Status = basics.NotParticipating - } - - data.RewardsBase = rewardsLevel - data.VoteFirstValid = 0 - data.VoteLastValid = 1000 - return data -} - -func randomFullAccountData(rewardsLevel, lastCreatableID uint64) (basics.AccountData, uint64) { - data := randomAccountData(rewardsLevel) - - crypto.RandBytes(data.VoteID[:]) - crypto.RandBytes(data.SelectionID[:]) - data.VoteFirstValid = basics.Round(crypto.RandUint64()) - data.VoteLastValid = basics.Round(crypto.RandUint64()) - data.VoteKeyDilution = crypto.RandUint64() - if 1 == (crypto.RandUint64() % 2) { - // if account has created assets, have these defined. - data.AssetParams = make(map[basics.AssetIndex]basics.AssetParams) - createdAssetsCount := crypto.RandUint64()%20 + 1 - for i := uint64(0); i < createdAssetsCount; i++ { - ap := basics.AssetParams{ - Total: crypto.RandUint64(), - Decimals: uint32(crypto.RandUint64() % 20), - DefaultFrozen: (crypto.RandUint64()%2 == 0), - UnitName: fmt.Sprintf("un%x", uint32(crypto.RandUint64()%0x7fffffff)), - AssetName: fmt.Sprintf("an%x", uint32(crypto.RandUint64()%0x7fffffff)), - URL: fmt.Sprintf("url%x", uint32(crypto.RandUint64()%0x7fffffff)), - } - crypto.RandBytes(ap.MetadataHash[:]) - crypto.RandBytes(ap.Manager[:]) - crypto.RandBytes(ap.Reserve[:]) - crypto.RandBytes(ap.Freeze[:]) - crypto.RandBytes(ap.Clawback[:]) - lastCreatableID++ - data.AssetParams[basics.AssetIndex(lastCreatableID)] = ap - } - } - if 1 == (crypto.RandUint64()%2) && lastCreatableID > 0 { - // if account owns assets - data.Assets = make(map[basics.AssetIndex]basics.AssetHolding) - ownedAssetsCount := crypto.RandUint64()%20 + 1 - for i := uint64(0); i < ownedAssetsCount; i++ { - ah := basics.AssetHolding{ - Amount: crypto.RandUint64(), - Frozen: (crypto.RandUint64()%2 == 0), - } - data.Assets[basics.AssetIndex(crypto.RandUint64()%lastCreatableID)] = ah - } - } - if 1 == (crypto.RandUint64() % 5) { - crypto.RandBytes(data.AuthAddr[:]) - } - - if 1 == (crypto.RandUint64()%3) && lastCreatableID > 0 { - data.AppLocalStates = make(map[basics.AppIndex]basics.AppLocalState) - appStatesCount := crypto.RandUint64()%20 + 1 - for i := uint64(0); i < appStatesCount; i++ { - ap := basics.AppLocalState{ - Schema: basics.StateSchema{ - NumUint: crypto.RandUint64()%5 + 1, - NumByteSlice: crypto.RandUint64() % 5, - }, - KeyValue: make(map[string]basics.TealValue), - } - - for i := uint64(0); i < ap.Schema.NumUint; i++ { - appName := fmt.Sprintf("lapp%x-%x", crypto.RandUint64(), i) - ap.KeyValue[appName] = basics.TealValue{ - Type: basics.TealUintType, - Uint: crypto.RandUint64(), - } - } - for i := uint64(0); i < ap.Schema.NumByteSlice; i++ { - appName := fmt.Sprintf("lapp%x-%x", crypto.RandUint64(), i) - tv := basics.TealValue{ - Type: basics.TealBytesType, - } - bytes := make([]byte, crypto.RandUint64()%uint64(config.MaxBytesKeyValueLen-len(appName))) - crypto.RandBytes(bytes[:]) - tv.Bytes = string(bytes) - ap.KeyValue[appName] = tv - } - if len(ap.KeyValue) == 0 { - ap.KeyValue = nil - } - data.AppLocalStates[basics.AppIndex(crypto.RandUint64()%lastCreatableID)] = ap - } - } - - if 1 == (crypto.RandUint64() % 3) { - data.TotalAppSchema = basics.StateSchema{ - NumUint: crypto.RandUint64() % 50, - NumByteSlice: crypto.RandUint64() % 50, - } - } - if 1 == (crypto.RandUint64() % 3) { - data.AppParams = make(map[basics.AppIndex]basics.AppParams) - appParamsCount := crypto.RandUint64()%5 + 1 - for i := uint64(0); i < appParamsCount; i++ { - ap := basics.AppParams{ - ApprovalProgram: make([]byte, int(crypto.RandUint63())%config.MaxAppProgramLen), - ClearStateProgram: make([]byte, int(crypto.RandUint63())%config.MaxAppProgramLen), - GlobalState: make(basics.TealKeyValue), - StateSchemas: basics.StateSchemas{ - LocalStateSchema: basics.StateSchema{ - NumUint: crypto.RandUint64()%5 + 1, - NumByteSlice: crypto.RandUint64() % 5, - }, - GlobalStateSchema: basics.StateSchema{ - NumUint: crypto.RandUint64()%5 + 1, - NumByteSlice: crypto.RandUint64() % 5, - }, - }, - } - if len(ap.ApprovalProgram) > 0 { - crypto.RandBytes(ap.ApprovalProgram[:]) - } else { - ap.ApprovalProgram = nil - } - if len(ap.ClearStateProgram) > 0 { - crypto.RandBytes(ap.ClearStateProgram[:]) - } else { - ap.ClearStateProgram = nil - } - - for i := uint64(0); i < ap.StateSchemas.LocalStateSchema.NumUint+ap.StateSchemas.GlobalStateSchema.NumUint; i++ { - appName := fmt.Sprintf("tapp%x-%x", crypto.RandUint64(), i) - ap.GlobalState[appName] = basics.TealValue{ - Type: basics.TealUintType, - Uint: crypto.RandUint64(), - } - } - for i := uint64(0); i < ap.StateSchemas.LocalStateSchema.NumByteSlice+ap.StateSchemas.GlobalStateSchema.NumByteSlice; i++ { - appName := fmt.Sprintf("tapp%x-%x", crypto.RandUint64(), i) - tv := basics.TealValue{ - Type: basics.TealBytesType, - } - bytes := make([]byte, crypto.RandUint64()%uint64(config.MaxBytesKeyValueLen)) - crypto.RandBytes(bytes[:]) - tv.Bytes = string(bytes) - ap.GlobalState[appName] = tv - } - if len(ap.GlobalState) == 0 { - ap.GlobalState = nil - } - lastCreatableID++ - data.AppParams[basics.AppIndex(lastCreatableID)] = ap - } - - } - return data, lastCreatableID -} - -func randomAccounts(niter int, simpleAccounts bool) map[basics.Address]basics.AccountData { - res := make(map[basics.Address]basics.AccountData) - if simpleAccounts { - for i := 0; i < niter; i++ { - res[randomAddress()] = randomAccountData(0) - } - } else { - lastCreatableID := crypto.RandUint64() % 512 - for i := 0; i < niter; i++ { - res[randomAddress()], lastCreatableID = randomFullAccountData(0, lastCreatableID) - } - } - return res -} - -func randomDeltas(niter int, base map[basics.Address]basics.AccountData, rewardsLevel uint64) (updates ledgercore.AccountDeltas, totals map[basics.Address]basics.AccountData, imbalance int64) { - updates, totals, imbalance, _ = randomDeltasImpl(niter, base, rewardsLevel, true, 0) - return -} - -func randomDeltasFull(niter int, base map[basics.Address]basics.AccountData, rewardsLevel uint64, lastCreatableIDIn uint64) (updates ledgercore.AccountDeltas, totals map[basics.Address]basics.AccountData, imbalance int64, lastCreatableID uint64) { - updates, totals, imbalance, lastCreatableID = randomDeltasImpl(niter, base, rewardsLevel, false, lastCreatableIDIn) - return -} - -func randomDeltasImpl(niter int, base map[basics.Address]basics.AccountData, rewardsLevel uint64, simple bool, lastCreatableIDIn uint64) (updates ledgercore.AccountDeltas, totals map[basics.Address]basics.AccountData, imbalance int64, lastCreatableID uint64) { - proto := config.Consensus[protocol.ConsensusCurrentVersion] - totals = make(map[basics.Address]basics.AccountData) - - // copy base -> totals - for addr, data := range base { - totals[addr] = data - } - - // if making a full delta then need to determine max asset/app id to get rid of conflicts - lastCreatableID = lastCreatableIDIn - if !simple { - for _, ad := range base { - for aid := range ad.AssetParams { - if uint64(aid) > lastCreatableID { - lastCreatableID = uint64(aid) - } - } - for aid := range ad.AppParams { - if uint64(aid) > lastCreatableID { - lastCreatableID = uint64(aid) - } - } - } - } - - // Change some existing accounts - { - i := 0 - for addr, old := range base { - if i >= len(base)/2 || i >= niter { - break - } - - if addr == testPoolAddr { - continue - } - i++ - - var new basics.AccountData - if simple { - new = randomAccountData(rewardsLevel) - } else { - new, lastCreatableID = randomFullAccountData(rewardsLevel, lastCreatableID) - } - updates.Upsert(addr, new) - imbalance += int64(old.WithUpdatedRewards(proto, rewardsLevel).MicroAlgos.Raw - new.MicroAlgos.Raw) - totals[addr] = new - break - } - } - - // Change some new accounts - for i := 0; i < niter; i++ { - addr := randomAddress() - old := totals[addr] - var new basics.AccountData - if simple { - new = randomAccountData(rewardsLevel) - } else { - new, lastCreatableID = randomFullAccountData(rewardsLevel, lastCreatableID) - } - updates.Upsert(addr, new) - imbalance += int64(old.WithUpdatedRewards(proto, rewardsLevel).MicroAlgos.Raw - new.MicroAlgos.Raw) - totals[addr] = new - } - - return -} - -func randomDeltasBalanced(niter int, base map[basics.Address]basics.AccountData, rewardsLevel uint64) (updates ledgercore.AccountDeltas, totals map[basics.Address]basics.AccountData) { - updates, totals, _ = randomDeltasBalancedImpl(niter, base, rewardsLevel, true, 0) - return -} - -func randomDeltasBalancedFull(niter int, base map[basics.Address]basics.AccountData, rewardsLevel uint64, lastCreatableIDIn uint64) (updates ledgercore.AccountDeltas, totals map[basics.Address]basics.AccountData, lastCreatableID uint64) { - updates, totals, lastCreatableID = randomDeltasBalancedImpl(niter, base, rewardsLevel, false, lastCreatableIDIn) - return -} - -func randomDeltasBalancedImpl(niter int, base map[basics.Address]basics.AccountData, rewardsLevel uint64, simple bool, lastCreatableIDIn uint64) (updates ledgercore.AccountDeltas, totals map[basics.Address]basics.AccountData, lastCreatableID uint64) { - var imbalance int64 - if simple { - updates, totals, imbalance = randomDeltas(niter, base, rewardsLevel) - } else { - updates, totals, imbalance, lastCreatableID = randomDeltasFull(niter, base, rewardsLevel, lastCreatableIDIn) - } - - oldPool := base[testPoolAddr] - newPool := oldPool - newPool.MicroAlgos.Raw += uint64(imbalance) - - updates.Upsert(testPoolAddr, newPool) - totals[testPoolAddr] = newPool - - return updates, totals, lastCreatableID -} - func checkAccounts(t *testing.T, tx *sql.Tx, rnd basics.Round, accts map[basics.Address]basics.AccountData) { - r, _, err := accountsRound(tx) + r, err := accountsRound(tx) require.NoError(t, err) require.Equal(t, r, rnd) - aq, err := accountsDbInit(tx, tx) + aq, err := accountsInitDbQueries(tx, tx) require.NoError(t, err) defer aq.close() @@ -382,18 +81,18 @@ func checkAccounts(t *testing.T, tx *sql.Tx, rnd basics.Round, accts map[basics. totals, err := accountsTotals(tx, false) require.NoError(t, err) - require.Equal(t, totals.Online.Money.Raw, totalOnline) + require.Equal(t, totals.Online.Money.Raw, totalOnline, "mismatching total online money") require.Equal(t, totals.Offline.Money.Raw, totalOffline) require.Equal(t, totals.NotParticipating.Money.Raw, totalNotPart) require.Equal(t, totals.Participating().Raw, totalOnline+totalOffline) require.Equal(t, totals.All().Raw, totalOnline+totalOffline+totalNotPart) - d, err := aq.lookup(randomAddress()) + d, err := aq.lookup(ledgertesting.RandomAddress()) require.NoError(t, err) require.Equal(t, rnd, d.round) require.Equal(t, d.accountData, basics.AccountData{}) - onlineAccounts := make(map[basics.Address]*onlineAccount) + onlineAccounts := make(map[basics.Address]*ledgercore.OnlineAccount) for addr, data := range accts { if data.Status == basics.Online { onlineAccounts[addr] = accountDataToOnline(addr, &data, proto) @@ -406,7 +105,7 @@ func checkAccounts(t *testing.T, tx *sql.Tx, rnd basics.Round, accts map[basics. require.Equal(t, i, len(dbtop)) // Compute the top-N accounts ourselves - var testtop []onlineAccount + var testtop []ledgercore.OnlineAccount for _, data := range onlineAccounts { testtop = append(testtop, *data) } @@ -447,7 +146,7 @@ func TestAccountDBInit(t *testing.T) { require.NoError(t, err) defer tx.Rollback() - accts := randomAccounts(20, true) + accts := ledgertesting.RandomAccounts(20, true) newDB, err := accountsInit(tx, accts, proto) require.NoError(t, err) require.True(t, newDB) @@ -540,10 +239,12 @@ func TestAccountDBRound(t *testing.T) { require.NoError(t, err) defer tx.Rollback() - accts := randomAccounts(20, true) + accts := ledgertesting.RandomAccounts(20, true) _, err = accountsInit(tx, accts, proto) require.NoError(t, err) checkAccounts(t, tx, 0, accts) + totals, err := accountsTotals(tx, false) + require.NoError(t, err) // used to determine how many creatables element will be in the test per iteration numElementsPerSegement := 10 @@ -553,11 +254,12 @@ func TestAccountDBRound(t *testing.T) { ctbsList, randomCtbs := randomCreatables(numElementsPerSegement) expectedDbImage := make(map[basics.CreatableIndex]ledgercore.ModifiedCreatable) var baseAccounts lruAccounts + var newaccts map[basics.Address]basics.AccountData baseAccounts.init(nil, 100, 80) for i := 1; i < 10; i++ { var updates ledgercore.AccountDeltas - var newaccts map[basics.Address]basics.AccountData - updates, newaccts, _, lastCreatableID = randomDeltasFull(20, accts, 0, lastCreatableID) + updates, newaccts, _, lastCreatableID = ledgertesting.RandomDeltasFull(20, accts, 0, lastCreatableID) + totals = ledgertesting.CalculateNewRoundAccountTotals(t, updates, 0, proto, accts, totals) accts = newaccts ctbsWithDeletes := randomCreatableSampling(i, ctbsList, randomCtbs, expectedDbImage, numElementsPerSegement) @@ -565,15 +267,26 @@ func TestAccountDBRound(t *testing.T) { updatesCnt := makeCompactAccountDeltas([]ledgercore.AccountDeltas{updates}, baseAccounts) err = updatesCnt.accountsLoadOld(tx) require.NoError(t, err) - err = totalsNewRounds(tx, []ledgercore.AccountDeltas{updates}, updatesCnt, []ledgercore.AccountTotals{{}}, proto) + err = accountsPutTotals(tx, totals, false) require.NoError(t, err) _, err = accountsNewRound(tx, updatesCnt, ctbsWithDeletes, proto, basics.Round(i)) require.NoError(t, err) - err = updateAccountsRound(tx, basics.Round(i), 0) + err = updateAccountsRound(tx, basics.Round(i)) require.NoError(t, err) checkAccounts(t, tx, basics.Round(i), accts) checkCreatables(t, tx, i, expectedDbImage) } + + // test the accounts totals + var updates ledgercore.AccountDeltas + for addr, acctData := range newaccts { + updates.Upsert(addr, acctData) + } + + expectedTotals := ledgertesting.CalculateNewRoundAccountTotals(t, updates, 0, proto, nil, ledgercore.AccountTotals{}) + actualTotals, err := accountsTotals(tx, false) + require.NoError(t, err) + require.Equal(t, expectedTotals, actualTotals) } // checkCreatables compares the expected database image to the actual databse content @@ -683,7 +396,7 @@ func randomCreatable(uniqueAssetIds map[basics.CreatableIndex]bool) ( creatable := ledgercore.ModifiedCreatable{ Ctype: ctype, Created: (crypto.RandUint64() % 2) == 1, - Creator: randomAddress(), + Creator: ledgertesting.RandomAddress(), Ndeltas: 1, } @@ -705,7 +418,7 @@ func generateRandomTestingAccountBalances(numAccounts int) (updates map[basics.A updates = make(map[basics.Address]basics.AccountData, numAccounts) for i := 0; i < numAccounts; i++ { - addr := randomAddress() + addr := ledgertesting.RandomAddress() updates[addr] = basics.AccountData{ MicroAlgos: basics.MicroAlgos{Raw: 0x000ffffffffffffff / uint64(numAccounts)}, Status: basics.NotParticipating, @@ -804,7 +517,7 @@ func benchmarkReadingRandomBalances(b *testing.B, inMemory bool) { accounts := benchmarkInitBalances(b, b.N, dbs, proto) - qs, err := accountsDbInit(dbs.Rdb.Handle, dbs.Wdb.Handle) + qs, err := accountsInitDbQueries(dbs.Rdb.Handle, dbs.Wdb.Handle) require.NoError(b, err) // read all the balances in the database, shuffled @@ -977,14 +690,14 @@ func TestAccountsReencoding(t *testing.T) { } for _, oldAccData := range oldEncodedAccountsData { - addr := randomAddress() + addr := ledgertesting.RandomAddress() _, err = tx.ExecContext(ctx, "INSERT INTO accountbase (address, data) VALUES (?, ?)", addr[:], oldAccData) if err != nil { return err } } for i := 0; i < 100; i++ { - addr := randomAddress() + addr := ledgertesting.RandomAddress() accData := basics.AccountData{ MicroAlgos: basics.MicroAlgos{Raw: 0x000ffffffffffffff}, Status: basics.NotParticipating, @@ -1058,7 +771,7 @@ func TestAccountsDbQueriesCreateClose(t *testing.T) { return nil }) require.NoError(t, err) - qs, err := accountsDbInit(dbs.Rdb.Handle, dbs.Wdb.Handle) + qs, err := accountsInitDbQueries(dbs.Rdb.Handle, dbs.Wdb.Handle) require.NoError(t, err) require.NotNil(t, qs.listCreatablesStmt) qs.close() @@ -1069,7 +782,7 @@ func TestAccountsDbQueriesCreateClose(t *testing.T) { func benchmarkWriteCatchpointStagingBalancesSub(b *testing.B, ascendingOrder bool) { proto := config.Consensus[protocol.ConsensusCurrentVersion] - genesisInitState, _ := testGenerateInitState(b, protocol.ConsensusCurrentVersion, 100) + genesisInitState, _ := ledgertesting.GenerateInitState(b, protocol.ConsensusCurrentVersion, 100) const inMem = false log := logging.TestingLog(b) cfg := config.GetDefaultLocal() @@ -1170,7 +883,7 @@ func TestCompactAccountDeltas(t *testing.T) { a.Equal(-1, idx) a.Equal(accountDelta{}, data) - addr := randomAddress() + addr := ledgertesting.RandomAddress() data, idx = ad.get(addr) a.Equal(-1, idx) a.Equal(accountDelta{}, data) @@ -1217,7 +930,7 @@ func TestCompactAccountDeltas(t *testing.T) { a.Equal(addr, address) a.Equal(accountDelta{new: sample2.new, old: old1}, data) - addr1 := randomAddress() + addr1 := ledgertesting.RandomAddress() old2 := persistedAccountData{addr: addr1, accountData: basics.AccountData{MicroAlgos: basics.MicroAlgos{Raw: 789}}} ad.upsertOld(old2) a.Equal(2, ad.len()) @@ -1235,7 +948,7 @@ func TestCompactAccountDeltas(t *testing.T) { a.Equal(addr, address) a.Equal(accountDelta{new: sample2.new, old: old2}, data) - addr2 := randomAddress() + addr2 := ledgertesting.RandomAddress() idx = ad.insert(addr2, sample2) a.Equal(3, ad.len()) a.Equal(2, idx) |