@aztec/sequencer-client 0.65.2 → 0.67.0

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 (48) hide show
  1. package/dest/client/sequencer-client.d.ts.map +1 -1
  2. package/dest/client/sequencer-client.js +3 -2
  3. package/dest/config.js +3 -3
  4. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  5. package/dest/global_variable_builder/global_builder.js +3 -4
  6. package/dest/publisher/config.d.ts +4 -4
  7. package/dest/publisher/config.d.ts.map +1 -1
  8. package/dest/publisher/config.js +3 -2
  9. package/dest/publisher/l1-publisher-metrics.d.ts.map +1 -1
  10. package/dest/publisher/l1-publisher-metrics.js +2 -8
  11. package/dest/publisher/l1-publisher.d.ts +7 -4
  12. package/dest/publisher/l1-publisher.d.ts.map +1 -1
  13. package/dest/publisher/l1-publisher.js +67 -50
  14. package/dest/publisher/utils.d.ts.map +1 -1
  15. package/dest/publisher/utils.js +2 -1
  16. package/dest/sequencer/metrics.d.ts.map +1 -1
  17. package/dest/sequencer/metrics.js +2 -8
  18. package/dest/sequencer/sequencer.d.ts +13 -4
  19. package/dest/sequencer/sequencer.d.ts.map +1 -1
  20. package/dest/sequencer/sequencer.js +124 -73
  21. package/dest/sequencer/utils.js +2 -2
  22. package/dest/tx_validator/gas_validator.js +3 -3
  23. package/dest/tx_validator/phases_validator.js +3 -3
  24. package/package.json +23 -19
  25. package/src/client/sequencer-client.ts +2 -2
  26. package/src/config.ts +2 -2
  27. package/src/global_variable_builder/global_builder.ts +3 -3
  28. package/src/publisher/config.ts +7 -4
  29. package/src/publisher/l1-publisher-metrics.ts +1 -7
  30. package/src/publisher/l1-publisher.ts +98 -64
  31. package/src/publisher/utils.ts +1 -0
  32. package/src/sequencer/metrics.ts +0 -7
  33. package/src/sequencer/sequencer.ts +152 -123
  34. package/src/sequencer/utils.ts +1 -1
  35. package/src/tx_validator/gas_validator.ts +2 -2
  36. package/src/tx_validator/phases_validator.ts +2 -2
  37. package/dest/block_builder/index.d.ts +0 -7
  38. package/dest/block_builder/index.d.ts.map +0 -1
  39. package/dest/block_builder/index.js +0 -3
  40. package/dest/block_builder/light.d.ts +0 -26
  41. package/dest/block_builder/light.d.ts.map +0 -1
  42. package/dest/block_builder/light.js +0 -58
  43. package/dest/block_builder/orchestrator.d.ts +0 -23
  44. package/dest/block_builder/orchestrator.d.ts.map +0 -1
  45. package/dest/block_builder/orchestrator.js +0 -33
  46. package/src/block_builder/index.ts +0 -7
  47. package/src/block_builder/light.ts +0 -92
  48. package/src/block_builder/orchestrator.ts +0 -43
@@ -7,7 +7,6 @@ import {
7
7
  type Tracer,
8
8
  type UpDownCounter,
9
9
  ValueType,
10
- millisecondBuckets,
11
10
  } from '@aztec/telemetry-client';
12
11
 
13
12
  import { type SequencerState, type SequencerStateCallback, sequencerStateToNumber } from './utils.js';
@@ -32,18 +31,12 @@ export class SequencerMetrics {
32
31
  unit: 'ms',
33
32
  description: 'Duration to build a block',
34
33
  valueType: ValueType.INT,
35
- advice: {
36
- explicitBucketBoundaries: millisecondBuckets(2),
37
- },
38
34
  });
39
35
  this.stateTransitionBufferDuration = meter.createHistogram(Metrics.SEQUENCER_STATE_TRANSITION_BUFFER_DURATION, {
40
36
  unit: 'ms',
41
37
  description:
42
38
  'The time difference between when the sequencer needed to transition to a new state and when it actually did.',
43
39
  valueType: ValueType.INT,
44
- advice: {
45
- explicitBucketBoundaries: millisecondBuckets(2),
46
- },
47
40
  });
48
41
 
