@aztec/sequencer-client 0.0.1-commit.1bea0213 → 0.0.1-commit.21ecf947b

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 (39) hide show
  1. package/dest/client/sequencer-client.js +1 -1
  2. package/dest/config.d.ts +1 -2
  3. package/dest/config.d.ts.map +1 -1
  4. package/dest/config.js +4 -8
  5. package/dest/publisher/sequencer-publisher-metrics.d.ts +1 -1
  6. package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
  7. package/dest/publisher/sequencer-publisher-metrics.js +12 -4
  8. package/dest/publisher/sequencer-publisher.d.ts +8 -2
  9. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  10. package/dest/publisher/sequencer-publisher.js +53 -23
  11. package/dest/sequencer/checkpoint_proposal_job.d.ts +32 -9
  12. package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
  13. package/dest/sequencer/checkpoint_proposal_job.js +79 -51
  14. package/dest/sequencer/metrics.d.ts +6 -2
  15. package/dest/sequencer/metrics.d.ts.map +1 -1
  16. package/dest/sequencer/metrics.js +81 -22
  17. package/dest/sequencer/sequencer.d.ts +3 -1
  18. package/dest/sequencer/sequencer.d.ts.map +1 -1
  19. package/dest/sequencer/sequencer.js +7 -2
  20. package/dest/sequencer/timetable.d.ts +1 -4
  21. package/dest/sequencer/timetable.d.ts.map +1 -1
  22. package/dest/sequencer/timetable.js +1 -4
  23. package/dest/test/mock_checkpoint_builder.d.ts +7 -5
  24. package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
  25. package/dest/test/mock_checkpoint_builder.js +6 -6
  26. package/dest/test/utils.d.ts +3 -3
  27. package/dest/test/utils.d.ts.map +1 -1
  28. package/dest/test/utils.js +5 -4
  29. package/package.json +28 -28
  30. package/src/client/sequencer-client.ts +1 -1
  31. package/src/config.ts +9 -11
  32. package/src/publisher/sequencer-publisher-metrics.ts +7 -3
  33. package/src/publisher/sequencer-publisher.ts +60 -22
  34. package/src/sequencer/checkpoint_proposal_job.ts +104 -67
  35. package/src/sequencer/metrics.ts +89 -23
  36. package/src/sequencer/sequencer.ts +9 -2
  37. package/src/sequencer/timetable.ts +6 -5
  38. package/src/test/mock_checkpoint_builder.ts +14 -5
  39. package/src/test/utils.ts +5 -2
@@ -11,6 +11,7 @@ import {
11
11
  type TelemetryClient,
12
12
  type Tracer,
13
13
  type UpDownCounter,
14
+ createUpDownCounterWithDefault,
14
15
  } from '@aztec/telemetry-client';
15
16
 
16
17
  import { type Hex, formatUnits } from 'viem';
@@ -50,6 +51,10 @@ export class SequencerMetrics {
50
51
  private fishermanTimeBeforeBlock: Histogram;
51
52
  private fishermanPendingBlobTxCount: Histogram;
52
53
  private fishermanIncludedBlobTxCount: Histogram;
54
+ private fishermanPendingBlobCount: Histogram;
55
+ private fishermanIncludedBlobCount: Histogram;
56
+ private fishermanBlockBlobsFull: UpDownCounter;
57
+ private fishermanMaxBlobCapacity: Histogram;
53
58
  private fishermanCalculatedPriorityFee: Histogram;
54
59
  private fishermanPriorityFeeDelta: Histogram;
55
60
  private fishermanEstimatedCost: Histogram;
@@ -67,7 +72,9 @@ export class SequencerMetrics {
67
72
  this.meter = client.getMeter(name);
68
73
  this.tracer = client.getTracer(name);
69
74
 
70
- this.blockCounter = this.meter.createUpDownCounter(Metrics.SEQUENCER_BLOCK_COUNT);
75
+ this.blockCounter = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_BLOCK_COUNT, {
76
+ [Attributes.STATUS]: ['failed', 'built'],
77
+ });
71
78
 
72
79
  this.blockBuildDuration = this.meter.createHistogram(Metrics.SEQUENCER_BLOCK_BUILD_DURATION);
73
80
 
@@ -77,23 +84,15 @@ export class SequencerMetrics {
77
84
 
78
85
  this.checkpointAttestationDelay = this.meter.createHistogram(Metrics.SEQUENCER_CHECKPOINT_ATTESTATION_DELAY);
79
86
 
80
- // Init gauges and counters
81
- this.blockCounter.add(0, {
82
- [Attributes.STATUS]: 'failed',
83
- });
84
- this.blockCounter.add(0, {
85
- [Attributes.STATUS]: 'built',
86
- });
87
-
88
87
  this.rewards = this.meter.createGauge(Metrics.SEQUENCER_CURRENT_BLOCK_REWARDS);
89
88
 
90
- this.slots = this.meter.createUpDownCounter(Metrics.SEQUENCER_SLOT_COUNT);
89
+ this.slots = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLOT_COUNT);
91
90
 
92
91
  /**
93
92
  * NOTE: we do not track missed slots as a separate metric. That would be difficult to determine
94
93
  * Instead, use a computed metric, `slots - filledSlots` to get the number of slots a sequencer has missed.
95
94
  */
96
- this.filledSlots = this.meter.createUpDownCounter(Metrics.SEQUENCER_FILLED_SLOT_COUNT);
95
+ this.filledSlots = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_FILLED_SLOT_COUNT);
97
96
 
