@aztec/sequencer-client 0.0.1-commit.1142ef1 → 0.0.1-commit.18ccd8f0
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/sequencer/checkpoint_proposal_job.d.ts +8 -6
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +97 -17
- 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 +17 -9
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +67 -11
- 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 -8
- 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/sequencer/checkpoint_proposal_job.ts +136 -28
- 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 +82 -10
- package/src/test/mock_checkpoint_builder.ts +65 -33
- 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,8 @@ 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
62
|
|
|
63
63
|
/** The last slot for which we triggered a checkpoint proposal job, to prevent duplicate attempts. */
|
|
64
64
|
private lastSlotForCheckpointProposalJob: SlotNumber | undefined;
|
|
@@ -202,7 +202,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
202
202
|
const { slot, ts, now, epoch } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
203
203
|
|
|
204
204
|
// 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);
|
|
205
|
+
const checkpointProposalJob = await this.prepareCheckpointProposal(epoch, slot, ts, now);
|
|
206
206
|
if (!checkpointProposalJob) {
|
|
207
207
|
return;
|
|
208
208
|
}
|
|
@@ -234,6 +234,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
234
234
|
*/
|
|
235
235
|
@trackSpan('Sequencer.prepareCheckpointProposal')
|
|
236
236
|
private async prepareCheckpointProposal(
|
|
237
|
+
epoch: EpochNumber,
|
|
237
238
|
slot: SlotNumber,
|
|
238
239
|
ts: bigint,
|
|
239
240
|
now: bigint,
|
|
@@ -263,6 +264,25 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
263
264
|
return undefined;
|
|
264
265
|
}
|
|
265
266
|
|
|
267
|
+
// If escape hatch is open for this epoch, do not start checkpoint proposal work and do not attempt invalidations.
|
|
268
|
+
// Still perform governance/slashing voting (as proposer) once per slot.
|
|
269
|
+
const isEscapeHatchOpen = await this.epochCache.isEscapeHatchOpen(epoch);
|
|
270
|
+
|
|
271
|
+
if (isEscapeHatchOpen) {
|
|
272
|
+
this.setState(SequencerState.PROPOSER_CHECK, slot);
|
|
273
|
+
const [canPropose, proposer] = await this.checkCanPropose(slot);
|
|
274
|
+
if (canPropose) {
|
|
275
|
+
await this.tryVoteWhenEscapeHatchOpen({ slot, proposer });
|
|
276
|
+
} else {
|
|
277
|
+
this.log.trace(`Escape hatch open but we are not proposer, skipping vote-only actions`, {
|
|
278
|
+
slot,
|
|
279
|
+
epoch,
|
|
280
|
+
proposer,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
|
|
266
286
|
// Next checkpoint follows from the last synced one
|
|
267
287
|
const checkpointNumber = CheckpointNumber(syncedTo.checkpointNumber + 1);
|
|
268
288
|
|
|
@@ -357,6 +377,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
357
377
|
|
|
358
378
|
// Create and return the checkpoint proposal job
|
|
359
379
|
return this.createCheckpointProposalJob(
|
|
380
|
+
epoch,
|
|
360
381
|
slot,
|
|
361
382
|
checkpointNumber,
|
|
362
383
|
syncedTo.blockNumber,
|
|
@@ -368,6 +389,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
368
389
|
}
|
|
369
390
|
|
|
370
391
|
protected createCheckpointProposalJob(
|
|
392
|
+
epoch: EpochNumber,
|
|
371
393
|
slot: SlotNumber,
|
|
372
394
|
checkpointNumber: CheckpointNumber,
|
|
373
395
|
syncedToBlockNumber: BlockNumber,
|
|
@@ -377,6 +399,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
377
399
|
invalidateCheckpoint: InvalidateCheckpointRequest | undefined,
|
|
378
400
|
): CheckpointProposalJob {
|
|
379
401
|
return new CheckpointProposalJob(
|
|
402
|
+
epoch,
|
|
380
403
|
slot,
|
|
381
404
|
checkpointNumber,
|
|
382
405
|
syncedToBlockNumber,
|
|
@@ -389,6 +412,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
389
412
|
this.p2pClient,
|
|
390
413
|
this.worldState,
|
|
391
414
|
this.l1ToL2MessageSource,
|
|
415
|
+
this.l2BlockSource,
|
|
392
416
|
this.checkpointsBuilder,
|
|
393
417
|
this.l2BlockSource,
|
|
394
418
|
this.l1Constants,
|
|
@@ -400,8 +424,8 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
400
424
|
this.metrics,
|
|
401
425
|
this,
|
|
402
426
|
this.setState.bind(this),
|
|
403
|
-
this.log,
|
|
404
427
|
this.tracer,
|
|
428
|
+
this.log.getBindings(),
|
|
405
429
|
);
|
|
406
430
|
}
|
|
407
431
|
|
|
@@ -505,7 +529,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
505
529
|
};
|
|
506
530
|
}
|
|
507
531
|
|
|
508
|
-
const block = await this.l2BlockSource.
|
|
532
|
+
const block = await this.l2BlockSource.getL2Block(blockNumber);
|
|
509
533
|
if (!block) {
|
|
510
534
|
// this shouldn't really happen because a moment ago we checked that all components were in sync
|
|
511
535
|
this.log.error(`Failed to get L2 block ${blockNumber} from the archiver with all components in sync`);
|
|
@@ -569,7 +593,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
569
593
|
const { slot } = args;
|
|
570
594
|
|
|
571
595
|
// Prevent duplicate attempts in the same slot
|
|
572
|
-
if (this.
|
|
596
|
+
if (this.lastSlotForFallbackVote === slot) {
|
|
573
597
|
this.log.trace(`Already attempted to vote in slot ${slot} (skipping)`);
|
|
574
598
|
return;
|
|
575
599
|
}
|
|
@@ -601,7 +625,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
601
625
|
}
|
|
602
626
|
|
|
603
627
|
// Mark this slot as attempted
|
|
604
|
-
this.
|
|
628
|
+
this.lastSlotForFallbackVote = slot;
|
|
605
629
|
|
|
606
630
|
// Get a publisher for voting
|
|
607
631
|
const { attestorAddress, publisher } = await this.publisherFactory.create(proposer);
|
|
@@ -636,7 +660,55 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
636
660
|
}
|
|
637
661
|
|
|
638
662
|
/**
|
|
639
|
-
*
|
|
663
|
+
* Tries to vote on slashing actions and governance proposals when escape hatch is open.
|
|
664
|
+
* This allows the sequencer to participate in voting without performing checkpoint proposal work.
|
|
665
|
+
*/
|
|
666
|
+
@trackSpan('Sequencer.tryVoteWhenEscapeHatchOpen', ({ slot }) => ({ [Attributes.SLOT_NUMBER]: slot }))
|
|
667
|
+
protected async tryVoteWhenEscapeHatchOpen(args: {
|
|
668
|
+
slot: SlotNumber;
|
|
669
|
+
proposer: EthAddress | undefined;
|
|
670
|
+
}): Promise<void> {
|
|
671
|
+
const { slot, proposer } = args;
|
|
672
|
+
|
|
673
|
+
// Prevent duplicate attempts in the same slot
|
|
674
|
+
if (this.lastSlotForFallbackVote === slot) {
|
|
675
|
+
this.log.trace(`Already attempted to vote in slot ${slot} (escape hatch open, skipping)`);
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// Mark this slot as attempted
|
|
680
|
+
this.lastSlotForFallbackVote = slot;
|
|
681
|
+
|
|
682
|
+
const { attestorAddress, publisher } = await this.publisherFactory.create(proposer);
|
|
683
|
+
|
|
684
|
+
this.log.debug(`Escape hatch open for slot ${slot}, attempting vote-only actions`, { slot, attestorAddress });
|
|
685
|
+
|
|
686
|
+
const voter = new CheckpointVoter(
|
|
687
|
+
slot,
|
|
688
|
+
publisher,
|
|
689
|
+
attestorAddress,
|
|
690
|
+
this.validatorClient,
|
|
691
|
+
this.slasherClient,
|
|
692
|
+
this.l1Constants,
|
|
693
|
+
this.config,
|
|
694
|
+
this.metrics,
|
|
695
|
+
this.log,
|
|
696
|
+
);
|
|
697
|
+
|
|
698
|
+
const votesPromises = voter.enqueueVotes();
|
|
699
|
+
const votes = await Promise.all(votesPromises);
|
|
700
|
+
|
|
701
|
+
if (votes.every(p => !p)) {
|
|
702
|
+
this.log.debug(`No votes to enqueue for slot ${slot} (escape hatch open)`);
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
this.log.info(`Voting in slot ${slot} (escape hatch open)`, { slot });
|
|
707
|
+
await publisher.sendRequests();
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Considers invalidating a block if the pending chain is invalid. Depends on how long the invalid block
|
|
640
712
|
* has been there without being invalidated and whether the sequencer is in the committee or not. We always
|
|
641
713
|
* have the proposer try to invalidate, but if they fail, the sequencers in the committee are expected to try,
|
|
642
714
|
* and if they fail, any sequencer will try as well.
|
|
@@ -798,7 +870,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
798
870
|
}
|
|
799
871
|
|
|
800
872
|
type SequencerSyncCheckResult = {
|
|
801
|
-
block?:
|
|
873
|
+
block?: L2Block;
|
|
802
874
|
checkpointNumber: CheckpointNumber;
|
|
803
875
|
blockNumber: BlockNumber;
|
|
804
876
|
archive: Fr;
|
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
import { type BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
3
|
import { Timer } from '@aztec/foundation/timer';
|
|
4
|
-
import
|
|
5
|
-
import { L2BlockNew } from '@aztec/stdlib/block';
|
|
4
|
+
import { L2Block } from '@aztec/stdlib/block';
|
|
6
5
|
import { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
7
6
|
import { Gas } from '@aztec/stdlib/gas';
|
|
8
|
-
import type {
|
|
7
|
+
import type {
|
|
8
|
+
FullNodeBlockBuilderConfig,
|
|
9
|
+
ICheckpointBlockBuilder,
|
|
10
|
+
ICheckpointsBuilder,
|
|
11
|
+
MerkleTreeWriteOperations,
|
|
12
|
+
PublicProcessorLimits,
|
|
13
|
+
} from '@aztec/stdlib/interfaces/server';
|
|
9
14
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
10
15
|
import { makeAppendOnlyTreeSnapshot } from '@aztec/stdlib/testing';
|
|
11
16
|
import type { CheckpointGlobalVariables, Tx } from '@aztec/stdlib/tx';
|
|
12
|
-
import type {
|
|
13
|
-
BuildBlockInCheckpointResult,
|
|
14
|
-
CheckpointBuilder,
|
|
15
|
-
FullNodeCheckpointsBuilder,
|
|
16
|
-
} from '@aztec/validator-client';
|
|
17
|
+
import type { BuildBlockInCheckpointResultWithTimer } from '@aztec/validator-client';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* A fake CheckpointBuilder for testing that implements the same interface as the real one.
|
|
20
21
|
* Can be seeded with blocks to return sequentially on each `buildBlock` call.
|
|
21
22
|
*/
|
|
22
|
-
export class MockCheckpointBuilder implements
|
|
23
|
-
private blocks:
|
|
24
|
-
private builtBlocks:
|
|
23
|
+
export class MockCheckpointBuilder implements ICheckpointBlockBuilder {
|
|
24
|
+
private blocks: L2Block[] = [];
|
|
25
|
+
private builtBlocks: L2Block[] = [];
|
|
25
26
|
private usedTxsPerBlock: Tx[][] = [];
|
|
26
27
|
private blockIndex = 0;
|
|
27
28
|
|
|
28
29
|
/** Optional function to dynamically provide the block (alternative to seedBlocks) */
|
|
29
|
-
private blockProvider: (() =>
|
|
30
|
+
private blockProvider: (() => L2Block) | undefined = undefined;
|
|
30
31
|
|
|
31
32
|
/** Track calls for assertions */
|
|
32
33
|
public buildBlockCalls: Array<{
|
|
@@ -34,6 +35,8 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
34
35
|
timestamp: bigint;
|
|
35
36
|
opts: PublicProcessorLimits;
|
|
36
37
|
}> = [];
|
|
38
|
+
/** Track all consumed transaction hashes across buildBlock calls */
|
|
39
|
+
public consumedTxHashes: Set<string> = new Set();
|
|
37
40
|
public completeCheckpointCalled = false;
|
|
38
41
|
public getCheckpointCalled = false;
|
|
39
42
|
|
|
@@ -46,7 +49,7 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
46
49
|
) {}
|
|
47
50
|
|
|
48
51
|
/** Seed the builder with blocks to return on successive buildBlock calls */
|
|
49
|
-
seedBlocks(blocks:
|
|
52
|
+
seedBlocks(blocks: L2Block[], usedTxsPerBlock?: Tx[][]): this {
|
|
50
53
|
this.blocks = blocks;
|
|
51
54
|
this.usedTxsPerBlock = usedTxsPerBlock ?? blocks.map(() => []);
|
|
52
55
|
this.blockIndex = 0;
|
|
@@ -58,7 +61,7 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
58
61
|
* Set a function that provides blocks dynamically.
|
|
59
62
|
* Useful for tests where the block is determined at call time (e.g., sequencer tests).
|
|
60
63
|
*/
|
|
61
|
-
setBlockProvider(provider: () =>
|
|
64
|
+
setBlockProvider(provider: () => L2Block): this {
|
|
62
65
|
this.blockProvider = provider;
|
|
63
66
|
this.blocks = [];
|
|
64
67
|
return this;
|
|
@@ -68,19 +71,19 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
68
71
|
return this.constants;
|
|
69
72
|
}
|
|
70
73
|
|
|
71
|
-
buildBlock(
|
|
72
|
-
|
|
74
|
+
async buildBlock(
|
|
75
|
+
pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
73
76
|
blockNumber: BlockNumber,
|
|
74
77
|
timestamp: bigint,
|
|
75
78
|
opts: PublicProcessorLimits,
|
|
76
|
-
): Promise<
|
|
79
|
+
): Promise<BuildBlockInCheckpointResultWithTimer> {
|
|
77
80
|
this.buildBlockCalls.push({ blockNumber, timestamp, opts });
|
|
78
81
|
|
|
79
82
|
if (this.errorOnBuild) {
|
|
80
|
-
|
|
83
|
+
throw this.errorOnBuild;
|
|
81
84
|
}
|
|
82
85
|
|
|
83
|
-
let block:
|
|
86
|
+
let block: L2Block;
|
|
84
87
|
let usedTxs: Tx[];
|
|
85
88
|
|
|
86
89
|
if (this.blockProvider) {
|
|
@@ -96,7 +99,20 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
96
99
|
this.builtBlocks.push(block);
|
|
97
100
|
}
|
|
98
101
|
|
|
99
|
-
|
|
102
|
+
// Check that no pending tx has already been consumed
|
|
103
|
+
for await (const tx of pendingTxs) {
|
|
104
|
+
const hash = tx.getTxHash().toString();
|
|
105
|
+
if (this.consumedTxHashes.has(hash)) {
|
|
106
|
+
throw new Error(`Transaction ${hash} was already consumed in a previous block`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Add used txs to consumed set
|
|
111
|
+
for (const tx of usedTxs) {
|
|
112
|
+
this.consumedTxHashes.add(tx.getTxHash().toString());
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
100
116
|
block,
|
|
101
117
|
publicGas: Gas.empty(),
|
|
102
118
|
publicProcessorDuration: 0,
|
|
@@ -104,7 +120,8 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
104
120
|
blockBuildingTimer: new Timer(),
|
|
105
121
|
usedTxs,
|
|
106
122
|
failedTxs: [],
|
|
107
|
-
|
|
123
|
+
usedTxBlobFields: block?.body?.txEffects?.reduce((sum, tx) => sum + tx.getNumBlobFields(), 0) ?? 0,
|
|
124
|
+
};
|
|
108
125
|
}
|
|
109
126
|
|
|
110
127
|
completeCheckpoint(): Promise<Checkpoint> {
|
|
@@ -146,7 +163,7 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
146
163
|
* Creates a CheckpointHeader from a block's header for testing.
|
|
147
164
|
* This is a simplified version that creates a minimal CheckpointHeader.
|
|
148
165
|
*/
|
|
149
|
-
private createCheckpointHeader(block:
|
|
166
|
+
private createCheckpointHeader(block: L2Block): CheckpointHeader {
|
|
150
167
|
const header = block.header;
|
|
151
168
|
const gv = header.globalVariables;
|
|
152
169
|
return CheckpointHeader.empty({
|
|
@@ -168,6 +185,7 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
168
185
|
this.usedTxsPerBlock = [];
|
|
169
186
|
this.blockIndex = 0;
|
|
170
187
|
this.buildBlockCalls = [];
|
|
188
|
+
this.consumedTxHashes.clear();
|
|
171
189
|
this.completeCheckpointCalled = false;
|
|
172
190
|
this.getCheckpointCalled = false;
|
|
173
191
|
this.errorOnBuild = undefined;
|
|
@@ -180,7 +198,7 @@ export class MockCheckpointBuilder implements FunctionsOf<CheckpointBuilder> {
|
|
|
180
198
|
* as FullNodeCheckpointsBuilder. Returns MockCheckpointBuilder instances.
|
|
181
199
|
* Does NOT use jest mocks - this is a proper test double.
|
|
182
200
|
*/
|
|
183
|
-
export class MockCheckpointsBuilder implements
|
|
201
|
+
export class MockCheckpointsBuilder implements ICheckpointsBuilder {
|
|
184
202
|
private checkpointBuilder: MockCheckpointBuilder | undefined;
|
|
185
203
|
|
|
186
204
|
/** Track calls for assertions */
|
|
@@ -188,12 +206,14 @@ export class MockCheckpointsBuilder implements FunctionsOf<FullNodeCheckpointsBu
|
|
|
188
206
|
checkpointNumber: CheckpointNumber;
|
|
189
207
|
constants: CheckpointGlobalVariables;
|
|
190
208
|
l1ToL2Messages: Fr[];
|
|
209
|
+
previousCheckpointOutHashes: Fr[];
|
|
191
210
|
}> = [];
|
|
192
211
|
public openCheckpointCalls: Array<{
|
|
193
212
|
checkpointNumber: CheckpointNumber;
|
|
194
213
|
constants: CheckpointGlobalVariables;
|
|
195
214
|
l1ToL2Messages: Fr[];
|
|
196
|
-
|
|
215
|
+
previousCheckpointOutHashes: Fr[];
|
|
216
|
+
existingBlocks: L2Block[];
|
|
197
217
|
}> = [];
|
|
198
218
|
public updateConfigCalls: Array<Partial<FullNodeBlockBuilderConfig>> = [];
|
|
199
219
|
|
|
@@ -240,33 +260,45 @@ export class MockCheckpointsBuilder implements FunctionsOf<FullNodeCheckpointsBu
|
|
|
240
260
|
checkpointNumber: CheckpointNumber,
|
|
241
261
|
constants: CheckpointGlobalVariables,
|
|
242
262
|
l1ToL2Messages: Fr[],
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
263
|
+
previousCheckpointOutHashes: Fr[],
|
|
264
|
+
_fork: MerkleTreeWriteOperations,
|
|
265
|
+
): Promise<ICheckpointBlockBuilder> {
|
|
266
|
+
this.startCheckpointCalls.push({ checkpointNumber, constants, l1ToL2Messages, previousCheckpointOutHashes });
|
|
246
267
|
|
|
247
268
|
if (!this.checkpointBuilder) {
|
|
248
269
|
// Auto-create a builder if none was set
|
|
249
270
|
this.checkpointBuilder = new MockCheckpointBuilder(constants, checkpointNumber);
|
|
250
271
|
}
|
|
251
272
|
|
|
252
|
-
return Promise.resolve(this.checkpointBuilder
|
|
273
|
+
return Promise.resolve(this.checkpointBuilder);
|
|
253
274
|
}
|
|
254
275
|
|
|
255
276
|
openCheckpoint(
|
|
256
277
|
checkpointNumber: CheckpointNumber,
|
|
257
278
|
constants: CheckpointGlobalVariables,
|
|
258
279
|
l1ToL2Messages: Fr[],
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
280
|
+
previousCheckpointOutHashes: Fr[],
|
|
281
|
+
_fork: MerkleTreeWriteOperations,
|
|
282
|
+
existingBlocks: L2Block[] = [],
|
|
283
|
+
): Promise<ICheckpointBlockBuilder> {
|
|
284
|
+
this.openCheckpointCalls.push({
|
|
285
|
+
checkpointNumber,
|
|
286
|
+
constants,
|
|
287
|
+
l1ToL2Messages,
|
|
288
|
+
previousCheckpointOutHashes,
|
|
289
|
+
existingBlocks,
|
|
290
|
+
});
|
|
263
291
|
|
|
264
292
|
if (!this.checkpointBuilder) {
|
|
265
293
|
// Auto-create a builder if none was set
|
|
266
294
|
this.checkpointBuilder = new MockCheckpointBuilder(constants, checkpointNumber);
|
|
267
295
|
}
|
|
268
296
|
|
|
269
|
-
return Promise.resolve(this.checkpointBuilder
|
|
297
|
+
return Promise.resolve(this.checkpointBuilder);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
getFork(_blockNumber: BlockNumber): Promise<MerkleTreeWriteOperations> {
|
|
301
|
+
throw new Error('MockCheckpointsBuilder.getFork not implemented');
|
|
270
302
|
}
|
|
271
303
|
|
|
272
304
|
/** 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"}
|