@aztec/sequencer-client 0.0.1-commit.18ccd8f0 → 0.0.1-commit.1bb068fb5

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.
Files changed (33) hide show
  1. package/dest/config.d.ts +1 -2
  2. package/dest/config.d.ts.map +1 -1
  3. package/dest/config.js +4 -8
  4. package/dest/publisher/sequencer-publisher.d.ts +8 -2
  5. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  6. package/dest/publisher/sequencer-publisher.js +53 -23
  7. package/dest/sequencer/checkpoint_proposal_job.d.ts +29 -6
  8. package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
  9. package/dest/sequencer/checkpoint_proposal_job.js +71 -47
  10. package/dest/sequencer/metrics.d.ts +4 -1
  11. package/dest/sequencer/metrics.d.ts.map +1 -1
  12. package/dest/sequencer/metrics.js +25 -0
  13. package/dest/sequencer/sequencer.d.ts +3 -1
  14. package/dest/sequencer/sequencer.d.ts.map +1 -1
  15. package/dest/sequencer/sequencer.js +6 -1
  16. package/dest/sequencer/timetable.d.ts +1 -4
  17. package/dest/sequencer/timetable.d.ts.map +1 -1
  18. package/dest/sequencer/timetable.js +1 -4
  19. package/dest/test/mock_checkpoint_builder.d.ts +7 -5
  20. package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
  21. package/dest/test/mock_checkpoint_builder.js +6 -6
  22. package/dest/test/utils.d.ts +3 -3
  23. package/dest/test/utils.d.ts.map +1 -1
  24. package/dest/test/utils.js +5 -4
  25. package/package.json +28 -28
  26. package/src/config.ts +9 -11
  27. package/src/publisher/sequencer-publisher.ts +60 -22
  28. package/src/sequencer/checkpoint_proposal_job.ts +95 -63
  29. package/src/sequencer/metrics.ts +24 -0
  30. package/src/sequencer/sequencer.ts +8 -1
  31. package/src/sequencer/timetable.ts +6 -5
  32. package/src/test/mock_checkpoint_builder.ts +14 -5
  33. package/src/test/utils.ts +5 -2
@@ -1,7 +1,13 @@
1
1
  import { NUM_CHECKPOINT_END_MARKER_FIELDS, getNumBlockEndBlobFields } from '@aztec/blob-lib/encoding';
2
2
  import { BLOBS_PER_CHECKPOINT, FIELDS_PER_BLOB } from '@aztec/constants';
3
3
  import type { EpochCache } from '@aztec/epoch-cache';
4
- import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
4
+ import {
5
+ BlockNumber,
6
+ CheckpointNumber,
7
+ EpochNumber,
8
+ IndexWithinCheckpoint,
9
+ SlotNumber,
10
+ } from '@aztec/foundation/branded-types';
5
11
  import { randomInt } from '@aztec/foundation/crypto/random';
6
12
  import { Fr } from '@aztec/foundation/curves/bn254';
7
13
  import { EthAddress } from '@aztec/foundation/eth-address';
@@ -10,7 +16,7 @@ import { filter } from '@aztec/foundation/iterator';
10
16
  import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
11
17
  import { sleep, sleepUntil } from '@aztec/foundation/sleep';
12
18
  import { type DateProvider, Timer } from '@aztec/foundation/timer';
13
- import { type TypedEventEmitter, unfreeze } from '@aztec/foundation/types';
19
+ import { type TypedEventEmitter, isErrorClass, unfreeze } from '@aztec/foundation/types';
14
20
  import type { P2P } from '@aztec/p2p';
15
21
  import type { SlasherClientInterface } from '@aztec/slasher';
