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

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 (115) hide show
  1. package/dest/client/sequencer-client.d.ts +32 -16
  2. package/dest/client/sequencer-client.d.ts.map +1 -1
  3. package/dest/client/sequencer-client.js +118 -28
  4. package/dest/config.d.ts +33 -8
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +99 -44
  7. package/dest/global_variable_builder/global_builder.d.ts +20 -13
  8. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  9. package/dest/global_variable_builder/global_builder.js +51 -41
  10. package/dest/index.d.ts +2 -3
  11. package/dest/index.d.ts.map +1 -1
  12. package/dest/index.js +1 -2
  13. package/dest/publisher/config.d.ts +41 -20
  14. package/dest/publisher/config.d.ts.map +1 -1
  15. package/dest/publisher/config.js +109 -39
  16. package/dest/publisher/index.d.ts +2 -1
  17. package/dest/publisher/index.d.ts.map +1 -1
  18. package/dest/publisher/l1_tx_failed_store/factory.d.ts +11 -0
  19. package/dest/publisher/l1_tx_failed_store/factory.d.ts.map +1 -0
  20. package/dest/publisher/l1_tx_failed_store/factory.js +22 -0
  21. package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +59 -0
  22. package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +1 -0
  23. package/dest/publisher/l1_tx_failed_store/failed_tx_store.js +1 -0
  24. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts +15 -0
  25. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts.map +1 -0
  26. package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.js +34 -0
  27. package/dest/publisher/l1_tx_failed_store/index.d.ts +4 -0
  28. package/dest/publisher/l1_tx_failed_store/index.d.ts.map +1 -0
  29. package/dest/publisher/l1_tx_failed_store/index.js +2 -0
  30. package/dest/publisher/sequencer-publisher-factory.d.ts +15 -6
  31. package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
  32. package/dest/publisher/sequencer-publisher-factory.js +28 -3
  33. package/dest/publisher/sequencer-publisher-metrics.d.ts +3 -3
  34. package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
  35. package/dest/publisher/sequencer-publisher-metrics.js +23 -86
  36. package/dest/publisher/sequencer-publisher.d.ts +73 -47
  37. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  38. package/dest/publisher/sequencer-publisher.js +888 -146
  39. package/dest/sequencer/checkpoint_proposal_job.d.ts +100 -0
  40. package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -0
  41. package/dest/sequencer/checkpoint_proposal_job.js +1244 -0
  42. package/dest/sequencer/checkpoint_voter.d.ts +35 -0
  43. package/dest/sequencer/checkpoint_voter.d.ts.map +1 -0
  44. package/dest/sequencer/checkpoint_voter.js +109 -0
  45. package/dest/sequencer/config.d.ts +3 -2
  46. package/dest/sequencer/config.d.ts.map +1 -1
  47. package/dest/sequencer/events.d.ts +46 -0
  48. package/dest/sequencer/events.d.ts.map +1 -0
  49. package/dest/sequencer/events.js +1 -0
  50. package/dest/sequencer/index.d.ts +4 -2
  51. package/dest/sequencer/index.d.ts.map +1 -1
  52. package/dest/sequencer/index.js +3 -1
  53. package/dest/sequencer/metrics.d.ts +38 -6
  54. package/dest/sequencer/metrics.d.ts.map +1 -1
  55. package/dest/sequencer/metrics.js +216 -72
  56. package/dest/sequencer/sequencer.d.ts +122 -133
  57. package/dest/sequencer/sequencer.d.ts.map +1 -1
  58. package/dest/sequencer/sequencer.js +717 -625
  59. package/dest/sequencer/timetable.d.ts +54 -16
  60. package/dest/sequencer/timetable.d.ts.map +1 -1
  61. package/dest/sequencer/timetable.js +147 -62
  62. package/dest/sequencer/types.d.ts +6 -0
  63. package/dest/sequencer/types.d.ts.map +1 -0
  64. package/dest/sequencer/types.js +1 -0
  65. package/dest/sequencer/utils.d.ts +14 -8
  66. package/dest/sequencer/utils.d.ts.map +1 -1
  67. package/dest/sequencer/utils.js +7 -4
  68. package/dest/test/index.d.ts +6 -7
  69. package/dest/test/index.d.ts.map +1 -1
  70. package/dest/test/mock_checkpoint_builder.d.ts +95 -0
  71. package/dest/test/mock_checkpoint_builder.d.ts.map +1 -0
  72. package/dest/test/mock_checkpoint_builder.js +231 -0
  73. package/dest/test/utils.d.ts +53 -0
  74. package/dest/test/utils.d.ts.map +1 -0
  75. package/dest/test/utils.js +104 -0
  76. package/package.json +32 -30
  77. package/src/client/sequencer-client.ts +158 -52
  78. package/src/config.ts +114 -54
  79. package/src/global_variable_builder/global_builder.ts +65 -61
  80. package/src/index.ts +1 -7
  81. package/src/publisher/config.ts +131 -50
  82. package/src/publisher/index.ts +3 -0
  83. package/src/publisher/l1_tx_failed_store/factory.ts +32 -0
  84. package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +55 -0
  85. package/src/publisher/l1_tx_failed_store/file_store_failed_tx_store.ts +46 -0
  86. package/src/publisher/l1_tx_failed_store/index.ts +3 -0
  87. package/src/publisher/sequencer-publisher-factory.ts +43 -10
  88. package/src/publisher/sequencer-publisher-metrics.ts +19 -71
  89. package/src/publisher/sequencer-publisher.ts +587 -191
  90. package/src/sequencer/README.md +531 -0
  91. package/src/sequencer/checkpoint_proposal_job.ts +960 -0
  92. package/src/sequencer/checkpoint_voter.ts +130 -0
  93. package/src/sequencer/config.ts +2 -1
  94. package/src/sequencer/events.ts +27 -0
  95. package/src/sequencer/index.ts +3 -1
  96. package/src/sequencer/metrics.ts +268 -82
  97. package/src/sequencer/sequencer.ts +464 -831
  98. package/src/sequencer/timetable.ts +178 -83
  99. package/src/sequencer/types.ts +9 -0
  100. package/src/sequencer/utils.ts +18 -9
  101. package/src/test/index.ts +5 -6
  102. package/src/test/mock_checkpoint_builder.ts +323 -0
  103. package/src/test/utils.ts +167 -0
  104. package/dest/sequencer/block_builder.d.ts +0 -27
  105. package/dest/sequencer/block_builder.d.ts.map +0 -1
  106. package/dest/sequencer/block_builder.js +0 -134
  107. package/dest/tx_validator/nullifier_cache.d.ts +0 -14
  108. package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
  109. package/dest/tx_validator/nullifier_cache.js +0 -24
  110. package/dest/tx_validator/tx_validator_factory.d.ts +0 -17
  111. package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
  112. package/dest/tx_validator/tx_validator_factory.js +0 -53
  113. package/src/sequencer/block_builder.ts +0 -222
  114. package/src/tx_validator/nullifier_cache.ts +0 -30
  115. package/src/tx_validator/tx_validator_factory.ts +0 -132