98
97
  this.timeToCollectAttestations = this.meter.createGauge(Metrics.SEQUENCER_COLLECT_ATTESTATIONS_DURATION);
99
98
 
@@ -103,20 +102,42 @@ export class SequencerMetrics {
103
102
 
104
103
  this.collectedAttestions = this.meter.createGauge(Metrics.SEQUENCER_COLLECTED_ATTESTATIONS_COUNT);
105
104
 
106
- this.blockProposalFailed = this.meter.createUpDownCounter(Metrics.SEQUENCER_BLOCK_PROPOSAL_FAILED_COUNT);
105
+ this.blockProposalFailed = createUpDownCounterWithDefault(
106
+ this.meter,
107
+ Metrics.SEQUENCER_BLOCK_PROPOSAL_FAILED_COUNT,
108
+ );
107
109
 
108
- this.blockProposalSuccess = this.meter.createUpDownCounter(Metrics.SEQUENCER_BLOCK_PROPOSAL_SUCCESS_COUNT);
110
+ this.blockProposalSuccess = createUpDownCounterWithDefault(
111
+ this.meter,
112
+ Metrics.SEQUENCER_BLOCK_PROPOSAL_SUCCESS_COUNT,
113
+ );
109
114
 
110
- this.checkpointSuccess = this.meter.createUpDownCounter(Metrics.SEQUENCER_CHECKPOINT_SUCCESS_COUNT);
115
+ this.checkpointSuccess = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_CHECKPOINT_SUCCESS_COUNT);
111
116
 
112
- this.blockProposalPrecheckFailed = this.meter.createUpDownCounter(
117
+ this.blockProposalPrecheckFailed = createUpDownCounterWithDefault(
118
+ this.meter,
113
119
  Metrics.SEQUENCER_BLOCK_PROPOSAL_PRECHECK_FAILED_COUNT,
120
+ {
121
+ [Attributes.ERROR_TYPE]: [
122
+ 'slot_already_taken',
123
+ 'rollup_contract_check_failed',
124
+ 'slot_mismatch',
125
+ 'block_number_mismatch',
126
+ ],
127
+ },
114
128
  );
115
129
 
116
- this.slashingAttempts = this.meter.createUpDownCounter(Metrics.SEQUENCER_SLASHING_ATTEMPTS_COUNT);
130
+ this.slashingAttempts = createUpDownCounterWithDefault(this.meter, Metrics.SEQUENCER_SLASHING_ATTEMPTS_COUNT);
117
131
 
118
132
  // Fisherman fee analysis metrics
119
- this.fishermanWouldBeIncluded = this.meter.createUpDownCounter(Metrics.FISHERMAN_FEE_ANALYSIS_WOULD_BE_INCLUDED);
133
+ this.fishermanWouldBeIncluded = createUpDownCounterWithDefault(
134
+ this.meter,
135
+ Metrics.FISHERMAN_FEE_ANALYSIS_WOULD_BE_INCLUDED,
136
+ {
137
+ [Attributes.OK]: [true, false],
138
+ [Attributes.BLOCK_FULL]: ['true', 'false'],
139
+ },
140
+ );
120
141
 
121
142
  this.fishermanTimeBeforeBlock = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_TIME_BEFORE_BLOCK);
