@aztec/sequencer-client 0.0.1-commit.96bb3f7 → 0.0.1-commit.9d2bcf6d
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 +1 -1
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +1 -3
- package/dest/global_variable_builder/global_builder.js +2 -2
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/publisher/sequencer-publisher-metrics.d.ts +1 -1
- package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-metrics.js +12 -4
- package/dest/publisher/sequencer-publisher.d.ts +1 -2
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +39 -18
- package/dest/sequencer/checkpoint_proposal_job.d.ts +32 -9
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +130 -31
- package/dest/sequencer/checkpoint_voter.d.ts +3 -2
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_voter.js +34 -10
- package/dest/sequencer/index.d.ts +1 -2
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +0 -1
- package/dest/sequencer/metrics.d.ts +2 -2
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +27 -17
- package/dest/sequencer/sequencer.d.ts +19 -9
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +72 -12
- package/dest/test/mock_checkpoint_builder.d.ts +17 -13
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.js +28 -10
- package/dest/test/utils.d.ts +8 -8
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +7 -7
- package/package.json +30 -28
- package/src/client/sequencer-client.ts +1 -1
- package/src/config.ts +1 -3
- package/src/global_variable_builder/global_builder.ts +2 -2
- package/src/index.ts +1 -6
- package/src/publisher/sequencer-publisher-metrics.ts +7 -3
- package/src/publisher/sequencer-publisher.ts +34 -18
- package/src/sequencer/checkpoint_proposal_job.ts +181 -51
- package/src/sequencer/checkpoint_voter.ts +32 -7
- package/src/sequencer/index.ts +0 -1
- package/src/sequencer/metrics.ts +36 -18
- package/src/sequencer/sequencer.ts +89 -11
- package/src/test/mock_checkpoint_builder.ts +64 -34
- package/src/test/utils.ts +19 -12
- package/dest/sequencer/block_builder.d.ts +0 -26
- package/dest/sequencer/block_builder.d.ts.map +0 -1
- package/dest/sequencer/block_builder.js +0 -129
- package/src/sequencer/block_builder.ts +0 -216
|
@@ -12,7 +12,7 @@ import type { DateProvider } from '@aztec/foundation/timer';
|
|
|
12
12
|
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
13
13
|
import type { P2P } from '@aztec/p2p';
|
|
14
14
|
import type { SlasherClientInterface } from '@aztec/slasher';
|
|
15
|
-
import type {
|
|
15
|
+
import type { L2Block, L2BlockSink, L2BlockSource, ValidateCheckpointResult } from '@aztec/stdlib/block';
|
|
16
16
|
import type { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
17
17
|
import { getSlotAtTimestamp, getSlotStartBuildTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
18
18
|
import {
|
|
@@ -57,8 +57,11 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
57
57
|
private state = SequencerState.STOPPED;
|
|
58
58
|
private metrics: SequencerMetrics;
|
|
59
59
|
|
|
60
|
-
/** The last slot for which we attempted to
|
|
61
|
-
private
|
|
60
|
+
/** The last slot for which we attempted to perform our voting duties with degraded block production */
|
|
61
|
+
private lastSlotForFallbackVote: SlotNumber | undefined;
|
|
62
|
+
|
|
63
|
+
/** The last slot for which we logged "no committee" warning, to avoid spam */
|
|
64
|
+
private lastSlotForNoCommitteeWarning: SlotNumber | undefined;
|
|
62
65
|
|
|
63
66
|
/** The last slot for which we triggered a checkpoint proposal job, to prevent duplicate attempts. */
|
|
64
67
|
private lastSlotForCheckpointProposalJob: SlotNumber | undefined;
|
|
@@ -202,7 +205,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
202
205
|
const { slot, ts, now, epoch } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
203
206
|
|
|
204
207
|
// Check if we are synced and it's our slot, grab a publisher, check previous block invalidation, etc
|
|
205
|
-
const checkpointProposalJob = await this.prepareCheckpointProposal(slot, ts, now);
|
|
208
|
+
const checkpointProposalJob = await this.prepareCheckpointProposal(epoch, slot, ts, now);
|
|
206
209
|
if (!checkpointProposalJob) {
|
|
207
210
|
return;
|
|
208
211
|
}
|
|
@@ -234,6 +237,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
234
237
|
*/
|
|
235
238
|
@trackSpan('Sequencer.prepareCheckpointProposal')
|
|
236
239
|
private async prepareCheckpointProposal(
|
|
240
|
+
epoch: EpochNumber,
|
|
237
241
|
slot: SlotNumber,
|
|
238
242
|
ts: bigint,
|
|
239
243
|
now: bigint,
|
|
@@ -263,6 +267,25 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
263
267
|
return undefined;
|
|
264
268
|
}
|
|
265
269
|
|
|
270
|
+
// If escape hatch is open for this epoch, do not start checkpoint proposal work and do not attempt invalidations.
|
|
271
|
+
// Still perform governance/slashing voting (as proposer) once per slot.
|
|
272
|
+
const isEscapeHatchOpen = await this.epochCache.isEscapeHatchOpen(epoch);
|
|
273
|
+
|
|
274
|
+
if (isEscapeHatchOpen) {
|
|
275
|
+
this.setState(SequencerState.PROPOSER_CHECK, slot);
|
|
276
|
+
const [canPropose, proposer] = await this.checkCanPropose(slot);
|
|
277
|
+
if (canPropose) {
|
|
278
|
+
await this.tryVoteWhenEscapeHatchOpen({ slot, proposer });
|
|
279
|
+
} else {
|
|
280
|
+
this.log.trace(`Escape hatch open but we are not proposer, skipping vote-only actions`, {
|
|
281
|
+
slot,
|
|
282
|
+
epoch,
|
|
283
|
+
proposer,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
|
|
266
289
|
// Next checkpoint follows from the last synced one
|
|
267
290
|
const checkpointNumber = CheckpointNumber(syncedTo.checkpointNumber + 1);
|
|
268
291
|
|
|
@@ -357,6 +380,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
357
380
|
|
|
358
381
|
// Create and return the checkpoint proposal job
|
|
359
382
|
return this.createCheckpointProposalJob(
|
|
383
|
+
epoch,
|
|
360
384
|
slot,
|
|
361
385
|
checkpointNumber,
|
|
362
386
|
syncedTo.blockNumber,
|
|
@@ -368,6 +392,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
368
392
|
}
|
|
369
393
|
|
|
370
394
|
protected createCheckpointProposalJob(
|
|
395
|
+
epoch: EpochNumber,
|
|
371
396
|
slot: SlotNumber,
|
|
372
397
|
checkpointNumber: CheckpointNumber,
|
|
373
398
|
syncedToBlockNumber: BlockNumber,
|
|
@@ -377,6 +402,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
377
402
|
invalidateCheckpoint: InvalidateCheckpointRequest | undefined,
|
|
378
403
|
): CheckpointProposalJob {
|
|
379
404
|
return new CheckpointProposalJob(
|
|
405
|
+
epoch,
|
|
380
406
|
slot,
|
|
381
407
|
checkpointNumber,
|
|
382
408
|
syncedToBlockNumber,
|
|
@@ -389,6 +415,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
389
415
|
this.p2pClient,
|
|
390
416
|
this.worldState,
|
|
391
417
|
this.l1ToL2MessageSource,
|
|
418
|
+
this.l2BlockSource,
|
|
392
419
|
this.checkpointsBuilder,
|
|
393
420
|
this.l2BlockSource,
|
|
394
421
|
this.l1Constants,
|
|
@@ -400,8 +427,8 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
400
427
|
this.metrics,
|
|
401
428
|
this,
|
|
402
429
|
this.setState.bind(this),
|
|
403
|
-
this.log,
|
|
404
430
|
this.tracer,
|
|
431
|
+
this.log.getBindings(),
|
|
405
432
|
);
|
|
406
433
|
}
|
|
407
434
|
|
|
@@ -505,7 +532,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
505
532
|
};
|
|
506
533
|
}
|
|
507
534
|
|
|
508
|
-
const block = await this.l2BlockSource.
|
|
535
|
+
const block = await this.l2BlockSource.getL2Block(blockNumber);
|
|
509
536
|
if (!block) {
|
|
510
537
|
// this shouldn't really happen because a moment ago we checked that all components were in sync
|
|
511
538
|
this.log.error(`Failed to get L2 block ${blockNumber} from the archiver with all components in sync`);
|
|
@@ -533,7 +560,10 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
533
560
|
proposer = await this.epochCache.getProposerAttesterAddressInSlot(slot);
|
|
534
561
|
} catch (e) {
|
|
535
562
|
if (e instanceof NoCommitteeError) {
|
|
536
|
-
this.
|
|
563
|
+
if (this.lastSlotForNoCommitteeWarning !== slot) {
|
|
564
|
+
this.lastSlotForNoCommitteeWarning = slot;
|
|
565
|
+
this.log.warn(`Cannot propose at next L2 slot ${slot} since the committee does not exist on L1`);
|
|
566
|
+
}
|
|
537
567
|
return [false, undefined];
|
|
538
568
|
}
|
|
539
569
|
this.log.error(`Error getting proposer for slot ${slot}`, e);
|
|
@@ -569,7 +599,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
569
599
|
const { slot } = args;
|
|
570
600
|
|
|
571
601
|
// Prevent duplicate attempts in the same slot
|
|
572
|
-
if (this.
|
|
602
|
+
if (this.lastSlotForFallbackVote === slot) {
|
|
573
603
|
this.log.trace(`Already attempted to vote in slot ${slot} (skipping)`);
|
|
574
604
|
return;
|
|
575
605
|
}
|
|
@@ -601,7 +631,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
601
631
|
}
|
|
602
632
|
|
|
603
633
|
// Mark this slot as attempted
|
|
604
|
-
this.
|
|
634
|
+
this.lastSlotForFallbackVote = slot;
|
|
605
635
|
|
|
606
636
|
// Get a publisher for voting
|
|
607
637
|
const { attestorAddress, publisher } = await this.publisherFactory.create(proposer);
|
|
@@ -636,7 +666,55 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
636
666
|
}
|
|
637
667
|
|
|
638
668
|
/**
|
|
639
|
-
*
|
|
669
|
+
* Tries to vote on slashing actions and governance proposals when escape hatch is open.
|
|
670
|
+
* This allows the sequencer to participate in voting without performing checkpoint proposal work.
|
|
671
|
+
*/
|
|
672
|
+
@trackSpan('Sequencer.tryVoteWhenEscapeHatchOpen', ({ slot }) => ({ [Attributes.SLOT_NUMBER]: slot }))
|
|
673
|
+
protected async tryVoteWhenEscapeHatchOpen(args: {
|
|
674
|
+
slot: SlotNumber;
|
|
675
|
+
proposer: EthAddress | undefined;
|
|
676
|
+
}): Promise<void> {
|
|
677
|
+
const { slot, proposer } = args;
|
|
678
|
+
|
|
679
|
+
// Prevent duplicate attempts in the same slot
|
|
680
|
+
if (this.lastSlotForFallbackVote === slot) {
|
|
681
|
+
this.log.trace(`Already attempted to vote in slot ${slot} (escape hatch open, skipping)`);
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// Mark this slot as attempted
|
|
686
|
+
this.lastSlotForFallbackVote = slot;
|
|
687
|
+
|
|
688
|
+
const { attestorAddress, publisher } = await this.publisherFactory.create(proposer);
|
|
689
|
+
|
|
690
|
+
this.log.debug(`Escape hatch open for slot ${slot}, attempting vote-only actions`, { slot, attestorAddress });
|
|
691
|
+
|
|
692
|
+
const voter = new CheckpointVoter(
|
|
693
|
+
slot,
|
|
694
|
+
publisher,
|
|
695
|
+
attestorAddress,
|
|
696
|
+
this.validatorClient,
|
|
697
|
+
this.slasherClient,
|
|
698
|
+
this.l1Constants,
|
|
699
|
+
this.config,
|
|
700
|
+
this.metrics,
|
|
701
|
+
this.log,
|
|
702
|
+
);
|
|
703
|
+
|
|
704
|
+
const votesPromises = voter.enqueueVotes();
|
|
705
|
+
const votes = await Promise.all(votesPromises);
|
|
706
|
+
|
|
707
|
+
if (votes.every(p => !p)) {
|
|
708
|
+
this.log.debug(`No votes to enqueue for slot ${slot} (escape hatch open)`);
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
this.log.info(`Voting in slot ${slot} (escape hatch open)`, { slot });
|
|
713
|
+
await publisher.sendRequests();
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Considers invalidating a block if the pending chain is invalid. Depends on how long the invalid block
|
|
640
718
|
* has been there without being invalidated and whether the sequencer is in the committee or not. We always
|
|
641
719
|
* have the proposer try to invalidate, but if they fail, the sequencers in the committee are expected to try,
|
|
642
720
|
* and if they fail, any sequencer will try as well.
|
|
@@ -798,7 +876,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
798
876
|
}
|
|
799
877
|
|
|
800
878
|
type SequencerSyncCheckResult = {
|
|
801
|
-
block?:
|
|
879
|
+
block?: L2Block;
|
|
802
880
|
checkpointNumber: CheckpointNumber;
|
|
803
881
|
blockNumber: BlockNumber;
|
|
804
882
|
archive: Fr;
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import { type BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
|
-
import {
|
|
4
|
-
import type { FunctionsOf } from '@aztec/foundation/types';
|
|
5
|
-
import { L2BlockNew } from '@aztec/stdlib/block';
|
|
3
|
+
import { L2Block } from '@aztec/stdlib/block';
|
|
6
4
|
import { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
7
5
|
import { Gas } from '@aztec/stdlib/gas';
|
|
8
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
FullNodeBlockBuilderConfig,
|
|
8
|
+
ICheckpointBlockBuilder,
|
|
9
|
+
ICheckpointsBuilder,
|
|
10
|
+
MerkleTreeWriteOperations,
|
|
11
|
+
PublicProcessorLimits,
|
|
12
|
+
} from '@aztec/stdlib/interfaces/server';
|
|
9
13
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
10
14
|
import { makeAppendOnlyTreeSnapshot } from '@aztec/stdlib/testing';
|
|
11
15
|
import type { CheckpointGlobalVariables, Tx } from '@aztec/stdlib/tx';
|
|
12
|
-
import type {
|
|
13
|
-
BuildBlockInCheckpointResult,
|
|
14
|
-
CheckpointBuilder,
|
|
15
|
-
FullNodeCheckpointsBuilder,
|
|
16
|
-
} from '@aztec/validator-client';
|
|
16
|
+
import type { BuildBlockInCheckpointResult } from '@aztec/validator-client';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* A fake CheckpointBuilder for testing that implements the same interface as the real one.
|
|
20
20
|
* Can be seeded with blocks to return sequentially on each `buildBlock` call.
|
|
21
21
|
*/
|
|
22
|
-
export class MockCheckpointBuilder implements
|
|
23
|
-
private blocks:
|
|
24
|
-
private builtBlocks:
|
|
22
|
+
export class MockCheckpointBuilder implements ICheckpointBlockBuilder {
|
|
23
|
+
private blocks: L2Block[] = [];
|
|
24
|
+
private builtBlocks: L2Block[] = [];
|
|
25
25
|
private usedTxsPerBlock: Tx[][] = [];
|
|
26
26
|
private blockIndex = 0;
|
|
27
27
|
|
|
28
28
|
/** Optional function to dynamically provide the block (alternative to seedBlocks) */
|
|
29
|
-
private blockProvider: (() =>
|
|
29
|
+
private blockProvider: (() => L2Block) | undefined = undefined;
|
|
30
30
|
|
|
31
31
|
/** Track calls for assertions */
|
|
32
32
|
public buildBlockCalls: Array<{
|
|
@@ -34,6 +34,8 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
34
34
|
timestamp: bigint;
|
|
35
35
|
opts: PublicProcessorLimits;
|
|
36
36
|
}> = [];
|
|
37
|
+
/** Track all consumed transaction hashes across buildBlock calls */
|
|
38
|
+
public consumedTxHashes: Set<string> = new Set();
|
|
37
39
|
public completeCheckpointCalled = false;
|
|
38
40
|
public getCheckpointCalled = false;
|
|
39
41
|
|
|
@@ -46,7 +48,7 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
46
48
|
) {}
|
|
47
49
|
|
|
48
50
|
/** Seed the builder with blocks to return on successive buildBlock calls */
|
|
49
|
-
seedBlocks(blocks:
|
|
51
|
+
seedBlocks(blocks: L2Block[], usedTxsPerBlock?: Tx[][]): this {
|
|
50
52
|
this.blocks = blocks;
|
|
51
53
|
this.usedTxsPerBlock = usedTxsPerBlock ?? blocks.map(() => []);
|
|
52
54
|
this.blockIndex = 0;
|
|
@@ -58,7 +60,7 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
58
60
|
* Set a function that provides blocks dynamically.
|
|
59
61
|
* Useful for tests where the block is determined at call time (e.g., sequencer tests).
|
|
60
62
|
*/
|
|
61
|
-
setBlockProvider(provider: () =>
|
|
63
|
+
setBlockProvider(provider: () => L2Block): this {
|
|
62
64
|
this.blockProvider = provider;
|
|
63
65
|
this.blocks = [];
|
|
64
66
|
return this;
|
|
@@ -68,8 +70,8 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
68
70
|
return this.constants;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
buildBlock(
|
|
72
|
-
|
|
73
|
+
async buildBlock(
|
|
74
|
+
pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
73
75
|
blockNumber: BlockNumber,
|
|
74
76
|
timestamp: bigint,
|
|
75
77
|
opts: PublicProcessorLimits,
|
|
@@ -77,10 +79,10 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
77
79
|
this.buildBlockCalls.push({ blockNumber, timestamp, opts });
|
|
78
80
|
|
|
79
81
|
if (this.errorOnBuild) {
|
|
80
|
-
|
|
82
|
+
throw this.errorOnBuild;
|
|
81
83
|
}
|
|
82
84
|
|
|
83
|
-
let block:
|
|
85
|
+
let block: L2Block;
|
|
84
86
|
let usedTxs: Tx[];
|
|
85
87
|
|
|
86
88
|
if (this.blockProvider) {
|
|
@@ -96,15 +98,28 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
96
98
|
this.builtBlocks.push(block);
|
|
97
99
|
}
|
|
98
100
|
|
|
99
|
-
|
|
101
|
+
// Check that no pending tx has already been consumed
|
|
102
|
+
for await (const tx of pendingTxs) {
|
|
103
|
+
const hash = tx.getTxHash().toString();
|
|
104
|
+
if (this.consumedTxHashes.has(hash)) {
|
|
105
|
+
throw new Error(`Transaction ${hash} was already consumed in a previous block`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Add used txs to consumed set
|
|
110
|
+
for (const tx of usedTxs) {
|
|
111
|
+
this.consumedTxHashes.add(tx.getTxHash().toString());
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
100
115
|
block,
|
|
101
116
|
publicGas: Gas.empty(),
|
|
102
117
|
publicProcessorDuration: 0,
|
|
103
118
|
numTxs: block?.body?.txEffects?.length ?? usedTxs.length,
|
|
104
|
-
blockBuildingTimer: new Timer(),
|
|
105
119
|
usedTxs,
|
|
106
120
|
failedTxs: [],
|
|
107
|
-
|
|
121
|
+
usedTxBlobFields: block?.body?.txEffects?.reduce((sum, tx) => sum + tx.getNumBlobFields(), 0) ?? 0,
|
|
122
|
+
};
|
|
108
123
|
}
|
|
109
124
|
|
|
110
125
|
completeCheckpoint(): Promise<Checkpoint> {
|
|
@@ -146,7 +161,7 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
146
161
|
* Creates a CheckpointHeader from a block's header for testing.
|
|
147
162
|
* This is a simplified version that creates a minimal CheckpointHeader.
|
|
148
163
|
*/
|
|
149
|
-
private createCheckpointHeader(block:
|
|
164
|
+
private createCheckpointHeader(block: L2Block): CheckpointHeader {
|
|
150
165
|
const header = block.header;
|
|
151
166
|
const gv = header.globalVariables;
|
|
152
167
|
return CheckpointHeader.empty({
|
|
@@ -168,6 +183,7 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
168
183
|
this.usedTxsPerBlock = [];
|
|
169
184
|
this.blockIndex = 0;
|
|
170
185
|
this.buildBlockCalls = [];
|
|
186
|
+
this.consumedTxHashes.clear();
|
|
171
187
|
this.completeCheckpointCalled = false;
|
|
172
188
|
this.getCheckpointCalled = false;
|
|
173
189
|
this.errorOnBuild = undefined;
|
|
@@ -180,7 +196,7 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
180
196
|
* as FullNodeCheckpointsBuilder. Returns MockCheckpointBuilder instances.
|
|
181
197
|
* Does NOT use jest mocks - this is a proper test double.
|
|
182
198
|
*/
|
|
183
|
-
export class MockCheckpointsBuilder implements
|
|
199
|
+
export class MockCheckpointsBuilder implements ICheckpointsBuilder {
|
|
184
200
|
private checkpointBuilder: MockCheckpointBuilder | undefined;
|
|
185
201
|
|
|
186
202
|
/** Track calls for assertions */
|
|
@@ -188,12 +204,14 @@ export class MockCheckpointsBuilder implements FunctionsOf<FullNodeCheckpointsBu
|
|
|
188
204
|
checkpointNumber: CheckpointNumber;
|
|
189
205
|
constants: CheckpointGlobalVariables;
|
|
190
206
|
l1ToL2Messages: Fr[];
|
|
207
|
+
previousCheckpointOutHashes: Fr[];
|
|
191
208
|
}> = [];
|
|
192
209
|
public openCheckpointCalls: Array<{
|
|
193
210
|
checkpointNumber: CheckpointNumber;
|
|
194
211
|
constants: CheckpointGlobalVariables;
|
|
195
212
|
l1ToL2Messages: Fr[];
|
|
196
|
-
|
|
213
|
+
previousCheckpointOutHashes: Fr[];
|
|
214
|
+
existingBlocks: L2Block[];
|
|
197
215
|
}> = [];
|
|
198
216
|
public updateConfigCalls: Array<Partial<FullNodeBlockBuilderConfig>> = [];
|
|
199
217
|
|
|
@@ -240,33 +258,45 @@ export class MockCheckpointsBuilder implements FunctionsOf<FullNodeCheckpointsBu
|
|
|
240
258
|
checkpointNumber: CheckpointNumber,
|
|
241
259
|
constants: CheckpointGlobalVariables,
|
|
242
260
|
l1ToL2Messages: Fr[],
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
261
|
+
previousCheckpointOutHashes: Fr[],
|
|
262
|
+
_fork: MerkleTreeWriteOperations,
|
|
263
|
+
): Promise<ICheckpointBlockBuilder> {
|
|
264
|
+
this.startCheckpointCalls.push({ checkpointNumber, constants, l1ToL2Messages, previousCheckpointOutHashes });
|
|
246
265
|
|
|
247
266
|
if (!this.checkpointBuilder) {
|
|
248
267
|
// Auto-create a builder if none was set
|
|
249
268
|
this.checkpointBuilder = new MockCheckpointBuilder(constants, checkpointNumber);
|
|
250
269
|
}
|
|
251
270
|
|
|
252
|
-
return Promise.resolve(this.checkpointBuilder
|
|
271
|
+
return Promise.resolve(this.checkpointBuilder);
|
|
253
272
|
}
|
|
254
273
|
|
|
255
274
|
openCheckpoint(
|
|
256
275
|
checkpointNumber: CheckpointNumber,
|
|
257
276
|
constants: CheckpointGlobalVariables,
|
|
258
277
|
l1ToL2Messages: Fr[],
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
278
|
+
previousCheckpointOutHashes: Fr[],
|
|
279
|
+
_fork: MerkleTreeWriteOperations,
|
|
280
|
+
existingBlocks: L2Block[] = [],
|
|
281
|
+
): Promise<ICheckpointBlockBuilder> {
|
|
282
|
+
this.openCheckpointCalls.push({
|
|
283
|
+
checkpointNumber,
|
|
284
|
+
constants,
|
|
285
|
+
l1ToL2Messages,
|
|
286
|
+
previousCheckpointOutHashes,
|
|
287
|
+
existingBlocks,
|
|
288
|
+
});
|
|
263
289
|
|
|
264
290
|
if (!this.checkpointBuilder) {
|
|
265
291
|
// Auto-create a builder if none was set
|
|
266
292
|
this.checkpointBuilder = new MockCheckpointBuilder(constants, checkpointNumber);
|
|
267
293
|
}
|
|
268
294
|
|
|
269
|
-
return Promise.resolve(this.checkpointBuilder
|
|
295
|
+
return Promise.resolve(this.checkpointBuilder);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
getFork(_blockNumber: BlockNumber): Promise<MerkleTreeWriteOperations> {
|
|
299
|
+
throw new Error('MockCheckpointsBuilder.getFork not implemented');
|
|
270
300
|
}
|
|
271
301
|
|
|
272
302
|
/** Reset for reuse in another test */
|
package/src/test/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Body } from '@aztec/aztec.js/block';
|
|
2
|
-
import { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { CheckpointNumber, IndexWithinCheckpoint } from '@aztec/foundation/branded-types';
|
|
3
3
|
import { times } from '@aztec/foundation/collection';
|
|
4
4
|
import { Secp256k1Signer } from '@aztec/foundation/crypto/secp256k1-signer';
|
|
5
5
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
@@ -7,7 +7,7 @@ import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
7
7
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
8
8
|
import type { P2P } from '@aztec/p2p';
|
|
9
9
|
import { PublicDataWrite } from '@aztec/stdlib/avm';
|
|
10
|
-
import { CommitteeAttestation,
|
|
10
|
+
import { CommitteeAttestation, L2Block } from '@aztec/stdlib/block';
|
|
11
11
|
import { BlockProposal, CheckpointAttestation, CheckpointProposal, ConsensusPayload } from '@aztec/stdlib/p2p';
|
|
12
12
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
13
13
|
import { makeAppendOnlyTreeSnapshot, mockTxForRollup } from '@aztec/stdlib/testing';
|
|
@@ -30,9 +30,9 @@ export async function makeTx(seed?: number, chainId?: Fr): Promise<Tx> {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* Creates an
|
|
33
|
+
* Creates an L2Block from transactions and global variables
|
|
34
34
|
*/
|
|
35
|
-
export async function makeBlock(txs: Tx[], globalVariables: GlobalVariables): Promise<
|
|
35
|
+
export async function makeBlock(txs: Tx[], globalVariables: GlobalVariables): Promise<L2Block> {
|
|
36
36
|
const processedTxs = await Promise.all(
|
|
37
37
|
txs.map(tx =>
|
|
38
38
|
makeProcessedTxFromPrivateOnlyTx(tx, Fr.ZERO, new PublicDataWrite(Fr.random(), Fr.random()), globalVariables),
|
|
@@ -41,7 +41,13 @@ export async function makeBlock(txs: Tx[], globalVariables: GlobalVariables): Pr
|
|
|
41
41
|
const body = new Body(processedTxs.map(tx => tx.txEffect));
|
|
42
42
|
const header = BlockHeader.empty({ globalVariables });
|
|
43
43
|
const archive = makeAppendOnlyTreeSnapshot(globalVariables.blockNumber + 1);
|
|
44
|
-
return new
|
|
44
|
+
return new L2Block(
|
|
45
|
+
archive,
|
|
46
|
+
header,
|
|
47
|
+
body,
|
|
48
|
+
CheckpointNumber.fromBlockNumber(globalVariables.blockNumber),
|
|
49
|
+
IndexWithinCheckpoint(0),
|
|
50
|
+
);
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
/**
|
|
@@ -70,16 +76,17 @@ export function createMockSignatures(signer: Secp256k1Signer): CommitteeAttestat
|
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
/**
|
|
73
|
-
* Creates a CheckpointHeader from an
|
|
74
|
-
* Uses mock values for blockHeadersHash, blobsHash and inHash since
|
|
79
|
+
* Creates a CheckpointHeader from an L2Block for testing purposes.
|
|
80
|
+
* Uses mock values for blockHeadersHash, blobsHash and inHash since L2Block doesn't have these fields.
|
|
75
81
|
*/
|
|
76
|
-
function createCheckpointHeaderFromBlock(block:
|
|
82
|
+
function createCheckpointHeaderFromBlock(block: L2Block): CheckpointHeader {
|
|
77
83
|
const gv = block.header.globalVariables;
|
|
78
84
|
return new CheckpointHeader(
|
|
79
85
|
block.header.lastArchive.root,
|
|
80
86
|
Fr.random(), // blockHeadersHash - mock value for testing
|
|
81
87
|
Fr.random(), // blobsHash - mock value for testing
|
|
82
88
|
Fr.random(), // inHash - mock value for testing
|
|
89
|
+
Fr.random(), // outHash - mock value for testing
|
|
83
90
|
gv.slotNumber,
|
|
84
91
|
gv.timestamp,
|
|
85
92
|
gv.coinbase,
|
|
@@ -92,7 +99,7 @@ function createCheckpointHeaderFromBlock(block: L2BlockNew): CheckpointHeader {
|
|
|
92
99
|
/**
|
|
93
100
|
* Creates a block proposal from a block and signature
|
|
94
101
|
*/
|
|
95
|
-
export function createBlockProposal(block:
|
|
102
|
+
export function createBlockProposal(block: L2Block, signature: Signature): BlockProposal {
|
|
96
103
|
const txHashes = block.body.txEffects.map(tx => tx.txHash);
|
|
97
104
|
return new BlockProposal(
|
|
98
105
|
block.header,
|
|
@@ -108,7 +115,7 @@ export function createBlockProposal(block: L2BlockNew, signature: Signature): Bl
|
|
|
108
115
|
* Creates a checkpoint proposal from a block and signature
|
|
109
116
|
*/
|
|
110
117
|
export function createCheckpointProposal(
|
|
111
|
-
block:
|
|
118
|
+
block: L2Block,
|
|
112
119
|
checkpointSignature: Signature,
|
|
113
120
|
blockSignature?: Signature,
|
|
114
121
|
): CheckpointProposal {
|
|
@@ -128,7 +135,7 @@ export function createCheckpointProposal(
|
|
|
128
135
|
* In production, the sender is recovered from the signature.
|
|
129
136
|
*/
|
|
130
137
|
export function createCheckpointAttestation(
|
|
131
|
-
block:
|
|
138
|
+
block: L2Block,
|
|
132
139
|
signature: Signature,
|
|
133
140
|
sender: EthAddress,
|
|
134
141
|
): CheckpointAttestation {
|
|
@@ -149,7 +156,7 @@ export async function setupTxsAndBlock(
|
|
|
149
156
|
globalVariables: GlobalVariables,
|
|
150
157
|
txCount: number,
|
|
151
158
|
chainId: Fr,
|
|
152
|
-
): Promise<{ txs: Tx[]; block:
|
|
159
|
+
): Promise<{ txs: Tx[]; block: L2Block }> {
|
|
153
160
|
const txs = await Promise.all(times(txCount, i => makeTx(i + 1, chainId)));
|
|
154
161
|
const block = await makeBlock(txs, globalVariables);
|
|
155
162
|
mockPendingTxs(p2p, txs);
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
|
-
import { DateProvider } from '@aztec/foundation/timer';
|
|
4
|
-
import { PublicProcessor } from '@aztec/simulator/server';
|
|
5
|
-
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
6
|
-
import type { BuildBlockResult, FullNodeBlockBuilderConfig, IFullNodeBlockBuilder, MerkleTreeWriteOperations, PublicProcessorLimits, PublicProcessorValidator, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
7
|
-
import { GlobalVariables, Tx } from '@aztec/stdlib/tx';
|
|
8
|
-
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
9
|
-
export declare class FullNodeBlockBuilder implements IFullNodeBlockBuilder {
|
|
10
|
-
private config;
|
|
11
|
-
private worldState;
|
|
12
|
-
private contractDataSource;
|
|
13
|
-
private dateProvider;
|
|
14
|
-
private telemetryClient;
|
|
15
|
-
constructor(config: FullNodeBlockBuilderConfig, worldState: WorldStateSynchronizer, contractDataSource: ContractDataSource, dateProvider: DateProvider, telemetryClient?: TelemetryClient);
|
|
16
|
-
getConfig(): FullNodeBlockBuilderConfig;
|
|
17
|
-
updateConfig(config: Partial<FullNodeBlockBuilderConfig>): void;
|
|
18
|
-
makeBlockBuilderDeps(globalVariables: GlobalVariables, fork: MerkleTreeWriteOperations): Promise<{
|
|
19
|
-
processor: PublicProcessor;
|
|
20
|
-
validator: PublicProcessorValidator;
|
|
21
|
-
}>;
|
|
22
|
-
private syncToPreviousBlock;
|
|
23
|
-
buildBlock(pendingTxs: Iterable<Tx> | AsyncIterable<Tx>, l1ToL2Messages: Fr[], globalVariables: GlobalVariables, opts: PublicProcessorLimits, suppliedFork?: MerkleTreeWriteOperations): Promise<BuildBlockResult>;
|
|
24
|
-
getFork(blockNumber: BlockNumber): Promise<MerkleTreeWriteOperations>;
|
|
25
|
-
}
|
|
26
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvY2tfYnVpbGRlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcXVlbmNlci9ibG9ja19idWlsZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUU5RCxPQUFPLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUl6RCxPQUFPLEVBQUUsWUFBWSxFQUFrQixNQUFNLHlCQUF5QixDQUFDO0FBR3ZFLE9BQU8sRUFHTCxlQUFlLEVBRWhCLE1BQU0seUJBQXlCLENBQUM7QUFDakMsT0FBTyxLQUFLLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUdqRSxPQUFPLEtBQUssRUFDVixnQkFBZ0IsRUFDaEIsMEJBQTBCLEVBQzFCLHFCQUFxQixFQUNyQix5QkFBeUIsRUFDekIscUJBQXFCLEVBQ3JCLHdCQUF3QixFQUN4QixzQkFBc0IsRUFDdkIsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsZUFBZSxFQUFFLEVBQUUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxLQUFLLGVBQWUsRUFBc0IsTUFBTSx5QkFBeUIsQ0FBQztBQTBFbkYscUJBQWEsb0JBQXFCLFlBQVcscUJBQXFCO0lBRTlELE9BQU8sQ0FBQyxNQUFNO0lBQ2QsT0FBTyxDQUFDLFVBQVU7SUFDbEIsT0FBTyxDQUFDLGtCQUFrQjtJQUMxQixPQUFPLENBQUMsWUFBWTtJQUNwQixPQUFPLENBQUMsZUFBZTtJQUx6QixZQUNVLE1BQU0sRUFBRSwwQkFBMEIsRUFDbEMsVUFBVSxFQUFFLHNCQUFzQixFQUNsQyxrQkFBa0IsRUFBRSxrQkFBa0IsRUFDdEMsWUFBWSxFQUFFLFlBQVksRUFDMUIsZUFBZSxHQUFFLGVBQXNDLEVBQzdEO0lBRUcsU0FBUyxJQUFJLDBCQUEwQixDQUU3QztJQUVNLFlBQVksQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLDBCQUEwQixDQUFDLFFBRTlEO0lBRVksb0JBQW9CLENBQUMsZUFBZSxFQUFFLGVBQWUsRUFBRSxJQUFJLEVBQUUseUJBQXlCOzs7T0FrQ2xHO1lBRWEsbUJBQW1CO0lBVTNCLFVBQVUsQ0FDZCxVQUFVLEVBQUUsUUFBUSxDQUFDLEVBQUUsQ0FBQyxHQUFHLGFBQWEsQ0FBQyxFQUFFLENBQUMsRUFDNUMsY0FBYyxFQUFFLEVBQUUsRUFBRSxFQUNwQixlQUFlLEVBQUUsZUFBZSxFQUNoQyxJQUFJLEVBQUUscUJBQXFCLEVBQzNCLFlBQVksQ0FBQyxFQUFFLHlCQUF5QixHQUN2QyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FzQzNCO0lBRUQsT0FBTyxDQUFDLFdBQVcsRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLHlCQUF5QixDQUFDLENBRXBFO0NBQ0YifQ==
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"block_builder.d.ts","sourceRoot":"","sources":["../../src/sequencer/block_builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAIzD,OAAO,EAAE,YAAY,EAAkB,MAAM,yBAAyB,CAAC;AAGvE,OAAO,EAGL,eAAe,EAEhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAGjE,OAAO,KAAK,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AA0EnF,qBAAa,oBAAqB,YAAW,qBAAqB;IAE9D,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,eAAe;IALzB,YACU,MAAM,EAAE,0BAA0B,EAClC,UAAU,EAAE,sBAAsB,EAClC,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,YAAY,EAC1B,eAAe,GAAE,eAAsC,EAC7D;IAEG,SAAS,IAAI,0BAA0B,CAE7C;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,0BAA0B,CAAC,QAE9D;IAEY,oBAAoB,CAAC,eAAe,EAAE,eAAe,EAAE,IAAI,EAAE,yBAAyB;;;OAkClG;YAEa,mBAAmB;IAU3B,UAAU,CACd,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,EAAE,CAAC,EAC5C,cAAc,EAAE,EAAE,EAAE,EACpB,eAAe,EAAE,eAAe,EAChC,IAAI,EAAE,qBAAqB,EAC3B,YAAY,CAAC,EAAE,yBAAyB,GACvC,OAAO,CAAC,gBAAgB,CAAC,CAsC3B;IAED,OAAO,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAEpE;CACF"}
|