Skip to content

fix(tests): rewrite ported static gas-snapshot tests with fork-derived measurements - #36

Draft
spencer-tb wants to merge 1 commit into
ported-static-gas-limit-wavefrom
ported-static-snapshot-rewrites
Draft

spencer-tb wants to merge 1 commit into
ported-static-gas-limit-wavefrom
ported-static-snapshot-rewrites

Conversation

@spencer-tb

Copy link
Copy Markdown
Owner

Description

Rewrites the gas-snapshot ported static tests (raw GAS reads / SUB(GAS, ...) deltas — the fragile shape that pins gas schedules) with fork-derived measurements: CodeGasMeasure windows, opcode-metadata composites, and derived budgets. 46 files across byzantium/frontier/tangerine_whistle/berlin/spurious_dragon/constantinople/istanbul; floors lowered where the rewrite unlocked them (several Cancun → Berlin/Byzantium/Frontier) and two valid_until("Prague") caps removed (tests now run on Osaka/Amsterdam). Three degraded ports restored along the way (never-dispatched failure modes, vacuous call targets, dropped pre-EIP-3651 cold-coinbase coverage). Every file full-range fill-verified through Amsterdam.

Related Issues or PRs

Part of ethereum#3272. Stacks on the gas-limit hygiene PR (#35).

Checklist

  • Ran fast static checks: just static
  • PR title has the form <type>(<area>): <title>

spencer-tb pushed a commit that referenced this pull request Oct 5, 2026
)

* feat(test-specs): add the invalid_tx_not_last marker

* feat(tests): cover order-dependent transaction validity in a block

* feat(tests): cover BAL cross-tx hazards of parallel execution

* feat(tests): cover a 7702 authorization staled by a prior tx

* feat(tests): widen BAL cross-tx hazard coverage

Extend the read-before-write test to five transactions with a reverted last write, add a balance read before a later transfer or withdrawal, a cold-access check across two transactions, a 7702 delegation arm on the code-reads test, and receipt pins on the coinbase burners.

* feat(tests): cover a 7702 authorization made valid by a prior tx

The positive twin of the stale-nonce arm: a plain transaction from the authority bumps its nonce to the one the authorization signed, and the delegation must be applied.

* fix(tests): put the invalid first tx's sender in the block access list

The trailing transaction now sends value to the unfunded sender instead of to a bystander. That lists the sender in the block access list, so a client that reads state through the list reaches the funds check instead of failing on the missing account, and it makes the case a stronger trap: a client that applies the later credit before checking the first transaction accepts the block. Every fork still fills; the Amsterdam engine payload now carries the sender.

* feat(tests): reject a BAL missing an account touched by any read path

Widen the missing-account negative from two scenarios to eight: a zero-value CALL and a STATICCALL to an EOA, a precompile, the code source behind a delegated EOA, the authority of a failed authorization, and a read inside a frame that reverts. Each is a different client path to the same empty entry, so a client that builds its list from one path and not another fails the one it skips.

* docs(test-markers): put a rejected transaction's sender in the BAL

The transition tool skips a rejected transaction, so its sender only enters the block access list through another transaction. A client that loads accounts from the list then rejects the block for the missing account rather than for the reason under test, as reth did on the invalid-first fixture. Tell invalid_tx_not_last users to have a valid transaction send value to that sender when the rejection depends on its account.

* docs(tests): point the missing-account negative at its positive tests

One sentence so the next reader knows the failed-authorization presence is already pinned by the invalid-nonce test and this arm only covers the rejection.

* feat(tests): cover a rejected block leaving nonce and balance untouched

The next block spends the same nonce and the exact balance the rejected transaction claimed to need, so a client that consumed either on rejection fails it. One arm trails a valid transaction from a second sender behind the rejected one and replays it at the same nonce, pinning that trailing transactions leave no trace either. The fork-transition tests retry a transaction across blocks but their validity flips with the rules; none pinned this.

* chore: clean up AI verbosity

* refactor(tests): fold the nonce-order case into the invalid-first test

Both are a block whose first transaction is invalid and would have been valid had the one after it run first, so they share one test with a cause axis: an unfunded sender funded later, or a nonce 1 arriving before its nonce 0. The three-transaction gap-then-fill arm is dropped; it was the same case with an extra transaction in front.

* refactor(tests): replay the trailing tx after an invalid-first block

The next block replays the valid transaction that trailed the rejected one, at the same nonce, so the invalid-first test also pins that a trailing transaction in a rejected block leaves no trace. That was the only part of the rejected-block test worth keeping, so it is removed; its other arm, a rejected block deducting nothing, is table stakes that fails elsewhere first.

* refactor(tests): drop the funds-spent test as a duplicate

Cancun's test_insufficient_balance_blob_tx_combinations already sends several transactions from one sender funded at their combined cost minus one wei and rejects the last, with an exact-balance twin. The frontier version only added legacy transaction types, over the same upfront-balance check.

* refactor(tests): merge the 7702 nonce authorization tests

One test, three cases: an authorization nonce wrong in the pre-state, one made stale by the authority's own earlier transaction, and one made valid by it. The last two are a boundary pair around the nonce after the prior transaction, and the case ids say which is which, so the invalid and valid tests no longer need separate names.

* test(tests): tie the invalid-first test to BAL parallel execution

Say in the docstring that the test guards clients executing a block's transactions in parallel, pin the sender's block access list entry in both blocks from Amsterdam on (index 2 in the rejected block, index 1 in the replay), and add its row to the EIP-7928 test cases table.

* suggestions (#36)

---------

Co-authored-by: Mario Vega <marioevz@gmail.com>
spencer-tb pushed a commit that referenced this pull request Oct 5, 2026
)

* feat(test-specs): add the invalid_tx_not_last marker

* feat(tests): cover order-dependent transaction validity in a block

* feat(tests): cover BAL cross-tx hazards of parallel execution

* feat(tests): cover a 7702 authorization staled by a prior tx

* feat(tests): widen BAL cross-tx hazard coverage

Extend the read-before-write test to five transactions with a reverted last write, add a balance read before a later transfer or withdrawal, a cold-access check across two transactions, a 7702 delegation arm on the code-reads test, and receipt pins on the coinbase burners.

* feat(tests): cover a 7702 authorization made valid by a prior tx

The positive twin of the stale-nonce arm: a plain transaction from the authority bumps its nonce to the one the authorization signed, and the delegation must be applied.

* fix(tests): put the invalid first tx's sender in the block access list

The trailing transaction now sends value to the unfunded sender instead of to a bystander. That lists the sender in the block access list, so a client that reads state through the list reaches the funds check instead of failing on the missing account, and it makes the case a stronger trap: a client that applies the later credit before checking the first transaction accepts the block. Every fork still fills; the Amsterdam engine payload now carries the sender.

* feat(tests): reject a BAL missing an account touched by any read path

Widen the missing-account negative from two scenarios to eight: a zero-value CALL and a STATICCALL to an EOA, a precompile, the code source behind a delegated EOA, the authority of a failed authorization, and a read inside a frame that reverts. Each is a different client path to the same empty entry, so a client that builds its list from one path and not another fails the one it skips.

* docs(test-markers): put a rejected transaction's sender in the BAL

The transition tool skips a rejected transaction, so its sender only enters the block access list through another transaction. A client that loads accounts from the list then rejects the block for the missing account rather than for the reason under test, as reth did on the invalid-first fixture. Tell invalid_tx_not_last users to have a valid transaction send value to that sender when the rejection depends on its account.

* docs(tests): point the missing-account negative at its positive tests

One sentence so the next reader knows the failed-authorization presence is already pinned by the invalid-nonce test and this arm only covers the rejection.

* feat(tests): cover a rejected block leaving nonce and balance untouched

The next block spends the same nonce and the exact balance the rejected transaction claimed to need, so a client that consumed either on rejection fails it. One arm trails a valid transaction from a second sender behind the rejected one and replays it at the same nonce, pinning that trailing transactions leave no trace either. The fork-transition tests retry a transaction across blocks but their validity flips with the rules; none pinned this.

* chore: clean up AI verbosity

* refactor(tests): fold the nonce-order case into the invalid-first test

Both are a block whose first transaction is invalid and would have been valid had the one after it run first, so they share one test with a cause axis: an unfunded sender funded later, or a nonce 1 arriving before its nonce 0. The three-transaction gap-then-fill arm is dropped; it was the same case with an extra transaction in front.

* refactor(tests): replay the trailing tx after an invalid-first block

The next block replays the valid transaction that trailed the rejected one, at the same nonce, so the invalid-first test also pins that a trailing transaction in a rejected block leaves no trace. That was the only part of the rejected-block test worth keeping, so it is removed; its other arm, a rejected block deducting nothing, is table stakes that fails elsewhere first.

* refactor(tests): drop the funds-spent test as a duplicate

Cancun's test_insufficient_balance_blob_tx_combinations already sends several transactions from one sender funded at their combined cost minus one wei and rejects the last, with an exact-balance twin. The frontier version only added legacy transaction types, over the same upfront-balance check.

* refactor(tests): merge the 7702 nonce authorization tests

One test, three cases: an authorization nonce wrong in the pre-state, one made stale by the authority's own earlier transaction, and one made valid by it. The last two are a boundary pair around the nonce after the prior transaction, and the case ids say which is which, so the invalid and valid tests no longer need separate names.

* test(tests): tie the invalid-first test to BAL parallel execution

Say in the docstring that the test guards clients executing a block's transactions in parallel, pin the sender's block access list entry in both blocks from Amsterdam on (index 2 in the rejected block, index 1 in the replay), and add its row to the EIP-7928 test cases table.

* suggestions (#36)

---------

Co-authored-by: Mario Vega <marioevz@gmail.com>

This branch has not been deployed

No deployments
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