@aztec/sequencer-client 0.42.0 → 0.44.0

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 (33) hide show
  1. package/dest/client/sequencer-client.d.ts +2 -1
  2. package/dest/client/sequencer-client.d.ts.map +1 -1
  3. package/dest/client/sequencer-client.js +4 -4
  4. package/dest/config.d.ts +13 -0
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +46 -35
  7. package/dest/publisher/l1-publisher.d.ts +4 -1
  8. package/dest/publisher/l1-publisher.d.ts.map +1 -1
  9. package/dest/publisher/l1-publisher.js +6 -1
  10. package/dest/publisher/viem-tx-sender.d.ts +3 -0
  11. package/dest/publisher/viem-tx-sender.d.ts.map +1 -1
  12. package/dest/publisher/viem-tx-sender.js +15 -1
  13. package/dest/sequencer/sequencer.d.ts +6 -3
  14. package/dest/sequencer/sequencer.d.ts.map +1 -1
  15. package/dest/sequencer/sequencer.js +284 -255
  16. package/dest/tx_validator/gas_validator.d.ts +2 -1
  17. package/dest/tx_validator/gas_validator.d.ts.map +1 -1
  18. package/dest/tx_validator/gas_validator.js +12 -5
  19. package/dest/tx_validator/phases_validator.d.ts +3 -3
  20. package/dest/tx_validator/phases_validator.d.ts.map +1 -1
  21. package/dest/tx_validator/phases_validator.js +25 -18
  22. package/dest/tx_validator/tx_validator_factory.d.ts +4 -3
  23. package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
  24. package/dest/tx_validator/tx_validator_factory.js +4 -3
  25. package/package.json +24 -15
  26. package/src/client/sequencer-client.ts +10 -2
  27. package/src/config.ts +47 -37
  28. package/src/publisher/l1-publisher.ts +11 -1
  29. package/src/publisher/viem-tx-sender.ts +15 -0
  30. package/src/sequencer/sequencer.ts +119 -94
  31. package/src/tx_validator/gas_validator.ts +9 -5
  32. package/src/tx_validator/phases_validator.ts +29 -19
  33. package/src/tx_validator/tx_validator_factory.ts +8 -4
@@ -7,19 +7,20 @@ import {
7
7
  type TxValidator,
8
8
  } from '@aztec/circuit-types';
9
9
  import {
10
- type AllowedFunction,
10
+ type AllowedElement,
11
11
  BlockProofError,
12
12
  type BlockProver,
13
13
  PROVING_STATUS,
14
14
  } from '@aztec/circuit-types/interfaces';
15
15
  import { type L2BlockBuiltStats } from '@aztec/circuit-types/stats';
16
- import { AztecAddress, EthAddress, type Proof } from '@aztec/circuits.js';
16
+ import { AztecAddress, EthAddress, type GlobalVariables, type Header, type Proof } from '@aztec/circuits.js';
17
17
  import { Fr } from '@aztec/foundation/fields';
18
18
  import { createDebugLogger } from '@aztec/foundation/log';
19
19
  import { RunningPromise } from '@aztec/foundation/running-promise';
20
20
  import { Timer, elapsed } from '@aztec/foundation/timer';
21
21
  import { type P2P } from '@aztec/p2p';
22
22
  import { type PublicProcessorFactory } from '@aztec/simulator';
23
+ import { Attributes, type TelemetryClient, type Tracer, trackSpan } from '@aztec/telemetry-client';
23
24
  import { type WorldStateStatus, type WorldStateSynchronizer } from '@aztec/world-state';
24
25
 
25
26
  import { type GlobalVariableBuilder } from '../global_variable_builder/global_builder.js';
