@aztec/sequencer-client 0.0.1-commit.6b113946b → 0.0.1-commit.6bd18f1aa

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 (32) hide show
  1. package/dest/client/sequencer-client.d.ts +4 -1
  2. package/dest/client/sequencer-client.d.ts.map +1 -1
  3. package/dest/client/sequencer-client.js +8 -13
  4. package/dest/global_variable_builder/global_builder.d.ts +13 -7
  5. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  6. package/dest/global_variable_builder/global_builder.js +22 -22
  7. package/dest/global_variable_builder/index.d.ts +2 -2
  8. package/dest/global_variable_builder/index.d.ts.map +1 -1
  9. package/dest/publisher/config.d.ts +13 -1
  10. package/dest/publisher/config.d.ts.map +1 -1
  11. package/dest/publisher/config.js +17 -2
  12. package/dest/publisher/sequencer-publisher-factory.d.ts +3 -3
  13. package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
  14. package/dest/publisher/sequencer-publisher-factory.js +2 -2
  15. package/dest/publisher/sequencer-publisher.d.ts +10 -5
  16. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  17. package/dest/publisher/sequencer-publisher.js +46 -33
  18. package/dest/sequencer/checkpoint_proposal_job.js +1 -1
  19. package/dest/sequencer/checkpoint_voter.d.ts +1 -2
  20. package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
  21. package/dest/sequencer/checkpoint_voter.js +2 -5
  22. package/dest/sequencer/sequencer.js +3 -3
  23. package/package.json +27 -27
  24. package/src/client/sequencer-client.ts +11 -17
  25. package/src/global_variable_builder/global_builder.ts +22 -24
  26. package/src/global_variable_builder/index.ts +1 -1
  27. package/src/publisher/config.ts +32 -0
  28. package/src/publisher/sequencer-publisher-factory.ts +3 -3
  29. package/src/publisher/sequencer-publisher.ts +37 -39
  30. package/src/sequencer/checkpoint_proposal_job.ts +1 -1
  31. package/src/sequencer/checkpoint_voter.ts +1 -12
  32. package/src/sequencer/sequencer.ts +3 -3
@@ -391,6 +391,7 @@ import { Timer } from '@aztec/foundation/timer';
391
391
  import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
392
392
  import { encodeSlashConsensusVotes } from '@aztec/slasher';
