@aztec/sequencer-client 0.0.1-commit.b655e406 → 0.0.1-commit.fce3e4f

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 (54) hide show
  1. package/dest/client/index.d.ts +1 -1
  2. package/dest/client/sequencer-client.d.ts +1 -1
  3. package/dest/client/sequencer-client.d.ts.map +1 -1
  4. package/dest/client/sequencer-client.js +2 -1
  5. package/dest/config.d.ts +1 -1
  6. package/dest/config.d.ts.map +1 -1
  7. package/dest/config.js +9 -0
  8. package/dest/global_variable_builder/global_builder.d.ts +3 -6
  9. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  10. package/dest/global_variable_builder/global_builder.js +9 -6
  11. package/dest/global_variable_builder/index.d.ts +1 -1
  12. package/dest/index.d.ts +1 -1
  13. package/dest/publisher/config.d.ts +3 -1
  14. package/dest/publisher/config.d.ts.map +1 -1
  15. package/dest/publisher/config.js +5 -0
  16. package/dest/publisher/index.d.ts +1 -1
  17. package/dest/publisher/sequencer-publisher-factory.d.ts +1 -1
  18. package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
  19. package/dest/publisher/sequencer-publisher-metrics.d.ts +1 -1
  20. package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
  21. package/dest/publisher/sequencer-publisher.d.ts +29 -23
  22. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  23. package/dest/publisher/sequencer-publisher.js +108 -57
  24. package/dest/sequencer/block_builder.d.ts +1 -1
  25. package/dest/sequencer/block_builder.d.ts.map +1 -1
  26. package/dest/sequencer/block_builder.js +10 -6
  27. package/dest/sequencer/config.d.ts +1 -1
  28. package/dest/sequencer/errors.d.ts +1 -1
  29. package/dest/sequencer/errors.d.ts.map +1 -1
  30. package/dest/sequencer/index.d.ts +1 -1
  31. package/dest/sequencer/metrics.d.ts +11 -2
  32. package/dest/sequencer/metrics.d.ts.map +1 -1
  33. package/dest/sequencer/metrics.js +38 -0
  34. package/dest/sequencer/sequencer.d.ts +17 -25
  35. package/dest/sequencer/sequencer.d.ts.map +1 -1
  36. package/dest/sequencer/sequencer.js +169 -46
  37. package/dest/sequencer/timetable.d.ts +1 -1
  38. package/dest/sequencer/timetable.d.ts.map +1 -1
  39. package/dest/sequencer/utils.d.ts +1 -1
  40. package/dest/test/index.d.ts +1 -1
  41. package/dest/tx_validator/nullifier_cache.d.ts +1 -1
  42. package/dest/tx_validator/nullifier_cache.d.ts.map +1 -1
  43. package/dest/tx_validator/tx_validator_factory.d.ts +2 -2
  44. package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
  45. package/package.json +31 -30
  46. package/src/client/sequencer-client.ts +2 -2
  47. package/src/config.ts +10 -0
  48. package/src/global_variable_builder/global_builder.ts +12 -8
  49. package/src/publisher/config.ts +8 -0
  50. package/src/publisher/sequencer-publisher-factory.ts +2 -1
  51. package/src/publisher/sequencer-publisher.ts +125 -70
  52. package/src/sequencer/block_builder.ts +10 -6
  53. package/src/sequencer/metrics.ts +51 -2
  54. package/src/sequencer/sequencer.ts +204 -60
@@ -18,13 +18,14 @@ import {
18
18
  type TransactionStats,
19
19
  type ViemCommitteeAttestations,
20
20
  type ViemHeader,
21
- type ViemStateReference,
21
+ WEI_CONST,
22
22
  formatViemError,
23
23
  tryExtractEvent,
24
24
  } from '@aztec/ethereum';
