Skip to content

execution/tests: add bal-devnet-3 fixtures and move bals hash check after post block validation and before commitment validation#19595

Merged
taratorio merged 3 commits into
mainfrom
enable_devnet_3_tests
Mar 4, 2026
Merged

execution/tests: add bal-devnet-3 fixtures and move bals hash check after post block validation and before commitment validation#19595
taratorio merged 3 commits into
mainfrom
enable_devnet_3_tests

Conversation

@taratorio

@taratorio taratorio commented Mar 4, 2026

Copy link
Copy Markdown
Member

DO NOT MERGE BEFORE #19528

  • adds the new bal-devnet-3 test fixtures and applies the skips for failing eips
  • moves the bals hash check after post block validation and before commitment verification so that we can clearly see the real errors (e.g. gas mismatches/receipt mismatches/etc) instead of always seeing block access list mismatch

@taratorio taratorio requested a review from shohamc1 March 4, 2026 01:29
@taratorio taratorio force-pushed the enable_devnet_3_tests branch from a277e35 to 1d0b0f9 Compare March 4, 2026 01:42
@taratorio taratorio changed the title execution/tests: add bal-devnet-3 fixtures and move bals hash check after post block validation and before commitment validation [DO-NOT-MERGE] execution/tests: add bal-devnet-3 fixtures and move bals hash check after post block validation and before commitment validation Mar 4, 2026

@mh0lt mh0lt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may need a refactor when next merging main. The BALs code is now localized with versionedio.