16
22
  import {
@@ -24,10 +30,11 @@ import {
24
30
  import type { Checkpoint } from '@aztec/stdlib/checkpoint';
25
31
  import { getSlotStartBuildTimestamp } from '@aztec/stdlib/epoch-helpers';
26
32
  import { Gas } from '@aztec/stdlib/gas';
27
- import type {
28
- PublicProcessorLimits,
29
- ResolvedSequencerConfig,
30
- WorldStateSynchronizer,
33
+ import {
34
+ NoValidTxsError,
35
+ type PublicProcessorLimits,
36
+ type ResolvedSequencerConfig,
37
+ type WorldStateSynchronizer,
31
38
  } from '@aztec/stdlib/interfaces/server';
32
39
  import { type L1ToL2MessageSource, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
33
40
  import type { BlockProposalOptions, CheckpointProposal, CheckpointProposalOptions } from '@aztec/stdlib/p2p';
@@ -184,6 +191,9 @@ export class CheckpointProposalJob implements Traceable {
184
191
  );
185
192
  const previousCheckpointOutHashes = previousCheckpoints.map(c => c.getCheckpointOutHash());
186
193
 
194
+ // Get the fee asset price modifier from the oracle
195
+ const feeAssetPriceModifier = await this.publisher.getFeeAssetPriceModifier();
196
+
187
197
  // Create a long-lived forked world state for the checkpoint builder
188
198
  using fork = await this.worldState.fork(this.syncedToBlockNumber, { closeDelayMs: 12_000 });
189
199
 
@@ -191,6 +201,7 @@ export class CheckpointProposalJob implements Traceable {
191
201
  const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(
192
202
  this.checkpointNumber,
193
203
  checkpointGlobalVariables,
204
+ feeAssetPriceModifier,
194
205
  l1ToL2Messages,
195
206
  previousCheckpointOutHashes,
196
207
  fork,
@@ -225,19 +236,7 @@ export class CheckpointProposalJob implements Traceable {
225
236
  // These errors are expected in HA mode, so we yield and let another HA node handle the slot
226
237
  // The only distinction between the 2 errors is SlashingProtectionError throws when the payload is different,
227
238
  // which is normal for block building (may have picked different txs)
228
- if (err instanceof DutyAlreadySignedError) {
229
- this.log.info(`Checkpoint proposal for slot ${this.slot} already signed by another HA node, yielding`, {
230
- slot: this.slot,
231
- signedByNode: err.signedByNode,
232
- });
233
- return undefined;
234
- }
235
- if (err instanceof SlashingProtectionError) {
236
- this.log.info(`Checkpoint proposal for slot ${this.slot} blocked by slashing protection, yielding`, {
237
- slot: this.slot,
238
- existingMessageHash: err.existingMessageHash,
239
- attemptedMessageHash: err.attemptedMessageHash,
240
- });
239
+ if (this.handleHASigningError(err, 'Block proposal')) {
241
240
  return undefined;
242
241
  }
243
242
  throw err;
@@ -280,6 +279,7 @@ export class CheckpointProposalJob implements Traceable {
280
279
  const proposal = await this.validatorClient.createCheckpointProposal(
281
280
  checkpoint.header,
282
281
  checkpoint.archive.root,
282
+ feeAssetPriceModifier,
283
283
  lastBlock,
284
284
  this.proposer,
285
285
  checkpointProposalOptions,
@@ -306,20 +306,8 @@ export class CheckpointProposalJob implements Traceable {
306
306
  );
307
307
  } catch (err) {
308
308
  // We shouldn't really get here since we yield to another HA node
309
- // as soon as we see these errors when creating block proposals.
310
- if (err instanceof DutyAlreadySignedError) {
311
- this.log.info(`Attestations signature for slot ${this.slot} already signed by another HA node, yielding`, {
312
- slot: this.slot,
313
- signedByNode: err.signedByNode,
314
- });
315
- return undefined;
316
- }
317
- if (err instanceof SlashingProtectionError) {
318
- this.log.info(`Attestations signature for slot ${this.slot} blocked by slashing protection, yielding`, {
319
- slot: this.slot,
320
- existingMessageHash: err.existingMessageHash,
321
- attemptedMessageHash: err.attemptedMessageHash,
322
- });
309
+ // as soon as we see these errors when creating block or checkpoint proposals.
310
+ if (this.handleHASigningError(err, 'Attestations signature')) {
323
311
  return undefined;
324
312
  }
325
313
  throw err;
@@ -372,7 +360,7 @@ export class CheckpointProposalJob implements Traceable {
372
360
 
373
361
  while (true) {
374
362
  const blocksBuilt = blocksInCheckpoint.length;
375
- const indexWithinCheckpoint = blocksBuilt;
363
+ const indexWithinCheckpoint = IndexWithinCheckpoint(blocksBuilt);
376
364
  const blockNumber = BlockNumber(initialBlockNumber + blocksBuilt);
377
365
 
378
366
  const secondsIntoSlot = this.getSecondsIntoSlot();
@@ -402,6 +390,7 @@ export class CheckpointProposalJob implements Traceable {
402
390
  remainingBlobFields,
403
391
  });
404
392
 
393
+ // TODO(palla/mbps): Review these conditions. We may want to keep trying in some scenarios.
405
394
  if (!buildResult && timingInfo.isLastBlock) {
406
395
  // If no block was produced due to not enough txs and this was the last subslot, exit
407
396
  break;
@@ -488,13 +477,13 @@ export class CheckpointProposalJob implements Traceable {
488
477
 
489
478
  /** Builds a single block. Called from the main block building loop. */
490
479
  @trackSpan('CheckpointProposalJob.buildSingleBlock')
491
- private async buildSingleBlock(
480
+ protected async buildSingleBlock(
492
481
  checkpointBuilder: CheckpointBuilder,
493
482
  opts: {
494
483
  forceCreate?: boolean;
495
484
  blockTimestamp: bigint;
496
485
  blockNumber: BlockNumber;
497
- indexWithinCheckpoint: number;
486
+ indexWithinCheckpoint: IndexWithinCheckpoint;
498
487
  buildDeadline: Date | undefined;
499
488
  txHashesAlreadyIncluded: Set<string>;
500
489
  remainingBlobFields: number;
@@ -532,7 +521,7 @@ export class CheckpointProposalJob implements Traceable {
532
521
  // Create iterator to pending txs. We filter out txs already included in previous blocks in the checkpoint
533
522
  // just in case p2p failed to sync the provisional block and didn't get to remove those txs from the mempool yet.
534
523
  const pendingTxs = filter(
535
- this.p2pClient.iteratePendingTxs(),
524
+ this.p2pClient.iterateEligiblePendingTxs(),
536
525
  tx => !txHashesAlreadyIncluded.has(tx.txHash.toString()),
537
526
  );
538
527
 
@@ -555,45 +544,38 @@ export class CheckpointProposalJob implements Traceable {
555
544
  };
556
545
 
557
546
  // Actually build the block by executing txs
558
- const workTimer = new Timer();
559
- const {
560
- publicGas,
561
- block,
562
- publicProcessorDuration,
563
- numTxs,
564
- blockBuildingTimer,
565
- usedTxs,
566
- failedTxs,
567
- usedTxBlobFields,
568
- } = await checkpointBuilder.buildBlock(pendingTxs, blockNumber, blockTimestamp, blockBuilderOptions);
569
- const blockBuildDuration = workTimer.ms();
547
+ const buildResult = await this.buildSingleBlockWithCheckpointBuilder(
548
+ checkpointBuilder,
549
+ pendingTxs,
550
+ blockNumber,
551
+ blockTimestamp,
552
+ blockBuilderOptions,
553
+ );
570
554
 
571
555
  // If any txs failed during execution, drop them from the mempool so we don't pick them up again
572
- await this.dropFailedTxsFromP2P(failedTxs);
556
+ await this.dropFailedTxsFromP2P(buildResult.failedTxs);
573
557
 
574
558
  // Check if we have created a block with enough txs. If there were invalid txs in the pool, or if execution took
575
559
  // too long, then we may not get to minTxsPerBlock after executing public functions.
576
560
  const minValidTxs = this.config.minValidTxsPerBlock ?? minTxs;
577
- if (!forceCreate && numTxs < minValidTxs) {
561
+ const numTxs = buildResult.status === 'no-valid-txs' ? 0 : buildResult.numTxs;
562
+ if (buildResult.status === 'no-valid-txs' || (!forceCreate && numTxs < minValidTxs)) {
578
563
  this.log.warn(
579
- `Block ${blockNumber} at index ${indexWithinCheckpoint} on slot ${this.slot} has too few valid txs to be proposed (got ${numTxs} but required ${minValidTxs})`,
580
- { slot: this.slot, blockNumber, numTxs, indexWithinCheckpoint },
564
+ `Block ${blockNumber} at index ${indexWithinCheckpoint} on slot ${this.slot} has too few valid txs to be proposed`,
565
+ { slot: this.slot, blockNumber, numTxs, indexWithinCheckpoint, minValidTxs, buildResult: buildResult.status },
581
566
  );
582
- this.eventEmitter.emit('block-tx-count-check-failed', {
583
- minTxs: minValidTxs,
584
- availableTxs: numTxs,
585
- slot: this.slot,
586
- });
567
+ this.eventEmitter.emit('block-build-failed', { reason: `Insufficient valid txs`, slot: this.slot });
587
568
  this.metrics.recordBlockProposalFailed('insufficient_valid_txs');
588
569
  return undefined;
589
570
  }
590
571
 
591
572
  // Block creation succeeded, emit stats and metrics
573
+ const { publicGas, block, publicProcessorDuration, usedTxs, usedTxBlobFields, blockBuildDuration } = buildResult;
574
+
592
575
  const blockStats = {
593
576
  eventName: 'l2-block-built',
594
577
  duration: blockBuildDuration,
595
578
  publicProcessDuration: publicProcessorDuration,
596
- rollupCircuitsDuration: blockBuildingTimer.ms(),
597
579
  ...block.getStats(),
598
580
  } satisfies L2BlockBuiltStats;
599
581
 
@@ -619,17 +601,40 @@ export class CheckpointProposalJob implements Traceable {
619
601
  }
620
602
  }
621
603
 
604
+ /** Uses the checkpoint builder to build a block, catching specific txs */
605
+ private async buildSingleBlockWithCheckpointBuilder(
606
+ checkpointBuilder: CheckpointBuilder,
607
+ pendingTxs: AsyncIterable<Tx>,
608
+ blockNumber: BlockNumber,
609
+ blockTimestamp: bigint,
610
+ blockBuilderOptions: PublicProcessorLimits,
611
+ ) {
612
+ try {
613
+ const workTimer = new Timer();
614
+ const result = await checkpointBuilder.buildBlock(pendingTxs, blockNumber, blockTimestamp, blockBuilderOptions);
615
+ const blockBuildDuration = workTimer.ms();
616
+ return { ...result, blockBuildDuration, status: 'success' as const };
617
+ } catch (err: unknown) {
618
+ if (isErrorClass(err, NoValidTxsError)) {
619
+ return { failedTxs: err.failedTxs, status: 'no-valid-txs' as const };
620
+ }
621
+ throw err;
622
+ }
623
+ }
624
+
622
625
  /** Waits until minTxs are available on the pool for building a block. */
623
626
  @trackSpan('CheckpointProposalJob.waitForMinTxs')
624
627
  private async waitForMinTxs(opts: {
625
628
  forceCreate?: boolean;
626
629
  blockNumber: BlockNumber;
627
- indexWithinCheckpoint: number;
630
+ indexWithinCheckpoint: IndexWithinCheckpoint;
628
631
  buildDeadline: Date | undefined;
629
632
  }): Promise<{ canStartBuilding: boolean; availableTxs: number }> {
630
- const minTxs = this.config.minTxsPerBlock;
631
633
  const { indexWithinCheckpoint, blockNumber, buildDeadline, forceCreate } = opts;
632
634
 
635
+ // We only allow a block with 0 txs in the first block of the checkpoint
636
+ const minTxs = indexWithinCheckpoint > 0 && this.config.minTxsPerBlock === 0 ? 1 : this.config.minTxsPerBlock;
637
+
633
638
  // Deadline is undefined if we are not enforcing the timetable, meaning we'll exit immediately when out of time
634
639
  const startBuildingDeadline = buildDeadline
635
640
  ? new Date(buildDeadline.getTime() - this.timetable.minExecutionTime * 1000)
@@ -650,7 +655,7 @@ export class CheckpointProposalJob implements Traceable {
650
655
  `Waiting for enough txs to build block ${blockNumber} at index ${indexWithinCheckpoint} in slot ${this.slot} (have ${availableTxs} but need ${minTxs})`,
651
656
  { blockNumber, slot: this.slot, indexWithinCheckpoint },
652
657
  );
653
- await sleep(TXS_POLLING_MS);
658
+ await this.waitForTxsPollingInterval();
654
659
  availableTxs = await this.p2pClient.getPendingTxCount();
655
660
  }
656
661
 
@@ -779,7 +784,7 @@ export class CheckpointProposalJob implements Traceable {
779
784
  const failedTxData = failedTxs.map(fail => fail.tx);
780
785
  const failedTxHashes = failedTxData.map(tx => tx.getTxHash());
781
786
  this.log.verbose(`Dropping failed txs ${failedTxHashes.join(', ')}`);
782
- await this.p2pClient.deleteTxs(failedTxHashes);
787
+ await this.p2pClient.handleFailedExecution(failedTxHashes);
783
788
  }
784
789
 
785
790
  /**
@@ -827,6 +832,28 @@ export class CheckpointProposalJob implements Traceable {
827
832
  this.publisher.clearPendingRequests();
828
833
  }
829
834
 
835
+ /**
836
+ * Helper to handle HA double-signing errors. Returns true if the error was handled (caller should yield).
837
+ */
838
+ private handleHASigningError(err: any, errorContext: string): boolean {
839
+ if (err instanceof DutyAlreadySignedError) {
840
+ this.log.info(`${errorContext} for slot ${this.slot} already signed by another HA node, yielding`, {
841
+ slot: this.slot,
842
+ signedByNode: err.signedByNode,
843
+ });
844
+ return true;
845
+ }
846
+ if (err instanceof SlashingProtectionError) {
847
+ this.log.info(`${errorContext} for slot ${this.slot} blocked by slashing protection, yielding`, {
848
+ slot: this.slot,
849
+ existingMessageHash: err.existingMessageHash,
850
+ attemptedMessageHash: err.attemptedMessageHash,
851
+ });
852
+ return true;
853
+ }
854
+ return false;
855
+ }
856
+
830
857
  /** Waits until a specific time within the current slot */
831
858
  @trackSpan('CheckpointProposalJob.waitUntilTimeInSlot')
832
859
  protected async waitUntilTimeInSlot(targetSecondsIntoSlot: number): Promise<void> {
@@ -835,6 +862,11 @@ export class CheckpointProposalJob implements Traceable {
835
862
  await sleepUntil(new Date(targetTimestamp * 1000), this.dateProvider.nowAsDate());
836
863
  }
837
864
 
865
+ /** Waits the polling interval for transactions. Extracted for test overriding. */
866
+ protected async waitForTxsPollingInterval(): Promise<void> {
867
+ await sleep(TXS_POLLING_MS);
868
+ }
869
+
838
870
  private getSlotStartBuildTimestamp(): number {
839
871
  return getSlotStartBuildTimestamp(this.slot, this.l1Constants);
840
872
  }
@@ -51,6 +51,9 @@ export class SequencerMetrics {
51
51
  private fishermanTimeBeforeBlock: Histogram;
52
52
  private fishermanPendingBlobTxCount: Histogram;
53
53
  private fishermanIncludedBlobTxCount: Histogram;
54
+ private fishermanPendingBlobCount: Histogram;
55
+ private fishermanIncludedBlobCount: Histogram;
56
+ private fishermanBlockBlobsFull: UpDownCounter;
54
57
  private fishermanCalculatedPriorityFee: Histogram;
55
58
  private fishermanPriorityFeeDelta: Histogram;
56
59
  private fishermanEstimatedCost: Histogram;
@@ -161,6 +164,18 @@ export class SequencerMetrics {
161
164
  this.fishermanMinedBlobTxTotalCost = this.meter.createHistogram(
162
165
  Metrics.FISHERMAN_FEE_ANALYSIS_MINED_BLOB_TX_TOTAL_COST,
163
166
  );
167
+
168
+ this.fishermanPendingBlobCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_PENDING_BLOB_COUNT);
169
+
170
+ this.fishermanIncludedBlobCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_INCLUDED_BLOB_COUNT);
171
+
172
+ this.fishermanBlockBlobsFull = createUpDownCounterWithDefault(
173
+ this.meter,
174
+ Metrics.FISHERMAN_FEE_ANALYSIS_BLOCK_BLOBS_FULL,
175
+ {
176
+ [Attributes.OK]: [true, false],
177
+ },
178
+ );
164
179
  }
165
180
 
166
181
  public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
@@ -281,10 +296,12 @@ export class SequencerMetrics {
281
296
 
282
297
  // Record pending block snapshot data (once per strategy for comparison)
283
298
  this.fishermanPendingBlobTxCount.record(analysis.pendingSnapshot.pendingBlobTxCount, strategyAttributes);
299
+ this.fishermanPendingBlobCount.record(analysis.pendingSnapshot.pendingBlobCount, strategyAttributes);
284
300
 
285
301
  // Record mined block data if available
286
302
  if (analysis.minedBlock) {
287
303
  this.fishermanIncludedBlobTxCount.record(analysis.minedBlock.includedBlobTxCount, strategyAttributes);
304
+ this.fishermanIncludedBlobCount.record(analysis.minedBlock.includedBlobCount, strategyAttributes);
288
305
 
289
306
  // Record actual fees from blob transactions in the mined block
290
307
  for (const blobTx of analysis.minedBlock.includedBlobTxs) {
@@ -318,6 +335,13 @@ export class SequencerMetrics {
318
335
  if (analysis.analysis) {
319
336
  this.fishermanTimeBeforeBlock.record(Math.ceil(analysis.analysis.timeBeforeBlockMs), strategyAttributes);
320
337
 
338
+ // Record whether the block reached 100% blob capacity
339
+ if (analysis.analysis.blockBlobsFull) {
340
+ this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: true });
341
+ } else {
342
+ this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: false });
343
+ }
344
+
321
345
  // Record strategy-specific inclusion result
322
346
  if (strategyResult.wouldBeIncluded !== undefined) {
323
347
  if (strategyResult.wouldBeIncluded) {
@@ -60,6 +60,9 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
60
60
  /** The last slot for which we attempted to perform our voting duties with degraded block production */
61
61
  private lastSlotForFallbackVote: SlotNumber | undefined;
62
62
 
63
+ /** The last slot for which we logged "no committee" warning, to avoid spam */
64
+ private lastSlotForNoCommitteeWarning: SlotNumber | undefined;
65
+
63
66
  /** The last slot for which we triggered a checkpoint proposal job, to prevent duplicate attempts. */
64
67
  private lastSlotForCheckpointProposalJob: SlotNumber | undefined;
65
68
 
@@ -373,6 +376,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
373
376
  }
374
377
 
375
378
  this.lastSlotForCheckpointProposalJob = slot;
379
+ await this.p2pClient.prepareForSlot(slot);
376
380
  this.log.info(`Preparing checkpoint proposal ${checkpointNumber} at slot ${slot}`, { ...logCtx, proposer });
377
381
 
378
382
  // Create and return the checkpoint proposal job
@@ -557,7 +561,10 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
557
561
  proposer = await this.epochCache.getProposerAttesterAddressInSlot(slot);
558
562
  } catch (e) {
559
563
  if (e instanceof NoCommitteeError) {
560
- this.log.warn(`Cannot propose at next L2 slot ${slot} since the committee does not exist on L1`);
564
+ if (this.lastSlotForNoCommitteeWarning !== slot) {
565
+ this.lastSlotForNoCommitteeWarning = slot;
566
+ this.log.warn(`Cannot propose at next L2 slot ${slot} since the committee does not exist on L1`);
567
+ }
561
568
  return [false, undefined];
562
569
  }
563
570
  this.log.error(`Error getting proposer for slot ${slot}`, e);
@@ -1,14 +1,15 @@
1
1
  import { createLogger } from '@aztec/aztec.js/log';
2
+ import {
3
+ CHECKPOINT_ASSEMBLE_TIME,
4
+ CHECKPOINT_INITIALIZATION_TIME,
5
+ DEFAULT_P2P_PROPAGATION_TIME,
6
+ MIN_EXECUTION_TIME,
7
+ } from '@aztec/stdlib/timetable';
2
8
 
3
- import { DEFAULT_ATTESTATION_PROPAGATION_TIME as DEFAULT_P2P_PROPAGATION_TIME } from '../config.js';
4
9
  import { SequencerTooSlowError } from './errors.js';
5
10
  import type { SequencerMetrics } from './metrics.js';
6
11
  import { SequencerState } from './utils.js';
7
12
 
8
- export const MIN_EXECUTION_TIME = 2;
9
- export const CHECKPOINT_INITIALIZATION_TIME = 1;
10
- export const CHECKPOINT_ASSEMBLE_TIME = 1;
11
-
12
13
  export class SequencerTimetable {
13
14
  /**
14
15
  * How late into the slot can we be to start working. Computed as the total time needed for assembling and publishing a block,
@@ -1,6 +1,5 @@
1
1
  import { type BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
2
2
  import { Fr } from '@aztec/foundation/curves/bn254';
3
- import { Timer } from '@aztec/foundation/timer';
4
3
  import { L2Block } from '@aztec/stdlib/block';
5
4
  import { Checkpoint } from '@aztec/stdlib/checkpoint';
6
5
  import { Gas } from '@aztec/stdlib/gas';
@@ -14,7 +13,7 @@ import type {
14
13
  import { CheckpointHeader } from '@aztec/stdlib/rollup';
15
14
  import { makeAppendOnlyTreeSnapshot } from '@aztec/stdlib/testing';
16
15
  import type { CheckpointGlobalVariables, Tx } from '@aztec/stdlib/tx';
17
- import type { BuildBlockInCheckpointResultWithTimer } from '@aztec/validator-client';
16
+ import type { BuildBlockInCheckpointResult } from '@aztec/validator-client';
18
17
 
19
18
  /**
20
19
  * A fake CheckpointBuilder for testing that implements the same interface as the real one.
@@ -76,7 +75,7 @@ export class MockCheckpointBuilder implements ICheckpointBlockBuilder {
76
75
  blockNumber: BlockNumber,
77
76
  timestamp: bigint,
78
77
  opts: PublicProcessorLimits,
79
- ): Promise<BuildBlockInCheckpointResultWithTimer> {
78
+ ): Promise<BuildBlockInCheckpointResult> {
80
79
  this.buildBlockCalls.push({ blockNumber, timestamp, opts });
81
80
 
82
81
  if (this.errorOnBuild) {
@@ -117,7 +116,6 @@ export class MockCheckpointBuilder implements ICheckpointBlockBuilder {
117
116
  publicGas: Gas.empty(),
118
117
  publicProcessorDuration: 0,
119
118
  numTxs: block?.body?.txEffects?.length ?? usedTxs.length,
120
- blockBuildingTimer: new Timer(),
121
119
  usedTxs,
122
120
  failedTxs: [],
123
121
  usedTxBlobFields: block?.body?.txEffects?.reduce((sum, tx) => sum + tx.getNumBlobFields(), 0) ?? 0,
@@ -207,6 +205,7 @@ export class MockCheckpointsBuilder implements ICheckpointsBuilder {
207
205
  constants: CheckpointGlobalVariables;
208
206
  l1ToL2Messages: Fr[];
209
207
  previousCheckpointOutHashes: Fr[];
208
+ feeAssetPriceModifier: bigint;
210
209
  }> = [];
211
210
  public openCheckpointCalls: Array<{
212
211
  checkpointNumber: CheckpointNumber;
@@ -214,6 +213,7 @@ export class MockCheckpointsBuilder implements ICheckpointsBuilder {
214
213
  l1ToL2Messages: Fr[];
215
214
  previousCheckpointOutHashes: Fr[];
216
215
  existingBlocks: L2Block[];
216
+ feeAssetPriceModifier: bigint;
217
217
  }> = [];
218
218
  public updateConfigCalls: Array<Partial<FullNodeBlockBuilderConfig>> = [];
219
219
 
@@ -259,11 +259,18 @@ export class MockCheckpointsBuilder implements ICheckpointsBuilder {
259
259
  startCheckpoint(
260
260
  checkpointNumber: CheckpointNumber,
261
261
  constants: CheckpointGlobalVariables,
262
+ feeAssetPriceModifier: bigint,
262
263
  l1ToL2Messages: Fr[],
263
264
  previousCheckpointOutHashes: Fr[],
264
265
  _fork: MerkleTreeWriteOperations,
265
266
  ): Promise<ICheckpointBlockBuilder> {
266
- this.startCheckpointCalls.push({ checkpointNumber, constants, l1ToL2Messages, previousCheckpointOutHashes });
267
+ this.startCheckpointCalls.push({
268
+ checkpointNumber,
269
+ constants,
270
+ l1ToL2Messages,
271
+ previousCheckpointOutHashes,
272
+ feeAssetPriceModifier,
273
+ });
267
274
 
268
275
  if (!this.checkpointBuilder) {
269
276
  // Auto-create a builder if none was set
@@ -276,6 +283,7 @@ export class MockCheckpointsBuilder implements ICheckpointsBuilder {
276
283
  openCheckpoint(
277
284
  checkpointNumber: CheckpointNumber,
278
285
  constants: CheckpointGlobalVariables,
286
+ feeAssetPriceModifier: bigint,
279
287
  l1ToL2Messages: Fr[],
280
288
  previousCheckpointOutHashes: Fr[],
281
289
  _fork: MerkleTreeWriteOperations,
@@ -287,6 +295,7 @@ export class MockCheckpointsBuilder implements ICheckpointsBuilder {
287
295
  l1ToL2Messages,
288
296
  previousCheckpointOutHashes,
289
297
  existingBlocks,
298
+ feeAssetPriceModifier,
290
299
  });
291
300
 
292
301
  if (!this.checkpointBuilder) {
package/src/test/utils.ts CHANGED
@@ -56,6 +56,7 @@ export async function makeBlock(txs: Tx[], globalVariables: GlobalVariables): Pr
56
56
  export function mockPendingTxs(p2p: MockProxy<P2P>, txs: Tx[]): void {
57
57
  p2p.getPendingTxCount.mockResolvedValue(txs.length);
58
58
  p2p.iteratePendingTxs.mockImplementation(() => mockTxIterator(Promise.resolve(txs)));
59
+ p2p.iterateEligiblePendingTxs.mockImplementation(() => mockTxIterator(Promise.resolve(txs)));
59
60
  }
60
61
 
61
62
  /**
@@ -118,10 +119,11 @@ export function createCheckpointProposal(
118
119
  block: L2Block,
119
120
  checkpointSignature: Signature,
120
121
  blockSignature?: Signature,
122
+ feeAssetPriceModifier: bigint = 0n,
121
123
  ): CheckpointProposal {
122
124
  const txHashes = block.body.txEffects.map(tx => tx.txHash);
123
125
  const checkpointHeader = createCheckpointHeaderFromBlock(block);
124
- return new CheckpointProposal(checkpointHeader, block.archive.root, checkpointSignature, {
126
+ return new CheckpointProposal(checkpointHeader, block.archive.root, feeAssetPriceModifier, checkpointSignature, {
125
127
  blockHeader: block.header,
126
128
  indexWithinCheckpoint: block.indexWithinCheckpoint,
127
129
  txHashes,
@@ -138,9 +140,10 @@ export function createCheckpointAttestation(
138
140
  block: L2Block,
139
141
  signature: Signature,
140
142
  sender: EthAddress,
143
+ feeAssetPriceModifier: bigint = 0n,
141
144
  ): CheckpointAttestation {
142
145
  const checkpointHeader = createCheckpointHeaderFromBlock(block);
143
- const payload = new ConsensusPayload(checkpointHeader, block.archive.root);
146
+ const payload = new ConsensusPayload(checkpointHeader, block.archive.root, feeAssetPriceModifier);
144
147
  const attestation = new CheckpointAttestation(payload, signature, signature);
145
148
  // Set sender directly for testing (bypasses signature recovery)
146
149
  (attestation as any).sender = sender;