25
25
  import type { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
26
26
  import { sumBigint } from '@aztec/foundation/bigint';
27
27
  import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
28
+ import { SlotNumber } from '@aztec/foundation/branded-types';
28
29
  import { EthAddress } from '@aztec/foundation/eth-address';
29
30
  import { Signature, type ViemSignature } from '@aztec/foundation/eth-signature';
30
31
  import type { Fr } from '@aztec/foundation/fields';
@@ -37,10 +38,9 @@ import { CommitteeAttestation, CommitteeAttestationsAndSigners, type ValidateBlo
37
38
  import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
38
39
  import type { CheckpointHeader } from '@aztec/stdlib/rollup';
39
40
  import type { L1PublishBlockStats } from '@aztec/stdlib/stats';
40
- import { StateReference } from '@aztec/stdlib/tx';
41
41
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
42
42
 
43
- import { type TransactionReceipt, type TypedDataDefinition, encodeFunctionData, toHex } from 'viem';
43
+ import { type StateOverride, type TransactionReceipt, type TypedDataDefinition, encodeFunctionData, toHex } from 'viem';
44
44
 
45
45
  import type { PublisherConfig, TxSenderConfig } from './config.js';
46
46
  import { SequencerPublisherMetrics } from './sequencer-publisher-metrics.js';
@@ -51,8 +51,6 @@ type L1ProcessArgs = {
51
51
  header: CheckpointHeader;
52
52
  /** A root of the archive tree after the L2 block is applied. */
53
53
  archive: Buffer;
54
- /** State reference after the L2 block is applied. */
55
- stateReference: StateReference;
56
54
  /** L2 block blobs containing all tx effects. */
57
55
  blobs: Blob[];
58
56
  /** Attestations */
@@ -91,7 +89,7 @@ export type InvalidateBlockRequest = {
91
89
  interface RequestWithExpiry {
92
90
  action: Action;
93
91
  request: L1TxRequest;
94
- lastValidL2Slot: bigint;
92
+ lastValidL2Slot: SlotNumber;
95
93
  gasConfig?: Pick<L1TxConfig, 'txTimeoutAt' | 'gasLimit'>;
96
94
  blobConfig?: L1BlobInputs;
97
95
  checkSuccess: (
@@ -108,12 +106,15 @@ export class SequencerPublisher {
108
106
  protected governanceLog = createLogger('sequencer:publisher:governance');
109
107
  protected slashingLog = createLogger('sequencer:publisher:slashing');
110
108
 
111
- protected lastActions: Partial<Record<Action, bigint>> = {};
109
+ protected lastActions: Partial<Record<Action, SlotNumber>> = {};
112
110
 
113
111
  protected log: Logger;
114
112
  protected ethereumSlotDuration: bigint;
115
113
 
116
114
  private blobSinkClient: BlobSinkClientInterface;
115
+
116
+ /** Address to use for simulations in fisherman mode (actual proposer's address) */
117
+ private proposerAddressForSimulation?: EthAddress;
117
118
  // @note - with blobs, the below estimate seems too large.
118
119
  // Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
119
120
  // Total used for emptier block from above test: 429k (of which 84k is 1x blob)
@@ -146,7 +147,7 @@ export class SequencerPublisher {
146
147
  epochCache: EpochCache;
147
148
  dateProvider: DateProvider;
148
149
  metrics: SequencerPublisherMetrics;
149
- lastActions: Partial<Record<Action, bigint>>;
150
+ lastActions: Partial<Record<Action, SlotNumber>>;
150
151
  log?: Logger;
151
152
  },
152
153
  ) {
@@ -183,14 +184,33 @@ export class SequencerPublisher {
183
184
  return this.l1TxUtils.getSenderAddress();
184
185
  }
185
186
 
187
+ /**
188
+ * Sets the proposer address to use for simulations in fisherman mode.
189
+ * @param proposerAddress - The actual proposer's address to use for balance lookups in simulations
190
+ */
191
+ public setProposerAddressForSimulation(proposerAddress: EthAddress | undefined) {
192
+ this.proposerAddressForSimulation = proposerAddress;
193
+ }
194
+
186
195
  public addRequest(request: RequestWithExpiry) {
187
196
  this.requests.push(request);
188
197
  }
189
198
 
190
- public getCurrentL2Slot(): bigint {
199
+ public getCurrentL2Slot(): SlotNumber {
191
200
  return this.epochCache.getEpochAndSlotNow().slot;
192
201
  }
193
202
 
203
+ /**
204
+ * Clears all pending requests without sending them.
205
+ */
206
+ public clearPendingRequests(): void {
207
+ const count = this.requests.length;
208
+ this.requests = [];
209
+ if (count > 0) {
210
+ this.log.debug(`Cleared ${count} pending request(s)`);
211
+ }
212
+ }
213
+
194
214
  /**
195
215
  * Sends all requests that are still valid.
196
216
  * @returns one of:
@@ -321,7 +341,9 @@ export class SequencerPublisher {
321
341
  const ignoredErrors = ['SlotAlreadyInChain', 'InvalidProposer', 'InvalidArchive'];
322
342
 
323
343
  return this.rollupContract
324
- .canProposeAtNextEthBlock(tipArchive.toBuffer(), msgSender.toString(), this.ethereumSlotDuration, opts)
344
+ .canProposeAtNextEthBlock(tipArchive.toBuffer(), msgSender.toString(), Number(this.ethereumSlotDuration), {
345
+ forcePendingCheckpointNumber: opts.forcePendingBlockNumber,
346
+ })
325
347
  .catch(err => {
326
348
  if (err instanceof FormattedViemError && ignoredErrors.find(e => err.message.includes(e))) {
327
349
  this.log.warn(`Failed canProposeAtTime check with ${ignoredErrors.find(e => err.message.includes(e))}`, {
@@ -353,10 +375,20 @@ export class SequencerPublisher {
353
375
  ] as const;
354
376
 
355
377
  const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
378
+ const stateOverrides = await this.rollupContract.makePendingCheckpointNumberOverride(opts?.forcePendingBlockNumber);
379
+ let balance = 0n;
380
+ if (this.config.fishermanMode) {
381
+ // In fisherman mode, we can't know where the proposer is publishing from
382
+ // so we just add sufficient balance to the multicall3 address
383
+ balance = 10n * WEI_CONST * WEI_CONST; // 10 ETH
384
+ } else {
385
+ balance = await this.l1TxUtils.getSenderBalance();
386
+ }
387
+ stateOverrides.push({
388
+ address: MULTI_CALL_3_ADDRESS,
389
+ balance,
390
+ });
356
391
 
357
- // use sender balance to simulate
358
- const balance = await this.l1TxUtils.getSenderBalance();
359
- this.log.debug(`Simulating validateHeader with balance: ${balance}`);
360
392
  await this.l1TxUtils.simulate(
361
393
  {
362
394
  to: this.rollupContract.address,
@@ -364,10 +396,7 @@ export class SequencerPublisher {
364
396
  from: MULTI_CALL_3_ADDRESS,
365
397
  },
366
398
  { time: ts + 1n },
367
- [
368
- { address: MULTI_CALL_3_ADDRESS, balance },
369
- ...(await this.rollupContract.makePendingBlockNumberOverride(opts?.forcePendingBlockNumber)),
370
- ],
399
+ stateOverrides,
371
400
  );
372
401
  this.log.debug(`Simulated validateHeader`);
373
402
  }
@@ -387,7 +416,7 @@ export class SequencerPublisher {
387
416
  const blockNumber = block.blockNumber;
388
417
  const logData = { ...block, reason };
389
418
 
390
- const currentBlockNumber = await this.rollupContract.getBlockNumber();
419
+ const currentBlockNumber = await this.rollupContract.getCheckpointNumber();
391
420
  if (currentBlockNumber < validationResult.block.blockNumber) {
392
421
  this.log.verbose(
393
422
  `Skipping block ${blockNumber} invalidation since it has already been removed from the pending chain`,
@@ -414,7 +443,7 @@ export class SequencerPublisher {
414
443
  `Simulation for invalidate block ${blockNumber} failed due to block not being in pending chain`,
415
444
  { ...logData, request, error: viemError.message },
416
445
  );
417
- const latestPendingBlockNumber = await this.rollupContract.getBlockNumber();
446
+ const latestPendingBlockNumber = await this.rollupContract.getCheckpointNumber();
418
447
  if (latestPendingBlockNumber < blockNumber) {
419
448
  this.log.verbose(`Block number ${blockNumber} has already been invalidated`, { ...logData });
420
449
  return undefined;
@@ -489,10 +518,10 @@ export class SequencerPublisher {
489
518
  // so that the committee is recalculated correctly
490
519
  const ignoreSignatures = attestationsAndSigners.attestations.length === 0;
491
520
  if (ignoreSignatures) {
492
- const { committee } = await this.epochCache.getCommittee(block.header.globalVariables.slotNumber.toBigInt());
521
+ const { committee } = await this.epochCache.getCommittee(block.header.globalVariables.slotNumber);
493
522
  if (!committee) {
494
- this.log.warn(`No committee found for slot ${block.header.globalVariables.slotNumber.toBigInt()}`);
495
- throw new Error(`No committee found for slot ${block.header.globalVariables.slotNumber.toBigInt()}`);
523
+ this.log.warn(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
524
+ throw new Error(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
496
525
  }
497
526
  attestationsAndSigners.attestations = committee.map(committeeMember =>
498
527
  CommitteeAttestation.fromAddress(committeeMember),
@@ -507,7 +536,6 @@ export class SequencerPublisher {
507
536
  {
508
537
  header: block.getCheckpointHeader().toViem(),
509
538
  archive: toHex(block.archive.root.toBuffer()),
510
- stateReference: block.header.state.toViem(),
511
539
  oracleInput: {
512
540
  feeAssetPriceModifier: 0n,
513
541
  },
@@ -523,7 +551,7 @@ export class SequencerPublisher {
523
551
  }
524
552
 
525
553
  private async enqueueCastSignalHelper(
526
- slotNumber: bigint,
554
+ slotNumber: SlotNumber,
527
555
  timestamp: bigint,
528
556
  signalType: GovernanceSignalAction,
529
557
  payload: EthAddress,
@@ -616,7 +644,7 @@ export class SequencerPublisher {
616
644
  */
617
645
  public enqueueGovernanceCastSignal(
618
646
  governancePayload: EthAddress,
619
- slotNumber: bigint,
647
+ slotNumber: SlotNumber,
620
648
  timestamp: bigint,
621
649
  signerAddress: EthAddress,
622
650
  signer: (msg: TypedDataDefinition) => Promise<`0x${string}`>,
@@ -635,7 +663,7 @@ export class SequencerPublisher {
635
663
  /** Enqueues all slashing actions as returned by the slasher client. */
636
664
  public async enqueueSlashingActions(
637
665
  actions: ProposerSlashAction[],
638
- slotNumber: bigint,
666
+ slotNumber: SlotNumber,
639
667
  timestamp: bigint,
640
668
  signerAddress: EthAddress,
641
669
  signer: (msg: TypedDataDefinition) => Promise<`0x${string}`>,
@@ -775,7 +803,6 @@ export class SequencerPublisher {
775
803
  const proposeTxArgs = {
776
804
  header: checkpointHeader,
777
805
  archive: block.archive.root.toBuffer(),
778
- stateReference: block.header.state,
779
806
  body: block.body.toBuffer(),
780
807
  blobs,
781
808
  attestationsAndSigners,
@@ -794,7 +821,7 @@ export class SequencerPublisher {
794
821
  } catch (err: any) {
795
822
  this.log.error(`Block validation failed. ${err instanceof Error ? err.message : 'No error message'}`, err, {
796
823
  ...block.getStats(),
797
- slotNumber: block.header.globalVariables.slotNumber.toBigInt(),
824
+ slotNumber: block.header.globalVariables.slotNumber,
798
825
  forcePendingBlockNumber: opts.forcePendingBlockNumber,
799
826
  });
800
827
  throw err;
@@ -820,13 +847,13 @@ export class SequencerPublisher {
820
847
  action: `invalidate-by-${request.reason}`,
821
848
  request: request.request,
822
849
  gasConfig: { gasLimit, txTimeoutAt: opts.txTimeoutAt },
823
- lastValidL2Slot: this.getCurrentL2Slot() + 2n,
850
+ lastValidL2Slot: SlotNumber(this.getCurrentL2Slot() + 2),
824
851
  checkSuccess: (_req, result) => {
825
852
  const success =
826
853
  result &&
827
854
  result.receipt &&
828
855
  result.receipt.status === 'success' &&
829
- tryExtractEvent(result.receipt.logs, this.rollupContract.address, RollupAbi, 'BlockInvalidated');
856
+ tryExtractEvent(result.receipt.logs, this.rollupContract.address, RollupAbi, 'CheckpointInvalidated');
830
857
  if (!success) {
831
858
  this.log.warn(`Invalidate block ${request.blockNumber} failed`, { ...result, ...logData });
832
859
  } else {
@@ -841,7 +868,7 @@ export class SequencerPublisher {
841
868
  action: Action,
842
869
  request: L1TxRequest,
843
870
  checkSuccess: (receipt: TransactionReceipt) => boolean | undefined,
844
- slotNumber: bigint,
871
+ slotNumber: SlotNumber,
845
872
  timestamp: bigint,
846
873
  ) {
847
874
  const logData = { slotNumber, timestamp, gasLimit: undefined as bigint | undefined };
@@ -914,36 +941,45 @@ export class SequencerPublisher {
914
941
  const kzg = Blob.getViemKzgInstance();
915
942
  const blobInput = getPrefixedEthBlobCommitments(encodedData.blobs);
916
943
  this.log.debug('Validating blob input', { blobInput });
917
- const blobEvaluationGas = await this.l1TxUtils
918
- .estimateGas(
919
- this.getSenderAddress().toString(),
920
- {
921
- to: this.rollupContract.address,
922
- data: encodeFunctionData({
923
- abi: RollupAbi,
924
- functionName: 'validateBlobs',
925
- args: [blobInput],
926
- }),
927
- },
928
- {},
929
- {
930
- blobs: encodedData.blobs.map(b => b.data),
931
- kzg,
932
- },
933
- )
934
- .catch(err => {
935
- const { message, metaMessages } = formatViemError(err);
936
- this.log.error(`Failed to validate blobs`, message, { metaMessages });
937
- throw new Error('Failed to validate blobs');
938
- });
939
944
 
945
+ // Get blob evaluation gas
946
+ let blobEvaluationGas: bigint;
947
+ if (this.config.fishermanMode) {
948
+ // In fisherman mode, we can't estimate blob gas because estimateGas doesn't support state overrides
949
+ // Use a fixed estimate.
950
+ blobEvaluationGas = BigInt(encodedData.blobs.length) * 21_000n;
951
+ this.log.debug(`Using fixed blob evaluation gas estimate in fisherman mode: ${blobEvaluationGas}`);
952
+ } else {
953
+ // Normal mode - use estimateGas with blob inputs
954
+ blobEvaluationGas = await this.l1TxUtils
955
+ .estimateGas(
956
+ this.getSenderAddress().toString(),
957
+ {
958
+ to: this.rollupContract.address,
959
+ data: encodeFunctionData({
960
+ abi: RollupAbi,
961
+ functionName: 'validateBlobs',
962
+ args: [blobInput],
963
+ }),
964
+ },
965
+ {},
966
+ {
967
+ blobs: encodedData.blobs.map(b => b.data),
968
+ kzg,
969
+ },
970
+ )
971
+ .catch(err => {
972
+ const { message, metaMessages } = formatViemError(err);
973
+ this.log.error(`Failed to validate blobs`, message, { metaMessages });
974
+ throw new Error('Failed to validate blobs');
975
+ });
976
+ }
940
977
  const signers = encodedData.attestationsAndSigners.getSigners().map(signer => signer.toString());
941
978
 
942
979
  const args = [
943
980
  {
944
981
  header: encodedData.header.toViem(),
945
982
  archive: toHex(encodedData.archive),
946
- stateReference: encodedData.stateReference.toViem(),
947
983
  oracleInput: {
948
984
  // We are currently not modifying these. See #9963
949
985
  feeAssetPriceModifier: 0n,
@@ -971,7 +1007,6 @@ export class SequencerPublisher {
971
1007
  {
972
1008
  readonly header: ViemHeader;
973
1009
  readonly archive: `0x${string}`;
974
- readonly stateReference: ViemStateReference;
975
1010
  readonly oracleInput: {
976
1011
  readonly feeAssetPriceModifier: 0n;
977
1012
  };
@@ -993,16 +1028,35 @@ export class SequencerPublisher {
993
1028
  // override the pending block number if requested
994
1029
  const forcePendingBlockNumberStateDiff = (
995
1030
  options.forcePendingBlockNumber !== undefined
996
- ? await this.rollupContract.makePendingBlockNumberOverride(options.forcePendingBlockNumber)
1031
+ ? await this.rollupContract.makePendingCheckpointNumberOverride(options.forcePendingBlockNumber)
997
1032
  : []
998
1033
  ).flatMap(override => override.stateDiff ?? []);
999
1034
 
1035
+ const stateOverrides: StateOverride = [
1036
+ {
1037
+ address: this.rollupContract.address,
1038
+ // @note we override checkBlob to false since blobs are not part simulate()
1039
+ stateDiff: [
1040
+ { slot: toPaddedHex(RollupContract.checkBlobStorageSlot, true), value: toPaddedHex(0n, true) },
1041
+ ...forcePendingBlockNumberStateDiff,
1042
+ ],
1043
+ },
1044
+ ];
1045
+ // In fisherman mode, simulate as the proposer but with sufficient balance
1046
+ if (this.proposerAddressForSimulation) {
1047
+ stateOverrides.push({
1048
+ address: this.proposerAddressForSimulation.toString(),
1049
+ balance: 10n * WEI_CONST * WEI_CONST, // 10 ETH
1050
+ });
1051
+ }
1052
+
1000
1053
  const simulationResult = await this.l1TxUtils
1001
1054
  .simulate(
1002
1055
  {
1003
1056
  to: this.rollupContract.address,
1004
1057
  data: rollupData,
1005
1058
  gas: SequencerPublisher.PROPOSE_GAS_GUESS,
1059
+ ...(this.proposerAddressForSimulation && { from: this.proposerAddressForSimulation.toString() }),
1006
1060
  },
1007
1061
  {
1008
1062
  // @note we add 1n to the timestamp because geth implementation doesn't like simulation timestamp to be equal to the current block timestamp
@@ -1010,16 +1064,7 @@ export class SequencerPublisher {
1010
1064
  // @note reth should have a 30m gas limit per block but throws errors that this tx is beyond limit so we increase here
1011
1065
  gasLimit: SequencerPublisher.PROPOSE_GAS_GUESS * 2n,
1012
1066
  },
1013
- [
1014
- {
1015
- address: this.rollupContract.address,
1016
- // @note we override checkBlob to false since blobs are not part simulate()
1017
- stateDiff: [
1018
- { slot: toPaddedHex(RollupContract.checkBlobStorageSlot, true), value: toPaddedHex(0n, true) },
1019
- ...forcePendingBlockNumberStateDiff,
1020
- ],
1021
- },
1022
- ],
1067
+ stateOverrides,
1023
1068
  RollupAbi,
1024
1069
  {
1025
1070
  // @note fallback gas estimate to use if the node doesn't support simulation API
@@ -1027,7 +1072,17 @@ export class SequencerPublisher {
1027
1072
  },
1028
1073
  )
1029
1074
  .catch(err => {
1030
- this.log.error(`Failed to simulate propose tx`, err);
1075
+ // In fisherman mode, we expect ValidatorSelection__MissingProposerSignature since fisherman doesn't have proposer signature
1076
+ const viemError = formatViemError(err);
1077
+ if (this.config.fishermanMode && viemError.message?.includes('ValidatorSelection__MissingProposerSignature')) {
1078
+ this.log.debug(`Ignoring expected ValidatorSelection__MissingProposerSignature error in fisherman mode`);
1079
+ // Return a minimal simulation result with the fallback gas estimate
1080
+ return {
1081
+ gasUsed: SequencerPublisher.PROPOSE_GAS_GUESS,
1082
+ logs: [],
1083
+ };
1084
+ }
1085
+ this.log.error(`Failed to simulate propose tx`, viemError);
1031
1086
  throw err;
1032
1087
  });
1033
1088
 
@@ -1066,7 +1121,7 @@ export class SequencerPublisher {
1066
1121
  to: this.rollupContract.address,
1067
1122
  data: rollupData,
1068
1123
  },
1069
- lastValidL2Slot: block.header.globalVariables.slotNumber.toBigInt(),
1124
+ lastValidL2Slot: block.header.globalVariables.slotNumber,
1070
1125
  gasConfig: { ...opts, gasLimit },
1071
1126
  blobConfig: {
1072
1127
  blobs: encodedData.blobs.map(b => b.data),
@@ -1080,7 +1135,7 @@ export class SequencerPublisher {
1080
1135
  const success =
1081
1136
  receipt &&
1082
1137
  receipt.status === 'success' &&
1083
- tryExtractEvent(receipt.logs, this.rollupContract.address, RollupAbi, 'L2BlockProposed');
1138
+ tryExtractEvent(receipt.logs, this.rollupContract.address, RollupAbi, 'CheckpointProposed');
1084
1139
  if (success) {
1085
1140
  const endBlock = receipt.blockNumber;
1086
1141
  const inclusionBlocks = Number(endBlock - startBlock);
@@ -1109,7 +1164,7 @@ export class SequencerPublisher {
1109
1164
  ...block.getStats(),
1110
1165
  receipt,
1111
1166
  txHash: receipt.transactionHash,
1112
- slotNumber: block.header.globalVariables.slotNumber.toBigInt(),
1167
+ slotNumber: block.header.globalVariables.slotNumber,
1113
1168
  });
1114
1169
  return false;
1115
1170
  }
@@ -13,6 +13,7 @@ import {
13
13
  PublicProcessor,
14
14
  TelemetryPublicTxSimulator,
15
15
  } from '@aztec/simulator/server';
16
+ import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
16
17
  import type { ContractDataSource } from '@aztec/stdlib/contract';
17
18
  import { type L1RollupConstants, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
18
19
  import { Gas } from '@aztec/stdlib/gas';
@@ -46,7 +47,7 @@ export async function buildBlock(
46
47
  ): Promise<BuildBlockResult> {
47
48
  const blockBuildingTimer = new Timer();
48
49
  const blockNumber = newGlobalVariables.blockNumber;
49
- const slot = newGlobalVariables.slotNumber.toBigInt();
50
+ const slot = newGlobalVariables.slotNumber;
50
51
  const msgCount = l1ToL2Messages.length;
51
52
  const stateReference = await worldStateFork.getStateReference();
52
53
  const archiveTree = await worldStateFork.getTreeInfo(MerkleTreeId.ARCHIVE);
@@ -125,11 +126,14 @@ export class FullNodeBlockBuilder implements IFullNodeBlockBuilder {
125
126
  contractsDB,
126
127
  globalVariables,
127
128
  this.telemetryClient,
128
- {
129
- doMerkleOperations: true,
130
- skipFeeEnforcement: true,
131
- clientInitiatedSimulation: false,
132
- },
129
+ PublicSimulatorConfig.from({
130
+ skipFeeEnforcement: false,
131
+ collectDebugLogs: false,
132
+ collectHints: false,
133
+ maxDebugLogMemoryReads: 0,
134
+ collectStatistics: false,
135
+ collectCallMetadata: false,
136
+ }),
133
137
  );
134
138
 
135
139
  const processor = new PublicProcessor(
@@ -1,5 +1,6 @@
1
1
  import { EthAddress } from '@aztec/aztec.js/addresses';
2
2
  import type { RollupContract } from '@aztec/ethereum';
3
+ import type { SlotNumber } from '@aztec/foundation/branded-types';
3
4
  import {
4
5
  Attributes,
5
6
  type Gauge,
@@ -36,7 +37,12 @@ export class SequencerMetrics {
36
37
  private slots: UpDownCounter;
37
38
  private filledSlots: UpDownCounter;
38
39
 
39
- private lastSeenSlot?: bigint;
40
+ private blockProposalFailed: UpDownCounter;
41
+ private blockProposalSuccess: UpDownCounter;
42
+ private blockProposalPrecheckFailed: UpDownCounter;
43
+ private slashingAttempts: UpDownCounter;
44
+
45
+ private lastSeenSlot?: SlotNumber;
40
46
 
41
47
  constructor(
42
48
  client: TelemetryClient,
@@ -121,6 +127,29 @@ export class SequencerMetrics {
121
127
  valueType: ValueType.INT,
122
128
  description: 'The minimum number of attestations required to publish a block',
123
129
  });
130
+
131
+ this.blockProposalFailed = this.meter.createUpDownCounter(Metrics.SEQUENCER_BLOCK_PROPOSAL_FAILED_COUNT, {
132
+ valueType: ValueType.INT,
133
+ description: 'The number of times block proposal failed (including validation builds)',
134
+ });
135
+
136
+ this.blockProposalSuccess = this.meter.createUpDownCounter(Metrics.SEQUENCER_BLOCK_PROPOSAL_SUCCESS_COUNT, {
137
+ valueType: ValueType.INT,
138
+ description: 'The number of times block proposal succeeded (including validation builds)',
139
+ });
140
+
141
+ this.blockProposalPrecheckFailed = this.meter.createUpDownCounter(
142
+ Metrics.SEQUENCER_BLOCK_PROPOSAL_PRECHECK_FAILED_COUNT,
143
+ {
144
+ valueType: ValueType.INT,
145
+ description: 'The number of times block proposal pre-build checks failed',
146
+ },
147
+ );
148
+
149
+ this.slashingAttempts = this.meter.createUpDownCounter(Metrics.SEQUENCER_SLASHING_ATTEMPTS_COUNT, {
150
+ valueType: ValueType.INT,
151
+ description: 'The number of slashing action attempts',
152
+ });
124
153
  }
125
154
 
126
155
  public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
@@ -157,7 +186,7 @@ export class SequencerMetrics {
157
186
  });
158
187
  }
159
188
 
160
- incOpenSlot(slot: bigint, proposer: string) {
189
+ incOpenSlot(slot: SlotNumber, proposer: string) {
161
190
  // sequencer went through the loop a second time. Noop
162
191
  if (slot === this.lastSeenSlot) {
163
192
  return;
@@ -188,4 +217,24 @@ export class SequencerMetrics {
188
217
  }
189
218
  }
190
219
  }
220
+
221
+ recordBlockProposalFailed(reason?: string) {
222
+ this.blockProposalFailed.add(1, {
223
+ ...(reason && { [Attributes.ERROR_TYPE]: reason }),
224
+ });
225
+ }
226
+
227
+ recordBlockProposalSuccess() {
228
+ this.blockProposalSuccess.add(1);
229
+ }
230
+
231
+ recordBlockProposalPrecheckFailed(checkType: string) {
232
+ this.blockProposalPrecheckFailed.add(1, {
233
+ [Attributes.ERROR_TYPE]: checkType,
234
+ });
235
+ }
236
+
237
+ recordSlashingAttempt(actionCount: number) {
238
+ this.slashingAttempts.add(actionCount);
239
+ }
191
240
  }