@aztec/validator-client 0.0.1-commit.993d240 → 0.0.1-commit.9a89641
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 +2 -0
- package/dest/checkpoint_builder.d.ts +17 -7
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +26 -9
- package/dest/config.d.ts +9 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +9 -1
- package/dest/factory.d.ts +1 -1
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +10 -3
- package/dest/key_store/web3signer_key_store.d.ts +10 -2
- package/dest/key_store/web3signer_key_store.d.ts.map +1 -1
- package/dest/key_store/web3signer_key_store.js +32 -41
- package/dest/metrics.d.ts +1 -1
- package/dest/metrics.d.ts.map +1 -1
- package/dest/metrics.js +3 -1
- package/dest/proposal_handler.d.ts +39 -8
- package/dest/proposal_handler.d.ts.map +1 -1
- package/dest/proposal_handler.js +290 -98
- package/dest/validator.d.ts +11 -5
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +54 -43
- package/package.json +19 -19
- package/src/checkpoint_builder.ts +28 -10
- package/src/config.ts +16 -3
- package/src/factory.ts +9 -1
- package/src/key_store/web3signer_key_store.ts +43 -59
- package/src/metrics.ts +2 -0
- package/src/proposal_handler.ts +309 -107
- package/src/validator.ts +63 -46
package/dest/validator.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { EpochCache } from '@aztec/epoch-cache';
|
|
|
3
3
|
import { CheckpointNumber, IndexWithinCheckpoint, SlotNumber } from '@aztec/foundation/branded-types';
|
|
4
4
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
5
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
|
-
import
|
|
6
|
+
import { Signature } from '@aztec/foundation/eth-signature';
|
|
7
7
|
import { type LogData, type Logger } from '@aztec/foundation/log';
|
|
8
8
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
9
9
|
import type { KeystoreManager } from '@aztec/node-keystore';
|
|
@@ -14,7 +14,7 @@ import type { CommitteeAttestationsAndSigners, L2BlockSink, L2BlockSource } from
|
|
|
14
14
|
import type { CheckpointReexecutionTracker } from '@aztec/stdlib/checkpoint';
|
|
15
15
|
import type { ITxProvider, Validator, ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
16
16
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
17
|
-
import { type BlockProposal, type BlockProposalOptions,
|
|
17
|
+
import { type BlockProposal, type BlockProposalOptions, CheckpointAttestation, CheckpointProposal, type CheckpointProposalCore, type CheckpointProposalOptions } from '@aztec/stdlib/p2p';
|
|
18
18
|
import type { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
19
19
|
import type { BlockHeader, Tx } from '@aztec/stdlib/tx';
|
|
20
20
|
import { type TelemetryClient, type Tracer } from '@aztec/telemetry-client';
|
|
@@ -55,10 +55,9 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
55
55
|
/** Tracks the last epoch in which each attester successfully submitted at least one attestation. */
|
|
56
56
|
private lastAttestedEpochByAttester;
|
|
57
57
|
private proposersOfInvalidBlocks;
|
|
58
|
-
private slotsWithInvalidProposals;
|
|
59
58
|
private invalidCheckpointProposalOffenseKeys;
|
|
59
|
+
private oversizedProposalOffenseKeys;
|
|
60
60
|
private badAttestationOffenseKeys;
|
|
61
|
-
private slotsWithProposalEquivocation;
|
|
62
61
|
/** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */
|
|
63
62
|
private lastAttestedProposal?;
|
|
64
63
|
protected constructor(keyStore: ExtendedValidatorKeyStore, epochCache: EpochCache, p2pClient: P2P, proposalHandler: ProposalHandler, blockSource: L2BlockSource, checkpointsBuilder: FullNodeCheckpointsBuilder, worldState: WorldStateSynchronizer, l1ToL2MessageSource: L1ToL2MessageSource, config: ValidatorClientFullConfig, blobClient: BlobClientInterface, slashingProtectionSigner: ValidatorHASigner, dateProvider?: DateProvider, telemetry?: TelemetryClient, log?: Logger);
|
|
@@ -109,6 +108,13 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
109
108
|
private markInvalidProposalSlot;
|
|
110
109
|
private handleCheckpointAttestation;
|
|
111
110
|
private slashAttestedToInvalidCheckpointProposal;
|
|
111
|
+
/**
|
|
112
|
+
* Handle detection of an oversized block proposal: one whose index within its checkpoint lands at or
|
|
113
|
+
* beyond the consensus per-checkpoint block limit. A single signed proposal at an illegal index is
|
|
114
|
+
* self-contained evidence, so emit an invalid-block-proposal slash event for the proposer, deduped per
|
|
115
|
+
* (proposer, slot) since the p2p layer reports every oversized proposal it stores.
|
|
116
|
+
*/
|
|
117
|
+
private handleOversizedProposal;
|
|
112
118
|
/**
|
|
113
119
|
* Handle detection of a duplicate proposal (equivocation).
|
|
114
120
|
* Emits a slash event when a proposer sends multiple proposals for the same position.
|
|
@@ -128,4 +134,4 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
128
134
|
private handleAuthRequest;
|
|
129
135
|
}
|
|
130
136
|
export {};
|
|
131
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
137
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFckUsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLGdCQUFnQixFQUFlLHFCQUFxQixFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ25ILE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNoRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFNUQsT0FBTyxFQUFFLEtBQUssT0FBTyxFQUFFLEtBQUssTUFBTSxFQUFnQixNQUFNLHVCQUF1QixDQUFDO0FBR2hGLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEtBQUssRUFBRSxlQUFlLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUM1RCxPQUFPLEtBQUssRUFBMEUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLFlBQVksQ0FBQztBQUV0SCxPQUFPLEVBSUwsS0FBSyxPQUFPLEVBQ1osS0FBSyxjQUFjLEVBRXBCLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxLQUFLLEVBQUUsWUFBWSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDaEUsT0FBTyxLQUFLLEVBQUUsK0JBQStCLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3ZHLE9BQU8sS0FBSyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFN0UsT0FBTyxLQUFLLEVBQ1YsV0FBVyxFQUNYLFNBQVMsRUFDVCx5QkFBeUIs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
|
package/dest/validator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAe,qBAAqB,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AACnH,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
|
package/dest/validator.js
CHANGED
|
@@ -8,49 +8,23 @@ import { DateProvider } from '@aztec/foundation/timer';
|
|
|
8
8
|
import { AuthRequest, AuthResponse, BlockProposalValidator, ReqRespSubProtocol } from '@aztec/p2p';
|
|
9
9
|
import { OffenseType, WANT_TO_CLEAR_SLASH_EVENT, WANT_TO_SLASH_EVENT, getOffenseTypeName } from '@aztec/slasher';
|
|
10
10
|
import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
|
|
11
|
+
import { ConsensusTimetable } from '@aztec/stdlib/timetable';
|
|
11
12
|
import { AttestationTimeoutError } from '@aztec/stdlib/validators';
|
|
12
13
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
13
14
|
import { createHASigner, createLocalSignerWithProtection, createSignerFromSharedDb } from '@aztec/validator-ha-signer/factory';
|
|
14
15
|
import { DutyType } from '@aztec/validator-ha-signer/types';
|
|
15
16
|
import { EventEmitter } from 'events';
|
|
17
|
+
import { DEFAULT_MAX_GOSSIP_CLOCK_DISPARITY_MS } from './config.js';
|
|
16
18
|
import { ValidationService } from './duties/validation_service.js';
|
|
17
19
|
import { HAKeyStore } from './key_store/ha_key_store.js';
|
|
18
20
|
import { NodeKeystoreAdapter } from './key_store/node_keystore_adapter.js';
|
|
19
21
|
import { ValidatorMetrics } from './metrics.js';
|
|
20
|
-
import { ProposalHandler } from './proposal_handler.js';
|
|
22
|
+
import { ProposalHandler, SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT, SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT } from './proposal_handler.js';
|
|
21
23
|
// We maintain a set of proposers who have proposed invalid blocks.
|
|
22
24
|
// Just cap the set to avoid unbounded growth.
|
|
23
25
|
const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
24
|
-
const MAX_TRACKED_INVALID_PROPOSAL_SLOTS = 1000;
|
|
25
26
|
const MAX_TRACKED_INVALID_CHECKPOINT_PROPOSALS = 1000;
|
|
26
27
|
const MAX_TRACKED_BAD_ATTESTATIONS = 10_000;
|
|
27
|
-
// What errors from the block proposal handler result in slashing
|
|
28
|
-
const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
29
|
-
'state_mismatch',
|
|
30
|
-
'failed_txs',
|
|
31
|
-
'global_variables_mismatch',
|
|
32
|
-
'invalid_proposal',
|
|
33
|
-
'parent_block_wrong_slot',
|
|
34
|
-
'in_hash_mismatch'
|
|
35
|
-
];
|
|
36
|
-
const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
37
|
-
// enabled
|
|
38
|
-
['invalid_fee_asset_price_modifier']: true,
|
|
39
|
-
['checkpoint_header_mismatch']: true,
|
|
40
|
-
// These late mismatches should normally be caught by earlier checks, but if reached after validating the local
|
|
41
|
-
// checkpoint inputs, the proposer-signed payload disagrees with deterministic recomputation.
|
|
42
|
-
['archive_mismatch']: true,
|
|
43
|
-
['out_hash_mismatch']: true,
|
|
44
|
-
['no_blocks_for_slot']: true,
|
|
45
|
-
['too_many_blocks_in_checkpoint']: true,
|
|
46
|
-
['checkpoint_validation_failed']: true,
|
|
47
|
-
['last_block_archive_mismatch']: true,
|
|
48
|
-
// disabled
|
|
49
|
-
['invalid_signature']: false,
|
|
50
|
-
['last_block_not_found']: false,
|
|
51
|
-
['block_fetch_error']: false,
|
|
52
|
-
['checkpoint_already_published']: false
|
|
53
|
-
};
|
|
54
28
|
/**
|
|
55
29
|
* Validator Client
|
|
56
30
|
*/ export class ValidatorClient extends EventEmitter {
|
|
@@ -78,13 +52,12 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
78
52
|
epochCacheUpdateLoop;
|
|
79
53
|
/** Tracks the last epoch in which each attester successfully submitted at least one attestation. */ lastAttestedEpochByAttester;
|
|
80
54
|
proposersOfInvalidBlocks;
|
|
81
|
-
slotsWithInvalidProposals;
|
|
82
55
|
invalidCheckpointProposalOffenseKeys;
|
|
56
|
+
oversizedProposalOffenseKeys;
|
|
83
57
|
badAttestationOffenseKeys;
|
|
84
|
-
slotsWithProposalEquivocation;
|
|
85
58
|
/** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */ lastAttestedProposal;
|
|
86
59
|
constructor(keyStore, epochCache, p2pClient, proposalHandler, blockSource, checkpointsBuilder, worldState, l1ToL2MessageSource, config, blobClient, slashingProtectionSigner, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator')){
|
|
87
|
-
super(), this.keyStore = keyStore, this.epochCache = epochCache, this.p2pClient = p2pClient, this.proposalHandler = proposalHandler, this.blockSource = blockSource, this.checkpointsBuilder = checkpointsBuilder, this.worldState = worldState, this.l1ToL2MessageSource = l1ToL2MessageSource, this.config = config, this.blobClient = blobClient, this.slashingProtectionSigner = slashingProtectionSigner, this.dateProvider = dateProvider, this.hasRegisteredHandlers = false, this.lastAttestedEpochByAttester = new Map(), this.proposersOfInvalidBlocks = FifoSet.withLimit(MAX_PROPOSERS_OF_INVALID_BLOCKS), this.
|
|
60
|
+
super(), this.keyStore = keyStore, this.epochCache = epochCache, this.p2pClient = p2pClient, this.proposalHandler = proposalHandler, this.blockSource = blockSource, this.checkpointsBuilder = checkpointsBuilder, this.worldState = worldState, this.l1ToL2MessageSource = l1ToL2MessageSource, this.config = config, this.blobClient = blobClient, this.slashingProtectionSigner = slashingProtectionSigner, this.dateProvider = dateProvider, this.hasRegisteredHandlers = false, this.lastAttestedEpochByAttester = new Map(), this.proposersOfInvalidBlocks = FifoSet.withLimit(MAX_PROPOSERS_OF_INVALID_BLOCKS), this.invalidCheckpointProposalOffenseKeys = FifoSet.withLimit(MAX_TRACKED_INVALID_CHECKPOINT_PROPOSALS), this.oversizedProposalOffenseKeys = FifoSet.withLimit(MAX_TRACKED_INVALID_CHECKPOINT_PROPOSALS), this.badAttestationOffenseKeys = FifoSet.withLimit(MAX_TRACKED_BAD_ATTESTATIONS);
|
|
88
61
|
// Create child logger with fisherman prefix if in fisherman mode
|
|
89
62
|
this.log = config.fishermanMode ? log.createChild('[FISHERMAN]') : log;
|
|
90
63
|
this.tracer = telemetry.getTracer('Validator');
|
|
@@ -142,7 +115,11 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
142
115
|
}
|
|
143
116
|
static async new(config, checkpointsBuilder, worldState, epochCache, p2pClient, blockSource, l1ToL2MessageSource, txProvider, keyStoreManager, blobClient, reexecutionTracker, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), slashingProtectionDb) {
|
|
144
117
|
const metrics = new ValidatorMetrics(telemetry);
|
|
145
|
-
const
|
|
118
|
+
const consensusTimetable = new ConsensusTimetable({
|
|
119
|
+
l1Constants: epochCache.getL1Constants(),
|
|
120
|
+
blockDuration: config.blockDurationMs / 1000
|
|
121
|
+
});
|
|
122
|
+
const blockProposalValidator = new BlockProposalValidator(epochCache, consensusTimetable, {
|
|
146
123
|
txsPermitted: !config.disableTransactions,
|
|
147
124
|
maxTxsPerBlock: config.validateMaxTxsPerBlock,
|
|
148
125
|
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
|
|
@@ -150,9 +127,10 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
150
127
|
signatureContext: {
|
|
151
128
|
chainId: config.l1ChainId,
|
|
152
129
|
rollupAddress: config.rollupAddress
|
|
153
|
-
}
|
|
130
|
+
},
|
|
131
|
+
clockDisparityMs: config.maxGossipClockDisparityMs ?? DEFAULT_MAX_GOSSIP_CLOCK_DISPARITY_MS
|
|
154
132
|
});
|
|
155
|
-
const proposalHandler = new ProposalHandler(checkpointsBuilder, worldState, blockSource, l1ToL2MessageSource, txProvider, blockProposalValidator, epochCache, config, blobClient, reexecutionTracker, metrics, dateProvider, telemetry, undefined);
|
|
133
|
+
const proposalHandler = new ProposalHandler(checkpointsBuilder, worldState, blockSource, l1ToL2MessageSource, txProvider, blockProposalValidator, epochCache, consensusTimetable, config, blobClient, reexecutionTracker, metrics, dateProvider, telemetry, undefined);
|
|
156
134
|
const nodeKeystoreAdapter = NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager);
|
|
157
135
|
let slashingProtectionSigner;
|
|
158
136
|
if (slashingProtectionDb) {
|
|
@@ -209,10 +187,10 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
209
187
|
return this.config;
|
|
210
188
|
}
|
|
211
189
|
hasProposalEquivocation(slotNumber) {
|
|
212
|
-
return this.
|
|
190
|
+
return this.proposalHandler.hasProposalEquivocation(slotNumber);
|
|
213
191
|
}
|
|
214
192
|
hasInvalidProposals(slotNumber) {
|
|
215
|
-
return this.
|
|
193
|
+
return this.proposalHandler.hasInvalidProposals(slotNumber);
|
|
216
194
|
}
|
|
217
195
|
updateConfig(config) {
|
|
218
196
|
this.config = {
|
|
@@ -262,6 +240,10 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
262
240
|
this.p2pClient.registerDuplicateProposalCallback((info)=>{
|
|
263
241
|
this.handleDuplicateProposal(info);
|
|
264
242
|
});
|
|
243
|
+
// Oversized proposal handler - triggers slashing for proposals beyond the per-checkpoint block limit
|
|
244
|
+
this.p2pClient.registerOversizedProposalCallback((info)=>{
|
|
245
|
+
this.handleOversizedProposal(info);
|
|
246
|
+
});
|
|
265
247
|
// Duplicate attestation handler - triggers slashing for attestation equivocation
|
|
266
248
|
this.p2pClient.registerDuplicateAttestationCallback((info)=>{
|
|
267
249
|
this.handleDuplicateAttestation(info);
|
|
@@ -319,7 +301,9 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
319
301
|
'state_mismatch',
|
|
320
302
|
'failed_txs',
|
|
321
303
|
'in_hash_mismatch',
|
|
322
|
-
'parent_block_wrong_slot'
|
|
304
|
+
'parent_block_wrong_slot',
|
|
305
|
+
'duplicate_txs',
|
|
306
|
+
'invalid_embedded_txs'
|
|
323
307
|
];
|
|
324
308
|
if (badProposalReasons.includes(reason)) {
|
|
325
309
|
this.metrics.incFailedAttestationsBadProposal(1, reason, partOfCommittee);
|
|
@@ -369,7 +353,7 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
369
353
|
}
|
|
370
354
|
// Ignore proposals from ourselves (may happen in HA setups)
|
|
371
355
|
if (proposer && this.getValidatorAddresses().some((addr)=>addr.equals(proposer))) {
|
|
372
|
-
this.log.debug(`
|
|
356
|
+
this.log.debug(`Not attesting to block proposal from self for slot ${proposalSlotNumber}`, {
|
|
373
357
|
proposer: proposer.toString(),
|
|
374
358
|
proposalSlotNumber
|
|
375
359
|
});
|
|
@@ -522,7 +506,8 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
522
506
|
if (!SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT[result.reason]) {
|
|
523
507
|
return;
|
|
524
508
|
}
|
|
525
|
-
this
|
|
509
|
+
// The slot is already marked invalid by the all-nodes checkpoint handler that invokes this callback,
|
|
510
|
+
// so we only emit the proposer slash event here.
|
|
526
511
|
if (this.slashInvalidCheckpointProposal(proposal)) {
|
|
527
512
|
this.log.info(`Detected invalid checkpoint proposal offense`, {
|
|
528
513
|
...proposalInfo,
|
|
@@ -557,11 +542,11 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
557
542
|
return true;
|
|
558
543
|
}
|
|
559
544
|
markInvalidProposalSlot(slotNumber) {
|
|
560
|
-
this.
|
|
545
|
+
this.proposalHandler.markInvalidProposalSlot(slotNumber);
|
|
561
546
|
}
|
|
562
547
|
handleCheckpointAttestation(attestation) {
|
|
563
548
|
const slotNumber = attestation.slotNumber;
|
|
564
|
-
if (!this.
|
|
549
|
+
if (!this.proposalHandler.hasInvalidProposals(slotNumber) || this.proposalHandler.hasProposalEquivocation(slotNumber)) {
|
|
565
550
|
return;
|
|
566
551
|
}
|
|
567
552
|
const attester = attestation.getSender();
|
|
@@ -595,11 +580,37 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
595
580
|
]);
|
|
596
581
|
}
|
|
597
582
|
/**
|
|
583
|
+
* Handle detection of an oversized block proposal: one whose index within its checkpoint lands at or
|
|
584
|
+
* beyond the consensus per-checkpoint block limit. A single signed proposal at an illegal index is
|
|
585
|
+
* self-contained evidence, so emit an invalid-block-proposal slash event for the proposer, deduped per
|
|
586
|
+
* (proposer, slot) since the p2p layer reports every oversized proposal it stores.
|
|
587
|
+
*/ handleOversizedProposal(info) {
|
|
588
|
+
const { slot, proposer } = info;
|
|
589
|
+
const offenseType = OffenseType.BROADCASTED_INVALID_BLOCK_PROPOSAL;
|
|
590
|
+
if (!this.oversizedProposalOffenseKeys.addIfAbsent(`${proposer.toString()}:${offenseType}:${slot}`)) {
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
this.log.info(`Detected oversized block proposal offense from ${proposer.toString()} at slot ${slot}`, {
|
|
594
|
+
proposer: proposer.toString(),
|
|
595
|
+
slot,
|
|
596
|
+
amount: this.config.slashBroadcastedInvalidBlockPenalty,
|
|
597
|
+
offenseType: getOffenseTypeName(offenseType)
|
|
598
|
+
});
|
|
599
|
+
this.emit(WANT_TO_SLASH_EVENT, [
|
|
600
|
+
{
|
|
601
|
+
validator: proposer,
|
|
602
|
+
amount: this.config.slashBroadcastedInvalidBlockPenalty,
|
|
603
|
+
offenseType,
|
|
604
|
+
epochOrSlot: BigInt(slot)
|
|
605
|
+
}
|
|
606
|
+
]);
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
598
609
|
* Handle detection of a duplicate proposal (equivocation).
|
|
599
610
|
* Emits a slash event when a proposer sends multiple proposals for the same position.
|
|
600
611
|
*/ handleDuplicateProposal(info) {
|
|
601
612
|
const { slot, proposer, type } = info;
|
|
602
|
-
this.
|
|
613
|
+
this.proposalHandler.markProposalEquivocation(slot);
|
|
603
614
|
this.log.info(`Detected duplicate ${type} proposal offense from ${proposer.toString()} at slot ${slot}`, {
|
|
604
615
|
proposer: proposer.toString(),
|
|
605
616
|
slot,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/validator-client",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.9a89641",
|
|
4
4
|
"main": "dest/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -64,30 +64,30 @@
|
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@aztec/blob-client": "0.0.1-commit.
|
|
68
|
-
"@aztec/blob-lib": "0.0.1-commit.
|
|
69
|
-
"@aztec/constants": "0.0.1-commit.
|
|
70
|
-
"@aztec/epoch-cache": "0.0.1-commit.
|
|
71
|
-
"@aztec/ethereum": "0.0.1-commit.
|
|
72
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
73
|
-
"@aztec/node-keystore": "0.0.1-commit.
|
|
74
|
-
"@aztec/
|
|
75
|
-
"@aztec/
|
|
76
|
-
"@aztec/
|
|
77
|
-
"@aztec/
|
|
78
|
-
"@aztec/
|
|
79
|
-
"@aztec/
|
|
80
|
-
"@aztec/
|
|
81
|
-
"@aztec/
|
|
82
|
-
"@aztec/validator-ha-signer": "0.0.1-commit.993d240",
|
|
67
|
+
"@aztec/blob-client": "0.0.1-commit.9a89641",
|
|
68
|
+
"@aztec/blob-lib": "0.0.1-commit.9a89641",
|
|
69
|
+
"@aztec/constants": "0.0.1-commit.9a89641",
|
|
70
|
+
"@aztec/epoch-cache": "0.0.1-commit.9a89641",
|
|
71
|
+
"@aztec/ethereum": "0.0.1-commit.9a89641",
|
|
72
|
+
"@aztec/foundation": "0.0.1-commit.9a89641",
|
|
73
|
+
"@aztec/node-keystore": "0.0.1-commit.9a89641",
|
|
74
|
+
"@aztec/p2p": "0.0.1-commit.9a89641",
|
|
75
|
+
"@aztec/protocol-contracts": "0.0.1-commit.9a89641",
|
|
76
|
+
"@aztec/prover-client": "0.0.1-commit.9a89641",
|
|
77
|
+
"@aztec/simulator": "0.0.1-commit.9a89641",
|
|
78
|
+
"@aztec/slasher": "0.0.1-commit.9a89641",
|
|
79
|
+
"@aztec/stdlib": "0.0.1-commit.9a89641",
|
|
80
|
+
"@aztec/telemetry-client": "0.0.1-commit.9a89641",
|
|
81
|
+
"@aztec/validator-ha-signer": "0.0.1-commit.9a89641",
|
|
83
82
|
"koa": "^2.16.1",
|
|
84
83
|
"koa-router": "^13.1.1",
|
|
85
84
|
"tslib": "^2.4.0",
|
|
86
85
|
"viem": "npm:@aztec/viem@2.38.2"
|
|
87
86
|
},
|
|
88
87
|
"devDependencies": {
|
|
89
|
-
"@aztec/archiver": "0.0.1-commit.
|
|
90
|
-
"@aztec/
|
|
88
|
+
"@aztec/archiver": "0.0.1-commit.9a89641",
|
|
89
|
+
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.9a89641",
|
|
90
|
+
"@aztec/world-state": "0.0.1-commit.9a89641",
|
|
91
91
|
"@electric-sql/pglite": "^0.3.14",
|
|
92
92
|
"@jest/globals": "^30.0.0",
|
|
93
93
|
"@types/jest": "^30.0.0",
|
|
@@ -9,12 +9,13 @@ import { DateProvider, elapsed } from '@aztec/foundation/timer';
|
|
|
9
9
|
import { createTxValidatorForBlockBuilding, getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
|
|
10
10
|
import { LightweightCheckpointBuilder } from '@aztec/prover-client/light';
|
|
11
11
|
import {
|
|
12
|
+
type AvmSimulator,
|
|
12
13
|
GuardedMerkleTreeOperations,
|
|
13
14
|
PublicContractsDB,
|
|
14
15
|
PublicProcessor,
|
|
15
16
|
createPublicTxSimulatorForBlockBuilding,
|
|
16
17
|
} from '@aztec/simulator/server';
|
|
17
|
-
import { L2Block } from '@aztec/stdlib/block';
|
|
18
|
+
import { type BlockHash, L2Block } from '@aztec/stdlib/block';
|
|
18
19
|
import { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
19
20
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
20
21
|
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
@@ -57,6 +58,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
57
58
|
private contractDataSource: ContractDataSource,
|
|
58
59
|
private dateProvider: DateProvider,
|
|
59
60
|
private telemetryClient: TelemetryClient,
|
|
61
|
+
private avmSimulator: AvmSimulator,
|
|
60
62
|
bindings?: LoggerBindings,
|
|
61
63
|
private debugLogStore: DebugLogStore = new NullDebugLogStore(),
|
|
62
64
|
) {
|
|
@@ -219,10 +221,12 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
219
221
|
if (opts.isBuildingProposal) {
|
|
220
222
|
const remainingBlocks = Math.max(1, opts.maxBlocksPerCheckpoint - existingBlocks.length);
|
|
221
223
|
const multiplier = opts.perBlockAllocationMultiplier;
|
|
224
|
+
// DA gas and blob fields use a higher multiplier so the largest contract class deploy fits a block.
|
|
225
|
+
const daMultiplier = opts.perBlockDAAllocationMultiplier ?? multiplier;
|
|
222
226
|
|
|
223
227
|
cappedL2Gas = Math.min(cappedL2Gas, Math.ceil((remainingMana / remainingBlocks) * multiplier));
|
|
224
|
-
cappedDAGas = Math.min(cappedDAGas, Math.ceil((remainingDAGas / remainingBlocks) *
|
|
225
|
-
cappedBlobFields = Math.min(cappedBlobFields, Math.ceil((maxBlobFieldsForTxs / remainingBlocks) *
|
|
228
|
+
cappedDAGas = Math.min(cappedDAGas, Math.ceil((remainingDAGas / remainingBlocks) * daMultiplier));
|
|
229
|
+
cappedBlobFields = Math.min(cappedBlobFields, Math.ceil((maxBlobFieldsForTxs / remainingBlocks) * daMultiplier));
|
|
226
230
|
cappedMaxTransactions = Math.min(cappedMaxTransactions, Math.ceil((remainingTxs / remainingBlocks) * multiplier));
|
|
227
231
|
}
|
|
228
232
|
|
|
@@ -241,16 +245,18 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
241
245
|
const contractsDB = this.contractsDB;
|
|
242
246
|
const guardedFork = new GuardedMerkleTreeOperations(fork);
|
|
243
247
|
|
|
244
|
-
const collectDebugLogs = this.debugLogStore.isEnabled;
|
|
245
|
-
|
|
246
248
|
const bindings = this.log.getBindings();
|
|
249
|
+
// Extract the WSDB fork ID so the C++ AVM can modify the same fork in-place; the simulator reads
|
|
250
|
+
// contract data from `contractsDB`, scoped to this fork for the duration of each simulation.
|
|
251
|
+
const wsdbForkId = fork.getRevision().forkId;
|
|
247
252
|
const publicTxSimulator = createPublicTxSimulatorForBlockBuilding(
|
|
248
|
-
|
|
249
|
-
contractsDB,
|
|
253
|
+
this.avmSimulator,
|
|
250
254
|
globalVariables,
|
|
255
|
+
contractsDB,
|
|
256
|
+
wsdbForkId,
|
|
251
257
|
this.telemetryClient,
|
|
252
258
|
bindings,
|
|
253
|
-
|
|
259
|
+
this.debugLogStore?.isEnabled ?? false,
|
|
254
260
|
);
|
|
255
261
|
|
|
256
262
|
const processor = new PublicProcessor(
|
|
@@ -289,6 +295,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
289
295
|
private worldState: WorldStateSynchronizer,
|
|
290
296
|
private contractDataSource: ContractDataSource,
|
|
291
297
|
private dateProvider: DateProvider,
|
|
298
|
+
private avmSimulator: AvmSimulator,
|
|
292
299
|
private telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
293
300
|
private debugLogStore: DebugLogStore = new NullDebugLogStore(),
|
|
294
301
|
) {
|
|
@@ -344,6 +351,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
344
351
|
this.contractDataSource,
|
|
345
352
|
this.dateProvider,
|
|
346
353
|
this.telemetryClient,
|
|
354
|
+
this.avmSimulator,
|
|
347
355
|
bindings,
|
|
348
356
|
this.debugLogStore,
|
|
349
357
|
);
|
|
@@ -405,13 +413,23 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
405
413
|
this.contractDataSource,
|
|
406
414
|
this.dateProvider,
|
|
407
415
|
this.telemetryClient,
|
|
416
|
+
this.avmSimulator,
|
|
408
417
|
bindings,
|
|
409
418
|
this.debugLogStore,
|
|
410
419
|
);
|
|
411
420
|
}
|
|
412
421
|
|
|
413
|
-
/**
|
|
414
|
-
|
|
422
|
+
/**
|
|
423
|
+
* Syncs world state to the given block number and returns a fork of it at that block.
|
|
424
|
+
*
|
|
425
|
+
* Syncing first is required: the block source (archiver) can already hold a block while world state
|
|
426
|
+
* still trails it, and forking a not-yet-applied block throws a raw "initialize from future block"
|
|
427
|
+
* tree error. syncImmediate blocks until world state reaches the block, or throws a typed error if it
|
|
428
|
+
* genuinely cannot. When `blockHash` is provided it is verified against the synced block, triggering a
|
|
429
|
+
* resync on mismatch (reorg detection).
|
|
430
|
+
*/
|
|
431
|
+
async getFork(blockNumber: BlockNumber, blockHash?: BlockHash): Promise<MerkleTreeWriteOperations> {
|
|
432
|
+
await this.worldState.syncImmediate(blockNumber, blockHash);
|
|
415
433
|
return this.worldState.fork(blockNumber);
|
|
416
434
|
}
|
|
417
435
|
}
|
package/src/config.ts
CHANGED
|
@@ -4,15 +4,26 @@ import {
|
|
|
4
4
|
getConfigFromMappings,
|
|
5
5
|
numberConfigHelper,
|
|
6
6
|
optionalNumberConfigHelper,
|
|
7
|
+
pickConfigMappings,
|
|
7
8
|
secretValueConfigHelper,
|
|
8
9
|
} from '@aztec/foundation/config';
|
|
9
10
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
11
|
+
import { type SequencerConfig, sharedSequencerConfigMappings } from '@aztec/stdlib/config';
|
|
10
12
|
import { localSignerConfigMappings, validatorHASignerConfigMappings } from '@aztec/stdlib/ha-signing';
|
|
11
13
|
import type { ValidatorClientConfig } from '@aztec/stdlib/interfaces/server';
|
|
12
14
|
|
|
13
15
|
export type { ValidatorClientConfig };
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Default clock-disparity tolerance (ms) for proposal/attestation receive windows, mirroring the p2p config
|
|
19
|
+
* default. Used by the validator-client validators when the merged node config does not carry the value.
|
|
20
|
+
*/
|
|
21
|
+
export const DEFAULT_MAX_GOSSIP_CLOCK_DISPARITY_MS = 500;
|
|
22
|
+
|
|
23
|
+
export const validatorClientConfigMappings: ConfigMappingsType<
|
|
24
|
+
ValidatorClientConfig & Pick<SequencerConfig, 'blockDurationMs'>
|
|
25
|
+
> = {
|
|
26
|
+
...pickConfigMappings(sharedSequencerConfigMappings, ['blockDurationMs']),
|
|
16
27
|
validatorPrivateKeys: {
|
|
17
28
|
env: 'VALIDATOR_PRIVATE_KEYS',
|
|
18
29
|
description: 'List of private keys of the validators participating in attestation duties',
|
|
@@ -112,6 +123,8 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
|
|
|
112
123
|
* Note: If an environment variable is not set, the default value is used.
|
|
113
124
|
* @returns The validator configuration.
|
|
114
125
|
*/
|
|
115
|
-
export function getProverEnvVars(): ValidatorClientConfig {
|
|
116
|
-
return getConfigFromMappings<ValidatorClientConfig
|
|
126
|
+
export function getProverEnvVars(): ValidatorClientConfig & Pick<SequencerConfig, 'blockDurationMs'> {
|
|
127
|
+
return getConfigFromMappings<ValidatorClientConfig & Pick<SequencerConfig, 'blockDurationMs'>>(
|
|
128
|
+
validatorClientConfigMappings,
|
|
129
|
+
);
|
|
117
130
|
}
|
package/src/factory.ts
CHANGED
|
@@ -7,10 +7,12 @@ import type { L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
|
7
7
|
import type { CheckpointReexecutionTracker } from '@aztec/stdlib/checkpoint';
|
|
8
8
|
import type { ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
9
9
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
10
|
+
import { ConsensusTimetable } from '@aztec/stdlib/timetable';
|
|
10
11
|
import type { TelemetryClient } from '@aztec/telemetry-client';
|
|
11
12
|
import type { SlashingProtectionDatabase } from '@aztec/validator-ha-signer/types';
|
|
12
13
|
|
|
13
14
|
import type { FullNodeCheckpointsBuilder } from './checkpoint_builder.js';
|
|
15
|
+
import { DEFAULT_MAX_GOSSIP_CLOCK_DISPARITY_MS } from './config.js';
|
|
14
16
|
import { ValidatorMetrics } from './metrics.js';
|
|
15
17
|
import { ProposalHandler } from './proposal_handler.js';
|
|
16
18
|
import { ValidatorClient } from './validator.js';
|
|
@@ -31,7 +33,11 @@ export function createProposalHandler(
|
|
|
31
33
|
},
|
|
32
34
|
) {
|
|
33
35
|
const metrics = new ValidatorMetrics(deps.telemetry);
|
|
34
|
-
const
|
|
36
|
+
const consensusTimetable = new ConsensusTimetable({
|
|
37
|
+
l1Constants: deps.epochCache.getL1Constants(),
|
|
38
|
+
blockDuration: config.blockDurationMs / 1000,
|
|
39
|
+
});
|
|
40
|
+
const blockProposalValidator = new BlockProposalValidator(deps.epochCache, consensusTimetable, {
|
|
35
41
|
txsPermitted: !config.disableTransactions,
|
|
36
42
|
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
|
|
37
43
|
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
|
|
@@ -39,6 +45,7 @@ export function createProposalHandler(
|
|
|
39
45
|
chainId: config.l1ChainId,
|
|
40
46
|
rollupAddress: config.rollupAddress,
|
|
41
47
|
},
|
|
48
|
+
clockDisparityMs: config.maxGossipClockDisparityMs ?? DEFAULT_MAX_GOSSIP_CLOCK_DISPARITY_MS,
|
|
42
49
|
});
|
|
43
50
|
return new ProposalHandler(
|
|
44
51
|
deps.checkpointsBuilder,
|
|
@@ -48,6 +55,7 @@ export function createProposalHandler(
|
|
|
48
55
|
deps.p2pClient.getTxProvider(),
|
|
49
56
|
blockProposalValidator,
|
|
50
57
|
deps.epochCache,
|
|
58
|
+
consensusTimetable,
|
|
51
59
|
config,
|
|
52
60
|
deps.blobClient,
|
|
53
61
|
deps.reexecutionTracker,
|