# 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