49
42
  const currentState = meter.createObservableGauge(Metrics.SEQUENCER_CURRENT_STATE, {
@@ -4,6 +4,7 @@ import {
4
4
  type L2Block,
5
5
  type L2BlockSource,
6
6
  type ProcessedTx,
7
+ SequencerConfigSchema,
7
8
  Tx,
8
9
  type TxHash,
9
10
  type TxValidator,
@@ -13,26 +14,26 @@ import type { AllowedElement, Signature, WorldStateSynchronizerStatus } from '@a
13
14
  import { type L2BlockBuiltStats } from '@aztec/circuit-types/stats';
14
15
  import {
15
16
  AppendOnlyTreeSnapshot,
17
+ BlockHeader,
16
18
  ContentCommitment,
17
19
  GENESIS_ARCHIVE_ROOT,
18
20
  type GlobalVariables,
19
- Header,
20
21
  StateReference,
21
22
  } from '@aztec/circuits.js';
22
23
  import { AztecAddress } from '@aztec/foundation/aztec-address';
24
+ import { omit } from '@aztec/foundation/collection';
23
25
  import { EthAddress } from '@aztec/foundation/eth-address';
24
26
  import { Fr } from '@aztec/foundation/fields';
25
- import { createDebugLogger } from '@aztec/foundation/log';
27
+ import { createLogger } from '@aztec/foundation/log';
26
28
  import { RunningPromise } from '@aztec/foundation/running-promise';
29
+ import { pickFromSchema } from '@aztec/foundation/schemas';
27
30
  import { Timer, elapsed } from '@aztec/foundation/timer';
28
31
  import { type P2P } from '@aztec/p2p';
32
+ import { type BlockBuilderFactory } from '@aztec/prover-client/block-builder';
29
33
  import { type PublicProcessorFactory } from '@aztec/simulator';
30
34
  import { Attributes, type TelemetryClient, type Tracer, trackSpan } from '@aztec/telemetry-client';
31
35
  import { type ValidatorClient } from '@aztec/validator-client';
32
36
 
33
- import { inspect } from 'util';
34
-
35
- import { type BlockBuilderFactory } from '../block_builder/index.js';
36
37
  import { type GlobalVariableBuilder } from '../global_variable_builder/global_builder.js';
37
38
  import { type L1Publisher } from '../publisher/l1-publisher.js';
38
39
  import { prettyLogViemErrorMsg } from '../publisher/utils.js';
@@ -108,11 +109,10 @@ export class Sequencer {
108
109
  private aztecSlotDuration: number,
109
110
  telemetry: TelemetryClient,
110
111
  private config: SequencerConfig = {},
111
- private log = createDebugLogger('aztec:sequencer'),
112
+ private log = createLogger('sequencer'),
112
113
  ) {
113
114
  this.updateConfig(config);
114
115
  this.metrics = new SequencerMetrics(telemetry, () => this.state, 'Sequencer');
115
- this.log.verbose(`Initialized sequencer with ${this.minTxsPerBLock}-${this.maxTxsPerBlock} txs per block.`);
116
116
 
117
117
  // Register the block builder with the validator client for re-execution
118
118
  this.validatorClient?.registerBlockBuilder(this.buildBlock.bind(this));
@@ -127,6 +127,11 @@ export class Sequencer {
127
127
  * @param config - New parameters.
128
128
  */
129
129
  public updateConfig(config: SequencerConfig) {
130
+ this.log.info(
131
+ `Sequencer config set`,
132
+ omit(pickFromSchema(this.config, SequencerConfigSchema), 'allowedInSetup', 'allowedInTeardown'),
133
+ );
134
+
130
135
  if (config.transactionPollingIntervalMS !== undefined) {
131
136
  this.pollingIntervalMs = config.transactionPollingIntervalMS;
132
137
  }
@@ -188,9 +193,9 @@ export class Sequencer {
188
193
  */
189
194
  public start() {
190
195
  this.runningPromise = new RunningPromise(this.work.bind(this), this.pollingIntervalMs);
196
+ this.setState(SequencerState.IDLE, 0n, true /** force */);
191
197
  this.runningPromise.start();
192
- this.setState(SequencerState.IDLE, 0, true /** force */);
193
- this.log.info('Sequencer started');
198
+ this.log.info(`Sequencer started with address ${this.publisher.getSenderAddress().toString()}`);
194
199
  return Promise.resolve();
195
200
  }
196
201
 
@@ -199,9 +204,10 @@ export class Sequencer {
199
204
  */
200
205
  public async stop(): Promise<void> {
201
206
  this.log.debug(`Stopping sequencer`);
207
+ await this.validatorClient?.stop();
202
208
  await this.runningPromise?.stop();
203
209
  this.publisher.interrupt();
204
- this.setState(SequencerState.STOPPED, 0, true /** force */);
210
+ this.setState(SequencerState.STOPPED, 0n, true /** force */);
205
211
  this.log.info('Stopped sequencer');
206
212
  }
207
213
 
@@ -212,7 +218,7 @@ export class Sequencer {
212
218
  this.log.info('Restarting sequencer');
213
219
  this.publisher.restart();
214
220
  this.runningPromise!.start();
215
- this.setState(SequencerState.IDLE, 0, true /** force */);
221
+ this.setState(SequencerState.IDLE, 0n, true /** force */);
216
222
  }
217
223
 
218
224
  /**
@@ -232,18 +238,15 @@ export class Sequencer {
232
238
  * - If our block for some reason is not included, revert the state
233
239
  */
234
240
  protected async doRealWork() {
235
- this.setState(SequencerState.SYNCHRONIZING, 0);
241
+ this.setState(SequencerState.SYNCHRONIZING, 0n);
236
242
  // Update state when the previous block has been synced
237
243
  const prevBlockSynced = await this.isBlockSynced();
238
244
  // Do not go forward with new block if the previous one has not been mined and processed
239
245
  if (!prevBlockSynced) {
240
- this.log.debug('Previous block has not been mined and processed yet');
241
246
  return;
242
247
  }
243
248
 
244
- this.log.debug('Previous block has been mined and processed');
245
-
246
- this.setState(SequencerState.PROPOSER_CHECK, 0);
249
+ this.setState(SequencerState.PROPOSER_CHECK, 0n);
247
250
 
248
251
  const chainTip = await this.l2BlockSource.getBlock(-1);
249
252
  const historicalHeader = chainTip?.header;
@@ -277,20 +280,24 @@ export class Sequencer {
277
280
  if (!this.shouldProposeBlock(historicalHeader, {})) {
278
281
  return;
279
282
  }
280
- const secondsIntoSlot = getSecondsIntoSlot(this.l1GenesisTime, this.aztecSlotDuration, Number(slot));
281
283
 
282
- this.setState(SequencerState.WAITING_FOR_TXS, secondsIntoSlot);
284
+ this.log.verbose(`Preparing proposal for block ${newBlockNumber} at slot ${slot}`, {
285
+ chainTipArchive: new Fr(chainTipArchive),
286
+ blockNumber: newBlockNumber,
287
+ slot,
288
+ });
289
+
290
+ this.setState(SequencerState.WAITING_FOR_TXS, slot);
283
291
 
284
292
  // Get txs to build the new block.
285
- const pendingTxs = this.p2pClient.getTxs('pending');
293
+ const pendingTxs = await this.p2pClient.getPendingTxs();
286
294
 
287
295
  if (!this.shouldProposeBlock(historicalHeader, { pendingTxsCount: pendingTxs.length })) {
288
296
  return;
289
297
  }
290
- this.log.debug(`Retrieved ${pendingTxs.length} txs from P2P pool`);
291
298
 
292
299
  // If I created a "partial" header here that should make our job much easier.
293
- const proposalHeader = new Header(
300
+ const proposalHeader = new BlockHeader(
294
301
  new AppendOnlyTreeSnapshot(Fr.fromBuffer(chainTipArchive), 1),
295
302
  ContentCommitment.empty(),
296
303
  StateReference.empty(),
@@ -312,6 +319,10 @@ export class Sequencer {
312
319
  // may break if we start emitting lots of log data from public-land.
313
320
  const validTxs = this.takeTxsWithinMaxSize(allValidTxs);
314
321
 
322
+ this.log.verbose(
323
+ `Collected ${validTxs.length} txs out of ${allValidTxs.length} valid txs out of ${pendingTxs.length} total pending txs for block ${newBlockNumber}`,
324
+ );
325
+
315
326
  // Bail if we don't have enough valid txs
316
327
  if (!this.shouldProposeBlock(historicalHeader, { validTxsCount: validTxs.length })) {
317
328
  return;
@@ -323,9 +334,9 @@ export class Sequencer {
323
334
  // be in for a world of pain.
324
335
  await this.buildBlockAndAttemptToPublish(validTxs, proposalHeader, historicalHeader);
325
336
  } catch (err) {
326
- this.log.error(`Error assembling block`, (err as any).stack);
337
+ this.log.error(`Error assembling block`, err, { blockNumber: newBlockNumber, slot });
327
338
  }
328
- this.setState(SequencerState.IDLE, 0);
339
+ this.setState(SequencerState.IDLE, 0n);
329
340
  }
330
341
 
331
342
  protected async work() {
@@ -339,12 +350,12 @@ export class Sequencer {
339
350
  throw err;
340
351
  }
341
352
  } finally {
342
- this.setState(SequencerState.IDLE, 0);
353
+ this.setState(SequencerState.IDLE, 0n);
343
354
  }
344
355
  }
345
356
 
346
357
  /** Whether to skip the check of min txs per block if more than maxSecondsBetweenBlocks has passed since the previous block. */
347
- private skipMinTxsPerBlockCheck(historicalHeader: Header | undefined): boolean {
358
+ private skipMinTxsPerBlockCheck(historicalHeader: BlockHeader | undefined): boolean {
348
359
  const lastBlockTime = historicalHeader?.globalVariables.timestamp.toNumber() || 0;
349
360
  const currentTime = Math.floor(Date.now() / 1000);
350
361
  const elapsed = currentTime - lastBlockTime;
@@ -358,16 +369,14 @@ export class Sequencer {
358
369
  const [slot, blockNumber] = await this.publisher.canProposeAtNextEthBlock(tipArchive);
359
370
 
360
371
  if (proposalBlockNumber !== blockNumber) {
361
- const msg = `Block number mismatch. Expected ${proposalBlockNumber} but got ${blockNumber}`;
362
- this.log.debug(msg);
372
+ const msg = `Sequencer block number mismatch. Expected ${proposalBlockNumber} but got ${blockNumber}.`;
373
+ this.log.warn(msg);
363
374
  throw new Error(msg);
364
375
  }
365
-
366
- this.log.verbose(`Can propose block ${proposalBlockNumber} at slot ${slot}`);
367
376
  return slot;
368
377
  } catch (err) {
369
378
  const msg = prettyLogViemErrorMsg(err);
370
- this.log.verbose(
379
+ this.log.debug(
371
380
  `Rejected from being able to propose at next block with ${tipArchive.toString('hex')}: ${msg ? `${msg}` : ''}`,
372
381
  );
373
382
  throw err;
@@ -384,7 +393,6 @@ export class Sequencer {
384
393
  }
385
394
 
386
395
  const bufferSeconds = this.timeTable[proposedState] - secondsIntoSlot;
387
- this.metrics.recordStateTransitionBufferMs(bufferSeconds * 1000, proposedState);
388
396
 
389
397
  if (bufferSeconds < 0) {
390
398
  this.log.warn(
@@ -392,26 +400,38 @@ export class Sequencer {
392
400
  );
393
401
  return false;
394
402
  }
403
+
404
+ this.metrics.recordStateTransitionBufferMs(Math.floor(bufferSeconds * 1000), proposedState);
405
+
395
406
  this.log.debug(
396
407
  `Enough time to transition to ${proposedState}, max allowed: ${this.timeTable[proposedState]}s, time into slot: ${secondsIntoSlot}s`,
397
408
  );
398
409
  return true;
399
410
  }
400
411
 
401
- setState(proposedState: SequencerState, secondsIntoSlot: number, force: boolean = false) {
412
+ /**
413
+ * Sets the sequencer state and checks if we have enough time left in the slot to transition to the new state.
414
+ * @param proposedState - The new state to transition to.
415
+ * @param currentSlotNumber - The current slot number.
416
+ * @param force - Whether to force the transition even if the sequencer is stopped.
417
+ *
418
+ * @dev If the `currentSlotNumber` doesn't matter (e.g. transitioning to IDLE), pass in `0n`;
419
+ * it is only used to check if we have enough time left in the slot to transition to the new state.
420
+ */
421
+ setState(proposedState: SequencerState, currentSlotNumber: bigint, force: boolean = false) {
402
422
  if (this.state === SequencerState.STOPPED && force !== true) {
403
- this.log.warn(
404
- `Cannot set sequencer from ${this.state} to ${proposedState} as it is stopped. Set force=true to override.`,
405
- );
423
+ this.log.warn(`Cannot set sequencer from ${this.state} to ${proposedState} as it is stopped.`);
406
424
  return;
407
425
  }
426
+ const secondsIntoSlot = getSecondsIntoSlot(this.l1GenesisTime, this.aztecSlotDuration, Number(currentSlotNumber));
408
427
  if (!this.doIHaveEnoughTimeLeft(proposedState, secondsIntoSlot)) {
409
428
  throw new SequencerTooSlowError(this.state, proposedState, this.timeTable[proposedState], secondsIntoSlot);
410
429
  }
430
+ this.log.debug(`Transitioning from ${this.state} to ${proposedState}`);
411
431
  this.state = proposedState;
412
432
  }
413
433
 
414
- shouldProposeBlock(historicalHeader: Header | undefined, args: ShouldProposeArgs): boolean {
434
+ shouldProposeBlock(historicalHeader: BlockHeader | undefined, args: ShouldProposeArgs): boolean {
415
435
  if (this.isFlushing) {
416
436
  this.log.verbose(`Flushing all pending txs in new block`);
417
437
  return true;
@@ -428,7 +448,7 @@ export class Sequencer {
428
448
  // If we haven't hit the maxSecondsBetweenBlocks, we need to have at least minTxsPerBLock txs.
429
449
  // Do not go forward with new block if not enough time has passed since last block
430
450
  if (this.minSecondsBetweenBlocks > 0 && elapsedSinceLastBlock < this.minSecondsBetweenBlocks) {
431
- this.log.debug(
451
+ this.log.verbose(
432
452
  `Not creating block because not enough time ${this.minSecondsBetweenBlocks} has passed since last block`,
433
453
  );
434
454
  return false;
@@ -444,7 +464,7 @@ export class Sequencer {
444
464
  `Creating block with only ${args.pendingTxsCount} txs as more than ${this.maxSecondsBetweenBlocks}s have passed since last block`,
445
465
  );
446
466
  } else {
447
- this.log.debug(
467
+ this.log.verbose(
448
468
  `Not creating block because not enough txs in the pool (got ${args.pendingTxsCount} min ${this.minTxsPerBLock})`,
449
469
  );
450
470
  return false;
@@ -456,7 +476,7 @@ export class Sequencer {
456
476
  if (args.validTxsCount != undefined) {
457
477
  // Bail if we don't have enough valid txs
458
478
  if (!skipCheck && args.validTxsCount < this.minTxsPerBLock) {
459
- this.log.debug(
479
+ this.log.verbose(
460
480
  `Not creating block because not enough valid txs loaded from the pool (got ${args.validTxsCount} min ${this.minTxsPerBLock})`,
461
481
  );
462
482
  return false;
@@ -469,7 +489,7 @@ export class Sequencer {
469
489
  // we should bail.
470
490
  if (args.processedTxsCount != undefined) {
471
491
  if (args.processedTxsCount === 0 && !skipCheck && this.minTxsPerBLock > 0) {
472
- this.log.verbose('No txs processed correctly to build block. Exiting');
492
+ this.log.verbose('No txs processed correctly to build block.');
473
493
  return false;
474
494
  }
475
495
  }
@@ -490,13 +510,23 @@ export class Sequencer {
490
510
  private async buildBlock(
491
511
  validTxs: Tx[],
492
512
  newGlobalVariables: GlobalVariables,
493
- historicalHeader?: Header,
513
+ historicalHeader?: BlockHeader,
494
514
  interrupt?: (processedTxs: ProcessedTx[]) => Promise<void>,
495
515
  ) {
496
- this.log.debug('Requesting L1 to L2 messages from contract');
497
- const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(newGlobalVariables.blockNumber.toBigInt());
516
+ const blockNumber = newGlobalVariables.blockNumber.toBigInt();
517
+ const slot = newGlobalVariables.slotNumber.toBigInt();
518
+
519
+ this.log.debug(`Requesting L1 to L2 messages from contract for block ${blockNumber}`);
520
+ const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(blockNumber);
521
+
498
522
  this.log.verbose(
499
- `Retrieved ${l1ToL2Messages.length} L1 to L2 messages for block ${newGlobalVariables.blockNumber.toNumber()}`,
523
+ `Building block ${blockNumber} with ${validTxs.length} txs and ${l1ToL2Messages.length} messages`,
524
+ {
525
+ msgCount: l1ToL2Messages.length,
526
+ txCount: validTxs.length,
527
+ slot,
528
+ blockNumber,
529
+ },
500
530
  );
501
531
 
502
532
  const numRealTxs = validTxs.length;
@@ -504,7 +534,7 @@ export class Sequencer {
504
534
 
505
535
  // Sync to the previous block at least
506
536
  await this.worldState.syncImmediate(newGlobalVariables.blockNumber.toNumber() - 1);
507
- this.log.verbose(`Synced to previous block ${newGlobalVariables.blockNumber.toNumber() - 1}`);
537
+ this.log.debug(`Synced to previous block ${newGlobalVariables.blockNumber.toNumber() - 1}`);
508
538
 
509
539
  // NB: separating the dbs because both should update the state
510
540
  const publicProcessorFork = await this.worldState.fork();
@@ -526,7 +556,7 @@ export class Sequencer {
526
556
  );
527
557
  if (failedTxs.length > 0) {
528
558
  const failedTxData = failedTxs.map(fail => fail.tx);
529
- this.log.debug(`Dropping failed txs ${Tx.getHashes(failedTxData).join(', ')}`);
559
+ this.log.verbose(`Dropping failed txs ${Tx.getHashes(failedTxData).join(', ')}`);
530
560
  await this.p2pClient.deleteTxs(Tx.getHashes(failedTxData));
531
561
  }
532
562
 
@@ -535,7 +565,13 @@ export class Sequencer {
535
565
  // All real transactions have been added, set the block as full and complete the proving.
536
566
  const block = await blockBuilder.setBlockCompleted();
537
567
 
538
- return { block, publicProcessorDuration, numProcessedTxs: processedTxs.length, blockBuildingTimer };
568
+ return {
569
+ block,
570
+ publicProcessorDuration,
571
+ numMsgs: l1ToL2Messages.length,
572
+ numProcessedTxs: processedTxs.length,
573
+ blockBuildingTimer,
574
+ };
539
575
  } finally {
540
576
  // We create a fresh processor each time to reset any cached state (eg storage writes)
541
577
  await publicProcessorFork.close();
@@ -558,26 +594,18 @@ export class Sequencer {
558
594
  }))
559
595
  private async buildBlockAndAttemptToPublish(
560
596
  validTxs: Tx[],
561
- proposalHeader: Header,
562
- historicalHeader: Header | undefined,
597
+ proposalHeader: BlockHeader,
598
+ historicalHeader: BlockHeader | undefined,
563
599
  ): Promise<void> {
564
600
  await this.publisher.validateBlockForSubmission(proposalHeader);
565
601
 
566
602
  const newGlobalVariables = proposalHeader.globalVariables;
603
+ const blockNumber = newGlobalVariables.blockNumber.toNumber();
604
+ const slot = newGlobalVariables.slotNumber.toBigInt();
567
605
 
568
- this.metrics.recordNewBlock(newGlobalVariables.blockNumber.toNumber(), validTxs.length);
606
+ this.metrics.recordNewBlock(blockNumber, validTxs.length);
569
607
  const workTimer = new Timer();
570
- const secondsIntoSlot = getSecondsIntoSlot(
571
- this.l1GenesisTime,
572
- this.aztecSlotDuration,
573
- newGlobalVariables.slotNumber.toNumber(),
574
- );
575
- this.setState(SequencerState.CREATING_BLOCK, secondsIntoSlot);
576
- this.log.info(
577
- `Building blockNumber=${newGlobalVariables.blockNumber.toNumber()} txCount=${
578
- validTxs.length
579
- } slotNumber=${newGlobalVariables.slotNumber.toNumber()}`,
580
- );
608
+ this.setState(SequencerState.CREATING_BLOCK, slot);
581
609
 
582
610
  /**
583
611
  * BuildBlock is shared between the sequencer and the validator for re-execution
@@ -600,12 +628,8 @@ export class Sequencer {
600
628
  };
601
629
 
602
630
  try {
603
- const { block, publicProcessorDuration, numProcessedTxs, blockBuildingTimer } = await this.buildBlock(
604
- validTxs,
605
- newGlobalVariables,
606
- historicalHeader,
607
- interrupt,
608
- );
631
+ const buildBlockRes = await this.buildBlock(validTxs, newGlobalVariables, historicalHeader, interrupt);
632
+ const { block, publicProcessorDuration, numProcessedTxs, numMsgs, blockBuildingTimer } = buildBlockRes;
609
633
 
610
634
  // TODO(@PhilWindle) We should probably periodically check for things like another
611
635
  // block being published before ours instead of just waiting on our block
@@ -613,43 +637,56 @@ export class Sequencer {
613
637
  await this.publisher.validateBlockForSubmission(block.header);
614
638
 
615
639
  const workDuration = workTimer.ms();
616
- this.log.info(
617
- `Assembled block ${block.number} (txEffectsHash: ${block.header.contentCommitment.txsEffectsHash.toString(
618
- 'hex',
619
- )})`,
620
- {
621
- eventName: 'l2-block-built',
622
- creator: this.publisher.getSenderAddress().toString(),
623
- duration: workDuration,
624
- publicProcessDuration: publicProcessorDuration,
625
- rollupCircuitsDuration: blockBuildingTimer.ms(),
626
- ...block.getStats(),
627
- } satisfies L2BlockBuiltStats,
628
- );
640
+ const blockStats: L2BlockBuiltStats = {
641
+ eventName: 'l2-block-built',
642
+ creator: this.publisher.getSenderAddress().toString(),
643
+ duration: workDuration,
644
+ publicProcessDuration: publicProcessorDuration,
645
+ rollupCircuitsDuration: blockBuildingTimer.ms(),
646
+ ...block.getStats(),
647
+ };
648
+
649
+ const blockHash = block.hash();
650
+ const txHashes = validTxs.map(tx => tx.getTxHash());
651
+ this.log.info(`Built block ${block.number} with hash ${blockHash}`, {
652
+ txEffectsHash: block.header.contentCommitment.txsEffectsHash.toString('hex'),
653
+ blockHash,
654
+ globalVariables: block.header.globalVariables.toInspect(),
655
+ txHashes,
656
+ ...blockStats,
657
+ });
629
658
 
630
659
  if (this.isFlushing) {
631
- this.log.info(`Flushing completed`);
660
+ this.log.verbose(`Sequencer flushing completed`);
632
661
  }
633
662
 
634
- const txHashes = validTxs.map(tx => tx.getTxHash());
635
-
636
663
  this.isFlushing = false;
637
- this.log.verbose('Collecting attestations');
664
+ this.log.debug('Collecting attestations');
638
665
  const stopCollectingAttestationsTimer = this.metrics.startCollectingAttestationsTimer();
639
666
  const attestations = await this.collectAttestations(block, txHashes);
640
- this.log.verbose('Attestations collected');
667
+ if (attestations !== undefined) {
668
+ this.log.verbose(`Collected ${attestations.length} attestations`);
669
+ }
641
670
  stopCollectingAttestationsTimer();
642
- this.log.verbose('Collecting proof quotes');
643
671
 
672
+ this.log.debug('Collecting proof quotes');
644
673
  const proofQuote = await this.createProofClaimForPreviousEpoch(newGlobalVariables.slotNumber.toBigInt());
645
- this.log.info(proofQuote ? `Using proof quote ${inspect(proofQuote.payload)}` : 'No proof quote available');
646
674
 
647
675
  await this.publishL2Block(block, attestations, txHashes, proofQuote);
648
676
  this.metrics.recordPublishedBlock(workDuration);
649
677
  this.log.info(
650
- `Submitted rollup block ${block.number} with ${numProcessedTxs} transactions duration=${Math.ceil(
651
- workDuration,
652
- )}ms (Submitter: ${this.publisher.getSenderAddress()})`,
678
+ `Published rollup block ${
679
+ block.number
680
+ } with ${numProcessedTxs} transactions and ${numMsgs} messages in ${Math.ceil(workDuration)}ms`,
681
+ {
682
+ blockNumber: block.number,
683
+ blockHash: blockHash,
684
+ slot,
685
+ txCount: numProcessedTxs,
686
+ msgCount: numMsgs,
687
+ duration: Math.ceil(workDuration),
688
+ submitter: this.publisher.getSenderAddress().toString(),
689
+ },
653
690
  );
654
691
  } catch (err) {
655
692
  this.metrics.recordFailedBlock();
@@ -670,11 +707,12 @@ export class Sequencer {
670
707
  protected async collectAttestations(block: L2Block, txHashes: TxHash[]): Promise<Signature[] | undefined> {
671
708
  // TODO(https://github.com/AztecProtocol/aztec-packages/issues/7962): inefficient to have a round trip in here - this should be cached
672
709
  const committee = await this.publisher.getCurrentEpochCommittee();
673
- this.log.debug(`Attesting committee length ${committee.length}`);
674
710
 
675
711
  if (committee.length === 0) {
676
- this.log.verbose(`Attesting committee length is 0, skipping`);
712
+ this.log.verbose(`Attesting committee is empty`);
677
713
  return undefined;
714
+ } else {
715
+ this.log.debug(`Attesting committee length is ${committee.length}`);
678
716
  }
679
717
 
680
718
  if (!this.validatorClient) {
@@ -685,28 +723,21 @@ export class Sequencer {
685
723
 
686
724
  const numberOfRequiredAttestations = Math.floor((committee.length * 2) / 3) + 1;
687
725
 
688
- this.log.info('Creating block proposal');
726
+ this.log.debug('Creating block proposal');
689
727
  const proposal = await this.validatorClient.createBlockProposal(block.header, block.archive.root, txHashes);
728
+ if (!proposal) {
729
+ this.log.warn(`Failed to create block proposal, skipping collecting attestations`);
730
+ return undefined;
731
+ }
690
732
 
691
- let secondsIntoSlot = getSecondsIntoSlot(
692
- this.l1GenesisTime,
693
- this.aztecSlotDuration,
694
- block.header.globalVariables.slotNumber.toNumber(),
695
- );
733
+ const slotNumber = block.header.globalVariables.slotNumber.toBigInt();
696
734
 
697
- this.setState(SequencerState.PUBLISHING_BLOCK_TO_PEERS, secondsIntoSlot);
698
- this.log.info('Broadcasting block proposal to validators');
735
+ this.setState(SequencerState.PUBLISHING_BLOCK_TO_PEERS, slotNumber);
736
+ this.log.debug('Broadcasting block proposal to validators');
699
737
  this.validatorClient.broadcastBlockProposal(proposal);
700
738
 
701
- secondsIntoSlot = getSecondsIntoSlot(
702
- this.l1GenesisTime,
703
- this.aztecSlotDuration,
704
- block.header.globalVariables.slotNumber.toNumber(),
705
- );
706
-
707
- this.setState(SequencerState.WAITING_FOR_ATTESTATIONS, secondsIntoSlot);
739
+ this.setState(SequencerState.WAITING_FOR_ATTESTATIONS, slotNumber);
708
740
  const attestations = await this.validatorClient.collectAttestations(proposal, numberOfRequiredAttestations);
709
- this.log.info(`Collected attestations from validators, number of attestations: ${attestations.length}`);
710
741
 
711
742
  // note: the smart contract requires that the signatures are provided in the order of the committee
712
743
  return orderAttestations(attestations, committee);
@@ -717,16 +748,17 @@ export class Sequencer {
717
748
  // Find out which epoch we are currently in
718
749
  const epochToProve = await this.publisher.getClaimableEpoch();
719
750
  if (epochToProve === undefined) {
720
- this.log.verbose(`No epoch to prove`);
751
+ this.log.debug(`No epoch to prove`);
721
752
  return undefined;
722
753
  }
723
754
 
724
755
  // Get quotes for the epoch to be proven
725
756
  const quotes = await this.p2pClient.getEpochProofQuotes(epochToProve);
726
- this.log.info(`Retrieved ${quotes.length} quotes, slot: ${slotNumber}, epoch to prove: ${epochToProve}`);
727
- for (const quote of quotes) {
728
- this.log.verbose(inspect(quote.payload));
729
- }
757
+ this.log.verbose(`Retrieved ${quotes.length} quotes for slot ${slotNumber} epoch ${epochToProve}`, {
758
+ epochToProve,
759
+ slotNumber,
760
+ quotes: quotes.map(q => q.payload),
761
+ });
730
762
  // ensure these quotes are still valid for the slot and have the contract validate them
731
763
  const validQuotesPromise = Promise.all(
732
764
  quotes.filter(x => x.payload.validUntilSlot >= slotNumber).map(x => this.publisher.validateProofQuote(x)),
@@ -741,9 +773,11 @@ export class Sequencer {
741
773
  const sortedQuotes = validQuotes.sort(
742
774
  (a: EpochProofQuote, b: EpochProofQuote) => a.payload.basisPointFee - b.payload.basisPointFee,
743
775
  );
744
- return sortedQuotes[0];
776
+ const quote = sortedQuotes[0];
777
+ this.log.info(`Selected proof quote for proof claim`, quote.payload);
778
+ return quote;
745
779
  } catch (err) {
746
- this.log.error(`Failed to create proof claim for previous epoch: ${err}`);
780
+ this.log.error(`Failed to create proof claim for previous epoch`, err, { slotNumber });
747
781
  return undefined;
748
782
  }
749
783
  }
@@ -761,13 +795,8 @@ export class Sequencer {
761
795
  txHashes?: TxHash[],
762
796
  proofQuote?: EpochProofQuote,
763
797
  ) {
764
- const secondsIntoSlot = getSecondsIntoSlot(
765
- this.l1GenesisTime,
766
- this.aztecSlotDuration,
767
- block.header.globalVariables.slotNumber.toNumber(),
768
- );
769
798
  // Publishes new block to the network and awaits the tx to be mined
770
- this.setState(SequencerState.PUBLISHING_BLOCK, secondsIntoSlot);
799
+ this.setState(SequencerState.PUBLISHING_BLOCK, block.header.globalVariables.slotNumber.toBigInt());
771
800
 
772
801
  const publishedL2Block = await this.publisher.proposeL2Block(block, attestations, txHashes, proofQuote);
773
802
  if (!publishedL2Block) {
@@ -793,7 +822,7 @@ export class Sequencer {
793
822
  for (const tx of txs) {
794
823
  const txSize = tx.getSize() - tx.clientIvcProof.clientIvcProofBuffer.length;
795
824
  if (totalSize + txSize > maxSize) {
796
- this.log.warn(
825
+ this.log.debug(
797
826
  `Dropping tx ${tx.getTxHash()} with estimated size ${txSize} due to exceeding ${maxSize} block size limit (currently at ${totalSize})`,
798
827
  );
799
828
  continue;
@@ -830,7 +859,7 @@ export class Sequencer {
830
859
  p2p >= l2BlockSource.number &&
831
860
  l1ToL2MessageSource >= l2BlockSource.number;
832
861
 
833
- this.log.verbose(`Sequencer sync check ${result ? 'succeeded' : 'failed'}`, {
862
+ this.log.debug(`Sequencer sync check ${result ? 'succeeded' : 'failed'}`, {
834
863
  worldStateNumber: worldState.number,
835
864
  worldStateHash: worldState.hash,
836
865
  l2BlockSourceNumber: l2BlockSource.number,
@@ -75,5 +75,5 @@ export function orderAttestations(attestations: BlockAttestation[], orderAddress
75
75
 
76
76
  export function getSecondsIntoSlot(l1GenesisTime: number, aztecSlotDuration: number, slotNumber: number): number {
77
77
  const slotStartTimestamp = l1GenesisTime + slotNumber * aztecSlotDuration;
78
- return Date.now() / 1000 - slotStartTimestamp;
78
+ return Number((Date.now() / 1000 - slotStartTimestamp).toFixed(3));
79
79
  }
@@ -1,6 +1,6 @@
1
1
  import { type Tx, TxExecutionPhase, type TxValidator } from '@aztec/circuit-types';
2
2
  import { type AztecAddress, type Fr, FunctionSelector } from '@aztec/circuits.js';
3
- import { createDebugLogger } from '@aztec/foundation/log';
3
+ import { createLogger } from '@aztec/foundation/log';
4
4
  import { computeFeePayerBalanceStorageSlot, getExecutionRequestsByPhase } from '@aztec/simulator';
5
5
 
6
6
  /** Provides a view into public contract state */
@@ -9,7 +9,7 @@ export interface PublicStateSource {
9
9
  }
10
10
 
11
11
  export class GasTxValidator implements TxValidator<Tx> {
12
- #log = createDebugLogger('aztec:sequencer:tx_validator:tx_gas');
12
+ #log = createLogger('sequencer:tx_validator:tx_gas');
13
13
  #publicDataSource: PublicStateSource;
14
14
  #feeJuiceAddress: AztecAddress;
15
15
 
@@ -6,11 +6,11 @@ import {
6
6
  type TxValidator,
7
7
  } from '@aztec/circuit-types';
8
8
  import { type ContractDataSource } from '@aztec/circuits.js';
9
- import { createDebugLogger } from '@aztec/foundation/log';
9
+ import { createLogger } from '@aztec/foundation/log';
10
10
  import { ContractsDataSourcePublicDB, getExecutionRequestsByPhase } from '@aztec/simulator';
11
11
 
12
12
  export class PhasesTxValidator implements TxValidator<Tx> {
13
- #log = createDebugLogger('aztec:sequencer:tx_validator:tx_phases');
13
+ #log = createLogger('sequencer:tx_validator:tx_phases');
14
14
  private contractDataSource: ContractsDataSourcePublicDB;
15
15
 
16
16
  constructor(contracts: ContractDataSource, private setupAllowList: AllowedElement[]) {
@@ -1,7 +0,0 @@
1
- import { type BlockBuilder, type MerkleTreeReadOperations } from '@aztec/circuit-types';
2
- export * from './orchestrator.js';
3
- export * from './light.js';
4
- export interface BlockBuilderFactory {
5
- create(db: MerkleTreeReadOperations): BlockBuilder;
6
- }
7
- //# sourceMappingURL=index.d.ts.map