@aztec/sequencer-client 0.47.1 → 0.48.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 (61) hide show
  1. package/dest/client/sequencer-client.d.ts +2 -2
  2. package/dest/client/sequencer-client.d.ts.map +1 -1
  3. package/dest/client/sequencer-client.js +2 -2
  4. package/dest/config.d.ts +6 -2
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +96 -31
  7. package/dest/global_variable_builder/global_builder.d.ts +14 -8
  8. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  9. package/dest/global_variable_builder/global_builder.js +10 -16
  10. package/dest/global_variable_builder/index.d.ts +2 -3
  11. package/dest/global_variable_builder/index.d.ts.map +1 -1
  12. package/dest/global_variable_builder/index.js +1 -1
  13. package/dest/global_variable_builder/viem-reader.d.ts +5 -4
  14. package/dest/global_variable_builder/viem-reader.d.ts.map +1 -1
  15. package/dest/global_variable_builder/viem-reader.js +11 -8
  16. package/dest/publisher/config.d.ts +7 -15
  17. package/dest/publisher/config.d.ts.map +1 -1
  18. package/dest/publisher/config.js +38 -11
  19. package/dest/publisher/index.d.ts +3 -2
  20. package/dest/publisher/index.d.ts.map +1 -1
  21. package/dest/publisher/index.js +4 -4
  22. package/dest/publisher/l1-publisher-metrics.d.ts +17 -0
  23. package/dest/publisher/l1-publisher-metrics.d.ts.map +1 -0
  24. package/dest/publisher/l1-publisher-metrics.js +75 -0
  25. package/dest/publisher/l1-publisher.d.ts +33 -5
  26. package/dest/publisher/l1-publisher.d.ts.map +1 -1
  27. package/dest/publisher/l1-publisher.js +44 -36
  28. package/dest/publisher/viem-tx-sender.d.ts +9 -2
  29. package/dest/publisher/viem-tx-sender.d.ts.map +1 -1
  30. package/dest/publisher/viem-tx-sender.js +85 -16
  31. package/dest/receiver.d.ts +2 -8
  32. package/dest/receiver.d.ts.map +1 -1
  33. package/dest/sequencer/metrics.d.ts +17 -0
  34. package/dest/sequencer/metrics.d.ts.map +1 -0
  35. package/dest/sequencer/metrics.js +56 -0
  36. package/dest/sequencer/sequencer.d.ts +7 -5
  37. package/dest/sequencer/sequencer.d.ts.map +1 -1
  38. package/dest/sequencer/sequencer.js +58 -21
  39. package/dest/tx_validator/gas_validator.d.ts +1 -1
  40. package/dest/tx_validator/gas_validator.js +11 -11
  41. package/dest/tx_validator/tx_validator_factory.js +2 -2
  42. package/package.json +15 -15
  43. package/src/client/sequencer-client.ts +3 -3
  44. package/src/config.ts +111 -54
  45. package/src/global_variable_builder/global_builder.ts +35 -25
  46. package/src/global_variable_builder/index.ts +3 -3
  47. package/src/global_variable_builder/viem-reader.ts +14 -11
  48. package/src/publisher/config.ts +43 -31
  49. package/src/publisher/index.ts +5 -3
  50. package/src/publisher/l1-publisher-metrics.ts +108 -0
  51. package/src/publisher/l1-publisher.ts +78 -43
  52. package/src/publisher/viem-tx-sender.ts +89 -14
  53. package/src/receiver.ts +3 -8
  54. package/src/sequencer/metrics.ts +86 -0
  55. package/src/sequencer/sequencer.ts +86 -31
  56. package/src/tx_validator/gas_validator.ts +9 -9
  57. package/src/tx_validator/tx_validator_factory.ts +2 -2
  58. package/dest/global_variable_builder/config.d.ts +0 -19
  59. package/dest/global_variable_builder/config.d.ts.map +0 -1
  60. package/dest/global_variable_builder/config.js +0 -2
  61. package/src/global_variable_builder/config.ts +0 -20