@yperbasis yperbasis added the Glamsterdam https://eips.ethereum.org/EIPS/eip-7773 label Mar 4, 2026
@taratorio taratorio changed the title [DO-NOT-MERGE] execution/tests: add bal-devnet-3 fixtures and move bals hash check after post block validation and before commitment validation execution/tests: add bal-devnet-3 fixtures and move bals hash check after post block validation and before commitment validation Mar 4, 2026
@taratorio taratorio enabled auto-merge (squash) March 4, 2026 10:43
@taratorio taratorio merged commit f52f52a into main Mar 4, 2026
24 checks passed
@taratorio taratorio deleted the enable_devnet_3_tests branch March 4, 2026 11:05
sudeepdino008 pushed a commit that referenced this pull request Mar 4, 2026
…fter post block validation and before commitment validation (#19595)

DO NOT MERGE BEFORE #19528

- adds the new bal-devnet-3 test fixtures and applies the skips for
failing eips
- moves the bals hash check after post block validation and before
commitment verification so that we can clearly see the real errors (e.g.
gas mismatches/receipt mismatches/etc) instead of always seeing `block
access list mismatch`
mh0lt added a commit that referenced this pull request Mar 5, 2026
…ion (#19628)

## Summary

Fixes multiple issues with Block Access List (EIP-7928) computation that
caused BAL hash mismatches on bal-devnet-2 when running with parallel
execution (12 workers). These fixes were validated on the live devnet
with 200+ consecutive blocks fork-validated without errors.

These represent errors encountered on the live devnet rather than in
hive tests which don't include the same issues in combination.

## Changes

### 1. Fix `AccessedAddresses()` dropping revertable flag
(`intra_block_state.go`)

`AccessedAddresses()` was returning `nil` for every `accessOptions`
entry instead of the actual options containing the `revertable` flag.
This made it impossible for downstream BAL code to distinguish
gas-calculation reads from real state access.

**Before:** `out[addr] = nil`
**After:** `out[addr] = opts`

### 2. System address filter using non-revertable access flag
(`versionedio.go`)

Per EIP-7928, `SYSTEM_ADDRESS` (0xff...fe) "MUST NOT be included unless
it experiences state access itself." The system address is touched
during every block's system call (EIP-4788 beacon root) as `msg.sender`,
creating incidental gas-calc reads.

Added a `nonRevertableUserAccess` field to `accountState` that tracks
whether any user transaction (txIndex >= 0) performed a non-revertable
access (e.g. `evm.Call` target, `BALANCE` opcode, `SELFDESTRUCT`
beneficiary). The system address is now only included in the BAL when it
has actual state changes OR when a user tx explicitly accessed it.

### 3. Mark state-reading opcodes as non-revertable (`instructions.go`)

Per EIP-7928, `BALANCE`, `EXTCODESIZE`, `EXTCODECOPY`, and `EXTCODEHASH`
are real state access operations. Added `MarkAddressAccess(addr, false)`
(non-revertable) to these opcodes so they correctly trigger system
address inclusion when a user tx queries it.

Previously, `EXTCODEHASH` used `MarkAddressAccess(address, true)`
(revertable) and the others had no explicit access marking at all — they
relied only on the implicit revertable marking from `versionRead`.

### 4. VersionMap HasBAL flag for read validation (`versionmap.go`)

When a BAL is present, significant writes for BalancePath, NoncePath,
CodePath and StoragePath are pre-populated in the VersionMap before
execution. Added a `HasBAL` field with two validation refinements:

**Path-specific bypass (MVReadResultDone):** The HasBAL validation
bypass now only applies to BAL-pre-populated paths (BalancePath,
NoncePath, CodePath, StoragePath). AddressPath and other paths that are
NOT pre-populated by the BAL always trigger invalidation, since a new
VersionMap entry for those paths indicates a real state change from a
concurrent worker (e.g. account creation).

**AddressPath cross-check (MVReadResultNone):** When HasBAL is true and
an AddressPath read returned None (account not in DB), cross-check
against BalancePath which IS pre-populated by the BAL. If BalancePath
has an entry at a prior txIndex, the account was created by a prior tx
and the nil AddressPath read is stale — triggering re-execution. This
fixes a class of BAL mismatches where a tx speculatively reads an
account as non-existent, a prior tx creates the account, but the stale
read goes undetected because AddressPath writes are not flushed to the
VersionMap when HasBAL is true.

### 5. Skip BAL validation when stored body is missing (`bal_create.go`)

Blocks downloaded via the backward block downloader (p2p sync) do not
carry BAL bodies — only blocks received via engine API have them stored.
When the stored BAL is missing, `HasBAL=false` on the VersionMap, so the
computed BAL may be inaccurate. Skip the computed-vs-header hash
comparison in this case. Added debug dump of stored vs computed BAL on
mismatch for diagnostics.

This limitation goes away once eth/71 delivers BAL bodies via p2p sync.

### 6. Read BAL data with fresh tx (`exec3.go`)

Changed BAL data reading from `tx.Apply()` to `te.cfg.db.View()` so the
execution stage can see BAL data committed by `InsertBlocks` after the
execution transaction was opened.

### 7. Replace `isChainTip` with `!isApplyingBlocks` (`exec3.go`)

Replaced the `isChainTip` variable (derived from `maxBlockNum ==
startBlockNum`) with the existing `isApplyingBlocks` flag (derived from
sync mode). These are semantically equivalent but `isApplyingBlocks` is
clearer and avoids having two variables for the same condition.

### 8. Skip `test_bal_invalid_*` spec tests (`block_test.go`)

Added a skip for `test_bal_invalid_*` execution spec tests. These tests
require BAL structural validation (rejecting blocks with intentionally
invalid BALs) which is not yet implemented. **Note:** these tests also
fail on `main` (see CI run
[#22680631291](https://github.com/erigontech/erigon/actions/runs/22680631291))
— they were added in #19595 without corresponding validation
implementation. This skip is not a regression introduced by this PR.

## Testing

- **bal-devnet-2**: 200+ consecutive blocks fork-validated with 12
parallel workers, zero BAL hash mismatches
- **Unit tests**: `TestExecutionSpecBlockchainDevnet` — all pass (128s)
- **Lint**: `make lint` — clean

---------

Co-authored-by: Mark Holt <erigon@dev-bm-e3-ethmainnet-n4.erigon.io>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
mh0lt pushed a commit that referenced this pull request Mar 6, 2026
Extracted from #19595: moves the BAL hash-check logic out of the
parallel executor's inline loop and into a dedicated ProcessBAL()
function in bal_create.go. This makes BAL validation reusable and
separates it from block validation ordering.

Excludes the bal-devnet-3 test fixtures from the same PR.
mh0lt added a commit that referenced this pull request Mar 6, 2026
…ion (#19628)

Fixes multiple issues with Block Access List (EIP-7928) computation that
caused BAL hash mismatches on bal-devnet-2 when running with parallel
execution (12 workers). These fixes were validated on the live devnet
with 200+ consecutive blocks fork-validated without errors.

These represent errors encountered on the live devnet rather than in
hive tests which don't include the same issues in combination.

(`intra_block_state.go`)

`AccessedAddresses()` was returning `nil` for every `accessOptions`
entry instead of the actual options containing the `revertable` flag.
This made it impossible for downstream BAL code to distinguish
gas-calculation reads from real state access.

**Before:** `out[addr] = nil`
**After:** `out[addr] = opts`

(`versionedio.go`)

Per EIP-7928, `SYSTEM_ADDRESS` (0xff...fe) "MUST NOT be included unless
it experiences state access itself." The system address is touched
during every block's system call (EIP-4788 beacon root) as `msg.sender`,
creating incidental gas-calc reads.

Added a `nonRevertableUserAccess` field to `accountState` that tracks
whether any user transaction (txIndex >= 0) performed a non-revertable
access (e.g. `evm.Call` target, `BALANCE` opcode, `SELFDESTRUCT`
beneficiary). The system address is now only included in the BAL when it
has actual state changes OR when a user tx explicitly accessed it.

Per EIP-7928, `BALANCE`, `EXTCODESIZE`, `EXTCODECOPY`, and `EXTCODEHASH`
are real state access operations. Added `MarkAddressAccess(addr, false)`
(non-revertable) to these opcodes so they correctly trigger system
address inclusion when a user tx queries it.

Previously, `EXTCODEHASH` used `MarkAddressAccess(address, true)`
(revertable) and the others had no explicit access marking at all — they
relied only on the implicit revertable marking from `versionRead`.

When a BAL is present, significant writes for BalancePath, NoncePath,
CodePath and StoragePath are pre-populated in the VersionMap before
execution. Added a `HasBAL` field with two validation refinements:

**Path-specific bypass (MVReadResultDone):** The HasBAL validation
bypass now only applies to BAL-pre-populated paths (BalancePath,
NoncePath, CodePath, StoragePath). AddressPath and other paths that are
NOT pre-populated by the BAL always trigger invalidation, since a new
VersionMap entry for those paths indicates a real state change from a
concurrent worker (e.g. account creation).

**AddressPath cross-check (MVReadResultNone):** When HasBAL is true and
an AddressPath read returned None (account not in DB), cross-check
against BalancePath which IS pre-populated by the BAL. If BalancePath
has an entry at a prior txIndex, the account was created by a prior tx
and the nil AddressPath read is stale — triggering re-execution. This
fixes a class of BAL mismatches where a tx speculatively reads an
account as non-existent, a prior tx creates the account, but the stale
read goes undetected because AddressPath writes are not flushed to the
VersionMap when HasBAL is true.

Blocks downloaded via the backward block downloader (p2p sync) do not
carry BAL bodies — only blocks received via engine API have them stored.
When the stored BAL is missing, `HasBAL=false` on the VersionMap, so the
computed BAL may be inaccurate. Skip the computed-vs-header hash
comparison in this case. Added debug dump of stored vs computed BAL on
mismatch for diagnostics.

This limitation goes away once eth/71 delivers BAL bodies via p2p sync.

Changed BAL data reading from `tx.Apply()` to `te.cfg.db.View()` so the
execution stage can see BAL data committed by `InsertBlocks` after the
execution transaction was opened.

Replaced the `isChainTip` variable (derived from `maxBlockNum ==
startBlockNum`) with the existing `isApplyingBlocks` flag (derived from
sync mode). These are semantically equivalent but `isApplyingBlocks` is
clearer and avoids having two variables for the same condition.

Added a skip for `test_bal_invalid_*` execution spec tests. These tests
require BAL structural validation (rejecting blocks with intentionally
invalid BALs) which is not yet implemented. **Note:** these tests also
fail on `main` (see CI run
[#22680631291](https://github.com/erigontech/erigon/actions/runs/22680631291))
— they were added in #19595 without corresponding validation
implementation. This skip is not a regression introduced by this PR.

- **bal-devnet-2**: 200+ consecutive blocks fork-validated with 12
parallel workers, zero BAL hash mismatches
- **Unit tests**: `TestExecutionSpecBlockchainDevnet` — all pass (128s)
- **Lint**: `make lint` — clean

---------

Co-authored-by: Mark Holt <erigon@dev-bm-e3-ethmainnet-n4.erigon.io>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
github-merge-queue Bot pushed a commit that referenced this pull request Mar 20, 2026
DO-NOT-MERGE BEFORE #19595

closes #19102

---------

Co-authored-by: Mark Holt <135143369+mh0lt@users.noreply.github.com>
Co-authored-by: yperbasis <andrey.ashikhmin@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Glamsterdam https://eips.ethereum.org/EIPS/eip-7773

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants