@aztec/sequencer-client 5.0.0-private.20260319 → 6.0.0-nightly.20260602
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +282 -21
- package/dest/client/sequencer-client.d.ts +8 -3
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +16 -21
- package/dest/config.d.ts +4 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +35 -14
- package/dest/global_variable_builder/fee_predictor.d.ts +37 -0
- package/dest/global_variable_builder/fee_predictor.d.ts.map +1 -0
- package/dest/global_variable_builder/fee_predictor.js +128 -0
- package/dest/global_variable_builder/fee_provider.d.ts +21 -0
- package/dest/global_variable_builder/fee_provider.d.ts.map +1 -0
- package/dest/global_variable_builder/fee_provider.js +58 -0
- package/dest/global_variable_builder/global_builder.d.ts +14 -14
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +16 -51
- package/dest/global_variable_builder/index.d.ts +4 -2
- package/dest/global_variable_builder/index.d.ts.map +1 -1
- package/dest/global_variable_builder/index.js +2 -0
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/publisher/config.d.ts +15 -3
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +19 -4
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +3 -4
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +1 -1
- package/dest/publisher/sequencer-bundle-simulator.d.ts +96 -0
- package/dest/publisher/sequencer-bundle-simulator.d.ts.map +1 -0
- package/dest/publisher/sequencer-bundle-simulator.js +198 -0
- package/dest/publisher/sequencer-publisher-factory.d.ts +3 -5
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +2 -3
- package/dest/publisher/sequencer-publisher.d.ts +70 -64
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +309 -532
- package/dest/sequencer/automine/automine_factory.d.ts +54 -0
- package/dest/sequencer/automine/automine_factory.d.ts.map +1 -0
- package/dest/sequencer/automine/automine_factory.js +84 -0
- package/dest/sequencer/automine/automine_sequencer.d.ts +151 -0
- package/dest/sequencer/automine/automine_sequencer.d.ts.map +1 -0
- package/dest/sequencer/automine/automine_sequencer.js +506 -0
- package/dest/sequencer/chain_state_overrides.d.ts +61 -0
- package/dest/sequencer/chain_state_overrides.d.ts.map +1 -0
- package/dest/sequencer/chain_state_overrides.js +98 -0
- package/dest/sequencer/checkpoint_proposal_job.d.ts +49 -12
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +632 -153
- package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts +34 -0
- package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_proposal_job_metrics.js +72 -0
- package/dest/sequencer/checkpoint_voter.d.ts +1 -2
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_voter.js +2 -5
- package/dest/sequencer/events.d.ts +46 -2
- package/dest/sequencer/events.d.ts.map +1 -1
- package/dest/sequencer/index.d.ts +3 -1
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +2 -0
- package/dest/sequencer/metrics.d.ts +9 -10
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +34 -20
- package/dest/sequencer/sequencer.d.ts +48 -10
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +274 -70
- package/dest/sequencer/timetable.d.ts +14 -1
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +45 -36
- package/dest/sequencer/types.d.ts +2 -2
- package/dest/sequencer/types.d.ts.map +1 -1
- package/dest/test/utils.d.ts +1 -1
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +7 -6
- package/package.json +27 -27
- package/src/client/sequencer-client.ts +28 -30
- package/src/config.ts +40 -11
- package/src/global_variable_builder/README.md +44 -0
- package/src/global_variable_builder/fee_predictor.ts +172 -0
- package/src/global_variable_builder/fee_provider.ts +75 -0
- package/src/global_variable_builder/global_builder.ts +25 -63
- package/src/global_variable_builder/index.ts +3 -1
- package/src/index.ts +10 -1
- package/src/publisher/config.ts +40 -6
- package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +3 -1
- package/src/publisher/sequencer-bundle-simulator.ts +254 -0
- package/src/publisher/sequencer-publisher-factory.ts +3 -6
- package/src/publisher/sequencer-publisher.ts +365 -576
- package/src/sequencer/README.md +152 -450
- package/src/sequencer/automine/README.md +46 -0
- package/src/sequencer/automine/automine_factory.ts +145 -0
- package/src/sequencer/automine/automine_sequencer.ts +592 -0
- package/src/sequencer/chain_state_overrides.ts +162 -0
- package/src/sequencer/checkpoint_proposal_job.ts +736 -174
- package/src/sequencer/checkpoint_proposal_job_metrics.ts +128 -0
- package/src/sequencer/checkpoint_voter.ts +1 -12
- package/src/sequencer/events.ts +50 -2
- package/src/sequencer/index.ts +2 -0
- package/src/sequencer/metrics.ts +43 -24
- package/src/sequencer/sequencer.ts +331 -78
- package/src/sequencer/timetable.ts +57 -45
- package/src/sequencer/types.ts +1 -1
- package/src/test/utils.ts +28 -10
package/README.md
CHANGED
|
@@ -1,45 +1,306 @@
|
|
|
1
1
|
# Sequencer Client
|
|
2
2
|
|
|
3
|
-
The sequencer is
|
|
3
|
+
The sequencer client is the proposer-side counterpart to the [validator client](../validator-client/README.md): it builds checkpoints, broadcasts the block and checkpoint proposals that validators attest to, and publishes the resulting checkpoint to L1. It runs on any node whose configured validator address has been selected as proposer for the current (or next) slot.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A single instance owns the entire proposer flow for one slot: deciding whether to propose, building several L2 blocks one after another, signing them, gossiping them, collecting attestations from the committee, and submitting the final checkpoint to L1 in one Multicall3 transaction together with governance and slashing votes.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The sequencer does **not** decide what is in the next block on its own. It composes the work of several other subsystems: the [tx pool](../p2p/README.md) supplies transactions, the [validator client](../validator-client/README.md) owns operator keys and contains the `CheckpointBuilder` that actually executes them, the [archiver](../archiver/README.md) provides the L2 chain state needed to anchor each block, the [epoch cache](../epoch-cache/README.md) answers proposer/committee lookups, and the [slasher](../slasher/README.md) supplies offenses to vote on.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Key Concepts
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
### Slots, Blocks, and Checkpoints
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
The Aztec consensus design splits each Aztec slot into multiple L2 blocks. This is the design originally called [building in chunks](https://github.com/AztecProtocol/engineering-designs/blob/main/docs/building-in-chunks/index.md).
|
|
14
14
|
|
|
15
|
-
-
|
|
15
|
+
- **Slot** — a fixed time window (e.g. 72 s) during which one proposer is allowed to build.
|
|
16
|
+
- **Block** — a single batch of transactions, executed and validated as a unit, with its own header.
|
|
17
|
+
- **Checkpoint** — the collection of all blocks built within one slot. The proposer commits to a checkpoint on L1 by submitting a `propose` transaction containing the aggregated header, the blocks' tx effects (as blobs), and the committee attestations.
|
|
18
|
+
- **Sub-slot** — a fixed-duration window within the slot during which one block is built. Sub-slots are equal in length and have deadlines fixed relative to the start of the slot.
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
Several blocks per slot is intentional: it amortizes the fixed L1 cost of a checkpoint over more transactions, and it lets the rest of the network reach a usable state-root much sooner than the full L1 confirmation latency.
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
### Proposed vs Checkpointed Chain
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
There are two tips the sequencer cares about:
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
- The **proposed chain** is the set of blocks that have been broadcast over p2p but not yet committed to L1. Both the sequencer and validators push these blocks into the archiver so the rest of the node can serve them.
|
|
27
|
+
- The **checkpointed chain** is the set of checkpoints that have landed on L1, recovered from `CheckpointProposed` events.
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
Within a slot, the proposer adds blocks to the proposed chain as it goes. Only the last block within the slot is bundled with a `CheckpointProposal` that committee members attest to; intermediate blocks are accepted onto the proposed chain by virtue of the proposer's signature alone, and every node that wants to follow the proposed chain re-executes them. See the [validator client README](../validator-client/README.md) for the consumer side.
|
|
26
30
|
|
|
27
|
-
|
|
31
|
+
### Proposer Pipelining
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+
The legacy ("non-pipelined") flow has the proposer for slot `N` build, attest, and publish inside slot `N`. The proposer spends most of `N` collecting attestations and waiting for the L1 transaction to be mined, leaving a long idle window. Pipelining, [proposed in this discussion](https://github.com/AztecProtocol/governance/discussions/8), removes that idle window: the proposer for slot `N` builds blocks during slot `N - 1`, finishes attestation collection before the slot boundary, and submits the L1 transaction at the start of slot `N`.
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
Pipelining shifts the work like this:
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
| Phase | Non-pipelined | Pipelined |
|
|
38
|
+
| ---------------------------------- | ------------- | ---------------- |
|
|
39
|
+
| Block building | slot `N` | slot `N - 1` |
|
|
40
|
+
| Last-block re-execution | slot `N` | slot `N - 1` |
|
|
41
|
+
| Attestation collection | slot `N` | slot `N - 1` * |
|
|
42
|
+
| L1 submission | slot `N` | slot `N` |
|
|
34
43
|
|
|
35
|
-
|
|
44
|
+
\* The pipelined timing model reserves enough end-of-slot budget for attestations to be in hand by the slot boundary, but the enforced deadline (`checkpointAttestationDeadline`) actually extends to `2 * aztecSlotDuration - l1PublishingTime`, so a late attestation can still spill into the target slot.
|
|
45
|
+
|
|
46
|
+
In practice, "non-pipelined mode" is being removed; this README treats pipelining as the default. The toggle still exists (`enableProposerPipelining`) because `EpochCache` consults it when looking up the proposer for the next L1 slot — when pipelining is enabled, the sequencer asks the cache for the proposer of `slot + 1` rather than `slot`.
|
|
47
|
+
|
|
48
|
+
The pipelining flow introduces two failure modes that block building has to handle:
|
|
49
|
+
|
|
50
|
+
- **Pipeline depth** is bounded to 2 (`checkpointNumber ≤ confirmedCheckpoint + 2`). Building further ahead would require trusting more in-flight parent proposals than the design allows.
|
|
51
|
+
- **Pipelined parent invalidation**: if the parent checkpoint we built on top of fails to land cleanly on L1, the next proposer's work is discarded (`pipelined-checkpoint-discarded` event) and an `invalidate` request is enqueued for the parent.
|
|
52
|
+
|
|
53
|
+
## Architecture
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
57
|
+
│ Sequencer │
|
|
58
|
+
│ (state machine, one slot at a time) │
|
|
59
|
+
│ │
|
|
60
|
+
│ work() ──► prepareCheckpointProposal() ──► proposal job │
|
|
61
|
+
└─────┬────────────────┬──────────────────┬──────────────────┬─┘
|
|
62
|
+
│ │ │ │
|
|
63
|
+
▼ ▼ ▼ ▼
|
|
64
|
+
┌──────────────────┐ ┌──────────┐ ┌──────────────────┐ ┌────────────────┐
|
|
65
|
+
│ ValidatorClient │ │ Epoch │ │ CheckpointBuilder│ │ Sequencer │
|
|
66
|
+
│ (owns keys, │ │ Cache │ │ (forked world │ │ Publisher │
|
|
67
|
+
│ HA signer, │ │ (proposer│ │ state, per-block│ │ (Multicall3 │
|
|
68
|
+
│ signs the │ │ + │ │ execution via │ │ L1 tx, with │
|
|
69
|
+
│ proposals) │ │ comm.) │ │ PublicProcessor)│ │ pre-checks) │
|
|
70
|
+
└──────────────────┘ └──────────┘ └──────────────────┘ └────────────────┘
|
|
71
|
+
│ │ │
|
|
72
|
+
│ block + checkpoint │ pull txs │
|
|
73
|
+
│ proposals over p2p ▼ ▼
|
|
74
|
+
│ ┌──────────┐ ┌────────────┐
|
|
75
|
+
├────────────────────────► │ Tx │ │ L1 Rollup │
|
|
76
|
+
│ │ Provider │ │ Contract │
|
|
77
|
+
│ push blocks to └──────────┘ └────────────┘
|
|
78
|
+
▼ proposed chain
|
|
79
|
+
┌──────────────────┐
|
|
80
|
+
│ Archiver │
|
|
81
|
+
│ (l2 tips, │
|
|
82
|
+
│ addBlock) │
|
|
83
|
+
└──────────────────┘
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`SequencerClient.new(config, deps)` is the entrypoint and is constructed by the full node. It reads L1 constants (`l1GenesisTime`, `slotDuration`, `rollupManaLimit`) from the rollup contract, builds the publisher factory, validator client wiring, and timetable, then instantiates the `Sequencer`. See `src/client/sequencer-client.ts`.
|
|
87
|
+
|
|
88
|
+
### Sequencer (work loop)
|
|
89
|
+
|
|
90
|
+
`Sequencer` (`src/sequencer/sequencer.ts`) drives one slot at a time using a `RunningPromise` that ticks every `sequencerPollingIntervalMS` (default 500 ms). On each tick it:
|
|
91
|
+
|
|
92
|
+
1. Asks the [epoch cache](../epoch-cache/README.md) for the slot at the next L1 block, and, when pipelining, for the *target* slot (`slot + 1`). Building runs during the wall-clock slot; the checkpoint commits to the target slot.
|
|
93
|
+
2. Calls `prepareCheckpointProposal`, which:
|
|
94
|
+
- Dedupes against the last slot we tried to propose for.
|
|
95
|
+
- Runs `checkSync()` — verifies world-state, l2 block source, p2p, and l1-to-l2 message source agree on the parent tip.
|
|
96
|
+
- Checks the escape hatch (governance-controlled freeze) for the target epoch.
|
|
97
|
+
- Calls `checkCanPropose(targetSlot)` to verify one of our configured validator addresses is the elected proposer.
|
|
98
|
+
- Falls back to `considerInvalidatingCheckpoint()` if we are *not* the proposer but a previous checkpoint is stuck with bad attestations and the slot is far enough along to invalidate (`secondsBeforeInvalidatingBlockAsCommitteeMember` / `…AsNonCommitteeMember`).
|
|
99
|
+
- Refuses to build further than two checkpoints ahead of the confirmed tip when pipelining.
|
|
100
|
+
- Builds L1 `eth_call` simulation overrides (so `Rollup.canProposeAt` sees the expected pending tip when we are building on a pipelined parent or invalidating).
|
|
101
|
+
- Calls `publisher.canProposeAt(...)` — if L1 rejects the simulated propose, abort early.
|
|
102
|
+
3. Constructs a `CheckpointProposalJob` and calls `.execute()`, parking the returned `pendingL1Submission` on the sequencer so `stop()` can await it without re-entering the loop.
|
|
103
|
+
|
|
104
|
+
Each state transition flows through `setState()`, which calls `timetable.assertTimeLeft()`. If the slot has advanced past the deadline for the new state, this throws `SequencerTooSlowError` and the slot is abandoned.
|
|
105
|
+
|
|
106
|
+
The sequencer is a `TypedEventEmitter<SequencerEvents>`. The most useful events are:
|
|
107
|
+
|
|
108
|
+
| Event | When emitted |
|
|
109
|
+
| ---------------------------------- | --------------------------------------------------------------------- |
|
|
110
|
+
| `state-changed` | Every `setState()` call. |
|
|
111
|
+
| `preparing-checkpoint` | After the canPropose check decides to build, before L1 simulation. |
|
|
112
|
+
| `block-proposed` | After `buildSingleBlock` succeeds, before sign + archiver push. |
|
|
113
|
+
| `checkpoint-published` | After the L1 submission lands. |
|
|
114
|
+
| `checkpoint-publish-failed` | Multicall3 tx failed or expired. |
|
|
115
|
+
| `pipelined-checkpoint-discarded` | Pipelined parent failed to land; this slot's work is thrown away. |
|
|
116
|
+
| `checkpoint-error` | Catch-all: an exception escaped `work()`. |
|
|
117
|
+
|
|
118
|
+
State enum (`src/sequencer/utils.ts`):
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
STOPPED → STOPPING → IDLE → SYNCHRONIZING → PROPOSER_CHECK
|
|
122
|
+
→ INITIALIZING_CHECKPOINT
|
|
123
|
+
→ (WAITING_FOR_TXS ↔ CREATING_BLOCK ↔ WAITING_UNTIL_NEXT_BLOCK)*
|
|
124
|
+
→ ASSEMBLING_CHECKPOINT
|
|
125
|
+
→ COLLECTING_ATTESTATIONS
|
|
126
|
+
→ PUBLISHING_CHECKPOINT
|
|
127
|
+
→ IDLE
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### CheckpointProposalJob
|
|
131
|
+
|
|
132
|
+
`CheckpointProposalJob` (`src/sequencer/checkpoint_proposal_job.ts`) is the per-slot unit of work. It owns the lifecycle from "we have decided to propose" through "the L1 transaction has been submitted". The contract is:
|
|
133
|
+
|
|
134
|
+
- `execute()` returns once the checkpoint has been broadcast over p2p (or has failed before that). The L1 submission runs in the background as `pendingL1Submission`.
|
|
135
|
+
- All work scheduled on the publisher (governance vote, slashing actions, propose, invalidate) is enqueued early and then flushed together in a single Multicall3 transaction.
|
|
136
|
+
|
|
137
|
+
Inside `execute()`:
|
|
138
|
+
|
|
139
|
+
1. **Vote enqueueing.** `CheckpointVoter.enqueueVotes()` signs and enqueues the governance and slashing vote requests up front. Even if block-building fails, these still go out in the final Multicall3 — they are the proposer's duty for the slot.
|
|
140
|
+
2. **`proposeCheckpoint()`** (blocking, returns a `CheckpointProposal`):
|
|
141
|
+
- Transitions to `INITIALIZING_CHECKPOINT`. If there is a pending invalidation, enqueue it.
|
|
142
|
+
- Builds **pipelined-parent simulation overrides**: when building on top of a parent that hasn't landed on L1 yet, the fee-asset price modifier must be computed against the parent fee header we predicted (not the L1 one), so all in-flight checkpoints in the pipeline agree on the same modifier.
|
|
143
|
+
- Asks the global variables builder for the slot's `CheckpointGlobalVariables` (`coinbase`, `feeRecipient`, `timestamp`, `gasFees`, `chainId`, `version`, `slotNumber`). These are shared across every block within the checkpoint — only `blockNumber` increments.
|
|
144
|
+
- Computes `inHash` from the L1→L2 messages for the checkpoint, and collects `previousCheckpointOutHashes` for prior checkpoints in the same epoch.
|
|
145
|
+
- Forks world state at the parent (`closeDelayMs: 12 s`) and asks `FullNodeCheckpointsBuilder` for a `CheckpointBuilder` bound to that fork.
|
|
146
|
+
- Runs `buildBlocksForCheckpoint()` — the per-block loop, described below.
|
|
147
|
+
- Transitions to `ASSEMBLING_CHECKPOINT`, asks the builder to `completeCheckpoint()`, validates it against the configured caps, and asks the validator client to sign the `CheckpointProposal` (which bundles the final block proposal so the two travel together).
|
|
148
|
+
- Broadcasts the `CheckpointProposal` via p2p.
|
|
149
|
+
3. **Attestation collection** (`waitForAttestationsAndEnqueueSubmissionAsync`) runs in the background:
|
|
150
|
+
- Transitions to `COLLECTING_ATTESTATIONS`. Reads the committee from `EpochCache`, computes the quorum (`2/3 + 1`), and waits for that many attestations on p2p. The validator client adds the proposer's own signature.
|
|
151
|
+
- If pipelining: `waitForValidParentCheckpointOnL1()` waits for the archiver to confirm the parent we built on top of has landed on L1 with matching hash and valid attestations. If not, the work is dropped (`pipelined-checkpoint-discarded`) and we enqueue an invalidation for the parent so the next proposer doesn't repeat the same mistake.
|
|
152
|
+
- Computes `submitAfter`: `getTimestampForSlot(targetSlot)` when pipelining (so the Multicall3 mines inside the target slot — EIP-712 signatures are bound to a slot and would silently fail if mined outside it), otherwise "now".
|
|
153
|
+
- Calls `publisher.sendRequestsAt(submitAfter)`, which sleeps until the deadline, re-runs each request's `preCheck` against fresh L1 state, and submits the bundled Multicall3.
|
|
154
|
+
|
|
155
|
+
### Per-block loop (`buildBlocksForCheckpoint`)
|
|
156
|
+
|
|
157
|
+
The per-block loop is the heart of the building flow:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
loop:
|
|
161
|
+
timing = timetable.canStartNextBlock(secondsIntoSlot)
|
|
162
|
+
if !timing.canStart: break
|
|
163
|
+
if blocksBuilt >= maxBlocksPerCheckpoint: break
|
|
164
|
+
|
|
165
|
+
state = WAITING_FOR_TXS
|
|
166
|
+
result = checkpointBuilder.buildBlock(
|
|
167
|
+
pendingTxs, blockNumber, timestamp,
|
|
168
|
+
{ maxTransactions, maxBlockGas, deadline,
|
|
169
|
+
minValidTxs, maxBlocksPerCheckpoint, perBlockAllocationMultiplier })
|
|
170
|
+
|
|
171
|
+
if result is 'insufficient-txs' or 'insufficient-valid-txs':
|
|
172
|
+
if isLastBlock or no deadline: break
|
|
173
|
+
else: continue (try next sub-slot)
|
|
174
|
+
if result is error: halt
|
|
175
|
+
|
|
176
|
+
blockProposal = validatorClient.createBlockProposal(block)
|
|
177
|
+
archiver.addBlock(block) // push to proposed chain
|
|
178
|
+
if not timing.isLastBlock:
|
|
179
|
+
p2pClient.broadcastProposal(blockProposal)
|
|
180
|
+
else:
|
|
181
|
+
blockPendingBroadcast = blockProposal // shipped with the CheckpointProposal
|
|
182
|
+
|
|
183
|
+
state = WAITING_UNTIL_NEXT_BLOCK
|
|
184
|
+
waitUntilNextSubSlot(timing.deadline)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The deadlines passed to `CheckpointBuilder.buildBlock` are absolute timestamps (`slotStart + timing.deadline`). The builder uses these as hard caps on tx execution, so a slow block cannot eat into the next sub-slot.
|
|
188
|
+
|
|
189
|
+
`maxBlocksPerCheckpoint` (the timetable's `maxNumberOfBlocks`) and `perBlockAllocationMultiplier` (default 1.2) are passed in opts so that the builder can redistribute the remaining checkpoint budget (L2 gas, DA gas, blob fields, tx count) across the remaining blocks. See [validator-client/README.md § Block Building Limits](../validator-client/README.md#block-building-limits) for the redistribution math; the sequencer only sets the inputs.
|
|
190
|
+
|
|
191
|
+
### Timetable
|
|
192
|
+
|
|
193
|
+
`SequencerTimetable` (`src/sequencer/timetable.ts`) is a thin wrapper around `CheckpointTiming` (from `@aztec/stdlib/timetable`). It owns two responsibilities:
|
|
194
|
+
|
|
195
|
+
- **Sub-slot scheduling**: `canStartNextBlock(secondsIntoSlot)` finds the next sub-slot with at least `minExecutionTime` remaining and returns its deadline and whether it is the last sub-slot. If we are running late, sub-slots are skipped; we never start a block we cannot finish.
|
|
196
|
+
- **Per-state deadlines**: `getMaxAllowedTime(state)` returns the latest seconds-into-slot value a state is allowed to be entered; `assertTimeLeft()` enforces it.
|
|
197
|
+
|
|
198
|
+
See [`src/sequencer/README.md`](src/sequencer/README.md) for the full timing model, including the pipelining math and the failure-mode walkthroughs.
|
|
199
|
+
|
|
200
|
+
### SequencerPublisher
|
|
201
|
+
|
|
202
|
+
`SequencerPublisher` (`src/publisher/sequencer-publisher.ts`) translates "I want to propose a checkpoint" into "submit this Multicall3 transaction to L1". It maintains an ordered queue of `RequestWithExpiry` entries — each one has a label (`propose`, `invalidate-by-*`, `governance-signal`, `vote-offenses`, `execute-slash`), a `preCheck` callback, and an ABI-encoded call. The queue is sorted so invalidations go first and proposes precede votes.
|
|
203
|
+
|
|
204
|
+
Key entry points:
|
|
205
|
+
|
|
206
|
+
- `canProposeAt(archive, msgSender, simulationOverridesPlan?)` — eth_call simulation of `Rollup.canProposeAt`. The sequencer runs this before deciding to build.
|
|
207
|
+
- `enqueueProposeCheckpoint(checkpoint, attestations, attestationsSignature, opts)` — adds the propose call, with a `preCheck` that re-validates the proposal against real L1 state when it is finally sent (catches drift between build time and submit time).
|
|
208
|
+
- `enqueueInvalidateCheckpoint`, `enqueueGovernanceCastSignal`, `enqueueSlashingActions` — the rest of the actions a proposer may bundle.
|
|
209
|
+
- `sendRequests()` — immediately flushes the queue as one Multicall3 transaction.
|
|
210
|
+
- `sendRequestsAt(submitAfter)` — sleeps (cancellable) until `submitAfter`, runs each request's `preCheck` (dropping those that fail), and then calls `sendRequests()`, which filters expired requests, sorts the remainder, and submits one Multicall3. Pipelining is implemented entirely by passing `getTimestampForSlot(targetSlot)` here.
|
|
211
|
+
|
|
212
|
+
`SequencerPublisherFactory` produces one publisher per attempt, wrapping an L1 publisher (EOA + `L1TxUtils`) leased from `PublisherManager`. Leases free the publisher when the job completes so multiple validator addresses on the same node can take turns without conflicts.
|
|
213
|
+
|
|
214
|
+
### Other components
|
|
215
|
+
|
|
216
|
+
| Component | File | Responsibility |
|
|
217
|
+
| --- | --- | --- |
|
|
218
|
+
| `CheckpointVoter` | `src/sequencer/checkpoint_voter.ts` | Signs and enqueues governance/slashing votes. Used by both the job and the "vote even though we can't propose" fallbacks. |
|
|
219
|
+
| `GlobalVariableBuilder` | `src/global_variable_builder/` | Computes `CheckpointGlobalVariables` and predicts the per-slot fee asset price modifier. See its [README](src/global_variable_builder/README.md). |
|
|
220
|
+
| `L1TxFailedStore` | `src/publisher/l1_tx_failed_store/` | Persists actions that returned a revert reason so they aren't retried in the same form on the next slot. |
|
|
221
|
+
| `ChainStateOverrides` | `src/sequencer/chain_state_overrides.ts` | Builds the L1 `eth_call` overrides used during the pipelined parent + invalidation simulations. |
|
|
222
|
+
| `AutomineSequencer` | `src/sequencer/automine/` | Minimal queue-driven sequencer for single-sequencer e2e tests. Bypasses consensus, pipelining, and timetable enforcement. See [`src/sequencer/automine/README.md`](src/sequencer/automine/README.md). |
|
|
223
|
+
|
|
224
|
+
## Configuration
|
|
225
|
+
|
|
226
|
+
The configuration object is `SequencerConfig` (`src/sequencer/config.ts` + `src/publisher/config.ts`). The options that most directly affect block building are:
|
|
227
|
+
|
|
228
|
+
### Block budgets
|
|
229
|
+
|
|
230
|
+
| Option / env var | Default | Purpose |
|
|
231
|
+
| --- | --- | --- |
|
|
232
|
+
| `minTxsPerBlock` / `SEQ_MIN_TX_PER_BLOCK` | 1 | Wait for at least this many txs before starting a block. |
|
|
233
|
+
| `minValidTxsPerBlock` | falls back to `minTxsPerBlock` | After execution, discard the block if fewer txs validated. |
|
|
234
|
+
| `maxTxsPerBlock` / `SEQ_MAX_TX_PER_BLOCK` | unset | Hard per-block tx cap (capped at `maxTxsPerCheckpoint` at startup). |
|
|
235
|
+
| `maxTxsPerCheckpoint` / `SEQ_MAX_TX_PER_CHECKPOINT` | unset | Total tx cap across the checkpoint. Enables redistribution when set. |
|
|
236
|
+
| `maxBlocksPerCheckpoint` / `MAX_BLOCKS_PER_CHECKPOINT` | 24 | Hard ceiling beyond what the timetable allows. Also caps the `indexWithinCheckpoint` accepted on inbound block proposals. |
|
|
237
|
+
| `maxL2BlockGas` / `SEQ_MAX_L2_BLOCK_GAS` | unset | Per-block mana cap, capped at `rollupManaLimit`. |
|
|
238
|
+
| `maxDABlockGas` / `SEQ_MAX_DA_BLOCK_GAS` | unset | Per-block DA gas cap, capped at `MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT`. |
|
|
239
|
+
| `perBlockAllocationMultiplier` / `SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER` | 1.2 | Multiplier passed to the checkpoint builder so early blocks can use slightly more than their even share. |
|
|
240
|
+
| `redistributeCheckpointBudget` / `SEQ_REDISTRIBUTE_CHECKPOINT_BUDGET` | true | Legacy flag. Redistribution is always on during proposal building. |
|
|
241
|
+
|
|
242
|
+
### Timing
|
|
243
|
+
|
|
244
|
+
| Option / env var | Default | Purpose |
|
|
245
|
+
| --- | --- | --- |
|
|
246
|
+
| `blockDurationMs` / `SEQ_BLOCK_DURATION_MS` | unset | Length of one sub-slot in ms. `undefined` falls back to single-block-per-slot mode (used by tests / sandbox). |
|
|
247
|
+
| `enforceTimeTable` / `SEQ_ENFORCE_TIME_TABLE` | true | If false, deadlines are not enforced and a single block is built with unbounded time. |
|
|
248
|
+
| `attestationPropagationTime` / `SEQ_ATTESTATION_PROPAGATION_TIME` | 2 s | One-way p2p estimate fed to the timetable. |
|
|
249
|
+
| `l1PublishingTime` / `SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT` | full L1 slot | Time reserved for the L1 tx to land. |
|
|
250
|
+
| `sequencerPollingIntervalMS` / `SEQ_POLLING_INTERVAL_MS` | 500 | Work-loop tick rate. |
|
|
251
|
+
| `enableProposerPipelining` / `SEQ_ENABLE_PROPOSER_PIPELINING` | false | When true, the sequencer builds for `slot + 1`. The flag lives in shared `PipelineConfig` and is read by `EpochCache`, not by the sequencer directly. |
|
|
252
|
+
|
|
253
|
+
### Behavior
|
|
254
|
+
|
|
255
|
+
| Option / env var | Default | Purpose |
|
|
256
|
+
| --- | --- | --- |
|
|
257
|
+
| `buildCheckpointIfEmpty` / `SEQ_BUILD_CHECKPOINT_IF_EMPTY` | false | Build and submit even when no txs are available. |
|
|
258
|
+
| `publishTxsWithProposals` / `SEQ_PUBLISH_TXS_WITH_PROPOSALS` | false | Embed full transactions in p2p block proposals (DA fallback for validators). |
|
|
259
|
+
| `fishermanMode` / `FISHERMAN_MODE` | false | Build internally for monitoring; never publish. |
|
|
260
|
+
| `coinbase` / `COINBASE` | proposer addr | Recipient of block rewards. |
|
|
261
|
+
| `feeRecipient` / `FEE_RECIPIENT` | proposer addr | Recipient of tx fees. |
|
|
262
|
+
| `governanceProposerPayload` / `GOVERNANCE_PROPOSER_PAYLOAD_ADDRESS` | unset | Payload signaled in the governance vote each slot. |
|
|
263
|
+
| `secondsBeforeInvalidatingBlockAsCommitteeMember` | 144 | When *not* the proposer, committee members may invalidate a stuck checkpoint after this many seconds into the slot. |
|
|
264
|
+
| `secondsBeforeInvalidatingBlockAsNonCommitteeMember` | 432 | Same for any node — last resort. |
|
|
265
|
+
|
|
266
|
+
The full list (including test/fault-injection hooks like `pauseProposingForSlots` and `skipPublishingCheckpointsPercent`) lives in `src/config.ts`.
|
|
267
|
+
|
|
268
|
+
## Failure modes
|
|
269
|
+
|
|
270
|
+
- **Not the proposer**: `checkCanPropose` returns false → no work done. If a previous checkpoint is stuck with invalid attestations and we are past the configured invalidation threshold, we fall through to `considerInvalidatingCheckpoint` and may still submit an invalidation tx.
|
|
271
|
+
- **Out of sync**: `checkSync` fails → governance/slashing votes still go out via `tryVoteWhenSyncFails`, but no block is built.
|
|
272
|
+
- **Insufficient txs in a sub-slot**: `CheckpointBuilder.buildBlock` returns `insufficient-txs`. The sub-slot is skipped without committing state; the next sub-slot retries. On the last sub-slot, if `buildCheckpointIfEmpty` is true, the block is still built with whatever is available (possibly zero txs).
|
|
273
|
+
- **Sub-slot deadline exceeded**: `CheckpointBuilder` enforces the deadline and stops executing further txs. The block is finalized with whatever fit.
|
|
274
|
+
- **Timetable deadline exceeded**: `assertTimeLeft` throws `SequencerTooSlowError`. The current slot is abandoned and the loop resets to `IDLE`.
|
|
275
|
+
- **Pipelined parent fails on L1**: `waitForValidParentCheckpointOnL1` returns false. The whole proposal is discarded (`pipelined-checkpoint-discarded`), the parent is enqueued for invalidation, and the L1 submission for *this* checkpoint is not sent.
|
|
276
|
+
- **L1 submission reverts or expires**: `checkpoint-publish-failed` is emitted with the individual action results so observability can break down which actions in the Multicall3 went through and which didn't.
|
|
277
|
+
|
|
278
|
+
## Where to look first
|
|
279
|
+
|
|
280
|
+
| Question | File |
|
|
281
|
+
| --- | --- |
|
|
282
|
+
| How does the work loop decide whether to propose? | `src/sequencer/sequencer.ts` → `prepareCheckpointProposal`, `checkCanPropose` |
|
|
283
|
+
| How does a checkpoint get built block-by-block? | `src/sequencer/checkpoint_proposal_job.ts` → `proposeCheckpoint`, `buildBlocksForCheckpoint` |
|
|
284
|
+
| How do sub-slot deadlines work? | `src/sequencer/timetable.ts` + `src/sequencer/README.md` |
|
|
285
|
+
| How does an L1 transaction get scheduled and submitted? | `src/publisher/sequencer-publisher.ts` → `sendRequestsAt` |
|
|
286
|
+
| How does pipelining wait for the parent to land? | `src/sequencer/checkpoint_proposal_job.ts` → `waitForValidParentCheckpointOnL1` |
|
|
287
|
+
| How do governance and slashing votes get into the L1 tx? | `src/sequencer/checkpoint_voter.ts` |
|
|
288
|
+
| How are fees predicted for the slot? | `src/global_variable_builder/README.md` |
|
|
289
|
+
| How are full-node services wired together? | `src/client/sequencer-client.ts` |
|
|
36
290
|
|
|
37
291
|
## Development
|
|
38
292
|
|
|
39
|
-
|
|
293
|
+
Build, format, lint, and test from `yarn-project/`:
|
|
40
294
|
|
|
41
|
-
|
|
295
|
+
```bash
|
|
296
|
+
yarn workspace @aztec/sequencer-client build
|
|
297
|
+
yarn workspace @aztec/sequencer-client test
|
|
298
|
+
```
|
|
42
299
|
|
|
43
|
-
|
|
300
|
+
The integration tests of interest are:
|
|
44
301
|
|
|
45
|
-
|
|
302
|
+
- `src/sequencer/sequencer.test.ts` — work-loop behavior, escape-hatch and invalidation fallbacks.
|
|
303
|
+
- `src/sequencer/checkpoint_proposal_job.test.ts` — full per-slot job, both pipelined and non-pipelined.
|
|
304
|
+
- `src/sequencer/checkpoint_proposal_job.timing.test.ts` — sub-slot timing and skip behavior under simulated clock drift.
|
|
305
|
+
- `src/sequencer/timetable.test.ts` — pure math against `CheckpointTiming`.
|
|
306
|
+
- `src/publisher/sequencer-publisher.test.ts` — request ordering, `sendRequestsAt`, preCheck re-runs.
|
|
@@ -7,12 +7,13 @@ import type { DateProvider } from '@aztec/foundation/timer';
|
|
|
7
7
|
import type { KeystoreManager } from '@aztec/node-keystore';
|
|
8
8
|
import type { P2P } from '@aztec/p2p';
|
|
9
9
|
import type { SlasherClientInterface } from '@aztec/slasher';
|
|
10
|
-
import type { L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
10
|
+
import type { L2BlockSink, L2BlockSource, ProposedCheckpointSink } from '@aztec/stdlib/block';
|
|
11
11
|
import type { ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
12
12
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
13
13
|
import { L1Metrics, type TelemetryClient } from '@aztec/telemetry-client';
|
|
14
14
|
import { FullNodeCheckpointsBuilder, NodeKeystoreAdapter, type ValidatorClient } from '@aztec/validator-client';
|
|
15
15
|
import { type SequencerClientConfig } from '../config.js';
|
|
16
|
+
import type { GlobalVariableBuilder } from '../global_variable_builder/index.js';
|
|
16
17
|
import { SequencerPublisherFactory } from '../publisher/sequencer-publisher-factory.js';
|
|
17
18
|
import { Sequencer, type SequencerConfig } from '../sequencer/index.js';
|
|
18
19
|
/**
|
|
@@ -44,7 +45,7 @@ export declare class SequencerClient {
|
|
|
44
45
|
worldStateSynchronizer: WorldStateSynchronizer;
|
|
45
46
|
slasherClient: SlasherClientInterface | undefined;
|
|
46
47
|
checkpointsBuilder: FullNodeCheckpointsBuilder;
|
|
47
|
-
l2BlockSource: L2BlockSource & L2BlockSink;
|
|
48
|
+
l2BlockSource: L2BlockSource & L2BlockSink & ProposedCheckpointSink;
|
|
48
49
|
l1ToL2MessageSource: L1ToL2MessageSource;
|
|
49
50
|
telemetry: TelemetryClient;
|
|
50
51
|
publisherFactory?: SequencerPublisherFactory;
|
|
@@ -52,7 +53,9 @@ export declare class SequencerClient {
|
|
|
52
53
|
dateProvider: DateProvider;
|
|
53
54
|
epochCache?: EpochCache;
|
|
54
55
|
l1TxUtils: L1TxUtils[];
|
|
56
|
+
funderL1TxUtils?: L1TxUtils;
|
|
55
57
|
nodeKeyStore: KeystoreManager;
|
|
58
|
+
globalVariableBuilder: GlobalVariableBuilder;
|
|
56
59
|
}): Promise<SequencerClient>;
|
|
57
60
|
/**
|
|
58
61
|
* Updates sequencer and validator client config.
|
|
@@ -65,6 +68,8 @@ export declare class SequencerClient {
|
|
|
65
68
|
* Stops the sequencer from processing new txs.
|
|
66
69
|
*/
|
|
67
70
|
stop(): Promise<void>;
|
|
71
|
+
/** Triggers an immediate run of the sequencer, bypassing the polling interval. */
|
|
72
|
+
trigger(): Promise<void> | undefined;
|
|
68
73
|
getSequencer(): Sequencer;
|
|
69
74
|
/** Updates the publisher factory's node keystore adapter after a keystore reload. */
|
|
70
75
|
updatePublisherNodeKeyStore(adapter: NodeKeystoreAdapter): void;
|
|
@@ -73,4 +78,4 @@ export declare class SequencerClient {
|
|
|
73
78
|
get validatorAddresses(): EthAddress[] | undefined;
|
|
74
79
|
get maxL2BlockGas(): number | undefined;
|
|
75
80
|
}
|
|
76
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VxdWVuY2VyLWNsaWVudC5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaWVudC9zZXF1ZW5jZXItY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFckUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBSWhELE9BQU8sRUFBRSxLQUFLLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUN0RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNyRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFFM0QsT0FBTyxLQUFLLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDNUQsT0FBTyxLQUFLLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDNUQsT0FBTyxLQUFLLEVBQUUsR0FBRyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3RDLE9BQU8sS0FBSyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0QsT0FBTyxLQUFLLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzlGLE9BQU8sS0FBSyxFQUFFLHlCQUF5QixFQUFFLHNCQUFzQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDekcsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNuRSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssZUFBZSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDMUUsT0FBTyxFQUFFLDBCQUEwQixFQUFFLG1CQUFtQixFQUFFLEtBQUssZUFBZSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFaEgsT0FBTyxFQUFFLEtBQUsscUJB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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequencer-client.d.ts","sourceRoot":"","sources":["../../src/client/sequencer-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIhD,OAAO,EAAE,KAAK,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"sequencer-client.d.ts","sourceRoot":"","sources":["../../src/client/sequencer-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,13 +4,10 @@ import { isAnvilTestChain } from '@aztec/ethereum/chain';
|
|
|
4
4
|
import { getPublicClient } from '@aztec/ethereum/client';
|
|
5
5
|
import { GovernanceProposerContract, RollupContract } from '@aztec/ethereum/contracts';
|
|
6
6
|
import { PublisherManager } from '@aztec/ethereum/publisher-manager';
|
|
7
|
-
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
8
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
9
|
-
import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
10
8
|
import { L1Metrics } from '@aztec/telemetry-client';
|
|
11
9
|
import { NodeKeystoreAdapter } from '@aztec/validator-client';
|
|
12
10
|
import { getPublisherConfigFromSequencerConfig } from '../config.js';
|
|
13
|
-
import { GlobalVariableBuilder } from '../global_variable_builder/index.js';
|
|
14
11
|
import { SequencerPublisherFactory } from '../publisher/sequencer-publisher-factory.js';
|
|
15
12
|
import { Sequencer } from '../sequencer/index.js';
|
|
16
13
|
/**
|
|
@@ -48,16 +45,18 @@ import { Sequencer } from '../sequencer/index.js';
|
|
|
48
45
|
const publicClient = getPublicClient(config);
|
|
49
46
|
const l1TxUtils = deps.l1TxUtils;
|
|
50
47
|
const l1Metrics = new L1Metrics(telemetryClient.getMeter('L1PublisherMetrics'), publicClient, l1TxUtils.map((x)=>x.getSenderAddress()));
|
|
51
|
-
const publisherManager = new PublisherManager(l1TxUtils, getPublisherConfigFromSequencerConfig(config),
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
const publisherManager = new PublisherManager(l1TxUtils, getPublisherConfigFromSequencerConfig(config), {
|
|
49
|
+
bindings: log.getBindings(),
|
|
50
|
+
funder: deps.funderL1TxUtils
|
|
51
|
+
});
|
|
52
|
+
const rollupContract = new RollupContract(publicClient, config.rollupAddress.toString());
|
|
53
|
+
const [l1GenesisTime, slotDuration, rollupManaLimit] = await Promise.all([
|
|
54
54
|
rollupContract.getL1GenesisTime(),
|
|
55
55
|
rollupContract.getSlotDuration(),
|
|
56
|
-
rollupContract.getVersion(),
|
|
57
56
|
rollupContract.getManaLimit().then(Number)
|
|
58
57
|
]);
|
|
59
|
-
const governanceProposerContract = new GovernanceProposerContract(publicClient, config.
|
|
60
|
-
const epochCache = deps.epochCache ?? await EpochCache.create(config.
|
|
58
|
+
const governanceProposerContract = new GovernanceProposerContract(publicClient, config.governanceProposerAddress.toString());
|
|
59
|
+
const epochCache = deps.epochCache ?? await EpochCache.create(config.rollupAddress, {
|
|
61
60
|
l1RpcUrls: rpcUrls,
|
|
62
61
|
l1ChainId: chainId,
|
|
63
62
|
viemPollingIntervalMS: config.viemPollingIntervalMS,
|
|
@@ -66,13 +65,11 @@ import { Sequencer } from '../sequencer/index.js';
|
|
|
66
65
|
}, {
|
|
67
66
|
dateProvider: deps.dateProvider
|
|
68
67
|
});
|
|
69
|
-
const slashFactoryContract = new SlashFactoryContract(publicClient, config.l1Contracts.slashFactoryAddress?.toString() ?? EthAddress.ZERO.toString());
|
|
70
68
|
const publisherFactory = deps.publisherFactory ?? new SequencerPublisherFactory(config, {
|
|
71
69
|
telemetry: telemetryClient,
|
|
72
70
|
blobClient: deps.blobClient,
|
|
73
71
|
epochCache,
|
|
74
72
|
governanceProposerContract,
|
|
75
|
-
slashFactoryContract,
|
|
76
73
|
rollupContract,
|
|
77
74
|
dateProvider: deps.dateProvider,
|
|
78
75
|
publisherManager,
|
|
@@ -80,13 +77,7 @@ import { Sequencer } from '../sequencer/index.js';
|
|
|
80
77
|
logger: log
|
|
81
78
|
});
|
|
82
79
|
const ethereumSlotDuration = config.ethereumSlotDuration;
|
|
83
|
-
const globalsBuilder =
|
|
84
|
-
...config,
|
|
85
|
-
l1GenesisTime,
|
|
86
|
-
slotDuration: Number(slotDuration),
|
|
87
|
-
ethereumSlotDuration,
|
|
88
|
-
rollupVersion
|
|
89
|
-
});
|
|
80
|
+
const globalsBuilder = deps.globalVariableBuilder;
|
|
90
81
|
// When running in anvil, assume we can post a tx up until one second before the end of an L1 slot.
|
|
91
82
|
// Otherwise, we need the full L1 slot duration for publishing to ensure inclusion.
|
|
92
83
|
// In theory, the L1 slot has an initial 4s phase where the block is propagated, so we could
|
|
@@ -99,7 +90,8 @@ import { Sequencer } from '../sequencer/index.js';
|
|
|
99
90
|
l1GenesisTime,
|
|
100
91
|
slotDuration: Number(slotDuration),
|
|
101
92
|
ethereumSlotDuration,
|
|
102
|
-
rollupManaLimit
|
|
93
|
+
rollupManaLimit,
|
|
94
|
+
epochDuration: config.aztecEpochDuration
|
|
103
95
|
};
|
|
104
96
|
const sequencer = new Sequencer(publisherFactory, validatorClient, globalsBuilder, p2pClient, worldStateSynchronizer, slasherClient, l2BlockSource, l1ToL2MessageSource, checkpointsBuilder, l1Constants, deps.dateProvider, epochCache, rollupContract, {
|
|
105
97
|
...config,
|
|
@@ -125,16 +117,19 @@ import { Sequencer } from '../sequencer/index.js';
|
|
|
125
117
|
await this.validatorClient?.start();
|
|
126
118
|
this.sequencer.start();
|
|
127
119
|
this.l1Metrics?.start();
|
|
128
|
-
await this.publisherManager.
|
|
120
|
+
await this.publisherManager.start();
|
|
129
121
|
}
|
|
130
122
|
/**
|
|
131
123
|
* Stops the sequencer from processing new txs.
|
|
132
124
|
*/ async stop() {
|
|
133
125
|
await this.sequencer.stop();
|
|
134
126
|
await this.validatorClient?.stop();
|
|
135
|
-
this.publisherManager.
|
|
127
|
+
await this.publisherManager.stop();
|
|
136
128
|
this.l1Metrics?.stop();
|
|
137
129
|
}
|
|
130
|
+
/** Triggers an immediate run of the sequencer, bypassing the polling interval. */ trigger() {
|
|
131
|
+
return this.sequencer.trigger();
|
|
132
|
+
}
|
|
138
133
|
getSequencer() {
|
|
139
134
|
return this.sequencer;
|
|
140
135
|
}
|
package/dest/config.d.ts
CHANGED
|
@@ -25,7 +25,9 @@ export declare const DefaultSequencerConfig: {
|
|
|
25
25
|
secondsBeforeInvalidatingBlockAsNonCommitteeMember: number;
|
|
26
26
|
skipCollectingAttestations: false;
|
|
27
27
|
skipInvalidateBlockAsProposer: false;
|
|
28
|
+
skipWaitForValidParentCheckpointOnL1: false;
|
|
28
29
|
broadcastInvalidBlockProposal: false;
|
|
30
|
+
broadcastInvalidCheckpointProposalOnly: false;
|
|
29
31
|
injectFakeAttestation: false;
|
|
30
32
|
injectHighSValueAttestation: false;
|
|
31
33
|
injectUnrecoverableSignatureAttestation: false;
|
|
@@ -33,6 +35,7 @@ export declare const DefaultSequencerConfig: {
|
|
|
33
35
|
shuffleAttestationOrdering: false;
|
|
34
36
|
skipPushProposedBlocksToArchiver: false;
|
|
35
37
|
skipPublishingCheckpointsPercent: number;
|
|
38
|
+
maxBlocksPerCheckpoint: number;
|
|
36
39
|
};
|
|
37
40
|
/**
|
|
38
41
|
* Configuration settings for the SequencerClient.
|
|
@@ -44,4 +47,4 @@ export declare const sequencerClientConfigMappings: ConfigMappingsType<Sequencer
|
|
|
44
47
|
* Creates an instance of SequencerClientConfig out of environment variables using sensible defaults for integration testing if not set.
|
|
45
48
|
*/
|
|
46
49
|
export declare function getConfigEnvVars(): SequencerClientConfig;
|
|
47
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
50
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLGlCQUFpQixFQUE2QixNQUFNLHdCQUF3QixDQUFDO0FBQzNGLE9BQU8sRUFBRSxLQUFLLGNBQWMsRUFBMEIsTUFBTSwyQkFBMkIsQ0FBQztBQUN4RixPQUFPLEVBQ0wsS0FBSyxrQkFBa0IsRUFNeEIsTUFBTSwwQkFBMEIsQ0FBQztBQUVsQyxPQUFPLEVBQUUsS0FBSyxjQUFjLEVBQTBCLE1BQU0sNkJBQTZCLENBQUM7QUFDMUYsT0FBTyxFQUFFLEtBQUssU0FBUyxFQUFxQixNQUFNLG1CQUFtQixDQUFDO0FBRXRFLE9BQU8sRUFDTCxLQUFLLFdBQVcsRUFFaEIsS0FBSyxjQUFjLEVBQ25CLEtBQUssZUFBZSxFQUlyQixNQUFNLHNCQUFzQixDQUFDO0FBRzlCLE9BQU8sRUFBRSxLQUFLLHFCQUFxQixFQUFpQyxNQUFNLGdDQUFnQyxDQUFDO0FBRTNHLE9BQU8sRUFDTCxLQUFLLHdCQUF3QixFQUM3QixLQUFLLHVCQUF1QixFQUc3QixNQUFNLHVCQUF1QixDQUFDO0FBRS9CLGNBQWMsdUJBQXVCLENBQUM7QUFDdEMsWUFBWSxFQUFFLGVBQWUsRUFBRSxDQUFDO0FBRWhDOzs7R0FHRztBQUNILGVBQU8sTUFBTSxzQkFBc0I7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztDQXdCQSxDQUFDO0FBRXBDOztHQUVHO0FBQ0gsTUFBTSxNQUFNLHFCQUFxQixHQUFHLHdCQUF3QixHQUMxRCxjQUFjLEdBQ2QscUJBQXFCLEdBQ3JCLHVCQUF1QixHQUN2QixlQUFlLEdBQ2YsY0FBYyxHQUNkLFdBQVcsR0FDWCxjQUFjLEdBQ2QsSUFBSSxDQUFDLFNBQVMsRUFBRSw4QkFBOEIsQ0FBQyxHQUMvQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsc0JBQXNCLEdBQUcsbUJBQW1CLEdBQUcsb0JBQW9CLENBQUMsQ0FBQztBQUUvRixlQUFPLE1BQU0sdUJBQXVCLEVBQUUsa0JBQWtCLENBQUMsZUFBZSxDQXdMdkUsQ0FBQztBQUVGLGVBQU8sTUFBTSw2QkFBNkIsRUFBRSxrQkFBa0IsQ0FBQyxxQkFBcUIsQ0FVbkYsQ0FBQztBQUVGOztHQUVHO0FBQ0gsd0JBQWdCLGdCQUFnQixJQUFJLHFCQUFxQixDQUV4RCJ9
|
package/dest/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAA6B,MAAM,wBAAwB,CAAC;AAC3F,OAAO,EAAE,KAAK,cAAc,EAA0B,MAAM,2BAA2B,CAAC;AACxF,OAAO,EACL,KAAK,kBAAkB,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAA6B,MAAM,wBAAwB,CAAC;AAC3F,OAAO,EAAE,KAAK,cAAc,EAA0B,MAAM,2BAA2B,CAAC;AACxF,OAAO,EACL,KAAK,kBAAkB,EAMxB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,KAAK,cAAc,EAA0B,MAAM,6BAA6B,CAAC;AAC1F,OAAO,EAAE,KAAK,SAAS,EAAqB,MAAM,mBAAmB,CAAC;AAEtE,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,cAAc,EACnB,KAAK,eAAe,EAIrB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,KAAK,qBAAqB,EAAiC,MAAM,gCAAgC,CAAC;AAE3G,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAG7B,MAAM,uBAAuB,CAAC;AAE/B,cAAc,uBAAuB,CAAC;AACtC,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;CAwBA,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,wBAAwB,GAC1D,cAAc,GACd,qBAAqB,GACrB,uBAAuB,GACvB,eAAe,GACf,cAAc,GACd,WAAW,GACX,cAAc,GACd,IAAI,CAAC,SAAS,EAAE,8BAA8B,CAAC,GAC/C,IAAI,CAAC,iBAAiB,EAAE,sBAAsB,GAAG,mBAAmB,GAAG,oBAAoB,CAAC,CAAC;AAE/F,eAAO,MAAM,uBAAuB,EAAE,kBAAkB,CAAC,eAAe,CAwLvE,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,kBAAkB,CAAC,qBAAqB,CAUnF,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,qBAAqB,CAExD"}
|