@aztec/sequencer-client 0.69.0 → 0.69.1

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 (60) hide show
  1. package/dest/client/sequencer-client.d.ts +2 -0
  2. package/dest/client/sequencer-client.d.ts.map +1 -1
  3. package/dest/client/sequencer-client.js +3 -4
  4. package/dest/config.d.ts.map +1 -1
  5. package/dest/config.js +11 -1
  6. package/dest/index.d.ts +3 -1
  7. package/dest/index.d.ts.map +1 -1
  8. package/dest/index.js +4 -2
  9. package/dest/publisher/config.d.ts +4 -0
  10. package/dest/publisher/config.d.ts.map +1 -1
  11. package/dest/publisher/config.js +6 -1
  12. package/dest/publisher/l1-publisher.d.ts +36 -11
  13. package/dest/publisher/l1-publisher.d.ts.map +1 -1
  14. package/dest/publisher/l1-publisher.js +154 -88
  15. package/dest/sequencer/index.d.ts +1 -0
  16. package/dest/sequencer/index.d.ts.map +1 -1
  17. package/dest/sequencer/index.js +2 -1
  18. package/dest/sequencer/sequencer.d.ts +9 -16
  19. package/dest/sequencer/sequencer.d.ts.map +1 -1
  20. package/dest/sequencer/sequencer.js +61 -130
  21. package/dest/sequencer/utils.d.ts +2 -2
  22. package/dest/sequencer/utils.d.ts.map +1 -1
  23. package/dest/sequencer/utils.js +3 -3
  24. package/dest/slasher/factory.d.ts +11 -0
  25. package/dest/slasher/factory.d.ts.map +1 -0
  26. package/dest/slasher/factory.js +10 -0
  27. package/dest/slasher/index.d.ts +3 -0
  28. package/dest/slasher/index.d.ts.map +1 -0
  29. package/dest/slasher/index.js +3 -0
  30. package/dest/slasher/slasher_client.d.ts +127 -0
  31. package/dest/slasher/slasher_client.d.ts.map +1 -0
  32. package/dest/slasher/slasher_client.js +305 -0
  33. package/dest/tx_validator/gas_validator.d.ts +2 -3
  34. package/dest/tx_validator/gas_validator.d.ts.map +1 -1
  35. package/dest/tx_validator/gas_validator.js +9 -22
  36. package/dest/tx_validator/nullifier_cache.d.ts +16 -0
  37. package/dest/tx_validator/nullifier_cache.d.ts.map +1 -0
  38. package/dest/tx_validator/nullifier_cache.js +24 -0
  39. package/dest/tx_validator/phases_validator.d.ts +2 -3
  40. package/dest/tx_validator/phases_validator.d.ts.map +1 -1
  41. package/dest/tx_validator/phases_validator.js +15 -24
  42. package/dest/tx_validator/tx_validator_factory.d.ts +15 -14
  43. package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
  44. package/dest/tx_validator/tx_validator_factory.js +38 -24
  45. package/package.json +21 -19
  46. package/src/client/sequencer-client.ts +5 -2
  47. package/src/config.ts +10 -0
  48. package/src/index.ts +3 -1
  49. package/src/publisher/config.ts +10 -0
  50. package/src/publisher/l1-publisher.ts +180 -97
  51. package/src/sequencer/index.ts +1 -0
  52. package/src/sequencer/sequencer.ts +70 -180
  53. package/src/sequencer/utils.ts +2 -2
  54. package/src/slasher/factory.ts +22 -0
  55. package/src/slasher/index.ts +2 -0
  56. package/src/slasher/slasher_client.ts +402 -0
  57. package/src/tx_validator/gas_validator.ts +11 -24
  58. package/src/tx_validator/nullifier_cache.ts +29 -0
  59. package/src/tx_validator/phases_validator.ts +22 -33
  60. package/src/tx_validator/tx_validator_factory.ts +82 -40
