Skip to content

Commit 8614421

Browse files
authored
Merge pull request #3943 from Algo-devops-service/relbeta3.6.1
2 parents cdcda99 + a6bf83c commit 8614421

File tree

4 files changed

+175
-70
lines changed

4 files changed

+175
-70
lines changed

buildnumber.dat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0
1+
1

ledger/acctupdates.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -895,9 +895,10 @@ func (au *accountUpdates) lookupLatest(addr basics.Address) (data basics.Account
895895
addResource := func(cidx basics.CreatableIndex, round basics.Round, res ledgercore.AccountResource) error {
896896
foundRound, ok := foundResources[cidx]
897897
if !ok { // first time seeing this cidx
898-
resourceCount++
899898
foundResources[cidx] = round
900-
ledgercore.AssignAccountResourceToAccountData(cidx, res, &data)
899+
if ledgercore.AssignAccountResourceToAccountData(cidx, res, &data) {
900+
resourceCount++
901+
}
901902
return nil
902903
}
903904
// is this newer than current "found" rnd for this resource?

ledger/acctupdates_test.go

Lines changed: 162 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2357,6 +2357,74 @@ func TestAcctUpdatesLookupRetry(t *testing.T) {
23572357
})
23582358
}
23592359

2360+
// auCommitSync is a helper function calling the committing sequence similarly to what tracker registry does
2361+
func auCommitSync(t *testing.T, rnd basics.Round, au *accountUpdates, ml *mockLedgerForTracker) {
2362+
_, maxLookback := au.committedUpTo(rnd)
2363+
dcc := &deferredCommitContext{
2364+
deferredCommitRange: deferredCommitRange{
2365+
lookback: maxLookback,
2366+
},
2367+
}
2368+
cdr := &dcc.deferredCommitRange
2369+
cdr = au.produceCommittingTask(rnd, ml.trackers.dbRound, cdr)
2370+
if cdr != nil {
2371+
func() {
2372+
dcc.deferredCommitRange = *cdr
2373+
ml.trackers.accountsWriting.Add(1)
2374+
defer ml.trackers.accountsWriting.Done()
2375+
2376+
// do not take any locks since all operations are synchronous
2377+
newBase := basics.Round(dcc.offset) + dcc.oldBase
2378+
dcc.newBase = newBase
2379+
2380+
err := au.prepareCommit(dcc)
2381+
require.NoError(t, err)
2382+
err = ml.trackers.dbs.Wdb.Atomic(func(ctx context.Context, tx *sql.Tx) (err error) {
2383+
err = au.commitRound(ctx, tx, dcc)
2384+
if err != nil {
2385+
return err
2386+
}
2387+
err = updateAccountsRound(tx, newBase)
2388+
return err
2389+
})
2390+
require.NoError(t, err)
2391+
ml.trackers.dbRound = newBase
2392+
au.postCommit(ml.trackers.ctx, dcc)
2393+
au.postCommitUnlocked(ml.trackers.ctx, dcc)
2394+
}()
2395+
}
2396+
}
2397+
2398+
type auNewBlockOpts struct {
2399+
updates ledgercore.AccountDeltas
2400+
version protocol.ConsensusVersion
2401+
protoParams config.ConsensusParams
2402+
knownCreatables map[basics.CreatableIndex]bool
2403+
}
2404+
2405+
func auNewBlock(t *testing.T, rnd basics.Round, au *accountUpdates, base map[basics.Address]basics.AccountData, data auNewBlockOpts) {
2406+
rewardLevel := uint64(0)
2407+
prevRound, prevTotals, err := au.LatestTotals()
2408+
require.Equal(t, rnd-1, prevRound)
2409+
require.NoError(t, err)
2410+
2411+
newTotals := ledgertesting.CalculateNewRoundAccountTotals(t, data.updates, rewardLevel, data.protoParams, base, prevTotals)
2412+
2413+
blk := bookkeeping.Block{
2414+
BlockHeader: bookkeeping.BlockHeader{
2415+
Round: basics.Round(rnd),
2416+
},
2417+
}
2418+
blk.RewardsLevel = rewardLevel
2419+
blk.CurrentProtocol = data.version
2420+
delta := ledgercore.MakeStateDelta(&blk.BlockHeader, 0, data.updates.Len(), 0)
2421+
delta.Accts.MergeAccounts(data.updates)
2422+
delta.Creatables = creatablesFromUpdates(base, data.updates, data.knownCreatables)
2423+
delta.Totals = newTotals
2424+
2425+
au.newBlock(blk, delta)
2426+
}
2427+
23602428
// TestAcctUpdatesLookupLatestCacheRetry simulates a situation when base account and resources are in a cache but
23612429
// account updates advances while calling lookupLatest
23622430
// The idea of the test:
@@ -2408,67 +2476,6 @@ func TestAcctUpdatesLookupLatestCacheRetry(t *testing.T) {
24082476
aidx2 := basics.AssetIndex(2)
24092477
knownCreatables := make(map[basics.CreatableIndex]bool)
24102478

2411-
commitSync := func(rnd basics.Round) {
2412-
_, maxLookback := au.committedUpTo(rnd)
2413-
dcc := &deferredCommitContext{
2414-
deferredCommitRange: deferredCommitRange{
2415-
lookback: maxLookback,
2416-
},
2417-
}
2418-
cdr := &dcc.deferredCommitRange
2419-
cdr = au.produceCommittingTask(rnd, ml.trackers.dbRound, cdr)
2420-
if cdr != nil {
2421-
func() {
2422-
dcc.deferredCommitRange = *cdr
2423-
ml.trackers.accountsWriting.Add(1)
2424-
defer ml.trackers.accountsWriting.Done()
2425-
2426-
// do not take any locks since all operations are synchronous
2427-
newBase := basics.Round(dcc.offset) + dcc.oldBase
2428-
dcc.newBase = newBase
2429-
2430-
err := au.prepareCommit(dcc)
2431-
require.NoError(t, err)
2432-
err = ml.trackers.dbs.Wdb.Atomic(func(ctx context.Context, tx *sql.Tx) (err error) {
2433-
err = au.commitRound(ctx, tx, dcc)
2434-
if err != nil {
2435-
return err
2436-
}
2437-
err = updateAccountsRound(tx, newBase)
2438-
return err
2439-
})
2440-
require.NoError(t, err)
2441-
ml.trackers.dbRound = newBase
2442-
au.postCommit(ml.trackers.ctx, dcc)
2443-
au.postCommitUnlocked(ml.trackers.ctx, dcc)
2444-
}()
2445-
2446-
}
2447-
}
2448-
2449-
newBlock := func(au *accountUpdates, rnd basics.Round, base map[basics.Address]basics.AccountData, updates ledgercore.AccountDeltas) {
2450-
rewardLevel := uint64(0)
2451-
prevRound, prevTotals, err := au.LatestTotals()
2452-
require.Equal(t, rnd-1, prevRound)
2453-
require.NoError(t, err)
2454-
2455-
newTotals := ledgertesting.CalculateNewRoundAccountTotals(t, updates, rewardLevel, protoParams, base, prevTotals)
2456-
2457-
blk := bookkeeping.Block{
2458-
BlockHeader: bookkeeping.BlockHeader{
2459-
Round: basics.Round(rnd),
2460-
},
2461-
}
2462-
blk.RewardsLevel = rewardLevel
2463-
blk.CurrentProtocol = testProtocolVersion
2464-
delta := ledgercore.MakeStateDelta(&blk.BlockHeader, 0, updates.Len(), 0)
2465-
delta.Accts.MergeAccounts(updates)
2466-
delta.Creatables = creatablesFromUpdates(base, updates, knownCreatables)
2467-
delta.Totals = newTotals
2468-
2469-
au.newBlock(blk, delta)
2470-
}
2471-
24722479
// the test 1 requires 2 blocks with different resource state, au requires MaxBalLookback block to start persisting
24732480
for i := basics.Round(1); i <= basics.Round(protoParams.MaxBalLookback+2); i++ {
24742481
var updates ledgercore.AccountDeltas
@@ -2485,10 +2492,11 @@ func TestAcctUpdatesLookupLatestCacheRetry(t *testing.T) {
24852492
accts = append(accts, newAccts)
24862493

24872494
// prepare block
2488-
newBlock(au, i, base, updates)
2495+
opts := auNewBlockOpts{updates, testProtocolVersion, protoParams, knownCreatables}
2496+
auNewBlock(t, i, au, base, opts)
24892497

24902498
// commit changes synchroniously
2491-
commitSync(i)
2499+
auCommitSync(t, i, au, ml)
24922500
}
24932501

24942502
// ensure rounds
@@ -2548,8 +2556,9 @@ func TestAcctUpdatesLookupLatestCacheRetry(t *testing.T) {
25482556
au.accountsMu.Lock()
25492557
au.cachedDBRound = oldCachedDBRound
25502558
au.accountsMu.Unlock()
2551-
newBlock(au, rnd+1, accts[rnd], ledgercore.AccountDeltas{})
2552-
commitSync(rnd + 1)
2559+
opts := auNewBlockOpts{ledgercore.AccountDeltas{}, testProtocolVersion, protoParams, knownCreatables}
2560+
auNewBlock(t, rnd+1, au, accts[rnd], opts)
2561+
auCommitSync(t, rnd+1, au, ml)
25532562

25542563
wg.Wait()
25552564

@@ -2559,3 +2568,91 @@ func TestAcctUpdatesLookupLatestCacheRetry(t *testing.T) {
25592568
require.Equal(t, uint64(100), ad.Assets[aidx1].Amount)
25602569
require.Equal(t, uint64(200), ad.Assets[aidx2].Amount)
25612570
}
2571+
2572+
// TestAcctUpdatesLookupResources creates 3 assets, deletes one
2573+
// and checks au.resources with deleted resources are not counted toward totals
2574+
func TestAcctUpdatesLookupResources(t *testing.T) {
2575+
partitiontest.PartitionTest(t)
2576+
2577+
accts := []map[basics.Address]basics.AccountData{ledgertesting.RandomAccounts(1, true)}
2578+
pooldata := basics.AccountData{}
2579+
pooldata.MicroAlgos.Raw = 100 * 1000 * 1000 * 1000 * 1000
2580+
pooldata.Status = basics.NotParticipating
2581+
accts[0][testPoolAddr] = pooldata
2582+
2583+
sinkdata := basics.AccountData{}
2584+
sinkdata.MicroAlgos.Raw = 1000 * 1000 * 1000 * 1000
2585+
sinkdata.Status = basics.NotParticipating
2586+
accts[0][testSinkAddr] = sinkdata
2587+
2588+
testProtocolVersion := protocol.ConsensusVersion("test-protocol-TestAcctUpdatesLookupResources")
2589+
protoParams := config.Consensus[protocol.ConsensusCurrentVersion]
2590+
protoParams.MaxBalLookback = 2
2591+
protoParams.SeedLookback = 1
2592+
protoParams.SeedRefreshInterval = 1
2593+
config.Consensus[testProtocolVersion] = protoParams
2594+
defer func() {
2595+
delete(config.Consensus, testProtocolVersion)
2596+
}()
2597+
2598+
ml := makeMockLedgerForTracker(t, true, 1, testProtocolVersion, accts)
2599+
defer ml.Close()
2600+
2601+
conf := config.GetDefaultLocal()
2602+
au := newAcctUpdates(t, ml, conf, ".")
2603+
defer au.close()
2604+
2605+
var addr1 basics.Address
2606+
for addr := range accts[0] {
2607+
if addr != testSinkAddr && addr != testPoolAddr {
2608+
addr1 = addr
2609+
break
2610+
}
2611+
}
2612+
2613+
aidx1 := basics.AssetIndex(1)
2614+
aidx2 := basics.AssetIndex(2)
2615+
aidx3 := basics.AssetIndex(3)
2616+
knownCreatables := make(map[basics.CreatableIndex]bool)
2617+
2618+
// test requires 5 blocks: 1 with aidx1, protoParams.MaxBalLookback empty blocks to commit the first one
2619+
// and 1 block with aidx2 and aidx3, and another one with aidx2 deleted
2620+
for i := basics.Round(1); i <= basics.Round(protoParams.MaxBalLookback+3); i++ {
2621+
var updates ledgercore.AccountDeltas
2622+
2623+
// add data
2624+
if i == 1 {
2625+
updates.Upsert(addr1, ledgercore.AccountData{AccountBaseData: ledgercore.AccountBaseData{MicroAlgos: basics.MicroAlgos{Raw: 1000000}, TotalAssets: 1}})
2626+
updates.UpsertAssetResource(addr1, aidx1, ledgercore.AssetParamsDelta{}, ledgercore.AssetHoldingDelta{Holding: &basics.AssetHolding{Amount: 100}})
2627+
}
2628+
if i == basics.Round(protoParams.MaxBalLookback+2) {
2629+
updates.Upsert(addr1, ledgercore.AccountData{AccountBaseData: ledgercore.AccountBaseData{MicroAlgos: basics.MicroAlgos{Raw: 1000000}, TotalAssets: 3}})
2630+
updates.UpsertAssetResource(addr1, aidx2, ledgercore.AssetParamsDelta{}, ledgercore.AssetHoldingDelta{Holding: &basics.AssetHolding{Amount: 200}})
2631+
updates.UpsertAssetResource(addr1, aidx3, ledgercore.AssetParamsDelta{}, ledgercore.AssetHoldingDelta{Holding: &basics.AssetHolding{Amount: 300}})
2632+
}
2633+
if i == basics.Round(protoParams.MaxBalLookback+3) {
2634+
updates.Upsert(addr1, ledgercore.AccountData{AccountBaseData: ledgercore.AccountBaseData{MicroAlgos: basics.MicroAlgos{Raw: 1000000}, TotalAssets: 2}})
2635+
updates.UpsertAssetResource(addr1, aidx2, ledgercore.AssetParamsDelta{}, ledgercore.AssetHoldingDelta{Deleted: true})
2636+
}
2637+
2638+
base := accts[i-1]
2639+
newAccts := applyPartialDeltas(base, updates)
2640+
accts = append(accts, newAccts)
2641+
2642+
// prepare block
2643+
opts := auNewBlockOpts{updates, testProtocolVersion, protoParams, knownCreatables}
2644+
auNewBlock(t, i, au, base, opts)
2645+
2646+
if i <= basics.Round(protoParams.MaxBalLookback+1) {
2647+
auCommitSync(t, i, au, ml)
2648+
}
2649+
// do not commit two last blocks to keep data in memory deltas
2650+
}
2651+
data, rnd, _, err := au.lookupLatest(addr1)
2652+
require.NoError(t, err)
2653+
require.Equal(t, basics.Round(protoParams.MaxBalLookback+3), rnd)
2654+
require.Len(t, data.Assets, 2)
2655+
require.Contains(t, data.Assets, aidx1)
2656+
require.Contains(t, data.Assets, aidx3)
2657+
require.NotContains(t, data.Assets, aidx2)
2658+
}

ledger/ledgercore/accountresource.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,31 +40,38 @@ type AppResource struct {
4040
AppParams *basics.AppParams
4141
}
4242

43-
// AssignAccountResourceToAccountData assignes the Asset/App params/holdings contained
43+
// AssignAccountResourceToAccountData assigns the Asset/App params/holdings contained
4444
// in the AccountResource to the given basics.AccountData, creating maps if necessary.
45-
func AssignAccountResourceToAccountData(cindex basics.CreatableIndex, resource AccountResource, ad *basics.AccountData) {
45+
// Returns true if the AccountResource contained a new or updated resource,
46+
// and false if the AccountResource contained no changes (indicating the resource was deleted).
47+
func AssignAccountResourceToAccountData(cindex basics.CreatableIndex, resource AccountResource, ad *basics.AccountData) (assigned bool) {
4648
if resource.AssetParams != nil {
4749
if ad.AssetParams == nil {
4850
ad.AssetParams = make(map[basics.AssetIndex]basics.AssetParams)
4951
}
5052
ad.AssetParams[basics.AssetIndex(cindex)] = *resource.AssetParams
53+
assigned = true
5154
}
5255
if resource.AssetHolding != nil {
5356
if ad.Assets == nil {
5457
ad.Assets = make(map[basics.AssetIndex]basics.AssetHolding)
5558
}
5659
ad.Assets[basics.AssetIndex(cindex)] = *resource.AssetHolding
60+
assigned = true
5761
}
5862
if resource.AppParams != nil {
5963
if ad.AppParams == nil {
6064
ad.AppParams = make(map[basics.AppIndex]basics.AppParams)
6165
}
6266
ad.AppParams[basics.AppIndex(cindex)] = *resource.AppParams
67+
assigned = true
6368
}
6469
if resource.AppLocalState != nil {
6570
if ad.AppLocalStates == nil {
6671
ad.AppLocalStates = make(map[basics.AppIndex]basics.AppLocalState)
6772
}
6873
ad.AppLocalStates[basics.AppIndex(cindex)] = *resource.AppLocalState
74+
assigned = true
6975
}
76+
return
7077
}

0 commit comments

Comments
 (0)