@@ -46,10 +47,12 @@ export class Sequencer {
46
47
  private _feeRecipient = AztecAddress.ZERO;
47
48
  private lastPublishedBlock = 0;
48
49
  private state = SequencerState.STOPPED;
49
- private allowedFunctionsInSetup: AllowedFunction[] = [];
50
- private allowedFunctionsInTeardown: AllowedFunction[] = [];
50
+ private allowedInSetup: AllowedElement[] = [];
51
+ private allowedInTeardown: AllowedElement[] = [];
51
52
  private maxBlockSizeInBytes: number = 1024 * 1024;
52
53
 
54
+ public readonly tracer: Tracer;
55
+
53
56
  constructor(
54
57
  private publisher: L1Publisher,
55
58
  private globalsBuilder: GlobalVariableBuilder,
@@ -60,10 +63,12 @@ export class Sequencer {
60
63
  private l1ToL2MessageSource: L1ToL2MessageSource,
61
64
  private publicProcessorFactory: PublicProcessorFactory,
62
65
  private txValidatorFactory: TxValidatorFactory,
66
+ telemetry: TelemetryClient,
63
67
  config: SequencerConfig = {},
64
68
  private log = createDebugLogger('aztec:sequencer'),
65
69
  ) {
66
70
  this.updateConfig(config);
71
+ this.tracer = telemetry.getTracer('Sequencer');
67
72
  this.log.verbose(`Initialized sequencer with ${this.minTxsPerBLock}-${this.maxTxsPerBlock} txs per block.`);
68
73
  }
69
74
 
@@ -87,15 +92,15 @@ export class Sequencer {
87
92
  if (config.feeRecipient) {
88
93
  this._feeRecipient = config.feeRecipient;
89
94
  }
90
- if (config.allowedFunctionsInSetup) {
91
- this.allowedFunctionsInSetup = config.allowedFunctionsInSetup;
95
+ if (config.allowedInSetup) {
96
+ this.allowedInSetup = config.allowedInSetup;
92
97
  }
93
98
  if (config.maxBlockSizeInBytes) {
94
99
  this.maxBlockSizeInBytes = config.maxBlockSizeInBytes;
95
100
  }
96
101
  // TODO(#5917) remove this. it is no longer needed since we don't need to whitelist functions in teardown
97
- if (config.allowedFunctionsInTeardown) {
98
- this.allowedFunctionsInTeardown = config.allowedFunctionsInTeardown;
102
+ if (config.allowedInTeardown) {
103
+ this.allowedInTeardown = config.allowedInTeardown;
99
104
  }
100
105
  }
101
106
 
@@ -162,7 +167,18 @@ export class Sequencer {
162
167
  return;
163
168
  }
164
169
 
165
- const workTimer = new Timer();
170
+ const historicalHeader = (await this.l2BlockSource.getBlock(-1))?.header;
171
+ const newBlockNumber =
172
+ (historicalHeader === undefined
173
+ ? await this.l2BlockSource.getBlockNumber()
174
+ : Number(historicalHeader.globalVariables.blockNumber.toBigInt())) + 1;
175
+
176
+ // Do not go forward with new block if not my turn
177
+ if (!(await this.publisher.isItMyTurnToSubmit(newBlockNumber))) {
178
+ this.log.verbose('Not my turn to submit block');
179
+ return;
180
+ }
181
+
166
182
  this.state = SequencerState.WAITING_FOR_TXS;
167
183
 
168
184
  // Get txs to build the new block
@@ -172,22 +188,6 @@ export class Sequencer {
172
188
  }
173
189
  this.log.debug(`Retrieved ${pendingTxs.length} txs from P2P pool`);
174
190
 
175
- const historicalHeader = (await this.l2BlockSource.getBlock(-1))?.header;
176
- const newBlockNumber =
177
- (historicalHeader === undefined
178
- ? await this.l2BlockSource.getBlockNumber()
179
- : Number(historicalHeader.globalVariables.blockNumber.toBigInt())) + 1;
180
-
181
- /**
182
- * We'll call this function before running expensive operations to avoid wasted work.
183
- */
184
- const assertBlockHeight = async () => {
185
- const currentBlockNumber = await this.l2BlockSource.getBlockNumber();
186
- if (currentBlockNumber + 1 !== newBlockNumber) {
187
- throw new Error('New block was emitted while building block');
188
- }
189
- };
190
-
191
191
  const newGlobalVariables = await this.globalsBuilder.buildGlobalVariables(
192
192
  new Fr(newBlockNumber),
193
193
  this._coinbase,
@@ -197,7 +197,7 @@ export class Sequencer {
197
197
  // TODO: It should be responsibility of the P2P layer to validate txs before passing them on here
198
198
  const allValidTxs = await this.takeValidTxs(
199
199
  pendingTxs,
200
- this.txValidatorFactory.validatorForNewTxs(newGlobalVariables, this.allowedFunctionsInSetup),
200
+ this.txValidatorFactory.validatorForNewTxs(newGlobalVariables, this.allowedInSetup),
201
201
  );
202
202
 
203
203
  // TODO: We are taking the size of the tx from private-land, but we should be doing this after running
@@ -211,72 +211,7 @@ export class Sequencer {
211
211
  return;
212
212
  }
213
213
 
214
- this.log.info(`Building block ${newBlockNumber} with ${validTxs.length} transactions`);
215
- this.state = SequencerState.CREATING_BLOCK;
216
-
217
- // Get l1 to l2 messages from the contract
218
- this.log.debug('Requesting L1 to L2 messages from contract');
219
- const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(BigInt(newBlockNumber));
220
- this.log.verbose(`Retrieved ${l1ToL2Messages.length} L1 to L2 messages for block ${newBlockNumber}`);
221
-
222
- // We create a fresh processor each time to reset any cached state (eg storage writes)
223
- const processor = await this.publicProcessorFactory.create(historicalHeader, newGlobalVariables);
224
-
225
- const blockBuildingTimer = new Timer();
226
-
227
- // We must initialise the block to be a power of 2 in size
228
- const numRealTxs = validTxs.length;
229
- const pow2 = Math.log2(numRealTxs);
230
- // TODO turn this back into a Math.ceil once we can pad blocks to the next-power-of-2 with empty txs
231
- const totalTxs = 2 ** Math.ceil(pow2);
232
- const blockSize = Math.max(2, totalTxs);
233
- const blockTicket = await this.prover.startNewBlock(blockSize, newGlobalVariables, l1ToL2Messages);
234
-
235
- const [publicProcessorDuration, [processedTxs, failedTxs]] = await elapsed(() =>
236
- processor.process(validTxs, blockSize, this.prover, this.txValidatorFactory.validatorForProcessedTxs()),
237
- );
238
- if (failedTxs.length > 0) {
239
- const failedTxData = failedTxs.map(fail => fail.tx);
240
- this.log.debug(`Dropping failed txs ${Tx.getHashes(failedTxData).join(', ')}`);
241
- await this.p2pClient.deleteTxs(Tx.getHashes(failedTxData));
242
- }
243
-
244
- if (processedTxs.length === 0) {
245
- this.log.verbose('No txs processed correctly to build block. Exiting');
246
- this.prover.cancelBlock();
247
- return;
248
- }
249
-
250
- await assertBlockHeight();
251
-
252
- // All real transactions have been added, set the block as full and complete the proving.
253
- await this.prover.setBlockCompleted();
254
-
255
- // Here we are now waiting for the block to be proven.
256
- // TODO(@PhilWindle) We should probably periodically check for things like another
257
- // block being published before ours instead of just waiting on our block
258
- const result = await blockTicket.provingPromise;
259
- if (result.status === PROVING_STATUS.FAILURE) {
260
- throw new Error(`Block proving failed, reason: ${result.reason}`);
261
- }
262
-
263
- await assertBlockHeight();
264
-
265
- // Block is proven, now finalise and publish!
266
- const { block, aggregationObject, proof } = await this.prover.finaliseBlock();
267
-
268
- await assertBlockHeight();
269
-
270
- this.log.verbose(`Assembled block ${block.number}`, {
271
- eventName: 'l2-block-built',
272
- duration: workTimer.ms(),
273
- publicProcessDuration: publicProcessorDuration,
274
- rollupCircuitsDuration: blockBuildingTimer.ms(),
275
- ...block.getStats(),
276
- } satisfies L2BlockBuiltStats);
277
-
278
- await this.publishL2Block(block, aggregationObject, proof);
279
- this.log.info(`Submitted rollup block ${block.number} with ${processedTxs.length} transactions`);
214
+ await this.buildBlockAndPublish(validTxs, newGlobalVariables, historicalHeader);
280
215
  } catch (err) {
281
216
  if (BlockProofError.isBlockProofError(err)) {
282
217
  const txHashes = err.txHashes.filter(h => !h.isZero());
@@ -290,10 +225,100 @@ export class Sequencer {
290
225
  }
291
226
  }
292
227
 
228
+ @trackSpan('Sequencer.buildBlockAndPublish', (_validTxs, newGlobalVariables, _historicalHeader) => ({
229
+ [Attributes.BLOCK_NUMBER]: newGlobalVariables.blockNumber.toNumber(),
230
+ }))
231
+ private async buildBlockAndPublish(
232
+ validTxs: Tx[],
233
+ newGlobalVariables: GlobalVariables,
234
+ historicalHeader: Header | undefined,
235
+ ): Promise<void> {
236
+ const workTimer = new Timer();
237
+ this.state = SequencerState.CREATING_BLOCK;
238
+ this.log.info(`Building block ${newGlobalVariables.blockNumber.toNumber()} with ${validTxs.length} transactions`);
239
+
240
+ const assertBlockHeight = async () => {
241
+ const currentBlockNumber = await this.l2BlockSource.getBlockNumber();
242
+ if (currentBlockNumber + 1 !== newGlobalVariables.blockNumber.toNumber()) {
243
+ throw new Error('New block was emitted while building block');
244
+ }
245
+ if (!(await this.publisher.isItMyTurnToSubmit(newGlobalVariables.blockNumber.toNumber()))) {
246
+ throw new Error(`Not this sequencer turn to submit block`);
247
+ }
248
+ };
249
+
250
+ // Get l1 to l2 messages from the contract
251
+ this.log.debug('Requesting L1 to L2 messages from contract');
252
+ const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(newGlobalVariables.blockNumber.toBigInt());
253
+ this.log.verbose(
254
+ `Retrieved ${l1ToL2Messages.length} L1 to L2 messages for block ${newGlobalVariables.blockNumber.toNumber()}`,
255
+ );
256
+
257
+ // We create a fresh processor each time to reset any cached state (eg storage writes)
258
+ const processor = await this.publicProcessorFactory.create(historicalHeader, newGlobalVariables);
259
+
260
+ const numRealTxs = validTxs.length;
261
+ const pow2 = Math.log2(numRealTxs);
262
+ const totalTxs = 2 ** Math.ceil(pow2);
263
+ const blockSize = Math.max(2, totalTxs);
264
+
265
+ const blockBuildingTimer = new Timer();
266
+ const blockTicket = await this.prover.startNewBlock(blockSize, newGlobalVariables, l1ToL2Messages);
267
+
268
+ const [publicProcessorDuration, [processedTxs, failedTxs]] = await elapsed(() =>
269
+ processor.process(validTxs, blockSize, this.prover, this.txValidatorFactory.validatorForProcessedTxs()),
270
+ );
271
+ if (failedTxs.length > 0) {
272
+ const failedTxData = failedTxs.map(fail => fail.tx);
273
+ this.log.debug(`Dropping failed txs ${Tx.getHashes(failedTxData).join(', ')}`);
274
+ await this.p2pClient.deleteTxs(Tx.getHashes(failedTxData));
275
+ }
276
+
277
+ if (processedTxs.length === 0) {
278
+ this.log.verbose('No txs processed correctly to build block. Exiting');
279
+ this.prover.cancelBlock();
280
+ return;
281
+ }
282
+
283
+ await assertBlockHeight();
284
+
285
+ // All real transactions have been added, set the block as full and complete the proving.
286
+ await this.prover.setBlockCompleted();
287
+
288
+ // Here we are now waiting for the block to be proven.
289
+ // TODO(@PhilWindle) We should probably periodically check for things like another
290
+ // block being published before ours instead of just waiting on our block
291
+ const result = await blockTicket.provingPromise;
292
+ if (result.status === PROVING_STATUS.FAILURE) {
293
+ throw new Error(`Block proving failed, reason: ${result.reason}`);
294
+ }
295
+
296
+ await assertBlockHeight();
297
+
298
+ // Block is proven, now finalise and publish!
299
+ const { block, aggregationObject, proof } = await this.prover.finaliseBlock();
300
+
301
+ await assertBlockHeight();
302
+
303
+ this.log.verbose(`Assembled block ${block.number}`, {
304
+ eventName: 'l2-block-built',
305
+ duration: workTimer.ms(),
306
+ publicProcessDuration: publicProcessorDuration,
307
+ rollupCircuitsDuration: blockBuildingTimer.ms(),
308
+ ...block.getStats(),
309
+ } satisfies L2BlockBuiltStats);
310
+
311
+ await this.publishL2Block(block, aggregationObject, proof);
312
+ this.log.info(`Submitted rollup block ${block.number} with ${processedTxs.length} transactions`);
313
+ }
314
+
293
315
  /**
294
316
  * Publishes the L2Block to the rollup contract.
295
317
  * @param block - The L2Block to be published.
296
318
  */
319
+ @trackSpan('Sequencer.publishL2Block', block => ({
320
+ [Attributes.BLOCK_NUMBER]: block.number,
321
+ }))
297
322
  protected async publishL2Block(block: L2Block, aggregationObject: Fr[], proof: Proof) {
298
323
  // Publishes new block to the network and awaits the tx to be mined
299
324
  this.state = SequencerState.PUBLISHING_BLOCK;
@@ -321,10 +346,10 @@ export class Sequencer {
321
346
 
322
347
  const toReturn: Tx[] = [];
323
348
  for (const tx of txs) {
324
- const txSize = tx.getStats().size - tx.proof.toBuffer().length;
349
+ const txSize = tx.getSize() - tx.proof.toBuffer().length;
325
350
  if (totalSize + txSize > maxSize) {
326
351
  this.log.warn(
327
- `Dropping tx ${tx.getTxHash()} with size ${txSize} due to exceeding ${maxSize} block size limit (currently at ${totalSize})`,
352
+ `Dropping tx ${tx.getTxHash()} with estimated size ${txSize} due to exceeding ${maxSize} block size limit (currently at ${totalSize})`,
328
353
  );
329
354
  continue;
330
355
  }
@@ -1,8 +1,8 @@
1
- import { type Tx, type TxValidator } from '@aztec/circuit-types';
1
+ import { PublicKernelType, type Tx, type TxValidator } from '@aztec/circuit-types';
2
2
  import { type AztecAddress, type Fr } from '@aztec/circuits.js';
3
3
  import { createDebugLogger } from '@aztec/foundation/log';
4
4
  import { GasTokenArtifact } from '@aztec/protocol-contracts/gas-token';
5
- import { AbstractPhaseManager, PublicKernelPhase, computeFeePayerBalanceStorageSlot } from '@aztec/simulator';
5
+ import { AbstractPhaseManager, computeFeePayerBalanceStorageSlot } from '@aztec/simulator';
6
6
 
7
7
  /** Provides a view into public contract state */
8
8
  export interface PublicStateSource {
@@ -14,7 +14,7 @@ export class GasTxValidator implements TxValidator<Tx> {
14
14
  #publicDataSource: PublicStateSource;
15
15
  #gasTokenAddress: AztecAddress;
16
16
 
17
- constructor(publicDataSource: PublicStateSource, gasTokenAddress: AztecAddress) {
17
+ constructor(publicDataSource: PublicStateSource, gasTokenAddress: AztecAddress, public enforceFees: boolean) {
18
18
  this.#publicDataSource = publicDataSource;
19
19
  this.#gasTokenAddress = gasTokenAddress;
20
20
  }
@@ -38,7 +38,11 @@ export class GasTxValidator implements TxValidator<Tx> {
38
38
  const feePayer = tx.data.feePayer;
39
39
  // TODO(@spalladino) Eventually remove the is_zero condition as we should always charge fees to every tx
40
40
  if (feePayer.isZero()) {
41
- return true;
41
+ if (this.enforceFees) {
42
+ this.#log.warn(`Rejecting transaction ${tx.getTxHash()} due to missing fee payer`);
43
+ } else {
44
+ return true;
45
+ }
42
46
  }
43
47
 
44
48
  // Compute the maximum fee that this tx may pay, based on its gasLimits and maxFeePerGas
@@ -51,7 +55,7 @@ export class GasTxValidator implements TxValidator<Tx> {
51
55
  );
52
56
 
53
57
  // If there is a claim in this tx that increases the fee payer balance in gas token, add it to balance
54
- const { [PublicKernelPhase.SETUP]: setupFns } = AbstractPhaseManager.extractEnqueuedPublicCallsByPhase(tx);
58
+ const { [PublicKernelType.SETUP]: setupFns } = AbstractPhaseManager.extractEnqueuedPublicCallsByPhase(tx);
55
59
  const claimFunctionCall = setupFns.find(
56
60
  fn =>
57
61
  fn.contractAddress.equals(this.#gasTokenAddress) &&
@@ -1,14 +1,14 @@
1
- import { type AllowedFunction, Tx, type TxValidator } from '@aztec/circuit-types';
1
+ import { type AllowedElement, PublicKernelType, Tx, type TxValidator } from '@aztec/circuit-types';
2
2
  import { type PublicCallRequest } from '@aztec/circuits.js';
3
3
  import { createDebugLogger } from '@aztec/foundation/log';
4
- import { AbstractPhaseManager, ContractsDataSourcePublicDB, PublicKernelPhase } from '@aztec/simulator';
4
+ import { AbstractPhaseManager, ContractsDataSourcePublicDB } from '@aztec/simulator';
5
5
  import { type ContractDataSource } from '@aztec/types/contracts';
6
6
 
7
7
  export class PhasesTxValidator implements TxValidator<Tx> {
8
8
  #log = createDebugLogger('aztec:sequencer:tx_validator:tx_phases');
9
9
  private contractDataSource: ContractsDataSourcePublicDB;
10
10
 
11
- constructor(contracts: ContractDataSource, private setupAllowList: AllowedFunction[]) {
11
+ constructor(contracts: ContractDataSource, private setupAllowList: AllowedElement[]) {
12
12
  this.contractDataSource = new ContractsDataSourcePublicDB(contracts);
13
13
  }
14
14
 
@@ -40,7 +40,7 @@ export class PhasesTxValidator implements TxValidator<Tx> {
40
40
  return true;
41
41
  }
42
42
 
43
- const { [PublicKernelPhase.SETUP]: setupFns } = AbstractPhaseManager.extractEnqueuedPublicCallsByPhase(tx);
43
+ const { [PublicKernelType.SETUP]: setupFns } = AbstractPhaseManager.extractEnqueuedPublicCallsByPhase(tx);
44
44
 
45
45
  for (const setupFn of setupFns) {
46
46
  if (!(await this.isOnAllowList(setupFn, this.setupAllowList))) {
@@ -57,7 +57,7 @@ export class PhasesTxValidator implements TxValidator<Tx> {
57
57
  return true;
58
58
  }
59
59
 
60
- async isOnAllowList(publicCall: PublicCallRequest, allowList: AllowedFunction[]): Promise<boolean> {
60
+ async isOnAllowList(publicCall: PublicCallRequest, allowList: AllowedElement[]): Promise<boolean> {
61
61
  if (publicCall.isEmpty()) {
62
62
  return true;
63
63
  }
@@ -66,27 +66,37 @@ export class PhasesTxValidator implements TxValidator<Tx> {
66
66
 
67
67
  // do these checks first since they don't require the contract class
68
68
  for (const entry of allowList) {
69
- if (!('address' in entry)) {
70
- continue;
69
+ if ('address' in entry && !('selector' in entry)) {
70
+ if (contractAddress.equals(entry.address)) {
71
+ return true;
72
+ }
71
73
  }
72
74
 
73
- if (contractAddress.equals(entry.address) && entry.selector.equals(functionSelector)) {
74
- return true;
75
+ if ('address' in entry && 'selector' in entry) {
76
+ if (contractAddress.equals(entry.address) && entry.selector.equals(functionSelector)) {
77
+ return true;
78
+ }
75
79
  }
76
- }
77
80
 
78
- const contractClass = await this.contractDataSource.getContractInstance(contractAddress);
79
- if (!contractClass) {
80
- throw new Error(`Contract not found: ${publicCall.contractAddress.toString()}`);
81
- }
81
+ const contractClass = await this.contractDataSource.getContractInstance(contractAddress);
82
82
 
83
- for (const entry of allowList) {
84
- if (!('classId' in entry)) {
85
- continue;
83
+ if (!contractClass) {
84
+ throw new Error(`Contract not found: ${publicCall.contractAddress.toString()}`);
85
+ }
86
+
87
+ if ('classId' in entry && !('selector' in entry)) {
88
+ if (contractClass.contractClassId.equals(entry.classId)) {
89
+ return true;
90
+ }
86
91
  }
87
92
 
88
- if (contractClass.contractClassId.equals(entry.classId) && entry.selector.equals(functionSelector)) {
89
- return true;
93
+ if ('classId' in entry && 'selector' in entry) {
94
+ if (
95
+ contractClass.contractClassId.equals(entry.classId) &&
96
+ (entry.selector === undefined || entry.selector.equals(functionSelector))
97
+ ) {
98
+ return true;
99
+ }
90
100
  }
91
101
  }
92
102
 
@@ -1,4 +1,4 @@
1
- import { type AllowedFunction, type ProcessedTx, type Tx, type TxValidator } from '@aztec/circuit-types';
1
+ import { type AllowedElement, type ProcessedTx, type Tx, type TxValidator } from '@aztec/circuit-types';
2
2
  import { type GlobalVariables } from '@aztec/circuits.js';
3
3
  import { GasTokenAddress } from '@aztec/protocol-contracts/gas-token';
4
4
  import { WorldStateDB, WorldStatePublicDB } from '@aztec/simulator';
@@ -12,14 +12,18 @@ import { MetadataTxValidator } from './metadata_validator.js';
12
12
  import { PhasesTxValidator } from './phases_validator.js';
13
13
 
14
14
  export class TxValidatorFactory {
15
- constructor(private merkleTreeDb: MerkleTreeOperations, private contractDataSource: ContractDataSource) {}
15
+ constructor(
16
+ private merkleTreeDb: MerkleTreeOperations,
17
+ private contractDataSource: ContractDataSource,
18
+ private enforceFees: boolean,
19
+ ) {}
16
20
 
17
- validatorForNewTxs(globalVariables: GlobalVariables, setupAllowList: AllowedFunction[]): TxValidator<Tx> {
21
+ validatorForNewTxs(globalVariables: GlobalVariables, setupAllowList: AllowedElement[]): TxValidator<Tx> {
18
22
  return new AggregateTxValidator(
19
23
  new MetadataTxValidator(globalVariables),
20
24
  new DoubleSpendTxValidator(new WorldStateDB(this.merkleTreeDb)),
21
25
  new PhasesTxValidator(this.contractDataSource, setupAllowList),
22
- new GasTxValidator(new WorldStatePublicDB(this.merkleTreeDb), GasTokenAddress),
26
+ new GasTxValidator(new WorldStatePublicDB(this.merkleTreeDb), GasTokenAddress, this.enforceFees),
23
27
  );
24
28
  }
25
29