-
Notifications
You must be signed in to change notification settings - Fork 471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ledger: fix LookupLatest when the ledger advances #3769
ledger: fix LookupLatest when the ledger advances #3769
Conversation
var wg sync.WaitGroup | ||
wg.Add(1) | ||
done := make(chan struct{}) | ||
go func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had another implementation with timer a bit simpler but this looks a bit more robust. Any suggestions on how to check lookupLatest has been blocked at au.accountsReadCond.Wait()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you'd have to change accountsReadCond to use an interface and create a mock (or wrapped) sync.Cond?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about adding some code into lookupLatest
or abstracting the cond var, but thought it is too much only for a single tests.
d4848e1
to
c720cb4
Compare
@@ -886,7 +886,7 @@ func (au *accountUpdates) lookupLatest(addr basics.Address) (data basics.Account | |||
var resourceDbRound basics.Round | |||
withRewards := true | |||
|
|||
foundAccount := false | |||
var foundAccount bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The two are equivilent..
@@ -957,6 +960,7 @@ func (au *accountUpdates) lookupLatest(addr basics.Address) (data basics.Account | |||
return basics.AccountData{}, basics.Round(0), basics.MicroAlgos{}, fmt.Errorf("offset != len(au.deltas): %w", ErrLookupLatestResources) | |||
} | |||
ad = ledgercore.AccountData{} | |||
foundAccount = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for finding this...
Summary
LookupLatest combines base account and resources data, and in some cases it cannot
determine reliably how many resources account has, therefore it reads data directly from the DB.
The DB might advance causing cachedDBRound (and base account data) and resourceDbRound
to be out of sync, and a retry needed.
If on retry baseAccount data is outdated, foundAccount flag incorrectly contains a value from
a previous iteration causing completion by checkDone because of empty ad (ledgercore.AccountData).
Having ad and foundAccount synchronized on retry eliminates the problem.
In addition checkDone improved for scenarios when accounts have only own assets.
Test Plan
Added new test