@aztec/sequencer-client 3.0.0-rc.5 → 4.0.0-nightly.20260107

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 (88) hide show
  1. package/dest/client/sequencer-client.d.ts +9 -8
  2. package/dest/client/sequencer-client.d.ts.map +1 -1
  3. package/dest/client/sequencer-client.js +28 -24
  4. package/dest/config.d.ts +7 -1
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +63 -26
  7. package/dest/global_variable_builder/global_builder.d.ts +16 -8
  8. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  9. package/dest/global_variable_builder/global_builder.js +37 -28
  10. package/dest/index.d.ts +2 -2
  11. package/dest/index.d.ts.map +1 -1
  12. package/dest/index.js +1 -1
  13. package/dest/publisher/config.d.ts +3 -3
  14. package/dest/publisher/config.d.ts.map +1 -1
  15. package/dest/publisher/config.js +2 -2
  16. package/dest/publisher/sequencer-publisher-factory.d.ts +3 -3
  17. package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
  18. package/dest/publisher/sequencer-publisher-factory.js +1 -1
  19. package/dest/publisher/sequencer-publisher-metrics.d.ts +3 -3
  20. package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
  21. package/dest/publisher/sequencer-publisher.d.ts +27 -23
  22. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  23. package/dest/publisher/sequencer-publisher.js +119 -64
  24. package/dest/sequencer/block_builder.d.ts +1 -3
  25. package/dest/sequencer/block_builder.d.ts.map +1 -1
  26. package/dest/sequencer/block_builder.js +4 -2
  27. package/dest/sequencer/checkpoint_builder.d.ts +63 -0
  28. package/dest/sequencer/checkpoint_builder.d.ts.map +1 -0
  29. package/dest/sequencer/checkpoint_builder.js +131 -0
  30. package/dest/sequencer/checkpoint_proposal_job.d.ts +74 -0
  31. package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -0
  32. package/dest/sequencer/checkpoint_proposal_job.js +642 -0
  33. package/dest/sequencer/checkpoint_voter.d.ts +34 -0
  34. package/dest/sequencer/checkpoint_voter.d.ts.map +1 -0
  35. package/dest/sequencer/checkpoint_voter.js +85 -0
  36. package/dest/sequencer/events.d.ts +46 -0
  37. package/dest/sequencer/events.d.ts.map +1 -0
  38. package/dest/sequencer/events.js +1 -0
  39. package/dest/sequencer/index.d.ts +5 -1
  40. package/dest/sequencer/index.d.ts.map +1 -1
  41. package/dest/sequencer/index.js +4 -0
  42. package/dest/sequencer/metrics.d.ts +21 -1
  43. package/dest/sequencer/metrics.d.ts.map +1 -1
  44. package/dest/sequencer/metrics.js +154 -0
  45. package/dest/sequencer/sequencer.d.ts +91 -125
  46. package/dest/sequencer/sequencer.d.ts.map +1 -1
  47. package/dest/sequencer/sequencer.js +581 -582
  48. package/dest/sequencer/timetable.d.ts +54 -14
  49. package/dest/sequencer/timetable.d.ts.map +1 -1
  50. package/dest/sequencer/timetable.js +148 -59
  51. package/dest/sequencer/types.d.ts +3 -0
  52. package/dest/sequencer/types.d.ts.map +1 -0
  53. package/dest/sequencer/types.js +1 -0
  54. package/dest/sequencer/utils.d.ts +14 -8
  55. package/dest/sequencer/utils.d.ts.map +1 -1
  56. package/dest/sequencer/utils.js +7 -4
  57. package/dest/test/index.d.ts +3 -1
  58. package/dest/test/index.d.ts.map +1 -1
  59. package/dest/test/mock_checkpoint_builder.d.ts +83 -0
  60. package/dest/test/mock_checkpoint_builder.d.ts.map +1 -0
  61. package/dest/test/mock_checkpoint_builder.js +179 -0
  62. package/dest/test/utils.d.ts +49 -0
  63. package/dest/test/utils.d.ts.map +1 -0
  64. package/dest/test/utils.js +94 -0
  65. package/package.json +27 -27
  66. package/src/client/sequencer-client.ts +24 -31
  67. package/src/config.ts +68 -25
  68. package/src/global_variable_builder/global_builder.ts +47 -41
  69. package/src/index.ts +2 -0
  70. package/src/publisher/config.ts +3 -3
  71. package/src/publisher/sequencer-publisher-factory.ts +3 -3
  72. package/src/publisher/sequencer-publisher-metrics.ts +2 -2
  73. package/src/publisher/sequencer-publisher.ts +170 -74
  74. package/src/sequencer/README.md +531 -0
  75. package/src/sequencer/block_builder.ts +4 -1
  76. package/src/sequencer/checkpoint_builder.ts +217 -0
  77. package/src/sequencer/checkpoint_proposal_job.ts +706 -0
  78. package/src/sequencer/checkpoint_voter.ts +105 -0
  79. package/src/sequencer/events.ts +27 -0
  80. package/src/sequencer/index.ts +4 -0
  81. package/src/sequencer/metrics.ts +202 -0
  82. package/src/sequencer/sequencer.ts +300 -779
  83. package/src/sequencer/timetable.ts +173 -79
  84. package/src/sequencer/types.ts +6 -0
  85. package/src/sequencer/utils.ts +18 -9
  86. package/src/test/index.ts +2 -0
  87. package/src/test/mock_checkpoint_builder.ts +247 -0
  88. package/src/test/utils.ts +137 -0
@@ -1,11 +1,12 @@
1
1
  import { Blob, getBlobsPerL1Block, getPrefixedEthBlobCommitments } from '@aztec/blob-lib';
2
- import { createBlobSinkClient } from '@aztec/blob-sink/client';
3
2
  import { MULTI_CALL_3_ADDRESS, Multicall3, RollupContract } from '@aztec/ethereum/contracts';
3
+ import { L1FeeAnalyzer } from '@aztec/ethereum/l1-fee-analysis';
4
4
  import { WEI_CONST } from '@aztec/ethereum/l1-tx-utils';
5
5
  import { FormattedViemError, formatViemError, tryExtractEvent } from '@aztec/ethereum/utils';
6
6
  import { sumBigint } from '@aztec/foundation/bigint';
7
7
  import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
8
8
  import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
9
+ import { pick } from '@aztec/foundation/collection';
9
10
  import { EthAddress } from '@aztec/foundation/eth-address';
10
11
  import { Signature } from '@aztec/foundation/eth-signature';
11
12
  import { createLogger } from '@aztec/foundation/log';
@@ -13,7 +14,7 @@ import { bufferToHex } from '@aztec/foundation/string';
13
14
  import { Timer } from '@aztec/foundation/timer';
14
15
  import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
15
16
  import { encodeSlashConsensusVotes } from '@aztec/slasher';
