Skip to content

Commit 3d577e9

Browse files
committed
Fix attestation injection logic, clean up README
1 parent 14b8119 commit 3d577e9

2 files changed

Lines changed: 16 additions & 83 deletions

File tree

README.md

Lines changed: 15 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,23 @@
22

33
Replays historical Ethereum mainnet blocks through [Lighthouse's](https://github.com/sigp/lighthouse) production [Fast Confirmation Rule](https://github.com/ethereum/consensus-specs/pull/4747) implementation to determine what percentage of blocks would have fast confirmed.
44

5-
Uses Lighthouse's actual consensus code (state transitions, fork choice, FCR evaluation) with `fake_crypto` to skip BLS verification for speed. Blocks are sourced from [ERA files](https://github.com/eth-clients/e2store-format-specs), checkpoint states from a beacon node API.
5+
## How It Works
66

7-
## Lighthouse Modifications
7+
For each slot N in the configured range:
8+
9+
1. Process block N through Lighthouse's production block processing pipeline (state transition, fork choice, attestation processing via `on_block`)
10+
2. Find the next block (N+1, or N+2/N+3 if there are missed slots)
11+
3. Inject that block's attestations into fork choice, simulating them arriving during slot N
12+
4. Recompute the fork choice head, triggering FCR evaluation
13+
5. Record the result
14+
15+
Blocks come from [ERA files](https://github.com/eth-clients/e2store-format-specs). The starting beacon state is fetched from a beacon node API and cached locally. BLS verification is disabled (`fake_crypto`) for speed since all blocks are from the canonical chain.
816

9-
This project uses a [fork of Lighthouse](https://github.com/samcm/lighthouse/tree/fcr-simulator) based on [dapplion's FCR branch](https://github.com/sigp/lighthouse/pull/8951). The modifications are minimal and auditable:
17+
The attestation model is optimistic: we assume attestations from the next block all arrived at the attestation deadline. This gives an upper bound on confirmation rates.
1018

11-
- [`fcr-simulator/`](https://github.com/samcm/lighthouse/tree/fcr-simulator/fcr-simulator) - the simulator crate (new)
12-
- [`data_availability_checker.rs`](https://github.com/samcm/lighthouse/compare/fcr...fcr-simulator#diff-data_availability_checker) - `new_without_da_check()` to bypass blob availability for historical blocks
13-
- [`block_verification_types.rs`](https://github.com/samcm/lighthouse/compare/fcr...fcr-simulator#diff-block_verification_types) - `from_available_block()` constructor for RangeSyncBlock
14-
- [`Cargo.toml`](https://github.com/samcm/lighthouse/compare/fcr...fcr-simulator#diff-Cargo.toml) - adds `fcr-simulator` to workspace members
19+
## Lighthouse Modifications
1520

16-
[Full diff of all Lighthouse changes](https://github.com/samcm/lighthouse/compare/fcr...fcr-simulator)
21+
Uses a [fork of Lighthouse](https://github.com/samcm/lighthouse/tree/fcr-simulator) based on [dapplion's FCR branch](https://github.com/sigp/lighthouse/pull/8951). [Full diff of changes](https://github.com/samcm/lighthouse/compare/fcr...fcr-simulator) -- adds the simulator crate and bypasses blob availability checks for historical blocks.
1722

1823
## Build
1924

@@ -35,9 +40,7 @@ CARGO_NET_GIT_FETCH_WITH_CLI=true cargo build -p fcr-simulator --features fake_c
3540
--parallel 2
3641
```
3742

38-
ERA files are downloaded automatically from `https://mainnet.era.nimbus.team` and cached locally. The beacon node is only used to fetch the starting checkpoint state (once per worker, cached).
39-
40-
Each worker uses ~2-3GB RAM. `--parallel` should be at most `num_cpus / 4` due to memory bandwidth constraints.
43+
Each worker uses ~2-3GB RAM. `--parallel` should be at most `num_cpus / 4` due to memory bandwidth.
4144

4245
## Docker
4346

@@ -53,80 +56,10 @@ docker run ghcr.io/ethpandaops/fcr-simulator \
5356

5457
## Output
5558

56-
CSV with one row per slot:
57-
58-
| Column | Description |
59-
|--------|-------------|
60-
| `slot` | Beacon chain slot number |
61-
| `epoch` | Epoch number |
62-
| `has_block` | Whether a block was proposed at this slot |
63-
| `block_root` | Head block root |
64-
| `confirmed` | Whether FCR confirmed within 1 slot (delay <= 1) |
65-
| `confirmed_root` | The FCR confirmed block root |
66-
| `confirmed_slot` | Slot of the confirmed block |
67-
| `confirmation_delay_slots` | Slots between current slot and confirmed slot |
68-
| `head_root` | Fork choice head root |
69-
| `finalized_epoch` | Current finalized epoch |
70-
| `justified_epoch` | Current justified epoch |
71-
| `num_attestations_injected` | Peek-ahead attestations injected |
72-
| `is_epoch_boundary` | Whether this slot starts an epoch |
73-
| `is_missed_slot` | Whether the proposer missed this slot |
74-
75-
## Methodology
76-
77-
### Simulation Loop
78-
79-
For each slot N:
80-
81-
1. Process the block at slot N through Lighthouse's full block processing pipeline (state transition, fork choice `on_block`, attestation processing)
82-
2. Recompute the fork choice head
83-
3. Scan forward to find the next block that contains attestations for slot N (up to 32 slots ahead)
84-
4. Inject only those attestations targeting slot N into the fork choice store
85-
5. Advance the slot clock and recompute head, which triggers the FCR evaluation
86-
6. Record the FCR result: confirmed root, confirmation delay, and per-slot metadata
87-
88-
### Attestation Model
89-
90-
The simulator uses an **optimistic attestation arrival model**: for each slot N, we extract the aggregate attestations that were eventually included on-chain and simulate them as if they all arrived at the attestation deadline (4 seconds into slot N+1).
91-
92-
Concretely, attestations for slot N are sourced from the first subsequent block that includes them. In the normal case this is block N+1. If slot N+1 is missed, we scan forward through N+2, N+3, etc. (up to the 32-slot inclusion window) until we find a block containing attestations with `attestation.data.slot == N`.
93-
94-
This means:
95-
96-
- **We only use attestations that were actually included on-chain.** We do not fabricate attestations or assume participation rates. The attestation data reflects what validators actually produced and propagated.
97-
- **We assume timely arrival.** In reality, some attestations arrive late and miss the FCR evaluation window. Our model assumes they all arrive on time, which makes our results an upper bound on confirmation rates.
98-
- **We use the first block containing each slot's attestations.** Attestations for a given slot can be split across multiple blocks (e.g., partial aggregates in N+1 and N+2). We only inject from the first block found. This means we slightly under-count attestation weight in some cases, which makes our results a conservative estimate.
99-
- **Missed slots are handled correctly.** When slot N has no block, the committee at slot N still attests (to the parent block). These attestations land in the next available block and are injected when we simulate slot N.
100-
101-
### What FCR Sees
102-
103-
The FCR evaluation uses Lighthouse's production `FastConfirmationRule` code from [PR #8951](https://github.com/sigp/lighthouse/pull/8951). It receives the same inputs it would in a live node:
104-
105-
- The proto-array fork choice store with all processed blocks and their weights
106-
- The materialized vote trackers (latest messages from all validators)
107-
- The beacon state for committee assignments and balance information
108-
- Justified and finalized checkpoints
109-
110-
The only difference from a live node is the attestation timing: a live node sees attestations arrive in real-time via gossip, while we batch-inject them from the historical record.
111-
112-
### Known Limitations
113-
114-
1. **Optimistic bias from timely arrival assumption.** Real nodes may not see all attestations before the FCR evaluation point. Our confirmation rates are an upper bound.
115-
2. **Conservative bias from single-block attestation sourcing.** Late attestations included in blocks N+2, N+3, etc. are not captured. This partially offsets limitation #1.
116-
3. **No equivocation simulation.** The simulator does not model equivocating validators. Equivocations on mainnet are extremely rare and would not materially affect results.
117-
4. **Byzantine threshold is configurable.** Default is 25% (the spec maximum). Lower thresholds confirm faster but provide weaker safety guarantees.
118-
119-
### Correctness Guarantees
120-
121-
- **State transitions** use Lighthouse's production `per_slot_processing` and `per_block_processing` code.
122-
- **Fork choice** uses Lighthouse's production `proto_array` implementation.
123-
- **FCR evaluation** uses Lighthouse's production `FastConfirmationRule` from the `fcr` branch.
124-
- **BLS verification** is disabled via `fake_crypto` for performance. This does not affect FCR results since the FCR algorithm operates on attestation weights and fork choice scores, not signature validity. All blocks being replayed are from the canonical chain and have already been verified by the network.
125-
- **Blob availability** checks are bypassed for historical blocks. This does not affect fork choice or FCR, which only depend on the beacon block contents (attestations, state roots, parent roots).
59+
CSV with one row per slot. Key columns: `slot`, `confirmed` (delay <= 1 slot), `confirmation_delay_slots`, `has_block`, `is_missed_slot`, `num_attestations_injected`.
12660

12761
## References
12862

12963
- [Fast Confirmation Rule spec](https://github.com/ethereum/consensus-specs/pull/4747)
13064
- [Lighthouse FCR implementation](https://github.com/sigp/lighthouse/pull/8951)
13165
- [Research paper (arXiv:2405.00549)](https://arxiv.org/abs/2405.00549)
132-
- [fastconfirm.it](https://fastconfirm.it)

lighthouse

0 commit comments

Comments
 (0)