@@ -1,45 +1,45 @@
1
- import type { BlobSinkClientInterface } from '@aztec/blob-sink/client';
1
+ import type { BlobClientInterface } from '@aztec/blob-client/client';
2
+ import { MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT } from '@aztec/constants';
2
3
  import { EpochCache } from '@aztec/epoch-cache';
3
- import {
4
- GovernanceProposerContract,
5
- PublisherManager,
6
- RollupContract,
7
- getPublicClient,
8
- isAnvilTestChain,
9
- } from '@aztec/ethereum';
10
- import { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
4
+ import { isAnvilTestChain } from '@aztec/ethereum/chain';
5
+ import { getPublicClient } from '@aztec/ethereum/client';
6
+ import { GovernanceProposerContract, RollupContract } from '@aztec/ethereum/contracts';
7
+ import { type Delayer, L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
8
+ import { PublisherManager } from '@aztec/ethereum/publisher-manager';
11
9
  import { EthAddress } from '@aztec/foundation/eth-address';
12
10
  import { createLogger } from '@aztec/foundation/log';
13
11
  import type { DateProvider } from '@aztec/foundation/timer';
14
12
  import type { KeystoreManager } from '@aztec/node-keystore';
15
13
  import type { P2P } from '@aztec/p2p';
16
14
  import type { SlasherClientInterface } from '@aztec/slasher';
17
- import type { L2BlockSource } from '@aztec/stdlib/block';
18
- import type {
19
- IFullNodeBlockBuilder,
20
- ValidatorClientFullConfig,
21
- WorldStateSynchronizer,
22
- } from '@aztec/stdlib/interfaces/server';
15
+ import type { L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
16
+ import type { ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
23
17
  import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
24
18
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
25
19
  import { L1Metrics, type TelemetryClient } from '@aztec/telemetry-client';
26
- import { NodeKeystoreAdapter, type ValidatorClient } from '@aztec/validator-client';
20
+ import { FullNodeCheckpointsBuilder, NodeKeystoreAdapter, type ValidatorClient } from '@aztec/validator-client';
27
21
 
28
- import type { SequencerClientConfig } from '../config.js';
22
+ import {
23
+ DefaultSequencerConfig,
24
+ type SequencerClientConfig,
25
+ getPublisherConfigFromSequencerConfig,
26
+ } from '../config.js';
29
27
  import { GlobalVariableBuilder } from '../global_variable_builder/index.js';
30
28
  import { SequencerPublisherFactory } from '../publisher/sequencer-publisher-factory.js';
31
29
  import { Sequencer, type SequencerConfig } from '../sequencer/index.js';
30
+ import { SequencerTimetable } from '../sequencer/timetable.js';
32
31
 
33
32
  /**
34
33
  * Encapsulates the full sequencer and publisher.
35
34
  */
36
35
  export class SequencerClient {
37
36
  constructor(
38
- protected publisherManager: PublisherManager<L1TxUtilsWithBlobs>,
37
+ protected publisherManager: PublisherManager<L1TxUtils>,
39
38
  protected sequencer: Sequencer,
40
- protected blockBuilder: IFullNodeBlockBuilder,
39
+ protected checkpointsBuilder: FullNodeCheckpointsBuilder,
41
40
  protected validatorClient?: ValidatorClient,
42
41
  private l1Metrics?: L1Metrics,
42
+ private delayer_?: Delayer,
43
43
  ) {}
44
44
 
45
45
  /**
@@ -57,19 +57,19 @@ export class SequencerClient {
57
57
  public static async new(
58
58
  config: SequencerClientConfig,
59
59
  deps: {
60
- validatorClient: ValidatorClient | undefined; // allowed to be undefined while we migrate
60
+ validatorClient: ValidatorClient;
61
61
  p2pClient: P2P;
62
62
  worldStateSynchronizer: WorldStateSynchronizer;
63
63
  slasherClient: SlasherClientInterface | undefined;
64
- blockBuilder: IFullNodeBlockBuilder;
65
- l2BlockSource: L2BlockSource;
64
+ checkpointsBuilder: FullNodeCheckpointsBuilder;
65
+ l2BlockSource: L2BlockSource & L2BlockSink;
66
66
  l1ToL2MessageSource: L1ToL2MessageSource;
67
67
  telemetry: TelemetryClient;
68
68
  publisherFactory?: SequencerPublisherFactory;
69
- blobSinkClient?: BlobSinkClientInterface;
69
+ blobClient: BlobClientInterface;
70
70
  dateProvider: DateProvider;
71
71
  epochCache?: EpochCache;
72
- l1TxUtils: L1TxUtilsWithBlobs[];
72
+ l1TxUtils: L1TxUtils[];
73
73
  nodeKeyStore: KeystoreManager;
74
74
  },
75
75
  ) {
@@ -78,7 +78,7 @@ export class SequencerClient {
78
78
  p2pClient,
79
79
  worldStateSynchronizer,
80
80
  slasherClient,
81
- blockBuilder,
81
+ checkpointsBuilder,
82
82
  l2BlockSource,
83
83
  l1ToL2MessageSource,
84
84
  telemetry: telemetryClient,
@@ -92,11 +92,17 @@ export class SequencerClient {
92
92
  publicClient,
93
93
  l1TxUtils.map(x => x.getSenderAddress()),
94
94
  );
95
- const publisherManager = new PublisherManager(l1TxUtils, config);
95
+ const publisherManager = new PublisherManager(
96
+ l1TxUtils,
97
+ getPublisherConfigFromSequencerConfig(config),
98
+ log.getBindings(),
99
+ );
96
100
  const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
97
- const [l1GenesisTime, slotDuration] = await Promise.all([
101
+ const [l1GenesisTime, slotDuration, rollupVersion, rollupManaLimit] = await Promise.all([
98
102
  rollupContract.getL1GenesisTime(),
99
103
  rollupContract.getSlotDuration(),
104
+ rollupContract.getVersion(),
105
+ rollupContract.getManaLimit().then(Number),
100
106
  ] as const);
101
107
 
102
108
  const governanceProposerContract = new GovernanceProposerContract(
@@ -125,7 +131,7 @@ export class SequencerClient {
125
131
  deps.publisherFactory ??
126
132
  new SequencerPublisherFactory(config, {
127
133
  telemetry: telemetryClient,
128
- blobSinkClient: deps.blobSinkClient,
134
+ blobClient: deps.blobClient,
129
135
  epochCache,
130
136
  governanceProposerContract,
131
137
  slashFactoryContract,
@@ -135,33 +141,33 @@ export class SequencerClient {
135
141
  nodeKeyStore: NodeKeystoreAdapter.fromKeyStoreManager(deps.nodeKeyStore),
136
142
  logger: log,
137
143
  });
138
- const globalsBuilder = new GlobalVariableBuilder(config);
139
144
 
140
145
  const ethereumSlotDuration = config.ethereumSlotDuration;
141
146
 
142
- const rollupManaLimit = Number(await rollupContract.getManaLimit());
143
- let sequencerManaLimit = config.maxL2BlockGas ?? rollupManaLimit;
144
- if (sequencerManaLimit > rollupManaLimit) {
145
- log.warn(
146
- `Provided maxL2BlockGas of ${sequencerManaLimit} is greater than the maximum allowed by the L1 (${rollupManaLimit}), setting limit to ${rollupManaLimit}`,
147
- );
148
- sequencerManaLimit = rollupManaLimit;
149
- }
147
+ const globalsBuilder = new GlobalVariableBuilder({
148
+ ...config,
149
+ l1GenesisTime,
150
+ slotDuration: Number(slotDuration),
151
+ ethereumSlotDuration,
152
+ rollupVersion,
153
+ });
150
154
 
151
155
  // When running in anvil, assume we can post a tx up until one second before the end of an L1 slot.
152
- // Otherwise, assume we must have broadcasted the tx before the slot started (we use a default
153
- // maxL1TxInclusionTimeIntoSlot of zero) to get the tx into that L1 slot.
156
+ // Otherwise, we need the full L1 slot duration for publishing to ensure inclusion.
154
157
  // In theory, the L1 slot has an initial 4s phase where the block is propagated, so we could
155
- // make it with a propagation time into slot equal to 4s. However, we prefer being conservative.
158
+ // reduce the publishing time allowance. However, we prefer being conservative.
156
159
  // See https://www.blocknative.com/blog/anatomy-of-a-slot#7 for more info.
157
- const maxInclusionBasedOnChain = isAnvilTestChain(config.l1ChainId) ? ethereumSlotDuration - 1 : 0;
158
- const maxL1TxInclusionTimeIntoSlot = config.maxL1TxInclusionTimeIntoSlot ?? maxInclusionBasedOnChain;
160
+ const l1PublishingTimeBasedOnChain = isAnvilTestChain(config.l1ChainId) ? 1 : ethereumSlotDuration;
161
+ const l1PublishingTime = config.l1PublishingTime ?? l1PublishingTimeBasedOnChain;
159
162
 
160
- const l1Constants = {
161
- l1GenesisTime,
162
- slotDuration: Number(slotDuration),
163
- ethereumSlotDuration,
164
- };
163
+ const { maxL2BlockGas, maxDABlockGas, maxTxsPerBlock } = computeBlockLimits(
164
+ config,
165
+ rollupManaLimit,
166
+ l1PublishingTime,
167
+ log,
168
+ );
169
+
170
+ const l1Constants = { l1GenesisTime, slotDuration: Number(slotDuration), ethereumSlotDuration, rollupManaLimit };
165
171
 
166
172
  const sequencer = new Sequencer(
167
173
  publisherFactory,
@@ -172,19 +178,22 @@ export class SequencerClient {
172
178
  slasherClient,
173
179
  l2BlockSource,
174
180
  l1ToL2MessageSource,
175
- blockBuilder,
181
+ checkpointsBuilder,
176
182
  l1Constants,
177
183
  deps.dateProvider,
178
184
  epochCache,
179
185
  rollupContract,
180
- { ...config, maxL1TxInclusionTimeIntoSlot, maxL2BlockGas: sequencerManaLimit },
186
+ { ...config, l1PublishingTime, maxL2BlockGas, maxDABlockGas, maxTxsPerBlock },
181
187
  telemetryClient,
182
188
  log,
183
189
  );
184
190
 
185
- await sequencer.init();
191
+ sequencer.init();
192
+
193
+ // Extract the shared delayer from the first L1TxUtils instance (all instances share the same delayer)
194
+ const delayer = l1TxUtils[0]?.delayer;
186
195
 
187
- return new SequencerClient(publisherManager, sequencer, blockBuilder, validatorClient, l1Metrics);
196
+ return new SequencerClient(publisherManager, sequencer, checkpointsBuilder, validatorClient, l1Metrics, delayer);
188
197
  }
189
198
 
190
199
  /**
@@ -193,7 +202,7 @@ export class SequencerClient {
193
202
  */
194
203
  public updateConfig(config: SequencerConfig & Partial<ValidatorClientFullConfig>) {
195
204
  this.sequencer.updateConfig(config);
196
- this.blockBuilder.updateConfig(config);
205
+ this.checkpointsBuilder.updateConfig(config);
197
206
  this.validatorClient?.updateConfig(config);
198
207
  }
199
208
 
@@ -219,6 +228,16 @@ export class SequencerClient {
219
228
  return this.sequencer;
220
229
  }
221
230
 
231
+ /** Updates the publisher factory's node keystore adapter after a keystore reload. */
232
+ public updatePublisherNodeKeyStore(adapter: NodeKeystoreAdapter): void {
233
+ this.sequencer.updatePublisherNodeKeyStore(adapter);
234
+ }
235
+
236
+ /** Returns the shared tx delayer for sequencer L1 txs, if enabled. Test-only. */
237
+ getDelayer(): Delayer | undefined {
238
+ return this.delayer_;
239
+ }
240
+
222
241
  get validatorAddresses(): EthAddress[] | undefined {
223
242
  return this.sequencer.getValidatorAddresses();
224
243
  }
@@ -227,3 +246,90 @@ export class SequencerClient {
227
246
  return this.sequencer.maxL2BlockGas;
228
247
  }
229
248
  }
249
+
250
+ /**
251
+ * Computes per-block L2 gas, DA gas, and TX count budgets based on the L1 rollup limits and the timetable.
252
+ * If the user explicitly set a limit, it is capped at the corresponding checkpoint limit.
253
+ * Otherwise, derives it as (checkpointLimit / maxBlocks) * multiplier, capped at the checkpoint limit.
254
+ */
255
+ export function computeBlockLimits(
256
+ config: SequencerClientConfig,
257
+ rollupManaLimit: number,
258
+ l1PublishingTime: number,
259
+ log: ReturnType<typeof createLogger>,
260
+ ): { maxL2BlockGas: number; maxDABlockGas: number; maxTxsPerBlock: number } {
261
+ const maxNumberOfBlocks = new SequencerTimetable({
262
+ ethereumSlotDuration: config.ethereumSlotDuration,
263
+ aztecSlotDuration: config.aztecSlotDuration,
264
+ l1PublishingTime,
265
+ p2pPropagationTime: config.attestationPropagationTime,
266
+ blockDurationMs: config.blockDurationMs,
267
+ enforce: config.enforceTimeTable ?? DefaultSequencerConfig.enforceTimeTable,
268
+ }).maxNumberOfBlocks;
269
+
270
+ const multiplier = config.perBlockAllocationMultiplier ?? DefaultSequencerConfig.perBlockAllocationMultiplier;
271
+
272
+ // Compute maxL2BlockGas
273
+ let maxL2BlockGas: number;
274
+ if (config.maxL2BlockGas !== undefined) {
275
+ if (config.maxL2BlockGas > rollupManaLimit) {
276
+ log.warn(
277
+ `Provided MAX_L2_BLOCK_GAS ${config.maxL2BlockGas} exceeds L1 rollup mana limit ${rollupManaLimit} (capping)`,
278
+ );
279
+ maxL2BlockGas = rollupManaLimit;
280
+ } else {
281
+ maxL2BlockGas = config.maxL2BlockGas;
282
+ }
283
+ } else {
284
+ maxL2BlockGas = Math.min(rollupManaLimit, Math.ceil((rollupManaLimit / maxNumberOfBlocks) * multiplier));
285
+ }
286
+
287
+ // Compute maxDABlockGas
288
+ const daCheckpointLimit = MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT;
289
+ let maxDABlockGas: number;
290
+ if (config.maxDABlockGas !== undefined) {
291
+ if (config.maxDABlockGas > daCheckpointLimit) {
292
+ log.warn(
293
+ `Provided MAX_DA_BLOCK_GAS ${config.maxDABlockGas} exceeds DA checkpoint limit ${daCheckpointLimit} (capping)`,
294
+ );
295
+ maxDABlockGas = daCheckpointLimit;
296
+ } else {
297
+ maxDABlockGas = config.maxDABlockGas;
298
+ }
299
+ } else {
300
+ maxDABlockGas = Math.min(daCheckpointLimit, Math.ceil((daCheckpointLimit / maxNumberOfBlocks) * multiplier));
301
+ }
302
+
303
+ // Compute maxTxsPerBlock
304
+ const defaultMaxTxsPerBlock = 32;
305
+ let maxTxsPerBlock: number;
306
+ if (config.maxTxsPerBlock !== undefined) {
307
+ if (config.maxTxsPerCheckpoint !== undefined && config.maxTxsPerBlock > config.maxTxsPerCheckpoint) {
308
+ log.warn(
309
+ `Provided MAX_TX_PER_BLOCK ${config.maxTxsPerBlock} exceeds MAX_TX_PER_CHECKPOINT ${config.maxTxsPerCheckpoint} (capping)`,
310
+ );
311
+ maxTxsPerBlock = config.maxTxsPerCheckpoint;
312
+ } else {
313
+ maxTxsPerBlock = config.maxTxsPerBlock;
314
+ }
315
+ } else if (config.maxTxsPerCheckpoint !== undefined) {
316
+ maxTxsPerBlock = Math.min(
317
+ config.maxTxsPerCheckpoint,
318
+ Math.ceil((config.maxTxsPerCheckpoint / maxNumberOfBlocks) * multiplier),
319
+ );
320
+ } else {
321
+ maxTxsPerBlock = defaultMaxTxsPerBlock;
322
+ }
323
+
324
+ log.info(`Computed block limits L2=${maxL2BlockGas} DA=${maxDABlockGas} maxTxs=${maxTxsPerBlock}`, {
325
+ maxL2BlockGas,
326
+ maxDABlockGas,
327
+ maxTxsPerBlock,
328
+ rollupManaLimit,
329
+ daCheckpointLimit,
330
+ maxNumberOfBlocks,
331
+ multiplier,
332
+ });
333
+
334
+ return { maxL2BlockGas, maxDABlockGas, maxTxsPerBlock };
335
+ }
package/src/config.ts CHANGED
@@ -1,9 +1,5 @@
1
- import {
2
- type L1ContractsConfig,
3
- type L1ReaderConfig,
4
- l1ContractsConfigMappings,
5
- l1ReaderConfigMappings,
6
- } from '@aztec/ethereum';
1
+ import { type L1ContractsConfig, l1ContractsConfigMappings } from '@aztec/ethereum/config';
2
+ import { type L1ReaderConfig, l1ReaderConfigMappings } from '@aztec/ethereum/l1-reader';
7
3
  import {
8
4
  type ConfigMappingsType,
9
5
  booleanConfigHelper,
@@ -12,67 +8,109 @@ import {
12
8
  pickConfigMappings,
13
9
  } from '@aztec/foundation/config';
14
10
  import { EthAddress } from '@aztec/foundation/eth-address';
15
- import { type KeyStoreConfig, keyStoreConfigMappings } from '@aztec/node-keystore';
16
- import { type P2PConfig, p2pConfigMappings } from '@aztec/p2p';
11
+ import { type KeyStoreConfig, keyStoreConfigMappings } from '@aztec/node-keystore/config';
12
+ import { type P2PConfig, p2pConfigMappings } from '@aztec/p2p/config';
17
13
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
18
- import { type ChainConfig, type SequencerConfig, chainConfigMappings } from '@aztec/stdlib/config';
19
- import { type ValidatorClientConfig, validatorClientConfigMappings } from '@aztec/validator-client';
14
+ import {
15
+ type ChainConfig,
16
+ type SequencerConfig,
17
+ chainConfigMappings,
18
+ sharedSequencerConfigMappings,
19
+ } from '@aztec/stdlib/config';
20
+ import type { ResolvedSequencerConfig } from '@aztec/stdlib/interfaces/server';
21
+ import { DEFAULT_P2P_PROPAGATION_TIME } from '@aztec/stdlib/timetable';
22
+ import { type ValidatorClientConfig, validatorClientConfigMappings } from '@aztec/validator-client/config';
20
23
 
21
24
  import {
22
- type PublisherConfig,
23
- type TxSenderConfig,
24
- getPublisherConfigMappings,
25
- getTxSenderConfigMappings,
25
+ type SequencerPublisherConfig,
26
+ type SequencerTxSenderConfig,
27
+ sequencerPublisherConfigMappings,
28
+ sequencerTxSenderConfigMappings,
26
29
  } from './publisher/config.js';
27
30
 
28
31
  export * from './publisher/config.js';
29
32
  export type { SequencerConfig };
30
33
 
31
- export const DEFAULT_ATTESTATION_PROPAGATION_TIME = 2;
34
+ /**
35
+ * Default values for SequencerConfig.
36
+ * Centralized location for all sequencer configuration defaults.
37
+ */
38
+ export const DefaultSequencerConfig = {
39
+ sequencerPollingIntervalMS: 500,
40
+ minTxsPerBlock: 1,
41
+ buildCheckpointIfEmpty: false,
42
+ publishTxsWithProposals: false,
43
+ perBlockAllocationMultiplier: 2,
44
+ enforceTimeTable: true,
45
+ attestationPropagationTime: DEFAULT_P2P_PROPAGATION_TIME,
46
+ secondsBeforeInvalidatingBlockAsCommitteeMember: 144, // 12 L1 blocks
47
+ secondsBeforeInvalidatingBlockAsNonCommitteeMember: 432, // 36 L1 blocks
48
+ skipCollectingAttestations: false,
49
+ skipInvalidateBlockAsProposer: false,
50
+ broadcastInvalidBlockProposal: false,
51
+ injectFakeAttestation: false,
52
+ injectHighSValueAttestation: false,
53
+ injectUnrecoverableSignatureAttestation: false,
54
+ fishermanMode: false,
55
+ shuffleAttestationOrdering: false,
56
+ skipPushProposedBlocksToArchiver: false,
57
+ skipPublishingCheckpointsPercent: 0,
58
+ } satisfies ResolvedSequencerConfig;
32
59
 
33
60
  /**
34
61
  * Configuration settings for the SequencerClient.
35
62
  */
36
- export type SequencerClientConfig = PublisherConfig &
63
+ export type SequencerClientConfig = SequencerPublisherConfig &
37
64
  KeyStoreConfig &
38
65
  ValidatorClientConfig &
39
- TxSenderConfig &
66
+ SequencerTxSenderConfig &
40
67
  SequencerConfig &
41
68
  L1ReaderConfig &
42
69
  ChainConfig &
43
- Pick<P2PConfig, 'txPublicSetupAllowList'> &
70
+ Pick<P2PConfig, 'txPublicSetupAllowListExtend'> &
44
71
  Pick<L1ContractsConfig, 'ethereumSlotDuration' | 'aztecSlotDuration' | 'aztecEpochDuration'>;
45
72
 
46
73
  export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
47
- transactionPollingIntervalMS: {
48
- env: 'SEQ_TX_POLLING_INTERVAL_MS',
49
- description: 'The number of ms to wait between polling for pending txs.',
50
- ...numberConfigHelper(500),
51
- },
52
- maxTxsPerBlock: {
53
- env: 'SEQ_MAX_TX_PER_BLOCK',
54
- description: 'The maximum number of txs to include in a block.',
55
- ...numberConfigHelper(32),
74
+ sequencerPollingIntervalMS: {
75
+ env: 'SEQ_POLLING_INTERVAL_MS',
76
+ description: 'The number of ms to wait between polling for checking to build on the next slot.',
77
+ ...numberConfigHelper(DefaultSequencerConfig.sequencerPollingIntervalMS),
78
+ },
79
+ maxTxsPerCheckpoint: {
80
+ env: 'SEQ_MAX_TX_PER_CHECKPOINT',
81
+ description: 'The maximum number of txs across all blocks in a checkpoint.',
82
+ parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
56
83
  },
57
84
  minTxsPerBlock: {
58
85
  env: 'SEQ_MIN_TX_PER_BLOCK',
59
86
  description: 'The minimum number of txs to include in a block.',
60
- ...numberConfigHelper(1),
87
+ ...numberConfigHelper(DefaultSequencerConfig.minTxsPerBlock),
88
+ },
89
+ minValidTxsPerBlock: {
90
+ description:
91
+ 'The minimum number of valid txs (after execution) to include in a block. If not set, falls back to minTxsPerBlock.',
61
92
  },
62
93
  publishTxsWithProposals: {
63
94
  env: 'SEQ_PUBLISH_TXS_WITH_PROPOSALS',
64
95
  description: 'Whether to publish txs with proposals.',
65
- ...booleanConfigHelper(false),
96
+ ...booleanConfigHelper(DefaultSequencerConfig.publishTxsWithProposals),
66
97
  },
67
98
  maxL2BlockGas: {
68
99
  env: 'SEQ_MAX_L2_BLOCK_GAS',
69
100
  description: 'The maximum L2 block gas.',
70
- ...numberConfigHelper(10e9),
101
+ parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
71
102
  },
72
103
  maxDABlockGas: {
73
104
  env: 'SEQ_MAX_DA_BLOCK_GAS',
74
105
  description: 'The maximum DA block gas.',
75
- ...numberConfigHelper(10e9),
106
+ parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
107
+ },
108
+ perBlockAllocationMultiplier: {
109
+ env: 'SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER',
110
+ description:
111
+ 'Per-block gas budget multiplier for both L2 and DA gas. Budget per block is (checkpointLimit / maxBlocks) * multiplier.' +
112
+ ' Values greater than one allow early blocks to use more than their even share, relying on checkpoint-level capping for later blocks.',
113
+ ...numberConfigHelper(DefaultSequencerConfig.perBlockAllocationMultiplier),
76
114
  },
77
115
  coinbase: {
78
116
  env: 'COINBASE',
@@ -92,78 +130,100 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
92
130
  env: 'ACVM_BINARY_PATH',
93
131
  description: 'The path to the ACVM binary',
94
132
  },
95
- maxBlockSizeInBytes: {
96
- env: 'SEQ_MAX_BLOCK_SIZE_IN_BYTES',
97
- description: 'Max block size',
98
- ...numberConfigHelper(1024 * 1024),
99
- },
100
133
  enforceTimeTable: {
101
134
  env: 'SEQ_ENFORCE_TIME_TABLE',
102
135
  description: 'Whether to enforce the time table when building blocks',
103
- ...booleanConfigHelper(),
104
- defaultValue: true,
136
+ ...booleanConfigHelper(DefaultSequencerConfig.enforceTimeTable),
105
137
  },
106
138
  governanceProposerPayload: {
107
139
  env: 'GOVERNANCE_PROPOSER_PAYLOAD_ADDRESS',
108
140
  description: 'The address of the payload for the governanceProposer',
109
141
  parseEnv: (val: string) => EthAddress.fromString(val),
110
- defaultValue: EthAddress.ZERO,
111
142
  },
112
- maxL1TxInclusionTimeIntoSlot: {
113
- env: 'SEQ_MAX_L1_TX_INCLUSION_TIME_INTO_SLOT',
114
- description: 'How many seconds into an L1 slot we can still send a tx and get it mined.',
143
+ l1PublishingTime: {
144
+ env: 'SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT',
145
+ description: 'How much time (in seconds) we allow in the slot for publishing the L1 tx (defaults to 1 L1 slot).',
115
146
  parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
116
147
  },
117
148
  attestationPropagationTime: {
118
149
  env: 'SEQ_ATTESTATION_PROPAGATION_TIME',
119
150
  description: 'How many seconds it takes for proposals and attestations to travel across the p2p layer (one-way)',
120
- ...numberConfigHelper(DEFAULT_ATTESTATION_PROPAGATION_TIME),
151
+ ...numberConfigHelper(DefaultSequencerConfig.attestationPropagationTime),
121
152
  },
122
153
  fakeProcessingDelayPerTxMs: {
123
154
  description: 'Used for testing to introduce a fake delay after processing each tx',
124
155
  },
156
+ fakeThrowAfterProcessingTxCount: {
157
+ description: 'Used for testing to throw an error after processing N txs',
158
+ },
125
159
  secondsBeforeInvalidatingBlockAsCommitteeMember: {
126
160
  env: 'SEQ_SECONDS_BEFORE_INVALIDATING_BLOCK_AS_COMMITTEE_MEMBER',
127
161
  description:
128
162
  'How many seconds to wait before trying to invalidate a block from the pending chain as a committee member (zero to never invalidate).' +
129
163
  ' The next proposer is expected to invalidate, so the committee acts as a fallback.',
130
- ...numberConfigHelper(144), // 12 L1 blocks
164
+ ...numberConfigHelper(DefaultSequencerConfig.secondsBeforeInvalidatingBlockAsCommitteeMember),
131
165
  },
132
166
  secondsBeforeInvalidatingBlockAsNonCommitteeMember: {
133
167
  env: 'SEQ_SECONDS_BEFORE_INVALIDATING_BLOCK_AS_NON_COMMITTEE_MEMBER',
134
168
  description:
135
169
  'How many seconds to wait before trying to invalidate a block from the pending chain as a non-committee member (zero to never invalidate).' +
136
170
  ' The next proposer is expected to invalidate, then the committee, so other sequencers act as a fallback.',
137
- ...numberConfigHelper(432), // 36 L1 blocks
171
+ ...numberConfigHelper(DefaultSequencerConfig.secondsBeforeInvalidatingBlockAsNonCommitteeMember),
138
172
  },
139
173
  skipCollectingAttestations: {
140
174
  description:
141
175
  'Whether to skip collecting attestations from validators and only use self-attestations (for testing only)',
142
- ...booleanConfigHelper(false),
176
+ ...booleanConfigHelper(DefaultSequencerConfig.skipCollectingAttestations),
143
177
  },
144
178
  skipInvalidateBlockAsProposer: {
145
179
  description: 'Do not invalidate the previous block if invalid when we are the proposer (for testing only)',
146
- ...booleanConfigHelper(false),
180
+ ...booleanConfigHelper(DefaultSequencerConfig.skipInvalidateBlockAsProposer),
147
181
  },
148
182
  broadcastInvalidBlockProposal: {
149
183
  description: 'Broadcast invalid block proposals with corrupted state (for testing only)',
150
- ...booleanConfigHelper(false),
184
+ ...booleanConfigHelper(DefaultSequencerConfig.broadcastInvalidBlockProposal),
151
185
  },
152
186
  injectFakeAttestation: {
153
187
  description: 'Inject a fake attestation (for testing only)',
154
- ...booleanConfigHelper(false),
188
+ ...booleanConfigHelper(DefaultSequencerConfig.injectFakeAttestation),
189
+ },
190
+ injectHighSValueAttestation: {
191
+ description: 'Inject a malleable attestation with a high-s value (for testing only)',
192
+ ...booleanConfigHelper(DefaultSequencerConfig.injectHighSValueAttestation),
193
+ },
194
+ injectUnrecoverableSignatureAttestation: {
195
+ description: 'Inject an attestation with an unrecoverable signature (for testing only)',
196
+ ...booleanConfigHelper(DefaultSequencerConfig.injectUnrecoverableSignatureAttestation),
155
197
  },
156
198
  fishermanMode: {
157
199
  env: 'FISHERMAN_MODE',
158
200
  description:
159
201
  'Whether to run in fisherman mode: builds blocks on every slot for validation without publishing to L1',
160
- ...booleanConfigHelper(false),
202
+ ...booleanConfigHelper(DefaultSequencerConfig.fishermanMode),
161
203
  },
162
204
  shuffleAttestationOrdering: {
163
205
  description: 'Shuffle attestation ordering to create invalid ordering (for testing only)',
164
- ...booleanConfigHelper(false),
206
+ ...booleanConfigHelper(DefaultSequencerConfig.shuffleAttestationOrdering),
207
+ },
208
+ ...sharedSequencerConfigMappings,
209
+ buildCheckpointIfEmpty: {
210
+ env: 'SEQ_BUILD_CHECKPOINT_IF_EMPTY',
211
+ description: 'Have sequencer build and publish an empty checkpoint if there are no txs',
212
+ ...booleanConfigHelper(DefaultSequencerConfig.buildCheckpointIfEmpty),
213
+ },
214
+ skipPushProposedBlocksToArchiver: {
215
+ description: 'Skip pushing proposed blocks to archiver (default: true)',
216
+ ...booleanConfigHelper(DefaultSequencerConfig.skipPushProposedBlocksToArchiver),
217
+ },
218
+ minBlocksForCheckpoint: {
219
+ description: 'Minimum number of blocks required for a checkpoint proposal (test only)',
220
+ },
221
+ skipPublishingCheckpointsPercent: {
222
+ env: 'SEQ_SKIP_CHECKPOINT_PUBLISH_PERCENT',
223
+ description: 'Percent probability (0 - 100) of sequencer skipping checkpoint publishing (testing only)',
224
+ ...numberConfigHelper(DefaultSequencerConfig.skipPublishingCheckpointsPercent),
165
225
  },
166
- ...pickConfigMappings(p2pConfigMappings, ['txPublicSetupAllowList']),
226
+ ...pickConfigMappings(p2pConfigMappings, ['txPublicSetupAllowListExtend']),
167
227
  };
168
228
 
169
229
  export const sequencerClientConfigMappings: ConfigMappingsType<SequencerClientConfig> = {
@@ -171,8 +231,8 @@ export const sequencerClientConfigMappings: ConfigMappingsType<SequencerClientCo
171
231
  ...sequencerConfigMappings,
172
232
  ...keyStoreConfigMappings,
173
233
  ...l1ReaderConfigMappings,
174
- ...getTxSenderConfigMappings('SEQ'),
175
- ...getPublisherConfigMappings('SEQ'),
234
+ ...sequencerTxSenderConfigMappings,
235
+ ...sequencerPublisherConfigMappings,
176
236
  ...chainConfigMappings,
177
237
  ...pickConfigMappings(l1ContractsConfigMappings, ['ethereumSlotDuration', 'aztecSlotDuration', 'aztecEpochDuration']),
178
238
  };