# EIP-7928 Block-Level Access Lists: OpenTelemetry Tracing Specification ## 1. Motivation ### 1.1 What BAL Enables EIP-7928 Block-Level Access Lists record all state accessed during block execution: - **Accounts** — addresses read or modified (balance, nonce, code) - **Storage** — slots read (`storage_reads`) or modified (`storage_changes`) - **Code** — contract bytecode deployed or modified The BAL hash is stored in the block header. This enables: | Capability | Without BAL | With BAL | |------------|-------------|----------| | State prefetch | On-demand during execution | Batch read before execution | | Transaction execution | Sequential | Parallel | | Storage trie updates | Sequential per account | Parallel across accounts | ### 1.2 What We Need to Measure 1. **Prefetch effectiveness** — Cache hit rate after prefetch 2. **Execution time** — Per-transaction and total block duration 3. **BAL overhead** — Size of BAL data 4. **Throughput impact** — MGas/sec with vs without BAL --- ## 2. Terminology | Term | Definition | |------|------------| | **BAL** | Block-Level Access List per EIP-7928 | | **Prefetch** | Batch reading state into cache before execution using BAL data | --- ## 3. Conformance Levels ### Mappings This spec proposes OTel span mappings for the following metrics: | Cross-Client JSON | Proposed OTel Span | |-------------------|-------------------| | `block.*` | `ethereum.block` | | `timing.execution_ms` | `ethereum.tx.execute` (aggregate) | | `timing.state_hash_ms` | `ethereum.stateroot` | ### BAL Extensions Clients implementing BAL MUST add: - `bal.*` attributes on cross-client spans (Section 5.2) - `ethereum.bal.prefetch` span (Section 5.3) - `ethereum.bal.prefetch.account` — Per-account prefetch timing - `ethereum.bal.prefetch.slot` — Per-slot prefetch timing --- ## 4. Resource Attributes Set once per client instance: | Attribute | Type | Required | Example | |-----------|------|----------|---------| | `service.name` | string | Yes | `geth` | | `service.version` | string | Yes | `1.14.0` | | `deployment.environment` | string | Yes | `mainnet` | | `ethereum.chain.id` | int64 | Yes | `1` | --- ## 5. Span Specification ### 5.1 Naming Conventions - Cross-client spans: `ethereum.*` - BAL-specific spans: `ethereum.bal.*` - All spans use kind `INTERNAL` ### 5.2 Span Definition These spans map to [Cross-Client Execution Metrics](https://hackmd.io/dg7rizTyTXuCf2LSa2LsyQ). BAL adds extension attributes. --- #### `ethereum.block` Root span for block processing. **Cross-Client Attributes** (from `block.*`): | Attribute | Type | Description | |-----------|------|-------------| | `block.number` | int64 | Block height | | `block.hash` | string | Block hash (0x-prefixed) | | `block.gas_used` | int64 | Total gas consumed | | `block.tx_count` | int64 | Transaction count | **BAL Extensions**: | Attribute | Type | Description | |-----------|------|-------------| | `bal.hash` | string | BAL hash from block header (0x-prefixed) | | `bal.accounts_count` | int64 | Unique accounts in BAL (reads + writes) | | `bal.storage_slots_count` | int64 | Total storage slots in BAL (reads + writes) | | `bal.code_count` | int64 | Unique contracts with code in BAL | | `bal.size_bytes` | int64 | RLP-encoded BAL size | --- #### `ethereum.tx.execute` Individual transaction execution. **Parent:** `ethereum.block` | Attribute | Type | Description | |-----------|------|-------------| | `tx.index` | int64 | Transaction index in block | | `tx.hash` | string | Transaction hash (0x-prefixed) | | `tx.gas_used` | int64 | Gas consumed | --- #### `ethereum.stateroot` State root calculation. Maps to `timing.state_hash_ms`. **Parent:** `ethereum.block` **Cross-Client Attributes** (from `state_writes.*`): | Attribute | Type | Description | |-----------|------|-------------| | `accounts_updated` | int64 | Accounts with changes | | `storage_slots_updated` | int64 | Storage slots modified | **BAL Extensions** (when `bal.enabled=true`): | Attribute | Type | Description | |-----------|------|-------------| | `bal.parallel` | bool | Whether trie updates were parallelized | --- ### 5.3 BAL-Specific Spans --- #### `ethereum.bal.prefetch` Batch state prefetching before execution. **Parent:** `ethereum.block` | Attribute | Type | Description | |-----------|------|-------------| | `accounts_count` | int64 | Accounts prefetched | | `storage_slots_count` | int64 | Storage slots prefetched | | `code_count` | int64 | Bytecodes prefetched | | `code_bytes` | int64 | Total bytes of code prefetched | | `cache_hits` | int64 | Items already in cache | | `cache_misses` | int64 | Items loaded from DB | --- #### `ethereum.bal.prefetch.account` *(optional)* **Parent:** `ethereum.bal.prefetch` | Attribute | Type | Description | |-----------|------|-------------| | `address` | string | Account address (0x-prefixed) | | `cache_hit` | bool | Whether already cached | --- #### `ethereum.bal.prefetch.slot` *(optional)* **Parent:** `ethereum.bal.prefetch` | Attribute | Type | Description | |-----------|------|-------------| | `address` | string | Contract address (0x-prefixed) | | `key` | string | Storage slot key (0x-prefixed) | | `cache_hit` | bool | Whether already cached | --- ### 5.4 Span Hierarchy ``` ethereum.block │ + block.number, block.hash, block.gas_used, block.tx_count │ + bal.enabled, bal.hash, bal.accounts_count, bal.storage_slots_count, bal.size_bytes │ ├── ethereum.bal.prefetch │ │ + accounts_count, storage_slots_count, code_count, code_bytes, cache_hits, cache_misses │ ├── ethereum.bal.prefetch.account (optional, per account) │ └── ethereum.bal.prefetch.slot (optional, per slot) │ ├── ethereum.tx.execute (per transaction) │ + tx.index, tx.hash, tx.gas_used │ └── ethereum.stateroot + accounts_updated, storage_slots_updated + bal.parallel ``` ### 5.5 Processing Flow ``` ┌─────────────────────────────────────────────────────────┐ │ ethereum.block │ │ │ │ ┌──────────────────┐ │ │ │ bal.prefetch │ Batch load state using BAL │ │ └────────┬─────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────┐ │ │ │ tx.execute (x N) │ Execute transactions (parallel) │ │ └────────┬─────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────┐ │ │ │ stateroot │ Compute state root │ │ └──────────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` --- ## 6. Metrics Specification ### 6.1 Naming Conventions - Cross-client metrics: `ethereum.*` - BAL-specific metrics: `ethereum.bal.*` - Units: `s` (seconds), `By` (bytes) ### 6.2 Counter Metrics **Cross-Client:** | Metric | Unit | Description | |--------|------|-------------| | `ethereum.blocks.total` | `{block}` | Blocks processed | | `ethereum.tx.total` | `{tx}` | Transactions processed | **BAL-Specific:** | Metric | Unit | Description | |--------|------|-------------| | `ethereum.bal.blocks.total` | `{block}` | BAL-enabled blocks | | `ethereum.bal.prefetch.accounts` | `{account}` | Accounts prefetched | | `ethereum.bal.prefetch.slots` | `{slot}` | Storage slots prefetched | | `ethereum.bal.prefetch.cache_hits` | `{item}` | Prefetch cache hits | | `ethereum.bal.prefetch.cache_misses` | `{item}` | Prefetch cache misses | ### 6.3 Histogram Metrics **Cross-Client:** | Metric | Unit | Description | |--------|------|-------------| | `ethereum.block.duration` | `s` | Block processing time | | `ethereum.tx.duration` | `s` | Per-transaction time | | `ethereum.stateroot.duration` | `s` | State root time | | `ethereum.throughput.mgas_per_sec` | `{mgas}/s` | Gas throughput | **BAL-Specific:** | Metric | Unit | Description | |--------|------|-------------| | `ethereum.bal.prefetch.duration` | `s` | Prefetch phase time | | `ethereum.bal.size` | `By` | BAL size in bytes | --- ## 7. Implementation Requirements ### 7.1 Performance | Requirement | Threshold | |-------------|-----------| | Tracing disabled overhead | < 0.1% | | Tracing enabled overhead | < 2% | | Per-span creation | < 1μs | ### 7.2 Configuration Clients SHOULD support: - OTLP endpoint (default: `localhost:4317`) - Sampling rate (default: 1.0) - Enable/disable BAL tracing --- ## 8. Analysis Queries ### 8.1 BAL Effectiveness ```sql SELECT AVG(CASE WHEN bal_enabled THEN block_duration_s END) AS avg_bal_block_s, AVG(CASE WHEN NOT bal_enabled THEN block_duration_s END) AS avg_no_bal_block_s, AVG(CASE WHEN bal_enabled THEN mgas_per_sec END) AS avg_bal_throughput, AVG(CASE WHEN NOT bal_enabled THEN mgas_per_sec END) AS avg_no_bal_throughput FROM block_metrics ``` ### 8.2 Prefetch Cache Effectiveness ```sql SELECT AVG(cache_hits * 100.0 / NULLIF(cache_hits + cache_misses, 0)) AS hit_rate_pct, AVG(prefetch_duration_s * 1000) AS avg_prefetch_ms FROM bal_prefetch_spans ``` --- ## 9. References 1. [EIP-7928: Block-Level Access Lists](https://eips.ethereum.org/EIPS/eip-7928) 2. [Cross-Client Execution Metrics Spec](https://hackmd.io/dg7rizTyTXuCf2LSa2LsyQ) 3. [Cross-Client Metrics Discussion](https://ethresear.ch/t/a-small-step-towards-data-driven-protocol-decisions-unified-slowblock-metrics-across-clients/23907) 4. [OpenTelemetry Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/) ### Implementation PRs (Cross-Client Metrics) - Geth: [#33655](https://github.com/ethereum/go-ethereum/pull/33655) - reth: [#21433](https://github.com/paradigmxyz/reth/pull/21433) - Besu: [#9660](https://github.com/hyperledger/besu/pull/9660) - Nethermind: [#10288](https://github.com/NethermindEth/nethermind/pull/10288)