@@ -4,11 +4,9 @@ import {
4
4
  type L1ToL2MessageSource,
5
5
  type L2Block,
6
6
  type L2BlockSource,
7
- type ProcessedTx,
8
7
  SequencerConfigSchema,
9
8
  Tx,
10
9
  type TxHash,
11
- type TxValidator,
12
10
  type WorldStateSynchronizer,
13
11
  } from '@aztec/circuit-types';
14
12
  import type { AllowedElement, Signature, WorldStateSynchronizerStatus } from '@aztec/circuit-types/interfaces';
@@ -17,7 +15,9 @@ import {
17
15
  AppendOnlyTreeSnapshot,
18
16
  BlockHeader,
19
17
  ContentCommitment,
18
+ type ContractDataSource,
20
19
  GENESIS_ARCHIVE_ROOT,
20
+ Gas,
21
21
  type GlobalVariables,
22
22
  StateReference,
23
23
  } from '@aztec/circuits.js';
@@ -36,9 +36,10 @@ import { Attributes, type TelemetryClient, type Tracer, trackSpan } from '@aztec
36
36
  import { type ValidatorClient } from '@aztec/validator-client';
37
37
 
38
38
  import { type GlobalVariableBuilder } from '../global_variable_builder/global_builder.js';
39
- import { type L1Publisher } from '../publisher/l1-publisher.js';
39
+ import { type L1Publisher, VoteType } from '../publisher/l1-publisher.js';
40
40
  import { prettyLogViemErrorMsg } from '../publisher/utils.js';
41
- import { type TxValidatorFactory } from '../tx_validator/tx_validator_factory.js';
41
+ import { type SlasherClient } from '../slasher/slasher_client.js';
42
+ import { createValidatorsForBlockBuilding } from '../tx_validator/tx_validator_factory.js';
42
43
  import { getDefaultAllowedSetupFunctions } from './allowed.js';
43
44
  import { type SequencerConfig } from './config.js';
44
45
  import { SequencerMetrics } from './metrics.js';
@@ -46,12 +47,6 @@ import { SequencerState, orderAttestations } from './utils.js';
46
47
 
47
48
  export { SequencerState };
48
49
 
