Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Describe your changes and provide context
Intro
This is the sequence of events during block commitment.
app.WriteState() writes latest state to
memiavl(among other things).app.cms.Commit(true) updates lastCommitInfo (among other things).
Effect on RPC reads
GetTransactionCount resolves stores to use on the following call path: GetTransactionCount -> RPCContextProvider -> CreateQueryContext -> CacheMultiStoreWithVersion.
Stores can be resolved in two ways dependent on whether
blockNumberfrom the RPC query is equal to rs.lastCommitInfo.Version:sei-chain/sei-cosmos/storev2/rootmulti/store.go
Line 253 in 06a4e24
sei-chain/sei-cosmos/storev2/rootmulti/store.go
Lines 257 to 275 in 06a4e24
If it is equal we allow reading from
memiavl(which holds only latest data if I understood correctly) and if it is different we allow reading from snapshot stores exclusively.Because of the sequence of events outlined in the intro the following can happen:
memiavlvia app.WriteState().eth_getTransactionCounton block X is querried and during execution evaluates thisifastrueand serves rs.CacheMultiStore() - since app.cms.Commit(true) has not yet executed and updated lastCommitInfo we think thatblockNumberfrom the RPC query is equal to rs.lastCommitInfo.Version.memiavlwhich serves the latest nonce instead of the nonce at block X.Impact
The corruption window lasts from when the state was written to
memiavlvia app.WriteState() until app.cms.Commit(true) executes.Issue affects all RPC data that can be served from
memiavlduring the window outlined above (e.g.eth_getBalance,eth_getTransactionCount, etc.).Solution
We should never serve
memiavlon the RPC read path (or any non-execution read path) and this block of code should be removed entirely.Logically it does not make sense to serve
memiavlas a store on the RPC read path seeing as it only contains the latest state and the read path does not get a clone/must not lock it meaning it can get modified on the fly which leads to inconsistencies.Testing performed to validate your change
I had a repro of the issue locally so I validated that the issue goes away when this change is introduced.