@aztec/sequencer-client 0.67.0 → 0.67.1-devnet
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/config.d.ts +3 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +3 -56
- package/dest/index.d.ts +0 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -2
- package/dest/publisher/index.d.ts +0 -1
- package/dest/publisher/index.d.ts.map +1 -1
- package/dest/publisher/index.js +1 -2
- package/dest/publisher/l1-publisher.d.ts.map +1 -1
- package/dest/publisher/l1-publisher.js +145 -35
- package/dest/sequencer/allowed.d.ts +3 -0
- package/dest/sequencer/allowed.d.ts.map +1 -0
- package/dest/sequencer/allowed.js +34 -0
- package/dest/sequencer/config.d.ts +1 -1
- package/dest/sequencer/config.d.ts.map +1 -1
- package/dest/sequencer/sequencer.d.ts +0 -4
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +20 -50
- package/dest/tx_validator/gas_validator.d.ts +3 -4
- package/dest/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/tx_validator/gas_validator.js +25 -8
- package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
- package/dest/tx_validator/tx_validator_factory.js +6 -4
- package/package.json +23 -20
- package/src/config.ts +5 -60
- package/src/index.ts +0 -1
- package/src/publisher/index.ts +0 -1
- package/src/publisher/l1-publisher.ts +183 -55
- package/src/sequencer/allowed.ts +36 -0
- package/src/sequencer/config.ts +1 -1
- package/src/sequencer/sequencer.ts +19 -66
- package/src/tx_validator/gas_validator.ts +32 -6
- package/src/tx_validator/tx_validator_factory.ts +11 -3
|
@@ -38,6 +38,7 @@ import { type GlobalVariableBuilder } from '../global_variable_builder/global_bu
|
|
|
38
38
|
import { type L1Publisher } from '../publisher/l1-publisher.js';
|
|
39
39
|
import { prettyLogViemErrorMsg } from '../publisher/utils.js';
|
|
40
40
|
import { type TxValidatorFactory } from '../tx_validator/tx_validator_factory.js';
|
|
41
|
+
import { getDefaultAllowedSetupFunctions } from './allowed.js';
|
|
41
42
|
import { type SequencerConfig } from './config.js';
|
|
42
43
|
import { SequencerMetrics } from './metrics.js';
|
|
43
44
|
import { SequencerState, getSecondsIntoSlot, orderAttestations } from './utils.js';
|
|
@@ -76,13 +77,11 @@ export class Sequencer {
|
|
|
76
77
|
private pollingIntervalMs: number = 1000;
|
|
77
78
|
private maxTxsPerBlock = 32;
|
|
78
79
|
private minTxsPerBLock = 1;
|
|
79
|
-
private minSecondsBetweenBlocks = 0;
|
|
80
|
-
private maxSecondsBetweenBlocks = 0;
|
|
81
80
|
// TODO: zero values should not be allowed for the following 2 values in PROD
|
|
82
81
|
private _coinbase = EthAddress.ZERO;
|
|
83
82
|
private _feeRecipient = AztecAddress.ZERO;
|
|
84
83
|
private state = SequencerState.STOPPED;
|
|
85
|
-
private allowedInSetup: AllowedElement[] =
|
|
84
|
+
private allowedInSetup: AllowedElement[] = getDefaultAllowedSetupFunctions();
|
|
86
85
|
private maxBlockSizeInBytes: number = 1024 * 1024;
|
|
87
86
|
private metrics: SequencerMetrics;
|
|
88
87
|
private isFlushing: boolean = false;
|
|
@@ -127,10 +126,7 @@ export class Sequencer {
|
|
|
127
126
|
* @param config - New parameters.
|
|
128
127
|
*/
|
|
129
128
|
public updateConfig(config: SequencerConfig) {
|
|
130
|
-
this.log.info(
|
|
131
|
-
`Sequencer config set`,
|
|
132
|
-
omit(pickFromSchema(this.config, SequencerConfigSchema), 'allowedInSetup', 'allowedInTeardown'),
|
|
133
|
-
);
|
|
129
|
+
this.log.info(`Sequencer config set`, omit(pickFromSchema(config, SequencerConfigSchema), 'allowedInSetup'));
|
|
134
130
|
|
|
135
131
|
if (config.transactionPollingIntervalMS !== undefined) {
|
|
136
132
|
this.pollingIntervalMs = config.transactionPollingIntervalMS;
|
|
@@ -141,12 +137,6 @@ export class Sequencer {
|
|
|
141
137
|
if (config.minTxsPerBlock !== undefined) {
|
|
142
138
|
this.minTxsPerBLock = config.minTxsPerBlock;
|
|
143
139
|
}
|
|
144
|
-
if (config.minSecondsBetweenBlocks !== undefined) {
|
|
145
|
-
this.minSecondsBetweenBlocks = config.minSecondsBetweenBlocks;
|
|
146
|
-
}
|
|
147
|
-
if (config.maxSecondsBetweenBlocks !== undefined) {
|
|
148
|
-
this.maxSecondsBetweenBlocks = config.maxSecondsBetweenBlocks;
|
|
149
|
-
}
|
|
150
140
|
if (config.coinbase) {
|
|
151
141
|
this._coinbase = config.coinbase;
|
|
152
142
|
}
|
|
@@ -192,7 +182,7 @@ export class Sequencer {
|
|
|
192
182
|
* Starts the sequencer and moves to IDLE state.
|
|
193
183
|
*/
|
|
194
184
|
public start() {
|
|
195
|
-
this.runningPromise = new RunningPromise(this.work.bind(this), this.pollingIntervalMs);
|
|
185
|
+
this.runningPromise = new RunningPromise(this.work.bind(this), this.log, this.pollingIntervalMs);
|
|
196
186
|
this.setState(SequencerState.IDLE, 0n, true /** force */);
|
|
197
187
|
this.runningPromise.start();
|
|
198
188
|
this.log.info(`Sequencer started with address ${this.publisher.getSenderAddress().toString()}`);
|
|
@@ -339,6 +329,7 @@ export class Sequencer {
|
|
|
339
329
|
this.setState(SequencerState.IDLE, 0n);
|
|
340
330
|
}
|
|
341
331
|
|
|
332
|
+
@trackSpan('Sequencer.work')
|
|
342
333
|
protected async work() {
|
|
343
334
|
try {
|
|
344
335
|
await this.doRealWork();
|
|
@@ -354,15 +345,6 @@ export class Sequencer {
|
|
|
354
345
|
}
|
|
355
346
|
}
|
|
356
347
|
|
|
357
|
-
/** Whether to skip the check of min txs per block if more than maxSecondsBetweenBlocks has passed since the previous block. */
|
|
358
|
-
private skipMinTxsPerBlockCheck(historicalHeader: BlockHeader | undefined): boolean {
|
|
359
|
-
const lastBlockTime = historicalHeader?.globalVariables.timestamp.toNumber() || 0;
|
|
360
|
-
const currentTime = Math.floor(Date.now() / 1000);
|
|
361
|
-
const elapsed = currentTime - lastBlockTime;
|
|
362
|
-
|
|
363
|
-
return this.maxSecondsBetweenBlocks > 0 && elapsed >= this.maxSecondsBetweenBlocks;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
348
|
async mayProposeBlock(tipArchive: Buffer, proposalBlockNumber: bigint): Promise<bigint> {
|
|
367
349
|
// This checks that we can propose, and gives us the slot that we are to propose for
|
|
368
350
|
try {
|
|
@@ -445,53 +427,29 @@ export class Sequencer {
|
|
|
445
427
|
`Last block mined at ${lastBlockTime} current time is ${currentTime} (elapsed ${elapsedSinceLastBlock})`,
|
|
446
428
|
);
|
|
447
429
|
|
|
448
|
-
//
|
|
449
|
-
|
|
450
|
-
if (this.minSecondsBetweenBlocks > 0 && elapsedSinceLastBlock < this.minSecondsBetweenBlocks) {
|
|
430
|
+
// We need to have at least minTxsPerBLock txs.
|
|
431
|
+
if (args.pendingTxsCount != undefined && args.pendingTxsCount < this.minTxsPerBLock) {
|
|
451
432
|
this.log.verbose(
|
|
452
|
-
`Not creating block because not enough
|
|
433
|
+
`Not creating block because not enough txs in the pool (got ${args.pendingTxsCount} min ${this.minTxsPerBLock})`,
|
|
453
434
|
);
|
|
454
435
|
return false;
|
|
455
436
|
}
|
|
456
437
|
|
|
457
|
-
const skipCheck = this.skipMinTxsPerBlockCheck(historicalHeader);
|
|
458
|
-
|
|
459
|
-
// If we haven't hit the maxSecondsBetweenBlocks, we need to have at least minTxsPerBLock txs.
|
|
460
|
-
if (args.pendingTxsCount != undefined) {
|
|
461
|
-
if (args.pendingTxsCount < this.minTxsPerBLock) {
|
|
462
|
-
if (skipCheck) {
|
|
463
|
-
this.log.debug(
|
|
464
|
-
`Creating block with only ${args.pendingTxsCount} txs as more than ${this.maxSecondsBetweenBlocks}s have passed since last block`,
|
|
465
|
-
);
|
|
466
|
-
} else {
|
|
467
|
-
this.log.verbose(
|
|
468
|
-
`Not creating block because not enough txs in the pool (got ${args.pendingTxsCount} min ${this.minTxsPerBLock})`,
|
|
469
|
-
);
|
|
470
|
-
return false;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
438
|
// Bail if we don't have enough valid txs
|
|
476
|
-
if (args.validTxsCount != undefined) {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
);
|
|
482
|
-
return false;
|
|
483
|
-
}
|
|
439
|
+
if (args.validTxsCount != undefined && args.validTxsCount < this.minTxsPerBLock) {
|
|
440
|
+
this.log.verbose(
|
|
441
|
+
`Not creating block because not enough valid txs loaded from the pool (got ${args.validTxsCount} min ${this.minTxsPerBLock})`,
|
|
442
|
+
);
|
|
443
|
+
return false;
|
|
484
444
|
}
|
|
485
445
|
|
|
486
446
|
// TODO: This check should be processedTxs.length < this.minTxsPerBLock, so we don't publish a block with
|
|
487
447
|
// less txs than the minimum. But that'd cause the entire block to be aborted and retried. Instead, we should
|
|
488
448
|
// go back to the p2p pool and load more txs until we hit our minTxsPerBLock target. Only if there are no txs
|
|
489
449
|
// we should bail.
|
|
490
|
-
if (args.processedTxsCount
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
return false;
|
|
494
|
-
}
|
|
450
|
+
if (args.processedTxsCount === 0 && this.minTxsPerBLock > 0) {
|
|
451
|
+
this.log.verbose('No txs processed correctly to build block.');
|
|
452
|
+
return false;
|
|
495
453
|
}
|
|
496
454
|
|
|
497
455
|
return true;
|
|
@@ -544,21 +502,17 @@ export class Sequencer {
|
|
|
544
502
|
const processor = this.publicProcessorFactory.create(publicProcessorFork, historicalHeader, newGlobalVariables);
|
|
545
503
|
const blockBuildingTimer = new Timer();
|
|
546
504
|
const blockBuilder = this.blockBuilderFactory.create(orchestratorFork);
|
|
547
|
-
await blockBuilder.startNewBlock(
|
|
505
|
+
await blockBuilder.startNewBlock(newGlobalVariables, l1ToL2Messages);
|
|
548
506
|
|
|
549
507
|
const [publicProcessorDuration, [processedTxs, failedTxs]] = await elapsed(() =>
|
|
550
|
-
processor.process(
|
|
551
|
-
validTxs,
|
|
552
|
-
blockSize,
|
|
553
|
-
blockBuilder,
|
|
554
|
-
this.txValidatorFactory.validatorForProcessedTxs(publicProcessorFork),
|
|
555
|
-
),
|
|
508
|
+
processor.process(validTxs, blockSize, this.txValidatorFactory.validatorForProcessedTxs(publicProcessorFork)),
|
|
556
509
|
);
|
|
557
510
|
if (failedTxs.length > 0) {
|
|
558
511
|
const failedTxData = failedTxs.map(fail => fail.tx);
|
|
559
512
|
this.log.verbose(`Dropping failed txs ${Tx.getHashes(failedTxData).join(', ')}`);
|
|
560
513
|
await this.p2pClient.deleteTxs(Tx.getHashes(failedTxData));
|
|
561
514
|
}
|
|
515
|
+
await blockBuilder.addTxs(processedTxs);
|
|
562
516
|
|
|
563
517
|
await interrupt?.(processedTxs);
|
|
564
518
|
|
|
@@ -649,7 +603,6 @@ export class Sequencer {
|
|
|
649
603
|
const blockHash = block.hash();
|
|
650
604
|
const txHashes = validTxs.map(tx => tx.getTxHash());
|
|
651
605
|
this.log.info(`Built block ${block.number} with hash ${blockHash}`, {
|
|
652
|
-
txEffectsHash: block.header.contentCommitment.txsEffectsHash.toString('hex'),
|
|
653
606
|
blockHash,
|
|
654
607
|
globalVariables: block.header.globalVariables.toInspect(),
|
|
655
608
|
txHashes,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Tx, TxExecutionPhase, type TxValidator } from '@aztec/circuit-types';
|
|
2
|
-
import { type AztecAddress, type Fr, FunctionSelector } from '@aztec/circuits.js';
|
|
2
|
+
import { type AztecAddress, type Fr, FunctionSelector, type GasFees } from '@aztec/circuits.js';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { computeFeePayerBalanceStorageSlot, getExecutionRequestsByPhase } from '@aztec/simulator';
|
|
5
5
|
|
|
@@ -12,36 +12,62 @@ export class GasTxValidator implements TxValidator<Tx> {
|
|
|
12
12
|
#log = createLogger('sequencer:tx_validator:tx_gas');
|
|
13
13
|
#publicDataSource: PublicStateSource;
|
|
14
14
|
#feeJuiceAddress: AztecAddress;
|
|
15
|
+
#enforceFees: boolean;
|
|
16
|
+
#gasFees: GasFees;
|
|
15
17
|
|
|
16
|
-
constructor(
|
|
18
|
+
constructor(
|
|
19
|
+
publicDataSource: PublicStateSource,
|
|
20
|
+
feeJuiceAddress: AztecAddress,
|
|
21
|
+
enforceFees: boolean,
|
|
22
|
+
gasFees: GasFees,
|
|
23
|
+
) {
|
|
17
24
|
this.#publicDataSource = publicDataSource;
|
|
18
25
|
this.#feeJuiceAddress = feeJuiceAddress;
|
|
26
|
+
this.#enforceFees = enforceFees;
|
|
27
|
+
this.#gasFees = gasFees;
|
|
19
28
|
}
|
|
20
29
|
|
|
21
|
-
async validateTxs(txs: Tx[]): Promise<[validTxs: Tx[], invalidTxs: Tx[]]> {
|
|
30
|
+
async validateTxs(txs: Tx[]): Promise<[validTxs: Tx[], invalidTxs: Tx[], skippedTxs: Tx[]]> {
|
|
22
31
|
const validTxs: Tx[] = [];
|
|
23
32
|
const invalidTxs: Tx[] = [];
|
|
33
|
+
const skippedTxs: Tx[] = [];
|
|
24
34
|
|
|
25
35
|
for (const tx of txs) {
|
|
26
|
-
if (
|
|
36
|
+
if (this.#shouldSkip(tx)) {
|
|
37
|
+
skippedTxs.push(tx);
|
|
38
|
+
} else if (await this.#validateTxFee(tx)) {
|
|
27
39
|
validTxs.push(tx);
|
|
28
40
|
} else {
|
|
29
41
|
invalidTxs.push(tx);
|
|
30
42
|
}
|
|
31
43
|
}
|
|
32
44
|
|
|
33
|
-
return [validTxs, invalidTxs];
|
|
45
|
+
return [validTxs, invalidTxs, skippedTxs];
|
|
34
46
|
}
|
|
35
47
|
|
|
36
48
|
validateTx(tx: Tx): Promise<boolean> {
|
|
37
49
|
return this.#validateTxFee(tx);
|
|
38
50
|
}
|
|
39
51
|
|
|
52
|
+
#shouldSkip(tx: Tx): boolean {
|
|
53
|
+
const gasSettings = tx.data.constants.txContext.gasSettings;
|
|
54
|
+
|
|
55
|
+
// Skip the tx if its max fees are not enough for the current block's gas fees.
|
|
56
|
+
const maxFeesPerGas = gasSettings.maxFeesPerGas;
|
|
57
|
+
const notEnoughMaxFees =
|
|
58
|
+
maxFeesPerGas.feePerDaGas.lt(this.#gasFees.feePerDaGas) ||
|
|
59
|
+
maxFeesPerGas.feePerL2Gas.lt(this.#gasFees.feePerL2Gas);
|
|
60
|
+
if (notEnoughMaxFees) {
|
|
61
|
+
this.#log.warn(`Skipping transaction ${tx.getTxHash()} due to insufficient fee per gas`);
|
|
62
|
+
}
|
|
63
|
+
return notEnoughMaxFees;
|
|
64
|
+
}
|
|
65
|
+
|
|
40
66
|
async #validateTxFee(tx: Tx): Promise<boolean> {
|
|
41
67
|
const feePayer = tx.data.feePayer;
|
|
42
68
|
// TODO(@spalladino) Eventually remove the is_zero condition as we should always charge fees to every tx
|
|
43
69
|
if (feePayer.isZero()) {
|
|
44
|
-
if (this
|
|
70
|
+
if (this.#enforceFees) {
|
|
45
71
|
this.#log.warn(`Rejecting transaction ${tx.getTxHash()} due to missing fee payer`);
|
|
46
72
|
} else {
|
|
47
73
|
return true;
|
|
@@ -29,7 +29,10 @@ export class TxValidatorFactory {
|
|
|
29
29
|
private enforceFees: boolean,
|
|
30
30
|
) {
|
|
31
31
|
this.nullifierSource = {
|
|
32
|
-
|
|
32
|
+
getNullifierIndices: nullifiers =>
|
|
33
|
+
this.committedDb
|
|
34
|
+
.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers)
|
|
35
|
+
.then(x => x.filter(index => index !== undefined) as bigint[]),
|
|
33
36
|
};
|
|
34
37
|
|
|
35
38
|
this.publicStateSource = {
|
|
@@ -45,13 +48,18 @@ export class TxValidatorFactory {
|
|
|
45
48
|
new MetadataTxValidator(globalVariables.chainId, globalVariables.blockNumber),
|
|
46
49
|
new DoubleSpendTxValidator(this.nullifierSource),
|
|
47
50
|
new PhasesTxValidator(this.contractDataSource, setupAllowList),
|
|
48
|
-
new GasTxValidator(
|
|
51
|
+
new GasTxValidator(
|
|
52
|
+
this.publicStateSource,
|
|
53
|
+
ProtocolContractAddress.FeeJuice,
|
|
54
|
+
this.enforceFees,
|
|
55
|
+
globalVariables.gasFees,
|
|
56
|
+
),
|
|
49
57
|
);
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
validatorForProcessedTxs(fork: MerkleTreeReadOperations): TxValidator<ProcessedTx> {
|
|
53
61
|
return new DoubleSpendTxValidator({
|
|
54
|
-
|
|
62
|
+
getNullifierIndices: nullifiers => fork.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers),
|
|
55
63
|
});
|
|
56
64
|
}
|
|
57
65
|
}
|