@aztec/validator-client 5.0.0-nightly.20260623 → 5.0.0-nightly.20260624
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/proposal_handler.d.ts +24 -2
- package/dest/proposal_handler.d.ts.map +1 -1
- package/dest/proposal_handler.js +70 -1
- package/dest/validator.d.ts +1 -3
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +9 -38
- package/package.json +19 -19
- package/src/proposal_handler.ts +93 -1
- package/src/validator.ts +12 -41
|
@@ -48,7 +48,17 @@ export type CheckpointProposalValidationFailureResult = {
|
|
|
48
48
|
};
|
|
49
49
|
export type CheckpointProposalValidationResult = CheckpointProposalValidationSuccessResult | CheckpointProposalValidationFailureResult;
|
|
50
50
|
export type CheckpointProposalValidationFailureCallback = (proposal: CheckpointProposalCore, result: CheckpointProposalValidationFailureResult, proposalInfo: LogData) => void | Promise<void>;
|
|
51
|
-
/**
|
|
51
|
+
/** Block-proposal validation failures that constitute a slashable invalid-block offense. */
|
|
52
|
+
export declare const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT: BlockProposalValidationFailureReason[];
|
|
53
|
+
/** Checkpoint-proposal validation failures that constitute a slashable invalid-checkpoint offense. */
|
|
54
|
+
export declare const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT: Record<CheckpointProposalValidationFailureReason, boolean>;
|
|
55
|
+
/**
|
|
56
|
+
* Handles block and checkpoint proposals for both validator and non-validator nodes. Also tracks which slots
|
|
57
|
+
* had a slashable invalid proposal or a proposal equivocation, exposing them via the
|
|
58
|
+
* `InvalidProposalSlotSource` interface consumed by the attested-invalid-proposal slashing watcher. The
|
|
59
|
+
* tracking is populated as a side effect of validating/re-executing proposals, so any node that re-executes
|
|
60
|
+
* proposals (the default) can serve it — not only validators.
|
|
61
|
+
*/
|
|
52
62
|
export declare class ProposalHandler {
|
|
53
63
|
private checkpointsBuilder;
|
|
54
64
|
private worldState;
|
|
@@ -76,6 +86,10 @@ export declare class ProposalHandler {
|
|
|
76
86
|
/** P2P proposal pool access for deciding when retained proposals should block archiver processing. */
|
|
77
87
|
private p2pClient?;
|
|
78
88
|
private checkpointProposalValidationFailureCallback?;
|
|
89
|
+
/** Slots at which a slashable invalid block or checkpoint proposal was observed. */
|
|
90
|
+
private readonly slotsWithInvalidProposals;
|
|
91
|
+
/** Slots at which a proposal equivocation was observed; suppresses attested-to-invalid-proposal slashing. */
|
|
92
|
+
private readonly slotsWithProposalEquivocation;
|
|
79
93
|
constructor(checkpointsBuilder: FullNodeCheckpointsBuilder, worldState: WorldStateSynchronizer, blockSource: L2BlockSource & L2BlockSink, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: ITxProvider, blockProposalValidator: BlockProposalValidator, epochCache: EpochCache, timetable: ConsensusTimetable, config: ValidatorClientFullConfig, blobClient: BlobClientInterface, reexecutionTracker: CheckpointReexecutionTracker, metrics?: ValidatorMetrics | undefined, dateProvider?: DateProvider, telemetry?: TelemetryClient, log?: import("@aztec/foundation/log").Logger);
|
|
80
94
|
updateConfig(config: Partial<ValidatorClientFullConfig>): void;
|
|
81
95
|
setCheckpointProposalValidationFailureCallback(callback?: CheckpointProposalValidationFailureCallback): void;
|
|
@@ -91,6 +105,14 @@ export declare class ProposalHandler {
|
|
|
91
105
|
* proposer's own view of its own work.
|
|
92
106
|
*/
|
|
93
107
|
recordOwnCheckpointProposalAsValid(slot: SlotNumber, archive: Fr, checkpointNumber: CheckpointNumber): void;
|
|
108
|
+
/** Whether a slashable invalid block or checkpoint proposal was observed at the given slot (InvalidProposalSlotSource). */
|
|
109
|
+
hasInvalidProposals(slotNumber: SlotNumber): boolean;
|
|
110
|
+
/** Whether a proposal equivocation was observed at the given slot (InvalidProposalSlotSource). */
|
|
111
|
+
hasProposalEquivocation(slotNumber: SlotNumber): boolean;
|
|
112
|
+
/** Records a slot as having a slashable invalid proposal, for offense observers (sentinel/slasher watchers). */
|
|
113
|
+
markInvalidProposalSlot(slotNumber: SlotNumber): void;
|
|
114
|
+
/** Records a slot as having a proposal equivocation, which suppresses attested-to-invalid-proposal slashing. */
|
|
115
|
+
markProposalEquivocation(slotNumber: SlotNumber): void;
|
|
94
116
|
/**
|
|
95
117
|
* Registers handlers for block and checkpoint proposals on the p2p client.
|
|
96
118
|
* Records the p2p client so validation can inspect retained proposals.
|
|
@@ -140,4 +162,4 @@ export declare class ProposalHandler {
|
|
|
140
162
|
private setProposedCheckpoint;
|
|
141
163
|
}
|
|
142
164
|
export {};
|
|
143
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
165
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvcG9zYWxfaGFuZGxlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Byb3Bvc2FsX2hhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDaEQsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUdyRSxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVyRCxPQUFPLEVBQ0wsV0FBVyxFQUNYLGdCQUFnQixFQUVoQixVQUFVLEVBQ1gsTUFBTSxpQ0FBaUMsQ0FBQztBQUV6QyxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFHcEQsT0FBTyxLQUFLLEVBQUUsT0FBTyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFHckQsT0FBTyxFQUFFLFlBQVksRUFBUyxNQUFNLHlCQUF5QixDQUFDO0FBQzlELE9BQU8sS0FBSyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDOUMsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDbkUsT0FBTyxLQUFLLEVBQWEsT0FBTyxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUMxRixPQUFPLEtBQUssRUFBRSw0QkFBNEIsRUFBc0IsTUFBTSwwQkFBMEIsQ0FBQztBQUlqRyxPQUFPLEtBQUssRUFBRSxXQUFXLEVBQUUseUJBQXlCLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN0SCxPQUFPLEVBQ0wsS0FBSyxtQkFBbUIsRUFHekIsTUFBTSx5QkFBeUIsQ0FBQztBQUNqQyxPQUFPLEtBQUssRUFBRSxhQUFhLEVBQXlCLHNCQUFzQixFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDdEcsT0FBTyxLQUFLLEVBQUUsa0JBQWtC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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proposal_handler.d.ts","sourceRoot":"","sources":["../src/proposal_handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAGrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EACL,WAAW,EACX,gBAAgB,EAEhB,UAAU,EACX,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"proposal_handler.d.ts","sourceRoot":"","sources":["../src/proposal_handler.ts"],"names":[],"mappings":"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"}
|
package/dest/proposal_handler.js
CHANGED
|
@@ -70,6 +70,7 @@ import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
|
70
70
|
import { pick } from '@aztec/foundation/collection';
|
|
71
71
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
72
72
|
import { TimeoutError } from '@aztec/foundation/error';
|
|
73
|
+
import { FifoSet } from '@aztec/foundation/fifo-set';
|
|
73
74
|
import { createLogger } from '@aztec/foundation/log';
|
|
74
75
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
75
76
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
@@ -98,7 +99,40 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
|
98
99
|
out_hash_mismatch: 'invalid',
|
|
99
100
|
checkpoint_validation_failed: 'invalid'
|
|
100
101
|
};
|
|
101
|
-
|
|
102
|
+
const MAX_TRACKED_INVALID_PROPOSAL_SLOTS = 1000;
|
|
103
|
+
/** Block-proposal validation failures that constitute a slashable invalid-block offense. */ export const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
104
|
+
'state_mismatch',
|
|
105
|
+
'failed_txs',
|
|
106
|
+
'global_variables_mismatch',
|
|
107
|
+
'invalid_proposal',
|
|
108
|
+
'parent_block_wrong_slot',
|
|
109
|
+
'in_hash_mismatch'
|
|
110
|
+
];
|
|
111
|
+
/** Checkpoint-proposal validation failures that constitute a slashable invalid-checkpoint offense. */ export const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
112
|
+
// enabled
|
|
113
|
+
['invalid_fee_asset_price_modifier']: true,
|
|
114
|
+
['checkpoint_header_mismatch']: true,
|
|
115
|
+
// These late mismatches should normally be caught by earlier checks, but if reached after validating the local
|
|
116
|
+
// checkpoint inputs, the proposer-signed payload disagrees with deterministic recomputation.
|
|
117
|
+
['archive_mismatch']: true,
|
|
118
|
+
['out_hash_mismatch']: true,
|
|
119
|
+
['no_blocks_for_slot']: true,
|
|
120
|
+
['too_many_blocks_in_checkpoint']: true,
|
|
121
|
+
['checkpoint_validation_failed']: true,
|
|
122
|
+
['last_block_archive_mismatch']: true,
|
|
123
|
+
// disabled
|
|
124
|
+
['invalid_signature']: false,
|
|
125
|
+
['last_block_not_found']: false,
|
|
126
|
+
['block_fetch_error']: false,
|
|
127
|
+
['checkpoint_already_published']: false
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Handles block and checkpoint proposals for both validator and non-validator nodes. Also tracks which slots
|
|
131
|
+
* had a slashable invalid proposal or a proposal equivocation, exposing them via the
|
|
132
|
+
* `InvalidProposalSlotSource` interface consumed by the attested-invalid-proposal slashing watcher. The
|
|
133
|
+
* tracking is populated as a side effect of validating/re-executing proposals, so any node that re-executes
|
|
134
|
+
* proposals (the default) can serve it — not only validators.
|
|
135
|
+
*/ export class ProposalHandler {
|
|
102
136
|
checkpointsBuilder;
|
|
103
137
|
worldState;
|
|
104
138
|
blockSource;
|
|
@@ -121,6 +155,8 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
|
121
155
|
/** Returns current validator addresses for own-proposal detection. Set via register(). */ getOwnValidatorAddresses;
|
|
122
156
|
/** P2P proposal pool access for deciding when retained proposals should block archiver processing. */ p2pClient;
|
|
123
157
|
checkpointProposalValidationFailureCallback;
|
|
158
|
+
/** Slots at which a slashable invalid block or checkpoint proposal was observed. */ slotsWithInvalidProposals;
|
|
159
|
+
/** Slots at which a proposal equivocation was observed; suppresses attested-to-invalid-proposal slashing. */ slotsWithProposalEquivocation;
|
|
124
160
|
constructor(checkpointsBuilder, worldState, blockSource, l1ToL2MessageSource, txProvider, blockProposalValidator, epochCache, timetable, config, blobClient, reexecutionTracker, metrics, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator:proposal-handler')){
|
|
125
161
|
this.checkpointsBuilder = checkpointsBuilder;
|
|
126
162
|
this.worldState = worldState;
|
|
@@ -136,6 +172,8 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
|
136
172
|
this.metrics = metrics;
|
|
137
173
|
this.dateProvider = dateProvider;
|
|
138
174
|
this.log = log;
|
|
175
|
+
this.slotsWithInvalidProposals = FifoSet.withLimit(MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
|
|
176
|
+
this.slotsWithProposalEquivocation = FifoSet.withLimit(MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
|
|
139
177
|
if (config.fishermanMode) {
|
|
140
178
|
this.log = this.log.createChild('[FISHERMAN]');
|
|
141
179
|
}
|
|
@@ -163,6 +201,18 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
|
163
201
|
*/ recordOwnCheckpointProposalAsValid(slot, archive, checkpointNumber) {
|
|
164
202
|
this.reexecutionTracker.recordOutcome(slot, archive, 'valid', checkpointNumber);
|
|
165
203
|
}
|
|
204
|
+
/** Whether a slashable invalid block or checkpoint proposal was observed at the given slot (InvalidProposalSlotSource). */ hasInvalidProposals(slotNumber) {
|
|
205
|
+
return this.slotsWithInvalidProposals.has(slotNumber);
|
|
206
|
+
}
|
|
207
|
+
/** Whether a proposal equivocation was observed at the given slot (InvalidProposalSlotSource). */ hasProposalEquivocation(slotNumber) {
|
|
208
|
+
return this.slotsWithProposalEquivocation.has(slotNumber);
|
|
209
|
+
}
|
|
210
|
+
/** Records a slot as having a slashable invalid proposal, for offense observers (sentinel/slasher watchers). */ markInvalidProposalSlot(slotNumber) {
|
|
211
|
+
this.slotsWithInvalidProposals.add(slotNumber);
|
|
212
|
+
}
|
|
213
|
+
/** Records a slot as having a proposal equivocation, which suppresses attested-to-invalid-proposal slashing. */ markProposalEquivocation(slotNumber) {
|
|
214
|
+
this.slotsWithProposalEquivocation.add(slotNumber);
|
|
215
|
+
}
|
|
166
216
|
/**
|
|
167
217
|
* Registers handlers for block and checkpoint proposals on the p2p client.
|
|
168
218
|
* Records the p2p client so validation can inspect retained proposals.
|
|
@@ -191,6 +241,15 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
|
191
241
|
});
|
|
192
242
|
return true;
|
|
193
243
|
} else {
|
|
244
|
+
// Track invalid proposals / equivocations so offense observers (the attested-invalid-proposal
|
|
245
|
+
// watcher) work on non-validator nodes too. Validators populate these via their own handlers.
|
|
246
|
+
// Skip invalid-proposal marking while the escape hatch is open, matching the validator path,
|
|
247
|
+
// which intentionally disables invalid-block slashing then.
|
|
248
|
+
if (result.reason === 'checkpoint_proposal_equivocation') {
|
|
249
|
+
this.markProposalEquivocation(slotNumber);
|
|
250
|
+
} else if (SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT.includes(result.reason) && !await this.epochCache.isEscapeHatchOpenAtSlot(slotNumber)) {
|
|
251
|
+
this.markInvalidProposalSlot(slotNumber);
|
|
252
|
+
}
|
|
194
253
|
this.log.warn(`Non-validator block proposal ${blockNumber} at slot ${slotNumber} failed processing with ${result.reason}`, {
|
|
195
254
|
blockNumber: result.blockNumber,
|
|
196
255
|
slotNumber,
|
|
@@ -204,6 +263,10 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
|
204
263
|
}
|
|
205
264
|
};
|
|
206
265
|
p2pClient.registerBlockProposalHandler(blockHandler);
|
|
266
|
+
// p2p detects duplicate (equivocated) proposals without routing them through the handlers above, so mark
|
|
267
|
+
// the slot as equivocated here. This suppresses false-positive attested-to-invalid-proposal slashing on
|
|
268
|
+
// non-validator offense collectors. Validators overwrite this with their own richer handler.
|
|
269
|
+
p2pClient.registerDuplicateProposalCallback((info)=>this.markProposalEquivocation(info.slot));
|
|
207
270
|
// All-nodes checkpoint proposal handler: validates, caches, and sets proposed checkpoint for pipelining.
|
|
208
271
|
// Runs for all nodes (validators and non-validators). Validators get the cached result in the
|
|
209
272
|
// validator-specific callback (attestToCheckpointProposal) which runs after this one.
|
|
@@ -243,6 +306,12 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
|
243
306
|
}
|
|
244
307
|
const result = await this.handleCheckpointProposal(proposal, proposalInfo);
|
|
245
308
|
if (!result.isValid) {
|
|
309
|
+
// Track invalid checkpoint proposals so offense observers (the attested-invalid-proposal watcher)
|
|
310
|
+
// work on non-validator nodes too. This handler runs for all nodes; validators also mark via the
|
|
311
|
+
// failure callback below (idempotent).
|
|
312
|
+
if (SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT[result.reason]) {
|
|
313
|
+
this.markInvalidProposalSlot(proposal.slotNumber);
|
|
314
|
+
}
|
|
246
315
|
await this.checkpointProposalValidationFailureCallback?.(proposal, result, proposalInfo);
|
|
247
316
|
} else if (this.archiver) {
|
|
248
317
|
const set = await this.setProposedCheckpoint(proposal);
|
package/dest/validator.d.ts
CHANGED
|
@@ -55,11 +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;
|
|
60
59
|
private oversizedProposalOffenseKeys;
|
|
61
60
|
private badAttestationOffenseKeys;
|
|
62
|
-
private slotsWithProposalEquivocation;
|
|
63
61
|
/** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */
|
|
64
62
|
private lastAttestedProposal?;
|
|
65
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);
|
|
@@ -136,4 +134,4 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
136
134
|
private handleAuthRequest;
|
|
137
135
|
}
|
|
138
136
|
export {};
|
|
139
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
137
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFckUsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLGdCQUFnQixFQUFlLHFCQUFxQixFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ25ILE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUVqRSxPQUFPLEVBQUUsS0FBSyxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFHaEYsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzVELE9BQU8sS0FBSyxFQUEwRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRXRILE9BQU8sRUFJTCxLQUFLLE9BQU8sRUFDWixLQUFLLGNBQWMsRUFFcEIsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSwrQkFBK0IsRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkcsT0FBTyxLQUFLLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUU3RSxPQUFPLEtBQUssRUFDVixXQUFXLEVBQ1gsU0FBUyxFQUNULHlC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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,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAGhF,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAA0E,GAAG,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEtH,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,cAAc,EAEpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,+BAA+B,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACvG,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAE7E,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,kBAAkB,EAClB,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,EAE/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,MAAM,EAAsB,MAAM,yBAAyB,CAAC;AAMhG,OAAO,EAAY,KAAK,cAAc,EAAE,KAAK,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAClH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gDAAgD,CAAC;AAGxF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAEhD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAI1E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAG1E,OAAO,
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
|
package/dest/validator.js
CHANGED
|
@@ -19,40 +19,12 @@ import { ValidationService } from './duties/validation_service.js';
|
|
|
19
19
|
import { HAKeyStore } from './key_store/ha_key_store.js';
|
|
20
20
|
import { NodeKeystoreAdapter } from './key_store/node_keystore_adapter.js';
|
|
21
21
|
import { ValidatorMetrics } from './metrics.js';
|
|
22
|
-
import { ProposalHandler } from './proposal_handler.js';
|
|
22
|
+
import { ProposalHandler, SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT, SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT } from './proposal_handler.js';
|
|
23
23
|
// We maintain a set of proposers who have proposed invalid blocks.
|
|
24
24
|
// Just cap the set to avoid unbounded growth.
|
|
25
25
|
const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
26
|
-
const MAX_TRACKED_INVALID_PROPOSAL_SLOTS = 1000;
|
|
27
26
|
const MAX_TRACKED_INVALID_CHECKPOINT_PROPOSALS = 1000;
|
|
28
27
|
const MAX_TRACKED_BAD_ATTESTATIONS = 10_000;
|
|
29
|
-
// What errors from the block proposal handler result in slashing
|
|
30
|
-
const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
31
|
-
'state_mismatch',
|
|
32
|
-
'failed_txs',
|
|
33
|
-
'global_variables_mismatch',
|
|
34
|
-
'invalid_proposal',
|
|
35
|
-
'parent_block_wrong_slot',
|
|
36
|
-
'in_hash_mismatch'
|
|
37
|
-
];
|
|
38
|
-
const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
39
|
-
// enabled
|
|
40
|
-
['invalid_fee_asset_price_modifier']: true,
|
|
41
|
-
['checkpoint_header_mismatch']: true,
|
|
42
|
-
// These late mismatches should normally be caught by earlier checks, but if reached after validating the local
|
|
43
|
-
// checkpoint inputs, the proposer-signed payload disagrees with deterministic recomputation.
|
|
44
|
-
['archive_mismatch']: true,
|
|
45
|
-
['out_hash_mismatch']: true,
|
|
46
|
-
['no_blocks_for_slot']: true,
|
|
47
|
-
['too_many_blocks_in_checkpoint']: true,
|
|
48
|
-
['checkpoint_validation_failed']: true,
|
|
49
|
-
['last_block_archive_mismatch']: true,
|
|
50
|
-
// disabled
|
|
51
|
-
['invalid_signature']: false,
|
|
52
|
-
['last_block_not_found']: false,
|
|
53
|
-
['block_fetch_error']: false,
|
|
54
|
-
['checkpoint_already_published']: false
|
|
55
|
-
};
|
|
56
28
|
/**
|
|
57
29
|
* Validator Client
|
|
58
30
|
*/ export class ValidatorClient extends EventEmitter {
|
|
@@ -80,14 +52,12 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
80
52
|
epochCacheUpdateLoop;
|
|
81
53
|
/** Tracks the last epoch in which each attester successfully submitted at least one attestation. */ lastAttestedEpochByAttester;
|
|
82
54
|
proposersOfInvalidBlocks;
|
|
83
|
-
slotsWithInvalidProposals;
|
|
84
55
|
invalidCheckpointProposalOffenseKeys;
|
|
85
56
|
oversizedProposalOffenseKeys;
|
|
86
57
|
badAttestationOffenseKeys;
|
|
87
|
-
slotsWithProposalEquivocation;
|
|
88
58
|
/** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */ lastAttestedProposal;
|
|
89
59
|
constructor(keyStore, epochCache, p2pClient, proposalHandler, blockSource, checkpointsBuilder, worldState, l1ToL2MessageSource, config, blobClient, slashingProtectionSigner, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator')){
|
|
90
|
-
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);
|
|
91
61
|
// Create child logger with fisherman prefix if in fisherman mode
|
|
92
62
|
this.log = config.fishermanMode ? log.createChild('[FISHERMAN]') : log;
|
|
93
63
|
this.tracer = telemetry.getTracer('Validator');
|
|
@@ -217,10 +187,10 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
217
187
|
return this.config;
|
|
218
188
|
}
|
|
219
189
|
hasProposalEquivocation(slotNumber) {
|
|
220
|
-
return this.
|
|
190
|
+
return this.proposalHandler.hasProposalEquivocation(slotNumber);
|
|
221
191
|
}
|
|
222
192
|
hasInvalidProposals(slotNumber) {
|
|
223
|
-
return this.
|
|
193
|
+
return this.proposalHandler.hasInvalidProposals(slotNumber);
|
|
224
194
|
}
|
|
225
195
|
updateConfig(config) {
|
|
226
196
|
this.config = {
|
|
@@ -534,7 +504,8 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
534
504
|
if (!SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT[result.reason]) {
|
|
535
505
|
return;
|
|
536
506
|
}
|
|
537
|
-
this
|
|
507
|
+
// The slot is already marked invalid by the all-nodes checkpoint handler that invokes this callback,
|
|
508
|
+
// so we only emit the proposer slash event here.
|
|
538
509
|
if (this.slashInvalidCheckpointProposal(proposal)) {
|
|
539
510
|
this.log.info(`Detected invalid checkpoint proposal offense`, {
|
|
540
511
|
...proposalInfo,
|
|
@@ -569,11 +540,11 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
569
540
|
return true;
|
|
570
541
|
}
|
|
571
542
|
markInvalidProposalSlot(slotNumber) {
|
|
572
|
-
this.
|
|
543
|
+
this.proposalHandler.markInvalidProposalSlot(slotNumber);
|
|
573
544
|
}
|
|
574
545
|
handleCheckpointAttestation(attestation) {
|
|
575
546
|
const slotNumber = attestation.slotNumber;
|
|
576
|
-
if (!this.
|
|
547
|
+
if (!this.proposalHandler.hasInvalidProposals(slotNumber) || this.proposalHandler.hasProposalEquivocation(slotNumber)) {
|
|
577
548
|
return;
|
|
578
549
|
}
|
|
579
550
|
const attester = attestation.getSender();
|
|
@@ -637,7 +608,7 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
637
608
|
* Emits a slash event when a proposer sends multiple proposals for the same position.
|
|
638
609
|
*/ handleDuplicateProposal(info) {
|
|
639
610
|
const { slot, proposer, type } = info;
|
|
640
|
-
this.
|
|
611
|
+
this.proposalHandler.markProposalEquivocation(slot);
|
|
641
612
|
this.log.info(`Detected duplicate ${type} proposal offense from ${proposer.toString()} at slot ${slot}`, {
|
|
642
613
|
proposer: proposer.toString(),
|
|
643
614
|
slot,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/validator-client",
|
|
3
|
-
"version": "5.0.0-nightly.
|
|
3
|
+
"version": "5.0.0-nightly.20260624",
|
|
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": "5.0.0-nightly.
|
|
68
|
-
"@aztec/blob-lib": "5.0.0-nightly.
|
|
69
|
-
"@aztec/constants": "5.0.0-nightly.
|
|
70
|
-
"@aztec/epoch-cache": "5.0.0-nightly.
|
|
71
|
-
"@aztec/ethereum": "5.0.0-nightly.
|
|
72
|
-
"@aztec/foundation": "5.0.0-nightly.
|
|
73
|
-
"@aztec/node-keystore": "5.0.0-nightly.
|
|
74
|
-
"@aztec/noir-protocol-circuits-types": "5.0.0-nightly.
|
|
75
|
-
"@aztec/p2p": "5.0.0-nightly.
|
|
76
|
-
"@aztec/protocol-contracts": "5.0.0-nightly.
|
|
77
|
-
"@aztec/prover-client": "5.0.0-nightly.
|
|
78
|
-
"@aztec/simulator": "5.0.0-nightly.
|
|
79
|
-
"@aztec/slasher": "5.0.0-nightly.
|
|
80
|
-
"@aztec/stdlib": "5.0.0-nightly.
|
|
81
|
-
"@aztec/telemetry-client": "5.0.0-nightly.
|
|
82
|
-
"@aztec/validator-ha-signer": "5.0.0-nightly.
|
|
67
|
+
"@aztec/blob-client": "5.0.0-nightly.20260624",
|
|
68
|
+
"@aztec/blob-lib": "5.0.0-nightly.20260624",
|
|
69
|
+
"@aztec/constants": "5.0.0-nightly.20260624",
|
|
70
|
+
"@aztec/epoch-cache": "5.0.0-nightly.20260624",
|
|
71
|
+
"@aztec/ethereum": "5.0.0-nightly.20260624",
|
|
72
|
+
"@aztec/foundation": "5.0.0-nightly.20260624",
|
|
73
|
+
"@aztec/node-keystore": "5.0.0-nightly.20260624",
|
|
74
|
+
"@aztec/noir-protocol-circuits-types": "5.0.0-nightly.20260624",
|
|
75
|
+
"@aztec/p2p": "5.0.0-nightly.20260624",
|
|
76
|
+
"@aztec/protocol-contracts": "5.0.0-nightly.20260624",
|
|
77
|
+
"@aztec/prover-client": "5.0.0-nightly.20260624",
|
|
78
|
+
"@aztec/simulator": "5.0.0-nightly.20260624",
|
|
79
|
+
"@aztec/slasher": "5.0.0-nightly.20260624",
|
|
80
|
+
"@aztec/stdlib": "5.0.0-nightly.20260624",
|
|
81
|
+
"@aztec/telemetry-client": "5.0.0-nightly.20260624",
|
|
82
|
+
"@aztec/validator-ha-signer": "5.0.0-nightly.20260624",
|
|
83
83
|
"koa": "^2.16.1",
|
|
84
84
|
"koa-router": "^13.1.1",
|
|
85
85
|
"tslib": "^2.4.0",
|
|
86
86
|
"viem": "npm:@aztec/viem@2.38.2"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
|
-
"@aztec/archiver": "5.0.0-nightly.
|
|
90
|
-
"@aztec/world-state": "5.0.0-nightly.
|
|
89
|
+
"@aztec/archiver": "5.0.0-nightly.20260624",
|
|
90
|
+
"@aztec/world-state": "5.0.0-nightly.20260624",
|
|
91
91
|
"@electric-sql/pglite": "^0.3.14",
|
|
92
92
|
"@jest/globals": "^30.0.0",
|
|
93
93
|
"@types/jest": "^30.0.0",
|
package/src/proposal_handler.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { pick } from '@aztec/foundation/collection';
|
|
14
14
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
15
15
|
import { TimeoutError } from '@aztec/foundation/error';
|
|
16
|
+
import { FifoSet } from '@aztec/foundation/fifo-set';
|
|
16
17
|
import type { LogData } from '@aztec/foundation/log';
|
|
17
18
|
import { createLogger } from '@aztec/foundation/log';
|
|
18
19
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
@@ -152,7 +153,49 @@ type BlockProposalSlotValidationResult =
|
|
|
152
153
|
| { isValid: true }
|
|
153
154
|
| { isValid: false; reason: 'block_proposal_beyond_checkpoint' | 'checkpoint_proposal_equivocation' };
|
|
154
155
|
|
|
155
|
-
|
|
156
|
+
const MAX_TRACKED_INVALID_PROPOSAL_SLOTS = 1000;
|
|
157
|
+
|
|
158
|
+
/** Block-proposal validation failures that constitute a slashable invalid-block offense. */
|
|
159
|
+
export const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT: BlockProposalValidationFailureReason[] = [
|
|
160
|
+
'state_mismatch',
|
|
161
|
+
'failed_txs',
|
|
162
|
+
'global_variables_mismatch',
|
|
163
|
+
'invalid_proposal',
|
|
164
|
+
'parent_block_wrong_slot',
|
|
165
|
+
'in_hash_mismatch',
|
|
166
|
+
];
|
|
167
|
+
|
|
168
|
+
/** Checkpoint-proposal validation failures that constitute a slashable invalid-checkpoint offense. */
|
|
169
|
+
export const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT: Record<
|
|
170
|
+
CheckpointProposalValidationFailureReason,
|
|
171
|
+
boolean
|
|
172
|
+
> = {
|
|
173
|
+
// enabled
|
|
174
|
+
['invalid_fee_asset_price_modifier']: true,
|
|
175
|
+
['checkpoint_header_mismatch']: true,
|
|
176
|
+
// These late mismatches should normally be caught by earlier checks, but if reached after validating the local
|
|
177
|
+
// checkpoint inputs, the proposer-signed payload disagrees with deterministic recomputation.
|
|
178
|
+
['archive_mismatch']: true,
|
|
179
|
+
['out_hash_mismatch']: true,
|
|
180
|
+
['no_blocks_for_slot']: true,
|
|
181
|
+
['too_many_blocks_in_checkpoint']: true,
|
|
182
|
+
['checkpoint_validation_failed']: true,
|
|
183
|
+
['last_block_archive_mismatch']: true,
|
|
184
|
+
|
|
185
|
+
// disabled
|
|
186
|
+
['invalid_signature']: false,
|
|
187
|
+
['last_block_not_found']: false,
|
|
188
|
+
['block_fetch_error']: false,
|
|
189
|
+
['checkpoint_already_published']: false,
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Handles block and checkpoint proposals for both validator and non-validator nodes. Also tracks which slots
|
|
194
|
+
* had a slashable invalid proposal or a proposal equivocation, exposing them via the
|
|
195
|
+
* `InvalidProposalSlotSource` interface consumed by the attested-invalid-proposal slashing watcher. The
|
|
196
|
+
* tracking is populated as a side effect of validating/re-executing proposals, so any node that re-executes
|
|
197
|
+
* proposals (the default) can serve it — not only validators.
|
|
198
|
+
*/
|
|
156
199
|
export class ProposalHandler {
|
|
157
200
|
public readonly tracer: Tracer;
|
|
158
201
|
|
|
@@ -175,6 +218,12 @@ export class ProposalHandler {
|
|
|
175
218
|
|
|
176
219
|
private checkpointProposalValidationFailureCallback?: CheckpointProposalValidationFailureCallback;
|
|
177
220
|
|
|
221
|
+
/** Slots at which a slashable invalid block or checkpoint proposal was observed. */
|
|
222
|
+
private readonly slotsWithInvalidProposals = FifoSet.withLimit<SlotNumber>(MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
|
|
223
|
+
|
|
224
|
+
/** Slots at which a proposal equivocation was observed; suppresses attested-to-invalid-proposal slashing. */
|
|
225
|
+
private readonly slotsWithProposalEquivocation = FifoSet.withLimit<SlotNumber>(MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
|
|
226
|
+
|
|
178
227
|
constructor(
|
|
179
228
|
private checkpointsBuilder: FullNodeCheckpointsBuilder,
|
|
180
229
|
private worldState: WorldStateSynchronizer,
|
|
@@ -221,6 +270,26 @@ export class ProposalHandler {
|
|
|
221
270
|
this.reexecutionTracker.recordOutcome(slot, archive, 'valid', checkpointNumber);
|
|
222
271
|
}
|
|
223
272
|
|
|
273
|
+
/** Whether a slashable invalid block or checkpoint proposal was observed at the given slot (InvalidProposalSlotSource). */
|
|
274
|
+
public hasInvalidProposals(slotNumber: SlotNumber): boolean {
|
|
275
|
+
return this.slotsWithInvalidProposals.has(slotNumber);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Whether a proposal equivocation was observed at the given slot (InvalidProposalSlotSource). */
|
|
279
|
+
public hasProposalEquivocation(slotNumber: SlotNumber): boolean {
|
|
280
|
+
return this.slotsWithProposalEquivocation.has(slotNumber);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** Records a slot as having a slashable invalid proposal, for offense observers (sentinel/slasher watchers). */
|
|
284
|
+
public markInvalidProposalSlot(slotNumber: SlotNumber): void {
|
|
285
|
+
this.slotsWithInvalidProposals.add(slotNumber);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/** Records a slot as having a proposal equivocation, which suppresses attested-to-invalid-proposal slashing. */
|
|
289
|
+
public markProposalEquivocation(slotNumber: SlotNumber): void {
|
|
290
|
+
this.slotsWithProposalEquivocation.add(slotNumber);
|
|
291
|
+
}
|
|
292
|
+
|
|
224
293
|
/**
|
|
225
294
|
* Registers handlers for block and checkpoint proposals on the p2p client.
|
|
226
295
|
* Records the p2p client so validation can inspect retained proposals.
|
|
@@ -256,6 +325,18 @@ export class ProposalHandler {
|
|
|
256
325
|
});
|
|
257
326
|
return true;
|
|
258
327
|
} else {
|
|
328
|
+
// Track invalid proposals / equivocations so offense observers (the attested-invalid-proposal
|
|
329
|
+
// watcher) work on non-validator nodes too. Validators populate these via their own handlers.
|
|
330
|
+
// Skip invalid-proposal marking while the escape hatch is open, matching the validator path,
|
|
331
|
+
// which intentionally disables invalid-block slashing then.
|
|
332
|
+
if (result.reason === 'checkpoint_proposal_equivocation') {
|
|
333
|
+
this.markProposalEquivocation(slotNumber);
|
|
334
|
+
} else if (
|
|
335
|
+
SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT.includes(result.reason) &&
|
|
336
|
+
!(await this.epochCache.isEscapeHatchOpenAtSlot(slotNumber))
|
|
337
|
+
) {
|
|
338
|
+
this.markInvalidProposalSlot(slotNumber);
|
|
339
|
+
}
|
|
259
340
|
this.log.warn(
|
|
260
341
|
`Non-validator block proposal ${blockNumber} at slot ${slotNumber} failed processing with ${result.reason}`,
|
|
261
342
|
{ blockNumber: result.blockNumber, slotNumber, reason: result.reason },
|
|
@@ -270,6 +351,11 @@ export class ProposalHandler {
|
|
|
270
351
|
|
|
271
352
|
p2pClient.registerBlockProposalHandler(blockHandler);
|
|
272
353
|
|
|
354
|
+
// p2p detects duplicate (equivocated) proposals without routing them through the handlers above, so mark
|
|
355
|
+
// the slot as equivocated here. This suppresses false-positive attested-to-invalid-proposal slashing on
|
|
356
|
+
// non-validator offense collectors. Validators overwrite this with their own richer handler.
|
|
357
|
+
p2pClient.registerDuplicateProposalCallback(info => this.markProposalEquivocation(info.slot));
|
|
358
|
+
|
|
273
359
|
// All-nodes checkpoint proposal handler: validates, caches, and sets proposed checkpoint for pipelining.
|
|
274
360
|
// Runs for all nodes (validators and non-validators). Validators get the cached result in the
|
|
275
361
|
// validator-specific callback (attestToCheckpointProposal) which runs after this one.
|
|
@@ -318,6 +404,12 @@ export class ProposalHandler {
|
|
|
318
404
|
|
|
319
405
|
const result = await this.handleCheckpointProposal(proposal, proposalInfo);
|
|
320
406
|
if (!result.isValid) {
|
|
407
|
+
// Track invalid checkpoint proposals so offense observers (the attested-invalid-proposal watcher)
|
|
408
|
+
// work on non-validator nodes too. This handler runs for all nodes; validators also mark via the
|
|
409
|
+
// failure callback below (idempotent).
|
|
410
|
+
if (SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT[result.reason]) {
|
|
411
|
+
this.markInvalidProposalSlot(proposal.slotNumber);
|
|
412
|
+
}
|
|
321
413
|
await this.checkpointProposalValidationFailureCallback?.(proposal, result, proposalInfo);
|
|
322
414
|
} else if (this.archiver) {
|
|
323
415
|
const set = await this.setProposedCheckpoint(proposal);
|
package/src/validator.ts
CHANGED
|
@@ -66,48 +66,18 @@ import { NodeKeystoreAdapter } from './key_store/node_keystore_adapter.js';
|
|
|
66
66
|
import { ValidatorMetrics } from './metrics.js';
|
|
67
67
|
import {
|
|
68
68
|
type BlockProposalValidationFailureReason,
|
|
69
|
-
type CheckpointProposalValidationFailureReason,
|
|
70
69
|
type CheckpointProposalValidationFailureResult,
|
|
71
70
|
ProposalHandler,
|
|
71
|
+
SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT,
|
|
72
|
+
SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT,
|
|
72
73
|
} from './proposal_handler.js';
|
|
73
74
|
|
|
74
75
|
// We maintain a set of proposers who have proposed invalid blocks.
|
|
75
76
|
// Just cap the set to avoid unbounded growth.
|
|
76
77
|
const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
77
|
-
const MAX_TRACKED_INVALID_PROPOSAL_SLOTS = 1000;
|
|
78
78
|
const MAX_TRACKED_INVALID_CHECKPOINT_PROPOSALS = 1000;
|
|
79
79
|
const MAX_TRACKED_BAD_ATTESTATIONS = 10_000;
|
|
80
80
|
|
|
81
|
-
// What errors from the block proposal handler result in slashing
|
|
82
|
-
const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT: BlockProposalValidationFailureReason[] = [
|
|
83
|
-
'state_mismatch',
|
|
84
|
-
'failed_txs',
|
|
85
|
-
'global_variables_mismatch',
|
|
86
|
-
'invalid_proposal',
|
|
87
|
-
'parent_block_wrong_slot',
|
|
88
|
-
'in_hash_mismatch',
|
|
89
|
-
];
|
|
90
|
-
|
|
91
|
-
const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT: Record<CheckpointProposalValidationFailureReason, boolean> = {
|
|
92
|
-
// enabled
|
|
93
|
-
['invalid_fee_asset_price_modifier']: true,
|
|
94
|
-
['checkpoint_header_mismatch']: true,
|
|
95
|
-
// These late mismatches should normally be caught by earlier checks, but if reached after validating the local
|
|
96
|
-
// checkpoint inputs, the proposer-signed payload disagrees with deterministic recomputation.
|
|
97
|
-
['archive_mismatch']: true,
|
|
98
|
-
['out_hash_mismatch']: true,
|
|
99
|
-
['no_blocks_for_slot']: true,
|
|
100
|
-
['too_many_blocks_in_checkpoint']: true,
|
|
101
|
-
['checkpoint_validation_failed']: true,
|
|
102
|
-
['last_block_archive_mismatch']: true,
|
|
103
|
-
|
|
104
|
-
// disabled
|
|
105
|
-
['invalid_signature']: false,
|
|
106
|
-
['last_block_not_found']: false,
|
|
107
|
-
['block_fetch_error']: false,
|
|
108
|
-
['checkpoint_already_published']: false,
|
|
109
|
-
};
|
|
110
|
-
|
|
111
81
|
/**
|
|
112
82
|
* Validator Client
|
|
113
83
|
*/
|
|
@@ -131,11 +101,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
131
101
|
private lastAttestedEpochByAttester: Map<string, EpochNumber> = new Map();
|
|
132
102
|
|
|
133
103
|
private proposersOfInvalidBlocks = FifoSet.withLimit<string>(MAX_PROPOSERS_OF_INVALID_BLOCKS);
|
|
134
|
-
private slotsWithInvalidProposals = FifoSet.withLimit<SlotNumber>(MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
|
|
135
104
|
private invalidCheckpointProposalOffenseKeys = FifoSet.withLimit<string>(MAX_TRACKED_INVALID_CHECKPOINT_PROPOSALS);
|
|
136
105
|
private oversizedProposalOffenseKeys = FifoSet.withLimit<string>(MAX_TRACKED_INVALID_CHECKPOINT_PROPOSALS);
|
|
137
106
|
private badAttestationOffenseKeys = FifoSet.withLimit<string>(MAX_TRACKED_BAD_ATTESTATIONS);
|
|
138
|
-
private slotsWithProposalEquivocation = FifoSet.withLimit<SlotNumber>(MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
|
|
139
107
|
|
|
140
108
|
/** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */
|
|
141
109
|
private lastAttestedProposal?: CheckpointProposalCore;
|
|
@@ -364,11 +332,11 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
364
332
|
}
|
|
365
333
|
|
|
366
334
|
public hasProposalEquivocation(slotNumber: SlotNumber): boolean {
|
|
367
|
-
return this.
|
|
335
|
+
return this.proposalHandler.hasProposalEquivocation(slotNumber);
|
|
368
336
|
}
|
|
369
337
|
|
|
370
338
|
public hasInvalidProposals(slotNumber: SlotNumber): boolean {
|
|
371
|
-
return this.
|
|
339
|
+
return this.proposalHandler.hasInvalidProposals(slotNumber);
|
|
372
340
|
}
|
|
373
341
|
|
|
374
342
|
public updateConfig(config: Partial<ValidatorClientFullConfig>) {
|
|
@@ -771,8 +739,8 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
771
739
|
return;
|
|
772
740
|
}
|
|
773
741
|
|
|
774
|
-
this
|
|
775
|
-
|
|
742
|
+
// The slot is already marked invalid by the all-nodes checkpoint handler that invokes this callback,
|
|
743
|
+
// so we only emit the proposer slash event here.
|
|
776
744
|
if (this.slashInvalidCheckpointProposal(proposal)) {
|
|
777
745
|
this.log.info(`Detected invalid checkpoint proposal offense`, {
|
|
778
746
|
...proposalInfo,
|
|
@@ -811,12 +779,15 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
811
779
|
}
|
|
812
780
|
|
|
813
781
|
private markInvalidProposalSlot(slotNumber: SlotNumber): void {
|
|
814
|
-
this.
|
|
782
|
+
this.proposalHandler.markInvalidProposalSlot(slotNumber);
|
|
815
783
|
}
|
|
816
784
|
|
|
817
785
|
private handleCheckpointAttestation(attestation: CheckpointAttestation): void {
|
|
818
786
|
const slotNumber = attestation.slotNumber;
|
|
819
|
-
if (
|
|
787
|
+
if (
|
|
788
|
+
!this.proposalHandler.hasInvalidProposals(slotNumber) ||
|
|
789
|
+
this.proposalHandler.hasProposalEquivocation(slotNumber)
|
|
790
|
+
) {
|
|
820
791
|
return;
|
|
821
792
|
}
|
|
822
793
|
|
|
@@ -891,7 +862,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
891
862
|
*/
|
|
892
863
|
private handleDuplicateProposal(info: DuplicateProposalInfo): void {
|
|
893
864
|
const { slot, proposer, type } = info;
|
|
894
|
-
this.
|
|
865
|
+
this.proposalHandler.markProposalEquivocation(slot);
|
|
895
866
|
|
|
896
867
|
this.log.info(`Detected duplicate ${type} proposal offense from ${proposer.toString()} at slot ${slot}`, {
|
|
897
868
|
proposer: proposer.toString(),
|