@aztec/sequencer-client 0.0.1-commit.4ad48494d → 0.0.1-commit.4d3c002

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 (84) hide show
  1. package/dest/client/sequencer-client.d.ts +15 -7
  2. package/dest/client/sequencer-client.d.ts.map +1 -1
  3. package/dest/client/sequencer-client.js +60 -26
  4. package/dest/config.d.ts +26 -6
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +44 -21
  7. package/dest/global_variable_builder/global_builder.d.ts +15 -11
  8. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  9. package/dest/global_variable_builder/global_builder.js +29 -25
  10. package/dest/global_variable_builder/index.d.ts +2 -2
  11. package/dest/global_variable_builder/index.d.ts.map +1 -1
  12. package/dest/publisher/config.d.ts +47 -17
  13. package/dest/publisher/config.d.ts.map +1 -1
  14. package/dest/publisher/config.js +121 -42
  15. package/dest/publisher/index.d.ts +2 -1
  16. package/dest/publisher/index.d.ts.map +1 -1
  17. package/dest/publisher/l1_tx_failed_store/factory.d.ts +11 -0
  18. package/dest/publisher/l1_tx_failed_store/factory.d.ts.map +1 -0
  19. package/dest/publisher/l1_tx_failed_store/factory.js +22 -0
  20. package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +59 -0
  21. package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +1 -0
  22. package/dest/publisher/l1_tx_failed_store/failed_tx_store.js +1 -0
  23. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts +15 -0
  24. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts.map +1 -0
  25. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.js +34 -0
  26. package/dest/publisher/l1_tx_failed_store/index.d.ts +4 -0
  27. package/dest/publisher/l1_tx_failed_store/index.d.ts.map +1 -0
  28. package/dest/publisher/l1_tx_failed_store/index.js +2 -0
  29. package/dest/publisher/sequencer-publisher-factory.d.ts +11 -3
  30. package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
  31. package/dest/publisher/sequencer-publisher-factory.js +27 -2
  32. package/dest/publisher/sequencer-publisher.d.ts +76 -30
  33. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  34. package/dest/publisher/sequencer-publisher.js +396 -71
  35. package/dest/sequencer/checkpoint_proposal_job.d.ts +33 -8
  36. package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
  37. package/dest/sequencer/checkpoint_proposal_job.js +347 -170
  38. package/dest/sequencer/checkpoint_voter.d.ts +1 -2
  39. package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
  40. package/dest/sequencer/checkpoint_voter.js +2 -5
  41. package/dest/sequencer/events.d.ts +2 -1
  42. package/dest/sequencer/events.d.ts.map +1 -1
  43. package/dest/sequencer/metrics.d.ts +18 -5
  44. package/dest/sequencer/metrics.d.ts.map +1 -1
  45. package/dest/sequencer/metrics.js +72 -15
  46. package/dest/sequencer/sequencer.d.ts +40 -17
  47. package/dest/sequencer/sequencer.d.ts.map +1 -1
  48. package/dest/sequencer/sequencer.js +145 -92
  49. package/dest/sequencer/timetable.d.ts +4 -3
  50. package/dest/sequencer/timetable.d.ts.map +1 -1
  51. package/dest/sequencer/timetable.js +6 -7
  52. package/dest/sequencer/types.d.ts +2 -2
  53. package/dest/sequencer/types.d.ts.map +1 -1
  54. package/dest/test/index.d.ts +3 -5
  55. package/dest/test/index.d.ts.map +1 -1
  56. package/dest/test/mock_checkpoint_builder.d.ts +11 -11
  57. package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
  58. package/dest/test/mock_checkpoint_builder.js +45 -34
  59. package/dest/test/utils.d.ts +3 -3
  60. package/dest/test/utils.d.ts.map +1 -1
  61. package/dest/test/utils.js +4 -4
  62. package/package.json +27 -28
  63. package/src/client/sequencer-client.ts +76 -23
  64. package/src/config.ts +56 -27
  65. package/src/global_variable_builder/global_builder.ts +38 -27
  66. package/src/global_variable_builder/index.ts +1 -1
  67. package/src/publisher/config.ts +153 -43
  68. package/src/publisher/index.ts +3 -0
  69. package/src/publisher/l1_tx_failed_store/factory.ts +32 -0
  70. package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +55 -0
  71. package/src/publisher/l1_tx_failed_store/file_store_failed_tx_store.ts +46 -0
  72. package/src/publisher/l1_tx_failed_store/index.ts +3 -0
  73. package/src/publisher/sequencer-publisher-factory.ts +38 -6
  74. package/src/publisher/sequencer-publisher.ts +442 -95
  75. package/src/sequencer/checkpoint_proposal_job.ts +456 -176
  76. package/src/sequencer/checkpoint_voter.ts +1 -12
  77. package/src/sequencer/events.ts +1 -1
  78. package/src/sequencer/metrics.ts +82 -18
  79. package/src/sequencer/sequencer.ts +208 -108
  80. package/src/sequencer/timetable.ts +7 -7
  81. package/src/sequencer/types.ts +1 -1
  82. package/src/test/index.ts +2 -4
  83. package/src/test/mock_checkpoint_builder.ts +63 -49
  84. package/src/test/utils.ts +4 -2
