@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.
- package/dest/client/sequencer-client.d.ts +2 -1
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +4 -4
- package/dest/config.d.ts +13 -0
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +46 -35
- package/dest/publisher/l1-publisher.d.ts +4 -1
- package/dest/publisher/l1-publisher.d.ts.map +1 -1
- package/dest/publisher/l1-publisher.js +6 -1
- package/dest/publisher/viem-tx-sender.d.ts +3 -0
- package/dest/publisher/viem-tx-sender.d.ts.map +1 -1
- package/dest/publisher/viem-tx-sender.js +15 -1
- package/dest/sequencer/sequencer.d.ts +6 -3
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +284 -255
- package/dest/tx_validator/gas_validator.d.ts +2 -1
- package/dest/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/tx_validator/gas_validator.js +12 -5
- package/dest/tx_validator/phases_validator.d.ts +3 -3
- package/dest/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/tx_validator/phases_validator.js +25 -18
- package/dest/tx_validator/tx_validator_factory.d.ts +4 -3
- package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
- package/dest/tx_validator/tx_validator_factory.js +4 -3
- package/package.json +24 -15
- package/src/client/sequencer-client.ts +10 -2
- package/src/config.ts +47 -37
- package/src/publisher/l1-publisher.ts +11 -1
- package/src/publisher/viem-tx-sender.ts +15 -0
- package/src/sequencer/sequencer.ts +119 -94
- package/src/tx_validator/gas_validator.ts +9 -5
- package/src/tx_validator/phases_validator.ts +29 -19
- 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
|
|
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
|
|
50
|
-
private
|
|
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.
|
|
91
|
-
this.
|
|
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.
|
|
98
|
-
this.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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,
|
|
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
|
-
|
|
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 { [
|
|
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
|
|
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
|
|
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:
|
|
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 { [
|
|
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:
|
|
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 (!('
|
|
70
|
-
|
|
69
|
+
if ('address' in entry && !('selector' in entry)) {
|
|
70
|
+
if (contractAddress.equals(entry.address)) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
if (
|
|
74
|
-
|
|
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
|
-
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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 (
|
|
89
|
-
|
|
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
|
|
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(
|
|
15
|
+
constructor(
|
|
16
|
+
private merkleTreeDb: MerkleTreeOperations,
|
|
17
|
+
private contractDataSource: ContractDataSource,
|
|
18
|
+
private enforceFees: boolean,
|
|
19
|
+
) {}
|
|
16
20
|
|
|
17
|
-
validatorForNewTxs(globalVariables: GlobalVariables, setupAllowList:
|
|
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
|
|