fix(exec): EIP-7702 delegate-then-CREATE nonce-halt stopgap + defensive hardening#387
Open
Richard1048576 wants to merge 2 commits into
Open
fix(exec): EIP-7702 delegate-then-CREATE nonce-halt stopgap + defensive hardening#387Richard1048576 wants to merge 2 commits into
Richard1048576 wants to merge 2 commits into
Conversation
… defensive hardening Three hardening changes on the deterministic ordered-block execution path. Stacked on Galxe#385 (the tx_filter stopgap builds on that PR's block-order sequential filter). 1. tx_filter: CREATE-halt stopgap (gravity-audit#838). A 7702 authority delegated in-block to a non-zero delegate can, if its delegated code runs CREATE/CREATE2, have its nonce bumped a *second* time during execution — an effect the filter cannot model without executing. Any *later* same-block tx from such an account is now dropped (halt-safe over-rejection), keeping the executor's NonceTooLow -> panic path unreachable for this vector. KNOWN GAP (documented in code): does not cover an account already delegated at block start that is then called via an inner call the filter cannot see; closing that fully would require rejecting all delegated-EOA txs, which breaks legitimate 7702. The complete fix is executor-side (do not panic on a tx-level InvalidTransaction), tracked in #838 / #823. Not RPC-reachable: a future-nonce follow-up tx is parked in reth's queued sub-pool and never proposed, so this vector requires a byzantine block proposer (see #838). 2. onchain_config/metadata_txn: the free `transact_system_txn` helper returns `Result` instead of `.unwrap()`-panicking on a tx-level error (defensive; no production caller today, so wiring it into the live path later cannot reintroduce a halt). 3. onchain_config/types: validator voting-power casts use `saturating_to` + a saturating fold so a pathological `votingPower` cannot overflow-panic on the epoch-boundary NewEpochEvent path (gravity-audit#823; a safety net, only reachable above ~1.8e19 tokens for one validator, far past total supply). Verified on a Prague single-node devnet: 28 tx_filter unit tests pass (including a new stopgap test; no regression), and the Prague e2e suite passes — the only "failure" is the halt-repro test correctly NOT halting on the fixed binary, which confirms the fix.
cb8745a to
f434ee6
Compare
This was referenced Jul 11, 2026
…t ERROR A duplicate / already-committed oracle attestation rejected by NativeOracle's sequential-nonce replay guard (NonceNotSequential, selector 0x32e429cd; legacy NonceNotIncreasing 0xc778b1a4) is benign — the replay guard working as intended. It was logged at ERROR on mainnet, tripping alerting and masking real failures. Decode the revert selector, classify severity, and log recoverable system-tx reverts at WARN; unknown / fatal reverts stay ERROR. Folds gravity-reth#359 into this PR so it ships as one execute-layer change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c5c3679 to
37fe70e
Compare
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.
Three hardening changes on the deterministic ordered-block execution path (the executor
panics on any tx-levelInvalidTransaction, which halts every validator).1. CREATE-halt stopgap —
tx_filter(gravity-audit#838)A 7702 authority delegated in-block to a non-zero delegate can, if its delegated code
runs
CREATE/CREATE2, have its nonce bumped a second time during execution — aneffect the filter cannot model without executing (nonce change (1) caller bump and (2) 7702
authorization bump are modelled; (3) execution-induced CREATE bump is not). A same-block
follow-up tx that the filter admits is then
NonceTooLowin revm → executor panic → halt.Reproduced (unit-level): filter admits
[tx1, tx2], revm returnsNonceTooLow{tx:1,state:2}.This drops every later same-block tx from an account delegated earlier in the block
(halt-safe over-rejection), keeping the
NonceTooLow → panicpath unreachable for thisvector.
start that is then called via an inner call the filter cannot see; closing that fully would
require rejecting all delegated-EOA txs, which breaks legitimate 7702. The complete fix is
executor-side (do not panic on a tx-level
InvalidTransaction) — tracked in #838 / #823.sub-pool and never proposed, so this vector needs a byzantine block proposer, not an
ordinary RPC user (analysis in #838).
2.
onchain_config/metadata_txn— returnResultinstead of.unwrap()The free
transact_system_txnhelper returned(SystemTxnResult, EvmState)and.unwrap()edtransact_raw. It now returnsResult. Defensive only — no production caller today (the livepath uses the executor method), so wiring it into the live path later cannot reintroduce a
halt.
3.
onchain_config/types— saturating voting-power casts (gravity-audit#823)Validator voting-power
to::<u64/u128>()(panics on overflow) →saturating_to+ a saturatingfold, so a pathological
votingPowercannot overflow-panic on the epoch-boundaryNewEpochEventpath. A safety net: the clamp is only reachable above ~1.8e19 tokens for asingle validator (far past total supply).
Verification
Built and run on a Prague single-node devnet:
tx_filterunit tests pass, including a newtest_filter_drops_later_tx_from_in_block_delegated_authority; no regression in the existing 27.test_eip7702_authority_nonce_halt) correctly not halting on the fixed binary (head 574→735, setcode mined, stale tx dropped) — an inverted test whose "failure" confirms the fix. All P-B 7702, fix/survival, cross-account, and EIP-2935 tests pass.Also folded in — oracle replay-revert log level (was #359)
Absorbs the standalone #359 into this execute-layer PR (closing #359). On mainnet a
benign system-tx revert was logged at ERROR: a duplicate / already-committed oracle
attestation rejected by
NativeOracle's sequential-nonce replay guard(
NonceNotSequential, selector0x32e429cd; legacyNonceNotIncreasing0xc778b1a4) —the guard working as intended. This tripped alerting and masked real failures.
execute_ordered_blocknow decodes the revert selector, classifies severity, and logsrecoverable system-tx reverts at WARN; unknown / fatal reverts stay ERROR.
Touches
lib.rs(the log site) +onchain_config/errors.rs(selector decode + severity).Compiles clean (
cargo check -p reth-pipe-exec-layer-ext-v2).Related
🤖 Generated with Claude Code