|
1 | 1 | # Slots and Intervals |
2 | 2 |
|
3 | | -A Lean Chain slot has a duration of 4 seconds and is divided in 5 intervals: |
| 3 | +A Lean Chain slot has a duration of 4 seconds and is divided in 5 intervals of 800 ms. |
| 4 | +Every duty a validator owes the chain is due in one of them: |
4 | 5 |
|
5 | | -1. Block proposal |
6 | | -2. Vote propagation |
7 | | -3. Vote aggregation |
8 | | -4. Safe target computation |
9 | | -5. Head update |
| 6 | +| Interval | Offset | Duty | Who acts | What it publishes | |
| 7 | +| --- | --- | --- | --- | --- | |
| 8 | +| 0 | t+0 ms | [Block proposal](#interval-0-block-proposal) | the slot's proposer | the block, on the `block` topic | |
| 9 | +| 1 | t+800 ms | [Vote propagation](#interval-1-vote-propagation) | every validator | a signed attestation, on its subnet topic | |
| 10 | +| 2 | t+1600 ms | [Vote aggregation](#interval-2-vote-aggregation) | aggregators | an aggregated attestation, on the `aggregation` topic | |
| 11 | +| 3 | t+2400 ms | [Safe target computation](#interval-3-safe-target-computation) | every validator | nothing: local bookkeeping | |
| 12 | +| 4 | t+3200 ms | [Head update](#interval-4-head-update) | every validator | nothing: local bookkeeping | |
10 | 13 |
|
11 | 14 | ```text |
12 | 15 | ONE SLOT (4000 ms) |
13 | 16 | ┌────────────┬────────────┬────────────┬────────────┬────────────┐ |
14 | 17 | │ Interval 0 │ Interval 1 │ Interval 2 │ Interval 3 │ Interval 4 │ |
15 | 18 | │ t+0 ms │ t+800 ms │ t+1600 ms │ t+2400 ms │ t+3200 ms │ |
16 | 19 | ├────────────┼────────────┼────────────┼────────────┼────────────┤ |
17 | | - │ block │ vote │ vote │ safe target│ head │ |
| 20 | + │ block │ vote │ vote │safe target │ head │ |
18 | 21 | │ proposal │propagation │aggregation │computation │ update │ |
19 | 22 | └────────────┴────────────┴────────────┴────────────┴────────────┘ |
| 23 | + ◄───────────── gossiped ─────────────▶ ◄───── local only ───────▶ |
20 | 24 | ``` |
21 | 25 |
|
22 | | -Block proposal is the first interval of a slot. During this interval, a block proposer, selected in a round-robin fashion, proposes a new block and gossips it to the network. Right before building the block, the proposer merges their "new attestations buffer" into their fork-choice view. They then include attestations that the proposer has recently seen into their block. Other validators verify the block and its contents, and merge the votes it includes into their fork-choice view. After importing a block, all validators recompute their [head](./lmd_ghost.md), and update the latest [finalized and justified checkpoints](./3sf_mini.md) according to the block's post-state. |
| 26 | +The grid comes from a genesis timestamp every node shares, so the schedule needs no |
| 27 | +coordination messages: a node reads its clock, works out which interval it is in, and |
| 28 | +knows which duty is due. The order is a dependency chain, since each interval consumes |
| 29 | +what the previous one produced. A duty that overruns its interval is not rescheduled: it |
| 30 | +lands late, and the slot moves on without it. |
23 | 31 |
|
24 | | -Vote propagation is the second interval of a slot. During this interval, validators gossip their votes for the block they consider to be the head of the chain, and append to it a `(source, target)` [finality vote](./3sf_mini.md). These votes are in aggregation subnets and are imported by aggregators. Aggregators verify the votes in their subnet and store them for later aggregation. |
| 32 | +> **In ethlambda:** the intervals are the `SlotInterval` variants in |
| 33 | +> `crates/blockchain/src/lib.rs`, and their length comes from |
| 34 | +> `MILLISECONDS_PER_INTERVAL` and `INTERVALS_PER_SLOT` in |
| 35 | +> `crates/common/types/src/constants.rs`. |
25 | 36 |
|
26 | | -Vote aggregation is the third interval of a slot. During this interval, aggregators aggregate the votes they have received and gossip the resulting aggregated attestations to the network. These aggregated attestations are imported by all validators, who verify and store them in a "new attestations buffer". |
| 37 | +## Interval 0: Block proposal |
27 | 38 |
|
28 | | -Safe target computation is the fourth interval of a slot. During this interval, validators compute the [safe target](./lmd_ghost.md#safe-target-selection) they'll use when deciding which finality vote to cast on the next slot. The safe target is computed based on the votes received in the current slot. |
| 39 | +A block proposer, selected in a round-robin fashion (`slot % num_validators`), proposes a |
| 40 | +new block and gossips it to the network. Right before building the block, the proposer |
| 41 | +merges their "new attestations buffer" into their fork-choice view. They then include |
| 42 | +attestations that the proposer has recently seen into their block. Other validators verify |
| 43 | +the block and its contents, and merge the votes it includes into their fork-choice view. |
| 44 | +After importing a block, all validators [recompute their head](./lmd_ghost.md), and update |
| 45 | +the latest [finalized and justified checkpoints](./3sf_mini.md) according to the block's |
| 46 | +post-state. |
29 | 47 |
|
30 | | -Head update is the fifth and final interval of a slot. During this interval, validators merge the aggregated attestations they have in their "new attestations buffer" into their fork-choice view, and recompute their head. |
| 48 | +A block body carries at most |
| 49 | +`MAX_ATTESTATIONS_DATA` aggregated attestations: distinct `(slot, head, target, source)` tuples, each paired with a |
| 50 | +bitfield naming the validators bound to it. |
| 51 | +Genesis occupies slot 0, so proposals start at slot 1, and nothing forces a slot to be |
| 52 | +filled: a proposer that is offline or too slow leaves an empty slot, and the next block |
| 53 | +simply points its parent root at an older block. |
31 | 54 |
|
32 | | -> **In ethlambda:** the intervals are the `SlotInterval` variants in |
33 | | -> `crates/blockchain/src/lib.rs`, and their length comes from |
34 | | -> `MILLISECONDS_PER_INTERVAL` and `INTERVALS_PER_SLOT` in |
35 | | -> `crates/common/types/src/constants.rs`. Block proposal is merged into the |
36 | | -> previous slot's head-update interval: the proposer advances its store to the |
37 | | -> next slot, builds the block there, and holds publication until the slot |
38 | | -> boundary. That buys the build one extra interval of headroom and leaves no |
39 | | -> actor work at the block-proposal tick itself. |
| 55 | +> **In ethlambda:** block proposal is merged into the previous slot's head-update |
| 56 | +> interval: the proposer advances its store to the next slot, builds the block there, |
| 57 | +> and holds publication until the slot boundary. That buys the build one extra interval |
| 58 | +> of headroom and leaves no actor work at the block-proposal tick itself. |
| 59 | +
|
| 60 | +## Interval 1: Vote propagation |
| 61 | + |
| 62 | +Validators gossip their votes for the block they consider to be the head of the chain, and |
| 63 | +append to it a `(source, target)` [finality vote](./3sf_mini.md#recap-attestation-anatomy). |
| 64 | +These votes are in aggregation subnets and are imported by aggregators. Aggregators verify |
| 65 | +the votes in their subnet and store them for later aggregation. |
| 66 | + |
| 67 | +> **In ethlambda:** a validator's subnet is `validator_index % attestation_committee_count`, |
| 68 | +> and a node only aggregates for subnets it subscribed to at startup. Aggregation is also |
| 69 | +> gated on the aggregator role, seeded by `--is-aggregator` and flippable at runtime |
| 70 | +> through the admin API. A chain whose validators all decline the role still gossips votes |
| 71 | +> and logs them as processed, but no aggregate is ever produced, so every block is empty |
| 72 | +> and the chain never justifies. |
| 73 | +
|
| 74 | +## Interval 2: Vote aggregation |
| 75 | + |
| 76 | +Aggregators aggregate the votes they have received and gossip the resulting aggregated |
| 77 | +attestations to the network. These aggregated attestations are imported by all validators, |
| 78 | +who verify and store them in a "new attestations buffer". |
| 79 | + |
| 80 | +Aggregation earns its own interval because it is the heaviest recurring computation in the |
| 81 | +client: collapsing a subnet's worth of them |
| 82 | +into one proof is heavy CPU work. It is also what makes a block affordable, since a block |
| 83 | +carrying raw votes would need one full XMSS signature per voter, quickly going over the network bandwidth limit. |
| 84 | + |
| 85 | +> **In ethlambda:** the proofs run on an off-thread worker so the blockchain actor's |
| 86 | +> message loop stays responsive, and a session may start up to `EARLY_AGGREGATION_WINDOW` |
| 87 | +> before the interval boundary once two thirds of the signatures are in. At the session's |
| 88 | +> soft deadline the actor stops handing out new jobs, but a proof already in flight |
| 89 | +> finishes and publishes late rather than being discarded. |
| 90 | +
|
| 91 | +## Interval 3: Safe target computation |
| 92 | + |
| 93 | +Validators compute the [safe target](./lmd_ghost.md#safe-target-selection) they'll use when |
| 94 | +deciding which finality vote to cast on the next slot. The safe target is computed based on |
| 95 | +the votes received in the current slot. |
| 96 | + |
| 97 | +It is LMD-GHOST run with a two-thirds weight threshold instead of a plain majority, so it |
| 98 | +sits at or behind the head and advances only once a branch is backed by a supermajority. |
| 99 | +Deriving targets from it is what stops [3SF-mini](./3sf_mini.md) from justifying a branch |
| 100 | +the network has not visibly converged on. |
| 101 | + |
| 102 | +## Interval 4: Head update |
| 103 | + |
| 104 | +Validators merge the aggregated attestations they have in their "new attestations buffer" |
| 105 | +into their fork-choice view, and recompute their head. |
| 106 | + |
| 107 | +This is the slot's second and last promotion point; the first is the proposer's, just |
| 108 | +before it builds. Between promotions a vote sits in the buffer without weight, which is |
| 109 | +what keeps a validator's fork-choice view from shifting under it mid-slot. See |
| 110 | +[why staged promotion](./lmd_ghost.md#why-staged-promotion) for the reasoning. |
0 commit comments