49
- export type ShouldProposeArgs = {
50
- pendingTxsCount?: number;
51
- validTxsCount?: number;
52
- processedTxsCount?: number;
53
- };
54
-
55
50
  export class SequencerTooSlowError extends Error {
56
51
  constructor(
57
52
  public readonly currentState: SequencerState,
@@ -89,6 +84,7 @@ export class Sequencer {
89
84
  private state = SequencerState.STOPPED;
90
85
  private allowedInSetup: AllowedElement[] = getDefaultAllowedSetupFunctions();
91
86
  private maxBlockSizeInBytes: number = 1024 * 1024;
87
+ private maxBlockGas: Gas = new Gas(10e9, 10e9);
92
88
  private processTxTime: number = 12;
93
89
  private metrics: SequencerMetrics;
94
90
  private isFlushing: boolean = false;
@@ -106,11 +102,12 @@ export class Sequencer {
106
102
  private globalsBuilder: GlobalVariableBuilder,
107
103
  private p2pClient: P2P,
108
104
  private worldState: WorldStateSynchronizer,
105
+ private slasherClient: SlasherClient,
109
106
  private blockBuilderFactory: BlockBuilderFactory,
110
107
  private l2BlockSource: L2BlockSource,
111
108
  private l1ToL2MessageSource: L1ToL2MessageSource,
112
109
  private publicProcessorFactory: PublicProcessorFactory,
113
- private txValidatorFactory: TxValidatorFactory,
110
+ private contractDataSource: ContractDataSource,
114
111
  protected l1Constants: SequencerRollupConstants,
115
112
  private dateProvider: DateProvider,
116
113
  telemetry: TelemetryClient,
@@ -122,6 +119,9 @@ export class Sequencer {
122
119
 
123
120
  // Register the block builder with the validator client for re-execution
124
121
  this.validatorClient?.registerBlockBuilder(this.buildBlock.bind(this));
122
+
123
+ // Register the slasher on the publisher to fetch slashing payloads
124
+ this.publisher.registerSlashPayloadGetter(this.slasherClient.getSlashPayload.bind(this.slasherClient));
125
125
  }
126
126
 
127
127
  get tracer(): Tracer {
@@ -144,6 +144,12 @@ export class Sequencer {
144
144
  if (config.minTxsPerBlock !== undefined) {
145
145
  this.minTxsPerBLock = config.minTxsPerBlock;
146
146
  }
147
+ if (config.maxDABlockGas !== undefined) {
148
+ this.maxBlockGas = new Gas(config.maxDABlockGas, this.maxBlockGas.l2Gas);
149
+ }
150
+ if (config.maxL2BlockGas !== undefined) {
151
+ this.maxBlockGas = new Gas(this.maxBlockGas.daGas, config.maxL2BlockGas);
152
+ }
147
153
  if (config.coinbase) {
148
154
  this._coinbase = config.coinbase;
149
155
  }
@@ -157,7 +163,7 @@ export class Sequencer {
157
163
  this.maxBlockSizeInBytes = config.maxBlockSizeInBytes;
158
164
  }
159
165
  if (config.governanceProposerPayload) {
160
- this.publisher.setPayload(config.governanceProposerPayload);
166
+ this.publisher.setGovernancePayload(config.governanceProposerPayload);
161
167
  }
162
168
  if (config.maxL1TxInclusionTimeIntoSlot !== undefined) {
163
169
  this.maxL1TxInclusionTimeIntoSlot = config.maxL1TxInclusionTimeIntoSlot;
@@ -174,7 +180,7 @@ export class Sequencer {
174
180
  // How late into the slot can we be to start working
175
181
  const initialTime = 2;
176
182
 
177
- // How long it takes to validate the txs collected and get ready to start building
183
+ // How long it takes to get ready to start building
178
184
  const blockPrepareTime = 1;
179
185
 
180
186
  // How long it takes to for attestations to travel across the p2p layer.
@@ -213,9 +219,9 @@ export class Sequencer {
213
219
  [SequencerState.SYNCHRONIZING]: this.aztecSlotDuration,
214
220
  // We always want to allow the full slot to check if we are the proposer
215
221
  [SequencerState.PROPOSER_CHECK]: this.aztecSlotDuration,
216
- // First transition towards building a block
217
- [SequencerState.WAITING_FOR_TXS]: initialTime,
218
- // We then validate the txs and prepare to start building the block
222
+ // How late we can start initializing a new block proposal
223
+ [SequencerState.INITIALIZING_PROPOSAL]: initialTime,
224
+ // When we start building a block
219
225
  [SequencerState.CREATING_BLOCK]: initialTime + blockPrepareTime,
220
226
  // We start collecting attestations after building the block
221
227
  [SequencerState.COLLECTING_ATTESTATIONS]: initialTime + blockPrepareTime + processTxsTime + blockValidationTime,
@@ -245,6 +251,7 @@ export class Sequencer {
245
251
  this.log.debug(`Stopping sequencer`);
246
252
  await this.validatorClient?.stop();
247
253
  await this.runningPromise?.stop();
254
+ await this.slasherClient?.stop();
248
255
  this.publisher.interrupt();
249
256
  this.setState(SequencerState.STOPPED, 0n, true /** force */);
250
257
  this.log.info('Stopped sequencer');
@@ -314,27 +321,30 @@ export class Sequencer {
314
321
  slot,
315
322
  );
316
323
 
317
- void this.publisher.castVote(slot, newGlobalVariables.timestamp.toBigInt());
324
+ void this.publisher.castVote(slot, newGlobalVariables.timestamp.toBigInt(), VoteType.GOVERNANCE);
325
+ void this.publisher.castVote(slot, newGlobalVariables.timestamp.toBigInt(), VoteType.SLASHING);
318
326
 
319
- if (!this.shouldProposeBlock(historicalHeader, {})) {
327
+ // Check the pool has enough txs to build a block
328
+ const pendingTxCount = this.p2pClient.getPendingTxCount();
329
+ if (pendingTxCount < this.minTxsPerBLock && !this.isFlushing) {
330
+ this.log.verbose(`Not enough txs to propose block. Got ${pendingTxCount} min ${this.minTxsPerBLock}.`, {
331
+ slot,
332
+ blockNumber: newBlockNumber,
333
+ });
334
+ await this.claimEpochProofRightIfAvailable(slot);
320
335
  return;
321
336
  }
322
337
 
338
+ this.setState(SequencerState.INITIALIZING_PROPOSAL, slot);
323
339
  this.log.verbose(`Preparing proposal for block ${newBlockNumber} at slot ${slot}`, {
324
340
  chainTipArchive: new Fr(chainTipArchive),
325
341
  blockNumber: newBlockNumber,
326
342
  slot,
327
343
  });
328
344
 
329
- this.setState(SequencerState.WAITING_FOR_TXS, slot);
330
-
331
- // Get txs to build the new block.
332
- const pendingTxs = await this.p2pClient.getPendingTxs();
333
-
334
- if (!this.shouldProposeBlock(historicalHeader, { pendingTxsCount: pendingTxs.length })) {
335
- await this.claimEpochProofRightIfAvailable(slot);
336
- return;
337
- }
345
+ // We don't fetch exactly maxTxsPerBlock txs here because we may not need all of them if we hit a limit before,
346
+ // and also we may need to fetch more if we don't have enough valid txs.
347
+ const pendingTxs = this.p2pClient.iteratePendingTxs();
338
348
 
339
349
  // If I created a "partial" header here that should make our job much easier.
340
350
  const proposalHeader = new BlockHeader(
@@ -346,35 +356,12 @@ export class Sequencer {
346
356
  Fr.ZERO,
347
357
  );
348
358
 
349
- // TODO: It should be responsibility of the P2P layer to validate txs before passing them on here.
350
- // TODO: We should validate only the number of txs we need to speed up this process.
351
- const allValidTxs = await this.takeValidTxs(
352
- pendingTxs,
353
- this.txValidatorFactory.validatorForNewTxs(newGlobalVariables, this.allowedInSetup),
354
- );
355
-
356
- // TODO: We are taking the size of the tx from private-land, but we should be doing this after running
357
- // public functions. Only reason why we do it here now is because the public processor and orchestrator
358
- // are set up such that they require knowing the total number of txs in advance. Still, main reason for
359
- // exceeding max block size in bytes is contract class registration, which happens in private-land. This
360
- // may break if we start emitting lots of log data from public-land.
361
- const validTxs = this.takeTxsWithinMaxSize(allValidTxs);
362
-
363
- this.log.verbose(
364
- `Collected ${validTxs.length} txs out of ${allValidTxs.length} valid txs out of ${pendingTxs.length} total pending txs for block ${newBlockNumber}`,
365
- );
366
-
367
- // Bail if we don't have enough valid txs
368
- if (!this.shouldProposeBlock(historicalHeader, { validTxsCount: validTxs.length })) {
369
- await this.claimEpochProofRightIfAvailable(slot);
370
- return;
371
- }
372
-
373
359
  try {
360
+ // TODO(palla/txs) Is the note below still valid? We don't seem to be doing any rollback in there.
374
361
  // @note It is very important that the following function will FAIL and not just return early
375
362
  // if it have made any state changes. If not, we won't rollback the state, and you will
376
363
  // be in for a world of pain.
377
- await this.buildBlockAndAttemptToPublish(validTxs, proposalHeader, historicalHeader);
364
+ await this.buildBlockAndAttemptToPublish(pendingTxs, proposalHeader, historicalHeader);
378
365
  } catch (err) {
379
366
  this.log.error(`Error assembling block`, err, { blockNumber: newBlockNumber, slot });
380
367
  }
@@ -462,64 +449,20 @@ export class Sequencer {
462
449
  this.state = proposedState;
463
450
  }
464
451
 
465
- shouldProposeBlock(historicalHeader: BlockHeader | undefined, args: ShouldProposeArgs): boolean {
466
- if (this.isFlushing) {
467
- this.log.verbose(`Flushing all pending txs in new block`);
468
- return true;
469
- }
470
-
471
- // Compute time elapsed since the previous block
472
- const lastBlockTime = historicalHeader?.globalVariables.timestamp.toNumber() || 0;
473
- const currentTime = Math.floor(Date.now() / 1000);
474
- const elapsedSinceLastBlock = currentTime - lastBlockTime;
475
- this.log.debug(
476
- `Last block mined at ${lastBlockTime} current time is ${currentTime} (elapsed ${elapsedSinceLastBlock})`,
477
- );
478
-
479
- // We need to have at least minTxsPerBLock txs.
480
- if (args.pendingTxsCount !== undefined && args.pendingTxsCount < this.minTxsPerBLock) {
481
- this.log.verbose(
482
- `Not creating block because not enough txs in the pool (got ${args.pendingTxsCount} min ${this.minTxsPerBLock})`,
483
- );
484
- return false;
485
- }
486
-
487
- // Bail if we don't have enough valid txs
488
- if (args.validTxsCount !== undefined && args.validTxsCount < this.minTxsPerBLock) {
489
- this.log.verbose(
490
- `Not creating block because not enough valid txs loaded from the pool (got ${args.validTxsCount} min ${this.minTxsPerBLock})`,
491
- );
492
- return false;
493
- }
494
-
495
- // TODO: This check should be processedTxs.length < this.minTxsPerBLock, so we don't publish a block with
496
- // less txs than the minimum. But that'd cause the entire block to be aborted and retried. Instead, we should
497
- // go back to the p2p pool and load more txs until we hit our minTxsPerBLock target. Only if there are no txs
498
- // we should bail.
499
- if (args.processedTxsCount === 0 && this.minTxsPerBLock > 0) {
500
- this.log.verbose('No txs processed correctly to build block.');
501
- return false;
502
- }
503
-
504
- return true;
505
- }
506
-
507
452
  /**
508
453
  * Build a block
509
454
  *
510
455
  * Shared between the sequencer and the validator for re-execution
511
456
  *
512
- * @param validTxs - The valid transactions to construct the block from
457
+ * @param pendingTxs - The pending transactions to construct the block from
513
458
  * @param newGlobalVariables - The global variables for the new block
514
459
  * @param historicalHeader - The historical header of the parent
515
- * @param interrupt - The interrupt callback, used to validate the block for submission and check if we should propose the block
516
460
  * @param opts - Whether to just validate the block as a validator, as opposed to building it as a proposal
517
461
  */
518
462
  private async buildBlock(
519
- validTxs: Tx[],
463
+ pendingTxs: Iterable<Tx>,
520
464
  newGlobalVariables: GlobalVariables,
521
465
  historicalHeader?: BlockHeader,
522
- interrupt?: (processedTxs: ProcessedTx[]) => Promise<void>,
523
466
  opts: { validateOnly?: boolean } = {},
524
467
  ) {
525
468
  const blockNumber = newGlobalVariables.blockNumber.toBigInt();
@@ -527,19 +470,9 @@ export class Sequencer {
527
470
 
528
471
  this.log.debug(`Requesting L1 to L2 messages from contract for block ${blockNumber}`);
529
472
  const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(blockNumber);
473
+ const msgCount = l1ToL2Messages.length;
530
474
 
531
- this.log.verbose(
532
- `Building block ${blockNumber} with ${validTxs.length} txs and ${l1ToL2Messages.length} messages`,
533
- {
534
- msgCount: l1ToL2Messages.length,
535
- txCount: validTxs.length,
536
- slot,
537
- blockNumber,
538
- },
539
- );
540
-
541
- const numRealTxs = validTxs.length;
542
- const blockSize = Math.max(2, numRealTxs);
475
+ this.log.verbose(`Building block ${blockNumber} for slot ${slot}`, { slot, blockNumber, msgCount });
543
476
 
544
477
  // Sync to the previous block at least
545
478
  await this.worldState.syncImmediate(newGlobalVariables.blockNumber.toNumber() - 1);
@@ -563,18 +496,30 @@ export class Sequencer {
563
496
  // We set the deadline for tx processing to the start of the CREATING_BLOCK phase, plus the expected time for tx processing.
564
497
  // Deadline is only set if enforceTimeTable is enabled.
565
498
  const processingEndTimeWithinSlot = this.timeTable[SequencerState.CREATING_BLOCK] + this.processTxTime;
566
- const processingDeadline = this.enforceTimeTable
499
+ const deadline = this.enforceTimeTable
567
500
  ? new Date((this.getSlotStartTimestamp(slot) + processingEndTimeWithinSlot) * 1000)
568
501
  : undefined;
569
- this.log.verbose(`Processing ${validTxs.length} txs`, {
502
+ this.log.verbose(`Processing pending txs`, {
570
503
  slot,
571
504
  slotStart: new Date(this.getSlotStartTimestamp(slot) * 1000),
572
505
  now: new Date(this.dateProvider.now()),
573
- deadline: processingDeadline,
506
+ deadline,
574
507
  });
575
- const processingTxValidator = this.txValidatorFactory.validatorForProcessedTxs(publicProcessorFork);
508
+
509
+ const validators = createValidatorsForBlockBuilding(
510
+ publicProcessorFork,
511
+ this.contractDataSource,
512
+ newGlobalVariables,
513
+ !!this.config.enforceFees,
514
+ this.allowedInSetup,
515
+ );
516
+
517
+ // REFACTOR: Public processor should just handle processing, one tx at a time. It should be responsibility
518
+ // of the sequencer to update world state and iterate over txs. We should refactor this along with unifying the
519
+ // publicProcessorFork and orchestratorFork, to avoid doing tree insertions twice when building the block.
520
+ const limits = { deadline, maxTransactions: this.maxTxsPerBlock, maxBlockSize: this.maxBlockSizeInBytes };
576
521
  const [publicProcessorDuration, [processedTxs, failedTxs]] = await elapsed(() =>
577
- processor.process(validTxs, blockSize, processingTxValidator, processingDeadline),
522
+ processor.process(pendingTxs, limits, validators),
578
523
  );
579
524
 
580
525
  if (failedTxs.length > 0) {
@@ -602,8 +547,6 @@ export class Sequencer {
602
547
  const duration = Number(end - start) / 1_000;
603
548
  this.metrics.recordBlockBuilderTreeInsertions(duration);
604
549
 
605
- await interrupt?.(processedTxs);
606
-
607
550
  // All real transactions have been added, set the block as full and pad if needed
608
551
  const block = await blockBuilder.setBlockCompleted();
609
552
 
@@ -611,7 +554,7 @@ export class Sequencer {
611
554
  block,
612
555
  publicProcessorDuration,
613
556
  numMsgs: l1ToL2Messages.length,
614
- numProcessedTxs: processedTxs.length,
557
+ numTxs: processedTxs.length,
615
558
  blockBuildingTimer,
616
559
  };
617
560
  } finally {
@@ -635,7 +578,7 @@ export class Sequencer {
635
578
  * @dev MUST throw instead of exiting early to ensure that world-state
636
579
  * is being rolled back if the block is dropped.
637
580
  *
638
- * @param validTxs - The valid transactions to construct the block from
581
+ * @param pendingTxs - Iterable of pending transactions to construct the block from
639
582
  * @param proposalHeader - The partial header constructed for the proposal
640
583
  * @param historicalHeader - The historical header of the parent
641
584
  */
@@ -643,7 +586,7 @@ export class Sequencer {
643
586
  [Attributes.BLOCK_NUMBER]: proposalHeader.globalVariables.blockNumber.toNumber(),
644
587
  }))
645
588
  private async buildBlockAndAttemptToPublish(
646
- validTxs: Tx[],
589
+ pendingTxs: Iterable<Tx>,
647
590
  proposalHeader: BlockHeader,
648
591
  historicalHeader: BlockHeader | undefined,
649
592
  ): Promise<void> {
@@ -653,40 +596,19 @@ export class Sequencer {
653
596
  const blockNumber = newGlobalVariables.blockNumber.toNumber();
654
597
  const slot = newGlobalVariables.slotNumber.toBigInt();
655
598
 
656
- this.metrics.recordNewBlock(blockNumber, validTxs.length);
599
+ // this.metrics.recordNewBlock(blockNumber, validTxs.length);
657
600
  const workTimer = new Timer();
658
601
  this.setState(SequencerState.CREATING_BLOCK, slot);
659
602
 
660
- /**
661
- * BuildBlock is shared between the sequencer and the validator for re-execution
662
- * We use the interrupt callback to validate the block for submission and check if we should propose the block
663
- *
664
- * If we fail, we throw an error in order to roll back
665
- */
666
- const interrupt = async (processedTxs: ProcessedTx[]) => {
667
- await this.publisher.validateBlockForSubmission(proposalHeader);
668
-
669
- if (
670
- !this.shouldProposeBlock(historicalHeader, {
671
- validTxsCount: validTxs.length,
672
- processedTxsCount: processedTxs.length,
673
- })
674
- ) {
675
- // TODO: Roll back changes to world state
676
- throw new Error('Should not propose the block');
677
- }
678
- };
679
-
680
603
  // Start collecting proof quotes for the previous epoch if needed in the background
681
604
  const proofQuotePromise = this.createProofClaimForPreviousEpoch(slot);
682
605
 
683
606
  try {
684
- const buildBlockRes = await this.buildBlock(validTxs, newGlobalVariables, historicalHeader, interrupt);
685
- const { block, publicProcessorDuration, numProcessedTxs, numMsgs, blockBuildingTimer } = buildBlockRes;
607
+ const buildBlockRes = await this.buildBlock(pendingTxs, newGlobalVariables, historicalHeader);
608
+ const { block, publicProcessorDuration, numTxs, numMsgs, blockBuildingTimer } = buildBlockRes;
686
609
 
687
610
  // TODO(@PhilWindle) We should probably periodically check for things like another
688
611
  // block being published before ours instead of just waiting on our block
689
-
690
612
  await this.publisher.validateBlockForSubmission(block.header);
691
613
 
692
614
  const workDuration = workTimer.ms();
@@ -700,8 +622,8 @@ export class Sequencer {
700
622
  };
701
623
 
702
624
  const blockHash = block.hash();
703
- const txHashes = validTxs.map(tx => tx.getTxHash());
704
- this.log.info(`Built block ${block.number} with hash ${blockHash}`, {
625
+ const txHashes = block.body.txEffects.map(tx => tx.txHash);
626
+ this.log.info(`Built block ${block.number} for slot ${slot} with ${numTxs} txs`, {
705
627
  blockHash,
706
628
  globalVariables: block.header.globalVariables.toInspect(),
707
629
  txHashes,
@@ -727,14 +649,12 @@ export class Sequencer {
727
649
  await this.publishL2Block(block, attestations, txHashes, proofQuote);
728
650
  this.metrics.recordPublishedBlock(workDuration);
729
651
  this.log.info(
730
- `Published rollup block ${
731
- block.number
732
- } with ${numProcessedTxs} transactions and ${numMsgs} messages in ${Math.ceil(workDuration)}ms`,
652
+ `Published block ${block.number} with ${numTxs} txs and ${numMsgs} messages in ${Math.ceil(workDuration)}ms`,
733
653
  {
734
654
  blockNumber: block.number,
735
655
  blockHash: blockHash,
736
656
  slot,
737
- txCount: numProcessedTxs,
657
+ txCount: txHashes.length,
738
658
  msgCount: numMsgs,
739
659
  duration: Math.ceil(workDuration),
740
660
  submitter: this.publisher.getSenderAddress().toString(),
@@ -858,36 +778,6 @@ export class Sequencer {
858
778
  }
859
779
  }
860
780
 
861
- protected async takeValidTxs<T extends Tx | ProcessedTx>(txs: T[], validator: TxValidator<T>): Promise<T[]> {
862
- const [valid, invalid] = await validator.validateTxs(txs);
863
- if (invalid.length > 0) {
864
- this.log.debug(`Dropping invalid txs from the p2p pool ${Tx.getHashes(invalid).join(', ')}`);
865
- await this.p2pClient.deleteTxs(Tx.getHashes(invalid));
866
- }
867
-
868
- return valid.slice(0, this.maxTxsPerBlock);
869
- }
870
-
871
- protected takeTxsWithinMaxSize(txs: Tx[]): Tx[] {
872
- const maxSize = this.maxBlockSizeInBytes;
873
- let totalSize = 0;
874
-
875
- const toReturn: Tx[] = [];
876
- for (const tx of txs) {
877
- const txSize = tx.getSize() - tx.clientIvcProof.clientIvcProofBuffer.length;
878
- if (totalSize + txSize > maxSize) {
879
- this.log.debug(
880
- `Dropping tx ${tx.getTxHash()} with estimated size ${txSize} due to exceeding ${maxSize} block size limit (currently at ${totalSize})`,
881
- );
882
- continue;
883
- }
884
- toReturn.push(tx);
885
- totalSize += txSize;
886
- }
887
-
888
- return toReturn;
889
- }
890
-
891
781
  @trackSpan(
892
782
  'Sequencer.claimEpochProofRightIfAvailable',
893
783
  slotNumber => ({ [Attributes.SLOT_NUMBER]: Number(slotNumber) }),
@@ -19,9 +19,9 @@ export enum SequencerState {
19
19
  */
20
20
  PROPOSER_CHECK = 'PROPOSER_CHECK',
21
21
  /**
22
- * Polling the P2P module for txs to include in a block. Will move to CREATING_BLOCK if there are valid txs to include, or back to SYNCHRONIZING otherwise.
22
+ * Initializing the block proposal. Will move to CREATING_BLOCK if there are valid txs to include, or back to SYNCHRONIZING otherwise.
23
23
  */
24
- WAITING_FOR_TXS = 'WAITING_FOR_TXS',
24
+ INITIALIZING_PROPOSAL = 'INITIALIZING_PROPOSAL',
25
25
  /**
26
26
  * Creating a new L2 block. Includes processing public function calls and running rollup circuits. Will move to PUBLISHING_CONTRACT_DATA.
27
27
  */
@@ -0,0 +1,22 @@
1
+ import type { L2BlockSource } from '@aztec/circuit-types';
2
+ import { type L1ContractsConfig, type L1ReaderConfig } from '@aztec/ethereum';
3
+ import { createLogger } from '@aztec/foundation/log';
4
+ import { type AztecKVStore } from '@aztec/kv-store';
5
+ import { type DataStoreConfig } from '@aztec/kv-store/config';
6
+ import { createStore } from '@aztec/kv-store/lmdb';
7
+ import { type TelemetryClient } from '@aztec/telemetry-client';
8
+ import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
9
+
10
+ import { SlasherClient } from './slasher_client.js';
11
+ import { type SlasherConfig } from './slasher_client.js';
12
+
13
+ export const createSlasherClient = async (
14
+ _config: SlasherConfig & DataStoreConfig & L1ContractsConfig & L1ReaderConfig,
15
+ l2BlockSource: L2BlockSource,
16
+ telemetry: TelemetryClient = new NoopTelemetryClient(),
17
+ deps: { store?: AztecKVStore } = {},
18
+ ) => {
19
+ const config = { ..._config };
20
+ const store = deps.store ?? (await createStore('slasher', config, createLogger('slasher:lmdb')));
21
+ return new SlasherClient(config, store, l2BlockSource, telemetry);
22
+ };
@@ -0,0 +1,2 @@
1
+ export * from './slasher_client.js';
2
+ export { createSlasherClient } from './factory.js';