@aztec/sequencer-client 0.76.4 → 0.77.0-testnet-ignition.21

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 (87) hide show
  1. package/dest/client/index.js +0 -1
  2. package/dest/client/sequencer-client.d.ts +12 -9
  3. package/dest/client/sequencer-client.d.ts.map +1 -1
  4. package/dest/client/sequencer-client.js +55 -60
  5. package/dest/config.d.ts +2 -2
  6. package/dest/config.d.ts.map +1 -1
  7. package/dest/config.js +41 -46
  8. package/dest/global_variable_builder/global_builder.d.ts +5 -2
  9. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  10. package/dest/global_variable_builder/global_builder.js +45 -31
  11. package/dest/global_variable_builder/index.js +0 -1
  12. package/dest/index.js +0 -1
  13. package/dest/publisher/config.d.ts.map +1 -1
  14. package/dest/publisher/config.js +33 -48
  15. package/dest/publisher/index.js +0 -1
  16. package/dest/publisher/sequencer-publisher-metrics.d.ts +5 -2
  17. package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
  18. package/dest/publisher/sequencer-publisher-metrics.js +47 -23
  19. package/dest/publisher/sequencer-publisher.d.ts +10 -9
  20. package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
  21. package/dest/publisher/sequencer-publisher.js +191 -160
  22. package/dest/sequencer/allowed.d.ts +1 -1
  23. package/dest/sequencer/allowed.d.ts.map +1 -1
  24. package/dest/sequencer/allowed.js +6 -13
  25. package/dest/sequencer/config.d.ts +1 -1
  26. package/dest/sequencer/config.d.ts.map +1 -1
  27. package/dest/sequencer/config.js +1 -2
  28. package/dest/sequencer/index.js +0 -1
  29. package/dest/sequencer/metrics.js +26 -18
  30. package/dest/sequencer/sequencer.d.ts +18 -12
  31. package/dest/sequencer/sequencer.d.ts.map +1 -1
  32. package/dest/sequencer/sequencer.js +589 -560
  33. package/dest/sequencer/timetable.d.ts +1 -1
  34. package/dest/sequencer/timetable.d.ts.map +1 -1
  35. package/dest/sequencer/timetable.js +33 -19
  36. package/dest/sequencer/utils.d.ts +2 -2
  37. package/dest/sequencer/utils.d.ts.map +1 -1
  38. package/dest/sequencer/utils.js +22 -32
  39. package/dest/slasher/factory.d.ts +4 -8
  40. package/dest/slasher/factory.d.ts.map +1 -1
  41. package/dest/slasher/factory.js +5 -7
  42. package/dest/slasher/index.js +0 -1
  43. package/dest/slasher/slasher_client.d.ts +10 -62
  44. package/dest/slasher/slasher_client.d.ts.map +1 -1
  45. package/dest/slasher/slasher_client.js +47 -231
  46. package/dest/test/index.d.ts +3 -3
  47. package/dest/test/index.d.ts.map +1 -1
  48. package/dest/test/index.js +4 -1
  49. package/dest/tx_validator/archive_cache.d.ts +3 -3
  50. package/dest/tx_validator/archive_cache.d.ts.map +1 -1
  51. package/dest/tx_validator/archive_cache.js +8 -8
  52. package/dest/tx_validator/gas_validator.d.ts +5 -3
  53. package/dest/tx_validator/gas_validator.d.ts.map +1 -1
  54. package/dest/tx_validator/gas_validator.js +70 -70
  55. package/dest/tx_validator/nullifier_cache.d.ts +2 -2
  56. package/dest/tx_validator/nullifier_cache.d.ts.map +1 -1
  57. package/dest/tx_validator/nullifier_cache.js +9 -9
  58. package/dest/tx_validator/phases_validator.d.ts +3 -2
  59. package/dest/tx_validator/phases_validator.d.ts.map +1 -1
  60. package/dest/tx_validator/phases_validator.js +29 -21
  61. package/dest/tx_validator/test_utils.d.ts +4 -2
  62. package/dest/tx_validator/test_utils.d.ts.map +1 -1
  63. package/dest/tx_validator/test_utils.js +2 -3
  64. package/dest/tx_validator/tx_validator_factory.d.ts +7 -5
  65. package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
  66. package/dest/tx_validator/tx_validator_factory.js +14 -13
  67. package/package.json +28 -29
  68. package/src/client/sequencer-client.ts +17 -14
  69. package/src/config.ts +6 -14
  70. package/src/global_variable_builder/global_builder.ts +18 -19
  71. package/src/publisher/config.ts +9 -17
  72. package/src/publisher/sequencer-publisher-metrics.ts +23 -2
  73. package/src/publisher/sequencer-publisher.ts +15 -17
  74. package/src/sequencer/allowed.ts +4 -4
  75. package/src/sequencer/config.ts +1 -1
  76. package/src/sequencer/sequencer.ts +40 -35
  77. package/src/sequencer/timetable.ts +1 -1
  78. package/src/sequencer/utils.ts +2 -2
  79. package/src/slasher/factory.ts +7 -13
  80. package/src/slasher/slasher_client.ts +30 -252
  81. package/src/test/index.ts +3 -3
  82. package/src/tx_validator/archive_cache.ts +4 -3
  83. package/src/tx_validator/gas_validator.ts +22 -31
  84. package/src/tx_validator/nullifier_cache.ts +3 -2
  85. package/src/tx_validator/phases_validator.ts +8 -8
  86. package/src/tx_validator/test_utils.ts +5 -3
  87. package/src/tx_validator/tx_validator_factory.ts +23 -17
