# bal-devnet-6 spec :::info :mega: bal-devnet-6 target launch: **Friday 01.05**. ::: :::info BAL benchmark dashboard https://nerolation.github.io/bal-dashboard/. Based on data from https://benchmarkoor.core.ethpandaops.io. Requires benchmarkoor api key. ::: :::info ❗ EIP-8037: bal-devnet-6 keeps the **static** `cost_per_state_byte = 1174` from bal-devnet-3. We will use opcode level accounting. ::: :::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-6. 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-6 | EIP | Title | Status | |--------|------|--------| | [EIP-7708](https://eips.ethereum.org/EIPS/eip-7708) | ETH transfers emit a log — **now includes `CREATE`/`CREATE2`** | :up: | | [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 — **block access index `uint32`** | :up: | | [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`~~ **static `cpsb=1174`** :exclamation: | :up: | | [EIP-8159](https://eips.ethereum.org/EIPS/eip-8159) | eth/71 – Block Access List Exchange — **empty BAL response `0x80`** | optional, :up: | | [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-6 | |------|--------------|--------------| | 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-7708 log emission | `CALL*` + `SELFDESTRUCT` | `CALL*` + `SELFDESTRUCT` + **`CREATE` / `CREATE2`** — [EIPs#11474](https://github.com/ethereum/EIPs/pull/11474) merged 2026-04-20. Every EL must emit ETH-transfer logs on contract creation. | | EIP-7928 block access index | `uint64` | `uint32` — [EIPs#11550](https://github.com/ethereum/EIPs/pull/11550) merged 2026-04-20 | | EIP-8159 empty BAL response | `0xc0` (empty list) | `0x80` (empty string) — [EIPs#11553](https://github.com/ethereum/EIPs/pull/11553) merged 2026-04-21, **after `snøbal-devnet-6@v1.0.0` cut**. Matches EIP-8189 / snap/1 `ByteCodes`/`TrieNodes` convention; avoids collision with empty BALs on chains without system contracts. | | Top-level reservoir refund | State gas persists on top-level failure | **Zeroed on failure.** See change #1. | | 0→x→0 SSTORE reservoir refill | Refund via capped `refund_counter` (20%) | **Refund directly to reservoir** — no cap. See change #2. | | CREATE failure state gas | Charged unconditionally in caller frame | **Upfront charge kept, refund to reservoir** on silent failure (balance, nonce, collision, stack depth). See change #3. | | 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. See change #4. | | CALL to self-destructed same-tx account | No state gas charge (`is_account_alive` correct) | **No change** — behaviour is correct. See change #5. | | 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. See change #6. | | Tx inclusion validity | 1D regular-gas check only | **2D check** — both regular gas and state gas validated per-tx before execution. See change #7. | | 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) | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | | 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-6 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/newaccount-stategas) | | 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 | Tests landed in [execution-specs#2718](https://github.com/ethereum/execution-specs/pull/2718) (rework of closed #2639); now in `snøbal-devnet-6@v1.0.0` | | 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-6 (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:** [`snøbal-devnet-6@v1.0.0`](https://github.com/ethereum/execution-spec-tests/releases/tag/snøbal-devnet-6@v1.0.0) — tagged 2026-04-21 on `devnets/bal/4` (commit `524b446`). --- ## Spec versions required & Open PRs ### EIP-8037 state-gas changes All 7 state-gas changes from the 2026-04-15 breakout plus the full dynamic `cost_per_state_byte` are now in both canonical EIP-8037 text and `tests-bal@v5.7.0`. | # | Change | EIPs PR | EELS PR | |---|----------|---------|---------| | 0 | Dynamic `cost_per_state_byte` — full pricing function derived from header gas limit (quantized via `CPSB_SIGNIFICANT_BITS=5`, `CPSB_OFFSET=9578`) | — | [specs#2687](https://github.com/ethereum/execution-specs/pull/2687) | | 1 | Top-level failure — zero execution state gas | [EIPs#11476](https://github.com/ethereum/EIPs/pull/11476) | [specs#2689](https://github.com/ethereum/execution-specs/pull/2689) | | 2 | 0→x→0 SSTORE — refund direct to reservoir (no `refund_counter`) | [EIPs#11532](https://github.com/ethereum/EIPs/pull/11532), [EIPs#11548](https://github.com/ethereum/EIPs/pull/11548) | [specs#2698](https://github.com/ethereum/execution-specs/pull/2698) | | 3 | CREATE silent-failure — upfront charge kept, refund to reservoir | [EIPs#11532](https://github.com/ethereum/EIPs/pull/11532) | [specs#2704](https://github.com/ethereum/execution-specs/pull/2704) | | 4 | Same-tx SELFDESTRUCT — refund state gas + storage costs at end of tx | [EIPs#11532](https://github.com/ethereum/EIPs/pull/11532) | [specs#2707](https://github.com/ethereum/execution-specs/pull/2707) | | 5 | CALL to same-tx selfdestructed account — no change (test only) | [EIPs#11532](https://github.com/ethereum/EIPs/pull/11532) | [specs#2646](https://github.com/ethereum/execution-specs/pull/2646) | | 6 | EIP-7702 `intrinsic_state_gas` — stop mid-execution mutation, refund when auth targets existing account | [EIPs#11532](https://github.com/ethereum/EIPs/pull/11532) | [specs#2711](https://github.com/ethereum/execution-specs/pull/2711) | | 7 | Per-dimension tx inclusion check (2D regular + state gas) | [EIPs#11536](https://github.com/ethereum/EIPs/pull/11536) | [specs#2703](https://github.com/ethereum/execution-specs/pull/2703) | **Open spec gap:** change 2 ↔ 4 nested-child-frame refund interaction is implemented in tests via [specs#2733](https://github.com/ethereum/execution-specs/pull/2733); canonical EIP-8037 text still needs a clarification PR. ### Execution APIs | PR | Title | Author | Note | |----|-------|--------|------| | [#786](https://github.com/ethereum/execution-apis/pull/786) | engine: Restrict no-reorg to the prefix of known finalized | mkalinin | required for glamsterdam-devnets, optional for bal-devnet-6 | --- ## 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 ``` --Blocks.ParallelExecution=true --Blocks.ParallelExecutionBatchRead=true ``` ### 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-6` once client branches exist): ```yaml articipants: - cl_type: lighthouse cl_image: ethpandaops/lighthouse:bal-devnet-6 supernode: true cl_log_level: debug el_type: geth el_image: ethpandaops/geth:bal-devnet-6 el_extra_params: ["--history.state=0", "--gcmode=archive", "--syncmode=full"] el_log_level: debug count: 1 - cl_type: lighthouse cl_image: ethpandaops/lighthouse:bal-devnet-6 supernode: true cl_log_level: debug el_type: besu el_image: ethpandaops/besu:bal-devnet-6 el_log_level: debug count: 1 - cl_type: lighthouse cl_image: ethpandaops/lighthouse:bal-devnet-6 supernode: true cl_log_level: debug el_type: reth el_image: ethpandaops/reth:bal-devnet-6 el_extra_params: ["--txpool.max-account-slots=256"] el_log_level: debug count: 1 - cl_type: lighthouse cl_image: ethpandaops/lighthouse:bal-devnet-6 supernode: true cl_log_level: debug el_type: nethermind el_image: ethpandaops/nethermind:bal-devnet-6 el_log_level: debug count: 1 - cl_type: lighthouse cl_image: ethpandaops/lighthouse:bal-devnet-6 supernode: true cl_log_level: debug el_type: erigon el_image: ethpandaops/erigon:bal-devnet-6 el_log_level: debug count: 1 - cl_type: lighthouse cl_image: ethpandaops/lighthouse:bal-devnet-6 supernode: true cl_log_level: debug el_type: ethrex el_image: ethpandaops/ethrex:bal-devnet-6 el_extra_params: ["--syncmode=full"] el_extra_env_vars: RUST_LOG: "info" el_log_level: debug count: 1 - cl_type: lighthouse cl_image: ethpandaops/lighthouse:bal-devnet-6 supernode: true cl_log_level: debug el_type: nimbus el_image: ethpandaops/nimbus-eth1:bal-devnet-6 el_log_level: debug count: 1 network_params: preset: minimal seconds_per_slot: 6 genesis_delay: 30 fulu_fork_epoch: 0 gloas_fork_epoch: 2 # 100M block gas limit per devnet-4 spec; also scales EIP-8037 cpsb correctly. genesis_gaslimit: 100000000 gas_limit: 100000000 snooper_enabled: true dora_params: image: ethpandaops/dora:eip7928-support spamoor_params: image: ethpandaops/spamoor:master spammers: - scenario: evm-fuzz config: {funding_gas_limit: 2000000, throughput: 50, payload_seed: "0x0400"} - scenario: eoatx config: {funding_gas_limit: 2000000, throughput: 50, gas_limit: 200000} - scenario: deploytx config: {funding_gas_limit: 2000000, throughput: 10, bytecodes: "0x6000", gas_limit: 10000000} - scenario: storagerefundtx config: {funding_gas_limit: 2000000, throughput: 20, slots_per_call: 500} - scenario: setcodetx config: {funding_gas_limit: 2000000, throughput: 20} ethereum_genesis_generator_params: image: ethpandaops/ethereum-genesis-generator:6.0.2 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