fix(anvil): serialize rollback against mining to stop a mine-race panic - #16711
Open
gomesalexandre wants to merge 3 commits into
Open
fix(anvil): serialize rollback against mining to stop a mine-race panic#16711gomesalexandre wants to merge 3 commits into
gomesalexandre wants to merge 3 commits into
Conversation
anvil_rollback/anvil_reorg could unwind the chain while a concurrent multi-block evm_mine_detailed call was still mining, since do_mine_block takes the mining lock per-block but rollback never took it at all. Depending on timing this surfaced as either a confusing BlockNotFound mid-mine (an in-flight mine_one losing the parent it was building on) or an "attempt to subtract with overflow" panic in evm_mine_detailed's post-mining block lookup, which assumed the chain height read right after mining still covered every block it had just mined. rollback now holds the same mining lock do_mine_block does, and evm_mine_detailed uses checked_sub instead of assuming that subtraction always fits, so a block that no longer exists is skipped rather than panicking or wrapping. Added a regression test that races evm_mine_detailed(blocks: 50) against anvil_rollback on a multi-threaded runtime - confirmed it reliably fails against the old code (both failure modes) and passes consistently with the fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lh6V2uPTUqauqq45BM7m5k
gomesalexandre
requested review from
0xrusowsky,
DaniPopes,
figtracer,
grandizzy,
mablr,
mattsse and
stevencartavia
as code owners
September 7, 2026 14:01
Contributor
✅ Changelog foundThe deterministic check will validate the changed entry. |
decofe
previously approved these changes
Sep 7, 2026
Hold the mining guard across complete multi-block mining and detailed result collection. Use the same guarded operations for rollback and reorg so height selection and state transitions cannot interleave.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
anvil_rollback/anvil_reorgcould unwind the chain while a concurrent multi-blockevm_mine_detailedcall was still mining, becausedo_mine_blocktakes the mining lock per-block butrollbacknever took it at all.Depending on exactly when the rollback landed, this surfaced as one of two things:
BlockNotFoundmid-mine - an in-flightmine_onelosing the parent it was building on.attempt to subtract with overflowpanic inevm_mine_detailed's post-mining block lookup (crates/anvil/src/eth/api.rs), which readsbest_number()once mining finishes and assumes it's still at leastmined_blocks - 1higher than the height before the call started.Fix
Backend::rollbacknow holds the sameself.mininglockdo_mine_blockalready takes, so it can't interleave with an in-flight mine.evm_mine_detaileduseschecked_subinstead of a bare subtraction when re-deriving each mined block's number from the post-mining height, skipping a block number that no longer exists instead of panicking or wrapping. This is defense in depth - the chain height can still move between individual mine iterations, not just around the rollback lock - so it's kept even with the lock fix.Verification
Added
evm_mine_detailed_handles_concurrent_rollback: a multi-threaded-runtime test that racesevm_mine_detailed(blocks: 50)against repeatedanvil_rollbackcalls.BlockNotFoundbefore the lock fix, then the arithmetic panic once only the lock fix was applied and the narrower post-loop race was exposed).cargo test -p anvil --libfor the touched modules (eth::api::tests, plus the existingrollback-related backend test) all green.receipts
🤖 Generated with Claude Code