# bal-devnet-4 spec :::info :mega: bal-devnet-4 target launch: **22.04**. ::: :::info ❗ EIP-8037: bal-devnet-4 switches from the **static** `cost_per_state_byte = 1174` used in bal-devnet-3 to the **full EIP variant** where `cpsb` is **derived from the block gas limit** (quantized via `CPSB_SIGNIFICANT_BITS = 5`, `CPSB_OFFSET = 9578`). ::: :::info ❗ Primary focus of this devnet is **EIP-8037 stabilization**: picking up the spec clarifications, follow-up tests, and the spec decisions from the [state gas accounting review](https://github.com/misilva73/evm-gas-repricings/blob/main/reports/eip-8037/spec_review_state_gas_accounting.md). ::: :::info ❗ **EIP-7976 and EIP-7981 must be implemented** by all EL clients for bal-devnet-4. Both were added post-ACDT; spec/test side is ready, client implementations are the remaining gate. ::: :::success ✅ **All 7 EIP-8037 state gas accounting decisions resolved** at Glamsterdam Repricing Breakout #6 (2026-04-15). [Recording](https://www.youtube.com/watch?v=U8RvbLPX188). See "Changes vs. bal-devnet-3" below for the full decision list. ::: ## EIP List for bal-devnet-4 | EIP | Title | Status | |--------|------|--------| | [EIP-7708](https://eips.ethereum.org/EIPS/eip-7708) | ETH transfers emit a log | | | [EIP-7778](https://eips.ethereum.org/EIPS/eip-7778) | Block Gas Accounting without Refunds | | | [EIP-7843](https://eips.ethereum.org/EIPS/eip-7843) | SLOTNUM opcode | | | [EIP-7928](https://eips.ethereum.org/EIPS/eip-7928) | Block-Level Access Lists | | | [EIP-7954](https://eips.ethereum.org/EIPS/eip-7954) | Increase Maximum Contract Size | | | [EIP-7975](https://eips.ethereum.org/EIPS/eip-7975) | eth/70 – partial block receipt lists | optional | | [EIP-8024](https://eips.ethereum.org/EIPS/eip-8024) | Backward compatible SWAPN, DUPN, EXCHANGE | | | [EIP-8037](https://eips.ethereum.org/EIPS/eip-8037) | State Creation Gas Cost Increase — **dynamic `cpsb`** :exclamation: | :up: | | [EIP-8159](https://eips.ethereum.org/EIPS/eip-8159) | eth/71 – Block Access List Exchange | optional | | [EIP-7976](https://eips.ethereum.org/EIPS/eip-7976) | Increase Calldata Floor Cost (64/64) | :new: | | [EIP-7981](https://eips.ethereum.org/EIPS/eip-7981) | Increase Access List Cost | :new: | **Key:** - :up: EIP has updated since bal-devnet-3 - :new: New EIP added --- ## Changes vs. bal-devnet-3 | Area | bal-devnet-3 | bal-devnet-4 | |------|--------------|--------------| | EIP-8037 `cost_per_state_byte` | Hardcoded `1174` (fork constant) | **Dynamic**, derived from header gas limit (quantized) | | EIP-8037 CREATE initcode ordering | Pre-check charge | Charge moved **after** initcode size validation ([specs#2608](https://github.com/ethereum/execution-specs/pull/2608)) | | EIP-8037 cross-EIP interaction | — | EIP-8024 + EIP-8037 test regressions fixed ([specs#2656](https://github.com/ethereum/execution-specs/pull/2656)) | | EIP-8037 test coverage | `bal@v5.6.1` | New release with additional state-gas edge case coverage (see Execution Specs below) | | Top-level reservoir refund | State gas persists on top-level failure | **Zeroed on failure** — [EIPs#11476](https://github.com/ethereum/EIPs/pull/11476); unblocks [execution-specs#2609](https://github.com/ethereum/execution-specs/pull/2609) | | 0→x→0 SSTORE reservoir refill | Refund via capped `refund_counter` (20%) | **Refund directly to reservoir** — no cap. Timing TBD: at `x→0` point or end of tx. EIP PR needed. | | CREATE failure state gas | Charged unconditionally in caller frame | **Upfront charge kept, refund to reservoir** on silent failure (balance, nonce, collision, stack depth). EIP PR needed. | | Same-tx SELFDESTRUCT refund | No refund of create state gas | **Refund state gas + storage costs** to reservoir at end of tx when SELFDESTRUCT destroys a same-tx-created account. EIP PR needed. | | CALL to self-destructed same-tx account | No state gas charge (`is_account_alive` correct) | **No change** — behaviour is correct. Test added in [execution-specs#2646](https://github.com/ethereum/execution-specs/pull/2646). | | EIP-7702 `intrinsic_state_gas` | Mutated mid-execution on delegation to existing account | **Stop mutating** — keep worst-case upfront charge, refund to reservoir when auth targets existing account. EIP PR needed. | | Tx inclusion validity | 1D regular-gas check only | **2D check** — both regular gas and state gas validated per-tx before execution. [EIPs#11503](https://github.com/ethereum/EIPs/pull/11503) needs update. | | Spillover classification | Ambiguous (bal-devnet-3 client split root cause) | **Clarified** — [EIPs#11522](https://github.com/ethereum/EIPs/pull/11522) merged 2026-04-14 | --- ## Execution Layer Client Support | EIP | Geth | Besu | Reth | Nethermind | Erigon | Nimbus-EL | Ethrex | |-----| :----:|:----:|:----:|:----------:|:------:|:---------:|:------:| | 7708 (ETH Logs) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | 7778 (Gas Refunds) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | 7843 (SLOTNUM) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | 7928 (BAL) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | 7954 (MContract) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | 7975 (eth/70) | ✅ | :hammer: | ❌ | ✅ | ❌ | ❌ | ✅ | | 8024 (SWAPN/DUPN) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | 8037 (dyn-cpsb) | :hammer: | :hammer: | :hammer: | :hammer: | :hammer: | :hammer: | :hammer: | | 7976 (Calldata) | :hammer: | :hammer: | :hammer: | :hammer: | :hammer: | :hammer: | :hammer: | | 7981 (AL Cost) | :hammer: | :hammer: | :hammer: | :hammer: | :hammer: | :hammer: | :hammer: | | 8159 (eth/71) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | :hammer: | ### bal-devnet-3 regression status (needs re-verification on devnet-4 branches) | Bug | Client | Status | Reference | |-----|--------|--------|-----------| | Nethermind: tx gas-limit validated against 1D `header.GasUsed` — artificially shrinks available budget when state dim dominates | Nethermind | Fixed on `bal-devnet-3` branch | [nethermind compare](https://github.com/NethermindEth/nethermind/compare/bal-devnet-3...qu0b:qu0b/fix/stategas-create-failure) | | Besu: reservoir consumed on top-level exceptional halt after child spill-restore (delta = `112 × cpsb`) | Besu | Fixed in `f4c8b36` | [besu compare](https://github.com/besu-eth/besu/compare/bal-devnet-3...qu0b:qu0b/fix/reservoir-zero-on-halt) | | Geth: nested CREATE failure incorrectly restores `GAS_NEW_ACCOUNT` to parent reservoir | Geth | Reported | execution-specs#2639 / [test `test_inner_create_state_gas_persists_on_failure`](https://github.com/ethereum/execution-specs/pull/2639) | | Erigon: 2D gas pool | Erigon | Fixed on `bal-devnet-3` | [erigon compare](https://github.com/erigontech/erigon/compare/bal-devnet-3...qu0b:qu0b/fix/gaspool-2d) | --- ## Consensus Layer Support | Feature/EIP | Lodestar | Lighthouse | Prysm | |-------------|----------|------------|-------| | EIP-7928 | ✅ | ✅ | bal-devnet-1 | | EIP-7843 | ✅ | ✅ | ❌ | No CL spec changes required for bal-devnet-4 (same as bal-devnet-3). CL teams only need to rebuild against `devnets/bal/4` tagged images. --- ## Test Releases - **Consensus Specs:** [`v1.6.1`](https://github.com/ethereum/consensus-specs/releases/tag/v1.6.1) — unchanged from bal-devnet-3. - **Execution Specs:** `bal@v5.7.0` (**TBD**). Current bal-devnet-3 release is [`bal@v5.6.1`](https://github.com/ethereum/execution-spec-tests/releases/tag/bal@v5.6.1). --- ## Spec versions required & Open PRs ### EIP updates included (merged since bal-devnet-3 cut) | PR | Title | Merged | |----|-------|--------| | [#11522](https://github.com/ethereum/EIPs/pull/11522) | Clarify spillover state gas still increments `execution_state_gas_used` | 2026-04-14 | ### EIP PRs — 8037 state gas accounting (decisions from 2026-04-15) | PR | Title | Status | Action | |----|-------|--------|--------| | [#11476](https://github.com/ethereum/EIPs/pull/11476) | Refund state gas on all frame failures including top level | ✅ Decided | **Merge.** [#11468](https://github.com/ethereum/EIPs/pull/11468) closed as superseded. | | [#11503](https://github.com/ethereum/EIPs/pull/11503) | Add additional tx validity condition | ✅ Decided | **Needs update** — add state gas dimension to the per-tx inclusion check (2D bottleneck). | | [#11522](https://github.com/ethereum/EIPs/pull/11522) | Clarify spillover state gas still increments `execution_state_gas_used` | ✅ Merged | Merged 2026-04-14. | | [#11523](https://github.com/ethereum/EIPs/pull/11523) | Clarifications for state gas accounting (review items 3-6) | ⚠️ Outdated | **Needs rewrite.** Items 3, 4, 6 reversed from "accept-and-document" to "refund to reservoir". Only item 5 (CALL to self-destructed account) remains unchanged. | | [#10542](https://github.com/ethereum/EIPs/pull/10542) | Access-list based deduplication and success/failure cases | Draft | Needs rebase; low priority for devnet-4. | EIP PRs still needed (decisions made, no PRs yet): 1. **0→x→0 SSTORE reservoir refill** — refund state gas directly to reservoir instead of capped `refund_counter`. Timing (at `x→0` vs end of tx) still open. 2. **CREATE failure refund** — keep upfront charge, refund state gas to reservoir on silent failure (balance, nonce, collision, stack depth). 3. **Same-tx SELFDESTRUCT refund** — refund state gas + storage costs to reservoir at end of tx (EIP-6780 interaction). 4. **EIP-7702 `intrinsic_state_gas`** — stop mid-execution mutation; keep worst-case upfront, refund to reservoir when auth targets existing account. ### Other EIPs — open PRs to consider for bal-devnet-4 Sweep of the non-8037 EIPs already in the bal-devnet-4 list. Surface in `#all-el` before cutting. | PR | EIP | Title | Author | Status | Recommendation | |----|-----|-------|--------|--------|----------------| | [EIPs#11474](https://github.com/ethereum/EIPs/pull/11474) | 7708 | Add `CREATE` and `CREATE2` to transfer log list | s1na | Open, MERGEABLE (2026-04-01) | **Include.** Substantive scope addition — every EL must emit ETH-transfer logs on contract creation, not just `CALL`. Land before cut so all clients align. | | [EIPs#10493](https://github.com/ethereum/EIPs/pull/10493) | 7928 | Clarify edge cases | Marchhill | Open, CONFLICTING (6 mo. stale) | **Pull items into a fresh PR.** Real spec gaps: zero-value balance-change recording, CALL/CALLCODE/CREATE balance changes, failed EIP-7702 delegation address inclusion. Author hasn't rebased since 2025-10. | | [EIPs#11226](https://github.com/ethereum/EIPs/pull/11226) | 7976 | Add EIP-3860 to requires header | BitcoinPro9246 | Open, MERGEABLE | **Conditional on 7976 entering scope.** Trivial header tweak. | EIP-7976 / EIP-7981 readiness (both authored by nerolation, both in Draft): - **Spec text:** in `EIPs/EIPS/eip-7976.md` and `eip-7981.md`. Recent merges: [EIPs#11499](https://github.com/ethereum/EIPs/pull/11499) (2026-04-09, sync with EIP-8007), [EIPs#11340](https://github.com/ethereum/EIPs/pull/11340) (2026-03-27, align 7981 with 7976). - **eest tests:** [specs#2115](https://github.com/ethereum/execution-specs/pull/2115) (EIP-7976) and [specs#2144](https://github.com/ethereum/execution-specs/pull/2144) (EIP-7981), both merged 2026-02-24. EELS spec for 7981 in [EIPs#10225](https://github.com/ethereum/EIPs/pull/10225). - **Gate:** ACDT scope decision + EL client implementation. Spec/test side is ready. Skipped (cosmetic / draft / low-impact): EIPs#11160 (7708 test-case docs), EIPs#9873 (7928 BAL linear-scaling note, draft), EIPs#10123 (7975 typo). ### Execution Specs — merged since bal-devnet-3 cut (`bal@v5.6.1`) | PR | Title | Author | |----|-------|--------| | [#2656](https://github.com/ethereum/execution-specs/pull/2656) | `fix(tests-eip-8024)`: Fix cross-eip failures (EIP-8037) | marioevz | Upstream branch `eips/amsterdam/eip-8037` also carries `refactor(tests-eip8037): Condition tests to EIP inclusion`, `feat(test-forks): Add EIP-8037 to Amsterdam`, `fix(tests): Use pytest.mark.valid_before for EIP-8037`, and a lint fix — these need to roll into the next `bal@` release. ### Execution Specs — tests already in `bal@v5.6.1` for conditional EIPs Coverage for the ACDT-pending EIPs is already in the current release. If 7976/7981 enter scope, no additional eest work is required — only client implementations. | PR | Title | Author | Merged | |----|-------|--------|--------| | [#2115](https://github.com/ethereum/execution-specs/pull/2115) | `feat(tests)`: adds EIP-7976 test and required framework changes | nerolation | 2026-02-24 | | [#2144](https://github.com/ethereum/execution-specs/pull/2144) | `feat(tests)`: adds EIP-7981 test and required framework changes | nerolation | 2026-02-24 | ### Execution Specs — open PRs targeting bal-devnet-4 | PR | Title | Author | Note | |----|-------|--------|------| | [#2639](https://github.com/ethereum/execution-specs/pull/2639) | `feat(tests)`: EIP-8037 additional state gas test coverage | spencer-tb | Closed 2026-04-14 without merge — tests being reworked. | | [#2609](https://github.com/ethereum/execution-specs/pull/2609) | `eip-8037`: refund execution state gas on top-level failure | qu0b | Implements EIPs#11476. ✅ Decision made — merge. | | [#2646](https://github.com/ethereum/execution-specs/pull/2646) | `feat(tests)` EIP-8037 CALL with value to self-destructed acct | kclowes | Covers scenario 5 from the [state gas accounting review](https://github.com/misilva73/evm-gas-repricings/blob/main/reports/eip-8037/spec_review_state_gas_accounting.md); safe to include. | | [#2615](https://github.com/ethereum/execution-specs/pull/2615) | `chore(tests)`: sync ported_static tests with forks/amsterdam | leolara | Cleans up the ported-static discrepancy reported on 2026-04-09. | | [#2620](https://github.com/ethereum/execution-specs/pull/2620) | `fix(specs)`: Fix sstore static fails | kclowes | | | [#2618](https://github.com/ethereum/execution-specs/pull/2618) | Fix `test_measure_gas` tests for Amsterdam | kclowes | | ### Execution Specs — open issues to track | Issue | Title | |-------|-------| | [specs#1938](https://github.com/ethereum/execution-specs/issues/1938) | EIP-7928 test vector metadata — carried from bal-devnet-3 | ### Execution APIs No new PRs required for bal-devnet-4. Continue to depend on the JSON-RPC additions merged for devnet-3 ([#726](https://github.com/ethereum/execution-apis/pull/726), [#748](https://github.com/ethereum/execution-apis/pull/748), [#746](https://github.com/ethereum/execution-apis/pull/746)). ### Networking / devp2p No devp2p changes for bal-devnet-4. --- ## Client BAL features Unchanged from bal-devnet-3. Flags below let us toggle BAL-based optimizations independently. | EL Client | Exec Par. | Batch IO (required) | State Par. | |-------------|:---------:|:-------------------:|:----------:| | Geth | ✅ | ✅ | ✅ | | Nethermind | ❓ | ❓ | ✅ | | Erigon | ✅ | ❓ | ❓ | | Besu | ✅ | ✅ | ✅ | | Reth | ✅ | ✅ | ✅ | ## Feature flags ### Besu | Option | Default | Type | Description | |--------|---------|------|-------------| | `--Xbal-optimization-enabled` | `true` | boolean | Disable BAL-based optimizations. | | `--Xbal-perfect-parallelization-enabled` | `true` | boolean | Disable BAL-based perfect parallelization. | | `--Xbal-lenient-on-state-root-mismatch` | `true` | boolean | Log instead of throw on state-root mismatch. | | `--Xbal-trust-state-root` | `false` | boolean | Trust BAL-computed state root without verification. | | `--Xbal-log-bals-on-mismatch` | `false` | boolean | Log constructed-block BAL when they differ. | | `--Xbal-api-enabled` | `false` | boolean | Enable `eth_getBlockAccessListByBlock*` and BALs in simulation. | | `--Xbal-state-root-timeout` | `1000` | long | Timeout (ms) awaiting BAL-computed state root. | | `--Xbal-processing-timeout` | `1000` | long | Timeout (ms) awaiting BAL tx processing results. | | `--Xbal-prefetch-reading-enabled` | `false` | boolean | Prefetch state based on BAL read ops. | | `--Xbal-prefetch-sorting-enabled` | `true` | boolean | Sort optimization during BAL prefetch. | ### Reth ```rust /// EIP-7928 BAL-based parallel execution. Falls back to tx-based prewarming when disabled. disable_bal_parallel_execution: bool, /// BAL-driven parallel state-root computation. Hashed post-state not sent to multiproof task when disabled. disable_bal_parallel_state_root: bool, /// BAL batched IO during prewarming. Falls back to per-slot reads when disabled. disable_bal_batch_io: bool, ``` CLI: `--engine.disable-bal-parallel-execution`, `--engine.disable-bal-parallel-state-root`, `--engine.disable-bal-batch-io`. ### Geth `--bal.executionmode=<full|sequential|nobatchio>`. ### Nethermind WIP. ### Erigon WIP. `IGNORE_BAL` env flag from [erigon#19903](https://github.com/erigontech/erigon/pull/19903). --- ## Local testing Kurtosis example (bump `bal-devnet-3` tags to `bal-devnet-4` once client branches exist): ```yaml participants: - cl_type: lighthouse cl_image: ethpandaops/lighthouse:bal-devnet-4 el_type: geth el_image: ethpandaops/geth:bal-devnet-4 el_extra_params: - --history.state=0 - --gcmode=archive - --syncmode=full count: 1 supernode: true - cl_type: lighthouse cl_image: ethpandaops/lighthouse:bal-devnet-4 el_type: besu el_image: ethpandaops/besu:bal-devnet-4 supernode: true el_min_mem: 4096 el_max_mem: 8192 count: 1 - cl_type: lighthouse cl_image: ethpandaops/lighthouse:bal-devnet-4 el_type: reth el_image: ethpandaops/reth:bal-devnet-4 supernode: true count: 1 - cl_type: lodestar cl_image: ethpandaops/lodestar:bal-devnet-4 el_type: nethermind el_image: ethpandaops/nethermind:bal-devnet-4 supernode: true count: 1 - cl_type: lodestar cl_image: ethpandaops/lodestar:bal-devnet-4 el_type: ethrex el_image: ethpandaops/ethrex:bal-devnet-4 count: 1 ethereum_genesis_generator_params: image: ethpandaops/ethereum-genesis-generator:5.3.1 global_log_level: debug network_params: preset: minimal seconds_per_slot: 6 genesis_delay: 30 fulu_fork_epoch: 0 gloas_fork_epoch: 2 snooper_enabled: true dora_params: image: ethpandaops/dora:eip7928-support spamoor_params: image: ethpandaops/spamoor:qu0b-fix-batcher-funding-gas-config spammers: - scenario: evm-fuzz config: {throughput: 50, payload_seed: "0x0200", funding_gas_limit: 200000} - scenario: eoatx config: {throughput: 50, gas_limit: 200000, funding_gas_limit: 200000} - scenario: deploytx config: {throughput: 10, bytecodes: "0x6000", gas_limit: 10000000, funding_gas_limit: 200000} - scenario: storagerefundtx config: {throughput: 20, slots_per_call: 500, funding_gas_limit: 200000} - scenario: setcodetx config: {throughput: 20, funding_gas_limit: 200000} additional_services: [dora, spamoor] port_publisher: additional_services: enabled: true public_port_start: 64400 ``` --- ## Metrics https://notes.ethereum.org/@ethpandaops/bal-otel Previous devnet spec sheet: https://notes.ethereum.org/@ethpandaops/bal-devnet-3