@aztec/validator-client 0.0.1-commit.6d3c34e → 0.0.1-commit.7035c9bd6
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 +94 -24
- package/dest/block_proposal_handler.d.ts +12 -11
- package/dest/block_proposal_handler.d.ts.map +1 -1
- package/dest/block_proposal_handler.js +140 -77
- package/dest/checkpoint_builder.d.ts +35 -26
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +144 -48
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +33 -14
- package/dest/duties/validation_service.d.ts +20 -7
- package/dest/duties/validation_service.d.ts.map +1 -1
- package/dest/duties/validation_service.js +69 -22
- package/dest/factory.d.ts +4 -2
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +4 -3
- package/dest/index.d.ts +1 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +0 -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 +12 -3
- package/dest/metrics.d.ts.map +1 -1
- package/dest/metrics.js +46 -5
- package/dest/validator.d.ts +45 -18
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +276 -107
- package/package.json +21 -17
- package/src/block_proposal_handler.ts +171 -95
- package/src/checkpoint_builder.ts +211 -61
- package/src/config.ts +32 -13
- package/src/duties/validation_service.ts +94 -25
- package/src/factory.ts +5 -0
- package/src/index.ts +0 -1
- 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 +63 -6
- package/src/validator.ts +354 -130
- package/dest/tx_validator/index.d.ts +0 -3
- package/dest/tx_validator/index.d.ts.map +0 -1
- package/dest/tx_validator/index.js +0 -2
- package/dest/tx_validator/nullifier_cache.d.ts +0 -14
- package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
- package/dest/tx_validator/nullifier_cache.js +0 -24
- package/dest/tx_validator/tx_validator_factory.d.ts +0 -18
- package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
- package/dest/tx_validator/tx_validator_factory.js +0 -53
- package/src/tx_validator/index.ts +0 -2
- package/src/tx_validator/nullifier_cache.ts +0 -30
- package/src/tx_validator/tx_validator_factory.ts +0 -133
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { NUM_CHECKPOINT_END_MARKER_FIELDS, getNumBlockEndBlobFields } from '@aztec/blob-lib/encoding';
|
|
2
|
+
import { BLOBS_PER_CHECKPOINT, FIELDS_PER_BLOB, MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT } from '@aztec/constants';
|
|
1
3
|
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import { merge, pick } from '@aztec/foundation/collection';
|
|
4
|
+
import { merge, pick, sum } from '@aztec/foundation/collection';
|
|
3
5
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
|
-
import { createLogger } from '@aztec/foundation/log';
|
|
6
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
5
7
|
import { bufferToHex } from '@aztec/foundation/string';
|
|
6
|
-
import { DateProvider,
|
|
7
|
-
import { getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
|
|
8
|
+
import { DateProvider, elapsed } from '@aztec/foundation/timer';
|
|
9
|
+
import { createTxValidatorForBlockBuilding, getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
|
|
8
10
|
import { LightweightCheckpointBuilder } from '@aztec/prover-client/light';
|
|
9
11
|
import {
|
|
10
12
|
GuardedMerkleTreeOperations,
|
|
@@ -12,39 +14,42 @@ import {
|
|
|
12
14
|
PublicProcessor,
|
|
13
15
|
createPublicTxSimulatorForBlockBuilding,
|
|
14
16
|
} from '@aztec/simulator/server';
|
|
15
|
-
import {
|
|
17
|
+
import { L2Block } from '@aztec/stdlib/block';
|
|
16
18
|
import { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
17
19
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
20
|
+
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
18
21
|
import { Gas } from '@aztec/stdlib/gas';
|
|
19
22
|
import {
|
|
23
|
+
type BlockBuilderOptions,
|
|
24
|
+
type BuildBlockInCheckpointResult,
|
|
20
25
|
type FullNodeBlockBuilderConfig,
|
|
21
26
|
FullNodeBlockBuilderConfigKeys,
|
|
27
|
+
type ICheckpointBlockBuilder,
|
|
28
|
+
type ICheckpointsBuilder,
|
|
29
|
+
InsufficientValidTxsError,
|
|
22
30
|
type MerkleTreeWriteOperations,
|
|
23
31
|
type PublicProcessorLimits,
|
|
32
|
+
type WorldStateSynchronizer,
|
|
24
33
|
} from '@aztec/stdlib/interfaces/server';
|
|
34
|
+
import { type DebugLogStore, NullDebugLogStore } from '@aztec/stdlib/logs';
|
|
25
35
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
26
|
-
import { type CheckpointGlobalVariables,
|
|
36
|
+
import { type CheckpointGlobalVariables, GlobalVariables, StateReference, Tx } from '@aztec/stdlib/tx';
|
|
27
37
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
38
|
+
import { ForkCheckpoint } from '@aztec/world-state';
|
|
28
39
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const log = createLogger('checkpoint-builder');
|
|
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
|
-
}
|
|
40
|
+
// Re-export for backward compatibility
|
|
41
|
+
export type { BuildBlockInCheckpointResult } from '@aztec/stdlib/interfaces/server';
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* Builder for a single checkpoint. Handles building blocks within the checkpoint
|
|
45
45
|
* and completing it.
|
|
46
46
|
*/
|
|
47
|
-
export class CheckpointBuilder {
|
|
47
|
+
export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
48
|
+
private log: Logger;
|
|
49
|
+
|
|
50
|
+
/** Persistent contracts DB shared across all blocks in this checkpoint. */
|
|
51
|
+
protected contractsDB: PublicContractsDB;
|
|
52
|
+
|
|
48
53
|
constructor(
|
|
49
54
|
private checkpointBuilder: LightweightCheckpointBuilder,
|
|
50
55
|
private fork: MerkleTreeWriteOperations,
|
|
@@ -52,7 +57,15 @@ export class CheckpointBuilder {
|
|
|
52
57
|
private contractDataSource: ContractDataSource,
|
|
53
58
|
private dateProvider: DateProvider,
|
|
54
59
|
private telemetryClient: TelemetryClient,
|
|
55
|
-
|
|
60
|
+
bindings?: LoggerBindings,
|
|
61
|
+
private debugLogStore: DebugLogStore = new NullDebugLogStore(),
|
|
62
|
+
) {
|
|
63
|
+
this.log = createLogger('checkpoint-builder', {
|
|
64
|
+
...bindings,
|
|
65
|
+
instanceId: `checkpoint-${checkpointBuilder.checkpointNumber}`,
|
|
66
|
+
});
|
|
67
|
+
this.contractsDB = new PublicContractsDB(this.contractDataSource, this.log.getBindings());
|
|
68
|
+
}
|
|
56
69
|
|
|
57
70
|
getConstantData(): CheckpointGlobalVariables {
|
|
58
71
|
return this.checkpointBuilder.constants;
|
|
@@ -60,17 +73,22 @@ export class CheckpointBuilder {
|
|
|
60
73
|
|
|
61
74
|
/**
|
|
62
75
|
* Builds a single block within this checkpoint.
|
|
76
|
+
* Automatically caps gas and blob field limits based on checkpoint-level budgets and prior blocks.
|
|
63
77
|
*/
|
|
64
78
|
async buildBlock(
|
|
65
79
|
pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
66
80
|
blockNumber: BlockNumber,
|
|
67
81
|
timestamp: bigint,
|
|
68
|
-
opts:
|
|
82
|
+
opts: BlockBuilderOptions & { expectedEndState?: StateReference },
|
|
69
83
|
): Promise<BuildBlockInCheckpointResult> {
|
|
70
|
-
const blockBuildingTimer = new Timer();
|
|
71
84
|
const slot = this.checkpointBuilder.constants.slotNumber;
|
|
72
85
|
|
|
73
|
-
log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
|
|
86
|
+
this.log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
|
|
87
|
+
slot,
|
|
88
|
+
blockNumber,
|
|
89
|
+
...opts,
|
|
90
|
+
currentTime: new Date(this.dateProvider.now()),
|
|
91
|
+
});
|
|
74
92
|
|
|
75
93
|
const constants = this.checkpointBuilder.constants;
|
|
76
94
|
const globalVariables = GlobalVariables.from({
|
|
@@ -85,36 +103,67 @@ export class CheckpointBuilder {
|
|
|
85
103
|
});
|
|
86
104
|
const { processor, validator } = await this.makeBlockBuilderDeps(globalVariables, this.fork);
|
|
87
105
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// Add block to checkpoint
|
|
93
|
-
const block = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
|
|
94
|
-
expectedEndState: opts.expectedEndState,
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// How much public gas was processed
|
|
98
|
-
const publicGas = processedTxs.reduce((acc, tx) => acc.add(tx.gasUsed.publicGas), Gas.empty());
|
|
99
|
-
|
|
100
|
-
const res = {
|
|
101
|
-
block,
|
|
102
|
-
publicGas,
|
|
103
|
-
publicProcessorDuration,
|
|
104
|
-
numTxs: processedTxs.length,
|
|
105
|
-
failedTxs,
|
|
106
|
-
blockBuildingTimer,
|
|
107
|
-
usedTxs,
|
|
106
|
+
// Cap gas limits amd available blob fields by remaining checkpoint-level budgets
|
|
107
|
+
const cappedOpts: PublicProcessorLimits & { expectedEndState?: StateReference } = {
|
|
108
|
+
...opts,
|
|
109
|
+
...this.capLimitsByCheckpointBudgets(opts),
|
|
108
110
|
};
|
|
109
|
-
|
|
110
|
-
|
|
111
|
+
|
|
112
|
+
// Create a block-level checkpoint on the contracts DB so we can roll back on failure
|
|
113
|
+
this.contractsDB.createCheckpoint();
|
|
114
|
+
// We execute all merkle tree operations on a world state fork checkpoint
|
|
115
|
+
// This enables us to discard all modifications in the event that we fail to successfully process sufficient transactions
|
|
116
|
+
const forkCheckpoint = await ForkCheckpoint.new(this.fork);
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs]] = await elapsed(() =>
|
|
120
|
+
processor.process(pendingTxs, cappedOpts, validator),
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// Throw before updating state if we don't have enough valid txs
|
|
124
|
+
const minValidTxs = opts.minValidTxs ?? 0;
|
|
125
|
+
if (processedTxs.length < minValidTxs) {
|
|
126
|
+
throw new InsufficientValidTxsError(processedTxs.length, minValidTxs, failedTxs);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Commit the fork checkpoint
|
|
130
|
+
await forkCheckpoint.commit();
|
|
131
|
+
|
|
132
|
+
// Add block to checkpoint
|
|
133
|
+
const { block } = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
|
|
134
|
+
expectedEndState: opts.expectedEndState,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
this.contractsDB.commitCheckpoint();
|
|
138
|
+
|
|
139
|
+
this.log.debug('Built block within checkpoint', {
|
|
140
|
+
header: block.header.toInspect(),
|
|
141
|
+
processedTxs: processedTxs.map(tx => tx.hash.toString()),
|
|
142
|
+
failedTxs: failedTxs.map(tx => tx.tx.txHash.toString()),
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
block,
|
|
147
|
+
publicProcessorDuration,
|
|
148
|
+
numTxs: processedTxs.length,
|
|
149
|
+
failedTxs,
|
|
150
|
+
usedTxs,
|
|
151
|
+
};
|
|
152
|
+
} catch (err) {
|
|
153
|
+
// Revert all changes to contracts db
|
|
154
|
+
this.contractsDB.revertCheckpoint();
|
|
155
|
+
// If we reached the point of committing the checkpoint, this does nothing
|
|
156
|
+
// Otherwise it reverts any changes made to the fork for this failed block
|
|
157
|
+
await forkCheckpoint.revert();
|
|
158
|
+
throw err;
|
|
159
|
+
}
|
|
111
160
|
}
|
|
112
161
|
|
|
113
162
|
/** Completes the checkpoint and returns it. */
|
|
114
163
|
async completeCheckpoint(): Promise<Checkpoint> {
|
|
115
164
|
const checkpoint = await this.checkpointBuilder.completeCheckpoint();
|
|
116
165
|
|
|
117
|
-
log.verbose(`Completed checkpoint ${checkpoint.number}`, {
|
|
166
|
+
this.log.verbose(`Completed checkpoint ${checkpoint.number}`, {
|
|
118
167
|
checkpointNumber: checkpoint.number,
|
|
119
168
|
numBlocks: checkpoint.blocks.length,
|
|
120
169
|
archiveRoot: checkpoint.archive.root.toString(),
|
|
@@ -128,16 +177,80 @@ export class CheckpointBuilder {
|
|
|
128
177
|
return this.checkpointBuilder.clone().completeCheckpoint();
|
|
129
178
|
}
|
|
130
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Caps per-block gas and blob field limits by remaining checkpoint-level budgets.
|
|
182
|
+
* When building a proposal (isBuildingProposal=true), computes a fair share of remaining budget
|
|
183
|
+
* across remaining blocks scaled by the multiplier. When validating, only caps by per-block limit
|
|
184
|
+
* and remaining checkpoint budget (no redistribution or multiplier).
|
|
185
|
+
*/
|
|
186
|
+
protected capLimitsByCheckpointBudgets(
|
|
187
|
+
opts: BlockBuilderOptions,
|
|
188
|
+
): Pick<PublicProcessorLimits, 'maxBlockGas' | 'maxBlobFields' | 'maxTransactions'> {
|
|
189
|
+
const existingBlocks = this.checkpointBuilder.getBlocks();
|
|
190
|
+
|
|
191
|
+
// Remaining L2 gas (mana)
|
|
192
|
+
// IMPORTANT: This assumes mana is computed solely based on L2 gas used in transactions.
|
|
193
|
+
// This may change in the future.
|
|
194
|
+
const usedMana = sum(existingBlocks.map(b => b.header.totalManaUsed.toNumber()));
|
|
195
|
+
const remainingMana = this.config.rollupManaLimit - usedMana;
|
|
196
|
+
|
|
197
|
+
// Remaining DA gas
|
|
198
|
+
const usedDAGas = sum(existingBlocks.map(b => b.computeDAGasUsed())) ?? 0;
|
|
199
|
+
const remainingDAGas = MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT - usedDAGas;
|
|
200
|
+
|
|
201
|
+
// Remaining blob fields (block blob fields include both tx data and block-end overhead)
|
|
202
|
+
const usedBlobFields = sum(existingBlocks.map(b => b.toBlobFields().length));
|
|
203
|
+
const totalBlobCapacity = BLOBS_PER_CHECKPOINT * FIELDS_PER_BLOB - NUM_CHECKPOINT_END_MARKER_FIELDS;
|
|
204
|
+
const isFirstBlock = existingBlocks.length === 0;
|
|
205
|
+
const blockEndOverhead = getNumBlockEndBlobFields(isFirstBlock);
|
|
206
|
+
const maxBlobFieldsForTxs = totalBlobCapacity - usedBlobFields - blockEndOverhead;
|
|
207
|
+
|
|
208
|
+
// Remaining txs
|
|
209
|
+
const usedTxs = sum(existingBlocks.map(b => b.body.txEffects.length));
|
|
210
|
+
const remainingTxs = Math.max(0, (this.config.maxTxsPerCheckpoint ?? Infinity) - usedTxs);
|
|
211
|
+
|
|
212
|
+
// Cap by per-block limit + remaining checkpoint budget
|
|
213
|
+
let cappedL2Gas = Math.min(opts.maxBlockGas?.l2Gas ?? Infinity, remainingMana);
|
|
214
|
+
let cappedDAGas = Math.min(opts.maxBlockGas?.daGas ?? Infinity, remainingDAGas);
|
|
215
|
+
let cappedBlobFields = Math.min(opts.maxBlobFields ?? Infinity, maxBlobFieldsForTxs);
|
|
216
|
+
let cappedMaxTransactions = Math.min(opts.maxTransactions ?? Infinity, remainingTxs);
|
|
217
|
+
|
|
218
|
+
// Proposer mode: further cap by fair share of remaining budget across remaining blocks
|
|
219
|
+
if (opts.isBuildingProposal) {
|
|
220
|
+
const remainingBlocks = Math.max(1, opts.maxBlocksPerCheckpoint - existingBlocks.length);
|
|
221
|
+
const multiplier = opts.perBlockAllocationMultiplier;
|
|
222
|
+
|
|
223
|
+
cappedL2Gas = Math.min(cappedL2Gas, Math.ceil((remainingMana / remainingBlocks) * multiplier));
|
|
224
|
+
cappedDAGas = Math.min(cappedDAGas, Math.ceil((remainingDAGas / remainingBlocks) * multiplier));
|
|
225
|
+
cappedBlobFields = Math.min(cappedBlobFields, Math.ceil((maxBlobFieldsForTxs / remainingBlocks) * multiplier));
|
|
226
|
+
cappedMaxTransactions = Math.min(cappedMaxTransactions, Math.ceil((remainingTxs / remainingBlocks) * multiplier));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
maxBlockGas: new Gas(cappedDAGas, cappedL2Gas),
|
|
231
|
+
maxBlobFields: cappedBlobFields,
|
|
232
|
+
maxTransactions: Number.isFinite(cappedMaxTransactions) ? cappedMaxTransactions : undefined,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
131
236
|
protected async makeBlockBuilderDeps(globalVariables: GlobalVariables, fork: MerkleTreeWriteOperations) {
|
|
132
|
-
const txPublicSetupAllowList =
|
|
133
|
-
|
|
237
|
+
const txPublicSetupAllowList = [
|
|
238
|
+
...(await getDefaultAllowedSetupFunctions()),
|
|
239
|
+
...(this.config.txPublicSetupAllowListExtend ?? []),
|
|
240
|
+
];
|
|
241
|
+
const contractsDB = this.contractsDB;
|
|
134
242
|
const guardedFork = new GuardedMerkleTreeOperations(fork);
|
|
135
243
|
|
|
244
|
+
const collectDebugLogs = this.debugLogStore.isEnabled;
|
|
245
|
+
|
|
246
|
+
const bindings = this.log.getBindings();
|
|
136
247
|
const publicTxSimulator = createPublicTxSimulatorForBlockBuilding(
|
|
137
248
|
guardedFork,
|
|
138
249
|
contractsDB,
|
|
139
250
|
globalVariables,
|
|
140
251
|
this.telemetryClient,
|
|
252
|
+
bindings,
|
|
253
|
+
collectDebugLogs,
|
|
141
254
|
);
|
|
142
255
|
|
|
143
256
|
const processor = new PublicProcessor(
|
|
@@ -147,15 +260,17 @@ export class CheckpointBuilder {
|
|
|
147
260
|
publicTxSimulator,
|
|
148
261
|
this.dateProvider,
|
|
149
262
|
this.telemetryClient,
|
|
150
|
-
|
|
263
|
+
createLogger('simulator:public-processor', bindings),
|
|
151
264
|
this.config,
|
|
265
|
+
this.debugLogStore,
|
|
152
266
|
);
|
|
153
267
|
|
|
154
|
-
const validator =
|
|
268
|
+
const validator = createTxValidatorForBlockBuilding(
|
|
155
269
|
fork,
|
|
156
270
|
this.contractDataSource,
|
|
157
271
|
globalVariables,
|
|
158
272
|
txPublicSetupAllowList,
|
|
273
|
+
this.log.getBindings(),
|
|
159
274
|
);
|
|
160
275
|
|
|
161
276
|
return {
|
|
@@ -165,16 +280,20 @@ export class CheckpointBuilder {
|
|
|
165
280
|
}
|
|
166
281
|
}
|
|
167
282
|
|
|
168
|
-
/**
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
283
|
+
/** Factory for creating checkpoint builders. */
|
|
284
|
+
export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
285
|
+
private log: Logger;
|
|
286
|
+
|
|
172
287
|
constructor(
|
|
173
|
-
private config: FullNodeBlockBuilderConfig,
|
|
288
|
+
private config: FullNodeBlockBuilderConfig & Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>,
|
|
289
|
+
private worldState: WorldStateSynchronizer,
|
|
174
290
|
private contractDataSource: ContractDataSource,
|
|
175
291
|
private dateProvider: DateProvider,
|
|
176
292
|
private telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
177
|
-
|
|
293
|
+
private debugLogStore: DebugLogStore = new NullDebugLogStore(),
|
|
294
|
+
) {
|
|
295
|
+
this.log = createLogger('checkpoint-builder');
|
|
296
|
+
}
|
|
178
297
|
|
|
179
298
|
public getConfig(): FullNodeBlockBuilderConfig {
|
|
180
299
|
return this.config;
|
|
@@ -190,25 +309,32 @@ export class FullNodeCheckpointsBuilder {
|
|
|
190
309
|
async startCheckpoint(
|
|
191
310
|
checkpointNumber: CheckpointNumber,
|
|
192
311
|
constants: CheckpointGlobalVariables,
|
|
312
|
+
feeAssetPriceModifier: bigint,
|
|
193
313
|
l1ToL2Messages: Fr[],
|
|
314
|
+
previousCheckpointOutHashes: Fr[],
|
|
194
315
|
fork: MerkleTreeWriteOperations,
|
|
316
|
+
bindings?: LoggerBindings,
|
|
195
317
|
): Promise<CheckpointBuilder> {
|
|
196
318
|
const stateReference = await fork.getStateReference();
|
|
197
319
|
const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
198
320
|
|
|
199
|
-
log.verbose(`Building new checkpoint ${checkpointNumber}`, {
|
|
321
|
+
this.log.verbose(`Building new checkpoint ${checkpointNumber}`, {
|
|
200
322
|
checkpointNumber,
|
|
201
323
|
msgCount: l1ToL2Messages.length,
|
|
202
324
|
initialStateReference: stateReference.toInspect(),
|
|
203
325
|
initialArchiveRoot: bufferToHex(archiveTree.root),
|
|
204
326
|
constants,
|
|
327
|
+
feeAssetPriceModifier,
|
|
205
328
|
});
|
|
206
329
|
|
|
207
330
|
const lightweightBuilder = await LightweightCheckpointBuilder.startNewCheckpoint(
|
|
208
331
|
checkpointNumber,
|
|
209
332
|
constants,
|
|
210
333
|
l1ToL2Messages,
|
|
334
|
+
previousCheckpointOutHashes,
|
|
211
335
|
fork,
|
|
336
|
+
bindings,
|
|
337
|
+
feeAssetPriceModifier,
|
|
212
338
|
);
|
|
213
339
|
|
|
214
340
|
return new CheckpointBuilder(
|
|
@@ -218,6 +344,8 @@ export class FullNodeCheckpointsBuilder {
|
|
|
218
344
|
this.contractDataSource,
|
|
219
345
|
this.dateProvider,
|
|
220
346
|
this.telemetryClient,
|
|
347
|
+
bindings,
|
|
348
|
+
this.debugLogStore,
|
|
221
349
|
);
|
|
222
350
|
}
|
|
223
351
|
|
|
@@ -227,32 +355,47 @@ export class FullNodeCheckpointsBuilder {
|
|
|
227
355
|
async openCheckpoint(
|
|
228
356
|
checkpointNumber: CheckpointNumber,
|
|
229
357
|
constants: CheckpointGlobalVariables,
|
|
358
|
+
feeAssetPriceModifier: bigint,
|
|
230
359
|
l1ToL2Messages: Fr[],
|
|
360
|
+
previousCheckpointOutHashes: Fr[],
|
|
231
361
|
fork: MerkleTreeWriteOperations,
|
|
232
|
-
existingBlocks:
|
|
362
|
+
existingBlocks: L2Block[] = [],
|
|
363
|
+
bindings?: LoggerBindings,
|
|
233
364
|
): Promise<CheckpointBuilder> {
|
|
234
365
|
const stateReference = await fork.getStateReference();
|
|
235
366
|
const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
236
367
|
|
|
237
368
|
if (existingBlocks.length === 0) {
|
|
238
|
-
return this.startCheckpoint(
|
|
369
|
+
return this.startCheckpoint(
|
|
370
|
+
checkpointNumber,
|
|
371
|
+
constants,
|
|
372
|
+
feeAssetPriceModifier,
|
|
373
|
+
l1ToL2Messages,
|
|
374
|
+
previousCheckpointOutHashes,
|
|
375
|
+
fork,
|
|
376
|
+
bindings,
|
|
377
|
+
);
|
|
239
378
|
}
|
|
240
379
|
|
|
241
|
-
log.verbose(`Resuming checkpoint ${checkpointNumber} with ${existingBlocks.length} existing blocks`, {
|
|
380
|
+
this.log.verbose(`Resuming checkpoint ${checkpointNumber} with ${existingBlocks.length} existing blocks`, {
|
|
242
381
|
checkpointNumber,
|
|
243
382
|
msgCount: l1ToL2Messages.length,
|
|
244
383
|
existingBlockCount: existingBlocks.length,
|
|
245
384
|
initialStateReference: stateReference.toInspect(),
|
|
246
385
|
initialArchiveRoot: bufferToHex(archiveTree.root),
|
|
247
386
|
constants,
|
|
387
|
+
feeAssetPriceModifier,
|
|
248
388
|
});
|
|
249
389
|
|
|
250
390
|
const lightweightBuilder = await LightweightCheckpointBuilder.resumeCheckpoint(
|
|
251
391
|
checkpointNumber,
|
|
252
392
|
constants,
|
|
393
|
+
feeAssetPriceModifier,
|
|
253
394
|
l1ToL2Messages,
|
|
395
|
+
previousCheckpointOutHashes,
|
|
254
396
|
fork,
|
|
255
397
|
existingBlocks,
|
|
398
|
+
bindings,
|
|
256
399
|
);
|
|
257
400
|
|
|
258
401
|
return new CheckpointBuilder(
|
|
@@ -262,6 +405,13 @@ export class FullNodeCheckpointsBuilder {
|
|
|
262
405
|
this.contractDataSource,
|
|
263
406
|
this.dateProvider,
|
|
264
407
|
this.telemetryClient,
|
|
408
|
+
bindings,
|
|
409
|
+
this.debugLogStore,
|
|
265
410
|
);
|
|
266
411
|
}
|
|
412
|
+
|
|
413
|
+
/** Returns a fork of the world state at the given block number. */
|
|
414
|
+
getFork(blockNumber: BlockNumber): Promise<MerkleTreeWriteOperations> {
|
|
415
|
+
return this.worldState.fork(blockNumber);
|
|
416
|
+
}
|
|
267
417
|
}
|
package/src/config.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
secretValueConfigHelper,
|
|
7
7
|
} from '@aztec/foundation/config';
|
|
8
8
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
9
|
+
import { localSignerConfigMappings, validatorHASignerConfigMappings } from '@aztec/stdlib/ha-signing';
|
|
9
10
|
import type { ValidatorClientConfig } from '@aztec/stdlib/interfaces/server';
|
|
10
11
|
|
|
11
12
|
export type { ValidatorClientConfig };
|
|
@@ -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,40 @@ 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),
|
|
79
|
+
},
|
|
80
|
+
validateMaxL2BlockGas: {
|
|
81
|
+
env: 'VALIDATOR_MAX_L2_BLOCK_GAS',
|
|
82
|
+
description: 'Maximum L2 block gas for validation. Proposals exceeding this limit are rejected.',
|
|
83
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
84
|
+
},
|
|
85
|
+
validateMaxDABlockGas: {
|
|
86
|
+
env: 'VALIDATOR_MAX_DA_BLOCK_GAS',
|
|
87
|
+
description: 'Maximum DA block gas for validation. Proposals exceeding this limit are rejected.',
|
|
88
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
89
|
+
},
|
|
90
|
+
validateMaxTxsPerBlock: {
|
|
91
|
+
env: 'VALIDATOR_MAX_TX_PER_BLOCK',
|
|
92
|
+
description: 'Maximum transactions per block for validation. Proposals exceeding this limit are rejected.',
|
|
93
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
94
|
+
},
|
|
95
|
+
validateMaxTxsPerCheckpoint: {
|
|
96
|
+
env: 'VALIDATOR_MAX_TX_PER_CHECKPOINT',
|
|
97
|
+
description: 'Maximum transactions per checkpoint for validation. Proposals exceeding this limit are rejected.',
|
|
98
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
82
99
|
},
|
|
100
|
+
...localSignerConfigMappings,
|
|
101
|
+
...validatorHASignerConfigMappings,
|
|
83
102
|
};
|
|
84
103
|
|
|
85
104
|
/**
|