16
- import { CommitteeAttestation, CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
17
+ import { CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
17
18
  import { getTelemetryClient } from '@aztec/telemetry-client';
18
19
  import { encodeFunctionData, toHex } from 'viem';
19
20
  import { SequencerPublisherMetrics } from './sequencer-publisher-metrics.js';
@@ -38,10 +39,12 @@ export class SequencerPublisher {
38
39
  governanceLog;
39
40
  slashingLog;
40
41
  lastActions;
42
+ isPayloadEmptyCache;
41
43
  log;
42
44
  ethereumSlotDuration;
43
- blobSinkClient;
45
+ blobClient;
44
46
  /** Address to use for simulations in fisherman mode (actual proposer's address) */ proposerAddressForSimulation;
47
+ /** L1 fee analyzer for fisherman mode */ l1FeeAnalyzer;
45
48
  // @note - with blobs, the below estimate seems too large.
46
49
  // Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
47
50
  // Total used for emptier block from above test: 429k (of which 84k is 1x blob)
@@ -62,14 +65,13 @@ export class SequencerPublisher {
62
65
  this.governanceLog = createLogger('sequencer:publisher:governance');
63
66
  this.slashingLog = createLogger('sequencer:publisher:slashing');
64
67
  this.lastActions = {};
68
+ this.isPayloadEmptyCache = new Map();
65
69
  this.requests = [];
66
70
  this.log = deps.log ?? createLogger('sequencer:publisher');
67
71
  this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
68
72
  this.epochCache = deps.epochCache;
69
73
  this.lastActions = deps.lastActions;
70
- this.blobSinkClient = deps.blobSinkClient ?? createBlobSinkClient(config, {
71
- logger: createLogger('sequencer:blob-sink:client')
72
- });
74
+ this.blobClient = deps.blobClient;
73
75
  const telemetry = deps.telemetry ?? getTelemetryClient();
74
76
  this.metrics = deps.metrics ?? new SequencerPublisherMetrics(telemetry, 'SequencerPublisher');
75
77
  this.l1TxUtils = deps.l1TxUtils;
@@ -82,6 +84,10 @@ export class SequencerPublisher {
82
84
  this.slashingProposerContract = newSlashingProposer;
83
85
  });
84
86
  this.slashFactoryContract = deps.slashFactoryContract;
87
+ // Initialize L1 fee analyzer for fisherman mode
88
+ if (config.fishermanMode) {
89
+ this.l1FeeAnalyzer = new L1FeeAnalyzer(this.l1TxUtils.client, deps.dateProvider, createLogger('sequencer:publisher:fee-analyzer'));
90
+ }
85
91
  }
86
92
  getRollupContract() {
87
93
  return this.rollupContract;
@@ -90,6 +96,11 @@ export class SequencerPublisher {
90
96
  return this.l1TxUtils.getSenderAddress();
91
97
  }
92
98
  /**
99
+ * Gets the L1 fee analyzer instance (only available in fisherman mode)
100
+ */ getL1FeeAnalyzer() {
101
+ return this.l1FeeAnalyzer;
102
+ }
103
+ /**
93
104
  * Sets the proposer address to use for simulations in fisherman mode.
94
105
  * @param proposerAddress - The actual proposer's address to use for balance lookups in simulations
95
106
  */ setProposerAddressForSimulation(proposerAddress) {
@@ -111,6 +122,46 @@ export class SequencerPublisher {
111
122
  }
112
123
  }
113
124
  /**
125
+ * Analyzes L1 fees for the pending requests without sending them.
126
+ * This is used in fisherman mode to validate fee calculations.
127
+ * @param l2SlotNumber - The L2 slot number for this analysis
128
+ * @param onComplete - Optional callback to invoke when analysis completes (after block is mined)
129
+ * @returns The analysis result (incomplete until block mines), or undefined if no requests
130
+ */ async analyzeL1Fees(l2SlotNumber, onComplete) {
131
+ if (!this.l1FeeAnalyzer) {
132
+ this.log.warn('L1 fee analyzer not available (not in fisherman mode)');
133
+ return undefined;
134
+ }
135
+ const requestsToAnalyze = [
136
+ ...this.requests
137
+ ];
138
+ if (requestsToAnalyze.length === 0) {
139
+ this.log.debug('No requests to analyze for L1 fees');
140
+ return undefined;
141
+ }
142
+ // Extract blob config from requests (if any)
143
+ const blobConfigs = requestsToAnalyze.filter((request)=>request.blobConfig).map((request)=>request.blobConfig);
144
+ const blobConfig = blobConfigs[0];
145
+ // Get gas configs
146
+ const gasConfigs = requestsToAnalyze.filter((request)=>request.gasConfig).map((request)=>request.gasConfig);
147
+ const gasLimits = gasConfigs.map((g)=>g?.gasLimit).filter((g)=>g !== undefined);
148
+ const gasLimit = gasLimits.length > 0 ? gasLimits.reduce((sum, g)=>sum + g, 0n) : 0n;
149
+ // Get the transaction requests
150
+ const l1Requests = requestsToAnalyze.map((r)=>r.request);
151
+ // Start the analysis
152
+ const analysisId = await this.l1FeeAnalyzer.startAnalysis(l2SlotNumber, gasLimit > 0n ? gasLimit : SequencerPublisher.PROPOSE_GAS_GUESS, l1Requests, blobConfig, onComplete);
153
+ this.log.info('Started L1 fee analysis', {
154
+ analysisId,
155
+ l2SlotNumber: l2SlotNumber.toString(),
156
+ requestCount: requestsToAnalyze.length,
157
+ hasBlobConfig: !!blobConfig,
158
+ gasLimit: gasLimit.toString(),
159
+ actions: requestsToAnalyze.map((r)=>r.action)
160
+ });
161
+ // Return the analysis result (will be incomplete until block mines)
162
+ return this.l1FeeAnalyzer.getAnalysis(analysisId);
163
+ }
164
+ /**
114
165
  * Sends all requests that are still valid.
115
166
  * @returns one of:
116
167
  * - A receipt and stats if the tx succeeded
@@ -121,7 +172,7 @@ export class SequencerPublisher {
121
172
  ...this.requests
122
173
  ];
123
174
  this.requests = [];
124
- if (this.interrupted) {
175
+ if (this.interrupted || requestsToProcess.length === 0) {
125
176
  return undefined;
126
177
  }
127
178
  const currentL2Slot = this.getCurrentL2Slot();
@@ -380,34 +431,29 @@ export class SequencerPublisher {
380
431
  throw new Error(`Unknown reason for invalidation`);
381
432
  }
382
433
  }
383
- /**
384
- * @notice Will simulate `propose` to make sure that the block is valid for submission
385
- *
386
- * @dev Throws if unable to propose
387
- *
388
- * @param block - The block to propose
389
- * @param attestationData - The block's attestation data
390
- *
391
- */ async validateBlockForSubmission(block, attestationsAndSigners, attestationsAndSignersSignature, options) {
434
+ /** Simulates `propose` to make sure that the checkpoint is valid for submission */ async validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, options) {
392
435
  const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
436
+ // TODO(palla/mbps): This should not be needed, there's no flow where we propose with zero attestations. Or is there?
393
437
  // If we have no attestations, we still need to provide the empty attestations
394
438
  // so that the committee is recalculated correctly
395
- const ignoreSignatures = attestationsAndSigners.attestations.length === 0;
396
- if (ignoreSignatures) {
397
- const { committee } = await this.epochCache.getCommittee(block.header.globalVariables.slotNumber);
398
- if (!committee) {
399
- this.log.warn(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
400
- throw new Error(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
401
- }
402
- attestationsAndSigners.attestations = committee.map((committeeMember)=>CommitteeAttestation.fromAddress(committeeMember));
403
- }
404
- const blobFields = block.getCheckpointBlobFields();
439
+ // const ignoreSignatures = attestationsAndSigners.attestations.length === 0;
440
+ // if (ignoreSignatures) {
441
+ // const { committee } = await this.epochCache.getCommittee(block.header.globalVariables.slotNumber);
442
+ // if (!committee) {
443
+ // this.log.warn(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
444
+ // throw new Error(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
445
+ // }
446
+ // attestationsAndSigners.attestations = committee.map(committeeMember =>
447
+ // CommitteeAttestation.fromAddress(committeeMember),
448
+ // );
449
+ // }
450
+ const blobFields = checkpoint.toBlobFields();
405
451
  const blobs = getBlobsPerL1Block(blobFields);
406
452
  const blobInput = getPrefixedEthBlobCommitments(blobs);
407
453
  const args = [
408
454
  {
409
- header: block.getCheckpointHeader().toViem(),
410
- archive: toHex(block.archive.root.toBuffer()),
455
+ header: checkpoint.header.toViem(),
456
+ archive: toHex(checkpoint.archive.root.toBuffer()),
411
457
  oracleInput: {
412
458
  feeAssetPriceModifier: 0n
413
459
  }
@@ -434,9 +480,16 @@ export class SequencerPublisher {
434
480
  }
435
481
  const round = await base.computeRound(slotNumber);
436
482
  const roundInfo = await base.getRoundInfo(this.rollupContract.address, round);
483
+ if (roundInfo.quorumReached) {
484
+ return false;
485
+ }
437
486
  if (roundInfo.lastSignalSlot >= slotNumber) {
438
487
  return false;
439
488
  }
489
+ if (await this.isPayloadEmpty(payload)) {
490
+ this.log.warn(`Skipping vote cast for payload with empty code`);
491
+ return false;
492
+ }
440
493
  const cachedLastVote = this.lastActions[signalType];
441
494
  this.lastActions[signalType] = slotNumber;
442
495
  const action = signalType;
@@ -475,17 +528,27 @@ export class SequencerPublisher {
475
528
  payload: payload.toString()
476
529
  };
477
530
  if (!success) {
478
- this.log.error(`Signaling in [${action}] for ${payload} at slot ${slotNumber} in round ${round} failed`, logData);
531
+ this.log.error(`Signaling in ${action} for ${payload} at slot ${slotNumber} in round ${round} failed`, logData);
479
532
  this.lastActions[signalType] = cachedLastVote;
480
533
  return false;
481
534
  } else {
482
- this.log.info(`Signaling in [${action}] for ${payload} at slot ${slotNumber} in round ${round} succeeded`, logData);
535
+ this.log.info(`Signaling in ${action} for ${payload} at slot ${slotNumber} in round ${round} succeeded`, logData);
483
536
  return true;
484
537
  }
485
538
  }
486
539
  });
487
540
  return true;
488
541
  }
542
+ async isPayloadEmpty(payload) {
543
+ const key = payload.toString();
544
+ const cached = this.isPayloadEmptyCache.get(key);
545
+ if (cached) {
546
+ return cached;
547
+ }
548
+ const isEmpty = !await this.l1TxUtils.getCode(payload);
549
+ this.isPayloadEmptyCache.set(key, isEmpty);
550
+ return isEmpty;
551
+ }
489
552
  /**
490
553
  * Enqueues a governance castSignal transaction to cast a signal for a given slot number.
491
554
  * @param slotNumber - The slot number to cast a signal for.
@@ -581,19 +644,13 @@ export class SequencerPublisher {
581
644
  }
582
645
  return true;
583
646
  }
584
- /**
585
- * Proposes a L2 block on L1.
586
- *
587
- * @param block - L2 block to propose.
588
- * @returns True if the tx has been enqueued, throws otherwise. See #9315
589
- */ async enqueueProposeL2Block(block, attestationsAndSigners, attestationsAndSignersSignature, opts = {}) {
590
- const checkpointHeader = block.getCheckpointHeader();
591
- const blobFields = block.getCheckpointBlobFields();
647
+ /** Simulates and enqueues a proposal for a checkpoint on L1 */ async enqueueProposeCheckpoint(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, opts = {}) {
648
+ const checkpointHeader = checkpoint.header;
649
+ const blobFields = checkpoint.toBlobFields();
592
650
  const blobs = getBlobsPerL1Block(blobFields);
593
651
  const proposeTxArgs = {
594
652
  header: checkpointHeader,
595
- archive: block.archive.root.toBuffer(),
596
- body: block.body.toBuffer(),
653
+ archive: checkpoint.archive.root.toBuffer(),
597
654
  blobs,
598
655
  attestationsAndSigners,
599
656
  attestationsAndSignersSignature
@@ -605,21 +662,20 @@ export class SequencerPublisher {
605
662
  // By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which
606
663
  // make time consistency checks break.
607
664
  // TODO(palla): Check whether we're validating twice, once here and once within addProposeTx, since we call simulateProposeTx in both places.
608
- ts = await this.validateBlockForSubmission(block, attestationsAndSigners, attestationsAndSignersSignature, opts);
665
+ ts = await this.validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, opts);
609
666
  } catch (err) {
610
- this.log.error(`Block validation failed. ${err instanceof Error ? err.message : 'No error message'}`, err, {
611
- ...block.getStats(),
612
- slotNumber: block.header.globalVariables.slotNumber,
667
+ this.log.error(`Checkpoint validation failed. ${err instanceof Error ? err.message : 'No error message'}`, err, {
668
+ ...checkpoint.getStats(),
669
+ slotNumber: checkpoint.header.slotNumber,
613
670
  forcePendingBlockNumber: opts.forcePendingBlockNumber
614
671
  });
615
672
  throw err;
616
673
  }
617
- this.log.verbose(`Enqueuing block propose transaction`, {
618
- ...block.toBlockInfo(),
674
+ this.log.verbose(`Enqueuing checkpoint propose transaction`, {
675
+ ...checkpoint.toCheckpointInfo(),
619
676
  ...opts
620
677
  });
621
- await this.addProposeTx(block, proposeTxArgs, opts, ts);
622
- return true;
678
+ await this.addProposeTx(checkpoint, proposeTxArgs, opts, ts);
623
679
  }
624
680
  enqueueInvalidateBlock(request, opts = {}) {
625
681
  if (!request) {
@@ -857,24 +913,25 @@ export class SequencerPublisher {
857
913
  simulationResult
858
914
  };
859
915
  }
860
- async addProposeTx(block, encodedData, opts = {}, timestamp) {
916
+ async addProposeTx(checkpoint, encodedData, opts = {}, timestamp) {
917
+ const slot = checkpoint.header.slotNumber;
861
918
  const timer = new Timer();
862
919
  const kzg = Blob.getViemKzgInstance();
863
920
  const { rollupData, simulationResult, blobEvaluationGas } = await this.prepareProposeTx(encodedData, timestamp, opts);
864
921
  const startBlock = await this.l1TxUtils.getBlockNumber();
865
922
  const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(simulationResult.gasUsed) * 64 / 63)) + blobEvaluationGas + SequencerPublisher.MULTICALL_OVERHEAD_GAS_GUESS);
866
- // Send the blobs to the blob sink preemptively. This helps in tests where the sequencer mistakingly thinks that the propose
867
- // tx fails but it does get mined. We make sure that the blobs are sent to the blob sink regardless of the tx outcome.
868
- void this.blobSinkClient.sendBlobsToBlobSink(encodedData.blobs).catch((_err)=>{
869
- this.log.error('Failed to send blobs to blob sink');
870
- });
923
+ // Send the blobs to the blob client preemptively. This helps in tests where the sequencer mistakingly thinks that the propose
924
+ // tx fails but it does get mined. We make sure that the blobs are sent to the blob client regardless of the tx outcome.
925
+ void Promise.resolve().then(()=>this.blobClient.sendBlobsToFilestore(encodedData.blobs).catch((_err)=>{
926
+ this.log.error('Failed to send blobs to blob client');
927
+ }));
871
928
  return this.addRequest({
872
929
  action: 'propose',
873
930
  request: {
874
931
  to: this.rollupContract.address,
875
932
  data: rollupData
876
933
  },
877
- lastValidL2Slot: block.header.globalVariables.slotNumber,
934
+ lastValidL2Slot: checkpoint.header.slotNumber,
878
935
  gasConfig: {
879
936
  ...opts,
880
937
  gasLimit
@@ -902,25 +959,23 @@ export class SequencerPublisher {
902
959
  calldataGas,
903
960
  calldataSize,
904
961
  sender,
905
- ...block.getStats(),
962
+ ...checkpoint.getStats(),
906
963
  eventName: 'rollup-published-to-l1',
907
964
  blobCount: encodedData.blobs.length,
908
965
  inclusionBlocks
909
966
  };
910
- this.log.info(`Published L2 block to L1 rollup contract`, {
967
+ this.log.info(`Published checkpoint ${checkpoint.number} at slot ${slot} to rollup contract`, {
911
968
  ...stats,
912
- ...block.getStats(),
913
- ...receipt
969
+ ...checkpoint.getStats(),
970
+ ...pick(receipt, 'transactionHash', 'blockHash')
914
971
  });
915
972
  this.metrics.recordProcessBlockTx(timer.ms(), publishStats);
916
973
  return true;
917
974
  } else {
918
975
  this.metrics.recordFailedTx('process');
919
- this.log.error(`Rollup process tx failed: ${errorMsg ?? 'no error message'}`, undefined, {
920
- ...block.getStats(),
921
- receipt,
922
- txHash: receipt.transactionHash,
923
- slotNumber: block.header.globalVariables.slotNumber
976
+ this.log.error(`Publishing checkpoint at slot ${slot} failed with ${errorMsg ?? 'no error message'}`, undefined, {
977
+ ...checkpoint.getStats(),
978
+ ...receipt
924
979
  });
925
980
  return false;
926
981
  }
@@ -3,11 +3,9 @@ import type { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import { DateProvider } from '@aztec/foundation/timer';
4
4
  import { PublicProcessor } from '@aztec/simulator/server';
5
5
  import type { ContractDataSource } from '@aztec/stdlib/contract';
6
- import { type L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
7
6
  import type { BuildBlockResult, FullNodeBlockBuilderConfig, IFullNodeBlockBuilder, MerkleTreeWriteOperations, PublicProcessorLimits, PublicProcessorValidator, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
8
7
  import { GlobalVariables, Tx } from '@aztec/stdlib/tx';
9
8
  import { type TelemetryClient } from '@aztec/telemetry-client';
10
- export declare function buildBlock(pendingTxs: Iterable<Tx> | AsyncIterable<Tx>, l1ToL2Messages: Fr[], newGlobalVariables: GlobalVariables, opts: PublicProcessorLimits | undefined, worldStateFork: MerkleTreeWriteOperations, processor: PublicProcessor, validator: PublicProcessorValidator, l1Constants: Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>, dateProvider: DateProvider, telemetryClient?: TelemetryClient): Promise<BuildBlockResult>;
11
9
  export declare class FullNodeBlockBuilder implements IFullNodeBlockBuilder {
12
10
  private config;
13
11
  private worldState;
@@ -25,4 +23,4 @@ export declare class FullNodeBlockBuilder implements IFullNodeBlockBuilder {
25
23
  buildBlock(pendingTxs: Iterable<Tx> | AsyncIterable<Tx>, l1ToL2Messages: Fr[], globalVariables: GlobalVariables, opts: PublicProcessorLimits, suppliedFork?: MerkleTreeWriteOperations): Promise<BuildBlockResult>;
26
24
  getFork(blockNumber: BlockNumber): Promise<MerkleTreeWriteOperations>;
27
25
  }
28
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvY2tfYnVpbGRlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcXVlbmNlci9ibG9ja19idWlsZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUU5RCxPQUFPLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUl6RCxPQUFPLEVBQUUsWUFBWSxFQUFrQixNQUFNLHlCQUF5QixDQUFDO0FBR3ZFLE9BQU8sRUFHTCxlQUFlLEVBRWhCLE1BQU0seUJBQXlCLENBQUM7QUFDakMsT0FBTyxLQUFLLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNqRSxPQUFPLEVBQUUsS0FBSyxpQkFBaUIsRUFBdUIsTUFBTSw2QkFBNkIsQ0FBQztBQUUxRixPQUFPLEtBQUssRUFDVixnQkFBZ0IsRUFDaEIsMEJBQTBCLEVBQzFCLHFCQUFxQixFQUNyQix5QkFBeUIsRUFDekIscUJBQXFCLEVBQ3JCLHdCQUF3QixFQUN4QixzQkFBc0IsRUFDdkIsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsZUFBZSxFQUFFLEVBQUUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxLQUFLLGVBQWUsRUFBc0IsTUFBTSx5QkFBeUIsQ0FBQztBQU1uRix3QkFBc0IsVUFBVSxDQUM5QixVQUFVLEVBQUUsUUFBUSxDQUFDLEVBQUUsQ0FBQyxHQUFHLGFBQWEsQ0FBQyxFQUFFLENBQUMsRUFDNUMsY0FBYyxFQUFFLEVBQUUsRUFBRSxFQUNwQixrQkFBa0IsRUFBRSxlQUFlLEVBQ25DLElBQUksbUNBQTRCLEVBQ2hDLGNBQWMsRUFBRSx5QkFBeUIsRUFDekMsU0FBUyxFQUFFLGVBQWUsRUFDMUIsU0FBUyxFQUFFLHdCQUF3QixFQUNuQyxXQUFXLEVBQUUsSUFBSSxDQUFDLGlCQUFpQixFQUFFLGVBQWUsR0FBRyxjQUFjLENBQUMsRUFDdEUsWUFBWSxFQUFFLFlBQVksRUFDMUIsZUFBZSxHQUFFLGVBQXNDLEdBQ3RELE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQTRDM0I7QUFXRCxxQkFBYSxvQkFBcUIsWUFBVyxxQkFBcUI7SUFFOUQsT0FBTyxDQUFDLE1BQU07SUFDZCxPQUFPLENBQUMsVUFBVTtJQUNsQixPQUFPLENBQUMsa0JBQWtCO0lBQzFCLE9BQU8sQ0FBQyxZQUFZO0lBQ3BCLE9BQU8sQ0FBQyxlQUFlO0lBTHpCLFlBQ1UsTUFBTSxFQUFFLDBCQUEwQixFQUNsQyxVQUFVLEVBQUUsc0JBQXNCLEVBQ2xDLGtCQUFrQixFQUFFLGtCQUFrQixFQUN0QyxZQUFZLEVBQUUsWUFBWSxFQUMxQixlQUFlLEdBQUUsZUFBc0MsRUFDN0Q7SUFFRyxTQUFTLElBQUksMEJBQTBCLENBRTdDO0lBRU0sWUFBWSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsMEJBQTBCLENBQUMsUUFFOUQ7SUFFWSxvQkFBb0IsQ0FBQyxlQUFlLEVBQUUsZUFBZSxFQUFFLElBQUksRUFBRSx5QkFBeUI7OztPQWtDbEc7WUFFYSxtQkFBbUI7SUFVM0IsVUFBVSxDQUNkLFVBQVUsRUFBRSxRQUFRLENBQUMsRUFBRSxDQUFDLEdBQUcsYUFBYSxDQUFDLEVBQUUsQ0FBQyxFQUM1QyxjQUFjLEVBQUUsRUFBRSxFQUFFLEVBQ3BCLGVBQWUsRUFBRSxlQUFlLEVBQ2hDLElBQUksRUFBRSxxQkFBcUIsRUFDM0IsWUFBWSxDQUFDLEVBQUUseUJBQXlCLEdBQ3ZDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQXNDM0I7SUFFRCxPQUFPLENBQUMsV0FBVyxFQUFFLFdBQVcsR0FBRyxPQUFPLENBQUMseUJBQXlCLENBQUMsQ0FFcEU7Q0FDRiJ9
26
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvY2tfYnVpbGRlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcXVlbmNlci9ibG9ja19idWlsZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUU5RCxPQUFPLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUl6RCxPQUFPLEVBQUUsWUFBWSxFQUFrQixNQUFNLHlCQUF5QixDQUFDO0FBR3ZFLE9BQU8sRUFHTCxlQUFlLEVBRWhCLE1BQU0seUJBQXlCLENBQUM7QUFDakMsT0FBTyxLQUFLLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUdqRSxPQUFPLEtBQUssRUFDVixnQkFBZ0IsRUFDaEIsMEJBQTBCLEVBQzFCLHFCQUFxQixFQUNyQix5QkFBeUIsRUFDekIscUJBQXFCLEVBQ3JCLHdCQUF3QixFQUN4QixzQkFBc0IsRUFDdkIsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsZUFBZSxFQUFFLEVBQUUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxLQUFLLGVBQWUsRUFBc0IsTUFBTSx5QkFBeUIsQ0FBQztBQTJFbkYscUJBQWEsb0JBQXFCLFlBQVcscUJBQXFCO0lBRTlELE9BQU8sQ0FBQyxNQUFNO0lBQ2QsT0FBTyxDQUFDLFVBQVU7SUFDbEIsT0FBTyxDQUFDLGtCQUFrQjtJQUMxQixPQUFPLENBQUMsWUFBWTtJQUNwQixPQUFPLENBQUMsZUFBZTtJQUx6QixZQUNVLE1BQU0sRUFBRSwwQkFBMEIsRUFDbEMsVUFBVSxFQUFFLHNCQUFzQixFQUNsQyxrQkFBa0IsRUFBRSxrQkFBa0IsRUFDdEMsWUFBWSxFQUFFLFlBQVksRUFDMUIsZUFBZSxHQUFFLGVBQXNDLEVBQzdEO0lBRUcsU0FBUyxJQUFJLDBCQUEwQixDQUU3QztJQUVNLFlBQVksQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLDBCQUEwQixDQUFDLFFBRTlEO0lBRVksb0JBQW9CLENBQUMsZUFBZSxFQUFFLGVBQWUsRUFBRSxJQUFJLEVBQUUseUJBQXlCOzs7T0FrQ2xHO1lBRWEsbUJBQW1CO0lBVTNCLFVBQVUsQ0FDZCxVQUFVLEVBQUUsUUFBUSxDQUFDLEVBQUUsQ0FBQyxHQUFHLGFBQWEsQ0FBQyxFQUFFLENBQUMsRUFDNUMsY0FBYyxFQUFFLEVBQUUsRUFBRSxFQUNwQixlQUFlLEVBQUUsZUFBZSxFQUNoQyxJQUFJLEVBQUUscUJBQXFCLEVBQzNCLFlBQVksQ0FBQyxFQUFFLHlCQUF5QixHQUN2QyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FzQzNCO0lBRUQsT0FBTyxDQUFDLFdBQVcsRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLHlCQUF5QixDQUFDLENBRXBFO0NBQ0YifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"block_builder.d.ts","sourceRoot":"","sources":["../../src/sequencer/block_builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAIzD,OAAO,EAAE,YAAY,EAAkB,MAAM,yBAAyB,CAAC;AAGvE,OAAO,EAGL,eAAe,EAEhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,KAAK,iBAAiB,EAAuB,MAAM,6BAA6B,CAAC;AAE1F,OAAO,KAAK,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAMnF,wBAAsB,UAAU,CAC9B,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,EAAE,CAAC,EAC5C,cAAc,EAAE,EAAE,EAAE,EACpB,kBAAkB,EAAE,eAAe,EACnC,IAAI,mCAA4B,EAChC,cAAc,EAAE,yBAAyB,EACzC,SAAS,EAAE,eAAe,EAC1B,SAAS,EAAE,wBAAwB,EACnC,WAAW,EAAE,IAAI,CAAC,iBAAiB,EAAE,eAAe,GAAG,cAAc,CAAC,EACtE,YAAY,EAAE,YAAY,EAC1B,eAAe,GAAE,eAAsC,GACtD,OAAO,CAAC,gBAAgB,CAAC,CA4C3B;AAWD,qBAAa,oBAAqB,YAAW,qBAAqB;IAE9D,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,eAAe;IALzB,YACU,MAAM,EAAE,0BAA0B,EAClC,UAAU,EAAE,sBAAsB,EAClC,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,YAAY,EAC1B,eAAe,GAAE,eAAsC,EAC7D;IAEG,SAAS,IAAI,0BAA0B,CAE7C;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,0BAA0B,CAAC,QAE9D;IAEY,oBAAoB,CAAC,eAAe,EAAE,eAAe,EAAE,IAAI,EAAE,yBAAyB;;;OAkClG;YAEa,mBAAmB;IAU3B,UAAU,CACd,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,EAAE,CAAC,EAC5C,cAAc,EAAE,EAAE,EAAE,EACpB,eAAe,EAAE,eAAe,EAChC,IAAI,EAAE,qBAAqB,EAC3B,YAAY,CAAC,EAAE,yBAAyB,GACvC,OAAO,CAAC,gBAAgB,CAAC,CAsC3B;IAED,OAAO,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAEpE;CACF"}
1
+ {"version":3,"file":"block_builder.d.ts","sourceRoot":"","sources":["../../src/sequencer/block_builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAIzD,OAAO,EAAE,YAAY,EAAkB,MAAM,yBAAyB,CAAC;AAGvE,OAAO,EAGL,eAAe,EAEhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAGjE,OAAO,KAAK,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AA2EnF,qBAAa,oBAAqB,YAAW,qBAAqB;IAE9D,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,eAAe;IALzB,YACU,MAAM,EAAE,0BAA0B,EAClC,UAAU,EAAE,sBAAsB,EAClC,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,YAAY,EAC1B,eAAe,GAAE,eAAsC,EAC7D;IAEG,SAAS,IAAI,0BAA0B,CAE7C;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,0BAA0B,CAAC,QAE9D;IAEY,oBAAoB,CAAC,eAAe,EAAE,eAAe,EAAE,IAAI,EAAE,yBAAyB;;;OAkClG;YAEa,mBAAmB;IAU3B,UAAU,CACd,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,EAAE,CAAC,EAC5C,cAAc,EAAE,EAAE,EAAE,EACpB,eAAe,EAAE,eAAe,EAChC,IAAI,EAAE,qBAAqB,EAC3B,YAAY,CAAC,EAAE,yBAAyB,GACvC,OAAO,CAAC,gBAAgB,CAAC,CAsC3B;IAED,OAAO,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAEpE;CACF"}
@@ -13,7 +13,7 @@ import { Gas } from '@aztec/stdlib/gas';
13
13
  import { getTelemetryClient } from '@aztec/telemetry-client';
14
14
  import { createValidatorForBlockBuilding } from '../tx_validator/tx_validator_factory.js';
15
15
  const log = createLogger('block-builder');
16
- export async function buildBlock(pendingTxs, l1ToL2Messages, newGlobalVariables, opts = {}, worldStateFork, processor, validator, l1Constants, dateProvider, telemetryClient = getTelemetryClient()) {
16
+ /** Builds a block out of pending txs */ async function buildBlock(pendingTxs, l1ToL2Messages, newGlobalVariables, opts = {}, worldStateFork, processor, validator, l1Constants, dateProvider, telemetryClient = getTelemetryClient()) {
17
17
  const blockBuildingTimer = new Timer();
18
18
  const blockNumber = newGlobalVariables.blockNumber;
19
19
  const slot = newGlobalVariables.slotNumber;
@@ -57,8 +57,10 @@ const FullNodeBlockBuilderConfigKeys = [
57
57
  'l1ChainId',
58
58
  'rollupVersion',
59
59
  'txPublicSetupAllowList',
60
- 'fakeProcessingDelayPerTxMs'
60
+ 'fakeProcessingDelayPerTxMs',
61
+ 'fakeThrowAfterProcessingTxCount'
61
62
  ];
63
+ // TODO(palla/mbps): Try killing this in favor of the CheckpointsBuilder
62
64
  export class FullNodeBlockBuilder {
63
65
  config;
64
66
  worldState;
@@ -0,0 +1,63 @@
1
+ import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
2
+ import { Fr } from '@aztec/foundation/curves/bn254';
3
+ import { DateProvider, Timer } from '@aztec/foundation/timer';
4
+ import { LightweightCheckpointBuilder } from '@aztec/prover-client/light';
5
+ import { PublicProcessor } from '@aztec/simulator/server';
6
+ import { L2BlockNew } from '@aztec/stdlib/block';
7
+ import { Checkpoint } from '@aztec/stdlib/checkpoint';
8
+ import type { ContractDataSource } from '@aztec/stdlib/contract';
9
+ import { Gas } from '@aztec/stdlib/gas';
10
+ import { type FullNodeBlockBuilderConfig, type MerkleTreeWriteOperations, type PublicProcessorLimits } from '@aztec/stdlib/interfaces/server';
11
+ import { type CheckpointGlobalVariables, type FailedTx, GlobalVariables, Tx } from '@aztec/stdlib/tx';
12
+ import { type TelemetryClient } from '@aztec/telemetry-client';
13
+ export interface BuildBlockInCheckpointResult {
14
+ block: L2BlockNew;
15
+ publicGas: Gas;
16
+ publicProcessorDuration: number;
17
+ numTxs: number;
18
+ failedTxs: FailedTx[];
19
+ blockBuildingTimer: Timer;
20
+ usedTxs: Tx[];
21
+ }
22
+ /**
23
+ * Builder for a single checkpoint. Handles building blocks within the checkpoint
24
+ * and completing it.
25
+ */
26
+ export declare class CheckpointBuilder {
27
+ private checkpointBuilder;
28
+ private fork;
29
+ private config;
30
+ private contractDataSource;
31
+ private dateProvider;
32
+ private telemetryClient;
33
+ constructor(checkpointBuilder: LightweightCheckpointBuilder, fork: MerkleTreeWriteOperations, config: FullNodeBlockBuilderConfig, contractDataSource: ContractDataSource, dateProvider: DateProvider, telemetryClient: TelemetryClient);
34
+ getConstantData(): CheckpointGlobalVariables;
35
+ /**
36
+ * Builds a single block within this checkpoint.
37
+ */
38
+ buildBlock(pendingTxs: Iterable<Tx> | AsyncIterable<Tx>, blockNumber: BlockNumber, timestamp: bigint, opts: PublicProcessorLimits): Promise<BuildBlockInCheckpointResult>;
39
+ /** Completes the checkpoint and returns it. */
40
+ completeCheckpoint(): Promise<Checkpoint>;
41
+ /** Gets the checkpoint currently in progress. */
42
+ getCheckpoint(): Promise<Checkpoint>;
43
+ protected makeBlockBuilderDeps(globalVariables: GlobalVariables, fork: MerkleTreeWriteOperations): Promise<{
44
+ processor: PublicProcessor;
45
+ validator: import("@aztec/stdlib/interfaces/server").PublicProcessorValidator;
46
+ }>;
47
+ }
48
+ /**
49
+ * Factory for creating checkpoint builders.
50
+ */
51
+ export declare class FullNodeCheckpointsBuilder {
52
+ private config;
53
+ private contractDataSource;
54
+ private dateProvider;
55
+ private telemetryClient;
56
+ constructor(config: FullNodeBlockBuilderConfig, contractDataSource: ContractDataSource, dateProvider: DateProvider, telemetryClient?: TelemetryClient);
57
+ updateConfig(config: Partial<FullNodeBlockBuilderConfig>): void;
58
+ /**
59
+ * Starts a new checkpoint and returns a CheckpointBuilder to build blocks within it.
60
+ */
61
+ startCheckpoint(checkpointNumber: CheckpointNumber, constants: CheckpointGlobalVariables, l1ToL2Messages: Fr[], fork: MerkleTreeWriteOperations): Promise<CheckpointBuilder>;
62
+ }
63
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2twb2ludF9idWlsZGVyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VxdWVuY2VyL2NoZWNrcG9pbnRfYnVpbGRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFaEYsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBR3BELE9BQU8sRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFXLE1BQU0seUJBQXlCLENBQUM7QUFFdkUsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDMUUsT0FBTyxFQUdMLGVBQWUsRUFFaEIsTUFBTSx5QkFBeUIsQ0FBQztBQUNqQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3RELE9BQU8sS0FBSyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDakUsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3hDLE9BQU8sRUFDTCxLQUFLLDBCQUEwQixFQUUvQixLQUFLLHlCQUF5QixFQUM5QixLQUFLLHFCQUFxQixFQUMzQixNQUFNLGlDQUFpQyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxLQUFLLHlCQUF5QixFQUFFLEtBQUssUUFBUSxFQUFFLGVBQWUsRUFBRSxFQUFFLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN0RyxPQUFPLEVBQUUsS0FBSyxlQUFlLEVBQXNCLE1BQU0seUJBQXlCLENBQUM7QUFNbkYsTUFBTSxXQUFXLDRCQUE0QjtJQUMzQyxLQUFLLEVBQUUsVUFBVSxDQUFDO0lBQ2xCLFNBQVMsRUFBRSxHQUFHLENBQUM7SUFDZix1QkFBdUIsRUFBRSxNQUFNLENBQUM7SUFDaEMsTUFBTSxFQUFFLE1BQU0sQ0FBQztJQUNmLFNBQVMsRUFBRSxRQUFRLEVBQUUsQ0FBQztJQUN0QixrQkFBa0IsRUFBRSxLQUFLLENBQUM7SUFDMUIsT0FBTyxFQUFFLEVBQUUsRUFBRSxDQUFDO0NBQ2Y7QUFFRDs7O0dBR0c7QUFDSCxxQkFBYSxpQkFBaUI7SUFFMUIsT0FBTyxDQUFDLGlCQUFpQjtJQUN6QixPQUFPLENBQUMsSUFBSTtJQUNaLE9BQU8sQ0FBQyxNQUFNO0lBQ2QsT0FBTyxDQUFDLGtCQUFrQjtJQUMxQixPQUFPLENBQUMsWUFBWTtJQUNwQixPQUFPLENBQUMsZUFBZTtJQU56QixZQUNVLGlCQUFpQixFQUFFLDRCQUE0QixFQUMvQyxJQUFJLEVBQUUseUJBQXlCLEVBQy9CLE1BQU0sRUFBRSwwQkFBMEIsRUFDbEMsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQ3RDLFlBQVksRUFBRSxZQUFZLEVBQzFCLGVBQWUsRUFBRSxlQUFlLEVBQ3RDO0lBRUosZUFBZSxJQUFJLHlCQUF5QixDQUUzQztJQUVEOztPQUVHO0lBQ0csVUFBVSxDQUNkLFVBQVUsRUFBRSxRQUFRLENBQUMsRUFBRSxDQUFDLEdBQUcsYUFBYSxDQUFDLEVBQUUsQ0FBQyxFQUM1QyxXQUFXLEVBQUUsV0FBVyxFQUN4QixTQUFTLEVBQUUsTUFBTSxFQUNqQixJQUFJLEVBQUUscUJBQXFCLEdBQzFCLE9BQU8sQ0FBQyw0QkFBNEIsQ0FBQyxDQXdDdkM7SUFFRCwrQ0FBK0M7SUFDekMsa0JBQWtCLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQVU5QztJQUVELGlEQUFpRDtJQUNqRCxhQUFhLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUVuQztJQUVELFVBQWdCLG9CQUFvQixDQUFDLGVBQWUsRUFBRSxlQUFlLEVBQUUsSUFBSSxFQUFFLHlCQUF5Qjs7O09Ba0NyRztDQUNGO0FBRUQ7O0dBRUc7QUFDSCxxQkFBYSwwQkFBMEI7SUFFbkMsT0FBTyxDQUFDLE1BQU07SUFDZCxPQUFPLENBQUMsa0JBQWtCO0lBQzFCLE9BQU8sQ0FBQyxZQUFZO0lBQ3BCLE9BQU8sQ0FBQyxlQUFlO0lBSnpCLFlBQ1UsTUFBTSxFQUFFLDBCQUEwQixFQUNsQyxrQkFBa0IsRUFBRSxrQkFBa0IsRUFDdEMsWUFBWSxFQUFFLFlBQVksRUFDMUIsZUFBZSxHQUFFLGVBQXNDLEVBQzdEO0lBRUcsWUFBWSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsMEJBQTBCLENBQUMsUUFFOUQ7SUFFRDs7T0FFRztJQUNHLGVBQWUsQ0FDbkIsZ0JBQWdCLEVBQUUsZ0JBQWdCLEVBQ2xDLFNBQVMsRUFBRSx5QkFBeUIsRUFDcEMsY0FBYyxFQUFFLEVBQUUsRUFBRSxFQUNwQixJQUFJLEVBQUUseUJBQXlCLEdBQzlCLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQTJCNUI7Q0FDRiJ9
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint_builder.d.ts","sourceRoot":"","sources":["../../src/sequencer/checkpoint_builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEhF,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAE,KAAK,EAAW,MAAM,yBAAyB,CAAC;AAEvE,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAGL,eAAe,EAEhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,EACL,KAAK,0BAA0B,EAE/B,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC3B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,KAAK,yBAAyB,EAAE,KAAK,QAAQ,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtG,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAMnF,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,GAAG,CAAC;IACf,uBAAuB,EAAE,MAAM,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,kBAAkB,EAAE,KAAK,CAAC;IAC1B,OAAO,EAAE,EAAE,EAAE,CAAC;CACf;AAED;;;GAGG;AACH,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,iBAAiB;IACzB,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,eAAe;IANzB,YACU,iBAAiB,EAAE,4BAA4B,EAC/C,IAAI,EAAE,yBAAyB,EAC/B,MAAM,EAAE,0BAA0B,EAClC,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,YAAY,EAC1B,eAAe,EAAE,eAAe,EACtC;IAEJ,eAAe,IAAI,yBAAyB,CAE3C;IAED;;OAEG;IACG,UAAU,CACd,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,EAAE,CAAC,EAC5C,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,4BAA4B,CAAC,CAwCvC;IAED,+CAA+C;IACzC,kBAAkB,IAAI,OAAO,CAAC,UAAU,CAAC,CAU9C;IAED,iDAAiD;IACjD,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC,CAEnC;IAED,UAAgB,oBAAoB,CAAC,eAAe,EAAE,eAAe,EAAE,IAAI,EAAE,yBAAyB;;;OAkCrG;CACF;AAED;;GAEG;AACH,qBAAa,0BAA0B;IAEnC,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,eAAe;IAJzB,YACU,MAAM,EAAE,0BAA0B,EAClC,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,YAAY,EAC1B,eAAe,GAAE,eAAsC,EAC7D;IAEG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,0BAA0B,CAAC,QAE9D;IAED;;OAEG;IACG,eAAe,CACnB,gBAAgB,EAAE,gBAAgB,EAClC,SAAS,EAAE,yBAAyB,EACpC,cAAc,EAAE,EAAE,EAAE,EACpB,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CA2B5B;CACF"}
@@ -0,0 +1,131 @@
1
+ import { MerkleTreeId } from '@aztec/aztec.js/trees';
2
+ import { merge, pick } from '@aztec/foundation/collection';
3
+ import { createLogger } from '@aztec/foundation/log';
4
+ import { bufferToHex } from '@aztec/foundation/string';
5
+ import { Timer, elapsed } from '@aztec/foundation/timer';
6
+ import { getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
7
+ import { LightweightCheckpointBuilder } from '@aztec/prover-client/light';
8
+ import { GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor, createPublicTxSimulatorForBlockBuilding } from '@aztec/simulator/server';
9
+ import { Gas } from '@aztec/stdlib/gas';
10
+ import { FullNodeBlockBuilderConfigKeys } from '@aztec/stdlib/interfaces/server';
11
+ import { GlobalVariables } from '@aztec/stdlib/tx';
12
+ import { getTelemetryClient } from '@aztec/telemetry-client';
13
+ import { createValidatorForBlockBuilding } from '../tx_validator/tx_validator_factory.js';
14
+ const log = createLogger('checkpoint-builder');
15
+ /**
16
+ * Builder for a single checkpoint. Handles building blocks within the checkpoint
17
+ * and completing it.
18
+ */ export class CheckpointBuilder {
19
+ checkpointBuilder;
20
+ fork;
21
+ config;
22
+ contractDataSource;
23
+ dateProvider;
24
+ telemetryClient;
25
+ constructor(checkpointBuilder, fork, config, contractDataSource, dateProvider, telemetryClient){
26
+ this.checkpointBuilder = checkpointBuilder;
27
+ this.fork = fork;
28
+ this.config = config;
29
+ this.contractDataSource = contractDataSource;
30
+ this.dateProvider = dateProvider;
31
+ this.telemetryClient = telemetryClient;
32
+ }
33
+ getConstantData() {
34
+ return this.checkpointBuilder.constants;
35
+ }
36
+ /**
37
+ * Builds a single block within this checkpoint.
38
+ */ async buildBlock(pendingTxs, blockNumber, timestamp, opts) {
39
+ const blockBuildingTimer = new Timer();
40
+ const slot = this.checkpointBuilder.constants.slotNumber;
41
+ log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
42
+ slot,
43
+ blockNumber,
44
+ ...opts
45
+ });
46
+ const constants = this.checkpointBuilder.constants;
47
+ const globalVariables = GlobalVariables.from({
48
+ chainId: constants.chainId,
49
+ version: constants.version,
50
+ blockNumber,
51
+ slotNumber: constants.slotNumber,
52
+ timestamp,
53
+ coinbase: constants.coinbase,
54
+ feeRecipient: constants.feeRecipient,
55
+ gasFees: constants.gasFees
56
+ });
57
+ const { processor, validator } = await this.makeBlockBuilderDeps(globalVariables, this.fork);
58
+ const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs]] = await elapsed(()=>processor.process(pendingTxs, opts, validator));
59
+ // Add block to checkpoint
60
+ const block = await this.checkpointBuilder.addBlock(globalVariables, processedTxs);
61
+ // How much public gas was processed
62
+ const publicGas = processedTxs.reduce((acc, tx)=>acc.add(tx.gasUsed.publicGas), Gas.empty());
63
+ const res = {
64
+ block,
65
+ publicGas,
66
+ publicProcessorDuration,
67
+ numTxs: processedTxs.length,
68
+ failedTxs,
69
+ blockBuildingTimer,
70
+ usedTxs
71
+ };
72
+ log.debug('Built block within checkpoint', res.block.header);
73
+ return res;
74
+ }
75
+ /** Completes the checkpoint and returns it. */ async completeCheckpoint() {
76
+ const checkpoint = await this.checkpointBuilder.completeCheckpoint();
77
+ log.verbose(`Completed checkpoint ${checkpoint.number}`, {
78
+ checkpointNumber: checkpoint.number,
79
+ numBlocks: checkpoint.blocks.length,
80
+ archiveRoot: checkpoint.archive.root.toString()
81
+ });
82
+ return checkpoint;
83
+ }
84
+ /** Gets the checkpoint currently in progress. */ getCheckpoint() {
85
+ return this.checkpointBuilder.clone().completeCheckpoint();
86
+ }
87
+ async makeBlockBuilderDeps(globalVariables, fork) {
88
+ const txPublicSetupAllowList = this.config.txPublicSetupAllowList ?? await getDefaultAllowedSetupFunctions();
89
+ const contractsDB = new PublicContractsDB(this.contractDataSource);
90
+ const guardedFork = new GuardedMerkleTreeOperations(fork);
91
+ const publicTxSimulator = createPublicTxSimulatorForBlockBuilding(guardedFork, contractsDB, globalVariables, this.telemetryClient);
92
+ const processor = new PublicProcessor(globalVariables, guardedFork, contractsDB, publicTxSimulator, this.dateProvider, this.telemetryClient, undefined, this.config);
93
+ const validator = createValidatorForBlockBuilding(fork, this.contractDataSource, globalVariables, txPublicSetupAllowList);
94
+ return {
95
+ processor,
96
+ validator
97
+ };
98
+ }
99
+ }
100
+ /**
101
+ * Factory for creating checkpoint builders.
102
+ */ export class FullNodeCheckpointsBuilder {
103
+ config;
104
+ contractDataSource;
105
+ dateProvider;
106
+ telemetryClient;
107
+ constructor(config, contractDataSource, dateProvider, telemetryClient = getTelemetryClient()){
108
+ this.config = config;
109
+ this.contractDataSource = contractDataSource;
110
+ this.dateProvider = dateProvider;
111
+ this.telemetryClient = telemetryClient;
112
+ }
113
+ updateConfig(config) {
114
+ this.config = merge(this.config, pick(config, ...FullNodeBlockBuilderConfigKeys));
115
+ }
116
+ /**
117
+ * Starts a new checkpoint and returns a CheckpointBuilder to build blocks within it.
118
+ */ async startCheckpoint(checkpointNumber, constants, l1ToL2Messages, fork) {
119
+ const stateReference = await fork.getStateReference();
120
+ const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
121
+ log.verbose(`Building checkpoint ${checkpointNumber}`, {
122
+ checkpointNumber,
123
+ msgCount: l1ToL2Messages.length,
124
+ initialStateReference: stateReference.toInspect(),
125
+ initialArchiveRoot: bufferToHex(archiveTree.root),
126
+ constants
127
+ });
128
+ const lightweightBuilder = await LightweightCheckpointBuilder.startNewCheckpoint(checkpointNumber, constants, l1ToL2Messages, fork);
129
+ return new CheckpointBuilder(lightweightBuilder, fork, this.config, this.contractDataSource, this.dateProvider, this.telemetryClient);
130
+ }
131
+ }