-
Notifications
You must be signed in to change notification settings - Fork 827
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
Use transient store for EVM deferred info #1690
Conversation
am.keeper.SetTxHashesOnHeight(ctx, ctx.BlockHeight(), utils.Filter(utils.Map(evmTxDeferredInfoList, func(i keeper.EvmTxDeferredInfo) common.Hash { return i.TxHash }), func(h common.Hash) bool { return h.Cmp(ethtypes.EmptyTxsHash) != 0 })) | ||
am.keeper.SetBlockBloom(ctx, ctx.BlockHeight(), utils.Map(evmTxDeferredInfoList, func(i keeper.EvmTxDeferredInfo) ethtypes.Bloom { return i.TxBloom })) | ||
am.keeper.DeleteAllAnteSurplus(ctx) | ||
am.keeper.SetTxHashesOnHeight(ctx, ctx.BlockHeight(), utils.Filter(utils.Map(evmTxDeferredInfoList, func(i *types.DeferredInfo) common.Hash { return common.BytesToHash(i.TxHash) }), func(h common.Hash) bool { return h.Cmp(ethtypes.EmptyTxsHash) != 0 })) |
Check warning
Code scanning / CodeQL
Panic in BeginBock or EndBlock consensus methods Warning
am.keeper.SetBlockBloom(ctx, ctx.BlockHeight(), utils.Map(evmTxDeferredInfoList, func(i keeper.EvmTxDeferredInfo) ethtypes.Bloom { return i.TxBloom })) | ||
am.keeper.DeleteAllAnteSurplus(ctx) | ||
am.keeper.SetTxHashesOnHeight(ctx, ctx.BlockHeight(), utils.Filter(utils.Map(evmTxDeferredInfoList, func(i *types.DeferredInfo) common.Hash { return common.BytesToHash(i.TxHash) }), func(h common.Hash) bool { return h.Cmp(ethtypes.EmptyTxsHash) != 0 })) | ||
am.keeper.SetBlockBloom(ctx, ctx.BlockHeight(), utils.Map(evmTxDeferredInfoList, func(i *types.DeferredInfo) ethtypes.Bloom { return ethtypes.BytesToBloom(i.TxBloom) })) |
Check warning
Code scanning / CodeQL
Panic in BeginBock or EndBlock consensus methods Warning
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.
is this safe?
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 panic seems to be a sanity check in BytesToBloom
which I think should be okay? (all bloom bytes are produced by geth code)
if err := info.Unmarshal(val); err != nil { | ||
// unable to unmarshal deferred info is serious, because it could cause | ||
// balance surplus to be mishandled and thus affect total supply | ||
panic(err) |
Check warning
Code scanning / CodeQL
Panic in BeginBock or EndBlock consensus methods Warning
da6304b
to
4ec6c09
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1690 +/- ##
==========================================
- Coverage 60.81% 60.76% -0.06%
==========================================
Files 373 373
Lines 27116 27129 +13
==========================================
- Hits 16491 16485 -6
- Misses 9518 9530 +12
- Partials 1107 1114 +7
|
4ec6c09
to
2b8bcb7
Compare
2b8bcb7
to
888db56
Compare
888db56
to
9902e71
Compare
Describe your changes and provide context
Previously, we were using an adhoc
sync.Map
to keep track of deferred information that needs to be persisted from each transaction's individual processing toEndBlock
(for purposes like surplus settlement, fee aggregation, etc.), where the map is key'ed on transaction index. The assumption of such usage is that the deferred info will be consistent across nodes by the end of the block because each TX index's entry will be overwritten by the final run of that transaction, under the context of OCC.However this assumption is not correct, because a later incarnation of a transaction does not immediately (or ever) terminates its previous incarnation's goroutine (because there is no way to do so in Golang), so it is possible that a former incarnation may finish (and write to deferred info map) later than the final incarnation, potentially causing the state to be inconsistent with other nodes (where the final incarnation does write the last).
This PR changes the store of such deferred info to a transient store that's governed by the multiversion store. Specifically we choose transient store instead of memstore because we don't need any of these deferred info to be carried over to the next block. Using a memstore means we'd need to delete every entry one-by-one at the start of each block, which can add a lot to latency, whereas with a transient store it will simply be replaced with a new store instance for every block. In doing so for deferred info, we also changed the store for ante surplus from memstore to transient store for the same reason.
Note that this change in theory would not affect app state (and thus not app hash breaking, because all relevant states are in-memory)
Testing performed to validate your change
unit test