@aztec/validator-client 0.0.1-commit.7d4e6cd → 0.0.1-commit.858058eac
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/README.md +53 -24
- package/dest/block_proposal_handler.d.ts +8 -8
- package/dest/block_proposal_handler.d.ts.map +1 -1
- package/dest/block_proposal_handler.js +27 -32
- package/dest/checkpoint_builder.d.ts +21 -25
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +50 -32
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +12 -14
- package/dest/duties/validation_service.d.ts +19 -6
- package/dest/duties/validation_service.d.ts.map +1 -1
- package/dest/duties/validation_service.js +72 -19
- package/dest/factory.d.ts +2 -2
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +1 -1
- package/dest/key_store/ha_key_store.d.ts +99 -0
- package/dest/key_store/ha_key_store.d.ts.map +1 -0
- package/dest/key_store/ha_key_store.js +208 -0
- package/dest/key_store/index.d.ts +2 -1
- package/dest/key_store/index.d.ts.map +1 -1
- package/dest/key_store/index.js +1 -0
- package/dest/key_store/interface.d.ts +36 -6
- package/dest/key_store/interface.d.ts.map +1 -1
- package/dest/key_store/local_key_store.d.ts +10 -5
- package/dest/key_store/local_key_store.d.ts.map +1 -1
- package/dest/key_store/local_key_store.js +8 -4
- package/dest/key_store/node_keystore_adapter.d.ts +18 -5
- package/dest/key_store/node_keystore_adapter.d.ts.map +1 -1
- package/dest/key_store/node_keystore_adapter.js +18 -4
- package/dest/key_store/web3signer_key_store.d.ts +10 -5
- package/dest/key_store/web3signer_key_store.d.ts.map +1 -1
- package/dest/key_store/web3signer_key_store.js +8 -4
- package/dest/metrics.d.ts +4 -3
- package/dest/metrics.d.ts.map +1 -1
- package/dest/metrics.js +34 -5
- package/dest/tx_validator/tx_validator_factory.d.ts +4 -3
- package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
- package/dest/tx_validator/tx_validator_factory.js +17 -16
- package/dest/validator.d.ts +35 -16
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +194 -91
- package/package.json +21 -17
- package/src/block_proposal_handler.ts +41 -42
- package/src/checkpoint_builder.ts +85 -38
- package/src/config.ts +11 -13
- package/src/duties/validation_service.ts +91 -23
- package/src/factory.ts +1 -0
- package/src/key_store/ha_key_store.ts +269 -0
- package/src/key_store/index.ts +1 -0
- package/src/key_store/interface.ts +44 -5
- package/src/key_store/local_key_store.ts +13 -4
- package/src/key_store/node_keystore_adapter.ts +27 -4
- package/src/key_store/web3signer_key_store.ts +17 -4
- package/src/metrics.ts +45 -6
- package/src/tx_validator/tx_validator_factory.ts +52 -31
- package/src/validator.ts +253 -111
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
|
+
import type { EpochCache } from '@aztec/epoch-cache';
|
|
2
3
|
import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
4
|
+
import { chunkBy } from '@aztec/foundation/collection';
|
|
3
5
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
6
|
import { TimeoutError } from '@aztec/foundation/error';
|
|
5
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
6
8
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
7
9
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
8
10
|
import type { P2P, PeerId } from '@aztec/p2p';
|
|
9
|
-
import { TxProvider } from '@aztec/p2p';
|
|
10
11
|
import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
|
|
11
|
-
import type {
|
|
12
|
-
import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
13
|
-
import type { ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
14
|
-
import {
|
|
12
|
+
import type { L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
13
|
+
import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
14
|
+
import type { ITxProvider, ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
15
|
+
import {
|
|
16
|
+
type L1ToL2MessageSource,
|
|
17
|
+
computeCheckpointOutHash,
|
|
18
|
+
computeInHashFromL1ToL2Messages,
|
|
19
|
+
} from '@aztec/stdlib/messaging';
|
|
15
20
|
import type { BlockProposal } from '@aztec/stdlib/p2p';
|
|
16
21
|
import { BlockHeader, type CheckpointGlobalVariables, type FailedTx, type Tx } from '@aztec/stdlib/tx';
|
|
17
22
|
import {
|
|
@@ -39,7 +44,7 @@ export type BlockProposalValidationFailureReason =
|
|
|
39
44
|
| 'unknown_error';
|
|
40
45
|
|
|
41
46
|
type ReexecuteTransactionsResult = {
|
|
42
|
-
block:
|
|
47
|
+
block: L2Block;
|
|
43
48
|
failedTxs: FailedTx[];
|
|
44
49
|
reexecutionTimeMs: number;
|
|
45
50
|
totalManaUsed: number;
|
|
@@ -72,8 +77,9 @@ export class BlockProposalHandler {
|
|
|
72
77
|
private worldState: WorldStateSynchronizer,
|
|
73
78
|
private blockSource: L2BlockSource & L2BlockSink,
|
|
74
79
|
private l1ToL2MessageSource: L1ToL2MessageSource,
|
|
75
|
-
private txProvider:
|
|
80
|
+
private txProvider: ITxProvider,
|
|
76
81
|
private blockProposalValidator: BlockProposalValidator,
|
|
82
|
+
private epochCache: EpochCache,
|
|
77
83
|
private config: ValidatorClientFullConfig,
|
|
78
84
|
private metrics?: ValidatorMetrics,
|
|
79
85
|
private dateProvider: DateProvider = new DateProvider(),
|
|
@@ -140,8 +146,8 @@ export class BlockProposalHandler {
|
|
|
140
146
|
|
|
141
147
|
// Check that the proposal is from the current proposer, or the next proposer
|
|
142
148
|
// This should have been handled by the p2p layer, but we double check here out of caution
|
|
143
|
-
const
|
|
144
|
-
if (
|
|
149
|
+
const validationResult = await this.blockProposalValidator.validate(proposal);
|
|
150
|
+
if (validationResult.result !== 'accept') {
|
|
145
151
|
this.log.warn(`Proposal is not valid, skipping processing`, proposalInfo);
|
|
146
152
|
return { isValid: false, reason: 'invalid_proposal' };
|
|
147
153
|
}
|
|
@@ -153,9 +159,9 @@ export class BlockProposalHandler {
|
|
|
153
159
|
return { isValid: false, reason: 'parent_block_not_found' };
|
|
154
160
|
}
|
|
155
161
|
|
|
156
|
-
// Check that the parent block's slot is
|
|
157
|
-
if (parentBlockHeader !== 'genesis' && parentBlockHeader.getSlot()
|
|
158
|
-
this.log.warn(`Parent block slot is greater than
|
|
162
|
+
// Check that the parent block's slot is not greater than the proposal's slot.
|
|
163
|
+
if (parentBlockHeader !== 'genesis' && parentBlockHeader.getSlot() > slotNumber) {
|
|
164
|
+
this.log.warn(`Parent block slot is greater than proposal slot, skipping processing`, {
|
|
159
165
|
parentBlockSlot: parentBlockHeader.getSlot().toString(),
|
|
160
166
|
proposalSlot: slotNumber.toString(),
|
|
161
167
|
...proposalInfo,
|
|
@@ -212,6 +218,18 @@ export class BlockProposalHandler {
|
|
|
212
218
|
// Try re-executing the transactions in the proposal if needed
|
|
213
219
|
let reexecutionResult;
|
|
214
220
|
if (shouldReexecute) {
|
|
221
|
+
// Compute the previous checkpoint out hashes for the epoch.
|
|
222
|
+
// TODO(leila/mbps): There can be a more efficient way to get the previous checkpoint out
|
|
223
|
+
// hashes without having to fetch all the blocks.
|
|
224
|
+
const epoch = getEpochAtSlot(slotNumber, this.epochCache.getL1Constants());
|
|
225
|
+
const checkpointedBlocks = (await this.blockSource.getCheckpointedBlocksForEpoch(epoch))
|
|
226
|
+
.filter(b => b.block.number < blockNumber)
|
|
227
|
+
.sort((a, b) => a.block.number - b.block.number);
|
|
228
|
+
const blocksByCheckpoint = chunkBy(checkpointedBlocks, b => b.checkpointNumber);
|
|
229
|
+
const previousCheckpointOutHashes = blocksByCheckpoint.map(checkpointBlocks =>
|
|
230
|
+
computeCheckpointOutHash(checkpointBlocks.map(b => b.block.body.txEffects.map(tx => tx.l2ToL1Msgs))),
|
|
231
|
+
);
|
|
232
|
+
|
|
215
233
|
try {
|
|
216
234
|
this.log.verbose(`Re-executing transactions in the proposal`, proposalInfo);
|
|
217
235
|
reexecutionResult = await this.reexecuteTransactions(
|
|
@@ -220,6 +238,7 @@ export class BlockProposalHandler {
|
|
|
220
238
|
checkpointNumber,
|
|
221
239
|
txs,
|
|
222
240
|
l1ToL2Messages,
|
|
241
|
+
previousCheckpointOutHashes,
|
|
223
242
|
);
|
|
224
243
|
} catch (error) {
|
|
225
244
|
this.log.error(`Error reexecuting txs while processing block proposal`, error, proposalInfo);
|
|
@@ -229,7 +248,6 @@ export class BlockProposalHandler {
|
|
|
229
248
|
}
|
|
230
249
|
|
|
231
250
|
// If we succeeded, push this block into the archiver (unless disabled)
|
|
232
|
-
// TODO(palla/mbps): Change default to false once block sync is stable.
|
|
233
251
|
if (reexecutionResult?.block && this.config.skipPushProposedBlocksToArchiver === false) {
|
|
234
252
|
await this.blockSource.addBlock(reexecutionResult?.block);
|
|
235
253
|
}
|
|
@@ -297,7 +315,7 @@ export class BlockProposalHandler {
|
|
|
297
315
|
// TODO(palla/mbps): The block header should include the checkpoint number to avoid this lookup,
|
|
298
316
|
// or at least the L2BlockSource should return a different struct that includes it.
|
|
299
317
|
const parentBlockNumber = parentBlockHeader.getBlockNumber();
|
|
300
|
-
const parentBlock = await this.blockSource.
|
|
318
|
+
const parentBlock = await this.blockSource.getL2Block(parentBlockNumber);
|
|
301
319
|
if (!parentBlock) {
|
|
302
320
|
this.log.warn(`Parent block ${parentBlockNumber} not found in archiver`, proposalInfo);
|
|
303
321
|
return { reason: 'invalid_proposal' };
|
|
@@ -338,7 +356,7 @@ export class BlockProposalHandler {
|
|
|
338
356
|
*/
|
|
339
357
|
private validateNonFirstBlockInCheckpoint(
|
|
340
358
|
proposal: BlockProposal,
|
|
341
|
-
parentBlock:
|
|
359
|
+
parentBlock: L2Block,
|
|
342
360
|
proposalInfo: object,
|
|
343
361
|
): CheckpointComputationResult | undefined {
|
|
344
362
|
const proposalGlobals = proposal.blockHeader.globalVariables;
|
|
@@ -414,31 +432,7 @@ export class BlockProposalHandler {
|
|
|
414
432
|
|
|
415
433
|
private getReexecutionDeadline(slot: SlotNumber, config: { l1GenesisTime: bigint; slotDuration: number }): Date {
|
|
416
434
|
const nextSlotTimestampSeconds = Number(getTimestampForSlot(SlotNumber(slot + 1), config));
|
|
417
|
-
|
|
418
|
-
return new Date(nextSlotTimestampSeconds * 1000 - msNeededForPropagationAndPublishing);
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
/**
|
|
422
|
-
* Gets all prior blocks in the same checkpoint (same slot and checkpoint number) up to but not including upToBlockNumber.
|
|
423
|
-
*/
|
|
424
|
-
private async getBlocksInCheckpoint(
|
|
425
|
-
slot: SlotNumber,
|
|
426
|
-
upToBlockNumber: BlockNumber,
|
|
427
|
-
checkpointNumber: CheckpointNumber,
|
|
428
|
-
): Promise<L2BlockNew[]> {
|
|
429
|
-
const blocks: L2BlockNew[] = [];
|
|
430
|
-
let currentBlockNumber = BlockNumber(upToBlockNumber - 1);
|
|
431
|
-
|
|
432
|
-
while (currentBlockNumber >= INITIAL_L2_BLOCK_NUM) {
|
|
433
|
-
const block = await this.blockSource.getL2BlockNew(currentBlockNumber);
|
|
434
|
-
if (!block || block.header.getSlot() !== slot || block.checkpointNumber !== checkpointNumber) {
|
|
435
|
-
break;
|
|
436
|
-
}
|
|
437
|
-
blocks.unshift(block);
|
|
438
|
-
currentBlockNumber = BlockNumber(currentBlockNumber - 1);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
return blocks;
|
|
435
|
+
return new Date(nextSlotTimestampSeconds * 1000);
|
|
442
436
|
}
|
|
443
437
|
|
|
444
438
|
private getReexecuteFailureReason(err: any) {
|
|
@@ -459,6 +453,7 @@ export class BlockProposalHandler {
|
|
|
459
453
|
checkpointNumber: CheckpointNumber,
|
|
460
454
|
txs: Tx[],
|
|
461
455
|
l1ToL2Messages: Fr[],
|
|
456
|
+
previousCheckpointOutHashes: Fr[],
|
|
462
457
|
): Promise<ReexecuteTransactionsResult> {
|
|
463
458
|
const { blockHeader, txHashes } = proposal;
|
|
464
459
|
|
|
@@ -473,11 +468,13 @@ export class BlockProposalHandler {
|
|
|
473
468
|
const slot = proposal.slotNumber;
|
|
474
469
|
const config = this.checkpointsBuilder.getConfig();
|
|
475
470
|
|
|
476
|
-
// Get prior blocks in this checkpoint (same slot
|
|
477
|
-
const
|
|
471
|
+
// Get prior blocks in this checkpoint (same slot before current block)
|
|
472
|
+
const allBlocksInSlot = await this.blockSource.getBlocksForSlot(slot);
|
|
473
|
+
const priorBlocks = allBlocksInSlot.filter(b => b.number < blockNumber && b.header.getSlot() === slot);
|
|
478
474
|
|
|
479
475
|
// Fork before the block to be built
|
|
480
476
|
const parentBlockNumber = BlockNumber(blockNumber - 1);
|
|
477
|
+
await this.worldState.syncImmediate(parentBlockNumber);
|
|
481
478
|
using fork = await this.worldState.fork(parentBlockNumber);
|
|
482
479
|
|
|
483
480
|
// Build checkpoint constants from proposal (excludes blockNumber and timestamp which are per-block)
|
|
@@ -495,8 +492,10 @@ export class BlockProposalHandler {
|
|
|
495
492
|
checkpointNumber,
|
|
496
493
|
constants,
|
|
497
494
|
l1ToL2Messages,
|
|
495
|
+
previousCheckpointOutHashes,
|
|
498
496
|
fork,
|
|
499
497
|
priorBlocks,
|
|
498
|
+
this.log.getBindings(),
|
|
500
499
|
);
|
|
501
500
|
|
|
502
501
|
// Build the new block
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { merge, pick } from '@aztec/foundation/collection';
|
|
3
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
|
-
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
5
5
|
import { bufferToHex } from '@aztec/foundation/string';
|
|
6
|
-
import { DateProvider,
|
|
6
|
+
import { DateProvider, elapsed } from '@aztec/foundation/timer';
|
|
7
7
|
import { getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
|
|
8
8
|
import { LightweightCheckpointBuilder } from '@aztec/prover-client/light';
|
|
9
9
|
import {
|
|
@@ -12,39 +12,38 @@ import {
|
|
|
12
12
|
PublicProcessor,
|
|
13
13
|
createPublicTxSimulatorForBlockBuilding,
|
|
14
14
|
} from '@aztec/simulator/server';
|
|
15
|
-
import {
|
|
15
|
+
import { L2Block } from '@aztec/stdlib/block';
|
|
16
16
|
import { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
17
17
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
18
|
+
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
18
19
|
import { Gas } from '@aztec/stdlib/gas';
|
|
19
20
|
import {
|
|
21
|
+
type BuildBlockInCheckpointResult,
|
|
20
22
|
type FullNodeBlockBuilderConfig,
|
|
21
23
|
FullNodeBlockBuilderConfigKeys,
|
|
24
|
+
type ICheckpointBlockBuilder,
|
|
25
|
+
type ICheckpointsBuilder,
|
|
22
26
|
type MerkleTreeWriteOperations,
|
|
27
|
+
NoValidTxsError,
|
|
23
28
|
type PublicProcessorLimits,
|
|
29
|
+
type WorldStateSynchronizer,
|
|
24
30
|
} from '@aztec/stdlib/interfaces/server';
|
|
25
31
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
26
|
-
import { type CheckpointGlobalVariables,
|
|
32
|
+
import { type CheckpointGlobalVariables, GlobalVariables, StateReference, Tx } from '@aztec/stdlib/tx';
|
|
27
33
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
28
34
|
|
|
29
35
|
import { createValidatorForBlockBuilding } from './tx_validator/tx_validator_factory.js';
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
export interface BuildBlockInCheckpointResult {
|
|
34
|
-
block: L2BlockNew;
|
|
35
|
-
publicGas: Gas;
|
|
36
|
-
publicProcessorDuration: number;
|
|
37
|
-
numTxs: number;
|
|
38
|
-
failedTxs: FailedTx[];
|
|
39
|
-
blockBuildingTimer: Timer;
|
|
40
|
-
usedTxs: Tx[];
|
|
41
|
-
}
|
|
37
|
+
// Re-export for backward compatibility
|
|
38
|
+
export type { BuildBlockInCheckpointResult } from '@aztec/stdlib/interfaces/server';
|
|
42
39
|
|
|
43
40
|
/**
|
|
44
41
|
* Builder for a single checkpoint. Handles building blocks within the checkpoint
|
|
45
42
|
* and completing it.
|
|
46
43
|
*/
|
|
47
|
-
export class CheckpointBuilder {
|
|
44
|
+
export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
45
|
+
private log: Logger;
|
|
46
|
+
|
|
48
47
|
constructor(
|
|
49
48
|
private checkpointBuilder: LightweightCheckpointBuilder,
|
|
50
49
|
private fork: MerkleTreeWriteOperations,
|
|
@@ -52,7 +51,13 @@ export class CheckpointBuilder {
|
|
|
52
51
|
private contractDataSource: ContractDataSource,
|
|
53
52
|
private dateProvider: DateProvider,
|
|
54
53
|
private telemetryClient: TelemetryClient,
|
|
55
|
-
|
|
54
|
+
bindings?: LoggerBindings,
|
|
55
|
+
) {
|
|
56
|
+
this.log = createLogger('checkpoint-builder', {
|
|
57
|
+
...bindings,
|
|
58
|
+
instanceId: `checkpoint-${checkpointBuilder.checkpointNumber}`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
56
61
|
|
|
57
62
|
getConstantData(): CheckpointGlobalVariables {
|
|
58
63
|
return this.checkpointBuilder.constants;
|
|
@@ -65,12 +70,16 @@ export class CheckpointBuilder {
|
|
|
65
70
|
pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
66
71
|
blockNumber: BlockNumber,
|
|
67
72
|
timestamp: bigint,
|
|
68
|
-
opts: PublicProcessorLimits & { expectedEndState?: StateReference },
|
|
73
|
+
opts: PublicProcessorLimits & { expectedEndState?: StateReference } = {},
|
|
69
74
|
): Promise<BuildBlockInCheckpointResult> {
|
|
70
|
-
const blockBuildingTimer = new Timer();
|
|
71
75
|
const slot = this.checkpointBuilder.constants.slotNumber;
|
|
72
76
|
|
|
73
|
-
log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
|
|
77
|
+
this.log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
|
|
78
|
+
slot,
|
|
79
|
+
blockNumber,
|
|
80
|
+
...opts,
|
|
81
|
+
currentTime: new Date(this.dateProvider.now()),
|
|
82
|
+
});
|
|
74
83
|
|
|
75
84
|
const constants = this.checkpointBuilder.constants;
|
|
76
85
|
const globalVariables = GlobalVariables.from({
|
|
@@ -85,10 +94,16 @@ export class CheckpointBuilder {
|
|
|
85
94
|
});
|
|
86
95
|
const { processor, validator } = await this.makeBlockBuilderDeps(globalVariables, this.fork);
|
|
87
96
|
|
|
88
|
-
const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs]] = await elapsed(() =>
|
|
97
|
+
const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs, _, usedTxBlobFields]] = await elapsed(() =>
|
|
89
98
|
processor.process(pendingTxs, opts, validator),
|
|
90
99
|
);
|
|
91
100
|
|
|
101
|
+
// Throw if we didn't collect a single valid tx and we're not allowed to build empty blocks
|
|
102
|
+
// (only the first block in a checkpoint can be empty)
|
|
103
|
+
if (processedTxs.length === 0 && this.checkpointBuilder.getBlockCount() > 0) {
|
|
104
|
+
throw new NoValidTxsError(failedTxs);
|
|
105
|
+
}
|
|
106
|
+
|
|
92
107
|
// Add block to checkpoint
|
|
93
108
|
const block = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
|
|
94
109
|
expectedEndState: opts.expectedEndState,
|
|
@@ -97,24 +112,28 @@ export class CheckpointBuilder {
|
|
|
97
112
|
// How much public gas was processed
|
|
98
113
|
const publicGas = processedTxs.reduce((acc, tx) => acc.add(tx.gasUsed.publicGas), Gas.empty());
|
|
99
114
|
|
|
100
|
-
|
|
115
|
+
this.log.debug('Built block within checkpoint', {
|
|
116
|
+
header: block.header.toInspect(),
|
|
117
|
+
processedTxs: processedTxs.map(tx => tx.hash.toString()),
|
|
118
|
+
failedTxs: failedTxs.map(tx => tx.tx.txHash.toString()),
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return {
|
|
101
122
|
block,
|
|
102
123
|
publicGas,
|
|
103
124
|
publicProcessorDuration,
|
|
104
125
|
numTxs: processedTxs.length,
|
|
105
126
|
failedTxs,
|
|
106
|
-
blockBuildingTimer,
|
|
107
127
|
usedTxs,
|
|
128
|
+
usedTxBlobFields,
|
|
108
129
|
};
|
|
109
|
-
log.debug('Built block within checkpoint', res.block.header);
|
|
110
|
-
return res;
|
|
111
130
|
}
|
|
112
131
|
|
|
113
132
|
/** Completes the checkpoint and returns it. */
|
|
114
133
|
async completeCheckpoint(): Promise<Checkpoint> {
|
|
115
134
|
const checkpoint = await this.checkpointBuilder.completeCheckpoint();
|
|
116
135
|
|
|
117
|
-
log.verbose(`Completed checkpoint ${checkpoint.number}`, {
|
|
136
|
+
this.log.verbose(`Completed checkpoint ${checkpoint.number}`, {
|
|
118
137
|
checkpointNumber: checkpoint.number,
|
|
119
138
|
numBlocks: checkpoint.blocks.length,
|
|
120
139
|
archiveRoot: checkpoint.archive.root.toString(),
|
|
@@ -130,14 +149,16 @@ export class CheckpointBuilder {
|
|
|
130
149
|
|
|
131
150
|
protected async makeBlockBuilderDeps(globalVariables: GlobalVariables, fork: MerkleTreeWriteOperations) {
|
|
132
151
|
const txPublicSetupAllowList = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
|
|
133
|
-
const contractsDB = new PublicContractsDB(this.contractDataSource);
|
|
152
|
+
const contractsDB = new PublicContractsDB(this.contractDataSource, this.log.getBindings());
|
|
134
153
|
const guardedFork = new GuardedMerkleTreeOperations(fork);
|
|
135
154
|
|
|
155
|
+
const bindings = this.log.getBindings();
|
|
136
156
|
const publicTxSimulator = createPublicTxSimulatorForBlockBuilding(
|
|
137
157
|
guardedFork,
|
|
138
158
|
contractsDB,
|
|
139
159
|
globalVariables,
|
|
140
160
|
this.telemetryClient,
|
|
161
|
+
bindings,
|
|
141
162
|
);
|
|
142
163
|
|
|
143
164
|
const processor = new PublicProcessor(
|
|
@@ -147,7 +168,7 @@ export class CheckpointBuilder {
|
|
|
147
168
|
publicTxSimulator,
|
|
148
169
|
this.dateProvider,
|
|
149
170
|
this.telemetryClient,
|
|
150
|
-
|
|
171
|
+
createLogger('simulator:public-processor', bindings),
|
|
151
172
|
this.config,
|
|
152
173
|
);
|
|
153
174
|
|
|
@@ -156,6 +177,7 @@ export class CheckpointBuilder {
|
|
|
156
177
|
this.contractDataSource,
|
|
157
178
|
globalVariables,
|
|
158
179
|
txPublicSetupAllowList,
|
|
180
|
+
this.log.getBindings(),
|
|
159
181
|
);
|
|
160
182
|
|
|
161
183
|
return {
|
|
@@ -165,16 +187,19 @@ export class CheckpointBuilder {
|
|
|
165
187
|
}
|
|
166
188
|
}
|
|
167
189
|
|
|
168
|
-
/**
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
190
|
+
/** Factory for creating checkpoint builders. */
|
|
191
|
+
export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
192
|
+
private log: Logger;
|
|
193
|
+
|
|
172
194
|
constructor(
|
|
173
|
-
private config: FullNodeBlockBuilderConfig,
|
|
195
|
+
private config: FullNodeBlockBuilderConfig & Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>,
|
|
196
|
+
private worldState: WorldStateSynchronizer,
|
|
174
197
|
private contractDataSource: ContractDataSource,
|
|
175
198
|
private dateProvider: DateProvider,
|
|
176
199
|
private telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
177
|
-
) {
|
|
200
|
+
) {
|
|
201
|
+
this.log = createLogger('checkpoint-builder');
|
|
202
|
+
}
|
|
178
203
|
|
|
179
204
|
public getConfig(): FullNodeBlockBuilderConfig {
|
|
180
205
|
return this.config;
|
|
@@ -191,12 +216,14 @@ export class FullNodeCheckpointsBuilder {
|
|
|
191
216
|
checkpointNumber: CheckpointNumber,
|
|
192
217
|
constants: CheckpointGlobalVariables,
|
|
193
218
|
l1ToL2Messages: Fr[],
|
|
219
|
+
previousCheckpointOutHashes: Fr[],
|
|
194
220
|
fork: MerkleTreeWriteOperations,
|
|
221
|
+
bindings?: LoggerBindings,
|
|
195
222
|
): Promise<CheckpointBuilder> {
|
|
196
223
|
const stateReference = await fork.getStateReference();
|
|
197
224
|
const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
198
225
|
|
|
199
|
-
log.verbose(`Building new checkpoint ${checkpointNumber}`, {
|
|
226
|
+
this.log.verbose(`Building new checkpoint ${checkpointNumber}`, {
|
|
200
227
|
checkpointNumber,
|
|
201
228
|
msgCount: l1ToL2Messages.length,
|
|
202
229
|
initialStateReference: stateReference.toInspect(),
|
|
@@ -208,7 +235,9 @@ export class FullNodeCheckpointsBuilder {
|
|
|
208
235
|
checkpointNumber,
|
|
209
236
|
constants,
|
|
210
237
|
l1ToL2Messages,
|
|
238
|
+
previousCheckpointOutHashes,
|
|
211
239
|
fork,
|
|
240
|
+
bindings,
|
|
212
241
|
);
|
|
213
242
|
|
|
214
243
|
return new CheckpointBuilder(
|
|
@@ -218,6 +247,7 @@ export class FullNodeCheckpointsBuilder {
|
|
|
218
247
|
this.contractDataSource,
|
|
219
248
|
this.dateProvider,
|
|
220
249
|
this.telemetryClient,
|
|
250
|
+
bindings,
|
|
221
251
|
);
|
|
222
252
|
}
|
|
223
253
|
|
|
@@ -228,17 +258,26 @@ export class FullNodeCheckpointsBuilder {
|
|
|
228
258
|
checkpointNumber: CheckpointNumber,
|
|
229
259
|
constants: CheckpointGlobalVariables,
|
|
230
260
|
l1ToL2Messages: Fr[],
|
|
261
|
+
previousCheckpointOutHashes: Fr[],
|
|
231
262
|
fork: MerkleTreeWriteOperations,
|
|
232
|
-
existingBlocks:
|
|
263
|
+
existingBlocks: L2Block[] = [],
|
|
264
|
+
bindings?: LoggerBindings,
|
|
233
265
|
): Promise<CheckpointBuilder> {
|
|
234
266
|
const stateReference = await fork.getStateReference();
|
|
235
267
|
const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
236
268
|
|
|
237
269
|
if (existingBlocks.length === 0) {
|
|
238
|
-
return this.startCheckpoint(
|
|
270
|
+
return this.startCheckpoint(
|
|
271
|
+
checkpointNumber,
|
|
272
|
+
constants,
|
|
273
|
+
l1ToL2Messages,
|
|
274
|
+
previousCheckpointOutHashes,
|
|
275
|
+
fork,
|
|
276
|
+
bindings,
|
|
277
|
+
);
|
|
239
278
|
}
|
|
240
279
|
|
|
241
|
-
log.verbose(`Resuming checkpoint ${checkpointNumber} with ${existingBlocks.length} existing blocks`, {
|
|
280
|
+
this.log.verbose(`Resuming checkpoint ${checkpointNumber} with ${existingBlocks.length} existing blocks`, {
|
|
242
281
|
checkpointNumber,
|
|
243
282
|
msgCount: l1ToL2Messages.length,
|
|
244
283
|
existingBlockCount: existingBlocks.length,
|
|
@@ -251,8 +290,10 @@ export class FullNodeCheckpointsBuilder {
|
|
|
251
290
|
checkpointNumber,
|
|
252
291
|
constants,
|
|
253
292
|
l1ToL2Messages,
|
|
293
|
+
previousCheckpointOutHashes,
|
|
254
294
|
fork,
|
|
255
295
|
existingBlocks,
|
|
296
|
+
bindings,
|
|
256
297
|
);
|
|
257
298
|
|
|
258
299
|
return new CheckpointBuilder(
|
|
@@ -262,6 +303,12 @@ export class FullNodeCheckpointsBuilder {
|
|
|
262
303
|
this.contractDataSource,
|
|
263
304
|
this.dateProvider,
|
|
264
305
|
this.telemetryClient,
|
|
306
|
+
bindings,
|
|
265
307
|
);
|
|
266
308
|
}
|
|
309
|
+
|
|
310
|
+
/** Returns a fork of the world state at the given block number. */
|
|
311
|
+
getFork(blockNumber: BlockNumber): Promise<MerkleTreeWriteOperations> {
|
|
312
|
+
return this.worldState.fork(blockNumber);
|
|
313
|
+
}
|
|
267
314
|
}
|
package/src/config.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from '@aztec/foundation/config';
|
|
8
8
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
9
9
|
import type { ValidatorClientConfig } from '@aztec/stdlib/interfaces/server';
|
|
10
|
+
import { validatorHASignerConfigMappings } from '@aztec/validator-ha-signer/config';
|
|
10
11
|
|
|
11
12
|
export type { ValidatorClientConfig };
|
|
12
13
|
|
|
@@ -53,16 +54,10 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
|
|
|
53
54
|
description: 'Re-execute transactions before attesting',
|
|
54
55
|
...booleanConfigHelper(true),
|
|
55
56
|
},
|
|
56
|
-
validatorReexecuteDeadlineMs: {
|
|
57
|
-
env: 'VALIDATOR_REEXECUTE_DEADLINE_MS',
|
|
58
|
-
description: 'Will re-execute until this many milliseconds are left in the slot',
|
|
59
|
-
...numberConfigHelper(6000),
|
|
60
|
-
},
|
|
61
57
|
alwaysReexecuteBlockProposals: {
|
|
62
|
-
env: 'ALWAYS_REEXECUTE_BLOCK_PROPOSALS',
|
|
63
58
|
description:
|
|
64
59
|
'Whether to always reexecute block proposals, even for non-validator nodes (useful for monitoring network status).',
|
|
65
|
-
|
|
60
|
+
defaultValue: true,
|
|
66
61
|
},
|
|
67
62
|
fishermanMode: {
|
|
68
63
|
env: 'FISHERMAN_MODE',
|
|
@@ -70,16 +65,19 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
|
|
|
70
65
|
'Whether to run in fisherman mode: validates all proposals and attestations but does not broadcast attestations or participate in consensus.',
|
|
71
66
|
...booleanConfigHelper(false),
|
|
72
67
|
},
|
|
73
|
-
// TODO(palla/mbps): Change default to false once checkpoint validation is stable
|
|
74
68
|
skipCheckpointProposalValidation: {
|
|
75
|
-
description: 'Skip checkpoint proposal validation and always attest (default:
|
|
76
|
-
defaultValue:
|
|
69
|
+
description: 'Skip checkpoint proposal validation and always attest (default: false)',
|
|
70
|
+
defaultValue: false,
|
|
77
71
|
},
|
|
78
|
-
// TODO(palla/mbps): Change default to false once block sync is stable
|
|
79
72
|
skipPushProposedBlocksToArchiver: {
|
|
80
|
-
description: 'Skip pushing re-executed blocks to archiver (default:
|
|
81
|
-
defaultValue:
|
|
73
|
+
description: 'Skip pushing re-executed blocks to archiver (default: false)',
|
|
74
|
+
defaultValue: false,
|
|
75
|
+
},
|
|
76
|
+
attestToEquivocatedProposals: {
|
|
77
|
+
description: 'Agree to attest to equivocated checkpoint proposals (for testing purposes only)',
|
|
78
|
+
...booleanConfigHelper(false),
|
|
82
79
|
},
|
|
80
|
+
...validatorHASignerConfigMappings,
|
|
83
81
|
};
|
|
84
82
|
|
|
85
83
|
/**
|