Skip to content

Rollback enabled shomei#166

Open
garyschulte wants to merge 16 commits intoConsensys:mainfrom
garyschulte:speculative/rollback-enabled
Open

Rollback enabled shomei#166
garyschulte wants to merge 16 commits intoConsensys:mainfrom
garyschulte:speculative/rollback-enabled

Conversation

@garyschulte
Copy link
Copy Markdown
Contributor

@garyschulte garyschulte commented Apr 11, 2026

PR Description

builds on #164 and #165. This is a claude-driven implementation of a trielog rollback facility in shomei.

Tested locally. It works as expected, and correctly errors when trying to roll back past a pre-eip-6780 selfdestruct.

Fixed Issue(s)

Documentation

  • I thought about documentation and added the doc-change-required label to this PR if updates are required.

Changelog

  • I thought about adding a changelog entry, and added one if I deemed necessary.

Note

High Risk
High risk because it introduces multi-step rollback reconstruction of historical world states and changes account/storage deletion semantics across in-memory, layered, and persisted storages, which can affect core state integrity and RPC results.

Overview
Adds a rollback path to reconstruct historical ZkEvmWorldStates from stored trie logs when snapshots are missing, via ZkWorldStateArchive.getOrLoadWorldState and a new multi-step rollBackToBlock that replays decodeTrieLogForRollback + accumulator rollBack on an ephemeral LayeredWorldStateStorage.

Extends worldstate storage updaters with removeStorageForAccount and wires it into account deletion in ZkEvmWorldState (including overlay tombstoning rules in LayeredWorldStateStorage), so storage-trie data is removed/hidden correctly during clears and rollbacks.

Updates trie-log decoding to support both forward decoding against an explicit WorldStateStorage and a dedicated rollback decoder, updates the virtual merkle-proof RPC to load/reconstruct the parent worldstate instead of requiring it to be cached, and adds an integration test suite with real trie logs to validate rollback behavior (including a documented failure case across pre-EIP-6780 SELFDESTRUCT).

Reviewed by Cursor Bugbot for commit d8c2952. Bugbot is set up for automated code reviews on this repo. Configure here.

Signed-off-by: garyschulte <garyschulte@gmail.com>
…ed overload

Signed-off-by: garyschulte <garyschulte@gmail.com>
Signed-off-by: garyschulte <garyschulte@gmail.com>
Signed-off-by: garyschulte <garyschulte@gmail.com>
Signed-off-by: garyschulte <garyschulte@gmail.com>
Signed-off-by: garyschulte <garyschulte@gmail.com>
Signed-off-by: garyschulte <garyschulte@gmail.com>
Signed-off-by: garyschulte <garyschulte@gmail.com>
@garyschulte garyschulte requested a review from matkt April 11, 2026 03:10
…and fix unused mock

Signed-off-by: garyschulte <garyschulte@gmail.com>
Signed-off-by: garyschulte <garyschulte@gmail.com>
Signed-off-by: garyschulte <garyschulte@gmail.com>
// TODO remove all slots from storage : if we not do that the rollback will not work
// get index leaf from DB and delete all keys starting by HKEY+index in trie branch
// Note: the account (A') was already removed by the isCleared block above.
// Block 3 (update/insert) will re-insert the original account (A) at the decremented NFN.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rollback of account creation fails to remove account

High Severity

When rolling back a block that created a new account, the account is never removed from the trie. After rollBack swaps the trie log's prior/updated, the ZkValue ends up with prior=AccountX, updated=null, isCleared=false, isRollforward=false. The dynamic isCleared() method's backward-direction check (!isRollforward && prior == null && updated != null) fails because prior is now AccountX (not null) — the swap made the original "updated" into "prior". Since isCleared() returns false, the removal block in updateAccount is skipped, and since getUpdated() is null, no insertion happens either. The account remains in the trie, producing an incorrect state root. The integration test passes only because blocks 29–33 in the test data don't create any new accounts.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 584208f. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cursor-bot's mistake: it assumes the "prior→AccountX swap" happens before isCleared() is evaluated, but isCleared() is evaluated on the unmodified TrieLogLayer ZkValue. By
the time the accumulator ZkValue exists with prior=AccountX, the isCleared=true value has already been computed and stored in isCleared_field. The criticism is invalid.

…irtual block processing

Signed-off-by: garyschulte <garyschulte@gmail.com>
…ldstate trie rebuild on removal

Signed-off-by: garyschulte <garyschulte@gmail.com>
Signed-off-by: garyschulte <garyschulte@gmail.com>
Signed-off-by: garyschulte <garyschulte@gmail.com>
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 4b33263. Configure here.

…ent hash map mutation/iteration also

Signed-off-by: garyschulte <garyschulte@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant