Skip to content

feat(l1): support bal-devnet-4 (bal@v5.7.0)#6518

Closed
edg-l wants to merge 3 commits into
mainfrom
bal-devnet-4
Closed

feat(l1): support bal-devnet-4 (bal@v5.7.0)#6518
edg-l wants to merge 3 commits into
mainfrom
bal-devnet-4

Conversation

@edg-l

@edg-l edg-l commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Brings ethrex to bal@v5.7.0 (bal-devnet-4) spec compliance. Three commits on top of main covering 9 EIPs, builder/validator parity fixes, and regression tests.

What changed

EIP-7928 (BAL)

  • Widen BlockAccessIndex u16 -> u32.
  • Shadow BAL recorder on per-tx tx_db in parallel validator with missing-entry detection across touched_addresses, storage_reads, storage_changes, code_changes.
  • Stop whitelisting SYSTEM_ADDRESS from unaccessed_pure_accounts.
  • PART B pre-state fallback for missing code_changes.

EIP-8037 (state gas 2D)

EIP-7976 / EIP-7981

  • Calldata floor 10->16 gas-per-token under Amsterdam.
  • Access-list data bytes (20/addr, 32/key) fold into floor-token count.

EIP-7708

  • Lex-ordered burn logs, no coinbase priority-fee log, SELFDESTRUCT-dest coalescing.

Builder/validator parity (commit 2613d549f)

Three miss-slot risks fixed:

  • Mempool transaction_intrinsic_gas was using TX_CREATE_GAS_COST = 53000 unconditionally; routed through intrinsic_gas_dimensions (re-exported from ethrex-vm) for Amsterdam+ so mempool admission matches VM charge.
  • fill_transactions had no EIP-8037 2D inclusion check; check_2d_gas_allowance is now pub and called before any BAL touches so rejected txs contribute nothing.
  • L2 payload builder missing BAL checkpoint/restore around undo_last_tx; added bal_checkpoint + tx_restore on both rejection paths.

Tests (commit 13422b493)

test/tests/blockchain/builder_validator_parity_tests.rs — 14 new tests:

  • 9 positive parity: builder produces block, validator accepts (empty block, simple transfer, CREATE, SSTORE, balance probe, large calldata, access list, system-address touch, multi-sender).
  • 5 negative parity: each corrupts the BAL and expects validator rejection (missing pure-access account, surplus system address, missing storage read, missing storage change, missing code change).

5 new LEVM unit test files: eip7976_7981_tests.rs, eip8037_tests.rs, eip8037_refund_tests.rs, eip8037_code_deposit_tests.rs, eip8037_top_level_failure_tests.rs.

6 EIP-8025 witness_codes_* fixtures skipped — filled against bal@v5.6.1 pre-#2711; re-enable when zkevm@v0.4.x ships.

Relationship to #6463

PR #6463 merged before this branch. The u32 widening on validate_bal_withdrawal_index and #6463's new &BalAddressIndex parameter were resolved into a combined signature on rebase. This PR does not re-introduce #6463's changes.

Priority review areas

  1. crates/vm/backends/levm/mod.rs — shadow recorder glue + parallel validator; PART B / SYSTEM_ADDRESS interactions.
  2. crates/vm/levm/src/utils.rsget_intrinsic_gas and intrinsic_gas_dimensions must stay in sync.
  3. crates/vm/levm/src/vm.rs — new state gas counters + snapshot fields on CallFrame.
  4. crates/vm/levm/src/gas_cost.rscost_per_state_byte formula.
  5. crates/blockchain/payload.rs::fill_transactions — 2D inclusion check + BAL checkpoint.
  6. test/tests/blockchain/builder_validator_parity_tests.rs — negative tests are the strongest regression guards.

Spec references

Test plan

  • make -C tooling/ef_tests/blockchain test — 8781 pass, 6 skipped (EIP-8025).
  • make run-hive-eels-amsterdam — 1342 pass / 0 fail.
  • cargo test -p ethrex-test --test ethrex_tests -- builder_validator_parity — 14 pass.
  • LEVM unit tests: new EIP-7976/7981/8037 test files pass.

edg-l added 3 commits April 23, 2026 15:08
Brings ethrex up to bal-devnet-4 fixture spec. Rolls up EIP-7928,
EIP-8037, EIP-7976, EIP-7981, EIP-7708 and misc BAL validation fixes
into one change set.

BAL (EIP-7928)
- Widen BlockAccessIndex and related recorder/index fields to u32.
- Shadow BAL recorder on per-tx tx_dbs in the parallel validator:
  diff touched_addresses / storage_reads against header BAL to catch
  missing pure-access entries and missing storage_reads.
- Fall back to pre-state code_hash in validate_tx_execution PART B
  when the BAL has no code_changes entry (missing_code_change).
- Stop whitelisting SYSTEM_ADDRESS from unaccessed_pure_accounts via
  system_seed / current_accounts_state scrubs; user-tx touches still
  remove it via the per-tx tracked_accounts path.

EIP-8037 (state gas 2D accounting)
- Dynamic cost_per_state_byte(block_gas_limit), Amsterdam only.
- Two-counter reservoir: state_gas_spill_outstanding +
  state_gas_credit_against_drain for correct revert math across
  nested sub-calls (PR #2733 clamp-and-spill).
- Per-tx 2D inclusion check (PR #2703) in sequential + parallel
  paths: reject with GAS_ALLOWANCE_EXCEEDED when tx.gas worst-case
  exceeds remaining block regular/state budget.
- intrinsic_state_gas immutable across the tx (PR #2711) and
  subtracted separately when deriving block-dimensional regular gas.
- CREATE collision/early/child failure refunds account state gas.
- Same-tx SELFDESTRUCT refunds state gas clamped against
  execution-only state gas (PR #2707), not total state_gas_used.
- Revert-path reservoir refill uses the PR #2733 X - Z formula.
- Top-level reservoir reset on tx failure (PR #2689).
- Zero gas_remaining on precompile exceptional halt so block
  accounting sees the full intrinsic.

Calldata / access-list floors
- TOTAL_COST_FLOOR_PER_TOKEN 10 -> 16 under Amsterdam (EIP-7976).
- Access-list data bytes fold into floor-token count (EIP-7981).

EIP-7708
- Lex-ordered burn logs, no coinbase priority-fee log, SELFDESTRUCT-
  destination coalescing.

Tests
- New levm tests for EIP-7976/7981, EIP-8037 refund/code-deposit/
  top-level-failure paths.
- Skip 6 zkevm@v0.3.0 EIP-8025 fixtures filled against bal@v5.6.1
  (re-enable once zkevm@v0.4.x ships).

Hive consume-engine amsterdam: 1339 pass, 3 remaining (withdrawal
missing-entry cases addressed by PR #6463, cherry-pick pending).
Addresses miss-slot risks found in the builder/validator parity audit of
the bal-devnet-4 rollup. Three builder-side paths could produce blocks
the validator rejects, plus minor hardening.

- Mempool intrinsic gas was using `TX_CREATE_GAS_COST = 53000`
  unconditionally for CREATE. Under Amsterdam the VM charges the
  `(regular, state)` split derived from `intrinsic_gas_dimensions`
  (`REGULAR_GAS_CREATE + STATE_BYTES_PER_NEW_ACCOUNT * cpsb`). Route
  through the shared helper for Amsterdam+ so admission matches VM charge.

- Payload builder (`fill_transactions`) had no EIP-8037 PR #2703 per-tx
  2D inclusion check. A tx passing execution in the builder could still
  fail the check in the validator's aggregation loop and invalidate the
  block. Expose `check_2d_gas_allowance` as pub and call it before any
  BAL touches so rejected txs contribute nothing.

- L2 payload builder recorded sender/recipient BAL touches before
  executing, with no checkpoint/restore for the `undo_last_tx` path
  (invalid L2 out-message) or apply-tx error. Mirror the L1 builder:
  take a `bal_checkpoint` after `set_bal_index`, restore on both
  rejection paths.

- `execute_block_parallel` now computes `is_amsterdam` locally and
  explicitly gates the 2D inclusion loop, keeping the Amsterdam-only
  invariant checkable rather than implicit in the caller.

- `check_2d_gas_allowance` doc now explains why our
  `block_regular_gas_used` aggregates `max(raw_regular, floor)` at
  tx-report time (matching EELS `block_output.block_gas_used`).

- Post-exec 2D overflow rollback in `apply_plain_transaction` replaces
  the unchecked `-=` on `cumulative_gas_spent` with `saturating_sub` +
  `debug_assert`.

- Missing-code-change per-tx BAL validation: when a BAL account has no
  `code_changes` entry (`seeded_pos == 0`), fall back to the
  `system_seed` / store pre-state code_hash. Fixes the remaining
  `missing_code_change` Hive test.

Hive consume-engine amsterdam: 1340 pass, 2 remaining (withdrawal
missing-entry cases addressed by PR #6463).
Regression guards for builder/validator drift on Amsterdam blocks. Both
paths share the VM core but diverge in plumbing (mempool admission,
shadow BAL recorder, 2D inclusion check, BAL checkpoint/restore, coinbase
and SYSTEM_ADDRESS filters), and a disagreement means a missed slot on
devnet that a green ef-tests run cannot catch — ef-tests only consume
blocks, never produce them.

Two groups of tests:

Positive parity (9). Builder produces a legitimate block, validator
pipeline (parallel, BAL-seeded) must accept. Covers: empty block with
only pre-exec system calls; plain transfer; CREATE tx (Amsterdam
intrinsic split); SSTORE state gas; BALANCE of untouched account
(pure-access BAL entry); calldata floor (EIP-7976); access-list floor
(EIP-7981); user-tx touch of SYSTEM_ADDRESS; multi-tx multi-sender
aggregation.

Negative parity (5). Builder produces a legitimate block, the test
corrupts the BAL (drops / mutates / appends entries), re-hashes the
header, and the validator must reject. Each scenario mirrors one of the
Hive test_bal_invalid_* cases fixed in session 3:

  parity_reject_missing_pure_access_account
  parity_reject_surplus_system_address
  parity_reject_missing_storage_read
  parity_reject_missing_storage_change
  parity_reject_missing_code_change

If one of the negative tests ever flips to "accept" the corresponding
BAL-validation check has regressed; treat as P0.
@github-actions github-actions Bot added the L1 Ethereum client label Apr 23, 2026
@github-actions

Copy link
Copy Markdown

Lines of code report

Total lines added: 646
Total lines removed: 2
Total lines changed: 648

Detailed view
+------------------------------------------------------------------------+-------+------+
| File                                                                   | Lines | Diff |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/blockchain/constants.rs                                  | 18    | +2   |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/blockchain/mempool.rs                                    | 462   | +9   |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/blockchain/payload.rs                                    | 832   | +19  |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/common/types/block_access_list.rs                        | 1107  | +15  |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/common/validation.rs                                     | 243   | -2   |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/l2/sequencer/block_producer/payload_builder.rs           | 250   | +16  |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/vm/backends/levm/mod.rs                                  | 2349  | +139 |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/vm/levm/src/call_frame.rs                                | 382   | +12  |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/vm/levm/src/environment.rs                               | 98    | +1   |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/vm/levm/src/gas_cost.rs                                  | 897   | +41  |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/vm/levm/src/hooks/default_hook.rs                        | 537   | +79  |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/vm/levm/src/opcode_handlers/stack_memory_storage_flow.rs | 327   | +1   |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/vm/levm/src/opcode_handlers/system.rs                    | 1005  | +56  |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/vm/levm/src/utils.rs                                     | 578   | +118 |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/vm/levm/src/vm.rs                                        | 694   | +136 |
+------------------------------------------------------------------------+-------+------+
| ethrex/crates/vm/lib.rs                                                | 15    | +2   |
+------------------------------------------------------------------------+-------+------+

@github-actions

Copy link
Copy Markdown

Benchmark Results Comparison

No significant difference was registered for any benchmark run.

Detailed Results

Benchmark Results: BubbleSort

Command Mean [s] Min [s] Max [s] Relative
main_revm_BubbleSort 3.247 ± 0.033 3.209 3.297 1.12 ± 0.01
main_levm_BubbleSort 2.901 ± 0.011 2.881 2.913 1.00
pr_revm_BubbleSort 3.240 ± 0.035 3.213 3.327 1.12 ± 0.01
pr_levm_BubbleSort 2.911 ± 0.023 2.893 2.971 1.00 ± 0.01

Benchmark Results: ERC20Approval

Command Mean [s] Min [s] Max [s] Relative
main_revm_ERC20Approval 1.051 ± 0.010 1.035 1.066 1.00
main_levm_ERC20Approval 1.088 ± 0.010 1.073 1.103 1.04 ± 0.01
pr_revm_ERC20Approval 1.061 ± 0.027 1.035 1.127 1.01 ± 0.03
pr_levm_ERC20Approval 1.093 ± 0.012 1.078 1.120 1.04 ± 0.02

Benchmark Results: ERC20Mint

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Mint 140.9 ± 1.8 139.5 144.4 1.00
main_levm_ERC20Mint 158.3 ± 1.6 157.2 162.7 1.12 ± 0.02
pr_revm_ERC20Mint 141.8 ± 2.8 139.0 147.7 1.01 ± 0.02
pr_levm_ERC20Mint 158.6 ± 1.7 156.8 161.1 1.13 ± 0.02

Benchmark Results: ERC20Transfer

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Transfer 249.5 ± 4.4 245.5 257.5 1.00
main_levm_ERC20Transfer 272.0 ± 5.6 267.1 283.8 1.09 ± 0.03
pr_revm_ERC20Transfer 249.8 ± 4.3 245.4 256.9 1.00 ± 0.02
pr_levm_ERC20Transfer 269.8 ± 4.9 266.1 282.3 1.08 ± 0.03

Benchmark Results: Factorial

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Factorial 229.0 ± 4.9 222.9 238.6 1.00
main_levm_Factorial 253.8 ± 8.8 249.0 277.9 1.11 ± 0.05
pr_revm_Factorial 232.5 ± 5.3 224.5 239.5 1.02 ± 0.03
pr_levm_Factorial 265.3 ± 40.8 249.0 380.7 1.16 ± 0.18

Benchmark Results: FactorialRecursive

Command Mean [s] Min [s] Max [s] Relative
main_revm_FactorialRecursive 1.636 ± 0.059 1.515 1.712 1.00
main_levm_FactorialRecursive 10.454 ± 0.059 10.389 10.602 6.39 ± 0.23
pr_revm_FactorialRecursive 1.669 ± 0.048 1.619 1.769 1.02 ± 0.05
pr_levm_FactorialRecursive 10.398 ± 0.097 10.245 10.542 6.36 ± 0.24

Benchmark Results: Fibonacci

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Fibonacci 222.5 ± 7.2 216.2 238.7 1.00
main_levm_Fibonacci 224.3 ± 4.0 222.1 235.1 1.01 ± 0.04
pr_revm_Fibonacci 228.8 ± 8.5 216.6 240.5 1.03 ± 0.05
pr_levm_Fibonacci 223.9 ± 1.4 222.8 226.1 1.01 ± 0.03

Benchmark Results: FibonacciRecursive

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_FibonacciRecursive 863.7 ± 12.8 838.8 881.4 1.37 ± 0.02
main_levm_FibonacciRecursive 628.9 ± 5.4 620.4 637.9 1.00
pr_revm_FibonacciRecursive 868.1 ± 10.9 854.2 889.4 1.38 ± 0.02
pr_levm_FibonacciRecursive 629.1 ± 4.9 621.6 637.3 1.00 ± 0.01

Benchmark Results: ManyHashes

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ManyHashes 9.1 ± 0.1 9.0 9.3 1.00 ± 0.01
main_levm_ManyHashes 10.6 ± 0.1 10.4 10.7 1.16 ± 0.01
pr_revm_ManyHashes 9.1 ± 0.1 8.9 9.2 1.00
pr_levm_ManyHashes 10.6 ± 0.1 10.4 10.9 1.17 ± 0.02

Benchmark Results: MstoreBench

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_MstoreBench 286.5 ± 5.9 279.6 296.2 1.22 ± 0.03
main_levm_MstoreBench 234.9 ± 2.2 232.7 239.6 1.00
pr_revm_MstoreBench 286.3 ± 5.8 280.1 297.6 1.22 ± 0.03
pr_levm_MstoreBench 235.4 ± 2.2 233.3 239.5 1.00 ± 0.01

Benchmark Results: Push

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Push 316.2 ± 2.5 313.7 321.5 1.08 ± 0.02
main_levm_Push 291.6 ± 3.5 289.2 300.1 1.00
pr_revm_Push 319.7 ± 5.5 313.4 327.0 1.10 ± 0.02
pr_levm_Push 292.2 ± 3.0 290.3 300.0 1.00 ± 0.02

Benchmark Results: SstoreBench_no_opt

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_SstoreBench_no_opt 177.4 ± 5.1 172.7 190.4 1.53 ± 0.07
main_levm_SstoreBench_no_opt 115.9 ± 3.7 113.9 126.2 1.00
pr_revm_SstoreBench_no_opt 176.5 ± 3.8 172.9 186.0 1.52 ± 0.06
pr_levm_SstoreBench_no_opt 116.2 ± 4.1 113.9 127.4 1.00 ± 0.05

@edg-l

edg-l commented Apr 23, 2026

Copy link
Copy Markdown
Contributor Author

Opening a fresh PR from the dedicated bal-devnet-4-pr branch. The bal-devnet-4 branch is long-lived and tracked by ethpanda's devnet tooling, so it shouldn't carry the PR lifecycle. Replacement PR follows.

@edg-l edg-l closed this Apr 23, 2026
edg-l added a commit that referenced this pull request May 6, 2026
Follow-up to PR #6518 addressing the test-gap list documented in the
session-3 review. Covers every remaining item in TODO.md except the
upstream zkevm@v0.4.x fixture re-enable (tracked externally).

Tests (10 new):

- `test_cpsb_clamp_to_one_for_tiny_gas_limit`,
  `test_cpsb_30m_bin_boundary` — cpsb quantization boundaries. Guards
  against an off-by-one in the `if quantized > CPSB_OFFSET` branch and
  against bin boundary regressions in the 5M-30M range.

- `test_change_variants_rlp_roundtrip_index_above_u16_max` — RLP
  round-trip for all 4 BAL change variants at index 70_000, guarding
  against an accidental revert to the pre-devnet-4 `u16` type that
  would silently truncate high indices.

- `amsterdam_create_intrinsic_matches_vm_dimensions` — mempool
  admission for Amsterdam CREATE txs must match the VM's `(regular,
  state)` split (TX_BASE + REGULAR_GAS_CREATE +
  STATE_BYTES_PER_NEW_ACCOUNT * cpsb), not the legacy 53000.

- `test_intrinsic_parity_plain_transfer` /
  `test_intrinsic_parity_create_tx` /
  `test_intrinsic_parity_with_calldata_and_access_list` /
  `test_intrinsic_parity_eip7702_auth_list` — parity between the
  standalone `intrinsic_gas_dimensions` helper (used by mempool and
  payload builder) and `VM::get_intrinsic_gas` (used during execution).
  Run across Prague / Osaka / Amsterdam at 30M and 120M block gas
  limits.

- `test_call_to_empty_account_with_value_retains_parent_state_gas` —
  EIP-8037 CALL-to-empty-with-value charges new-account state gas in
  the caller's frame, retained across successful parent continuation.
  Pairs with the existing `test_child_charge_then_revert_returns_state_gas_to_parent`
  for the revert direction.

Code polish:

- Clarifying comment on the `frame_outstanding_delta` invariant in
  `credit_state_gas_refund` (`crates/vm/levm/src/vm.rs`). The
  subtraction is fragile — documenting why it must read
  `state_gas_spill_outstanding` and not `state_gas_spill`.

- `debug_assert!` guards on tx count vs `u32::MAX` at each block-exec
  entry (`execute_block`, `execute_block_pipeline`), keeping the
  EIP-7928 `BlockAccessIndex` invariant explicit rather than implicit
  in the ~10 downstream `u32::try_from(...).unwrap_or(u32::MAX)` sites.

Docs:

- `docs/roadmaps/forks-roadmap.md` — EIP-7976 / EIP-7981 flipped
  🔴→✅, EIP-8037 status line expanded (dynamic cpsb, clamp-and-spill,
  2D inclusion, same-tx SELFDESTRUCT refund), priority note updated
  for bal-devnet-4 + PR #6518.

All 478 tests pass. No behavior changes — these are regression guards
and documentation for the bal-devnet-4 work landed in PR #6518.
edg-l added a commit that referenced this pull request May 6, 2026
Follow-up to PR #6518 addressing the test-gap list documented in the
session-3 review. Covers every remaining item in TODO.md except the
upstream zkevm@v0.4.x fixture re-enable (tracked externally).

Tests (10 new):

- `test_cpsb_clamp_to_one_for_tiny_gas_limit`,
  `test_cpsb_30m_bin_boundary` — cpsb quantization boundaries. Guards
  against an off-by-one in the `if quantized > CPSB_OFFSET` branch and
  against bin boundary regressions in the 5M-30M range.

- `test_change_variants_rlp_roundtrip_index_above_u16_max` — RLP
  round-trip for all 4 BAL change variants at index 70_000, guarding
  against an accidental revert to the pre-devnet-4 `u16` type that
  would silently truncate high indices.

- `amsterdam_create_intrinsic_matches_vm_dimensions` — mempool
  admission for Amsterdam CREATE txs must match the VM's `(regular,
  state)` split (TX_BASE + REGULAR_GAS_CREATE +
  STATE_BYTES_PER_NEW_ACCOUNT * cpsb), not the legacy 53000.

- `test_intrinsic_parity_plain_transfer` /
  `test_intrinsic_parity_create_tx` /
  `test_intrinsic_parity_with_calldata_and_access_list` /
  `test_intrinsic_parity_eip7702_auth_list` — parity between the
  standalone `intrinsic_gas_dimensions` helper (used by mempool and
  payload builder) and `VM::get_intrinsic_gas` (used during execution).
  Run across Prague / Osaka / Amsterdam at 30M and 120M block gas
  limits.

- `test_call_to_empty_account_with_value_retains_parent_state_gas` —
  EIP-8037 CALL-to-empty-with-value charges new-account state gas in
  the caller's frame, retained across successful parent continuation.
  Pairs with the existing `test_child_charge_then_revert_returns_state_gas_to_parent`
  for the revert direction.

Code polish:

- Clarifying comment on the `frame_outstanding_delta` invariant in
  `credit_state_gas_refund` (`crates/vm/levm/src/vm.rs`). The
  subtraction is fragile — documenting why it must read
  `state_gas_spill_outstanding` and not `state_gas_spill`.

- `debug_assert!` guards on tx count vs `u32::MAX` at each block-exec
  entry (`execute_block`, `execute_block_pipeline`), keeping the
  EIP-7928 `BlockAccessIndex` invariant explicit rather than implicit
  in the ~10 downstream `u32::try_from(...).unwrap_or(u32::MAX)` sites.

Docs:

- `docs/roadmaps/forks-roadmap.md` — EIP-7976 / EIP-7981 flipped
  🔴→✅, EIP-8037 status line expanded (dynamic cpsb, clamp-and-spill,
  2D inclusion, same-tx SELFDESTRUCT refund), priority note updated
  for bal-devnet-4 + PR #6518.

All 478 tests pass. No behavior changes — these are regression guards
and documentation for the bal-devnet-4 work landed in PR #6518.
edg-l added a commit that referenced this pull request May 6, 2026
Follow-up to PR #6518 addressing the test-gap list documented in the
session-3 review. Covers every remaining item in TODO.md except the
upstream zkevm@v0.4.x fixture re-enable (tracked externally).

Tests (10 new):

- `test_cpsb_clamp_to_one_for_tiny_gas_limit`,
  `test_cpsb_30m_bin_boundary` — cpsb quantization boundaries. Guards
  against an off-by-one in the `if quantized > CPSB_OFFSET` branch and
  against bin boundary regressions in the 5M-30M range.

- `test_change_variants_rlp_roundtrip_index_above_u16_max` — RLP
  round-trip for all 4 BAL change variants at index 70_000, guarding
  against an accidental revert to the pre-devnet-4 `u16` type that
  would silently truncate high indices.

- `amsterdam_create_intrinsic_matches_vm_dimensions` — mempool
  admission for Amsterdam CREATE txs must match the VM's `(regular,
  state)` split (TX_BASE + REGULAR_GAS_CREATE +
  STATE_BYTES_PER_NEW_ACCOUNT * cpsb), not the legacy 53000.

- `test_intrinsic_parity_plain_transfer` /
  `test_intrinsic_parity_create_tx` /
  `test_intrinsic_parity_with_calldata_and_access_list` /
  `test_intrinsic_parity_eip7702_auth_list` — parity between the
  standalone `intrinsic_gas_dimensions` helper (used by mempool and
  payload builder) and `VM::get_intrinsic_gas` (used during execution).
  Run across Prague / Osaka / Amsterdam at 30M and 120M block gas
  limits.

- `test_call_to_empty_account_with_value_retains_parent_state_gas` —
  EIP-8037 CALL-to-empty-with-value charges new-account state gas in
  the caller's frame, retained across successful parent continuation.
  Pairs with the existing `test_child_charge_then_revert_returns_state_gas_to_parent`
  for the revert direction.

Code polish:

- Clarifying comment on the `frame_outstanding_delta` invariant in
  `credit_state_gas_refund` (`crates/vm/levm/src/vm.rs`). The
  subtraction is fragile — documenting why it must read
  `state_gas_spill_outstanding` and not `state_gas_spill`.

- `debug_assert!` guards on tx count vs `u32::MAX` at each block-exec
  entry (`execute_block`, `execute_block_pipeline`), keeping the
  EIP-7928 `BlockAccessIndex` invariant explicit rather than implicit
  in the ~10 downstream `u32::try_from(...).unwrap_or(u32::MAX)` sites.

Docs:

- `docs/roadmaps/forks-roadmap.md` — EIP-7976 / EIP-7981 flipped
  🔴→✅, EIP-8037 status line expanded (dynamic cpsb, clamp-and-spill,
  2D inclusion, same-tx SELFDESTRUCT refund), priority note updated
  for bal-devnet-4 + PR #6518.

All 478 tests pass. No behavior changes — these are regression guards
and documentation for the bal-devnet-4 work landed in PR #6518.
edg-l added a commit that referenced this pull request May 7, 2026
Follow-up to PR #6518 addressing the test-gap list documented in the
session-3 review. Covers every remaining item in TODO.md except the
upstream zkevm@v0.4.x fixture re-enable (tracked externally).

Tests (10 new):

- `test_cpsb_clamp_to_one_for_tiny_gas_limit`,
  `test_cpsb_30m_bin_boundary` — cpsb quantization boundaries. Guards
  against an off-by-one in the `if quantized > CPSB_OFFSET` branch and
  against bin boundary regressions in the 5M-30M range.

- `test_change_variants_rlp_roundtrip_index_above_u16_max` — RLP
  round-trip for all 4 BAL change variants at index 70_000, guarding
  against an accidental revert to the pre-devnet-4 `u16` type that
  would silently truncate high indices.

- `amsterdam_create_intrinsic_matches_vm_dimensions` — mempool
  admission for Amsterdam CREATE txs must match the VM's `(regular,
  state)` split (TX_BASE + REGULAR_GAS_CREATE +
  STATE_BYTES_PER_NEW_ACCOUNT * cpsb), not the legacy 53000.

- `test_intrinsic_parity_plain_transfer` /
  `test_intrinsic_parity_create_tx` /
  `test_intrinsic_parity_with_calldata_and_access_list` /
  `test_intrinsic_parity_eip7702_auth_list` — parity between the
  standalone `intrinsic_gas_dimensions` helper (used by mempool and
  payload builder) and `VM::get_intrinsic_gas` (used during execution).
  Run across Prague / Osaka / Amsterdam at 30M and 120M block gas
  limits.

- `test_call_to_empty_account_with_value_retains_parent_state_gas` —
  EIP-8037 CALL-to-empty-with-value charges new-account state gas in
  the caller's frame, retained across successful parent continuation.
  Pairs with the existing `test_child_charge_then_revert_returns_state_gas_to_parent`
  for the revert direction.

Code polish:

- Clarifying comment on the `frame_outstanding_delta` invariant in
  `credit_state_gas_refund` (`crates/vm/levm/src/vm.rs`). The
  subtraction is fragile — documenting why it must read
  `state_gas_spill_outstanding` and not `state_gas_spill`.

- `debug_assert!` guards on tx count vs `u32::MAX` at each block-exec
  entry (`execute_block`, `execute_block_pipeline`), keeping the
  EIP-7928 `BlockAccessIndex` invariant explicit rather than implicit
  in the ~10 downstream `u32::try_from(...).unwrap_or(u32::MAX)` sites.

Docs:

- `docs/roadmaps/forks-roadmap.md` — EIP-7976 / EIP-7981 flipped
  🔴→✅, EIP-8037 status line expanded (dynamic cpsb, clamp-and-spill,
  2D inclusion, same-tx SELFDESTRUCT refund), priority note updated
  for bal-devnet-4 + PR #6518.

All 478 tests pass. No behavior changes — these are regression guards
and documentation for the bal-devnet-4 work landed in PR #6518.
edg-l added a commit that referenced this pull request May 7, 2026
Follow-up to PR #6518 addressing the test-gap list documented in the
session-3 review. Covers every remaining item in TODO.md except the
upstream zkevm@v0.4.x fixture re-enable (tracked externally).

Tests (10 new):

- `test_cpsb_clamp_to_one_for_tiny_gas_limit`,
  `test_cpsb_30m_bin_boundary` — cpsb quantization boundaries. Guards
  against an off-by-one in the `if quantized > CPSB_OFFSET` branch and
  against bin boundary regressions in the 5M-30M range.

- `test_change_variants_rlp_roundtrip_index_above_u16_max` — RLP
  round-trip for all 4 BAL change variants at index 70_000, guarding
  against an accidental revert to the pre-devnet-4 `u16` type that
  would silently truncate high indices.

- `amsterdam_create_intrinsic_matches_vm_dimensions` — mempool
  admission for Amsterdam CREATE txs must match the VM's `(regular,
  state)` split (TX_BASE + REGULAR_GAS_CREATE +
  STATE_BYTES_PER_NEW_ACCOUNT * cpsb), not the legacy 53000.

- `test_intrinsic_parity_plain_transfer` /
  `test_intrinsic_parity_create_tx` /
  `test_intrinsic_parity_with_calldata_and_access_list` /
  `test_intrinsic_parity_eip7702_auth_list` — parity between the
  standalone `intrinsic_gas_dimensions` helper (used by mempool and
  payload builder) and `VM::get_intrinsic_gas` (used during execution).
  Run across Prague / Osaka / Amsterdam at 30M and 120M block gas
  limits.

- `test_call_to_empty_account_with_value_retains_parent_state_gas` —
  EIP-8037 CALL-to-empty-with-value charges new-account state gas in
  the caller's frame, retained across successful parent continuation.
  Pairs with the existing `test_child_charge_then_revert_returns_state_gas_to_parent`
  for the revert direction.

Code polish:

- Clarifying comment on the `frame_outstanding_delta` invariant in
  `credit_state_gas_refund` (`crates/vm/levm/src/vm.rs`). The
  subtraction is fragile — documenting why it must read
  `state_gas_spill_outstanding` and not `state_gas_spill`.

- `debug_assert!` guards on tx count vs `u32::MAX` at each block-exec
  entry (`execute_block`, `execute_block_pipeline`), keeping the
  EIP-7928 `BlockAccessIndex` invariant explicit rather than implicit
  in the ~10 downstream `u32::try_from(...).unwrap_or(u32::MAX)` sites.

Docs:

- `docs/roadmaps/forks-roadmap.md` — EIP-7976 / EIP-7981 flipped
  🔴→✅, EIP-8037 status line expanded (dynamic cpsb, clamp-and-spill,
  2D inclusion, same-tx SELFDESTRUCT refund), priority note updated
  for bal-devnet-4 + PR #6518.

All 478 tests pass. No behavior changes — these are regression guards
and documentation for the bal-devnet-4 work landed in PR #6518.
edg-l added a commit that referenced this pull request May 8, 2026
Follow-up to PR #6518 addressing the test-gap list documented in the
session-3 review. Covers every remaining item in TODO.md except the
upstream zkevm@v0.4.x fixture re-enable (tracked externally).

Tests (10 new):

- `test_cpsb_clamp_to_one_for_tiny_gas_limit`,
  `test_cpsb_30m_bin_boundary` — cpsb quantization boundaries. Guards
  against an off-by-one in the `if quantized > CPSB_OFFSET` branch and
  against bin boundary regressions in the 5M-30M range.

- `test_change_variants_rlp_roundtrip_index_above_u16_max` — RLP
  round-trip for all 4 BAL change variants at index 70_000, guarding
  against an accidental revert to the pre-devnet-4 `u16` type that
  would silently truncate high indices.

- `amsterdam_create_intrinsic_matches_vm_dimensions` — mempool
  admission for Amsterdam CREATE txs must match the VM's `(regular,
  state)` split (TX_BASE + REGULAR_GAS_CREATE +
  STATE_BYTES_PER_NEW_ACCOUNT * cpsb), not the legacy 53000.

- `test_intrinsic_parity_plain_transfer` /
  `test_intrinsic_parity_create_tx` /
  `test_intrinsic_parity_with_calldata_and_access_list` /
  `test_intrinsic_parity_eip7702_auth_list` — parity between the
  standalone `intrinsic_gas_dimensions` helper (used by mempool and
  payload builder) and `VM::get_intrinsic_gas` (used during execution).
  Run across Prague / Osaka / Amsterdam at 30M and 120M block gas
  limits.

- `test_call_to_empty_account_with_value_retains_parent_state_gas` —
  EIP-8037 CALL-to-empty-with-value charges new-account state gas in
  the caller's frame, retained across successful parent continuation.
  Pairs with the existing `test_child_charge_then_revert_returns_state_gas_to_parent`
  for the revert direction.

Code polish:

- Clarifying comment on the `frame_outstanding_delta` invariant in
  `credit_state_gas_refund` (`crates/vm/levm/src/vm.rs`). The
  subtraction is fragile — documenting why it must read
  `state_gas_spill_outstanding` and not `state_gas_spill`.

- `debug_assert!` guards on tx count vs `u32::MAX` at each block-exec
  entry (`execute_block`, `execute_block_pipeline`), keeping the
  EIP-7928 `BlockAccessIndex` invariant explicit rather than implicit
  in the ~10 downstream `u32::try_from(...).unwrap_or(u32::MAX)` sites.

Docs:

- `docs/roadmaps/forks-roadmap.md` — EIP-7976 / EIP-7981 flipped
  🔴→✅, EIP-8037 status line expanded (dynamic cpsb, clamp-and-spill,
  2D inclusion, same-tx SELFDESTRUCT refund), priority note updated
  for bal-devnet-4 + PR #6518.

All 478 tests pass. No behavior changes — these are regression guards
and documentation for the bal-devnet-4 work landed in PR #6518.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

L1 Ethereum client

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant