go-ethereum/core
Stefan ff772bfa08
bal: lazy scope allocation in access list builder (#34019)
## Summary

- Avoid allocating a `map[common.Address]*constructionAccountAccess` on
every `enterScope()` call in the BAL access list builder
- Push `nil` onto the stack and lazily allocate via `currentScope()`
only when a state change occurs
- `exitScope()` short-circuits when child scope is nil (no merge needed)
- Adds correctness test (`TestLazyScopeCorrectness`) and benchmark
(`BenchmarkPrecompileScopes`)

## Context

The [execution-specs benchmark
tests](https://github.com/ethereum/execution-specs/blob/tests-benchmark@v0.0.7/tests/benchmark/compute/precompile/test_alt_bn128.py)
for `bn128_add` (line 19) and `bn128_pairing` (line 496) create blocks
with transactions that loop `STATICCALL` to precompiles thousands of
times. Each STATICCALL triggers `EnterScope()`/`ExitScope()` in the BAL
tracer, but precompile calls produce empty scopes since they don't touch
state (`AddBalance(0)` is filtered by `!amount.IsZero()`).

The previous implementation eagerly allocated a map on every
`enterScope()`, creating ~200K unnecessary heap allocations per
transaction for `bn128_add` (150 gas, ~200K calls per 30M gas block).

**Note:** For benchmark-only workloads that don't need BAL validation,
`--bal.executionmode=sequential` can be used to skip the parallel
processor entirely and avoid all tracing overhead.

## Benchmark results

Precompile calls with no state changes per scope:

| Calls | Before (ns/op) | After (ns/op) | Speedup | Allocs Before →
After |
|---|---|---|---|---|
| 100 | 5,073 | 1,499 | **3.4x** | 119 → 19 |
| 1,000 | 47,392 | 3,199 | **14.8x** | 1,019 → 19 |
| 10,000 | 493,651 | 20,644 | **23.9x** | 10,019 → 19 |
| 100,000 | 4,526,165 | 192,502 | **23.5x** | 100,019 → 19 |

## Test plan

- [x] `TestLazyScopeCorrectness` — mixed workload: precompile scopes +
state-changing scopes + reverted scopes
- [x] `BenchmarkPrecompileScopes` — measures scope tracking overhead for
100 to 100K empty scopes
- [x] All `core/vm/` tests pass
- [x] All `core/types/bal/` tests pass (pre-existing failures in
`TestBALEncoding` and `TestBlockAccessListValidation` unrelated)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 09:08:06 -04:00
..
filtermaps core/filtermaps: fix operator precedence in delete logging condition (#33280) 2025-12-06 04:21:38 +01:00
forkid params: set osaka and BPO1 & BPO2 mainnet dates (#33063) 2025-11-03 17:41:22 +01:00
history core: initialize history pruning in BlockChain (#31636) 2025-04-15 14:32:46 +02:00
overlay core/overlay: fix incorrect debug log key/value in LoadTransitionState (#32637) 2025-12-14 21:51:13 +01:00
rawdb attempt fix decoding bal 2026-02-05 13:59:41 +01:00
state * factor bal size when enforcing block size limit while adding txs to payload in miner 2026-02-11 16:55:16 -05:00
stateless core/stateless: cap witness depth metrics buckets (#33389) 2025-12-11 15:42:32 +08:00
tracing all: all block access list changes up through devnet 1 including perf changes 2026-01-27 13:48:18 -05:00
txpool core/txpool/legacypool: fix stale counter (#33653) 2026-01-23 13:35:14 +01:00
types bal: lazy scope allocation in access list builder (#34019) 2026-03-17 09:08:06 -04:00
vm remove static guard from callcode 2026-02-03 11:07:04 -05:00
.gitignore Renamed chain => core 2014-12-04 10:28:02 +01:00
bench_test.go core: using testing.B.Loop (#32662) 2025-09-19 17:06:27 -06:00
bintrie_witness_test.go cmd/evm/internal/t8ntool, trie: support for verkle-at-genesis, use UBT, and move the transition tree to its own package (#32445) 2025-11-14 15:25:30 +01:00
block_access_list_tracer.go * factor bal size when enforcing block size limit while adding txs to payload in miner 2026-02-11 16:55:16 -05:00
block_validator.go simplify blockchain logic 2026-02-03 11:07:04 -05:00
block_validator_test.go core: consolidate BlockChain constructor options (#31925) 2025-06-19 12:21:15 +02:00
blockchain.go * factor bal size when enforcing block size limit while adding txs to payload in miner 2026-02-11 16:55:16 -05:00
blockchain_insert.go core: remove unused peek function in insertIterator (#33155) 2025-11-12 15:30:16 +08:00
blockchain_reader.go ethstats: report newPayload processing time to stats server (#33395) 2026-01-05 17:49:30 +01:00
blockchain_repair_test.go core: consolidate BlockChain constructor options (#31925) 2025-06-19 12:21:15 +02:00
blockchain_sethead_test.go core: consolidate BlockChain constructor options (#31925) 2025-06-19 12:21:15 +02:00
blockchain_snapshot_test.go triedb/pathdb, eth: use double-buffer mechanism in pathdb (#30464) 2025-06-22 20:40:54 +08:00
blockchain_stats.go * factor bal size when enforcing block size limit while adding txs to payload in miner 2026-02-11 16:55:16 -05:00
blockchain_test.go all: all block access list changes up through devnet 1 including perf changes 2026-01-27 13:48:18 -05:00
chain_makers.go core: finally fix miner? 2026-02-05 16:46:44 +01:00
chain_makers_test.go core: consolidate BlockChain constructor options (#31925) 2025-06-19 12:21:15 +02:00
dao_test.go core: consolidate BlockChain constructor options (#31925) 2025-06-19 12:21:15 +02:00
error.go core, params: add limit for max blobs in blob transaction (#32246) 2025-07-21 16:26:24 +02:00
eth_transfer_logs_test.go core, params: add comments, move consts to params 2026-02-03 11:05:24 -05:00
events.go ethstats: report newPayload processing time to stats server (#33395) 2026-01-05 17:49:30 +01:00
evm.go eip-7708 fix: don't emit log when calling to self 2026-02-03 11:07:04 -05:00
gaspool.go core, miner: revert block gas counter in case of invalid transaction (#26799) 2023-03-07 05:23:52 -05:00
gen_genesis.go all: all block access list changes up through devnet 1 including perf changes 2026-01-27 13:48:18 -05:00
genesis.go core: fix rebasing errors 2026-02-05 14:06:44 +01:00
genesis_alloc.go params: add hoodi testnet definition (#31406) 2025-03-18 12:07:49 +01:00
genesis_test.go core/state, core/tracing: new state update hook (#33490) 2026-01-08 11:07:19 +08:00
headerchain.go core/rawdb: reduce allocations in rawdb.ReadHeaderNumber (#31913) 2025-07-15 15:48:36 +02:00
headerchain_test.go core/state, core/tracing: new state update hook (#33490) 2026-01-08 11:07:19 +08:00
mkalloc.go accounts, cmd/geth, core: close opened files (#29598) 2024-04-30 15:47:21 +02:00
parallel_state_processor.go * factor bal size when enforcing block size limit while adding txs to payload in miner 2026-02-11 16:55:16 -05:00
rlp_test.go core: using testing.B.Loop (#32662) 2025-09-19 17:06:27 -06:00
sender_cacher.go core: use sync.Once for SenderCacher initialization (#31029) 2025-01-16 14:36:45 +01:00
state_prefetcher.go trie, core/state: introduce trie Prefetch for optimizing preload (#32134) 2025-08-20 21:45:27 +08:00
state_processor.go core: finally fix miner? 2026-02-05 16:46:44 +01:00
state_processor_test.go core/vm: implement eip-7843 2026-02-03 11:05:23 -05:00
state_transition.go core: fix rebasing errors 2026-02-05 14:25:43 +01:00
stateless.go core: refactor StateProcessor to accept ChainContext interface (#32739) 2025-10-02 14:34:06 +02:00
txindexer.go core/rawdb: reduce allocations in rawdb.ReadHeaderNumber (#31913) 2025-07-15 15:48:36 +02:00
txindexer_test.go core/rawdb: integrate eradb backend for RPC (#31604) 2025-06-03 10:47:38 +02:00
types.go all: all block access list changes up through devnet 1 including perf changes 2026-01-27 13:48:18 -05:00