@aztec/sequencer-client 0.0.1-commit.f2ce05ee → 0.0.1-commit.f5d02921e

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 +345 -172
  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 +21 -5
  44. package/dest/sequencer/metrics.d.ts.map +1 -1
  45. package/dest/sequencer/metrics.js +97 -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 -91
  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 +5 -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 +454 -178
  76. package/src/sequencer/checkpoint_voter.ts +1 -12
  77. package/src/sequencer/events.ts +1 -1
  78. package/src/sequencer/metrics.ts +106 -18
  79. package/src/sequencer/sequencer.ts +208 -107
  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 +5 -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,17 +39,28 @@ 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;
51
57
  private fishermanTimeBeforeBlock: Histogram;
52
58
  private fishermanPendingBlobTxCount: Histogram;
53
59
  private fishermanIncludedBlobTxCount: Histogram;
60
+ private fishermanPendingBlobCount: Histogram;
61
+ private fishermanIncludedBlobCount: Histogram;
62
+ private fishermanBlockBlobsFull: UpDownCounter;
63
+ private fishermanMaxBlobCapacity: Histogram;
54
64
  private fishermanCalculatedPriorityFee: Histogram;
55
65
  private fishermanPriorityFeeDelta: Histogram;
56
66
  private fishermanEstimatedCost: Histogram;
@@ -80,7 +90,7 @@ export class SequencerMetrics {
80
90
 
81
91
  this.checkpointAttestationDelay = this.meter.createHistogram(Metrics.SEQUENCER_CHECKPOINT_ATTESTATION_DELAY);
82
92
 
83
- this.rewards = this.meter.createGauge(Metrics.SEQUENCER_CURRENT_BLOCK_REWARDS);
93
+ this.rewards = this.meter.createGauge(Metrics.SEQUENCER_CURRENT_SLOT_REWARDS);
84
94
 
85
95
  this.slots = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLOT_COUNT);
86
96
 
@@ -103,16 +113,16 @@ export class SequencerMetrics {
103
113
  Metrics.SEQUENCER_BLOCK_PROPOSAL_FAILED_COUNT,
104
114
  );
105
115
 
106
- this.blockProposalSuccess = createUpDownCounterWithDefault(
116
+ this.checkpointProposalSuccess = createUpDownCounterWithDefault(
107
117
  this.meter,
108
- Metrics.SEQUENCER_BLOCK_PROPOSAL_SUCCESS_COUNT,
118
+ Metrics.SEQUENCER_CHECKPOINT_PROPOSAL_SUCCESS_COUNT,
109
119
  );
110
120
 
111
121
  this.checkpointSuccess = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_CHECKPOINT_SUCCESS_COUNT);
112
122
 
113
- this.blockProposalPrecheckFailed = createUpDownCounterWithDefault(
123
+ this.checkpointPrecheckFailed = createUpDownCounterWithDefault(
114
124
  this.meter,
115
- Metrics.SEQUENCER_BLOCK_PROPOSAL_PRECHECK_FAILED_COUNT,
125
+ Metrics.SEQUENCER_CHECKPOINT_PRECHECK_FAILED_COUNT,
116
126
  {
117
127
  [Attributes.ERROR_TYPE]: [
118
128
  'slot_already_taken',
@@ -123,14 +133,29 @@ export class SequencerMetrics {
123
133
  },
124
134
  );
125
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
+
126
146
  this.slashingAttempts = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLASHING_ATTEMPTS_COUNT);
127
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
+
128
152
  // Fisherman fee analysis metrics
129
153
  this.fishermanWouldBeIncluded = createUpDownCounterWithDefault(
130
154
  this.meter,
131
155
  Metrics.FISHERMAN_FEE_ANALYSIS_WOULD_BE_INCLUDED,
132
156
  {
133
157
  [Attributes.OK]: [true, false],
158
+ [Attributes.BLOCK_FULL]: ['true', 'false'],
134
159
  },
135
160
  );
136
161
 
@@ -161,6 +186,20 @@ export class SequencerMetrics {
161
186
  this.fishermanMinedBlobTxTotalCost = this.meter.createHistogram(
162
187
  Metrics.FISHERMAN_FEE_ANALYSIS_MINED_BLOB_TX_TOTAL_COST,
163
188
  );
189
+
190
+ this.fishermanPendingBlobCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_PENDING_BLOB_COUNT);
191
+
192
+ this.fishermanIncludedBlobCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_INCLUDED_BLOB_COUNT);
193
+
194
+ this.fishermanBlockBlobsFull = createUpDownCounterWithDefault(
195
+ this.meter,
196
+ Metrics.FISHERMAN_FEE_ANALYSIS_BLOCK_BLOBS_FULL,
197
+ {
198
+ [Attributes.OK]: [true, false],
199
+ },
200
+ );
201
+
202
+ this.fishermanMaxBlobCapacity = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_MAX_BLOB_CAPACITY);
164
203
  }
165
204
 
166
205
  public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
@@ -201,6 +240,14 @@ export class SequencerMetrics {
201
240
  });
202
241
  }
203
242
 
243
+ recordPipelineDepth(depth: number) {
244
+ this.pipelineDepth.record(depth);
245
+ }
246
+
247
+ recordPipelineDiscard(count = 1) {
248
+ this.pipelineDiscards.add(count);
249
+ }
250
+
204
251
  incOpenSlot(slot: SlotNumber, proposer: string) {
205
252
  // sequencer went through the loop a second time. Noop
206
253
  if (slot === this.lastSeenSlot) {
@@ -243,18 +290,30 @@ export class SequencerMetrics {
243
290
  });
244
291
  }
245
292
 
246
- recordBlockProposalSuccess() {
247
- this.blockProposalSuccess.add(1);
293
+ recordCheckpointProposalSuccess() {
294
+ this.checkpointProposalSuccess.add(1);
248
295
  }
249
296
 
250
- recordBlockProposalPrecheckFailed(
297
+ recordCheckpointPrecheckFailed(
251
298
  checkType: 'slot_already_taken' | 'rollup_contract_check_failed' | 'slot_mismatch' | 'block_number_mismatch',
252
299
  ) {
253
- this.blockProposalPrecheckFailed.add(1, {
254
- [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 }),
255
306
  });
256
307
  }
257
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
+
258
317
  recordSlashingAttempt(actionCount: number) {
259
318
  this.slashingAttempts.add(actionCount);
260
319
  }
@@ -281,10 +340,12 @@ export class SequencerMetrics {
281
340
 
282
341
  // Record pending block snapshot data (once per strategy for comparison)
283
342
  this.fishermanPendingBlobTxCount.record(analysis.pendingSnapshot.pendingBlobTxCount, strategyAttributes);
343
+ this.fishermanPendingBlobCount.record(analysis.pendingSnapshot.pendingBlobCount, strategyAttributes);
284
344
 
285
345
  // Record mined block data if available
286
346
  if (analysis.minedBlock) {
287
347
  this.fishermanIncludedBlobTxCount.record(analysis.minedBlock.includedBlobTxCount, strategyAttributes);
348
+ this.fishermanIncludedBlobCount.record(analysis.minedBlock.includedBlobCount, strategyAttributes);
288
349
 
289
350
  // Record actual fees from blob transactions in the mined block
290
351
  for (const blobTx of analysis.minedBlock.includedBlobTxs) {
@@ -318,13 +379,28 @@ export class SequencerMetrics {
318
379
  if (analysis.analysis) {
319
380
  this.fishermanTimeBeforeBlock.record(Math.ceil(analysis.analysis.timeBeforeBlockMs), strategyAttributes);
320
381
 
382
+ // Record whether the block reached 100% blob capacity
383
+ if (analysis.analysis.blockBlobsFull) {
384
+ this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: true });
385
+ } else {
386
+ this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: false });
387
+ }
388
+
389
+ // Record the max blob capacity for this block
390
+ this.fishermanMaxBlobCapacity.record(analysis.analysis.maxBlobCapacity, strategyAttributes);
391
+
321
392
  // Record strategy-specific inclusion result
322
393
  if (strategyResult.wouldBeIncluded !== undefined) {
394
+ const inclusionAttributes = {
395
+ ...strategyAttributes,
396
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
397
+ };
398
+
323
399
  if (strategyResult.wouldBeIncluded) {
324
- this.fishermanWouldBeIncluded.add(1, { ...strategyAttributes, [Attributes.OK]: true });
400
+ this.fishermanWouldBeIncluded.add(1, { ...inclusionAttributes, [Attributes.OK]: true });
325
401
  } else {
326
402
  this.fishermanWouldBeIncluded.add(1, {
327
- ...strategyAttributes,
403
+ ...inclusionAttributes,
328
404
  [Attributes.OK]: false,
329
405
  ...(strategyResult.exclusionReason && { [Attributes.ERROR_TYPE]: strategyResult.exclusionReason }),
330
406
  });
@@ -334,17 +410,29 @@ export class SequencerMetrics {
334
410
  // Record strategy-specific priority fee delta
335
411
  if (strategyResult.priorityFeeDelta !== undefined) {
336
412
  const priorityFeeDeltaGwei = Number(strategyResult.priorityFeeDelta) / 1e9;
337
- 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);
338
418
  }
339
419
 
340
420
  // Record estimated cost if available
341
421
  if (strategyResult.estimatedCostEth !== undefined) {
342
- 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);
343
427
  }
344
428
 
345
429
  // Record estimated overpayment if available
346
430
  if (strategyResult.estimatedOverpaymentEth !== undefined) {
347
- 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);
348
436
  }
349
437
  }
350
438
  }