122
143
 
@@ -145,6 +166,20 @@ export class SequencerMetrics {
145
166
  this.fishermanMinedBlobTxTotalCost = this.meter.createHistogram(
146
167
  Metrics.FISHERMAN_FEE_ANALYSIS_MINED_BLOB_TX_TOTAL_COST,
147
168
  );
169
+
170
+ this.fishermanPendingBlobCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_PENDING_BLOB_COUNT);
171
+
172
+ this.fishermanIncludedBlobCount = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_INCLUDED_BLOB_COUNT);
173
+
174
+ this.fishermanBlockBlobsFull = createUpDownCounterWithDefault(
175
+ this.meter,
176
+ Metrics.FISHERMAN_FEE_ANALYSIS_BLOCK_BLOBS_FULL,
177
+ {
178
+ [Attributes.OK]: [true, false],
179
+ },
180
+ );
181
+
182
+ this.fishermanMaxBlobCapacity = this.meter.createHistogram(Metrics.FISHERMAN_FEE_ANALYSIS_MAX_BLOB_CAPACITY);
148
183
  }
149
184
 
150
185
  public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
@@ -231,7 +266,9 @@ export class SequencerMetrics {
231
266
  this.blockProposalSuccess.add(1);
232
267
  }
233
268
 
234
- recordBlockProposalPrecheckFailed(checkType: string) {
269
+ recordBlockProposalPrecheckFailed(
270
+ checkType: 'slot_already_taken' | 'rollup_contract_check_failed' | 'slot_mismatch' | 'block_number_mismatch',
271
+ ) {
235
272
  this.blockProposalPrecheckFailed.add(1, {
236
273
  [Attributes.ERROR_TYPE]: checkType,
237
274
  });
@@ -263,10 +300,12 @@ export class SequencerMetrics {
263
300
 
264
301
  // Record pending block snapshot data (once per strategy for comparison)
265
302
  this.fishermanPendingBlobTxCount.record(analysis.pendingSnapshot.pendingBlobTxCount, strategyAttributes);
303
+ this.fishermanPendingBlobCount.record(analysis.pendingSnapshot.pendingBlobCount, strategyAttributes);
266
304
 
267
305
  // Record mined block data if available
268
306
  if (analysis.minedBlock) {
269
307
  this.fishermanIncludedBlobTxCount.record(analysis.minedBlock.includedBlobTxCount, strategyAttributes);
308
+ this.fishermanIncludedBlobCount.record(analysis.minedBlock.includedBlobCount, strategyAttributes);
270
309
 
271
310
  // Record actual fees from blob transactions in the mined block
272
311
  for (const blobTx of analysis.minedBlock.includedBlobTxs) {
@@ -300,13 +339,28 @@ export class SequencerMetrics {
300
339
  if (analysis.analysis) {
301
340
  this.fishermanTimeBeforeBlock.record(Math.ceil(analysis.analysis.timeBeforeBlockMs), strategyAttributes);
302
341
 
342
+ // Record whether the block reached 100% blob capacity
343
+ if (analysis.analysis.blockBlobsFull) {
344
+ this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: true });
345
+ } else {
346
+ this.fishermanBlockBlobsFull.add(1, { ...strategyAttributes, [Attributes.OK]: false });
347
+ }
348
+
349
+ // Record the max blob capacity for this block
350
+ this.fishermanMaxBlobCapacity.record(analysis.analysis.maxBlobCapacity, strategyAttributes);
351
+
303
352
  // Record strategy-specific inclusion result
304
353
  if (strategyResult.wouldBeIncluded !== undefined) {
354
+ const inclusionAttributes = {
355
+ ...strategyAttributes,
356
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
357
+ };
358
+
305
359
  if (strategyResult.wouldBeIncluded) {
306
- this.fishermanWouldBeIncluded.add(1, { ...strategyAttributes, [Attributes.OK]: true });
360
+ this.fishermanWouldBeIncluded.add(1, { ...inclusionAttributes, [Attributes.OK]: true });
307
361
  } else {
308
362
  this.fishermanWouldBeIncluded.add(1, {
309
- ...strategyAttributes,
363
+ ...inclusionAttributes,
310
364
  [Attributes.OK]: false,
311
365
  ...(strategyResult.exclusionReason && { [Attributes.ERROR_TYPE]: strategyResult.exclusionReason }),
312
366
  });
@@ -316,17 +370,29 @@ export class SequencerMetrics {
316
370
  // Record strategy-specific priority fee delta
317
371
  if (strategyResult.priorityFeeDelta !== undefined) {
318
372
  const priorityFeeDeltaGwei = Number(strategyResult.priorityFeeDelta) / 1e9;
319
- this.fishermanPriorityFeeDelta.record(priorityFeeDeltaGwei, strategyAttributes);
373
+ const deltaAttributes = {
374
+ ...strategyAttributes,
375
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
376
+ };
377
+ this.fishermanPriorityFeeDelta.record(priorityFeeDeltaGwei, deltaAttributes);
320
378
  }
321
379
 
322
380
  // Record estimated cost if available
323
381
  if (strategyResult.estimatedCostEth !== undefined) {
324
- this.fishermanEstimatedCost.record(strategyResult.estimatedCostEth, strategyAttributes);
382
+ const costAttributes = {
383
+ ...strategyAttributes,
384
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
385
+ };
386
+ this.fishermanEstimatedCost.record(strategyResult.estimatedCostEth, costAttributes);
325
387
  }
326
388
 
327
389
  // Record estimated overpayment if available
328
390
  if (strategyResult.estimatedOverpaymentEth !== undefined) {
329
- this.fishermanEstimatedOverpayment.record(strategyResult.estimatedOverpaymentEth, strategyAttributes);
391
+ const overpaymentAttributes = {
392
+ ...strategyAttributes,
393
+ [Attributes.BLOCK_FULL]: analysis.analysis.blockBlobsFull ? 'true' : 'false',
394
+ };
395
+ this.fishermanEstimatedOverpayment.record(strategyResult.estimatedOverpaymentEth, overpaymentAttributes);
330
396
  }
331
397
  }
332
398
  }
@@ -60,6 +60,9 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
60
60
  /** The last slot for which we attempted to perform our voting duties with degraded block production */
61
61
  private lastSlotForFallbackVote: SlotNumber | undefined;
62
62
 
63
+ /** The last slot for which we logged "no committee" warning, to avoid spam */
64
+ private lastSlotForNoCommitteeWarning: SlotNumber | undefined;
65
+
63
66
  /** The last slot for which we triggered a checkpoint proposal job, to prevent duplicate attempts. */
64
67
  private lastSlotForCheckpointProposalJob: SlotNumber | undefined;
65
68
 
@@ -373,6 +376,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
373
376
  }
374
377
 
375
378
  this.lastSlotForCheckpointProposalJob = slot;
379
+ await this.p2pClient.prepareForSlot(slot);
376
380
  this.log.info(`Preparing checkpoint proposal ${checkpointNumber} at slot ${slot}`, { ...logCtx, proposer });
377
381
 
378
382
  // Create and return the checkpoint proposal job
@@ -424,8 +428,8 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
424
428
  this.metrics,
425
429
  this,
426
430
  this.setState.bind(this),
427
- this.log,
428
431
  this.tracer,
432
+ this.log.getBindings(),
429
433
  );
430
434
  }
431
435
 
@@ -557,7 +561,10 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
557
561
  proposer = await this.epochCache.getProposerAttesterAddressInSlot(slot);
558
562
  } catch (e) {
559
563
  if (e instanceof NoCommitteeError) {
560
- this.log.warn(`Cannot propose at next L2 slot ${slot} since the committee does not exist on L1`);
564
+ if (this.lastSlotForNoCommitteeWarning !== slot) {
565
+ this.lastSlotForNoCommitteeWarning = slot;
566
+ this.log.warn(`Cannot propose at next L2 slot ${slot} since the committee does not exist on L1`);
567
+ }
561
568
  return [false, undefined];
562
569
  }
563
570
  this.log.error(`Error getting proposer for slot ${slot}`, e);
@@ -1,14 +1,15 @@
1
1
  import { createLogger } from '@aztec/aztec.js/log';
2
+ import {
3
+ CHECKPOINT_ASSEMBLE_TIME,
4
+ CHECKPOINT_INITIALIZATION_TIME,
5
+ DEFAULT_P2P_PROPAGATION_TIME,
6
+ MIN_EXECUTION_TIME,
7
+ } from '@aztec/stdlib/timetable';
2
8
 
3
- import { DEFAULT_ATTESTATION_PROPAGATION_TIME as DEFAULT_P2P_PROPAGATION_TIME } from '../config.js';
4
9
  import { SequencerTooSlowError } from './errors.js';
5
10
  import type { SequencerMetrics } from './metrics.js';
6
11
  import { SequencerState } from './utils.js';
7
12
 
8
- export const MIN_EXECUTION_TIME = 2;
9
- export const CHECKPOINT_INITIALIZATION_TIME = 1;
10
- export const CHECKPOINT_ASSEMBLE_TIME = 1;
11
-
12
13
  export class SequencerTimetable {
13
14
  /**
14
15
  * How late into the slot can we be to start working. Computed as the total time needed for assembling and publishing a block,
@@ -1,6 +1,5 @@
1
1
  import { type BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
2
2
  import { Fr } from '@aztec/foundation/curves/bn254';
3
- import { Timer } from '@aztec/foundation/timer';
4
3
  import { L2Block } from '@aztec/stdlib/block';
5
4
  import { Checkpoint } from '@aztec/stdlib/checkpoint';
6
5
  import { Gas } from '@aztec/stdlib/gas';
@@ -14,7 +13,7 @@ import type {
14
13
  import { CheckpointHeader } from '@aztec/stdlib/rollup';
15
14
  import { makeAppendOnlyTreeSnapshot } from '@aztec/stdlib/testing';
16
15
  import type { CheckpointGlobalVariables, Tx } from '@aztec/stdlib/tx';
17
- import type { BuildBlockInCheckpointResultWithTimer } from '@aztec/validator-client';
16
+ import type { BuildBlockInCheckpointResult } from '@aztec/validator-client';
18
17
 
19
18
  /**
20
19
  * A fake CheckpointBuilder for testing that implements the same interface as the real one.
@@ -76,7 +75,7 @@ export class MockCheckpointBuilder implements ICheckpointBlockBuilder {
76
75
  blockNumber: BlockNumber,
77
76
  timestamp: bigint,
78
77
  opts: PublicProcessorLimits,
79
- ): Promise<BuildBlockInCheckpointResultWithTimer> {
78
+ ): Promise<BuildBlockInCheckpointResult> {
80
79
  this.buildBlockCalls.push({ blockNumber, timestamp, opts });
81
80
 
82
81
  if (this.errorOnBuild) {
@@ -117,7 +116,6 @@ export class MockCheckpointBuilder implements ICheckpointBlockBuilder {
117
116
  publicGas: Gas.empty(),
118
117
  publicProcessorDuration: 0,
119
118
  numTxs: block?.body?.txEffects?.length ?? usedTxs.length,
120
- blockBuildingTimer: new Timer(),
121
119
  usedTxs,
122
120
  failedTxs: [],
123
121
  usedTxBlobFields: block?.body?.txEffects?.reduce((sum, tx) => sum + tx.getNumBlobFields(), 0) ?? 0,
@@ -207,6 +205,7 @@ export class MockCheckpointsBuilder implements ICheckpointsBuilder {
207
205
  constants: CheckpointGlobalVariables;
208
206
  l1ToL2Messages: Fr[];
209
207
  previousCheckpointOutHashes: Fr[];
208
+ feeAssetPriceModifier: bigint;
210
209
  }> = [];
211
210
  public openCheckpointCalls: Array<{
212
211
  checkpointNumber: CheckpointNumber;
@@ -214,6 +213,7 @@ export class MockCheckpointsBuilder implements ICheckpointsBuilder {
214
213
  l1ToL2Messages: Fr[];
215
214
  previousCheckpointOutHashes: Fr[];
216
215
  existingBlocks: L2Block[];
216
+ feeAssetPriceModifier: bigint;
217
217
  }> = [];
218
218
  public updateConfigCalls: Array<Partial<FullNodeBlockBuilderConfig>> = [];
219
219
 
@@ -259,11 +259,18 @@ export class MockCheckpointsBuilder implements ICheckpointsBuilder {
259
259
  startCheckpoint(
260
260
  checkpointNumber: CheckpointNumber,
261
261
  constants: CheckpointGlobalVariables,
262
+ feeAssetPriceModifier: bigint,
262
263
  l1ToL2Messages: Fr[],
263
264
  previousCheckpointOutHashes: Fr[],
264
265
  _fork: MerkleTreeWriteOperations,
265
266
  ): Promise<ICheckpointBlockBuilder> {
266
- this.startCheckpointCalls.push({ checkpointNumber, constants, l1ToL2Messages, previousCheckpointOutHashes });
267
+ this.startCheckpointCalls.push({
268
+ checkpointNumber,
269
+ constants,
270
+ l1ToL2Messages,
271
+ previousCheckpointOutHashes,
272
+ feeAssetPriceModifier,
273
+ });
267
274
 
268
275
  if (!this.checkpointBuilder) {
269
276
  // Auto-create a builder if none was set
@@ -276,6 +283,7 @@ export class MockCheckpointsBuilder implements ICheckpointsBuilder {
276
283
  openCheckpoint(
277
284
  checkpointNumber: CheckpointNumber,
278
285
  constants: CheckpointGlobalVariables,
286
+ feeAssetPriceModifier: bigint,
279
287
  l1ToL2Messages: Fr[],
280
288
  previousCheckpointOutHashes: Fr[],
281
289
  _fork: MerkleTreeWriteOperations,
@@ -287,6 +295,7 @@ export class MockCheckpointsBuilder implements ICheckpointsBuilder {
287
295
  l1ToL2Messages,
288
296
  previousCheckpointOutHashes,
289
297
  existingBlocks,
298
+ feeAssetPriceModifier,
290
299
  });
291
300
 
292
301
  if (!this.checkpointBuilder) {
package/src/test/utils.ts CHANGED
@@ -56,6 +56,7 @@ export async function makeBlock(txs: Tx[], globalVariables: GlobalVariables): Pr
56
56
  export function mockPendingTxs(p2p: MockProxy<P2P>, txs: Tx[]): void {
57
57
  p2p.getPendingTxCount.mockResolvedValue(txs.length);
58
58
  p2p.iteratePendingTxs.mockImplementation(() => mockTxIterator(Promise.resolve(txs)));
59
+ p2p.iterateEligiblePendingTxs.mockImplementation(() => mockTxIterator(Promise.resolve(txs)));
59
60
  }
60
61
 
61
62
  /**
@@ -118,10 +119,11 @@ export function createCheckpointProposal(
118
119
  block: L2Block,
119
120
  checkpointSignature: Signature,
120
121
  blockSignature?: Signature,
122
+ feeAssetPriceModifier: bigint = 0n,
121
123
  ): CheckpointProposal {
122
124
  const txHashes = block.body.txEffects.map(tx => tx.txHash);
123
125
  const checkpointHeader = createCheckpointHeaderFromBlock(block);
124
- return new CheckpointProposal(checkpointHeader, block.archive.root, checkpointSignature, {
126
+ return new CheckpointProposal(checkpointHeader, block.archive.root, feeAssetPriceModifier, checkpointSignature, {
125
127
  blockHeader: block.header,
126
128
  indexWithinCheckpoint: block.indexWithinCheckpoint,
127
129
  txHashes,
@@ -138,9 +140,10 @@ export function createCheckpointAttestation(
138
140
  block: L2Block,
139
141
  signature: Signature,
140
142
  sender: EthAddress,
143
+ feeAssetPriceModifier: bigint = 0n,
141
144
  ): CheckpointAttestation {
142
145
  const checkpointHeader = createCheckpointHeaderFromBlock(block);
143
- const payload = new ConsensusPayload(checkpointHeader, block.archive.root);
146
+ const payload = new ConsensusPayload(checkpointHeader, block.archive.root, feeAssetPriceModifier);
144
147
  const attestation = new CheckpointAttestation(payload, signature, signature);
145
148
  // Set sender directly for testing (bypasses signature recovery)
146
149
  (attestation as any).sender = sender;