@@ -1,36 +1,27 @@
1
1
  import {
2
- type L2Block,
3
- type L2BlockId,
4
- type L2BlockSource,
5
- L2BlockStream,
6
- type L2BlockStreamEvent,
7
- type L2Tips,
8
- } from '@aztec/circuit-types';
9
- import { INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js/constants';
10
- import { type L1ContractsConfig, type L1ReaderConfig, createEthereumChain } from '@aztec/ethereum';
2
+ type L1ContractsConfig,
3
+ type L1ReaderConfig,
4
+ type ViemPublicClient,
5
+ createEthereumChain,
6
+ } from '@aztec/ethereum';
11
7
  import { EthAddress } from '@aztec/foundation/eth-address';
12
8
  import { createLogger } from '@aztec/foundation/log';
13
- import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncSingleton } from '@aztec/kv-store';
14
9
  import { SlashFactoryAbi } from '@aztec/l1-artifacts';
10
+ import {
11
+ type L2BlockId,
12
+ type L2BlockSourceEvent,
13
+ type L2BlockSourceEventEmitter,
14
+ L2BlockSourceEvents,
15
+ } from '@aztec/stdlib/block';
15
16
  import { type TelemetryClient, WithTracer, getTelemetryClient } from '@aztec/telemetry-client';
16
17
 
17
- import {
18
- type Chain,
19
- type GetContractReturnType,
20
- type HttpTransport,
21
- type PublicClient,
22
- createPublicClient,
23
- getAddress,
24
- getContract,
25
- http,
26
- } from 'viem';
18
+ import { type GetContractReturnType, createPublicClient, fallback, getAddress, getContract, http } from 'viem';
27
19
 
28
20
  /**
29
21
  * Enum defining the possible states of the Slasher client.
30
22
  */
31
23
  export enum SlasherClientState {
32
24
  IDLE,
33
- SYNCHING,
34
25
  RUNNING,
35
26
  STOPPED,
36
27
  }
