Skip to content

Block access list changes - BAL construction, execution and validation#32263

Closed
jwasinger wants to merge 48 commits intoethereum:masterfrom
jwasinger:bal-execution
Closed

Block access list changes - BAL construction, execution and validation#32263
jwasinger wants to merge 48 commits intoethereum:masterfrom
jwasinger:bal-execution

Conversation

@jwasinger
Copy link
Copy Markdown
Contributor

@jwasinger jwasinger commented Jul 23, 2025

Change summary:

  • when --experimental.bal is enabled:
    • insertion of post-Cancun blocks which don't contain access lists will cause them to be created during block execution and embedded into the block body.
    • Insertion of post-cancun blocks that contain access lists will perform transaction execution and post-state root calculation in parallel using the state diffs provided in the access list. The state diffs produced by execution are validated against the entries in the BAL.
  • Introduced new modified blockchain suite test runner which first imports the test chain (generating BALs), and then re-inserts the access-list-containing blocks.

Deviations from EIP-7928:

  • Use RLP for the encoding format instead of SSZ.
  • Modify BAL format to accomodate pre/post-tx execution state changes:
    • entries with txindex=0 correspond to state reads/changes which occur from system contract execution before transactions.
    • entries with txindx=1..len(block.transactions) correspond to state reads/changes occurring for each transaction.
    • entries with txindex=len(block.transactions)+1 correspond to the post-block system contracts and EIP-4895 withdrawals.

TODO:

  • validation of BAL account/storage reads (it's somewhat likely that these will be removed from the spec, so I'm holding off for now).

@jwasinger
Copy link
Copy Markdown
Contributor Author

A lot of the comments in the code are straight-up wrong/misleading. There's a lot of notes/reminders I made as I was implementing this, and not all of them have been removed/corrected at this point.

@jwasinger
Copy link
Copy Markdown
Contributor Author

jwasinger commented Jul 29, 2025

I've pushed parallel execution changes here.

Still failing 2 tests (other than modexp repricing ones which will be fixed with a rebase on master):

--- FAIL: TestExecutionSpecBlocktestsBAL/prague/eip7251_consolidations/consolidations_during_fork/consolidation_requests_during_fork.json (0.03s)
        block_test.go:233: test with config {snapshotter:false, scheme:path} failed: mismatch between BAl value and computed value
    --- FAIL: TestExecutionSpecBlocktestsBAL/prague/eip7002_el_triggerable_withdrawals/withdrawal_requests_during_fork/withdrawal_requests_during_fork.json (0.02s)
        block_test.go:233: test with config {snapshotter:false, scheme:path} failed: mismatch between BAl value and computed value

I've been trying to debug these but it's proving to be exceedingly difficult with the parallel execution enabled. The tests seem to relate to behavior of some system contracts on the fork boundaries, so I will just proceed with gathering numbers on mainnet performance for the meantime.

Comment thread core/types/bal/bal.go Outdated
@jwasinger jwasinger force-pushed the bal-execution branch 2 times, most recently from ab1c562 to 8f200db Compare August 4, 2025 08:51
@jwasinger jwasinger marked this pull request as ready for review August 4, 2025 10:13
@jwasinger
Copy link
Copy Markdown
Contributor Author

INFO [08-04|13:21:15.227] Imported new chain segment number=23,051,616 hash=228379..13abd2 blocks=0 txs=10783 mgas=1137.280 elapsed=8.072s mgasps=140.878 age=2d6h46m triediffs=271.84MiB triedirty=112.48MiB

Broke the block count on the insertion log statement here. Will try to fix tomorrow.

@jwasinger
Copy link
Copy Markdown
Contributor Author

Getting some empty accounts in the BAL. example:

 {
      address: "0xff00000000000000000000000000000000008453"
  }

Copy link
Copy Markdown
Member

@lightclient lightclient left a comment

Choose a reason for hiding this comment

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

Looking good so far, just a few comments.

Comment thread core/blockchain.go Outdated
var resCh chan *ProcessResultWithMetrics
resCh, err = bc.processor.ProcessWithAccessList(block, statedb, bc.cfg.VmConfig)
if err != nil {
// TODO: okay to pass nil here as execution result?
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should be fine, we just use it to get out the receipts (if it is non nil).

Comment thread core/blockchain.go Outdated
Comment thread core/state/state_object.go Outdated
Comment thread core/state_processor.go Outdated
Comment thread params/config.go Outdated
@jwasinger
Copy link
Copy Markdown
Contributor Author

jwasinger commented Aug 27, 2025

We decided on the EIP breakout call to keep account/storage reads in for now. Basically, without having this information it is possible that a transaction can be crafted which does a ton of storage reads and slow down the processing of the block significantly.

So until we can evaluate worst-cases here, account/storage reads are staying in the spec.

Comment thread core/blockchain.go
bc.prefetcher.Prefetch(block, throwaway, vmCfg, &interrupt)
if block.Body().AccessList == nil {
// only use the state prefetcher for non-BAL blocks.
bc.prefetcher.Prefetch(block, throwaway, vmCfg, &interrupt)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I previously implemented a state prefetcher for BALs. I deleted it so that the import benchmarks I am running will capture the BAL block processing speed equivalent to a synced node executing blocks at chain head.

We should probably add back the BAL prefetcher and measure the import performance.

@jwasinger
Copy link
Copy Markdown
Contributor Author

Also TODO: need to implement validation of storage/account reads against the BAL.

Comment thread core/state/statedb.go Outdated
// The tx context and all occurred logs in the scope of transaction.
thash common.Hash
txIndex int
sender common.Address
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

remove trhis.

Comment thread core/state/statedb.go Outdated
// The tx context and all occurred logs in the scope of transaction.
thash common.Hash
txIndex int
sender common.Address
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

leftover, remove

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this should not be committed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, it's leftover test data for a unit test that no longer exists (but should be updated and added back in).

Comment thread core/blockchain.go Outdated
return nil, err
vstart := time.Now()
var err error
err = bc.validator.ValidateState(block, statedb, resWithMetrics.ProcessResult, false, false)
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.

I would like to ask why validate state is needed here. The root has been calculated and compared during parallel processing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's because ValidateState performs some other checks beyond root comparison that we still need to do.

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.

 Got it, thanks.
Since the root is already computed and checked in parallel processing, should ValidateState still call statedb.IntermediateRoot()? Or should it only run the extra checks?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I thought about optionally-enabling the call to IntermediateRoot via a flag parameter to ValidateState but decided against it because it felt dirtier than just always calling IntermediateRoot and incurring the overhead of an extra hash check. Also, a call to IntermediateRoot caches the result on the statedb instance so calling it a second time is a effectively a no-op.

I have essentially rewritten the BAL code path for state root calculation in order to optimize it. I haven't yet pushed those changes to this branch because I am trying to sort out a bug in them.

jwasinger and others added 20 commits November 22, 2025 16:33
…ding state, move readOnly call context check into gas func to avoid unecessary state reads in the gas handler in case where these are called in a static context.
…ate access if the component of the call price which is independent from the state is not sufficient to cover the provided gas.
This PR is an alternative to ethereum#32556.

Instead of trying to be smart and reuse `geth init`, we can introduce a
new flag `--genesis` that loads the `genesis.json` from file into the
`Genesis` object in the same path that the other network flags currently
work in.

Question: is something like `--genesis` enough to start deprecating
`geth init`?

--

```console
$ geth --datadir data --hoodi
..
INFO [10-06|22:37:11.202]  - BPO2:                        @1762955544
..
$ geth --datadir data --genesis genesis.json
..
INFO [10-06|22:37:27.988]  - BPO2:                       @1862955544
..
```

Pull the genesis [from the
specs](https://raw.githubusercontent.com/eth-clients/hoodi/refs/heads/main/metadata/genesis.json)
and modify one of the BPO timestamps to simulate a shadow fork.

---------

Co-authored-by: rjl493456442 <garyrong0905@gmail.com>
…the Amsterdam tests aren't filled with bpo1/2 activated
…oesn't contain one. remove the new pre/post-tx tracer hooks and use the system contract start/end hooks instead in the bal tracer
@jwasinger
Copy link
Copy Markdown
Contributor Author

This got stale and I plan to propose a slightly different set of changes as an initial target for merging EIP-7928 support: we will merge a version that doesn't include the performance improvements initially.

@jwasinger jwasinger closed this Jan 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants