@aztec/sequencer-client 0.0.1-commit.3fd054f6 → 0.0.1-commit.42ee6df9b
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/dest/global_variable_builder/global_builder.d.ts +3 -3
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +7 -4
- package/dest/publisher/sequencer-publisher.d.ts +46 -24
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +72 -40
- package/dest/sequencer/checkpoint_proposal_job.d.ts +28 -9
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +149 -74
- 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/sequencer.d.ts +14 -4
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +60 -15
- package/package.json +27 -27
- package/src/global_variable_builder/global_builder.ts +15 -3
- package/src/publisher/sequencer-publisher.ts +113 -51
- package/src/sequencer/checkpoint_proposal_job.ts +181 -77
- package/src/sequencer/checkpoint_voter.ts +1 -12
- package/src/sequencer/sequencer.ts +89 -19
|
@@ -13,7 +13,7 @@ import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
|
13
13
|
import type { P2P } from '@aztec/p2p';
|
|
14
14
|
import type { SlasherClientInterface } from '@aztec/slasher';
|
|
15
15
|
import type { BlockData, L2BlockSink, L2BlockSource, ValidateCheckpointResult } from '@aztec/stdlib/block';
|
|
16
|
-
import type { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
16
|
+
import type { Checkpoint, ProposedCheckpointData } from '@aztec/stdlib/checkpoint';
|
|
17
17
|
import { getSlotStartBuildTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
18
18
|
import {
|
|
19
19
|
type ResolvedSequencerConfig,
|
|
@@ -72,6 +72,9 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
72
72
|
/** The last epoch for which we logged strategy comparison in fisherman mode. */
|
|
73
73
|
private lastEpochForStrategyComparison: EpochNumber | undefined;
|
|
74
74
|
|
|
75
|
+
/** The last checkpoint proposal job, tracked so we can await its pending L1 submission during shutdown. */
|
|
76
|
+
private lastCheckpointProposalJob: CheckpointProposalJob | undefined;
|
|
77
|
+
|
|
75
78
|
/** The maximum number of seconds that the sequencer can be into a slot to transition to a particular state. */
|
|
76
79
|
protected timetable!: SequencerTimetable;
|
|
77
80
|
|
|
@@ -149,6 +152,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
149
152
|
this.setState(SequencerState.STOPPING, undefined, { force: true });
|
|
150
153
|
await this.publisherFactory.stopAll();
|
|
151
154
|
await this.runningPromise?.stop();
|
|
155
|
+
await this.lastCheckpointProposalJob?.awaitPendingSubmission();
|
|
152
156
|
this.setState(SequencerState.STOPPED, undefined, { force: true });
|
|
153
157
|
this.log.info('Stopped sequencer');
|
|
154
158
|
}
|
|
@@ -208,6 +212,9 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
208
212
|
return;
|
|
209
213
|
}
|
|
210
214
|
|
|
215
|
+
// Track the job so we can await its pending L1 submission during shutdown
|
|
216
|
+
this.lastCheckpointProposalJob = checkpointProposalJob;
|
|
217
|
+
|
|
211
218
|
// Execute the checkpoint proposal job
|
|
212
219
|
const checkpoint = await checkpointProposalJob.execute();
|
|
213
220
|
|
|
@@ -234,7 +241,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
234
241
|
* @returns CheckpointProposalJob if successful, undefined if we are not yet synced or are not the proposer.
|
|
235
242
|
*/
|
|
236
243
|
@trackSpan('Sequencer.prepareCheckpointProposal')
|
|
237
|
-
|
|
244
|
+
protected async prepareCheckpointProposal(
|
|
238
245
|
slot: SlotNumber,
|
|
239
246
|
targetSlot: SlotNumber,
|
|
240
247
|
epoch: EpochNumber,
|
|
@@ -292,6 +299,16 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
292
299
|
// Next checkpoint follows from the last synced one
|
|
293
300
|
const checkpointNumber = CheckpointNumber(syncedTo.checkpointNumber + 1);
|
|
294
301
|
|
|
302
|
+
// Guard: don't exceed 1-deep pipeline. Without a proposed checkpoint, we can only build
|
|
303
|
+
// confirmed + 1. With a proposed checkpoint, we can build confirmed + 2.
|
|
304
|
+
const confirmedCkpt = syncedTo.checkpointedCheckpointNumber;
|
|
305
|
+
if (checkpointNumber > confirmedCkpt + 2) {
|
|
306
|
+
this.log.warn(
|
|
307
|
+
`Skipping slot ${targetSlot}: checkpoint ${checkpointNumber} exceeds max pipeline depth (confirmed=${confirmedCkpt})`,
|
|
308
|
+
);
|
|
309
|
+
return undefined;
|
|
310
|
+
}
|
|
311
|
+
|
|
295
312
|
const logCtx = {
|
|
296
313
|
nowSeconds,
|
|
297
314
|
syncedToL2Slot: syncedTo.syncedL2Slot,
|
|
@@ -337,13 +354,41 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
337
354
|
}
|
|
338
355
|
|
|
339
356
|
// Prepare invalidation request if the pending chain is invalid (returns undefined if no need)
|
|
340
|
-
|
|
357
|
+
let invalidateCheckpoint = await publisher.simulateInvalidateCheckpoint(syncedTo.pendingChainValidationStatus);
|
|
358
|
+
|
|
359
|
+
// Determine the correct archive and L1 state overrides for the canProposeAt check.
|
|
360
|
+
// The L1 contract reads archives[proposedCheckpointNumber] and compares it with the provided archive.
|
|
361
|
+
// When invalidating or pipelining, the local archive may differ from L1's, so we adjust accordingly.
|
|
362
|
+
let archiveForCheck = syncedTo.archive;
|
|
363
|
+
const l1Overrides: {
|
|
364
|
+
forcePendingCheckpointNumber?: CheckpointNumber;
|
|
365
|
+
forceArchive?: { checkpointNumber: CheckpointNumber; archive: Fr };
|
|
366
|
+
} = {};
|
|
367
|
+
|
|
368
|
+
if (this.epochCache.isProposerPipeliningEnabled() && syncedTo.hasProposedCheckpoint) {
|
|
369
|
+
// Parent checkpoint hasn't landed on L1 yet. Override both the proposed checkpoint number
|
|
370
|
+
// and the archive at that checkpoint so L1 simulation sees the correct chain tip.
|
|
371
|
+
const parentCheckpointNumber = CheckpointNumber(checkpointNumber - 1);
|
|
372
|
+
l1Overrides.forcePendingCheckpointNumber = parentCheckpointNumber;
|
|
373
|
+
l1Overrides.forceArchive = { checkpointNumber: parentCheckpointNumber, archive: syncedTo.archive };
|
|
374
|
+
this.metrics.recordPipelineDepth(1);
|
|
375
|
+
|
|
376
|
+
this.log.verbose(
|
|
377
|
+
`Building on top of proposed checkpoint (pending=${syncedTo.proposedCheckpointData?.checkpointNumber})`,
|
|
378
|
+
);
|
|
379
|
+
// Clear the invalidation - the proposed checkpoint should handle it.
|
|
380
|
+
invalidateCheckpoint = undefined;
|
|
381
|
+
} else if (invalidateCheckpoint) {
|
|
382
|
+
// After invalidation, L1 will roll back to checkpoint N-1. The archive at N-1 already
|
|
383
|
+
// exists on L1, so we just pass the matching archive (the lastArchive of the invalid checkpoint).
|
|
384
|
+
archiveForCheck = invalidateCheckpoint.lastArchive;
|
|
385
|
+
l1Overrides.forcePendingCheckpointNumber = invalidateCheckpoint.forcePendingCheckpointNumber;
|
|
386
|
+
this.metrics.recordPipelineDepth(0);
|
|
387
|
+
} else {
|
|
388
|
+
this.metrics.recordPipelineDepth(0);
|
|
389
|
+
}
|
|
341
390
|
|
|
342
|
-
|
|
343
|
-
// if all the previous checks are good, but we do it just in case.
|
|
344
|
-
const canProposeCheck = await publisher.canProposeAt(syncedTo.archive, proposer ?? EthAddress.ZERO, {
|
|
345
|
-
...invalidateCheckpoint,
|
|
346
|
-
});
|
|
391
|
+
const canProposeCheck = await publisher.canProposeAt(archiveForCheck, proposer ?? EthAddress.ZERO, l1Overrides);
|
|
347
392
|
|
|
348
393
|
if (canProposeCheck === undefined) {
|
|
349
394
|
this.log.warn(
|
|
@@ -391,7 +436,6 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
391
436
|
return this.createCheckpointProposalJob(
|
|
392
437
|
slot,
|
|
393
438
|
targetSlot,
|
|
394
|
-
epoch,
|
|
395
439
|
targetEpoch,
|
|
396
440
|
checkpointNumber,
|
|
397
441
|
syncedTo.blockNumber,
|
|
@@ -399,13 +443,13 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
399
443
|
publisher,
|
|
400
444
|
attestorAddress,
|
|
401
445
|
invalidateCheckpoint,
|
|
446
|
+
syncedTo.proposedCheckpointData,
|
|
402
447
|
);
|
|
403
448
|
}
|
|
404
449
|
|
|
405
450
|
protected createCheckpointProposalJob(
|
|
406
451
|
slot: SlotNumber,
|
|
407
452
|
targetSlot: SlotNumber,
|
|
408
|
-
epoch: EpochNumber,
|
|
409
453
|
targetEpoch: EpochNumber,
|
|
410
454
|
checkpointNumber: CheckpointNumber,
|
|
411
455
|
syncedToBlockNumber: BlockNumber,
|
|
@@ -413,11 +457,11 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
413
457
|
publisher: SequencerPublisher,
|
|
414
458
|
attestorAddress: EthAddress,
|
|
415
459
|
invalidateCheckpoint: InvalidateCheckpointRequest | undefined,
|
|
460
|
+
proposedCheckpointData?: ProposedCheckpointData,
|
|
416
461
|
): CheckpointProposalJob {
|
|
417
462
|
return new CheckpointProposalJob(
|
|
418
463
|
slot,
|
|
419
464
|
targetSlot,
|
|
420
|
-
epoch,
|
|
421
465
|
targetEpoch,
|
|
422
466
|
checkpointNumber,
|
|
423
467
|
syncedToBlockNumber,
|
|
@@ -444,6 +488,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
444
488
|
this.setState.bind(this),
|
|
445
489
|
this.tracer,
|
|
446
490
|
this.log.getBindings(),
|
|
491
|
+
proposedCheckpointData,
|
|
447
492
|
);
|
|
448
493
|
}
|
|
449
494
|
|
|
@@ -518,25 +563,37 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
518
563
|
number: syncSummary.latestBlockNumber,
|
|
519
564
|
hash: syncSummary.latestBlockHash,
|
|
520
565
|
})),
|
|
521
|
-
this.l2BlockSource
|
|
566
|
+
this.l2BlockSource
|
|
567
|
+
.getL2Tips()
|
|
568
|
+
.then(t => ({ proposed: t.proposed, checkpointed: t.checkpointed, proposedCheckpoint: t.proposedCheckpoint })),
|
|
522
569
|
this.p2pClient.getStatus().then(p2p => p2p.syncedToL2Block),
|
|
523
570
|
this.l1ToL2MessageSource.getL2Tips().then(t => t.proposed),
|
|
524
571
|
this.l2BlockSource.getPendingChainValidationStatus(),
|
|
572
|
+
this.l2BlockSource.getProposedCheckpointOnly(),
|
|
525
573
|
] as const);
|
|
526
574
|
|
|
527
|
-
const [worldState,
|
|
575
|
+
const [worldState, l2Tips, p2p, l1ToL2MessageSource, pendingChainValidationStatus, proposedCheckpointData] =
|
|
576
|
+
syncedBlocks;
|
|
528
577
|
|
|
529
578
|
// Handle zero as a special case, since the block hash won't match across services if we're changing the prefilled data for the genesis block,
|
|
530
579
|
// as the world state can compute the new genesis block hash, but other components use the hardcoded constant.
|
|
531
580
|
// TODO(palla/mbps): Fix the above. All components should be able to handle dynamic genesis block hashes.
|
|
532
581
|
const result =
|
|
533
|
-
(
|
|
534
|
-
|
|
535
|
-
p2p.
|
|
536
|
-
l1ToL2MessageSource.
|
|
582
|
+
(l2Tips.proposed.number === 0 &&
|
|
583
|
+
worldState.number === 0 &&
|
|
584
|
+
p2p.number === 0 &&
|
|
585
|
+
l1ToL2MessageSource.number === 0) ||
|
|
586
|
+
(worldState.hash === l2Tips.proposed.hash &&
|
|
587
|
+
p2p.hash === l2Tips.proposed.hash &&
|
|
588
|
+
l1ToL2MessageSource.hash === l2Tips.proposed.hash);
|
|
537
589
|
|
|
538
590
|
if (!result) {
|
|
539
|
-
this.log.debug(`Sequencer sync check failed`, {
|
|
591
|
+
this.log.debug(`Sequencer sync check failed`, {
|
|
592
|
+
worldState,
|
|
593
|
+
l2BlockSource: l2Tips.proposed,
|
|
594
|
+
p2p,
|
|
595
|
+
l1ToL2MessageSource,
|
|
596
|
+
});
|
|
540
597
|
return undefined;
|
|
541
598
|
}
|
|
542
599
|
|
|
@@ -546,8 +603,10 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
546
603
|
const archive = new Fr((await this.worldState.getCommitted().getTreeInfo(MerkleTreeId.ARCHIVE)).root);
|
|
547
604
|
return {
|
|
548
605
|
checkpointNumber: CheckpointNumber.ZERO,
|
|
606
|
+
checkpointedCheckpointNumber: CheckpointNumber.ZERO,
|
|
549
607
|
blockNumber: BlockNumber.ZERO,
|
|
550
608
|
archive,
|
|
609
|
+
hasProposedCheckpoint: false,
|
|
551
610
|
syncedL2Slot,
|
|
552
611
|
pendingChainValidationStatus,
|
|
553
612
|
};
|
|
@@ -560,11 +619,16 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
560
619
|
return undefined;
|
|
561
620
|
}
|
|
562
621
|
|
|
622
|
+
const hasProposedCheckpoint = l2Tips.proposedCheckpoint.checkpoint.number > l2Tips.checkpointed.checkpoint.number;
|
|
623
|
+
|
|
563
624
|
return {
|
|
564
625
|
blockData,
|
|
565
626
|
blockNumber: blockData.header.getBlockNumber(),
|
|
566
627
|
checkpointNumber: blockData.checkpointNumber,
|
|
628
|
+
checkpointedCheckpointNumber: l2Tips.checkpointed.checkpoint.number,
|
|
567
629
|
archive: blockData.archive.root,
|
|
630
|
+
hasProposedCheckpoint,
|
|
631
|
+
proposedCheckpointData,
|
|
568
632
|
syncedL2Slot,
|
|
569
633
|
pendingChainValidationStatus,
|
|
570
634
|
};
|
|
@@ -612,7 +676,10 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
612
676
|
return [false, proposer];
|
|
613
677
|
}
|
|
614
678
|
|
|
615
|
-
this.log.
|
|
679
|
+
this.log.info(`We are the proposer for pipeline slot ${targetSlot}`, {
|
|
680
|
+
targetSlot,
|
|
681
|
+
proposer,
|
|
682
|
+
});
|
|
616
683
|
return [true, proposer];
|
|
617
684
|
}
|
|
618
685
|
|
|
@@ -909,8 +976,11 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
909
976
|
type SequencerSyncCheckResult = {
|
|
910
977
|
blockData?: BlockData;
|
|
911
978
|
checkpointNumber: CheckpointNumber;
|
|
979
|
+
checkpointedCheckpointNumber: CheckpointNumber;
|
|
912
980
|
blockNumber: BlockNumber;
|
|
913
981
|
archive: Fr;
|
|
982
|
+
hasProposedCheckpoint: boolean;
|
|
983
|
+
proposedCheckpointData?: ProposedCheckpointData;
|
|
914
984
|
syncedL2Slot: SlotNumber;
|
|
915
985
|
pendingChainValidationStatus: ValidateCheckpointResult;
|
|
916
986
|
};
|