393
393
  import { CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
394
+ import { getLastL1SlotTimestampForL2Slot, getNextL1SlotTimestamp } from '@aztec/stdlib/epoch-helpers';
394
395
  import { getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
395
396
  import { encodeFunctionData, keccak256, multicall3Abi, toHex } from 'viem';
396
397
  import { createL1TxFailedStore } from './l1_tx_failed_store/index.js';
@@ -442,6 +443,7 @@ export class SequencerPublisher {
442
443
  log;
443
444
  ethereumSlotDuration;
444
445
  aztecSlotDuration;
446
+ dateProvider;
445
447
  blobClient;
446
448
  /** Address to use for simulations in fisherman mode (actual proposer's address) */ proposerAddressForSimulation;
447
449
  /** Optional callback to obtain a replacement publisher when the current one fails to send. */ getNextPublisher;
@@ -470,6 +472,7 @@ export class SequencerPublisher {
470
472
  this.log = deps.log ?? createLogger('sequencer:publisher');
471
473
  this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
472
474
  this.aztecSlotDuration = BigInt(config.aztecSlotDuration);
475
+ this.dateProvider = deps.dateProvider;
473
476
  this.epochCache = deps.epochCache;
474
477
  this.lastActions = deps.lastActions;
475
478
  this.blobClient = deps.blobClient;
@@ -840,7 +843,8 @@ export class SequencerPublisher {
840
843
  ];
841
844
  const pipelined = opts.pipelined ?? this.epochCache.isProposerPipeliningEnabled();
842
845
  const slotOffset = pipelined ? this.aztecSlotDuration : 0n;
843
- return this.rollupContract.canProposeAt(tipArchive.toBuffer(), msgSender.toString(), this.ethereumSlotDuration, slotOffset, {
846
+ const nextL1SlotTs = this.getNextL1SlotTimestamp() + slotOffset;
847
+ return this.rollupContract.canProposeAt(tipArchive.toBuffer(), msgSender.toString(), nextL1SlotTs, {
844
848
  forcePendingCheckpointNumber: opts.forcePendingCheckpointNumber
845
849
  }).catch((err)=>{
846
850
  if (err instanceof FormattedViemError && ignoredErrors.find((e)=>err.message.includes(e))) {
@@ -872,7 +876,7 @@ export class SequencerPublisher {
872
876
  header.blobsHash.toString(),
873
877
  flags
874
878
  ];
875
- const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
879
+ const ts = this.getSimulationTimestamp(header.slotNumber);
876
880
  const stateOverrides = await this.rollupContract.makePendingCheckpointNumberOverride(opts?.forcePendingCheckpointNumber);
877
881
  let balance = 0n;
878
882
  if (this.config.fishermanMode) {
@@ -895,7 +899,7 @@ export class SequencerPublisher {
895
899
  }),
896
900
  from: MULTI_CALL_3_ADDRESS
897
901
  }, {
898
- time: ts + 1n
902
+ time: ts
899
903
  }, stateOverrides);
900
904
  this.log.debug(`Simulated validateHeader`);
901
905
  }
@@ -1015,9 +1019,6 @@ export class SequencerPublisher {
1015
1019
  }
1016
1020
  }
1017
1021
  /** Simulates `propose` to make sure that the checkpoint is valid for submission */ async validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, options) {
1018
- // Anchor the simulation timestamp to the checkpoint's own slot start time
1019
- // rather than the current L1 block timestamp, which may overshoot into the next slot if the build ran late.
1020
- const ts = checkpoint.header.timestamp;
1021
1022
  const blobFields = checkpoint.toBlobFields();
1022
1023
  const blobs = await getBlobsPerL1Block(blobFields);
1023
1024
  const blobInput = getPrefixedEthBlobCommitments(blobs);
@@ -1034,10 +1035,9 @@ export class SequencerPublisher {
1034
1035
  attestationsAndSignersSignature.toViemSignature(),
1035
1036
  blobInput
1036
1037
  ];
1037
- await this.simulateProposeTx(args, ts, options);
1038
- return ts;
1038
+ await this.simulateProposeTx(args, options);
1039
1039
  }
1040
- async enqueueCastSignalHelper(slotNumber, timestamp, signalType, payload, base, signerAddress, signer) {
1040
+ async enqueueCastSignalHelper(slotNumber, signalType, payload, base, signerAddress, signer) {
1041
1041
  if (this.lastActions[signalType] && this.lastActions[signalType] === slotNumber) {
1042
1042
  this.log.debug(`Skipping duplicate vote cast signal ${signalType} for slot ${slotNumber}`);
1043
1043
  return false;
@@ -1094,6 +1094,7 @@ export class SequencerPublisher {
1094
1094
  lastValidL2Slot: slotNumber
1095
1095
  });
1096
1096
  const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
1097
+ const timestamp = this.getSimulationTimestamp(slotNumber);
1097
1098
  try {
1098
1099
  await this.l1TxUtils.simulate(request, {
1099
1100
  time: timestamp
@@ -1106,7 +1107,10 @@ export class SequencerPublisher {
1106
1107
  });
1107
1108
  } catch (err) {
1108
1109
  const viemError = formatViemError(err);
1109
- this.log.error(`Failed simulation for ${action} at slot ${slotNumber} (enqueuing the action anyway)`, viemError);
1110
+ this.log.error(`Failed simulation for ${action} at slot ${slotNumber} (enqueuing the action anyway)`, viemError, {
1111
+ simulationTimestamp: timestamp,
1112
+ l1BlockNumber
1113
+ });
1110
1114
  this.backupFailedTx({
1111
1115
  id: keccak256(request.data),
1112
1116
  failureType: 'simulation',
@@ -1171,12 +1175,11 @@ export class SequencerPublisher {
1171
1175
  /**
1172
1176
  * Enqueues a governance castSignal transaction to cast a signal for a given slot number.
1173
1177
  * @param slotNumber - The slot number to cast a signal for.
1174
- * @param timestamp - The timestamp of the slot to cast a signal for.
1175
1178
  * @returns True if the signal was successfully enqueued, false otherwise.
1176
- */ enqueueGovernanceCastSignal(governancePayload, slotNumber, timestamp, signerAddress, signer) {
1177
- return this.enqueueCastSignalHelper(slotNumber, timestamp, 'governance-signal', governancePayload, this.govProposerContract, signerAddress, signer);
1179
+ */ enqueueGovernanceCastSignal(governancePayload, slotNumber, signerAddress, signer) {
1180
+ return this.enqueueCastSignalHelper(slotNumber, 'governance-signal', governancePayload, this.govProposerContract, signerAddress, signer);
1178
1181
  }
1179
- /** Enqueues all slashing actions as returned by the slasher client. */ async enqueueSlashingActions(actions, slotNumber, timestamp, signerAddress, signer) {
1182
+ /** Enqueues all slashing actions as returned by the slasher client. */ async enqueueSlashingActions(actions, slotNumber, signerAddress, signer) {
1180
1183
  if (actions.length === 0) {
1181
1184
  this.log.debug(`No slashing actions to enqueue for slot ${slotNumber}`);
1182
1185
  return false;
@@ -1192,7 +1195,7 @@ export class SequencerPublisher {
1192
1195
  this.log.debug(`Enqueuing slashing vote for payload ${action.payload} at slot ${slotNumber}`, {
1193
1196
  signerAddress
1194
1197
  });
1195
- await this.enqueueCastSignalHelper(slotNumber, timestamp, 'empire-slashing-signal', action.payload, this.slashingProposerContract, signerAddress, signer);
1198
+ await this.enqueueCastSignalHelper(slotNumber, 'empire-slashing-signal', action.payload, this.slashingProposerContract, signerAddress, signer);
1196
1199
  break;
1197
1200
  }
1198
1201
  case 'create-empire-payload':
@@ -1202,7 +1205,7 @@ export class SequencerPublisher {
1202
1205
  signerAddress
1203
1206
  });
1204
1207
  const request = this.slashFactoryContract.buildCreatePayloadRequest(action.data);
1205
- await this.simulateAndEnqueueRequest('create-empire-payload', request, (receipt)=>!!this.slashFactoryContract.tryExtractSlashPayloadCreatedEvent(receipt.logs), slotNumber, timestamp);
1208
+ await this.simulateAndEnqueueRequest('create-empire-payload', request, (receipt)=>!!this.slashFactoryContract.tryExtractSlashPayloadCreatedEvent(receipt.logs), slotNumber);
1206
1209
  break;
1207
1210
  }
1208
1211
  case 'execute-empire-payload':
@@ -1217,7 +1220,7 @@ export class SequencerPublisher {
1217
1220
  }
1218
1221
  const empireSlashingProposer = this.slashingProposerContract;
1219
1222
  const request = empireSlashingProposer.buildExecuteRoundRequest(action.round);
1220
- await this.simulateAndEnqueueRequest('execute-empire-payload', request, (receipt)=>!!empireSlashingProposer.tryExtractPayloadSubmittedEvent(receipt.logs), slotNumber, timestamp);
1223
+ await this.simulateAndEnqueueRequest('execute-empire-payload', request, (receipt)=>!!empireSlashingProposer.tryExtractPayloadSubmittedEvent(receipt.logs), slotNumber);
1221
1224
  break;
1222
1225
  }
1223
1226
  case 'vote-offenses':
@@ -1235,7 +1238,7 @@ export class SequencerPublisher {
1235
1238
  const tallySlashingProposer = this.slashingProposerContract;
1236
1239
  const votes = bufferToHex(encodeSlashConsensusVotes(action.votes));
1237
1240
  const request = await tallySlashingProposer.buildVoteRequestFromSigner(votes, slotNumber, signer);
1238
- await this.simulateAndEnqueueRequest('vote-offenses', request, (receipt)=>!!tallySlashingProposer.tryExtractVoteCastEvent(receipt.logs), slotNumber, timestamp);
1241
+ await this.simulateAndEnqueueRequest('vote-offenses', request, (receipt)=>!!tallySlashingProposer.tryExtractVoteCastEvent(receipt.logs), slotNumber);
1239
1242
  break;
1240
1243
  }
1241
1244
  case 'execute-slash':
@@ -1251,7 +1254,7 @@ export class SequencerPublisher {
1251
1254
  }
1252
1255
  const tallySlashingProposer = this.slashingProposerContract;
1253
1256
  const request = tallySlashingProposer.buildExecuteRoundRequest(action.round, action.committees);
1254
- await this.simulateAndEnqueueRequest('execute-slash', request, (receipt)=>!!tallySlashingProposer.tryExtractRoundExecutedEvent(receipt.logs), slotNumber, timestamp);
1257
+ await this.simulateAndEnqueueRequest('execute-slash', request, (receipt)=>!!tallySlashingProposer.tryExtractRoundExecutedEvent(receipt.logs), slotNumber);
1255
1258
  break;
1256
1259
  }
1257
1260
  default:
@@ -1275,14 +1278,13 @@ export class SequencerPublisher {
1275
1278
  attestationsAndSignersSignature,
1276
1279
  feeAssetPriceModifier: checkpoint.feeAssetPriceModifier
1277
1280
  };
1278
- let ts;
1279
1281
  try {
1280
1282
  // @note This will make sure that we are passing the checks for our header ASSUMING that the data is also made available
1281
1283
  // This means that we can avoid the simulation issues in later checks.
1282
1284
  // By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which
1283
1285
  // make time consistency checks break.
1284
1286
  // TODO(palla): Check whether we're validating twice, once here and once within addProposeTx, since we call simulateProposeTx in both places.
1285
- ts = await this.validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, opts);
1287
+ await this.validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, opts);
1286
1288
  } catch (err) {
1287
1289
  this.log.error(`Checkpoint validation failed. ${err instanceof Error ? err.message : 'No error message'}`, err, {
1288
1290
  ...checkpoint.getStats(),
@@ -1295,7 +1297,7 @@ export class SequencerPublisher {
1295
1297
  ...checkpoint.toCheckpointInfo(),
1296
1298
  ...opts
1297
1299
  });
1298
- await this.addProposeTx(checkpoint, proposeTxArgs, opts, ts);
1300
+ await this.addProposeTx(checkpoint, proposeTxArgs, opts);
1299
1301
  }
1300
1302
  enqueueInvalidateCheckpoint(request, opts = {}) {
1301
1303
  if (!request) {
@@ -1336,7 +1338,8 @@ export class SequencerPublisher {
1336
1338
  }
1337
1339
  });
1338
1340
  }
1339
- async simulateAndEnqueueRequest(action, request, checkSuccess, slotNumber, timestamp) {
1341
+ async simulateAndEnqueueRequest(action, request, checkSuccess, slotNumber) {
1342
+ const timestamp = this.getSimulationTimestamp(slotNumber);
1340
1343
  const logData = {
1341
1344
  slotNumber,
1342
1345
  timestamp,
@@ -1358,7 +1361,7 @@ export class SequencerPublisher {
1358
1361
  try {
1359
1362
  ({ gasUsed } = await this.l1TxUtils.simulate(request, {
1360
1363
  time: timestamp
1361
- }, [], simulateAbi)); // TODO(palla/slash): Check the timestamp logic
1364
+ }, [], simulateAbi));
1362
1365
  this.log.verbose(`Simulation for ${action} succeeded`, {
1363
1366
  ...logData,
1364
1367
  request,
@@ -1439,7 +1442,7 @@ export class SequencerPublisher {
1439
1442
  this.interrupted = false;
1440
1443
  this.l1TxUtils.restart();
1441
1444
  }
1442
- async prepareProposeTx(encodedData, timestamp, options) {
1445
+ async prepareProposeTx(encodedData, options) {
1443
1446
  const kzg = Blob.getViemKzgInstance();
1444
1447
  const blobInput = getPrefixedEthBlobCommitments(encodedData.blobs);
1445
1448
  this.log.debug('Validating blob input', {
@@ -1516,7 +1519,7 @@ export class SequencerPublisher {
1516
1519
  encodedData.attestationsAndSignersSignature.toViemSignature(),
1517
1520
  blobInput
1518
1521
  ];
1519
- const { rollupData, simulationResult } = await this.simulateProposeTx(args, timestamp, options);
1522
+ const { rollupData, simulationResult } = await this.simulateProposeTx(args, options);
1520
1523
  return {
1521
1524
  args,
1522
1525
  blobEvaluationGas,
@@ -1527,9 +1530,8 @@ export class SequencerPublisher {
1527
1530
  /**
1528
1531
  * Simulates the propose tx with eth_simulateV1
1529
1532
  * @param args - The propose tx args
1530
- * @param timestamp - The timestamp to simulate proposal at
1531
1533
  * @returns The simulation result
1532
- */ async simulateProposeTx(args, timestamp, options) {
1534
+ */ async simulateProposeTx(args, options) {
1533
1535
  const rollupData = encodeFunctionData({
1534
1536
  abi: RollupAbi,
1535
1537
  functionName: 'propose',
@@ -1558,6 +1560,7 @@ export class SequencerPublisher {
1558
1560
  });
1559
1561
  }
1560
1562
  const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
1563
+ const simTs = this.getSimulationTimestamp(SlotNumber.fromBigInt(args[0].header.slotNumber));
1561
1564
  const simulationResult = await this.l1TxUtils.simulate({
1562
1565
  to: this.rollupContract.address,
1563
1566
  data: rollupData,
@@ -1566,8 +1569,7 @@ export class SequencerPublisher {
1566
1569
  from: this.proposerAddressForSimulation.toString()
1567
1570
  }
1568
1571
  }, {
1569
- // @note we add 1n to the timestamp because geth implementation doesn't like simulation timestamp to be equal to the current block timestamp
1570
- time: timestamp + 1n,
1572
+ time: simTs,
1571
1573
  // @note reth should have a 30m gas limit per block but throws errors that this tx is beyond limit so we increase here
1572
1574
  gasLimit: MAX_L1_TX_LIMIT * 2n
1573
1575
  }, stateOverrides, RollupAbi, {
@@ -1584,7 +1586,9 @@ export class SequencerPublisher {
1584
1586
  logs: []
1585
1587
  };
1586
1588
  }
1587
- this.log.error(`Failed to simulate propose tx`, viemError);
1589
+ this.log.error(`Failed to simulate propose tx`, viemError, {
1590
+ simulationTimestamp: simTs
1591
+ });
1588
1592
  this.backupFailedTx({
1589
1593
  id: keccak256(rollupData),
1590
1594
  failureType: 'simulation',
@@ -1612,11 +1616,11 @@ export class SequencerPublisher {
1612
1616
  simulationResult
1613
1617
  };
1614
1618
  }
1615
- async addProposeTx(checkpoint, encodedData, opts = {}, timestamp) {
1619
+ async addProposeTx(checkpoint, encodedData, opts = {}) {
1616
1620
  const slot = checkpoint.header.slotNumber;
1617
1621
  const timer = new Timer();
1618
1622
  const kzg = Blob.getViemKzgInstance();
1619
- const { rollupData, simulationResult, blobEvaluationGas } = await this.prepareProposeTx(encodedData, timestamp, opts);
1623
+ const { rollupData, simulationResult, blobEvaluationGas } = await this.prepareProposeTx(encodedData, opts);
1620
1624
  const startBlock = await this.l1TxUtils.getBlockNumber();
1621
1625
  const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(simulationResult.gasUsed) * 64 / 63)) + blobEvaluationGas + SequencerPublisher.MULTICALL_OVERHEAD_GAS_GUESS);
1622
1626
  // Send the blobs to the blob client preemptively. This helps in tests where the sequencer mistakingly thinks that the propose
@@ -1681,4 +1685,13 @@ export class SequencerPublisher {
1681
1685
  }
1682
1686
  });
1683
1687
  }
1688
+ /** Returns the timestamp of the last L1 slot within a given L2 slot. Used as the simulation timestamp
1689
+ * for eth_simulateV1 calls, since it's guaranteed to be greater than any L1 block produced during the slot. */ getSimulationTimestamp(slot) {
1690
+ const l1Constants = this.epochCache.getL1Constants();
1691
+ return getLastL1SlotTimestampForL2Slot(slot, l1Constants);
1692
+ }
1693
+ /** Returns the timestamp of the next L1 slot boundary after now. */ getNextL1SlotTimestamp() {
1694
+ const l1Constants = this.epochCache.getL1Constants();
1695
+ return getNextL1SlotTimestamp(this.dateProvider.nowInSeconds(), l1Constants);
1696
+ }
1684
1697
  }
@@ -1216,7 +1216,7 @@ _dec = trackSpan('CheckpointProposalJob.execute'), _dec1 = trackSpan('Checkpoint
1216
1216
  * Gossip doesn't echo messages back to the sender, so the proposer's archiver/world-state
1217
1217
  * would never receive its own block without this explicit sync.
1218
1218
  */ async syncProposedBlockToArchiver(block) {
1219
- if (this.config.skipPushProposedBlocksToArchiver !== false) {
1219
+ if (this.config.skipPushProposedBlocksToArchiver) {
1220
1220
  this.log.warn(`Skipping push of proposed block ${block.number} to archiver`, {
1221
1221
  blockNumber: block.number,
1222
1222
  slot: block.header.globalVariables.slotNumber
@@ -20,7 +20,6 @@ export declare class CheckpointVoter {
20
20
  private readonly config;
21
21
  private readonly metrics;
22
22
  private readonly log;
23
- private slotTimestamp;
24
23
  private governanceSigner;
25
24
  private slashingSigner;
26
25
  constructor(slot: SlotNumber, publisher: SequencerPublisher, attestorAddress: EthAddress, validatorClient: ValidatorClient, slasherClient: SlasherClientInterface | undefined, l1Constants: SequencerRollupConstants, config: ResolvedSequencerConfig, metrics: SequencerMetrics, log: Logger);
@@ -32,4 +31,4 @@ export declare class CheckpointVoter {
32
31
  private enqueueGovernanceVote;
33
32
  private enqueueSlashingVote;
34
33
  }
35
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2twb2ludF92b3Rlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcXVlbmNlci9jaGVja3BvaW50X3ZvdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ2xFLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ2hFLE9BQU8sS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3BELE9BQU8sS0FBSyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFN0QsT0FBTyxLQUFLLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUMvRSxPQUFPLEtBQUssRUFBRSxlQUFlLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQU0vRCxPQUFPLEtBQUssRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBQzlFLE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3JELE9BQU8sS0FBSyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRTNEOztHQUVHO0FBQ0gscUJBQWEsZUFBZTtJQU14QixPQUFPLENBQUMsUUFBUSxDQUFDLElBQUk7SUFDckIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxTQUFTO0lBQzFCLE9BQU8sQ0FBQyxRQUFRLENBQUMsZUFBZTtJQUNoQyxPQUFPLENBQUMsUUFBUSxDQUFDLGVBQWU7SUFDaEMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxhQUFhO0lBQzlCLE9BQU8sQ0FBQyxRQUFRLENBQUMsV0FBVztJQUM1QixPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU07SUFDdkIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPO0lBQ3hCLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRztJQWJ0QixPQUFPLENBQUMsYUFBYSxDQUFTO0lBQzlCLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBdUQ7SUFDL0UsT0FBTyxDQUFDLGNBQWMsQ0FBdUQ7SUFFN0UsWUFDbUIsSUFBSSxFQUFFLFVBQVUsRUFDaEIsU0FBUyxFQUFFLGtCQUFrQixFQUM3QixlQUFlLEVBQUUsVUFBVSxFQUMzQixlQUFlLEVBQUUsZUFBZSxFQUNoQyxhQUFhLEVBQUUsc0JBQXNCLEdBQUcsU0FBUyxFQUNqRCxXQUFXLEVBQUUsd0JBQXdCLEVBQ3JDLE1BQU0sRUFBRSx1QkFBdUIsRUFDL0IsT0FBTyxFQUFFLGdCQUFnQixFQUN6QixHQUFHLEVBQUUsTUFBTSxFQWE3QjtJQUVEOzs7T0FHRztJQUNILFlBQVksSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEdBQUcsU0FBUyxDQUFDLEVBQUUsT0FBTyxDQUFDLE9BQU8sR0FBRyxTQUFTLENBQUMsQ0FBQyxDQVUzRTtZQUVhLHFCQUFxQjtZQWdDckIsbUJBQW1CO0NBaUNsQyJ9
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2twb2ludF92b3Rlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcXVlbmNlci9jaGVja3BvaW50X3ZvdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ2xFLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ2hFLE9BQU8sS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3BELE9BQU8sS0FBSyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0QsT0FBTyxLQUFLLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUMvRSxPQUFPLEtBQUssRUFBRSxlQUFlLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQU0vRCxPQUFPLEtBQUssRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBQzlFLE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3JELE9BQU8sS0FBSyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRTNEOztHQUVHO0FBQ0gscUJBQWEsZUFBZTtJQUt4QixPQUFPLENBQUMsUUFBUSxDQUFDLElBQUk7SUFDckIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxTQUFTO0lBQzFCLE9BQU8sQ0FBQyxRQUFRLENBQUMsZUFBZTtJQUNoQyxPQUFPLENBQUMsUUFBUSxDQUFDLGVBQWU7SUFDaEMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxhQUFhO0lBQzlCLE9BQU8sQ0FBQyxRQUFRLENBQUMsV0FBVztJQUM1QixPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU07SUFDdkIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPO0lBQ3hCLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRztJQVp0QixPQUFPLENBQUMsZ0JBQWdCLENBQXVEO0lBQy9FLE9BQU8sQ0FBQyxjQUFjLENBQXVEO0lBRTdFLFlBQ21CLElBQUksRUFBRSxVQUFVLEVBQ2hCLFNBQVMsRUFBRSxrQkFBa0IsRUFDN0IsZUFBZSxFQUFFLFVBQVUsRUFDM0IsZUFBZSxFQUFFLGVBQWUsRUFDaEMsYUFBYSxFQUFFLHNCQUFzQixHQUFHLFNBQVMsRUFDakQsV0FBVyxFQUFFLHdCQUF3QixFQUNyQyxNQUFNLEVBQUUsdUJBQXVCLEVBQy9CLE9BQU8sRUFBRSxnQkFBZ0IsRUFDekIsR0FBRyxFQUFFLE1BQU0sRUFXN0I7SUFFRDs7O09BR0c7SUFDSCxZQUFZLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxHQUFHLFNBQVMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxPQUFPLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FVM0U7WUFFYSxxQkFBcUI7WUErQnJCLG1CQUFtQjtDQTJCbEMifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"checkpoint_voter.d.ts","sourceRoot":"","sources":["../../src/sequencer/checkpoint_voter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAM/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D;;GAEG;AACH,qBAAa,eAAe;IAMxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAbtB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,gBAAgB,CAAuD;IAC/E,OAAO,CAAC,cAAc,CAAuD;IAE7E,YACmB,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,kBAAkB,EAC7B,eAAe,EAAE,UAAU,EAC3B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,sBAAsB,GAAG,SAAS,EACjD,WAAW,EAAE,wBAAwB,EACrC,MAAM,EAAE,uBAAuB,EAC/B,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EAa7B;IAED;;;OAGG;IACH,YAAY,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,EAAE,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,CAU3E;YAEa,qBAAqB;YAgCrB,mBAAmB;CAiClC"}
1
+ {"version":3,"file":"checkpoint_voter.d.ts","sourceRoot":"","sources":["../../src/sequencer/checkpoint_voter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAM/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D;;GAEG;AACH,qBAAa,eAAe;IAKxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAZtB,OAAO,CAAC,gBAAgB,CAAuD;IAC/E,OAAO,CAAC,cAAc,CAAuD;IAE7E,YACmB,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,kBAAkB,EAC7B,eAAe,EAAE,UAAU,EAC3B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,sBAAsB,GAAG,SAAS,EACjD,WAAW,EAAE,wBAAwB,EACrC,MAAM,EAAE,uBAAuB,EAC/B,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EAW7B;IAED;;;OAGG;IACH,YAAY,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,EAAE,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,CAU3E;YAEa,qBAAqB;YA+BrB,mBAAmB;CA2BlC"}
@@ -1,4 +1,3 @@
1
- import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
2
1
  import { DutyAlreadySignedError } from '@aztec/validator-ha-signer/errors';
3
2
  import { DutyType } from '@aztec/validator-ha-signer/types';
4
3
  /**
@@ -13,7 +12,6 @@ import { DutyType } from '@aztec/validator-ha-signer/types';
13
12
  config;
14
13
  metrics;
15
14
  log;
16
- slotTimestamp;
17
15
  governanceSigner;
18
16
  slashingSigner;
19
17
  constructor(slot, publisher, attestorAddress, validatorClient, slasherClient, l1Constants, config, metrics, log){
@@ -26,7 +24,6 @@ import { DutyType } from '@aztec/validator-ha-signer/types';
26
24
  this.config = config;
27
25
  this.metrics = metrics;
28
26
  this.log = log;
29
- this.slotTimestamp = getTimestampForSlot(this.slot, this.l1Constants);
30
27
  // Create separate signers with appropriate duty contexts for governance and slashing votes
31
28
  // These use HA protection to ensure only one node signs per slot/duty
32
29
  const governanceContext = {
@@ -69,7 +66,7 @@ import { DutyType } from '@aztec/validator-ha-signer/types';
69
66
  governanceProposerPayload: governanceProposerPayload.toString()
70
67
  });
71
68
  try {
72
- return await this.publisher.enqueueGovernanceCastSignal(governanceProposerPayload, this.slot, this.slotTimestamp, this.attestorAddress, this.governanceSigner);
69
+ return await this.publisher.enqueueGovernanceCastSignal(governanceProposerPayload, this.slot, this.attestorAddress, this.governanceSigner);
73
70
  } catch (err) {
74
71
  if (err instanceof DutyAlreadySignedError) {
75
72
  this.log.info(`Governance vote already signed by another node`, {
@@ -93,7 +90,7 @@ import { DutyType } from '@aztec/validator-ha-signer/types';
93
90
  actionCount: actions.length
94
91
  });
95
92
  this.metrics.recordSlashingAttempt(actions.length);
96
- return await this.publisher.enqueueSlashingActions(actions, this.slot, this.slotTimestamp, this.attestorAddress, this.slashingSigner);
93
+ return await this.publisher.enqueueSlashingActions(actions, this.slot, this.attestorAddress, this.slashingSigner);
97
94
  } catch (err) {
98
95
  if (err instanceof DutyAlreadySignedError) {
99
96
  this.log.info(`Slashing vote already signed by another node`, {
@@ -494,7 +494,7 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
494
494
  this.setState(SequencerState.STOPPING, undefined, {
495
495
  force: true
496
496
  });
497
- this.publisherFactory.interruptAll();
497
+ await this.publisherFactory.stopAll();
498
498
  await this.runningPromise?.stop();
499
499
  this.setState(SequencerState.STOPPED, undefined, {
500
500
  force: true
@@ -751,8 +751,8 @@ _dec = trackSpan('Sequencer.work'), _dec1 = trackSpan('Sequencer.prepareCheckpoi
751
751
  * We don't check against the previous block submitted since it may have been reorg'd out.
752
752
  */ async checkSync(args) {
753
753
  // Check that the archiver has fully synced the L2 slot before the one we want to propose in.
754
- // TODO(#14766): Archiver reports L1 timestamp based on L1 blocks seen, which means that a missed L1 block will
755
- // cause the archiver L1 timestamp to fall behind, and cause this sequencer to start processing one L1 slot later.
754
+ // The archiver reports sync progress via L1 block timestamps and synced checkpoint slots.
755
+ // See getSyncedL2SlotNumber for how missed L1 blocks are handled.
756
756
  const syncedL2Slot = await this.l2BlockSource.getSyncedL2SlotNumber();
757
757
  const { slot } = args;
758
758
  if (syncedL2Slot === undefined || syncedL2Slot + 1 < slot) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/sequencer-client",
3
- "version": "0.0.1-commit.6b113946b",
3
+ "version": "0.0.1-commit.6bd18f1aa",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -26,37 +26,37 @@
26
26
  "test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --config jest.integration.config.json"
27
27
  },
28
28
  "dependencies": {
29
- "@aztec/aztec.js": "0.0.1-commit.6b113946b",
30
- "@aztec/bb-prover": "0.0.1-commit.6b113946b",
31
- "@aztec/blob-client": "0.0.1-commit.6b113946b",
32
- "@aztec/blob-lib": "0.0.1-commit.6b113946b",
33
- "@aztec/constants": "0.0.1-commit.6b113946b",
34
- "@aztec/epoch-cache": "0.0.1-commit.6b113946b",
35
- "@aztec/ethereum": "0.0.1-commit.6b113946b",
36
- "@aztec/foundation": "0.0.1-commit.6b113946b",
37
- "@aztec/l1-artifacts": "0.0.1-commit.6b113946b",
38
- "@aztec/node-keystore": "0.0.1-commit.6b113946b",
39
- "@aztec/noir-acvm_js": "0.0.1-commit.6b113946b",
40
- "@aztec/noir-contracts.js": "0.0.1-commit.6b113946b",
41
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.6b113946b",
42
- "@aztec/noir-types": "0.0.1-commit.6b113946b",
43
- "@aztec/p2p": "0.0.1-commit.6b113946b",
44
- "@aztec/protocol-contracts": "0.0.1-commit.6b113946b",
45
- "@aztec/prover-client": "0.0.1-commit.6b113946b",
46
- "@aztec/simulator": "0.0.1-commit.6b113946b",
47
- "@aztec/slasher": "0.0.1-commit.6b113946b",
48
- "@aztec/stdlib": "0.0.1-commit.6b113946b",
49
- "@aztec/telemetry-client": "0.0.1-commit.6b113946b",
50
- "@aztec/validator-client": "0.0.1-commit.6b113946b",
51
- "@aztec/validator-ha-signer": "0.0.1-commit.6b113946b",
52
- "@aztec/world-state": "0.0.1-commit.6b113946b",
29
+ "@aztec/aztec.js": "0.0.1-commit.6bd18f1aa",
30
+ "@aztec/bb-prover": "0.0.1-commit.6bd18f1aa",
31
+ "@aztec/blob-client": "0.0.1-commit.6bd18f1aa",
32
+ "@aztec/blob-lib": "0.0.1-commit.6bd18f1aa",
33
+ "@aztec/constants": "0.0.1-commit.6bd18f1aa",
34
+ "@aztec/epoch-cache": "0.0.1-commit.6bd18f1aa",
35
+ "@aztec/ethereum": "0.0.1-commit.6bd18f1aa",
36
+ "@aztec/foundation": "0.0.1-commit.6bd18f1aa",
37
+ "@aztec/l1-artifacts": "0.0.1-commit.6bd18f1aa",
38
+ "@aztec/node-keystore": "0.0.1-commit.6bd18f1aa",
39
+ "@aztec/noir-acvm_js": "0.0.1-commit.6bd18f1aa",
40
+ "@aztec/noir-contracts.js": "0.0.1-commit.6bd18f1aa",
41
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.6bd18f1aa",
42
+ "@aztec/noir-types": "0.0.1-commit.6bd18f1aa",
43
+ "@aztec/p2p": "0.0.1-commit.6bd18f1aa",
44
+ "@aztec/protocol-contracts": "0.0.1-commit.6bd18f1aa",
45
+ "@aztec/prover-client": "0.0.1-commit.6bd18f1aa",
46
+ "@aztec/simulator": "0.0.1-commit.6bd18f1aa",
47
+ "@aztec/slasher": "0.0.1-commit.6bd18f1aa",
48
+ "@aztec/stdlib": "0.0.1-commit.6bd18f1aa",
49
+ "@aztec/telemetry-client": "0.0.1-commit.6bd18f1aa",
50
+ "@aztec/validator-client": "0.0.1-commit.6bd18f1aa",
51
+ "@aztec/validator-ha-signer": "0.0.1-commit.6bd18f1aa",
52
+ "@aztec/world-state": "0.0.1-commit.6bd18f1aa",
53
53
  "lodash.chunk": "^4.2.0",
54
54
  "tslib": "^2.4.0",
55
55
  "viem": "npm:@aztec/viem@2.38.2"
56
56
  },
57
57
  "devDependencies": {
58
- "@aztec/archiver": "0.0.1-commit.6b113946b",
59
- "@aztec/kv-store": "0.0.1-commit.6b113946b",
58
+ "@aztec/archiver": "0.0.1-commit.6bd18f1aa",
59
+ "@aztec/kv-store": "0.0.1-commit.6bd18f1aa",
60
60
  "@electric-sql/pglite": "^0.3.14",
61
61
  "@jest/globals": "^30.0.0",
62
62
  "@types/jest": "^30.0.0",
@@ -20,7 +20,7 @@ import { L1Metrics, type TelemetryClient } from '@aztec/telemetry-client';
20
20
  import { FullNodeCheckpointsBuilder, NodeKeystoreAdapter, type ValidatorClient } from '@aztec/validator-client';
21
21
 
22
22
  import { type SequencerClientConfig, getPublisherConfigFromSequencerConfig } from '../config.js';
23
- import { GlobalVariableBuilder } from '../global_variable_builder/index.js';
23
+ import type { GlobalVariableBuilder } from '../global_variable_builder/index.js';
24
24
  import { SequencerPublisherFactory } from '../publisher/sequencer-publisher-factory.js';
25
25
  import { Sequencer, type SequencerConfig } from '../sequencer/index.js';
26
26
 
@@ -65,7 +65,9 @@ export class SequencerClient {
65
65
  dateProvider: DateProvider;
66
66
  epochCache?: EpochCache;
67
67
  l1TxUtils: L1TxUtils[];
68
+ funderL1TxUtils?: L1TxUtils;
68
69
  nodeKeyStore: KeystoreManager;
70
+ globalVariableBuilder: GlobalVariableBuilder;
69
71
  },
70
72
  ) {
71
73
  const {
@@ -87,16 +89,14 @@ export class SequencerClient {
87
89
  publicClient,
88
90
  l1TxUtils.map(x => x.getSenderAddress()),
89
91
  );
90
- const publisherManager = new PublisherManager(
91
- l1TxUtils,
92
- getPublisherConfigFromSequencerConfig(config),
93
- log.getBindings(),
94
- );
92
+ const publisherManager = new PublisherManager(l1TxUtils, getPublisherConfigFromSequencerConfig(config), {
93
+ bindings: log.getBindings(),
94
+ funder: deps.funderL1TxUtils,
95
+ });
95
96
  const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
96
- const [l1GenesisTime, slotDuration, rollupVersion, rollupManaLimit] = await Promise.all([
97
+ const [l1GenesisTime, slotDuration, rollupManaLimit] = await Promise.all([
97
98
  rollupContract.getL1GenesisTime(),
98
99
  rollupContract.getSlotDuration(),
99
- rollupContract.getVersion(),
100
100
  rollupContract.getManaLimit().then(Number),
101
101
  ] as const);
102
102
 
@@ -140,13 +140,7 @@ export class SequencerClient {
140
140
 
141
141
  const ethereumSlotDuration = config.ethereumSlotDuration;
142
142
 
143
- const globalsBuilder = new GlobalVariableBuilder({
144
- ...config,
145
- l1GenesisTime,
146
- slotDuration: Number(slotDuration),
147
- ethereumSlotDuration,
148
- rollupVersion,
149
- });
143
+ const globalsBuilder = deps.globalVariableBuilder;
150
144
 
151
145
  // When running in anvil, assume we can post a tx up until one second before the end of an L1 slot.
152
146
  // Otherwise, we need the full L1 slot duration for publishing to ensure inclusion.
@@ -202,7 +196,7 @@ export class SequencerClient {
202
196
  await this.validatorClient?.start();
203
197
  this.sequencer.start();
204
198
  this.l1Metrics?.start();
205
- await this.publisherManager.loadState();
199
+ await this.publisherManager.start();
206
200
  }
207
201
 
208
202
  /**
@@ -211,7 +205,7 @@ export class SequencerClient {
211
205
  public async stop() {
212
206
  await this.sequencer.stop();
213
207
  await this.validatorClient?.stop();
214
- this.publisherManager.interrupt();
208
+ await this.publisherManager.stop();
215
209
  this.l1Metrics?.stop();
216
210
  }
217
211
 
@@ -1,15 +1,13 @@
1
- import { createEthereumChain } from '@aztec/ethereum/chain';
2
- import { makeL1HttpTransport } from '@aztec/ethereum/client';
3
- import type { L1ContractsConfig } from '@aztec/ethereum/config';
4
1
  import { RollupContract } from '@aztec/ethereum/contracts';
5
- import type { L1ReaderConfig } from '@aztec/ethereum/l1-reader';
2
+ import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
6
3
  import type { ViemPublicClient } from '@aztec/ethereum/types';
7
4
  import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
8
5
  import { Fr } from '@aztec/foundation/curves/bn254';
9
6
  import type { EthAddress } from '@aztec/foundation/eth-address';
10
7
  import { createLogger } from '@aztec/foundation/log';
8
+ import type { DateProvider } from '@aztec/foundation/timer';
11
9
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
12
- import { type L1RollupConstants, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
10
+ import { type L1RollupConstants, getNextL1SlotTimestamp, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
13
11
  import { GasFees } from '@aztec/stdlib/gas';
14
12
  import type {
15
13
  CheckpointGlobalVariables,
@@ -17,7 +15,12 @@ import type {
17
15
  } from '@aztec/stdlib/tx';
18
16
  import { GlobalVariables } from '@aztec/stdlib/tx';
19
17
 
20
- import { createPublicClient } from 'viem';
18
+ /** Configuration for the GlobalVariableBuilder (excludes L1 client config). */
19
+ export type GlobalVariableBuilderConfig = {
20
+ l1Contracts: Pick<L1ContractAddresses, 'rollupAddress'>;
21
+ ethereumSlotDuration: number;
22
+ rollupVersion: bigint;
23
+ } & Pick<L1RollupConstants, 'slotDuration' | 'l1GenesisTime'>;
21
24
 
22
25
  /**
23
26
  * Simple global variables builder.
@@ -28,7 +31,6 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
28
31
  private currentL1BlockNumber: bigint | undefined = undefined;
29
32
 
30
33
  private readonly rollupContract: RollupContract;
31
- private readonly publicClient: ViemPublicClient;
32
34
  private readonly ethereumSlotDuration: number;
33
35
  private readonly aztecSlotDuration: number;
34
36
  private readonly l1GenesisTime: bigint;
@@ -37,28 +39,18 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
37
39
  private version: Fr;
38
40
 
39
41
  constructor(
40
- config: L1ReaderConfig &
41
- Pick<L1ContractsConfig, 'ethereumSlotDuration'> &
42
- Pick<L1RollupConstants, 'slotDuration' | 'l1GenesisTime'> & { rollupVersion: bigint },
42
+ private readonly dateProvider: DateProvider,
43
+ private readonly publicClient: ViemPublicClient,
44
+ config: GlobalVariableBuilderConfig,
43
45
  ) {
44
- const { l1RpcUrls, l1ChainId: chainId, l1Contracts } = config;
45
-
46
- const chain = createEthereumChain(l1RpcUrls, chainId);
47
-
48
46
  this.version = new Fr(config.rollupVersion);
49
- this.chainId = new Fr(chainId);
47
+ this.chainId = new Fr(this.publicClient.chain!.id);
50
48
 
51
49
  this.ethereumSlotDuration = config.ethereumSlotDuration;
52
50
  this.aztecSlotDuration = config.slotDuration;
53
51
  this.l1GenesisTime = config.l1GenesisTime;
54
52
 
55
- this.publicClient = createPublicClient({
56
- chain: chain.chainInfo,
57
- transport: makeL1HttpTransport(chain.rpcUrls, { timeout: config.l1HttpTimeoutMS }),
58
- pollingInterval: config.viemPollingIntervalMS,
59
- });
60
-
61
- this.rollupContract = new RollupContract(this.publicClient, l1Contracts.rollupAddress);
53
+ this.rollupContract = new RollupContract(this.publicClient, config.l1Contracts.rollupAddress);
62
54
  }
63
55
 
64
56
  /**
@@ -74,7 +66,10 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
74
66
  const earliestTimestamp = await this.rollupContract.getTimestampForSlot(
75
67
  SlotNumber.fromBigInt(BigInt(lastCheckpoint.slotNumber) + 1n),
76
68
  );
77
- const nextEthTimestamp = BigInt((await this.publicClient.getBlock()).timestamp + BigInt(this.ethereumSlotDuration));
69
+ const nextEthTimestamp = getNextL1SlotTimestamp(this.dateProvider.nowInSeconds(), {
70
+ l1GenesisTime: this.l1GenesisTime,
71
+ ethereumSlotDuration: this.ethereumSlotDuration,
72
+ });
78
73
  const timestamp = earliestTimestamp > nextEthTimestamp ? earliestTimestamp : nextEthTimestamp;
79
74
 
80
75
  return new GasFees(0, await this.rollupContract.getManaMinFeeAt(timestamp, true));
@@ -109,7 +104,10 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
109
104
  const slot: SlotNumber =
110
105
  maybeSlot ??
111
106
  (await this.rollupContract.getSlotAt(
112
- BigInt((await this.publicClient.getBlock()).timestamp + BigInt(this.ethereumSlotDuration)),
107
+ getNextL1SlotTimestamp(this.dateProvider.nowInSeconds(), {
108
+ l1GenesisTime: this.l1GenesisTime,
109
+ ethereumSlotDuration: this.ethereumSlotDuration,
110
+ }),
113
111
  ));
114
112
 
115
113
  const checkpointGlobalVariables = await this.buildCheckpointGlobalVariables(coinbase, feeRecipient, slot);
@@ -1 +1 @@
1
- export { GlobalVariableBuilder } from './global_builder.js';
1
+ export { GlobalVariableBuilder, type GlobalVariableBuilderConfig } from './global_builder.js';