@@ -2,7 +2,6 @@ import type { SlotNumber } from '@aztec/foundation/branded-types';
2
2
  import type { EthAddress } from '@aztec/foundation/eth-address';
3
3
  import type { Logger } from '@aztec/foundation/log';
4
4
  import type { SlasherClientInterface } from '@aztec/slasher';
5
- import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
6
5
  import type { ResolvedSequencerConfig } from '@aztec/stdlib/interfaces/server';
7
6
  import type { ValidatorClient } from '@aztec/validator-client';
8
7
  import { DutyAlreadySignedError } from '@aztec/validator-ha-signer/errors';
@@ -18,7 +17,6 @@ import type { SequencerRollupConstants } from './types.js';
18
17
  * Handles governance and slashing voting for a given slot.
19
18
  */
20
19
  export class CheckpointVoter {
21
- private slotTimestamp: bigint;
22
20
  private governanceSigner: (msg: TypedDataDefinition) => Promise<`0x${string}`>;
23
21
  private slashingSigner: (msg: TypedDataDefinition) => Promise<`0x${string}`>;
24
22
 
@@ -33,8 +31,6 @@ export class CheckpointVoter {
33
31
  private readonly metrics: SequencerMetrics,
34
32
  private readonly log: Logger,
35
33
  ) {
36
- this.slotTimestamp = getTimestampForSlot(this.slot, this.l1Constants);
37
-
38
34
  // Create separate signers with appropriate duty contexts for governance and slashing votes
39
35
  // These use HA protection to ensure only one node signs per slot/duty
40
36
  const governanceContext: SigningContext = { slot: this.slot, dutyType: DutyType.GOVERNANCE_VOTE };
@@ -77,7 +73,6 @@ export class CheckpointVoter {
77
73
  return await this.publisher.enqueueGovernanceCastSignal(
78
74
  governanceProposerPayload,
79
75
  this.slot,
80
- this.slotTimestamp,
81
76
  this.attestorAddress,
82
77
  this.governanceSigner,
83
78
  );
@@ -108,13 +103,7 @@ export class CheckpointVoter {
108
103
 
109
104
  this.metrics.recordSlashingAttempt(actions.length);
110
105
 
111
- return await this.publisher.enqueueSlashingActions(
112
- actions,
113
- this.slot,
114
- this.slotTimestamp,
115
- this.attestorAddress,
116
- this.slashingSigner,
117
- );
106
+ return await this.publisher.enqueueSlashingActions(actions, this.slot, this.attestorAddress, this.slashingSigner);
118
107
  } catch (err) {
119
108
  if (err instanceof DutyAlreadySignedError) {
120
109
  this.log.info(`Slashing vote already signed by another node`, {
@@ -13,7 +13,7 @@ export type SequencerEvents = {
13
13
  ['proposer-rollup-check-failed']: (args: { reason: string; slot: SlotNumber }) => void;
14
14
  ['block-tx-count-check-failed']: (args: { minTxs: number; availableTxs: number; slot: SlotNumber }) => void;
15
15
  ['block-build-failed']: (args: { reason: string; slot: SlotNumber }) => void;
16
- ['block-proposed']: (args: { blockNumber: BlockNumber; slot: SlotNumber }) => void;
16
+ ['block-proposed']: (args: { blockNumber: BlockNumber; slot: SlotNumber; buildSlot: SlotNumber }) => void;
17
17
  ['checkpoint-empty']: (args: { slot: SlotNumber }) => void;
18
18
  ['checkpoint-publish-failed']: (args: {
19
19
  slot: SlotNumber;
@@ -18,7 +18,6 @@ import { type Hex, formatUnits } from 'viem';
18
18
 
19
19
  import type { SequencerState } from './utils.js';
20
20
 
21
- // TODO(palla/mbps): Review all metrics and add any missing ones per checkpoint
22
21
  export class SequencerMetrics {
23
22
  public readonly tracer: Tracer;
24
23
  private meter: Meter;
@@ -40,11 +39,18 @@ export class SequencerMetrics {
40
39
  private filledSlots: UpDownCounter;
41
40
 
42
41
  private blockProposalFailed: UpDownCounter;
43
- private blockProposalSuccess: UpDownCounter;
44
- private blockProposalPrecheckFailed: UpDownCounter;
42
+ private checkpointProposalSuccess: UpDownCounter;
43
+ private checkpointPrecheckFailed: UpDownCounter;
44
+ private checkpointProposalFailed: UpDownCounter;
45
45
  private checkpointSuccess: UpDownCounter;
46
46
  private slashingAttempts: UpDownCounter;
47
47
  private checkpointAttestationDelay: Histogram;
48
+ private checkpointBuildDuration: Histogram;
49
+ private checkpointBlockCount: Gauge;
50
+ private checkpointTxCount: Gauge;
51
+ private checkpointTotalMana: Gauge;
52
+ private pipelineDepth: Gauge;
53
+ private pipelineDiscards: UpDownCounter;
48
54
 
49
55
  // Fisherman fee analysis metrics
50
56
  private fishermanWouldBeIncluded: UpDownCounter;
@@ -54,6 +60,7 @@ export class SequencerMetrics {
54
60
  private fishermanPendingBlobCount: Histogram;
55
61
  private fishermanIncludedBlobCount: Histogram;
56
62
  private fishermanBlockBlobsFull: UpDownCounter;
63
+ private fishermanMaxBlobCapacity: Histogram;
57
64
  private fishermanCalculatedPriorityFee: Histogram;
58
65
  private fishermanPriorityFeeDelta: Histogram;
59
66
  private fishermanEstimatedCost: Histogram;
@@ -83,7 +90,7 @@ export class SequencerMetrics {
83
90
 
84
91
  this.checkpointAttestationDelay = this.meter.createHistogram(Metrics.SEQUENCER_CHECKPOINT_ATTESTATION_DELAY);
85
92
 
86
- this.rewards = this.meter.createGauge(Metrics.SEQUENCER_CURRENT_BLOCK_REWARDS);
93
+ this.rewards = this.meter.createGauge(Metrics.SEQUENCER_CURRENT_SLOT_REWARDS);
87
94
 
88
95
  this.slots = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLOT_COUNT);
89
96
 
@@ -106,16 +113,16 @@ export class SequencerMetrics {
106
113
  Metrics.SEQUENCER_BLOCK_PROPOSAL_FAILED_COUNT,
107
114
  );
108
115
 
109
- this.blockProposalSuccess = createUpDownCounterWithDefault(
116
+ this.checkpointProposalSuccess = createUpDownCounterWithDefault(
110
117
  this.meter,
111
- Metrics.SEQUENCER_BLOCK_PROPOSAL_SUCCESS_COUNT,
118
+ Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_SUCCESS_COUNT,
112
119
  );
113
120
 
114
121
  this.checkpointSuccess = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_CHECKPOINT_SUCCESS_COUNT);
115
122
 
116
- this.blockProposalPrecheckFailed = createUpDownCounterWithDefault(
123
+ this.checkpointPrecheckFailed = createUpDownCounterWithDefault(
117
124
  this.meter,
118
- Metrics.SEQUENCER_BLOCK_PROPOSAL_PRECHECK_FAILED_COUNT,
125
+ Metrics.SEQUENCER_CHECKPOINT_PRECHECK_FAILED_COUNT,
119
126
  {
120
127
  [Attributes.ERROR_TYPE]: [
121
128
  'slot_already_taken',
@@ -126,14 +133,29 @@ export class SequencerMetrics {
126
133
  },
127
134
  );
128
135
 
136
+ this.checkpointProposalFailed = createUpDownCounterWithDefault(
137
+ this.meter,
138
+ Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_FAILED_COUNT,
139
+ );
140
+
141
+ this.checkpointBuildDuration = this.meter.createHistogram(Metrics.SEQUENCER_CHECKPOINT_BUILD_DURATION);
142
+ this.checkpointBlockCount = this.meter.createGauge(Metrics.SEQUENCER_CHECKPOINT_BLOCK_COUNT);
143
+ this.checkpointTxCount = this.meter.createGauge(Metrics.SEQUENCER_CHECKPOINT_TX_COUNT);
144
+ this.checkpointTotalMana = this.meter.createGauge(Metrics.SEQUENCER_CHECKPOINT_TOTAL_MANA);
145
+
129
146
  this.slashingAttempts = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLASHING_ATTEMPTS_COUNT);
130
147
 
148
+ this.pipelineDepth = this.meter.createGauge(Metrics.SEQUENCER_PIPELINE_DEPTH);
149
+ this.pipelineDiscards = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_PIPELINE_DISCARDS_COUNT);
150
+ this.pipelineDepth.record(0);
151
+
131
152
  // Fisherman fee analysis metrics
132
153
  this.fishermanWouldBeIncluded = createUpDownCounterWithDefault(
133
154
  this.meter,
134
155
  Metrics.FISHERMAN_FEE_ANALYSIS_WOULD_BE_INCLUDED,
135
156
  {
136
157
  [Attributes.OK]: [true, false],
158
+ [Attributes.BLOCK_FULL]: ['true', 'false'],
137
159
  },
138
160
  );
139
161
 
@@ -176,6 +198,8 @@ export class SequencerMetrics {
176
198
  [Attributes.OK]: [true, false],
177
199
  },
178
200
  );
201
+
202
+ this.fishermanMaxBlobCapacity = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_MAX_BLOB_CAPACITY);
179
203
  }
180
204
 
181
205
  public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
@@ -216,6 +240,14 @@ export class SequencerMetrics {
216
240
  });
217
241
  }
218
242
 
243
+ recordPipelineDepth(depth: number) {
244
+ this.pipelineDepth.record(depth);
245
+ }
246
+
247
+ recordPipelineDiscard(count = 1) {
248
+ this.pipelineDiscards.add(count);
249
+ }
250
+
219
251
  incOpenSlot(slot: SlotNumber, proposer: string) {
220
252
  // sequencer went through the loop a second time. Noop
221
253
  if (slot === this.lastSeenSlot) {
@@ -258,18 +290,30 @@ export class SequencerMetrics {
258
290
  });
259
291
  }
260
292
 
261
- recordBlockProposalSuccess() {
262
- this.blockProposalSuccess.add(1);
293
+ recordCheckpointProposalSuccess() {
294
+ this.checkpointProposalSuccess.add(1);
263
295
  }
264
296
 
265
- recordBlockProposalPrecheckFailed(
297
+ recordCheckpointPrecheckFailed(
266
298
  checkType: 'slot_already_taken' | 'rollup_contract_check_failed' | 'slot_mismatch' | 'block_number_mismatch',
267
299
  ) {
268
- this.blockProposalPrecheckFailed.add(1, {
269
- [Attributes.ERROR_TYPE]: checkType,
300
+ this.checkpointPrecheckFailed.add(1, { [Attributes.ERROR_TYPE]: checkType });
301
+ }
302
+
303
+ recordCheckpointProposalFailed(reason?: string) {
304
+ this.checkpointProposalFailed.add(1, {
305
+ ...(reason && { [Attributes.ERROR_TYPE]: reason }),
270
306
  });
271
307
  }
272
308
 
309
+ /** Records aggregate metrics for a completed checkpoint build. */
310
+ recordCheckpointBuild(durationMs: number, blockCount: number, txCount: number, totalMana: number) {
311
+ this.checkpointBuildDuration.record(Math.ceil(durationMs));
312
+ this.checkpointBlockCount.record(blockCount);
313
+ this.checkpointTxCount.record(txCount);
314
+ this.checkpointTotalMana.record(totalMana);
315
+ }
316
+
273
317
  recordSlashingAttempt(actionCount: number) {
274
318
  this.slashingAttempts.add(actionCount);
275
319
  }
@@ -342,13 +386,21 @@ export class SequencerMetrics {
342
386
  this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: false });
343
387
  }
344
388
 
389
+ // Record the max blob capacity for this block
390
+ this.fishermanMaxBlobCapacity.record(analysis.analysis.maxBlobCapacity, strategyAttributes);
391
+
345
392
  // Record strategy-specific inclusion result
346
393
  if (strategyResult.wouldBeIncluded !== undefined) {
394
+ const inclusionAttributes = {
395
+ ...strategyAttributes,
396
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
397
+ };
398
+
347
399
  if (strategyResult.wouldBeIncluded) {
348
- this.fishermanWouldBeIncluded.add(1, { ...strategyAttributes, [Attributes.OK]: true });
400
+ this.fishermanWouldBeIncluded.add(1, { ...inclusionAttributes, [Attributes.OK]: true });
349
401
  } else {
350
402
  this.fishermanWouldBeIncluded.add(1, {
351
- ...strategyAttributes,
403
+ ...inclusionAttributes,
352
404
  [Attributes.OK]: false,
353
405
  ...(strategyResult.exclusionReason && { [Attributes.ERROR_TYPE]: strategyResult.exclusionReason }),
354
406
  });
@@ -358,17 +410,29 @@ export class SequencerMetrics {
358
410
  // Record strategy-specific priority fee delta
359
411
  if (strategyResult.priorityFeeDelta !== undefined) {
360
412
  const priorityFeeDeltaGwei = Number(strategyResult.priorityFeeDelta) / 1e9;
361
- this.fishermanPriorityFeeDelta.record(priorityFeeDeltaGwei, strategyAttributes);
413
+ const deltaAttributes = {
414
+ ...strategyAttributes,
415
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
416
+ };
417
+ this.fishermanPriorityFeeDelta.record(priorityFeeDeltaGwei, deltaAttributes);
362
418
  }
363
419
 
364
420
  // Record estimated cost if available
365
421
  if (strategyResult.estimatedCostEth !== undefined) {
366
- this.fishermanEstimatedCost.record(strategyResult.estimatedCostEth, strategyAttributes);
422
+ const costAttributes = {
423
+ ...strategyAttributes,
424
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
425
+ };
426
+ this.fishermanEstimatedCost.record(strategyResult.estimatedCostEth, costAttributes);
367
427
  }
368
428
 
369
429
  // Record estimated overpayment if available
370
430
  if (strategyResult.estimatedOverpaymentEth !== undefined) {
371
- this.fishermanEstimatedOverpayment.record(strategyResult.estimatedOverpaymentEth, strategyAttributes);
431
+ const overpaymentAttributes = {
432
+ ...strategyAttributes,
433
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
434
+ };
435
+ this.fishermanEstimatedOverpayment.record(strategyResult.estimatedOverpaymentEth, overpaymentAttributes);
372
436
  }
373
437
  }
374
438
  }