@@ -86,22 +77,9 @@ type SlashEvent = {
86
77
  * slashing only the first, because the "lifetime" of the second would have passed after that vote
87
78
  */
88
79
  export class SlasherClient extends WithTracer {
89
- private currentState = SlasherClientState.IDLE;
90
- private syncPromise = Promise.resolve();
91
- private syncResolve?: () => void = undefined;
92
- private latestBlockNumberAtStart = -1;
93
- private provenBlockNumberAtStart = -1;
94
-
95
- private synchedBlockHashes: AztecAsyncMap<number, string>;
96
- private synchedLatestBlockNumber: AztecAsyncSingleton<number>;
97
- private synchedProvenBlockNumber: AztecAsyncSingleton<number>;
98
-
99
- private blockStream;
100
-
101
80
  private slashEvents: SlashEvent[] = [];
102
81
 
103
- protected slashFactoryContract?: GetContractReturnType<typeof SlashFactoryAbi, PublicClient<HttpTransport, Chain>> =
104
- undefined;
82
+ protected slashFactoryContract?: GetContractReturnType<typeof SlashFactoryAbi, ViemPublicClient> = undefined;
105
83
 
106
84
  // The amount to slash for a prune.
107
85
  // Note that we set it to 0, such that no actual slashing will happen, but the event will be fired,
@@ -110,27 +88,17 @@ export class SlasherClient extends WithTracer {
110
88
 
111
89
  constructor(
112
90
  private config: SlasherConfig & L1ContractsConfig & L1ReaderConfig,
113
- private store: AztecAsyncKVStore,
114
- private l2BlockSource: L2BlockSource,
91
+ private l2BlockSource: L2BlockSourceEventEmitter,
115
92
  telemetry: TelemetryClient = getTelemetryClient(),
116
93
  private log = createLogger('slasher'),
117
94
  ) {
118
95
  super(telemetry, 'slasher');
119
96
 
120
- this.blockStream = new L2BlockStream(l2BlockSource, this, this, createLogger('slasher:block_stream'), {
121
- batchSize: config.blockRequestBatchSize,
122
- pollIntervalMS: config.blockCheckIntervalMS,
123
- });
124
-
125
- this.synchedBlockHashes = store.openMap('slasher_block_hashes');
126
- this.synchedLatestBlockNumber = store.openSingleton('slasher_last_l2_block');
127
- this.synchedProvenBlockNumber = store.openSingleton('slasher_last_proven_l2_block');
128
-
129
97
  if (config.l1Contracts.slashFactoryAddress && config.l1Contracts.slashFactoryAddress !== EthAddress.ZERO) {
130
- const chain = createEthereumChain(config.l1RpcUrl, config.l1ChainId);
98
+ const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
131
99
  const publicClient = createPublicClient({
132
100
  chain: chain.chainInfo,
133
- transport: http(chain.rpcUrl),
101
+ transport: fallback(chain.rpcUrls.map(url => http(url))),
134
102
  pollingInterval: config.viemPollingIntervalMS,
135
103
  });
136
104
 
@@ -146,6 +114,11 @@ export class SlasherClient extends WithTracer {
146
114
  this.log.info(`Slasher client initialized`);
147
115
  }
148
116
 
117
+ public start() {
118
+ this.log.info('Starting Slasher client...');
119
+ this.l2BlockSource.on(L2BlockSourceEvents.L2PruneDetected, this.handlePruneL2Blocks.bind(this));
120
+ }
121
+
149
122
  // This is where we should put a bunch of the improvements mentioned earlier.
150
123
  public async getSlashPayload(slotNumber: bigint): Promise<EthAddress | undefined> {
151
124
  if (!this.slashFactoryContract) {
@@ -177,198 +150,32 @@ export class SlasherClient extends WithTracer {
177
150
  return EthAddress.fromString(payloadAddress);
178
151
  }
179
152
 
180
- public getL2BlockHash(number: number): Promise<string | undefined> {
181
- return this.synchedBlockHashes.getAsync(number);
182
- }
183
-
184
- public async getL2Tips(): Promise<L2Tips> {
185
- const latestBlockNumber = await this.getSyncedLatestBlockNum();
186
- let latestBlockHash: string | undefined;
187
- const provenBlockNumber = await this.getSyncedProvenBlockNum();
188
- let provenBlockHash: string | undefined;
189
-
190
- if (latestBlockNumber > 0) {
191
- latestBlockHash = await this.synchedBlockHashes.getAsync(latestBlockNumber);
192
- if (typeof latestBlockHash === 'undefined') {
193
- this.log.warn(`Block hash for latest block ${latestBlockNumber} not found`);
194
- throw new Error();
195
- }
196
- }
197
-
198
- if (provenBlockNumber > 0) {
199
- provenBlockHash = await this.synchedBlockHashes.getAsync(provenBlockNumber);
200
- if (typeof provenBlockHash === 'undefined') {
201
- this.log.warn(`Block hash for proven block ${provenBlockNumber} not found`);
202
- throw new Error();
203
- }
204
- }
205
-
206
- return Promise.resolve({
207
- latest: { hash: latestBlockHash!, number: latestBlockNumber },
208
- proven: { hash: provenBlockHash!, number: provenBlockNumber },
209
- finalized: { hash: provenBlockHash!, number: provenBlockNumber },
210
- });
211
- }
212
-
213
- public async handleBlockStreamEvent(event: L2BlockStreamEvent): Promise<void> {
153
+ public handleBlockStreamEvent(event: L2BlockSourceEvent): Promise<void> {
214
154
  this.log.debug(`Handling block stream event ${event.type}`);
215
155
  switch (event.type) {
216
- case 'blocks-added':
217
- await this.handleLatestL2Blocks(event.blocks);
218
- break;
219
- case 'chain-finalized':
220
- // TODO (alexg): I think we can prune the block hashes map here
221
- break;
222
- case 'chain-proven': {
223
- const from = (await this.getSyncedProvenBlockNum()) + 1;
224
- const limit = event.blockNumber - from + 1;
225
- await this.handleProvenL2Blocks(await this.l2BlockSource.getBlocks(from, limit));
226
- break;
227
- }
228
- case 'chain-pruned':
229
- await this.handlePruneL2Blocks(event.blockNumber);
156
+ case L2BlockSourceEvents.L2PruneDetected:
157
+ this.handlePruneL2Blocks(event);
230
158
  break;
231
159
  default: {
232
- const _: never = event;
233
160
  break;
234
161
  }
235
162
  }
236
- }
237
-
238
- public async start() {
239
- if (this.currentState === SlasherClientState.STOPPED) {
240
- throw new Error('Slasher already stopped');
241
- }
242
- if (this.currentState !== SlasherClientState.IDLE) {
243
- return this.syncPromise;
244
- }
245
-
246
- // get the current latest block numbers
247
- this.latestBlockNumberAtStart = await this.l2BlockSource.getBlockNumber();
248
- this.provenBlockNumberAtStart = await this.l2BlockSource.getProvenBlockNumber();
249
-
250
- const syncedLatestBlock = (await this.getSyncedLatestBlockNum()) + 1;
251
- const syncedProvenBlock = (await this.getSyncedProvenBlockNum()) + 1;
252
-
253
- // if there are blocks to be retrieved, go to a synching state
254
- if (syncedLatestBlock <= this.latestBlockNumberAtStart || syncedProvenBlock <= this.provenBlockNumberAtStart) {
255
- this.setCurrentState(SlasherClientState.SYNCHING);
256
- this.syncPromise = new Promise(resolve => {
257
- this.syncResolve = resolve;
258
- });
259
- this.log.verbose(`Starting sync from ${syncedLatestBlock} (last proven ${syncedProvenBlock})`);
260
- } else {
261
- // if no blocks to be retrieved, go straight to running
262
- this.setCurrentState(SlasherClientState.RUNNING);
263
- this.syncPromise = Promise.resolve();
264
- this.log.verbose(`Block ${syncedLatestBlock} (proven ${syncedProvenBlock}) already beyond current block`);
265
- }
266
-
267
- this.blockStream.start();
268
- this.log.verbose(`Started block downloader from block ${syncedLatestBlock}`);
269
-
270
- return this.syncPromise;
163
+ return Promise.resolve();
271
164
  }
272
165
 
273
166
  /**
274
167
  * Allows consumers to stop the instance of the slasher client.
275
168
  * 'ready' will now return 'false' and the running promise that keeps the client synced is interrupted.
276
169
  */
277
- public async stop() {
170
+ public stop() {
278
171
  this.log.debug('Stopping Slasher client...');
279
- await this.blockStream.stop();
280
- this.log.debug('Stopped block downloader');
281
- await this.store.close();
282
- this.log.debug('Stopped slasher store');
283
- this.setCurrentState(SlasherClientState.STOPPED);
172
+ this.l2BlockSource.removeListener(L2BlockSourceEvents.L2PruneDetected, this.handlePruneL2Blocks.bind(this));
284
173
  this.log.info('Slasher client stopped.');
285
174
  }
286
175
 
287
- /**
288
- * Public function to check if the slasher client is fully synced and ready to receive txs.
289
- * @returns True if the slasher client is ready to receive txs.
290
- */
291
- public isReady() {
292
- return this.currentState === SlasherClientState.RUNNING;
293
- }
294
-
295
- /**
296
- * Public function to check the latest block number that the slasher client is synced to.
297
- * @returns Block number of latest L2 Block we've synced with.
298
- */
299
- public async getSyncedLatestBlockNum(): Promise<number> {
300
- return (await this.synchedLatestBlockNumber.getAsync()) ?? INITIAL_L2_BLOCK_NUM - 1;
301
- }
302
-
303
- /**
304
- * Public function to check the latest proven block number that the slasher client is synced to.
305
- * @returns Block number of latest proven L2 Block we've synced with.
306
- */
307
- public async getSyncedProvenBlockNum(): Promise<number> {
308
- return (await this.synchedProvenBlockNumber.getAsync()) ?? INITIAL_L2_BLOCK_NUM - 1;
309
- }
310
-
311
- /**
312
- * Method to check the status of the slasher client.
313
- * @returns Information about slasher client status: state & syncedToBlockNum.
314
- */
315
- public async getStatus(): Promise<SlasherSyncState> {
316
- const blockNumber = await this.getSyncedLatestBlockNum();
317
- const blockHash =
318
- blockNumber == 0
319
- ? ''
320
- : await this.l2BlockSource
321
- .getBlockHeader(blockNumber)
322
- .then(header => header?.hash())
323
- .then(hash => hash?.toString());
324
- return Promise.resolve({
325
- state: this.currentState,
326
- syncedToL2Block: { number: blockNumber, hash: blockHash },
327
- } as SlasherSyncState);
328
- }
329
-
330
- /**
331
- * Handles new blocks
332
- * @param blocks - A list of blocks that the slasher client needs to store block hashes for
333
- * @returns Empty promise.
334
- */
335
- private async handleLatestL2Blocks(blocks: L2Block[]): Promise<void> {
336
- if (!blocks.length) {
337
- return;
338
- }
339
-
340
- await this.store.transactionAsync(async () => {
341
- for (const block of blocks) {
342
- await this.synchedBlockHashes.set(block.number, (await block.hash()).toString());
343
- }
344
-
345
- const lastBlockNum = blocks[blocks.length - 1].number;
346
- await this.synchedLatestBlockNumber.set(lastBlockNum);
347
- });
348
-
349
- await this.startServiceIfSynched();
350
- }
351
-
352
- /**
353
- * Handles new proven blocks by updating the proven block number
354
- * @param blocks - A list of proven L2 blocks.
355
- * @returns Empty promise.
356
- */
357
- private async handleProvenL2Blocks(blocks: L2Block[]): Promise<void> {
358
- if (!blocks.length) {
359
- return Promise.resolve();
360
- }
361
- const lastBlockNum = blocks[blocks.length - 1].number;
362
- await this.synchedProvenBlockNumber.set(lastBlockNum);
363
- this.log.debug(`Synched to proven block ${lastBlockNum}`);
364
-
365
- await this.startServiceIfSynched();
366
- }
367
-
368
- private async handlePruneL2Blocks(latestBlock: number): Promise<void> {
369
- const blockHeader = await this.l2BlockSource.getBlockHeader(latestBlock);
370
- const slotNumber = blockHeader ? blockHeader.globalVariables.slotNumber.toBigInt() : BigInt(0);
371
- const epochNumber = slotNumber / BigInt(this.config.aztecEpochDuration);
176
+ // I need to get the slot number from the block that was just pruned
177
+ private handlePruneL2Blocks(event: L2BlockSourceEvent): void {
178
+ const { slotNumber, epochNumber } = event;
372
179
  this.log.info(`Detected chain prune. Punishing the validators at epoch ${epochNumber}`);
373
180
 
374
181
  // Set the lifetime such that we have a full round that we could vote throughout.
@@ -382,34 +189,5 @@ export class SlasherClient extends WithTracer {
382
189
  amount: this.slashingAmount,
383
190
  lifetime,
384
191
  });
385
-
386
- await this.synchedLatestBlockNumber.set(latestBlock);
387
- }
388
-
389
- private async startServiceIfSynched() {
390
- const [latestBlock, provenBlock] = await Promise.all([
391
- this.getSyncedLatestBlockNum(),
392
- this.getSyncedProvenBlockNum(),
393
- ]);
394
- if (
395
- this.currentState === SlasherClientState.SYNCHING &&
396
- latestBlock >= this.latestBlockNumberAtStart &&
397
- provenBlock >= this.provenBlockNumberAtStart
398
- ) {
399
- this.log.debug(`Synched to blocks at start`);
400
- this.setCurrentState(SlasherClientState.RUNNING);
401
- if (this.syncResolve !== undefined) {
402
- this.syncResolve();
403
- }
404
- }
405
- }
406
-
407
- /**
408
- * Method to set the value of the current state.
409
- * @param newState - New state value.
410
- */
411
- private setCurrentState(newState: SlasherClientState) {
412
- this.currentState = newState;
413
- this.log.debug(`Moved to state ${SlasherClientState[this.currentState]}`);
414
192
  }
415
193
  }
package/src/test/index.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { type PublicProcessorFactory } from '@aztec/simulator/server';
1
+ import type { PublicProcessorFactory } from '@aztec/simulator/server';
2
2
 
3
3
  import { SequencerClient } from '../client/sequencer-client.js';
4
- import { type SequencerPublisher } from '../publisher/sequencer-publisher.js';
4
+ import type { SequencerPublisher } from '../publisher/sequencer-publisher.js';
5
5
  import { Sequencer } from '../sequencer/sequencer.js';
6
- import { type SequencerTimetable } from '../sequencer/timetable.js';
6
+ import type { SequencerTimetable } from '../sequencer/timetable.js';
7
7
 
8
8
  class TestSequencer_ extends Sequencer {
9
9
  public override publicProcessorFactory!: PublicProcessorFactory;
@@ -1,6 +1,7 @@
1
- import { MerkleTreeId, type MerkleTreeReadOperations } from '@aztec/circuit-types';
2
- import { type Fr } from '@aztec/circuits.js';
3
- import { type ArchiveSource } from '@aztec/p2p';
1
+ import type { Fr } from '@aztec/foundation/fields';
2
+ import type { ArchiveSource } from '@aztec/p2p';
3
+ import type { MerkleTreeReadOperations } from '@aztec/stdlib/interfaces/server';
4
+ import { MerkleTreeId } from '@aztec/stdlib/trees';
4
5
 
5
6
  /**
6
7
  * Implements an archive source by checking a DB and an in-memory collection.
@@ -1,8 +1,11 @@
1
- import { type Tx, TxExecutionPhase, type TxValidationResult, type TxValidator } from '@aztec/circuit-types';
2
- import { type AztecAddress, Fr, FunctionSelector, type GasFees } from '@aztec/circuits.js';
3
- import { U128 } from '@aztec/foundation/abi';
1
+ import { Fr } from '@aztec/foundation/fields';
4
2
  import { createLogger } from '@aztec/foundation/log';
5
- import { computeFeePayerBalanceStorageSlot, getExecutionRequestsByPhase } from '@aztec/simulator/server';
3
+ import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
4
+ import { getExecutionRequestsByPhase } from '@aztec/simulator/server';
5
+ import { FunctionSelector } from '@aztec/stdlib/abi';
6
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
7
+ import type { GasFees } from '@aztec/stdlib/gas';
8
+ import { type Tx, TxExecutionPhase, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
6
9
 
7
10
  /** Provides a view into public contract state */
8
11
  export interface PublicStateSource {
@@ -13,23 +16,16 @@ export class GasTxValidator implements TxValidator<Tx> {
13
16
  #log = createLogger('sequencer:tx_validator:tx_gas');
14
17
  #publicDataSource: PublicStateSource;
15
18
  #feeJuiceAddress: AztecAddress;
16
- #enforceFees: boolean;
17
19
  #gasFees: GasFees;
18
20
 
19
- constructor(
20
- publicDataSource: PublicStateSource,
21
- feeJuiceAddress: AztecAddress,
22
- enforceFees: boolean,
23
- gasFees: GasFees,
24
- ) {
21
+ constructor(publicDataSource: PublicStateSource, feeJuiceAddress: AztecAddress, gasFees: GasFees) {
25
22
  this.#publicDataSource = publicDataSource;
26
23
  this.#feeJuiceAddress = feeJuiceAddress;
27
- this.#enforceFees = enforceFees;
28
24
  this.#gasFees = gasFees;
29
25
  }
30
26
 
31
- validateTx(tx: Tx): Promise<TxValidationResult> {
32
- if (this.#shouldSkip(tx)) {
27
+ async validateTx(tx: Tx): Promise<TxValidationResult> {
28
+ if (await this.#shouldSkip(tx)) {
33
29
  return Promise.resolve({ result: 'skipped', reason: ['Insufficient fee per gas'] });
34
30
  }
35
31
  return this.#validateTxFee(tx);
@@ -37,11 +33,11 @@ export class GasTxValidator implements TxValidator<Tx> {
37
33
 
38
34
  /**
39
35
  * Check whether the tx's max fees are valid for the current block, and skip if not.
40
- * We skip instead of invalidating since the tx may become elligible later.
36
+ * We skip instead of invalidating since the tx may become eligible later.
41
37
  * Note that circuits check max fees even if fee payer is unset, so we
42
38
  * keep this validation even if the tx does not pay fees.
43
39
  */
44
- #shouldSkip(tx: Tx): boolean {
40
+ async #shouldSkip(tx: Tx): Promise<boolean> {
45
41
  const gasSettings = tx.data.constants.txContext.gasSettings;
46
42
 
47
43
  // Skip the tx if its max fees are not enough for the current block's gas fees.
@@ -51,22 +47,16 @@ export class GasTxValidator implements TxValidator<Tx> {
51
47
  maxFeesPerGas.feePerL2Gas.lt(this.#gasFees.feePerL2Gas);
52
48
 
53
49
  if (notEnoughMaxFees) {
54
- this.#log.warn(`Skipping transaction ${tx.getTxHash()} due to insufficient fee per gas`);
50
+ this.#log.warn(`Skipping transaction ${await tx.getTxHash()} due to insufficient fee per gas`, {
51
+ txMaxFeesPerGas: maxFeesPerGas.toInspect(),
52
+ currentGasFees: this.#gasFees.toInspect(),
53
+ });
55
54
  }
56
55
  return notEnoughMaxFees;
57
56
  }
58
57
 
59
58
  async #validateTxFee(tx: Tx): Promise<TxValidationResult> {
60
59
  const feePayer = tx.data.feePayer;
61
- // TODO(@spalladino) Eventually remove the is_zero condition as we should always charge fees to every tx
62
- if (feePayer.isZero()) {
63
- if (this.#enforceFees) {
64
- this.#log.warn(`Rejecting transaction ${tx.getTxHash()} due to missing fee payer`);
65
- return { result: 'invalid', reason: ['Missing fee payer'] };
66
- } else {
67
- return { result: 'valid' };
68
- }
69
- }
70
60
 
71
61
  // Compute the maximum fee that this tx may pay, based on its gasLimits and maxFeePerGas
72
62
  const feeLimit = tx.data.constants.txContext.gasSettings.getFeeLimit();
@@ -80,7 +70,7 @@ export class GasTxValidator implements TxValidator<Tx> {
80
70
  // If there is a claim in this tx that increases the fee payer balance in Fee Juice, add it to balance
81
71
  const setupFns = getExecutionRequestsByPhase(tx, TxExecutionPhase.SETUP);
82
72
  const increasePublicBalanceSelector = await FunctionSelector.fromSignature(
83
- '_increase_public_balance((Field),(Field,Field))',
73
+ '_increase_public_balance((Field),u128)',
84
74
  );
85
75
  const claimFunctionCall = setupFns.find(
86
76
  fn =>
@@ -93,10 +83,11 @@ export class GasTxValidator implements TxValidator<Tx> {
93
83
  !fn.callContext.isStaticCall,
94
84
  );
95
85
 
96
- // `amount` in the claim function call arguments occupies 2 fields as it is represented as U128.
97
- const balance = claimFunctionCall
98
- ? initialBalance.add(new Fr(U128.fromFields(claimFunctionCall.args.slice(2, 4)).toInteger()))
99
- : initialBalance;
86
+ // The claim amount is at index 2 in the args array because:
87
+ // - Index 0: Target function selector (due to dispatch routing)
88
+ // - Index 1: Amount recipient
89
+ // - Index 2: Amount being claimed
90
+ const balance = claimFunctionCall ? initialBalance.add(claimFunctionCall.args[2]) : initialBalance;
100
91
  if (balance.lt(feeLimit)) {
101
92
  this.#log.warn(`Rejecting transaction due to not enough fee payer balance`, {
102
93
  feePayer,
@@ -1,5 +1,6 @@
1
- import { MerkleTreeId, type MerkleTreeReadOperations } from '@aztec/circuit-types';
2
- import { type NullifierSource } from '@aztec/p2p';
1
+ import type { NullifierSource } from '@aztec/p2p';
2
+ import type { MerkleTreeReadOperations } from '@aztec/stdlib/interfaces/server';
3
+ import { MerkleTreeId } from '@aztec/stdlib/trees';
3
4
 
4
5
  /**
5
6
  * Implements a nullifier source by checking a DB and an in-memory collection.
@@ -1,14 +1,14 @@
1
+ import { createLogger } from '@aztec/foundation/log';
2
+ import { ContractsDataSourcePublicDB, getExecutionRequestsByPhase } from '@aztec/simulator/server';
3
+ import type { ContractDataSource } from '@aztec/stdlib/contract';
4
+ import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
1
5
  import {
2
- type AllowedElement,
3
6
  type PublicExecutionRequest,
4
7
  Tx,
5
8
  TxExecutionPhase,
6
9
  type TxValidationResult,
7
10
  type TxValidator,
8
- } from '@aztec/circuit-types';
9
- import { type ContractDataSource } from '@aztec/circuits.js';
10
- import { createLogger } from '@aztec/foundation/log';
11
- import { ContractsDataSourcePublicDB, getExecutionRequestsByPhase } from '@aztec/simulator/server';
11
+ } from '@aztec/stdlib/tx';
12
12
 
13
13
  export class PhasesTxValidator implements TxValidator<Tx> {
14
14
  #log = createLogger('sequencer:tx_validator:tx_phases');
@@ -46,7 +46,7 @@ export class PhasesTxValidator implements TxValidator<Tx> {
46
46
 
47
47
  return { result: 'valid' };
48
48
  } finally {
49
- await this.contractDataSource.removeNewContracts(tx);
49
+ this.contractDataSource.clearContractsForTx();
50
50
  }
51
51
  }
52
52
 
@@ -78,14 +78,14 @@ export class PhasesTxValidator implements TxValidator<Tx> {
78
78
  }
79
79
 
80
80
  if ('classId' in entry && !('selector' in entry)) {
81
- if (contractClass.contractClassId.equals(entry.classId)) {
81
+ if (contractClass.currentContractClassId.equals(entry.classId)) {
82
82
  return true;
83
83
  }
84
84
  }
85
85
 
86
86
  if ('classId' in entry && 'selector' in entry) {
87
87
  if (
88
- contractClass.contractClassId.equals(entry.classId) &&
88
+ contractClass.currentContractClassId.equals(entry.classId) &&
89
89
  (entry.selector === undefined || entry.selector.equals(functionSelector))
90
90
  ) {
91
91
  return true;
@@ -1,6 +1,8 @@
1
- import { type Tx } from '@aztec/circuit-types';
2
- import { type AztecAddress, type Fr, type FunctionSelector } from '@aztec/circuits.js';
3
- import { computeVarArgsHash } from '@aztec/circuits.js/hash';
1
+ import type { Fr } from '@aztec/foundation/fields';
2
+ import type { FunctionSelector } from '@aztec/stdlib/abi';
3
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
+ import { computeVarArgsHash } from '@aztec/stdlib/hash';
5
+ import type { Tx } from '@aztec/stdlib/tx';
4
6
 
5
7
  export function patchNonRevertibleFn(
6
8
  tx: Tx,
@@ -1,12 +1,4 @@
1
- import {
2
- type AllowedElement,
3
- type ClientProtocolCircuitVerifier,
4
- type MerkleTreeReadOperations,
5
- type ProcessedTx,
6
- type Tx,
7
- type TxValidator,
8
- } from '@aztec/circuit-types';
9
- import { type AztecAddress, type ContractDataSource, Fr, type GasFees, type GlobalVariables } from '@aztec/circuits.js';
1
+ import { Fr } from '@aztec/foundation/fields';
10
2
  import {
11
3
  AggregateTxValidator,
12
4
  BlockHeaderTxValidator,
@@ -17,6 +9,15 @@ import {
17
9
  } from '@aztec/p2p';
18
10
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
19
11
  import { readPublicState } from '@aztec/simulator/server';
12
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
13
+ import type { ContractDataSource } from '@aztec/stdlib/contract';
14
+ import type { GasFees } from '@aztec/stdlib/gas';
15
+ import type {
16
+ AllowedElement,
17
+ ClientProtocolCircuitVerifier,
18
+ MerkleTreeReadOperations,
19
+ } from '@aztec/stdlib/interfaces/server';
20
+ import { GlobalVariables, type ProcessedTx, type Tx, type TxValidator } from '@aztec/stdlib/tx';
20
21
 
21
22
  import { ArchiveCache } from './archive_cache.js';
22
23
  import { GasTxValidator, type PublicStateSource } from './gas_validator.js';
@@ -27,24 +28,32 @@ export function createValidatorForAcceptingTxs(
27
28
  db: MerkleTreeReadOperations,
28
29
  contractDataSource: ContractDataSource,
29
30
  verifier: ClientProtocolCircuitVerifier | undefined,
30
- data: {
31
+ {
32
+ blockNumber,
33
+ l1ChainId,
34
+ setupAllowList,
35
+ gasFees,
36
+ skipFeeEnforcement,
37
+ }: {
31
38
  blockNumber: number;
32
39
  l1ChainId: number;
33
- enforceFees: boolean;
34
40
  setupAllowList: AllowedElement[];
35
41
  gasFees: GasFees;
42
+ skipFeeEnforcement?: boolean;
36
43
  },
37
44
  ): TxValidator<Tx> {
38
- const { blockNumber, l1ChainId, enforceFees, setupAllowList, gasFees } = data;
39
45
  const validators: TxValidator<Tx>[] = [
40
46
  new DataTxValidator(),
41
47
  new MetadataTxValidator(new Fr(l1ChainId), new Fr(blockNumber)),
42
48
  new DoubleSpendTxValidator(new NullifierCache(db)),
43
49
  new PhasesTxValidator(contractDataSource, setupAllowList),
44
- new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, enforceFees, gasFees),
45
50
  new BlockHeaderTxValidator(new ArchiveCache(db)),
46
51
  ];
47
52
 
53
+ if (!skipFeeEnforcement) {
54
+ validators.push(new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, gasFees));
55
+ }
56
+
48
57
  if (verifier) {
49
58
  validators.push(new TxProofValidator(verifier));
50
59
  }
@@ -56,7 +65,6 @@ export function createValidatorsForBlockBuilding(
56
65
  db: MerkleTreeReadOperations,
57
66
  contractDataSource: ContractDataSource,
58
67
  globalVariables: GlobalVariables,
59
- enforceFees: boolean,
60
68
  setupAllowList: AllowedElement[],
61
69
  ): {
62
70
  preprocessValidator: TxValidator<Tx>;
@@ -73,7 +81,6 @@ export function createValidatorsForBlockBuilding(
73
81
  archiveCache,
74
82
  publicStateSource,
75
83
  contractDataSource,
76
- enforceFees,
77
84
  globalVariables,
78
85
  setupAllowList,
79
86
  ),
@@ -95,7 +102,6 @@ function preprocessValidator(
95
102
  archiveCache: ArchiveCache,
96
103
  publicStateSource: PublicStateSource,
97
104
  contractDataSource: ContractDataSource,
98
- enforceFees: boolean,
99
105
  globalVariables: GlobalVariables,
100
106
  setupAllowList: AllowedElement[],
101
107
  ): TxValidator<Tx> {
@@ -104,7 +110,7 @@ function preprocessValidator(
104
110
  new MetadataTxValidator(globalVariables.chainId, globalVariables.blockNumber),
105
111
  new DoubleSpendTxValidator(nullifierCache),
106
112
  new PhasesTxValidator(contractDataSource, setupAllowList),
107
- new GasTxValidator(publicStateSource, ProtocolContractAddress.FeeJuice, enforceFees, globalVariables.gasFees),
113
+ new GasTxValidator(publicStateSource, ProtocolContractAddress.FeeJuice, globalVariables.gasFees),
108
114
  new BlockHeaderTxValidator(archiveCache),
109
115
  );
110
116
  }