@aztec/sequencer-client 0.66.0 → 0.67.1
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.js +2 -1
- package/dest/config.js +3 -3
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +3 -4
- package/dest/publisher/l1-publisher-metrics.d.ts.map +1 -1
- package/dest/publisher/l1-publisher-metrics.js +2 -8
- package/dest/publisher/l1-publisher.d.ts +3 -2
- package/dest/publisher/l1-publisher.d.ts.map +1 -1
- package/dest/publisher/l1-publisher.js +15 -16
- package/dest/publisher/utils.d.ts.map +1 -1
- package/dest/publisher/utils.js +2 -1
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +2 -8
- package/dest/sequencer/sequencer.d.ts +2 -2
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +99 -60
- package/dest/tx_validator/gas_validator.js +3 -3
- package/dest/tx_validator/phases_validator.js +3 -3
- package/package.json +23 -19
- package/src/client/sequencer-client.ts +1 -1
- package/src/config.ts +2 -2
- package/src/global_variable_builder/global_builder.ts +3 -3
- package/src/publisher/l1-publisher-metrics.ts +1 -7
- package/src/publisher/l1-publisher.ts +17 -18
- package/src/publisher/utils.ts +1 -0
- package/src/sequencer/metrics.ts +0 -7
- package/src/sequencer/sequencer.ts +126 -92
- package/src/tx_validator/gas_validator.ts +2 -2
- package/src/tx_validator/phases_validator.ts +2 -2
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type L2Block,
|
|
5
5
|
type L2BlockSource,
|
|
6
6
|
type ProcessedTx,
|
|
7
|
+
SequencerConfigSchema,
|
|
7
8
|
Tx,
|
|
8
9
|
type TxHash,
|
|
9
10
|
type TxValidator,
|
|
@@ -13,17 +14,19 @@ import type { AllowedElement, Signature, WorldStateSynchronizerStatus } from '@a
|
|
|
13
14
|
import { type L2BlockBuiltStats } from '@aztec/circuit-types/stats';
|
|
14
15
|
import {
|
|
15
16
|
AppendOnlyTreeSnapshot,
|
|
17
|
+
BlockHeader,
|
|
16
18
|
ContentCommitment,
|
|
17
19
|
GENESIS_ARCHIVE_ROOT,
|
|
18
20
|
type GlobalVariables,
|
|
19
|
-
Header,
|
|
20
21
|
StateReference,
|
|
21
22
|
} from '@aztec/circuits.js';
|
|
22
23
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
24
|
+
import { omit } from '@aztec/foundation/collection';
|
|
23
25
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
24
26
|
import { Fr } from '@aztec/foundation/fields';
|
|
25
|
-
import {
|
|
27
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
26
28
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
29
|
+
import { pickFromSchema } from '@aztec/foundation/schemas';
|
|
27
30
|
import { Timer, elapsed } from '@aztec/foundation/timer';
|
|
28
31
|
import { type P2P } from '@aztec/p2p';
|
|
29
32
|
import { type BlockBuilderFactory } from '@aztec/prover-client/block-builder';
|
|
@@ -31,8 +34,6 @@ import { type PublicProcessorFactory } from '@aztec/simulator';
|
|
|
31
34
|
import { Attributes, type TelemetryClient, type Tracer, trackSpan } from '@aztec/telemetry-client';
|
|
32
35
|
import { type ValidatorClient } from '@aztec/validator-client';
|
|
33
36
|
|
|
34
|
-
import { inspect } from 'util';
|
|
35
|
-
|
|
36
37
|
import { type GlobalVariableBuilder } from '../global_variable_builder/global_builder.js';
|
|
37
38
|
import { type L1Publisher } from '../publisher/l1-publisher.js';
|
|
38
39
|
import { prettyLogViemErrorMsg } from '../publisher/utils.js';
|
|
@@ -108,11 +109,10 @@ export class Sequencer {
|
|
|
108
109
|
private aztecSlotDuration: number,
|
|
109
110
|
telemetry: TelemetryClient,
|
|
110
111
|
private config: SequencerConfig = {},
|
|
111
|
-
private log =
|
|
112
|
+
private log = createLogger('sequencer'),
|
|
112
113
|
) {
|
|
113
114
|
this.updateConfig(config);
|
|
114
115
|
this.metrics = new SequencerMetrics(telemetry, () => this.state, 'Sequencer');
|
|
115
|
-
this.log.verbose(`Initialized sequencer with ${this.minTxsPerBLock}-${this.maxTxsPerBlock} txs per block.`);
|
|
116
116
|
|
|
117
117
|
// Register the block builder with the validator client for re-execution
|
|
118
118
|
this.validatorClient?.registerBlockBuilder(this.buildBlock.bind(this));
|
|
@@ -127,6 +127,11 @@ export class Sequencer {
|
|
|
127
127
|
* @param config - New parameters.
|
|
128
128
|
*/
|
|
129
129
|
public updateConfig(config: SequencerConfig) {
|
|
130
|
+
this.log.info(
|
|
131
|
+
`Sequencer config set`,
|
|
132
|
+
omit(pickFromSchema(this.config, SequencerConfigSchema), 'allowedInSetup', 'allowedInTeardown'),
|
|
133
|
+
);
|
|
134
|
+
|
|
130
135
|
if (config.transactionPollingIntervalMS !== undefined) {
|
|
131
136
|
this.pollingIntervalMs = config.transactionPollingIntervalMS;
|
|
132
137
|
}
|
|
@@ -188,9 +193,9 @@ export class Sequencer {
|
|
|
188
193
|
*/
|
|
189
194
|
public start() {
|
|
190
195
|
this.runningPromise = new RunningPromise(this.work.bind(this), this.pollingIntervalMs);
|
|
191
|
-
this.runningPromise.start();
|
|
192
196
|
this.setState(SequencerState.IDLE, 0n, true /** force */);
|
|
193
|
-
this.
|
|
197
|
+
this.runningPromise.start();
|
|
198
|
+
this.log.info(`Sequencer started with address ${this.publisher.getSenderAddress().toString()}`);
|
|
194
199
|
return Promise.resolve();
|
|
195
200
|
}
|
|
196
201
|
|
|
@@ -199,6 +204,7 @@ export class Sequencer {
|
|
|
199
204
|
*/
|
|
200
205
|
public async stop(): Promise<void> {
|
|
201
206
|
this.log.debug(`Stopping sequencer`);
|
|
207
|
+
await this.validatorClient?.stop();
|
|
202
208
|
await this.runningPromise?.stop();
|
|
203
209
|
this.publisher.interrupt();
|
|
204
210
|
this.setState(SequencerState.STOPPED, 0n, true /** force */);
|
|
@@ -237,12 +243,9 @@ export class Sequencer {
|
|
|
237
243
|
const prevBlockSynced = await this.isBlockSynced();
|
|
238
244
|
// Do not go forward with new block if the previous one has not been mined and processed
|
|
239
245
|
if (!prevBlockSynced) {
|
|
240
|
-
this.log.debug('Previous block has not been mined and processed yet');
|
|
241
246
|
return;
|
|
242
247
|
}
|
|
243
248
|
|
|
244
|
-
this.log.debug('Previous block has been mined and processed');
|
|
245
|
-
|
|
246
249
|
this.setState(SequencerState.PROPOSER_CHECK, 0n);
|
|
247
250
|
|
|
248
251
|
const chainTip = await this.l2BlockSource.getBlock(-1);
|
|
@@ -278,18 +281,23 @@ export class Sequencer {
|
|
|
278
281
|
return;
|
|
279
282
|
}
|
|
280
283
|
|
|
284
|
+
this.log.verbose(`Preparing proposal for block ${newBlockNumber} at slot ${slot}`, {
|
|
285
|
+
chainTipArchive: new Fr(chainTipArchive),
|
|
286
|
+
blockNumber: newBlockNumber,
|
|
287
|
+
slot,
|
|
288
|
+
});
|
|
289
|
+
|
|
281
290
|
this.setState(SequencerState.WAITING_FOR_TXS, slot);
|
|
282
291
|
|
|
283
292
|
// Get txs to build the new block.
|
|
284
|
-
const pendingTxs = this.p2pClient.
|
|
293
|
+
const pendingTxs = await this.p2pClient.getPendingTxs();
|
|
285
294
|
|
|
286
295
|
if (!this.shouldProposeBlock(historicalHeader, { pendingTxsCount: pendingTxs.length })) {
|
|
287
296
|
return;
|
|
288
297
|
}
|
|
289
|
-
this.log.debug(`Retrieved ${pendingTxs.length} txs from P2P pool`);
|
|
290
298
|
|
|
291
299
|
// If I created a "partial" header here that should make our job much easier.
|
|
292
|
-
const proposalHeader = new
|
|
300
|
+
const proposalHeader = new BlockHeader(
|
|
293
301
|
new AppendOnlyTreeSnapshot(Fr.fromBuffer(chainTipArchive), 1),
|
|
294
302
|
ContentCommitment.empty(),
|
|
295
303
|
StateReference.empty(),
|
|
@@ -311,6 +319,10 @@ export class Sequencer {
|
|
|
311
319
|
// may break if we start emitting lots of log data from public-land.
|
|
312
320
|
const validTxs = this.takeTxsWithinMaxSize(allValidTxs);
|
|
313
321
|
|
|
322
|
+
this.log.verbose(
|
|
323
|
+
`Collected ${validTxs.length} txs out of ${allValidTxs.length} valid txs out of ${pendingTxs.length} total pending txs for block ${newBlockNumber}`,
|
|
324
|
+
);
|
|
325
|
+
|
|
314
326
|
// Bail if we don't have enough valid txs
|
|
315
327
|
if (!this.shouldProposeBlock(historicalHeader, { validTxsCount: validTxs.length })) {
|
|
316
328
|
return;
|
|
@@ -322,7 +334,7 @@ export class Sequencer {
|
|
|
322
334
|
// be in for a world of pain.
|
|
323
335
|
await this.buildBlockAndAttemptToPublish(validTxs, proposalHeader, historicalHeader);
|
|
324
336
|
} catch (err) {
|
|
325
|
-
this.log.error(`Error assembling block`,
|
|
337
|
+
this.log.error(`Error assembling block`, err, { blockNumber: newBlockNumber, slot });
|
|
326
338
|
}
|
|
327
339
|
this.setState(SequencerState.IDLE, 0n);
|
|
328
340
|
}
|
|
@@ -343,7 +355,7 @@ export class Sequencer {
|
|
|
343
355
|
}
|
|
344
356
|
|
|
345
357
|
/** Whether to skip the check of min txs per block if more than maxSecondsBetweenBlocks has passed since the previous block. */
|
|
346
|
-
private skipMinTxsPerBlockCheck(historicalHeader:
|
|
358
|
+
private skipMinTxsPerBlockCheck(historicalHeader: BlockHeader | undefined): boolean {
|
|
347
359
|
const lastBlockTime = historicalHeader?.globalVariables.timestamp.toNumber() || 0;
|
|
348
360
|
const currentTime = Math.floor(Date.now() / 1000);
|
|
349
361
|
const elapsed = currentTime - lastBlockTime;
|
|
@@ -357,18 +369,14 @@ export class Sequencer {
|
|
|
357
369
|
const [slot, blockNumber] = await this.publisher.canProposeAtNextEthBlock(tipArchive);
|
|
358
370
|
|
|
359
371
|
if (proposalBlockNumber !== blockNumber) {
|
|
360
|
-
const msg = `
|
|
361
|
-
this.log.
|
|
372
|
+
const msg = `Sequencer block number mismatch. Expected ${proposalBlockNumber} but got ${blockNumber}.`;
|
|
373
|
+
this.log.warn(msg);
|
|
362
374
|
throw new Error(msg);
|
|
363
375
|
}
|
|
364
|
-
|
|
365
|
-
this.log.verbose(`Can propose block ${proposalBlockNumber} at slot ${slot}`, {
|
|
366
|
-
publisherAddress: this.publisher.publisherAddress,
|
|
367
|
-
});
|
|
368
376
|
return slot;
|
|
369
377
|
} catch (err) {
|
|
370
378
|
const msg = prettyLogViemErrorMsg(err);
|
|
371
|
-
this.log.
|
|
379
|
+
this.log.debug(
|
|
372
380
|
`Rejected from being able to propose at next block with ${tipArchive.toString('hex')}: ${msg ? `${msg}` : ''}`,
|
|
373
381
|
);
|
|
374
382
|
throw err;
|
|
@@ -385,7 +393,6 @@ export class Sequencer {
|
|
|
385
393
|
}
|
|
386
394
|
|
|
387
395
|
const bufferSeconds = this.timeTable[proposedState] - secondsIntoSlot;
|
|
388
|
-
this.metrics.recordStateTransitionBufferMs(bufferSeconds * 1000, proposedState);
|
|
389
396
|
|
|
390
397
|
if (bufferSeconds < 0) {
|
|
391
398
|
this.log.warn(
|
|
@@ -393,6 +400,9 @@ export class Sequencer {
|
|
|
393
400
|
);
|
|
394
401
|
return false;
|
|
395
402
|
}
|
|
403
|
+
|
|
404
|
+
this.metrics.recordStateTransitionBufferMs(Math.floor(bufferSeconds * 1000), proposedState);
|
|
405
|
+
|
|
396
406
|
this.log.debug(
|
|
397
407
|
`Enough time to transition to ${proposedState}, max allowed: ${this.timeTable[proposedState]}s, time into slot: ${secondsIntoSlot}s`,
|
|
398
408
|
);
|
|
@@ -410,19 +420,18 @@ export class Sequencer {
|
|
|
410
420
|
*/
|
|
411
421
|
setState(proposedState: SequencerState, currentSlotNumber: bigint, force: boolean = false) {
|
|
412
422
|
if (this.state === SequencerState.STOPPED && force !== true) {
|
|
413
|
-
this.log.warn(
|
|
414
|
-
`Cannot set sequencer from ${this.state} to ${proposedState} as it is stopped. Set force=true to override.`,
|
|
415
|
-
);
|
|
423
|
+
this.log.warn(`Cannot set sequencer from ${this.state} to ${proposedState} as it is stopped.`);
|
|
416
424
|
return;
|
|
417
425
|
}
|
|
418
426
|
const secondsIntoSlot = getSecondsIntoSlot(this.l1GenesisTime, this.aztecSlotDuration, Number(currentSlotNumber));
|
|
419
427
|
if (!this.doIHaveEnoughTimeLeft(proposedState, secondsIntoSlot)) {
|
|
420
428
|
throw new SequencerTooSlowError(this.state, proposedState, this.timeTable[proposedState], secondsIntoSlot);
|
|
421
429
|
}
|
|
430
|
+
this.log.debug(`Transitioning from ${this.state} to ${proposedState}`);
|
|
422
431
|
this.state = proposedState;
|
|
423
432
|
}
|
|
424
433
|
|
|
425
|
-
shouldProposeBlock(historicalHeader:
|
|
434
|
+
shouldProposeBlock(historicalHeader: BlockHeader | undefined, args: ShouldProposeArgs): boolean {
|
|
426
435
|
if (this.isFlushing) {
|
|
427
436
|
this.log.verbose(`Flushing all pending txs in new block`);
|
|
428
437
|
return true;
|
|
@@ -439,7 +448,7 @@ export class Sequencer {
|
|
|
439
448
|
// If we haven't hit the maxSecondsBetweenBlocks, we need to have at least minTxsPerBLock txs.
|
|
440
449
|
// Do not go forward with new block if not enough time has passed since last block
|
|
441
450
|
if (this.minSecondsBetweenBlocks > 0 && elapsedSinceLastBlock < this.minSecondsBetweenBlocks) {
|
|
442
|
-
this.log.
|
|
451
|
+
this.log.verbose(
|
|
443
452
|
`Not creating block because not enough time ${this.minSecondsBetweenBlocks} has passed since last block`,
|
|
444
453
|
);
|
|
445
454
|
return false;
|
|
@@ -455,7 +464,7 @@ export class Sequencer {
|
|
|
455
464
|
`Creating block with only ${args.pendingTxsCount} txs as more than ${this.maxSecondsBetweenBlocks}s have passed since last block`,
|
|
456
465
|
);
|
|
457
466
|
} else {
|
|
458
|
-
this.log.
|
|
467
|
+
this.log.verbose(
|
|
459
468
|
`Not creating block because not enough txs in the pool (got ${args.pendingTxsCount} min ${this.minTxsPerBLock})`,
|
|
460
469
|
);
|
|
461
470
|
return false;
|
|
@@ -467,7 +476,7 @@ export class Sequencer {
|
|
|
467
476
|
if (args.validTxsCount != undefined) {
|
|
468
477
|
// Bail if we don't have enough valid txs
|
|
469
478
|
if (!skipCheck && args.validTxsCount < this.minTxsPerBLock) {
|
|
470
|
-
this.log.
|
|
479
|
+
this.log.verbose(
|
|
471
480
|
`Not creating block because not enough valid txs loaded from the pool (got ${args.validTxsCount} min ${this.minTxsPerBLock})`,
|
|
472
481
|
);
|
|
473
482
|
return false;
|
|
@@ -480,7 +489,7 @@ export class Sequencer {
|
|
|
480
489
|
// we should bail.
|
|
481
490
|
if (args.processedTxsCount != undefined) {
|
|
482
491
|
if (args.processedTxsCount === 0 && !skipCheck && this.minTxsPerBLock > 0) {
|
|
483
|
-
this.log.verbose('No txs processed correctly to build block.
|
|
492
|
+
this.log.verbose('No txs processed correctly to build block.');
|
|
484
493
|
return false;
|
|
485
494
|
}
|
|
486
495
|
}
|
|
@@ -501,13 +510,23 @@ export class Sequencer {
|
|
|
501
510
|
private async buildBlock(
|
|
502
511
|
validTxs: Tx[],
|
|
503
512
|
newGlobalVariables: GlobalVariables,
|
|
504
|
-
historicalHeader?:
|
|
513
|
+
historicalHeader?: BlockHeader,
|
|
505
514
|
interrupt?: (processedTxs: ProcessedTx[]) => Promise<void>,
|
|
506
515
|
) {
|
|
507
|
-
|
|
508
|
-
const
|
|
516
|
+
const blockNumber = newGlobalVariables.blockNumber.toBigInt();
|
|
517
|
+
const slot = newGlobalVariables.slotNumber.toBigInt();
|
|
518
|
+
|
|
519
|
+
this.log.debug(`Requesting L1 to L2 messages from contract for block ${blockNumber}`);
|
|
520
|
+
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(blockNumber);
|
|
521
|
+
|
|
509
522
|
this.log.verbose(
|
|
510
|
-
`
|
|
523
|
+
`Building block ${blockNumber} with ${validTxs.length} txs and ${l1ToL2Messages.length} messages`,
|
|
524
|
+
{
|
|
525
|
+
msgCount: l1ToL2Messages.length,
|
|
526
|
+
txCount: validTxs.length,
|
|
527
|
+
slot,
|
|
528
|
+
blockNumber,
|
|
529
|
+
},
|
|
511
530
|
);
|
|
512
531
|
|
|
513
532
|
const numRealTxs = validTxs.length;
|
|
@@ -515,7 +534,7 @@ export class Sequencer {
|
|
|
515
534
|
|
|
516
535
|
// Sync to the previous block at least
|
|
517
536
|
await this.worldState.syncImmediate(newGlobalVariables.blockNumber.toNumber() - 1);
|
|
518
|
-
this.log.
|
|
537
|
+
this.log.debug(`Synced to previous block ${newGlobalVariables.blockNumber.toNumber() - 1}`);
|
|
519
538
|
|
|
520
539
|
// NB: separating the dbs because both should update the state
|
|
521
540
|
const publicProcessorFork = await this.worldState.fork();
|
|
@@ -537,7 +556,7 @@ export class Sequencer {
|
|
|
537
556
|
);
|
|
538
557
|
if (failedTxs.length > 0) {
|
|
539
558
|
const failedTxData = failedTxs.map(fail => fail.tx);
|
|
540
|
-
this.log.
|
|
559
|
+
this.log.verbose(`Dropping failed txs ${Tx.getHashes(failedTxData).join(', ')}`);
|
|
541
560
|
await this.p2pClient.deleteTxs(Tx.getHashes(failedTxData));
|
|
542
561
|
}
|
|
543
562
|
|
|
@@ -546,7 +565,13 @@ export class Sequencer {
|
|
|
546
565
|
// All real transactions have been added, set the block as full and complete the proving.
|
|
547
566
|
const block = await blockBuilder.setBlockCompleted();
|
|
548
567
|
|
|
549
|
-
return {
|
|
568
|
+
return {
|
|
569
|
+
block,
|
|
570
|
+
publicProcessorDuration,
|
|
571
|
+
numMsgs: l1ToL2Messages.length,
|
|
572
|
+
numProcessedTxs: processedTxs.length,
|
|
573
|
+
blockBuildingTimer,
|
|
574
|
+
};
|
|
550
575
|
} finally {
|
|
551
576
|
// We create a fresh processor each time to reset any cached state (eg storage writes)
|
|
552
577
|
await publicProcessorFork.close();
|
|
@@ -569,21 +594,18 @@ export class Sequencer {
|
|
|
569
594
|
}))
|
|
570
595
|
private async buildBlockAndAttemptToPublish(
|
|
571
596
|
validTxs: Tx[],
|
|
572
|
-
proposalHeader:
|
|
573
|
-
historicalHeader:
|
|
597
|
+
proposalHeader: BlockHeader,
|
|
598
|
+
historicalHeader: BlockHeader | undefined,
|
|
574
599
|
): Promise<void> {
|
|
575
600
|
await this.publisher.validateBlockForSubmission(proposalHeader);
|
|
576
601
|
|
|
577
602
|
const newGlobalVariables = proposalHeader.globalVariables;
|
|
603
|
+
const blockNumber = newGlobalVariables.blockNumber.toNumber();
|
|
604
|
+
const slot = newGlobalVariables.slotNumber.toBigInt();
|
|
578
605
|
|
|
579
|
-
this.metrics.recordNewBlock(
|
|
606
|
+
this.metrics.recordNewBlock(blockNumber, validTxs.length);
|
|
580
607
|
const workTimer = new Timer();
|
|
581
|
-
this.setState(SequencerState.CREATING_BLOCK,
|
|
582
|
-
this.log.info(
|
|
583
|
-
`Building blockNumber=${newGlobalVariables.blockNumber.toNumber()} txCount=${
|
|
584
|
-
validTxs.length
|
|
585
|
-
} slotNumber=${newGlobalVariables.slotNumber.toNumber()}`,
|
|
586
|
-
);
|
|
608
|
+
this.setState(SequencerState.CREATING_BLOCK, slot);
|
|
587
609
|
|
|
588
610
|
/**
|
|
589
611
|
* BuildBlock is shared between the sequencer and the validator for re-execution
|
|
@@ -606,12 +628,8 @@ export class Sequencer {
|
|
|
606
628
|
};
|
|
607
629
|
|
|
608
630
|
try {
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
newGlobalVariables,
|
|
612
|
-
historicalHeader,
|
|
613
|
-
interrupt,
|
|
614
|
-
);
|
|
631
|
+
const buildBlockRes = await this.buildBlock(validTxs, newGlobalVariables, historicalHeader, interrupt);
|
|
632
|
+
const { block, publicProcessorDuration, numProcessedTxs, numMsgs, blockBuildingTimer } = buildBlockRes;
|
|
615
633
|
|
|
616
634
|
// TODO(@PhilWindle) We should probably periodically check for things like another
|
|
617
635
|
// block being published before ours instead of just waiting on our block
|
|
@@ -619,43 +637,56 @@ export class Sequencer {
|
|
|
619
637
|
await this.publisher.validateBlockForSubmission(block.header);
|
|
620
638
|
|
|
621
639
|
const workDuration = workTimer.ms();
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
640
|
+
const blockStats: L2BlockBuiltStats = {
|
|
641
|
+
eventName: 'l2-block-built',
|
|
642
|
+
creator: this.publisher.getSenderAddress().toString(),
|
|
643
|
+
duration: workDuration,
|
|
644
|
+
publicProcessDuration: publicProcessorDuration,
|
|
645
|
+
rollupCircuitsDuration: blockBuildingTimer.ms(),
|
|
646
|
+
...block.getStats(),
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
const blockHash = block.hash();
|
|
650
|
+
const txHashes = validTxs.map(tx => tx.getTxHash());
|
|
651
|
+
this.log.info(`Built block ${block.number} with hash ${blockHash}`, {
|
|
652
|
+
txEffectsHash: block.header.contentCommitment.txsEffectsHash.toString('hex'),
|
|
653
|
+
blockHash,
|
|
654
|
+
globalVariables: block.header.globalVariables.toInspect(),
|
|
655
|
+
txHashes,
|
|
656
|
+
...blockStats,
|
|
657
|
+
});
|
|
635
658
|
|
|
636
659
|
if (this.isFlushing) {
|
|
637
|
-
this.log.
|
|
660
|
+
this.log.verbose(`Sequencer flushing completed`);
|
|
638
661
|
}
|
|
639
662
|
|
|
640
|
-
const txHashes = validTxs.map(tx => tx.getTxHash());
|
|
641
|
-
|
|
642
663
|
this.isFlushing = false;
|
|
643
|
-
this.log.
|
|
664
|
+
this.log.debug('Collecting attestations');
|
|
644
665
|
const stopCollectingAttestationsTimer = this.metrics.startCollectingAttestationsTimer();
|
|
645
666
|
const attestations = await this.collectAttestations(block, txHashes);
|
|
646
|
-
|
|
667
|
+
if (attestations !== undefined) {
|
|
668
|
+
this.log.verbose(`Collected ${attestations.length} attestations`);
|
|
669
|
+
}
|
|
647
670
|
stopCollectingAttestationsTimer();
|
|
648
|
-
this.log.verbose('Collecting proof quotes');
|
|
649
671
|
|
|
672
|
+
this.log.debug('Collecting proof quotes');
|
|
650
673
|
const proofQuote = await this.createProofClaimForPreviousEpoch(newGlobalVariables.slotNumber.toBigInt());
|
|
651
|
-
this.log.info(proofQuote ? `Using proof quote ${inspect(proofQuote.payload)}` : 'No proof quote available');
|
|
652
674
|
|
|
653
675
|
await this.publishL2Block(block, attestations, txHashes, proofQuote);
|
|
654
676
|
this.metrics.recordPublishedBlock(workDuration);
|
|
655
677
|
this.log.info(
|
|
656
|
-
`
|
|
657
|
-
|
|
658
|
-
|
|
678
|
+
`Published rollup block ${
|
|
679
|
+
block.number
|
|
680
|
+
} with ${numProcessedTxs} transactions and ${numMsgs} messages in ${Math.ceil(workDuration)}ms`,
|
|
681
|
+
{
|
|
682
|
+
blockNumber: block.number,
|
|
683
|
+
blockHash: blockHash,
|
|
684
|
+
slot,
|
|
685
|
+
txCount: numProcessedTxs,
|
|
686
|
+
msgCount: numMsgs,
|
|
687
|
+
duration: Math.ceil(workDuration),
|
|
688
|
+
submitter: this.publisher.getSenderAddress().toString(),
|
|
689
|
+
},
|
|
659
690
|
);
|
|
660
691
|
} catch (err) {
|
|
661
692
|
this.metrics.recordFailedBlock();
|
|
@@ -676,11 +707,12 @@ export class Sequencer {
|
|
|
676
707
|
protected async collectAttestations(block: L2Block, txHashes: TxHash[]): Promise<Signature[] | undefined> {
|
|
677
708
|
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/7962): inefficient to have a round trip in here - this should be cached
|
|
678
709
|
const committee = await this.publisher.getCurrentEpochCommittee();
|
|
679
|
-
this.log.debug(`Attesting committee length ${committee.length}`);
|
|
680
710
|
|
|
681
711
|
if (committee.length === 0) {
|
|
682
|
-
this.log.verbose(`Attesting committee
|
|
712
|
+
this.log.verbose(`Attesting committee is empty`);
|
|
683
713
|
return undefined;
|
|
714
|
+
} else {
|
|
715
|
+
this.log.debug(`Attesting committee length is ${committee.length}`);
|
|
684
716
|
}
|
|
685
717
|
|
|
686
718
|
if (!this.validatorClient) {
|
|
@@ -691,22 +723,21 @@ export class Sequencer {
|
|
|
691
723
|
|
|
692
724
|
const numberOfRequiredAttestations = Math.floor((committee.length * 2) / 3) + 1;
|
|
693
725
|
|
|
694
|
-
this.log.
|
|
726
|
+
this.log.debug('Creating block proposal');
|
|
695
727
|
const proposal = await this.validatorClient.createBlockProposal(block.header, block.archive.root, txHashes);
|
|
696
728
|
if (!proposal) {
|
|
697
|
-
this.log.
|
|
729
|
+
this.log.warn(`Failed to create block proposal, skipping collecting attestations`);
|
|
698
730
|
return undefined;
|
|
699
731
|
}
|
|
700
732
|
|
|
701
733
|
const slotNumber = block.header.globalVariables.slotNumber.toBigInt();
|
|
702
734
|
|
|
703
735
|
this.setState(SequencerState.PUBLISHING_BLOCK_TO_PEERS, slotNumber);
|
|
704
|
-
this.log.
|
|
736
|
+
this.log.debug('Broadcasting block proposal to validators');
|
|
705
737
|
this.validatorClient.broadcastBlockProposal(proposal);
|
|
706
738
|
|
|
707
739
|
this.setState(SequencerState.WAITING_FOR_ATTESTATIONS, slotNumber);
|
|
708
740
|
const attestations = await this.validatorClient.collectAttestations(proposal, numberOfRequiredAttestations);
|
|
709
|
-
this.log.info(`Collected attestations from validators, number of attestations: ${attestations.length}`);
|
|
710
741
|
|
|
711
742
|
// note: the smart contract requires that the signatures are provided in the order of the committee
|
|
712
743
|
return orderAttestations(attestations, committee);
|
|
@@ -717,16 +748,17 @@ export class Sequencer {
|
|
|
717
748
|
// Find out which epoch we are currently in
|
|
718
749
|
const epochToProve = await this.publisher.getClaimableEpoch();
|
|
719
750
|
if (epochToProve === undefined) {
|
|
720
|
-
this.log.
|
|
751
|
+
this.log.debug(`No epoch to prove`);
|
|
721
752
|
return undefined;
|
|
722
753
|
}
|
|
723
754
|
|
|
724
755
|
// Get quotes for the epoch to be proven
|
|
725
756
|
const quotes = await this.p2pClient.getEpochProofQuotes(epochToProve);
|
|
726
|
-
this.log.
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
757
|
+
this.log.verbose(`Retrieved ${quotes.length} quotes for slot ${slotNumber} epoch ${epochToProve}`, {
|
|
758
|
+
epochToProve,
|
|
759
|
+
slotNumber,
|
|
760
|
+
quotes: quotes.map(q => q.payload),
|
|
761
|
+
});
|
|
730
762
|
// ensure these quotes are still valid for the slot and have the contract validate them
|
|
731
763
|
const validQuotesPromise = Promise.all(
|
|
732
764
|
quotes.filter(x => x.payload.validUntilSlot >= slotNumber).map(x => this.publisher.validateProofQuote(x)),
|
|
@@ -741,9 +773,11 @@ export class Sequencer {
|
|
|
741
773
|
const sortedQuotes = validQuotes.sort(
|
|
742
774
|
(a: EpochProofQuote, b: EpochProofQuote) => a.payload.basisPointFee - b.payload.basisPointFee,
|
|
743
775
|
);
|
|
744
|
-
|
|
776
|
+
const quote = sortedQuotes[0];
|
|
777
|
+
this.log.info(`Selected proof quote for proof claim`, quote.payload);
|
|
778
|
+
return quote;
|
|
745
779
|
} catch (err) {
|
|
746
|
-
this.log.error(`Failed to create proof claim for previous epoch
|
|
780
|
+
this.log.error(`Failed to create proof claim for previous epoch`, err, { slotNumber });
|
|
747
781
|
return undefined;
|
|
748
782
|
}
|
|
749
783
|
}
|
|
@@ -788,7 +822,7 @@ export class Sequencer {
|
|
|
788
822
|
for (const tx of txs) {
|
|
789
823
|
const txSize = tx.getSize() - tx.clientIvcProof.clientIvcProofBuffer.length;
|
|
790
824
|
if (totalSize + txSize > maxSize) {
|
|
791
|
-
this.log.
|
|
825
|
+
this.log.debug(
|
|
792
826
|
`Dropping tx ${tx.getTxHash()} with estimated size ${txSize} due to exceeding ${maxSize} block size limit (currently at ${totalSize})`,
|
|
793
827
|
);
|
|
794
828
|
continue;
|
|
@@ -825,7 +859,7 @@ export class Sequencer {
|
|
|
825
859
|
p2p >= l2BlockSource.number &&
|
|
826
860
|
l1ToL2MessageSource >= l2BlockSource.number;
|
|
827
861
|
|
|
828
|
-
this.log.
|
|
862
|
+
this.log.debug(`Sequencer sync check ${result ? 'succeeded' : 'failed'}`, {
|
|
829
863
|
worldStateNumber: worldState.number,
|
|
830
864
|
worldStateHash: worldState.hash,
|
|
831
865
|
l2BlockSourceNumber: l2BlockSource.number,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Tx, TxExecutionPhase, type TxValidator } from '@aztec/circuit-types';
|
|
2
2
|
import { type AztecAddress, type Fr, FunctionSelector } from '@aztec/circuits.js';
|
|
3
|
-
import {
|
|
3
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { computeFeePayerBalanceStorageSlot, getExecutionRequestsByPhase } from '@aztec/simulator';
|
|
5
5
|
|
|
6
6
|
/** Provides a view into public contract state */
|
|
@@ -9,7 +9,7 @@ export interface PublicStateSource {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export class GasTxValidator implements TxValidator<Tx> {
|
|
12
|
-
#log =
|
|
12
|
+
#log = createLogger('sequencer:tx_validator:tx_gas');
|
|
13
13
|
#publicDataSource: PublicStateSource;
|
|
14
14
|
#feeJuiceAddress: AztecAddress;
|
|
15
15
|
|
|
@@ -6,11 +6,11 @@ import {
|
|
|
6
6
|
type TxValidator,
|
|
7
7
|
} from '@aztec/circuit-types';
|
|
8
8
|
import { type ContractDataSource } from '@aztec/circuits.js';
|
|
9
|
-
import {
|
|
9
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
10
10
|
import { ContractsDataSourcePublicDB, getExecutionRequestsByPhase } from '@aztec/simulator';
|
|
11
11
|
|
|
12
12
|
export class PhasesTxValidator implements TxValidator<Tx> {
|
|
13
|
-
#log =
|
|
13
|
+
#log = createLogger('sequencer:tx_validator:tx_phases');
|
|
14
14
|
private contractDataSource: ContractsDataSourcePublicDB;
|
|
15
15
|
|
|
16
16
|
constructor(contracts: ContractDataSource, private setupAllowList: AllowedElement[]) {
|