@@ -9,11 +9,11 @@ import {
9
9
  import {
10
10
  type AllowedElement,
11
11
  BlockProofError,
12
- type BlockProver,
13
12
  PROVING_STATUS,
13
+ type ProverClient,
14
14
  } from '@aztec/circuit-types/interfaces';
15
15
  import { type L2BlockBuiltStats } from '@aztec/circuit-types/stats';
16
- import { AztecAddress, EthAddress, type GlobalVariables, type Header } from '@aztec/circuits.js';
16
+ import { AztecAddress, EthAddress, type GlobalVariables, type Header, IS_DEV_NET } from '@aztec/circuits.js';
17
17
  import { Fr } from '@aztec/foundation/fields';
18
18
  import { createDebugLogger } from '@aztec/foundation/log';
19
19
  import { RunningPromise } from '@aztec/foundation/running-promise';
@@ -24,9 +24,10 @@ import { Attributes, type TelemetryClient, type Tracer, trackSpan } from '@aztec
24
24
  import { type WorldStateStatus, type WorldStateSynchronizer } from '@aztec/world-state';
25
25
 
26
26
  import { type GlobalVariableBuilder } from '../global_variable_builder/global_builder.js';
27
- import { type L1Publisher } from '../publisher/l1-publisher.js';
27
+ import { type Attestation, type L1Publisher } from '../publisher/l1-publisher.js';
28
28
  import { type TxValidatorFactory } from '../tx_validator/tx_validator_factory.js';
29
29
  import { type SequencerConfig } from './config.js';
30
+ import { SequencerMetrics } from './metrics.js';
30
31
 
31
32
  /**
32
33
  * Sequencer client
@@ -53,15 +54,14 @@ export class Sequencer {
53
54
  private allowedInTeardown: AllowedElement[] = [];
54
55
  private maxBlockSizeInBytes: number = 1024 * 1024;
55
56
  private skipSubmitProofs: boolean = false;
56
-
57
- public readonly tracer: Tracer;
57
+ private metrics: SequencerMetrics;
58
58
 
59
59
  constructor(
60
60
  private publisher: L1Publisher,
61
61
  private globalsBuilder: GlobalVariableBuilder,
62
62
  private p2pClient: P2P,
63
63
  private worldState: WorldStateSynchronizer,
64
- private prover: BlockProver,
64
+ private prover: ProverClient,
65
65
  private l2BlockSource: L2BlockSource,
66
66
  private l1ToL2MessageSource: L1ToL2MessageSource,
67
67
  private publicProcessorFactory: PublicProcessorFactory,
@@ -71,10 +71,14 @@ export class Sequencer {
71
71
  private log = createDebugLogger('aztec:sequencer'),
72
72
  ) {
73
73
  this.updateConfig(config);
74
- this.tracer = telemetry.getTracer('Sequencer');
74
+ this.metrics = new SequencerMetrics(telemetry, () => this.state, 'Sequencer');
75
75
  this.log.verbose(`Initialized sequencer with ${this.minTxsPerBLock}-${this.maxTxsPerBlock} txs per block.`);
76
76
  }
77
77
 
78
+ get tracer(): Tracer {
79
+ return this.metrics.tracer;
80
+ }
81
+
78
82
  /**
79
83
  * Updates sequencer config.
80
84
  * @param config - New parameters.
@@ -170,16 +174,17 @@ export class Sequencer {
170
174
  try {
171
175
  // Update state when the previous block has been synced
172
176
  const prevBlockSynced = await this.isBlockSynced();
173
- if (prevBlockSynced && this.state === SequencerState.PUBLISHING_BLOCK) {
174
- this.log.debug(`Block has been synced`);
175
- this.state = SequencerState.IDLE;
176
- }
177
-
178
177
  // Do not go forward with new block if the previous one has not been mined and processed
179
178
  if (!prevBlockSynced) {
179
+ this.log.debug('Previous block has not been mined and processed yet');
180
180
  return;
181
181
  }
182
182
 
183
+ if (prevBlockSynced && this.state === SequencerState.PUBLISHING_BLOCK) {
184
+ this.log.debug(`Block has been synced`);
185
+ this.state = SequencerState.IDLE;
186
+ }
187
+
183
188
  const historicalHeader = (await this.l2BlockSource.getBlock(-1))?.header;
184
189
  const newBlockNumber =
185
190
  (historicalHeader === undefined
@@ -231,6 +236,8 @@ export class Sequencer {
231
236
  this._feeRecipient,
232
237
  );
233
238
 
239
+ // @todo @LHerskind Include some logic to consider slots
240
+
234
241
  // TODO: It should be responsibility of the P2P layer to validate txs before passing them on here
235
242
  const allValidTxs = await this.takeValidTxs(
236
243
  pendingTxs,
@@ -260,8 +267,6 @@ export class Sequencer {
260
267
  await this.p2pClient.deleteTxs(txHashes);
261
268
  }
262
269
  this.log.error(`Rolling back world state DB due to error assembling block`, (err as any).stack);
263
- // Cancel any further proving on the block
264
- this.prover?.cancelBlock();
265
270
  await this.worldState.getLatest().rollback();
266
271
  }
267
272
  }
@@ -280,6 +285,7 @@ export class Sequencer {
280
285
  historicalHeader: Header | undefined,
281
286
  elapsedSinceLastBlock: number,
282
287
  ): Promise<void> {
288
+ this.metrics.recordNewBlock(newGlobalVariables.blockNumber.toNumber(), validTxs.length);
283
289
  const workTimer = new Timer();
284
290
  this.state = SequencerState.CREATING_BLOCK;
285
291
  this.log.info(`Building block ${newGlobalVariables.blockNumber.toNumber()} with ${validTxs.length} transactions`);
@@ -287,12 +293,15 @@ export class Sequencer {
287
293
  const assertBlockHeight = async () => {
288
294
  const currentBlockNumber = await this.l2BlockSource.getBlockNumber();
289
295
  if (currentBlockNumber + 1 !== newGlobalVariables.blockNumber.toNumber()) {
296
+ this.metrics.recordCancelledBlock();
290
297
  throw new Error('New block was emitted while building block');
291
298
  }
292
299
 
293
300
  if (!(await this.publisher.isItMyTurnToSubmit())) {
294
301
  throw new Error(`Not this sequencer turn to submit block`);
295
302
  }
303
+
304
+ // @todo @LHerskind Should take into account, block number, proposer and slot number
296
305
  };
297
306
 
298
307
  // Get l1 to l2 messages from the contract
@@ -309,10 +318,11 @@ export class Sequencer {
309
318
  const blockSize = Math.max(2, numRealTxs);
310
319
 
311
320
  const blockBuildingTimer = new Timer();
312
- const blockTicket = await this.prover.startNewBlock(blockSize, newGlobalVariables, l1ToL2Messages);
321
+ const prover = this.prover.createBlockProver(this.worldState.getLatest());
322
+ const blockTicket = await prover.startNewBlock(blockSize, newGlobalVariables, l1ToL2Messages);
313
323
 
314
324
  const [publicProcessorDuration, [processedTxs, failedTxs]] = await elapsed(() =>
315
- processor.process(validTxs, blockSize, this.prover, this.txValidatorFactory.validatorForProcessedTxs()),
325
+ processor.process(validTxs, blockSize, prover, this.txValidatorFactory.validatorForProcessedTxs()),
316
326
  );
317
327
  if (failedTxs.length > 0) {
318
328
  const failedTxData = failedTxs.map(fail => fail.tx);
@@ -326,14 +336,14 @@ export class Sequencer {
326
336
  // we should bail.
327
337
  if (processedTxs.length === 0 && !this.skipMinTxsPerBlockCheck(elapsedSinceLastBlock)) {
328
338
  this.log.verbose('No txs processed correctly to build block. Exiting');
329
- this.prover.cancelBlock();
339
+ prover.cancelBlock();
330
340
  return;
331
341
  }
332
342
 
333
343
  await assertBlockHeight();
334
344
 
335
345
  // All real transactions have been added, set the block as full and complete the proving.
336
- await this.prover.setBlockCompleted();
346
+ await prover.setBlockCompleted();
337
347
 
338
348
  // Here we are now waiting for the block to be proven.
339
349
  // TODO(@PhilWindle) We should probably periodically check for things like another
@@ -346,30 +356,75 @@ export class Sequencer {
346
356
  await assertBlockHeight();
347
357
 
348
358
  // Block is proven, now finalise and publish!
349
- const { block, aggregationObject, proof } = await this.prover.finaliseBlock();
359
+ const { block, aggregationObject, proof } = await prover.finaliseBlock();
350
360
 
351
361
  await assertBlockHeight();
352
362
 
353
- this.log.verbose(`Assembled block ${block.number}`, {
354
- eventName: 'l2-block-built',
355
- duration: workTimer.ms(),
356
- publicProcessDuration: publicProcessorDuration,
357
- rollupCircuitsDuration: blockBuildingTimer.ms(),
358
- ...block.getStats(),
359
- } satisfies L2BlockBuiltStats);
363
+ const workDuration = workTimer.ms();
364
+ this.log.verbose(
365
+ `Assembled block ${block.number} (txEffectsHash: ${block.header.contentCommitment.txsEffectsHash.toString(
366
+ 'hex',
367
+ )})`,
368
+ {
369
+ eventName: 'l2-block-built',
370
+ duration: workDuration,
371
+ publicProcessDuration: publicProcessorDuration,
372
+ rollupCircuitsDuration: blockBuildingTimer.ms(),
373
+ ...block.getStats(),
374
+ } satisfies L2BlockBuiltStats,
375
+ );
360
376
 
361
- await this.publishL2Block(block);
362
- this.log.info(`Submitted rollup block ${block.number} with ${processedTxs.length} transactions`);
377
+ try {
378
+ const attestations = await this.collectAttestations(block);
379
+ await this.publishL2Block(block, attestations);
380
+ this.metrics.recordPublishedBlock(workDuration);
381
+ this.log.info(
382
+ `Submitted rollup block ${block.number} with ${
383
+ processedTxs.length
384
+ } transactions duration=${workDuration}ms (Submitter: ${await this.publisher.senderAddress()})`,
385
+ );
386
+ } catch (err) {
387
+ this.metrics.recordFailedBlock();
388
+ throw err;
389
+ }
363
390
 
364
391
  // Submit the proof if we have configured this sequencer to run with an actual prover.
365
392
  // This is temporary while we submit one proof per block, but will have to change once we
366
393
  // move onto proving batches of multiple blocks at a time.
367
394
  if (aggregationObject && proof && !this.skipSubmitProofs) {
368
- await this.publisher.submitProof(block.header, block.archive.root, aggregationObject, proof);
395
+ await this.publisher.submitProof(
396
+ block.header,
397
+ block.archive.root,
398
+ prover.getProverId(),
399
+ aggregationObject,
400
+ proof,
401
+ );
369
402
  this.log.info(`Submitted proof for block ${block.number}`);
370
403
  }
371
404
  }
372
405
 
406
+ protected async collectAttestations(block: L2Block): Promise<Attestation[] | undefined> {
407
+ // @todo This should collect attestations properly and fix the ordering of them to make sense
408
+ // the current implementation is a PLACEHOLDER and should be nuked from orbit.
409
+ // It is assuming that there will only be ONE (1) validator, so only one attestation
410
+ // is needed.
411
+ // @note This is quite a sin, but I'm committing war crimes in this code already.
412
+ // _ ._ _ , _ ._
413
+ // (_ ' ( ` )_ .__)
414
+ // ( ( ( ) `) ) _)
415
+ // (__ (_ (_ . _) _) ,__)
416
+ // `~~`\ ' . /`~~`
417
+ // ; ;
418
+ // / \
419
+ // _____________/_ __ \_____________
420
+ if (IS_DEV_NET) {
421
+ return undefined;
422
+ }
423
+
424
+ const myAttestation = await this.publisher.attest(block.archive.root.toString());
425
+ return [myAttestation];
426
+ }
427
+
373
428
  /**
374
429
  * Publishes the L2Block to the rollup contract.
375
430
  * @param block - The L2Block to be published.
@@ -377,10 +432,10 @@ export class Sequencer {
377
432
  @trackSpan('Sequencer.publishL2Block', block => ({
378
433
  [Attributes.BLOCK_NUMBER]: block.number,
379
434
  }))
380
- protected async publishL2Block(block: L2Block) {
435
+ protected async publishL2Block(block: L2Block, attestations?: Attestation[]) {
381
436
  // Publishes new block to the network and awaits the tx to be mined
382
437
  this.state = SequencerState.PUBLISHING_BLOCK;
383
- const publishedL2Block = await this.publisher.processL2Block(block);
438
+ const publishedL2Block = await this.publisher.processL2Block(block, attestations);
384
439
  if (publishedL2Block) {
385
440
  this.lastPublishedBlock = block.number;
386
441
  } else {
@@ -1,7 +1,7 @@
1
1
  import { PublicKernelType, type Tx, type TxValidator } from '@aztec/circuit-types';
2
2
  import { type AztecAddress, type Fr } from '@aztec/circuits.js';
3
3
  import { createDebugLogger } from '@aztec/foundation/log';
4
- import { GasTokenArtifact } from '@aztec/protocol-contracts/gas-token';
4
+ import { FeeJuiceArtifact } from '@aztec/protocol-contracts/fee-juice';
5
5
  import { AbstractPhaseManager, computeFeePayerBalanceStorageSlot } from '@aztec/simulator';
6
6
 
7
7
  /** Provides a view into public contract state */
@@ -12,11 +12,11 @@ export interface PublicStateSource {
12
12
  export class GasTxValidator implements TxValidator<Tx> {
13
13
  #log = createDebugLogger('aztec:sequencer:tx_validator:tx_gas');
14
14
  #publicDataSource: PublicStateSource;
15
- #gasTokenAddress: AztecAddress;
15
+ #feeJuiceAddress: AztecAddress;
16
16
 
17
- constructor(publicDataSource: PublicStateSource, gasTokenAddress: AztecAddress, public enforceFees: boolean) {
17
+ constructor(publicDataSource: PublicStateSource, feeJuiceAddress: AztecAddress, public enforceFees: boolean) {
18
18
  this.#publicDataSource = publicDataSource;
19
- this.#gasTokenAddress = gasTokenAddress;
19
+ this.#feeJuiceAddress = feeJuiceAddress;
20
20
  }
21
21
 
22
22
  async validateTxs(txs: Tx[]): Promise<[validTxs: Tx[], invalidTxs: Tx[]]> {
@@ -50,18 +50,18 @@ export class GasTxValidator implements TxValidator<Tx> {
50
50
 
51
51
  // Read current balance of the feePayer
52
52
  const initialBalance = await this.#publicDataSource.storageRead(
53
- this.#gasTokenAddress,
53
+ this.#feeJuiceAddress,
54
54
  computeFeePayerBalanceStorageSlot(feePayer),
55
55
  );
56
56
 
57
- // If there is a claim in this tx that increases the fee payer balance in gas token, add it to balance
57
+ // If there is a claim in this tx that increases the fee payer balance in Fee Juice, add it to balance
58
58
  const { [PublicKernelType.SETUP]: setupFns } = AbstractPhaseManager.extractEnqueuedPublicCallsByPhase(tx);
59
59
  const claimFunctionCall = setupFns.find(
60
60
  fn =>
61
- fn.contractAddress.equals(this.#gasTokenAddress) &&
62
- fn.callContext.msgSender.equals(this.#gasTokenAddress) &&
61
+ fn.contractAddress.equals(this.#feeJuiceAddress) &&
62
+ fn.callContext.msgSender.equals(this.#feeJuiceAddress) &&
63
63
  fn.callContext.functionSelector.equals(
64
- GasTokenArtifact.functions.find(f => f.name === '_increase_public_balance')!,
64
+ FeeJuiceArtifact.functions.find(f => f.name === '_increase_public_balance')!,
65
65
  ) &&
66
66
  fn.args[0].equals(feePayer) &&
67
67
  !fn.callContext.isStaticCall &&
@@ -1,6 +1,6 @@
1
1
  import { type AllowedElement, type ProcessedTx, type Tx, type TxValidator } from '@aztec/circuit-types';
2
2
  import { type GlobalVariables } from '@aztec/circuits.js';
3
- import { GasTokenAddress } from '@aztec/protocol-contracts/gas-token';
3
+ import { FeeJuiceAddress } from '@aztec/protocol-contracts/fee-juice';
4
4
  import { WorldStateDB, WorldStatePublicDB } from '@aztec/simulator';
5
5
  import { type ContractDataSource } from '@aztec/types/contracts';
6
6
  import { type MerkleTreeOperations } from '@aztec/world-state';
@@ -25,7 +25,7 @@ export class TxValidatorFactory {
25
25
  new MetadataTxValidator(globalVariables),
26
26
  new DoubleSpendTxValidator(new WorldStateDB(this.merkleTreeDb)),
27
27
  new PhasesTxValidator(this.contractDataSource, setupAllowList),
28
- new GasTxValidator(new WorldStatePublicDB(this.merkleTreeDb), GasTokenAddress, this.enforceFees),
28
+ new GasTxValidator(new WorldStatePublicDB(this.merkleTreeDb), FeeJuiceAddress, this.enforceFees),
29
29
  );
30
30
  }
31
31
 
@@ -1,19 +0,0 @@
1
- import { type L1ContractAddresses } from '@aztec/ethereum';
2
- /**
3
- * Configuration of the L1GlobalReader.
4
- */
5
- export interface GlobalReaderConfig {
6
- /**
7
- * The RPC Url of the ethereum host.
8
- */
9
- rpcUrl: string;
10
- /**
11
- * The chain ID of the ethereum host.
12
- */
13
- l1ChainId: number;
14
- /**
15
- * The deployed l1 contract addresses
16
- */
17
- l1Contracts: L1ContractAddresses;
18
- }
19
- //# sourceMappingURL=config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/global_variable_builder/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,WAAW,EAAE,mBAAmB,CAAC;CAClC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2dsb2JhbF92YXJpYWJsZV9idWlsZGVyL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
@@ -1,20 +0,0 @@
1
- import { type L1ContractAddresses } from '@aztec/ethereum';
2
-
3
- /**
4
- * Configuration of the L1GlobalReader.
5
- */
6
- export interface GlobalReaderConfig {
7
- /**
8
- * The RPC Url of the ethereum host.
9
- */
10
- rpcUrl: string;
11
- /**
12
- * The chain ID of the ethereum host.
13
- */
14
- l1ChainId: number;
15
-
16
- /**
17
- * The deployed l1 contract addresses
18
- */
19
- l1Contracts: L1ContractAddresses;
20
- }