@aztec/validator-client 0.0.1-commit.f295ac2 → 0.0.1-commit.fc805bf
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 +1 -1
- package/dest/block_proposal_handler.d.ts +5 -7
- package/dest/block_proposal_handler.d.ts.map +1 -1
- package/dest/block_proposal_handler.js +17 -32
- package/dest/checkpoint_builder.d.ts +11 -12
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +38 -25
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +4 -6
- 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 +7 -8
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +21 -27
- package/package.json +19 -17
- package/src/block_proposal_handler.ts +25 -46
- package/src/checkpoint_builder.ts +57 -27
- package/src/config.ts +4 -6
- package/src/metrics.ts +45 -6
- package/src/tx_validator/tx_validator_factory.ts +52 -31
- package/src/validator.ts +22 -33
|
@@ -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,7 +12,7 @@ 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
18
|
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
type ICheckpointBlockBuilder,
|
|
25
25
|
type ICheckpointsBuilder,
|
|
26
26
|
type MerkleTreeWriteOperations,
|
|
27
|
+
NoValidTxsError,
|
|
27
28
|
type PublicProcessorLimits,
|
|
28
29
|
type WorldStateSynchronizer,
|
|
29
30
|
} from '@aztec/stdlib/interfaces/server';
|
|
@@ -36,18 +37,13 @@ import { createValidatorForBlockBuilding } from './tx_validator/tx_validator_fac
|
|
|
36
37
|
// Re-export for backward compatibility
|
|
37
38
|
export type { BuildBlockInCheckpointResult } from '@aztec/stdlib/interfaces/server';
|
|
38
39
|
|
|
39
|
-
const log = createLogger('checkpoint-builder');
|
|
40
|
-
|
|
41
|
-
/** Result of building a block within a checkpoint. Extends the base interface with timer. */
|
|
42
|
-
export interface BuildBlockInCheckpointResultWithTimer extends BuildBlockInCheckpointResult {
|
|
43
|
-
blockBuildingTimer: Timer;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
40
|
/**
|
|
47
41
|
* Builder for a single checkpoint. Handles building blocks within the checkpoint
|
|
48
42
|
* and completing it.
|
|
49
43
|
*/
|
|
50
44
|
export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
45
|
+
private log: Logger;
|
|
46
|
+
|
|
51
47
|
constructor(
|
|
52
48
|
private checkpointBuilder: LightweightCheckpointBuilder,
|
|
53
49
|
private fork: MerkleTreeWriteOperations,
|
|
@@ -55,7 +51,13 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
55
51
|
private contractDataSource: ContractDataSource,
|
|
56
52
|
private dateProvider: DateProvider,
|
|
57
53
|
private telemetryClient: TelemetryClient,
|
|
58
|
-
|
|
54
|
+
bindings?: LoggerBindings,
|
|
55
|
+
) {
|
|
56
|
+
this.log = createLogger('checkpoint-builder', {
|
|
57
|
+
...bindings,
|
|
58
|
+
instanceId: `checkpoint-${checkpointBuilder.checkpointNumber}`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
59
61
|
|
|
60
62
|
getConstantData(): CheckpointGlobalVariables {
|
|
61
63
|
return this.checkpointBuilder.constants;
|
|
@@ -68,12 +70,11 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
68
70
|
pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
69
71
|
blockNumber: BlockNumber,
|
|
70
72
|
timestamp: bigint,
|
|
71
|
-
opts: PublicProcessorLimits & { expectedEndState?: StateReference },
|
|
72
|
-
): Promise<
|
|
73
|
-
const blockBuildingTimer = new Timer();
|
|
73
|
+
opts: PublicProcessorLimits & { expectedEndState?: StateReference } = {},
|
|
74
|
+
): Promise<BuildBlockInCheckpointResult> {
|
|
74
75
|
const slot = this.checkpointBuilder.constants.slotNumber;
|
|
75
76
|
|
|
76
|
-
log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
|
|
77
|
+
this.log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
|
|
77
78
|
slot,
|
|
78
79
|
blockNumber,
|
|
79
80
|
...opts,
|
|
@@ -97,6 +98,12 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
97
98
|
processor.process(pendingTxs, opts, validator),
|
|
98
99
|
);
|
|
99
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
|
+
|
|
100
107
|
// Add block to checkpoint
|
|
101
108
|
const block = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
|
|
102
109
|
expectedEndState: opts.expectedEndState,
|
|
@@ -105,25 +112,28 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
105
112
|
// How much public gas was processed
|
|
106
113
|
const publicGas = processedTxs.reduce((acc, tx) => acc.add(tx.gasUsed.publicGas), Gas.empty());
|
|
107
114
|
|
|
108
|
-
|
|
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 {
|
|
109
122
|
block,
|
|
110
123
|
publicGas,
|
|
111
124
|
publicProcessorDuration,
|
|
112
125
|
numTxs: processedTxs.length,
|
|
113
126
|
failedTxs,
|
|
114
|
-
blockBuildingTimer,
|
|
115
127
|
usedTxs,
|
|
116
128
|
usedTxBlobFields,
|
|
117
129
|
};
|
|
118
|
-
log.debug('Built block within checkpoint', res.block.header);
|
|
119
|
-
return res;
|
|
120
130
|
}
|
|
121
131
|
|
|
122
132
|
/** Completes the checkpoint and returns it. */
|
|
123
133
|
async completeCheckpoint(): Promise<Checkpoint> {
|
|
124
134
|
const checkpoint = await this.checkpointBuilder.completeCheckpoint();
|
|
125
135
|
|
|
126
|
-
log.verbose(`Completed checkpoint ${checkpoint.number}`, {
|
|
136
|
+
this.log.verbose(`Completed checkpoint ${checkpoint.number}`, {
|
|
127
137
|
checkpointNumber: checkpoint.number,
|
|
128
138
|
numBlocks: checkpoint.blocks.length,
|
|
129
139
|
archiveRoot: checkpoint.archive.root.toString(),
|
|
@@ -139,14 +149,16 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
139
149
|
|
|
140
150
|
protected async makeBlockBuilderDeps(globalVariables: GlobalVariables, fork: MerkleTreeWriteOperations) {
|
|
141
151
|
const txPublicSetupAllowList = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
|
|
142
|
-
const contractsDB = new PublicContractsDB(this.contractDataSource);
|
|
152
|
+
const contractsDB = new PublicContractsDB(this.contractDataSource, this.log.getBindings());
|
|
143
153
|
const guardedFork = new GuardedMerkleTreeOperations(fork);
|
|
144
154
|
|
|
155
|
+
const bindings = this.log.getBindings();
|
|
145
156
|
const publicTxSimulator = createPublicTxSimulatorForBlockBuilding(
|
|
146
157
|
guardedFork,
|
|
147
158
|
contractsDB,
|
|
148
159
|
globalVariables,
|
|
149
160
|
this.telemetryClient,
|
|
161
|
+
bindings,
|
|
150
162
|
);
|
|
151
163
|
|
|
152
164
|
const processor = new PublicProcessor(
|
|
@@ -156,7 +168,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
156
168
|
publicTxSimulator,
|
|
157
169
|
this.dateProvider,
|
|
158
170
|
this.telemetryClient,
|
|
159
|
-
|
|
171
|
+
createLogger('simulator:public-processor', bindings),
|
|
160
172
|
this.config,
|
|
161
173
|
);
|
|
162
174
|
|
|
@@ -165,6 +177,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
165
177
|
this.contractDataSource,
|
|
166
178
|
globalVariables,
|
|
167
179
|
txPublicSetupAllowList,
|
|
180
|
+
this.log.getBindings(),
|
|
168
181
|
);
|
|
169
182
|
|
|
170
183
|
return {
|
|
@@ -176,13 +189,17 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
176
189
|
|
|
177
190
|
/** Factory for creating checkpoint builders. */
|
|
178
191
|
export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
192
|
+
private log: Logger;
|
|
193
|
+
|
|
179
194
|
constructor(
|
|
180
195
|
private config: FullNodeBlockBuilderConfig & Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>,
|
|
181
196
|
private worldState: WorldStateSynchronizer,
|
|
182
197
|
private contractDataSource: ContractDataSource,
|
|
183
198
|
private dateProvider: DateProvider,
|
|
184
199
|
private telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
185
|
-
) {
|
|
200
|
+
) {
|
|
201
|
+
this.log = createLogger('checkpoint-builder');
|
|
202
|
+
}
|
|
186
203
|
|
|
187
204
|
public getConfig(): FullNodeBlockBuilderConfig {
|
|
188
205
|
return this.config;
|
|
@@ -201,11 +218,12 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
201
218
|
l1ToL2Messages: Fr[],
|
|
202
219
|
previousCheckpointOutHashes: Fr[],
|
|
203
220
|
fork: MerkleTreeWriteOperations,
|
|
221
|
+
bindings?: LoggerBindings,
|
|
204
222
|
): Promise<CheckpointBuilder> {
|
|
205
223
|
const stateReference = await fork.getStateReference();
|
|
206
224
|
const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
207
225
|
|
|
208
|
-
log.verbose(`Building new checkpoint ${checkpointNumber}`, {
|
|
226
|
+
this.log.verbose(`Building new checkpoint ${checkpointNumber}`, {
|
|
209
227
|
checkpointNumber,
|
|
210
228
|
msgCount: l1ToL2Messages.length,
|
|
211
229
|
initialStateReference: stateReference.toInspect(),
|
|
@@ -219,6 +237,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
219
237
|
l1ToL2Messages,
|
|
220
238
|
previousCheckpointOutHashes,
|
|
221
239
|
fork,
|
|
240
|
+
bindings,
|
|
222
241
|
);
|
|
223
242
|
|
|
224
243
|
return new CheckpointBuilder(
|
|
@@ -228,6 +247,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
228
247
|
this.contractDataSource,
|
|
229
248
|
this.dateProvider,
|
|
230
249
|
this.telemetryClient,
|
|
250
|
+
bindings,
|
|
231
251
|
);
|
|
232
252
|
}
|
|
233
253
|
|
|
@@ -240,16 +260,24 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
240
260
|
l1ToL2Messages: Fr[],
|
|
241
261
|
previousCheckpointOutHashes: Fr[],
|
|
242
262
|
fork: MerkleTreeWriteOperations,
|
|
243
|
-
existingBlocks:
|
|
263
|
+
existingBlocks: L2Block[] = [],
|
|
264
|
+
bindings?: LoggerBindings,
|
|
244
265
|
): Promise<CheckpointBuilder> {
|
|
245
266
|
const stateReference = await fork.getStateReference();
|
|
246
267
|
const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
247
268
|
|
|
248
269
|
if (existingBlocks.length === 0) {
|
|
249
|
-
return this.startCheckpoint(
|
|
270
|
+
return this.startCheckpoint(
|
|
271
|
+
checkpointNumber,
|
|
272
|
+
constants,
|
|
273
|
+
l1ToL2Messages,
|
|
274
|
+
previousCheckpointOutHashes,
|
|
275
|
+
fork,
|
|
276
|
+
bindings,
|
|
277
|
+
);
|
|
250
278
|
}
|
|
251
279
|
|
|
252
|
-
log.verbose(`Resuming checkpoint ${checkpointNumber} with ${existingBlocks.length} existing blocks`, {
|
|
280
|
+
this.log.verbose(`Resuming checkpoint ${checkpointNumber} with ${existingBlocks.length} existing blocks`, {
|
|
253
281
|
checkpointNumber,
|
|
254
282
|
msgCount: l1ToL2Messages.length,
|
|
255
283
|
existingBlockCount: existingBlocks.length,
|
|
@@ -265,6 +293,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
265
293
|
previousCheckpointOutHashes,
|
|
266
294
|
fork,
|
|
267
295
|
existingBlocks,
|
|
296
|
+
bindings,
|
|
268
297
|
);
|
|
269
298
|
|
|
270
299
|
return new CheckpointBuilder(
|
|
@@ -274,6 +303,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
274
303
|
this.contractDataSource,
|
|
275
304
|
this.dateProvider,
|
|
276
305
|
this.telemetryClient,
|
|
306
|
+
bindings,
|
|
277
307
|
);
|
|
278
308
|
}
|
|
279
309
|
|
package/src/config.ts
CHANGED
|
@@ -65,15 +65,13 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
|
|
|
65
65
|
'Whether to run in fisherman mode: validates all proposals and attestations but does not broadcast attestations or participate in consensus.',
|
|
66
66
|
...booleanConfigHelper(false),
|
|
67
67
|
},
|
|
68
|
-
// TODO(palla/mbps): Change default to false once checkpoint validation is stable
|
|
69
68
|
skipCheckpointProposalValidation: {
|
|
70
|
-
description: 'Skip checkpoint proposal validation and always attest (default:
|
|
71
|
-
defaultValue:
|
|
69
|
+
description: 'Skip checkpoint proposal validation and always attest (default: false)',
|
|
70
|
+
defaultValue: false,
|
|
72
71
|
},
|
|
73
|
-
// TODO(palla/mbps): Change default to false once block sync is stable
|
|
74
72
|
skipPushProposedBlocksToArchiver: {
|
|
75
|
-
description: 'Skip pushing re-executed blocks to archiver (default:
|
|
76
|
-
defaultValue:
|
|
73
|
+
description: 'Skip pushing re-executed blocks to archiver (default: false)',
|
|
74
|
+
defaultValue: false,
|
|
77
75
|
},
|
|
78
76
|
...validatorHASignerConfigMappings,
|
|
79
77
|
};
|
package/src/metrics.ts
CHANGED
|
@@ -6,8 +6,11 @@ import {
|
|
|
6
6
|
Metrics,
|
|
7
7
|
type TelemetryClient,
|
|
8
8
|
type UpDownCounter,
|
|
9
|
+
createUpDownCounterWithDefault,
|
|
9
10
|
} from '@aztec/telemetry-client';
|
|
10
11
|
|
|
12
|
+
import type { BlockProposalValidationFailureReason } from './block_proposal_handler.js';
|
|
13
|
+
|
|
11
14
|
export class ValidatorMetrics {
|
|
12
15
|
private failedReexecutionCounter: UpDownCounter;
|
|
13
16
|
private successfulAttestationsCount: UpDownCounter;
|
|
@@ -21,16 +24,44 @@ export class ValidatorMetrics {
|
|
|
21
24
|
constructor(telemetryClient: TelemetryClient) {
|
|
22
25
|
const meter = telemetryClient.getMeter('Validator');
|
|
23
26
|
|
|
24
|
-
this.failedReexecutionCounter = meter
|
|
27
|
+
this.failedReexecutionCounter = createUpDownCounterWithDefault(meter, Metrics.VALIDATOR_FAILED_REEXECUTION_COUNT, {
|
|
28
|
+
[Attributes.STATUS]: ['failed'],
|
|
29
|
+
});
|
|
25
30
|
|
|
26
|
-
this.successfulAttestationsCount =
|
|
31
|
+
this.successfulAttestationsCount = createUpDownCounterWithDefault(
|
|
32
|
+
meter,
|
|
33
|
+
Metrics.VALIDATOR_ATTESTATION_SUCCESS_COUNT,
|
|
34
|
+
);
|
|
27
35
|
|
|
28
|
-
this.failedAttestationsBadProposalCount =
|
|
36
|
+
this.failedAttestationsBadProposalCount = createUpDownCounterWithDefault(
|
|
37
|
+
meter,
|
|
29
38
|
Metrics.VALIDATOR_ATTESTATION_FAILED_BAD_PROPOSAL_COUNT,
|
|
39
|
+
{
|
|
40
|
+
[Attributes.ERROR_TYPE]: [
|
|
41
|
+
'invalid_proposal',
|
|
42
|
+
'state_mismatch',
|
|
43
|
+
'failed_txs',
|
|
44
|
+
'in_hash_mismatch',
|
|
45
|
+
'parent_block_wrong_slot',
|
|
46
|
+
],
|
|
47
|
+
[Attributes.IS_COMMITTEE_MEMBER]: [true, false],
|
|
48
|
+
},
|
|
30
49
|
);
|
|
31
50
|
|
|
32
|
-
this.failedAttestationsNodeIssueCount =
|
|
51
|
+
this.failedAttestationsNodeIssueCount = createUpDownCounterWithDefault(
|
|
52
|
+
meter,
|
|
33
53
|
Metrics.VALIDATOR_ATTESTATION_FAILED_NODE_ISSUE_COUNT,
|
|
54
|
+
{
|
|
55
|
+
[Attributes.ERROR_TYPE]: [
|
|
56
|
+
'parent_block_not_found',
|
|
57
|
+
'global_variables_mismatch',
|
|
58
|
+
'block_number_already_exists',
|
|
59
|
+
'txs_not_available',
|
|
60
|
+
'timeout',
|
|
61
|
+
'unknown_error',
|
|
62
|
+
],
|
|
63
|
+
[Attributes.IS_COMMITTEE_MEMBER]: [true, false],
|
|
64
|
+
},
|
|
34
65
|
);
|
|
35
66
|
|
|
36
67
|
this.reexMana = meter.createHistogram(Metrics.VALIDATOR_RE_EXECUTION_MANA);
|
|
@@ -58,14 +89,22 @@ export class ValidatorMetrics {
|
|
|
58
89
|
this.successfulAttestationsCount.add(num);
|
|
59
90
|
}
|
|
60
91
|
|
|
61
|
-
public incFailedAttestationsBadProposal(
|
|
92
|
+
public incFailedAttestationsBadProposal(
|
|
93
|
+
num: number,
|
|
94
|
+
reason: BlockProposalValidationFailureReason,
|
|
95
|
+
inCommittee: boolean,
|
|
96
|
+
) {
|
|
62
97
|
this.failedAttestationsBadProposalCount.add(num, {
|
|
63
98
|
[Attributes.ERROR_TYPE]: reason,
|
|
64
99
|
[Attributes.IS_COMMITTEE_MEMBER]: inCommittee,
|
|
65
100
|
});
|
|
66
101
|
}
|
|
67
102
|
|
|
68
|
-
public incFailedAttestationsNodeIssue(
|
|
103
|
+
public incFailedAttestationsNodeIssue(
|
|
104
|
+
num: number,
|
|
105
|
+
reason: BlockProposalValidationFailureReason,
|
|
106
|
+
inCommittee: boolean,
|
|
107
|
+
) {
|
|
69
108
|
this.failedAttestationsNodeIssueCount.add(num, {
|
|
70
109
|
[Attributes.ERROR_TYPE]: reason,
|
|
71
110
|
[Attributes.IS_COMMITTEE_MEMBER]: inCommittee,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
|
+
import type { LoggerBindings } from '@aztec/foundation/log';
|
|
3
4
|
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
4
5
|
import {
|
|
5
6
|
AggregateTxValidator,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
GasTxValidator,
|
|
11
12
|
MetadataTxValidator,
|
|
12
13
|
PhasesTxValidator,
|
|
14
|
+
SizeTxValidator,
|
|
13
15
|
TimestampTxValidator,
|
|
14
16
|
TxPermittedValidator,
|
|
15
17
|
TxProofValidator,
|
|
@@ -52,31 +54,41 @@ export function createValidatorForAcceptingTxs(
|
|
|
52
54
|
blockNumber: BlockNumber;
|
|
53
55
|
txsPermitted: boolean;
|
|
54
56
|
},
|
|
57
|
+
bindings?: LoggerBindings,
|
|
55
58
|
): TxValidator<Tx> {
|
|
56
59
|
const validators: TxValidator<Tx>[] = [
|
|
57
|
-
new TxPermittedValidator(txsPermitted),
|
|
58
|
-
new
|
|
59
|
-
new
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
new
|
|
70
|
-
|
|
71
|
-
|
|
60
|
+
new TxPermittedValidator(txsPermitted, bindings),
|
|
61
|
+
new SizeTxValidator(bindings),
|
|
62
|
+
new DataTxValidator(bindings),
|
|
63
|
+
new MetadataTxValidator(
|
|
64
|
+
{
|
|
65
|
+
l1ChainId: new Fr(l1ChainId),
|
|
66
|
+
rollupVersion: new Fr(rollupVersion),
|
|
67
|
+
protocolContractsHash,
|
|
68
|
+
vkTreeRoot: getVKTreeRoot(),
|
|
69
|
+
},
|
|
70
|
+
bindings,
|
|
71
|
+
),
|
|
72
|
+
new TimestampTxValidator(
|
|
73
|
+
{
|
|
74
|
+
timestamp,
|
|
75
|
+
blockNumber,
|
|
76
|
+
},
|
|
77
|
+
bindings,
|
|
78
|
+
),
|
|
79
|
+
new DoubleSpendTxValidator(new NullifierCache(db), bindings),
|
|
80
|
+
new PhasesTxValidator(contractDataSource, setupAllowList, timestamp, bindings),
|
|
81
|
+
new BlockHeaderTxValidator(new ArchiveCache(db), bindings),
|
|
72
82
|
];
|
|
73
83
|
|
|
74
84
|
if (!skipFeeEnforcement) {
|
|
75
|
-
validators.push(
|
|
85
|
+
validators.push(
|
|
86
|
+
new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, gasFees, bindings),
|
|
87
|
+
);
|
|
76
88
|
}
|
|
77
89
|
|
|
78
90
|
if (verifier) {
|
|
79
|
-
validators.push(new TxProofValidator(verifier));
|
|
91
|
+
validators.push(new TxProofValidator(verifier, bindings));
|
|
80
92
|
}
|
|
81
93
|
|
|
82
94
|
return new AggregateTxValidator(...validators);
|
|
@@ -87,6 +99,7 @@ export function createValidatorForBlockBuilding(
|
|
|
87
99
|
contractDataSource: ContractDataSource,
|
|
88
100
|
globalVariables: GlobalVariables,
|
|
89
101
|
setupAllowList: AllowedElement[],
|
|
102
|
+
bindings?: LoggerBindings,
|
|
90
103
|
): PublicProcessorValidator {
|
|
91
104
|
const nullifierCache = new NullifierCache(db);
|
|
92
105
|
const archiveCache = new ArchiveCache(db);
|
|
@@ -100,6 +113,7 @@ export function createValidatorForBlockBuilding(
|
|
|
100
113
|
contractDataSource,
|
|
101
114
|
globalVariables,
|
|
102
115
|
setupAllowList,
|
|
116
|
+
bindings,
|
|
103
117
|
),
|
|
104
118
|
nullifierCache,
|
|
105
119
|
};
|
|
@@ -112,22 +126,29 @@ function preprocessValidator(
|
|
|
112
126
|
contractDataSource: ContractDataSource,
|
|
113
127
|
globalVariables: GlobalVariables,
|
|
114
128
|
setupAllowList: AllowedElement[],
|
|
129
|
+
bindings?: LoggerBindings,
|
|
115
130
|
): TxValidator<Tx> {
|
|
116
131
|
// We don't include the TxProofValidator nor the DataTxValidator here because they are already checked by the time we get to block building.
|
|
117
132
|
return new AggregateTxValidator(
|
|
118
|
-
new MetadataTxValidator(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
133
|
+
new MetadataTxValidator(
|
|
134
|
+
{
|
|
135
|
+
l1ChainId: globalVariables.chainId,
|
|
136
|
+
rollupVersion: globalVariables.version,
|
|
137
|
+
protocolContractsHash,
|
|
138
|
+
vkTreeRoot: getVKTreeRoot(),
|
|
139
|
+
},
|
|
140
|
+
bindings,
|
|
141
|
+
),
|
|
142
|
+
new TimestampTxValidator(
|
|
143
|
+
{
|
|
144
|
+
timestamp: globalVariables.timestamp,
|
|
145
|
+
blockNumber: globalVariables.blockNumber,
|
|
146
|
+
},
|
|
147
|
+
bindings,
|
|
148
|
+
),
|
|
149
|
+
new DoubleSpendTxValidator(nullifierCache, bindings),
|
|
150
|
+
new PhasesTxValidator(contractDataSource, setupAllowList, globalVariables.timestamp, bindings),
|
|
151
|
+
new GasTxValidator(publicStateSource, ProtocolContractAddress.FeeJuice, globalVariables.gasFees, bindings),
|
|
152
|
+
new BlockHeaderTxValidator(archiveCache, bindings),
|
|
132
153
|
);
|
|
133
154
|
}
|
package/src/validator.ts
CHANGED
|
@@ -18,19 +18,20 @@ import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
|
18
18
|
import { sleep } from '@aztec/foundation/sleep';
|
|
19
19
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
20
20
|
import type { KeystoreManager } from '@aztec/node-keystore';
|
|
21
|
-
import type { P2P, PeerId
|
|
21
|
+
import type { P2P, PeerId } from '@aztec/p2p';
|
|
22
22
|
import { AuthRequest, AuthResponse, BlockProposalValidator, ReqRespSubProtocol } from '@aztec/p2p';
|
|
23
23
|
import { OffenseType, WANT_TO_SLASH_EVENT, type Watcher, type WatcherEmitter } from '@aztec/slasher';
|
|
24
24
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
25
|
-
import type { CommitteeAttestationsAndSigners,
|
|
25
|
+
import type { CommitteeAttestationsAndSigners, L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
26
26
|
import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
|
|
27
27
|
import type {
|
|
28
28
|
CreateCheckpointProposalLastBlockData,
|
|
29
|
+
ITxProvider,
|
|
29
30
|
Validator,
|
|
30
31
|
ValidatorClientFullConfig,
|
|
31
32
|
WorldStateSynchronizer,
|
|
32
33
|
} from '@aztec/stdlib/interfaces/server';
|
|
33
|
-
import type
|
|
34
|
+
import { type L1ToL2MessageSource, accumulateCheckpointOutHashes } from '@aztec/stdlib/messaging';
|
|
34
35
|
import type {
|
|
35
36
|
BlockProposal,
|
|
36
37
|
BlockProposalOptions,
|
|
@@ -87,11 +88,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
87
88
|
|
|
88
89
|
private proposersOfInvalidBlocks: Set<string> = new Set();
|
|
89
90
|
|
|
90
|
-
// TODO(palla/mbps): Remove this once checkpoint validation is stable and we can validate all blocks properly.
|
|
91
|
-
// Tracks slots for which we have successfully validated a block proposal, so we can attest to checkpoint proposals for those slots.
|
|
92
|
-
// eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
|
|
93
|
-
private validatedBlockSlots: Set<SlotNumber> = new Set();
|
|
94
|
-
|
|
95
91
|
protected constructor(
|
|
96
92
|
private keyStore: ExtendedValidatorKeyStore,
|
|
97
93
|
private epochCache: EpochCache,
|
|
@@ -184,7 +180,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
184
180
|
p2pClient: P2P,
|
|
185
181
|
blockSource: L2BlockSource & L2BlockSink,
|
|
186
182
|
l1ToL2MessageSource: L1ToL2MessageSource,
|
|
187
|
-
txProvider:
|
|
183
|
+
txProvider: ITxProvider,
|
|
188
184
|
keyStoreManager: KeystoreManager,
|
|
189
185
|
blobClient: BlobClientInterface,
|
|
190
186
|
dateProvider: DateProvider = new DateProvider(),
|
|
@@ -413,10 +409,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
413
409
|
return false;
|
|
414
410
|
}
|
|
415
411
|
|
|
416
|
-
// TODO(palla/mbps): Remove this once checkpoint validation is stable.
|
|
417
|
-
// Track that we successfully validated a block for this slot, so we can attest to checkpoint proposals for it.
|
|
418
|
-
this.validatedBlockSlots.add(slotNumber);
|
|
419
|
-
|
|
420
412
|
return true;
|
|
421
413
|
}
|
|
422
414
|
|
|
@@ -461,17 +453,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
461
453
|
fishermanMode: this.config.fishermanMode || false,
|
|
462
454
|
});
|
|
463
455
|
|
|
464
|
-
// TODO(palla/mbps): Remove this once checkpoint validation is stable.
|
|
465
|
-
// Check that we have successfully validated a block for this slot before attesting to the checkpoint.
|
|
466
|
-
if (!this.validatedBlockSlots.has(slotNumber)) {
|
|
467
|
-
this.log.warn(`No validated block found for slot ${slotNumber}, refusing to attest to checkpoint`, proposalInfo);
|
|
468
|
-
return undefined;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
456
|
// Validate the checkpoint proposal before attesting (unless skipCheckpointProposalValidation is set)
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
this.log.verbose(`Skipping checkpoint proposal validation for slot ${slotNumber}`, proposalInfo);
|
|
457
|
+
if (this.config.skipCheckpointProposalValidation) {
|
|
458
|
+
this.log.warn(`Skipping checkpoint proposal validation for slot ${slotNumber}`, proposalInfo);
|
|
475
459
|
} else {
|
|
476
460
|
const validationResult = await this.validateCheckpointProposal(proposal, proposalInfo);
|
|
477
461
|
if (!validationResult.isValid) {
|
|
@@ -547,7 +531,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
547
531
|
proposalInfo: LogData,
|
|
548
532
|
): Promise<{ isValid: true } | { isValid: false; reason: string }> {
|
|
549
533
|
const slot = proposal.slotNumber;
|
|
550
|
-
const timeoutSeconds = 10;
|
|
534
|
+
const timeoutSeconds = 10; // TODO(palla/mbps): This should map to the timetable settings
|
|
551
535
|
|
|
552
536
|
// Wait for last block to sync by archive
|
|
553
537
|
let lastBlockHeader: BlockHeader | undefined;
|
|
@@ -617,6 +601,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
617
601
|
previousCheckpointOutHashes,
|
|
618
602
|
fork,
|
|
619
603
|
blocks,
|
|
604
|
+
this.log.getBindings(),
|
|
620
605
|
);
|
|
621
606
|
|
|
622
607
|
// Complete the checkpoint to get computed values
|
|
@@ -642,13 +627,17 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
642
627
|
return { isValid: false, reason: 'archive_mismatch' };
|
|
643
628
|
}
|
|
644
629
|
|
|
645
|
-
// Check that the accumulated out hash matches the value in the proposal.
|
|
646
|
-
|
|
647
|
-
const
|
|
648
|
-
|
|
630
|
+
// Check that the accumulated epoch out hash matches the value in the proposal.
|
|
631
|
+
// The epoch out hash is the accumulated hash of all checkpoint out hashes in the epoch.
|
|
632
|
+
const checkpointOutHash = computedCheckpoint.getCheckpointOutHash();
|
|
633
|
+
const computedEpochOutHash = accumulateCheckpointOutHashes([...previousCheckpointOutHashes, checkpointOutHash]);
|
|
634
|
+
const proposalEpochOutHash = proposal.checkpointHeader.epochOutHash;
|
|
635
|
+
if (!computedEpochOutHash.equals(proposalEpochOutHash)) {
|
|
649
636
|
this.log.warn(`Epoch out hash mismatch`, {
|
|
650
|
-
|
|
651
|
-
|
|
637
|
+
proposalEpochOutHash: proposalEpochOutHash.toString(),
|
|
638
|
+
computedEpochOutHash: computedEpochOutHash.toString(),
|
|
639
|
+
checkpointOutHash: checkpointOutHash.toString(),
|
|
640
|
+
previousCheckpointOutHashes: previousCheckpointOutHashes.map(h => h.toString()),
|
|
652
641
|
...proposalInfo,
|
|
653
642
|
});
|
|
654
643
|
return { isValid: false, reason: 'out_hash_mismatch' };
|
|
@@ -664,7 +653,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
664
653
|
/**
|
|
665
654
|
* Extract checkpoint global variables from a block.
|
|
666
655
|
*/
|
|
667
|
-
private extractCheckpointConstants(block:
|
|
656
|
+
private extractCheckpointConstants(block: L2Block): CheckpointGlobalVariables {
|
|
668
657
|
const gv = block.header.globalVariables;
|
|
669
658
|
return {
|
|
670
659
|
chainId: gv.chainId,
|
|
@@ -739,7 +728,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
739
728
|
archive: Fr,
|
|
740
729
|
txs: Tx[],
|
|
741
730
|
proposerAddress: EthAddress | undefined,
|
|
742
|
-
options: BlockProposalOptions,
|
|
731
|
+
options: BlockProposalOptions = {},
|
|
743
732
|
): Promise<BlockProposal> {
|
|
744
733
|
// TODO(palla/mbps): Prevent double proposals properly
|
|
745
734
|
// if (this.previousProposal?.slotNumber === blockHeader.globalVariables.slotNumber) {
|
|
@@ -771,7 +760,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
771
760
|
archive: Fr,
|
|
772
761
|
lastBlockInfo: CreateCheckpointProposalLastBlockData | undefined,
|
|
773
762
|
proposerAddress: EthAddress | undefined,
|
|
774
|
-
options: CheckpointProposalOptions,
|
|
763
|
+
options: CheckpointProposalOptions = {},
|
|
775
764
|
): Promise<CheckpointProposal> {
|
|
776
765
|
this.log.info(`Assembling checkpoint proposal for slot ${checkpointHeader.slotNumber}`);
|
|
777
766
|
return await this.validationService.createCheckpointProposal(
|