@aztec/validator-client 5.0.0-nightly.20260528 → 5.0.0-nightly.20260529
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/validator.d.ts +5 -4
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +41 -42
- package/package.json +19 -19
- package/src/validator.ts +39 -56
package/dest/validator.d.ts
CHANGED
|
@@ -55,10 +55,10 @@ 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
|
|
58
|
+
private slotsWithInvalidProposals;
|
|
59
59
|
private invalidCheckpointProposalOffenseKeys;
|
|
60
|
-
private slotsWithProposalEquivocation;
|
|
61
60
|
private badAttestationOffenseKeys;
|
|
61
|
+
private slotsWithProposalEquivocation;
|
|
62
62
|
/** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */
|
|
63
63
|
private lastAttestedProposal?;
|
|
64
64
|
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);
|
|
@@ -72,6 +72,8 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
72
72
|
getCoinbaseForAttestor(attestor: EthAddress): EthAddress;
|
|
73
73
|
getFeeRecipientForAttestor(attestor: EthAddress): AztecAddress;
|
|
74
74
|
getConfig(): ValidatorClientFullConfig;
|
|
75
|
+
hasProposalEquivocation(slotNumber: SlotNumber): boolean;
|
|
76
|
+
hasInvalidProposals(slotNumber: SlotNumber): boolean;
|
|
75
77
|
updateConfig(config: Partial<ValidatorClientFullConfig>): void;
|
|
76
78
|
reloadKeystore(newManager: KeystoreManager): void;
|
|
77
79
|
start(): Promise<void>;
|
|
@@ -117,7 +119,6 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
117
119
|
* Emits a slash event when an attester signs attestations for different proposals at the same slot.
|
|
118
120
|
*/
|
|
119
121
|
private handleDuplicateAttestation;
|
|
120
|
-
private getSlotKey;
|
|
121
122
|
createBlockProposal(blockHeader: BlockHeader, checkpointNumber: CheckpointNumber, indexWithinCheckpoint: IndexWithinCheckpoint, inHash: Fr, archive: Fr, txs: Tx[], proposerAddress: EthAddress | undefined, options?: BlockProposalOptions): Promise<BlockProposal>;
|
|
122
123
|
createCheckpointProposal(checkpointHeader: CheckpointHeader, archive: Fr, checkpointNumber: CheckpointNumber, feeAssetPriceModifier: bigint, lastBlockProposal: BlockProposal | undefined, proposerAddress: EthAddress | undefined, options?: CheckpointProposalOptions): Promise<CheckpointProposal>;
|
|
123
124
|
broadcastBlockProposal(proposal: BlockProposal): Promise<void>;
|
|
@@ -127,4 +128,4 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
127
128
|
private handleAuthRequest;
|
|
128
129
|
}
|
|
129
130
|
export {};
|
|
130
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
131
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFckUsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLGdCQUFnQixFQUFlLHFCQUFxQixFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ25ILE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUVqRSxPQUFPLEVBQUUsS0FBSyxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFHaEYsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzVELE9BQU8sS0FBSyxFQUFtRCxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRS9GLE9BQU8sRUFJTCxLQUFLLE9BQU8sRUFDWixLQUFLLGNBQWMsRUFFcEIsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSwrQkFBK0IsRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkcsT0FBTyxLQUFLLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUU3RSxPQUFPLEtBQUssRUFDVixXQUFXLEVBQ1gsU0FBUyxFQUNULHlC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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,EAAmD,GAAG,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAE/F,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,cAAc,
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
|
package/dest/validator.js
CHANGED
|
@@ -6,7 +6,7 @@ import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
|
6
6
|
import { sleep } from '@aztec/foundation/sleep';
|
|
7
7
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
8
8
|
import { AuthRequest, AuthResponse, BlockProposalValidator, ReqRespSubProtocol } from '@aztec/p2p';
|
|
9
|
-
import { OffenseType, WANT_TO_CLEAR_SLASH_EVENT, WANT_TO_SLASH_EVENT } from '@aztec/slasher';
|
|
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
11
|
import { AttestationTimeoutError } from '@aztec/stdlib/validators';
|
|
12
12
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
@@ -78,13 +78,13 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
78
78
|
epochCacheUpdateLoop;
|
|
79
79
|
/** Tracks the last epoch in which each attester successfully submitted at least one attestation. */ lastAttestedEpochByAttester;
|
|
80
80
|
proposersOfInvalidBlocks;
|
|
81
|
-
|
|
81
|
+
slotsWithInvalidProposals;
|
|
82
82
|
invalidCheckpointProposalOffenseKeys;
|
|
83
|
-
slotsWithProposalEquivocation;
|
|
84
83
|
badAttestationOffenseKeys;
|
|
84
|
+
slotsWithProposalEquivocation;
|
|
85
85
|
/** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */ lastAttestedProposal;
|
|
86
86
|
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.
|
|
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.slotsWithInvalidProposals = FifoSet.withLimit(MAX_TRACKED_INVALID_PROPOSAL_SLOTS), this.invalidCheckpointProposalOffenseKeys = FifoSet.withLimit(MAX_TRACKED_INVALID_CHECKPOINT_PROPOSALS), this.badAttestationOffenseKeys = FifoSet.withLimit(MAX_TRACKED_BAD_ATTESTATIONS), this.slotsWithProposalEquivocation = FifoSet.withLimit(MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
|
|
88
88
|
// Create child logger with fisherman prefix if in fisherman mode
|
|
89
89
|
this.log = config.fishermanMode ? log.createChild('[FISHERMAN]') : log;
|
|
90
90
|
this.tracer = telemetry.getTracer('Validator');
|
|
@@ -208,6 +208,12 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
208
208
|
getConfig() {
|
|
209
209
|
return this.config;
|
|
210
210
|
}
|
|
211
|
+
hasProposalEquivocation(slotNumber) {
|
|
212
|
+
return this.slotsWithProposalEquivocation.has(slotNumber);
|
|
213
|
+
}
|
|
214
|
+
hasInvalidProposals(slotNumber) {
|
|
215
|
+
return this.slotsWithInvalidProposals.has(slotNumber);
|
|
216
|
+
}
|
|
211
217
|
updateConfig(config) {
|
|
212
218
|
this.config = {
|
|
213
219
|
...this.config,
|
|
@@ -302,11 +308,8 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
302
308
|
txHashes: proposal.txHashes.map((t)=>t.toString()),
|
|
303
309
|
fishermanMode: this.config.fishermanMode || false
|
|
304
310
|
});
|
|
305
|
-
// Reexecute
|
|
306
|
-
|
|
307
|
-
const { slashBroadcastedInvalidBlockPenalty, slashAttestInvalidCheckpointProposalPenalty, alwaysReexecuteBlockProposals, fishermanMode } = this.config;
|
|
308
|
-
const shouldReexecute = fishermanMode || slashBroadcastedInvalidBlockPenalty > 0n || slashAttestInvalidCheckpointProposalPenalty > 0n || partOfCommittee || alwaysReexecuteBlockProposals || this.blobClient.canUpload();
|
|
309
|
-
const validationResult = await this.proposalHandler.handleBlockProposal(proposal, proposalSender, !!shouldReexecute && !escapeHatchOpen);
|
|
311
|
+
// Reexecute outside the escape hatch so slashing observers can detect invalid proposals even when penalties are 0.
|
|
312
|
+
const validationResult = await this.proposalHandler.handleBlockProposal(proposal, proposalSender, !escapeHatchOpen);
|
|
310
313
|
if (!validationResult.isValid) {
|
|
311
314
|
const reason = validationResult.reason || 'unknown';
|
|
312
315
|
this.log.warn(`Block proposal validation failed: ${reason}`, proposalInfo);
|
|
@@ -325,13 +328,13 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
325
328
|
this.metrics.incFailedAttestationsNodeIssue(1, reason, partOfCommittee);
|
|
326
329
|
}
|
|
327
330
|
if (!escapeHatchOpen && validationResult.reason && SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT.includes(validationResult.reason)) {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
this.
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
331
|
+
this.log.info(`Detected invalid block proposal offense`, {
|
|
332
|
+
...proposalInfo,
|
|
333
|
+
amount: this.config.slashBroadcastedInvalidBlockPenalty,
|
|
334
|
+
offenseType: getOffenseTypeName(OffenseType.BROADCASTED_INVALID_BLOCK_PROPOSAL)
|
|
335
|
+
});
|
|
336
|
+
this.slashInvalidBlock(proposal);
|
|
337
|
+
this.markInvalidProposalSlot(proposal.slotNumber);
|
|
335
338
|
}
|
|
336
339
|
return false;
|
|
337
340
|
}
|
|
@@ -519,17 +522,17 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
519
522
|
if (!SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT[result.reason]) {
|
|
520
523
|
return;
|
|
521
524
|
}
|
|
525
|
+
this.markInvalidProposalSlot(proposal.slotNumber);
|
|
522
526
|
if (this.slashInvalidCheckpointProposal(proposal)) {
|
|
523
|
-
this.log.
|
|
527
|
+
this.log.info(`Detected invalid checkpoint proposal offense`, {
|
|
524
528
|
...proposalInfo,
|
|
525
|
-
reason: result.reason
|
|
529
|
+
reason: result.reason,
|
|
530
|
+
amount: this.config.slashBroadcastedInvalidCheckpointProposalPenalty,
|
|
531
|
+
offenseType: getOffenseTypeName(OffenseType.BROADCASTED_INVALID_CHECKPOINT_PROPOSAL)
|
|
526
532
|
});
|
|
527
533
|
}
|
|
528
534
|
}
|
|
529
535
|
slashInvalidCheckpointProposal(proposal) {
|
|
530
|
-
if (this.config.slashBroadcastedInvalidCheckpointProposalPenalty <= 0n) {
|
|
531
|
-
return false;
|
|
532
|
-
}
|
|
533
536
|
const proposer = proposal.getSender();
|
|
534
537
|
if (!proposer) {
|
|
535
538
|
this.log.warn(`Cannot slash checkpoint proposal with invalid signature`, {
|
|
@@ -539,7 +542,7 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
539
542
|
return false;
|
|
540
543
|
}
|
|
541
544
|
const offenseType = OffenseType.BROADCASTED_INVALID_CHECKPOINT_PROPOSAL;
|
|
542
|
-
const offenseKey = `${proposer.toString()}:${offenseType}:${
|
|
545
|
+
const offenseKey = `${proposer.toString()}:${offenseType}:${proposal.slotNumber}`;
|
|
543
546
|
if (!this.invalidCheckpointProposalOffenseKeys.addIfAbsent(offenseKey)) {
|
|
544
547
|
return false;
|
|
545
548
|
}
|
|
@@ -554,13 +557,11 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
554
557
|
return true;
|
|
555
558
|
}
|
|
556
559
|
markInvalidProposalSlot(slotNumber) {
|
|
557
|
-
|
|
558
|
-
this.slotsWithInvalidBlockProposals.add(slotKey);
|
|
560
|
+
this.slotsWithInvalidProposals.add(slotNumber);
|
|
559
561
|
}
|
|
560
562
|
handleCheckpointAttestation(attestation) {
|
|
561
563
|
const slotNumber = attestation.slotNumber;
|
|
562
|
-
|
|
563
|
-
if (!this.slotsWithInvalidBlockProposals.has(slotKey) || this.slotsWithProposalEquivocation.has(slotKey)) {
|
|
564
|
+
if (!this.slotsWithInvalidProposals.has(slotNumber) || this.slotsWithProposalEquivocation.has(slotNumber)) {
|
|
564
565
|
return;
|
|
565
566
|
}
|
|
566
567
|
const attester = attestation.getSender();
|
|
@@ -574,16 +575,15 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
574
575
|
this.slashAttestedToInvalidCheckpointProposal(slotNumber, attester);
|
|
575
576
|
}
|
|
576
577
|
slashAttestedToInvalidCheckpointProposal(slotNumber, attester) {
|
|
577
|
-
|
|
578
|
-
return;
|
|
579
|
-
}
|
|
580
|
-
const offenseKey = `${this.getSlotKey(slotNumber)}:${attester.toString()}`;
|
|
578
|
+
const offenseKey = `${attester.toString()}:${OffenseType.ATTESTED_TO_INVALID_CHECKPOINT_PROPOSAL}:${slotNumber}`;
|
|
581
579
|
if (!this.badAttestationOffenseKeys.addIfAbsent(offenseKey)) {
|
|
582
580
|
return;
|
|
583
581
|
}
|
|
584
|
-
this.log.
|
|
582
|
+
this.log.info(`Detected attestation to invalid checkpoint proposal offense`, {
|
|
585
583
|
attester: attester.toString(),
|
|
586
|
-
slotNumber
|
|
584
|
+
slotNumber,
|
|
585
|
+
amount: this.config.slashAttestInvalidCheckpointProposalPenalty,
|
|
586
|
+
offenseType: getOffenseTypeName(OffenseType.ATTESTED_TO_INVALID_CHECKPOINT_PROPOSAL)
|
|
587
587
|
});
|
|
588
588
|
this.emit(WANT_TO_SLASH_EVENT, [
|
|
589
589
|
{
|
|
@@ -599,14 +599,14 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
599
599
|
* Emits a slash event when a proposer sends multiple proposals for the same position.
|
|
600
600
|
*/ handleDuplicateProposal(info) {
|
|
601
601
|
const { slot, proposer, type } = info;
|
|
602
|
-
|
|
603
|
-
this.
|
|
604
|
-
this.log.warn(`Triggering slash event for duplicate ${type} proposal from ${proposer.toString()} at slot ${slot}`, {
|
|
602
|
+
this.slotsWithProposalEquivocation.add(slot);
|
|
603
|
+
this.log.info(`Detected duplicate ${type} proposal offense from ${proposer.toString()} at slot ${slot}`, {
|
|
605
604
|
proposer: proposer.toString(),
|
|
606
605
|
slot,
|
|
607
|
-
type
|
|
606
|
+
type,
|
|
607
|
+
amount: this.config.slashDuplicateProposalPenalty,
|
|
608
|
+
offenseType: getOffenseTypeName(OffenseType.DUPLICATE_PROPOSAL)
|
|
608
609
|
});
|
|
609
|
-
// Emit slash event
|
|
610
610
|
this.emit(WANT_TO_SLASH_EVENT, [
|
|
611
611
|
{
|
|
612
612
|
validator: proposer,
|
|
@@ -627,9 +627,11 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
627
627
|
* Emits a slash event when an attester signs attestations for different proposals at the same slot.
|
|
628
628
|
*/ handleDuplicateAttestation(info) {
|
|
629
629
|
const { slot, attester } = info;
|
|
630
|
-
this.log.
|
|
630
|
+
this.log.info(`Detected duplicate attestation offense from ${attester.toString()} at slot ${slot}`, {
|
|
631
631
|
attester: attester.toString(),
|
|
632
|
-
slot
|
|
632
|
+
slot,
|
|
633
|
+
amount: this.config.slashDuplicateAttestationPenalty,
|
|
634
|
+
offenseType: getOffenseTypeName(OffenseType.DUPLICATE_ATTESTATION)
|
|
633
635
|
});
|
|
634
636
|
this.emit(WANT_TO_SLASH_EVENT, [
|
|
635
637
|
{
|
|
@@ -640,9 +642,6 @@ const SLASHABLE_CHECKPOINT_PROPOSAL_VALIDATION_RESULT = {
|
|
|
640
642
|
}
|
|
641
643
|
]);
|
|
642
644
|
}
|
|
643
|
-
getSlotKey(slot) {
|
|
644
|
-
return slot.toString();
|
|
645
|
-
}
|
|
646
645
|
async createBlockProposal(blockHeader, checkpointNumber, indexWithinCheckpoint, inHash, archive, txs, proposerAddress, options = {}) {
|
|
647
646
|
// Validate that we're not creating a proposal for an older or equal position
|
|
648
647
|
if (this.lastProposedBlock) {
|
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.20260529",
|
|
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.20260529",
|
|
68
|
+
"@aztec/blob-lib": "5.0.0-nightly.20260529",
|
|
69
|
+
"@aztec/constants": "5.0.0-nightly.20260529",
|
|
70
|
+
"@aztec/epoch-cache": "5.0.0-nightly.20260529",
|
|
71
|
+
"@aztec/ethereum": "5.0.0-nightly.20260529",
|
|
72
|
+
"@aztec/foundation": "5.0.0-nightly.20260529",
|
|
73
|
+
"@aztec/node-keystore": "5.0.0-nightly.20260529",
|
|
74
|
+
"@aztec/noir-protocol-circuits-types": "5.0.0-nightly.20260529",
|
|
75
|
+
"@aztec/p2p": "5.0.0-nightly.20260529",
|
|
76
|
+
"@aztec/protocol-contracts": "5.0.0-nightly.20260529",
|
|
77
|
+
"@aztec/prover-client": "5.0.0-nightly.20260529",
|
|
78
|
+
"@aztec/simulator": "5.0.0-nightly.20260529",
|
|
79
|
+
"@aztec/slasher": "5.0.0-nightly.20260529",
|
|
80
|
+
"@aztec/stdlib": "5.0.0-nightly.20260529",
|
|
81
|
+
"@aztec/telemetry-client": "5.0.0-nightly.20260529",
|
|
82
|
+
"@aztec/validator-ha-signer": "5.0.0-nightly.20260529",
|
|
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.20260529",
|
|
90
|
+
"@aztec/world-state": "5.0.0-nightly.20260529",
|
|
91
91
|
"@electric-sql/pglite": "^0.3.14",
|
|
92
92
|
"@jest/globals": "^30.0.0",
|
|
93
93
|
"@types/jest": "^30.0.0",
|
package/src/validator.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
WANT_TO_SLASH_EVENT,
|
|
20
20
|
type Watcher,
|
|
21
21
|
type WatcherEmitter,
|
|
22
|
+
getOffenseTypeName,
|
|
22
23
|
} from '@aztec/slasher';
|
|
23
24
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
24
25
|
import type { CommitteeAttestationsAndSigners, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
@@ -128,10 +129,10 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
128
129
|
private lastAttestedEpochByAttester: Map<string, EpochNumber> = new Map();
|
|
129
130
|
|
|
130
131
|
private proposersOfInvalidBlocks = FifoSet.withLimit<string>(MAX_PROPOSERS_OF_INVALID_BLOCKS);
|
|
131
|
-
private
|
|
132
|
+
private slotsWithInvalidProposals = FifoSet.withLimit<SlotNumber>(MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
|
|
132
133
|
private invalidCheckpointProposalOffenseKeys = FifoSet.withLimit<string>(MAX_TRACKED_INVALID_CHECKPOINT_PROPOSALS);
|
|
133
|
-
private slotsWithProposalEquivocation = FifoSet.withLimit<string>(MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
|
|
134
134
|
private badAttestationOffenseKeys = FifoSet.withLimit<string>(MAX_TRACKED_BAD_ATTESTATIONS);
|
|
135
|
+
private slotsWithProposalEquivocation = FifoSet.withLimit<SlotNumber>(MAX_TRACKED_INVALID_PROPOSAL_SLOTS);
|
|
135
136
|
|
|
136
137
|
/** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */
|
|
137
138
|
private lastAttestedProposal?: CheckpointProposalCore;
|
|
@@ -171,7 +172,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
171
172
|
|
|
172
173
|
// Refresh epoch cache every second to trigger alert if participation in committee changes
|
|
173
174
|
this.epochCacheUpdateLoop = new RunningPromise(this.handleEpochCommitteeUpdate.bind(this), this.log, 1000);
|
|
174
|
-
|
|
175
175
|
const myAddresses = this.getValidatorAddresses();
|
|
176
176
|
this.log.verbose(`Initialized validator with addresses: ${myAddresses.map(a => a.toString()).join(', ')}`);
|
|
177
177
|
}
|
|
@@ -354,6 +354,14 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
354
354
|
return this.config;
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
+
public hasProposalEquivocation(slotNumber: SlotNumber): boolean {
|
|
358
|
+
return this.slotsWithProposalEquivocation.has(slotNumber);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
public hasInvalidProposals(slotNumber: SlotNumber): boolean {
|
|
362
|
+
return this.slotsWithInvalidProposals.has(slotNumber);
|
|
363
|
+
}
|
|
364
|
+
|
|
357
365
|
public updateConfig(config: Partial<ValidatorClientFullConfig>) {
|
|
358
366
|
this.config = { ...this.config, ...config };
|
|
359
367
|
this.proposalHandler.updateConfig(config);
|
|
@@ -475,27 +483,8 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
475
483
|
fishermanMode: this.config.fishermanMode || false,
|
|
476
484
|
});
|
|
477
485
|
|
|
478
|
-
// Reexecute
|
|
479
|
-
|
|
480
|
-
const {
|
|
481
|
-
slashBroadcastedInvalidBlockPenalty,
|
|
482
|
-
slashAttestInvalidCheckpointProposalPenalty,
|
|
483
|
-
alwaysReexecuteBlockProposals,
|
|
484
|
-
fishermanMode,
|
|
485
|
-
} = this.config;
|
|
486
|
-
const shouldReexecute =
|
|
487
|
-
fishermanMode ||
|
|
488
|
-
slashBroadcastedInvalidBlockPenalty > 0n ||
|
|
489
|
-
slashAttestInvalidCheckpointProposalPenalty > 0n ||
|
|
490
|
-
partOfCommittee ||
|
|
491
|
-
alwaysReexecuteBlockProposals ||
|
|
492
|
-
this.blobClient.canUpload();
|
|
493
|
-
|
|
494
|
-
const validationResult = await this.proposalHandler.handleBlockProposal(
|
|
495
|
-
proposal,
|
|
496
|
-
proposalSender,
|
|
497
|
-
!!shouldReexecute && !escapeHatchOpen,
|
|
498
|
-
);
|
|
486
|
+
// Reexecute outside the escape hatch so slashing observers can detect invalid proposals even when penalties are 0.
|
|
487
|
+
const validationResult = await this.proposalHandler.handleBlockProposal(proposal, proposalSender, !escapeHatchOpen);
|
|
499
488
|
|
|
500
489
|
if (!validationResult.isValid) {
|
|
501
490
|
const reason = validationResult.reason || 'unknown';
|
|
@@ -523,13 +512,13 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
523
512
|
validationResult.reason &&
|
|
524
513
|
SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT.includes(validationResult.reason)
|
|
525
514
|
) {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
this.
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
515
|
+
this.log.info(`Detected invalid block proposal offense`, {
|
|
516
|
+
...proposalInfo,
|
|
517
|
+
amount: this.config.slashBroadcastedInvalidBlockPenalty,
|
|
518
|
+
offenseType: getOffenseTypeName(OffenseType.BROADCASTED_INVALID_BLOCK_PROPOSAL),
|
|
519
|
+
});
|
|
520
|
+
this.slashInvalidBlock(proposal);
|
|
521
|
+
this.markInvalidProposalSlot(proposal.slotNumber);
|
|
533
522
|
}
|
|
534
523
|
return false;
|
|
535
524
|
}
|
|
@@ -768,19 +757,19 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
768
757
|
return;
|
|
769
758
|
}
|
|
770
759
|
|
|
760
|
+
this.markInvalidProposalSlot(proposal.slotNumber);
|
|
761
|
+
|
|
771
762
|
if (this.slashInvalidCheckpointProposal(proposal)) {
|
|
772
|
-
this.log.
|
|
763
|
+
this.log.info(`Detected invalid checkpoint proposal offense`, {
|
|
773
764
|
...proposalInfo,
|
|
774
765
|
reason: result.reason,
|
|
766
|
+
amount: this.config.slashBroadcastedInvalidCheckpointProposalPenalty,
|
|
767
|
+
offenseType: getOffenseTypeName(OffenseType.BROADCASTED_INVALID_CHECKPOINT_PROPOSAL),
|
|
775
768
|
});
|
|
776
769
|
}
|
|
777
770
|
}
|
|
778
771
|
|
|
779
772
|
private slashInvalidCheckpointProposal(proposal: CheckpointProposalCore): boolean {
|
|
780
|
-
if (this.config.slashBroadcastedInvalidCheckpointProposalPenalty <= 0n) {
|
|
781
|
-
return false;
|
|
782
|
-
}
|
|
783
|
-
|
|
784
773
|
const proposer = proposal.getSender();
|
|
785
774
|
if (!proposer) {
|
|
786
775
|
this.log.warn(`Cannot slash checkpoint proposal with invalid signature`, {
|
|
@@ -791,7 +780,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
791
780
|
}
|
|
792
781
|
|
|
793
782
|
const offenseType = OffenseType.BROADCASTED_INVALID_CHECKPOINT_PROPOSAL;
|
|
794
|
-
const offenseKey = `${proposer.toString()}:${offenseType}:${
|
|
783
|
+
const offenseKey = `${proposer.toString()}:${offenseType}:${proposal.slotNumber}`;
|
|
795
784
|
if (!this.invalidCheckpointProposalOffenseKeys.addIfAbsent(offenseKey)) {
|
|
796
785
|
return false;
|
|
797
786
|
}
|
|
@@ -808,14 +797,12 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
808
797
|
}
|
|
809
798
|
|
|
810
799
|
private markInvalidProposalSlot(slotNumber: SlotNumber): void {
|
|
811
|
-
|
|
812
|
-
this.slotsWithInvalidBlockProposals.add(slotKey);
|
|
800
|
+
this.slotsWithInvalidProposals.add(slotNumber);
|
|
813
801
|
}
|
|
814
802
|
|
|
815
803
|
private handleCheckpointAttestation(attestation: CheckpointAttestation): void {
|
|
816
804
|
const slotNumber = attestation.slotNumber;
|
|
817
|
-
|
|
818
|
-
if (!this.slotsWithInvalidBlockProposals.has(slotKey) || this.slotsWithProposalEquivocation.has(slotKey)) {
|
|
805
|
+
if (!this.slotsWithInvalidProposals.has(slotNumber) || this.slotsWithProposalEquivocation.has(slotNumber)) {
|
|
819
806
|
return;
|
|
820
807
|
}
|
|
821
808
|
|
|
@@ -832,18 +819,16 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
832
819
|
}
|
|
833
820
|
|
|
834
821
|
private slashAttestedToInvalidCheckpointProposal(slotNumber: SlotNumber, attester: EthAddress): void {
|
|
835
|
-
|
|
836
|
-
return;
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
const offenseKey = `${this.getSlotKey(slotNumber)}:${attester.toString()}`;
|
|
822
|
+
const offenseKey = `${attester.toString()}:${OffenseType.ATTESTED_TO_INVALID_CHECKPOINT_PROPOSAL}:${slotNumber}`;
|
|
840
823
|
if (!this.badAttestationOffenseKeys.addIfAbsent(offenseKey)) {
|
|
841
824
|
return;
|
|
842
825
|
}
|
|
843
826
|
|
|
844
|
-
this.log.
|
|
827
|
+
this.log.info(`Detected attestation to invalid checkpoint proposal offense`, {
|
|
845
828
|
attester: attester.toString(),
|
|
846
829
|
slotNumber,
|
|
830
|
+
amount: this.config.slashAttestInvalidCheckpointProposalPenalty,
|
|
831
|
+
offenseType: getOffenseTypeName(OffenseType.ATTESTED_TO_INVALID_CHECKPOINT_PROPOSAL),
|
|
847
832
|
});
|
|
848
833
|
|
|
849
834
|
this.emit(WANT_TO_SLASH_EVENT, [
|
|
@@ -862,16 +847,16 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
862
847
|
*/
|
|
863
848
|
private handleDuplicateProposal(info: DuplicateProposalInfo): void {
|
|
864
849
|
const { slot, proposer, type } = info;
|
|
865
|
-
|
|
866
|
-
this.slotsWithProposalEquivocation.add(slotKey);
|
|
850
|
+
this.slotsWithProposalEquivocation.add(slot);
|
|
867
851
|
|
|
868
|
-
this.log.
|
|
852
|
+
this.log.info(`Detected duplicate ${type} proposal offense from ${proposer.toString()} at slot ${slot}`, {
|
|
869
853
|
proposer: proposer.toString(),
|
|
870
854
|
slot,
|
|
871
855
|
type,
|
|
856
|
+
amount: this.config.slashDuplicateProposalPenalty,
|
|
857
|
+
offenseType: getOffenseTypeName(OffenseType.DUPLICATE_PROPOSAL),
|
|
872
858
|
});
|
|
873
859
|
|
|
874
|
-
// Emit slash event
|
|
875
860
|
this.emit(WANT_TO_SLASH_EVENT, [
|
|
876
861
|
{
|
|
877
862
|
validator: proposer,
|
|
@@ -896,9 +881,11 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
896
881
|
private handleDuplicateAttestation(info: DuplicateAttestationInfo): void {
|
|
897
882
|
const { slot, attester } = info;
|
|
898
883
|
|
|
899
|
-
this.log.
|
|
884
|
+
this.log.info(`Detected duplicate attestation offense from ${attester.toString()} at slot ${slot}`, {
|
|
900
885
|
attester: attester.toString(),
|
|
901
886
|
slot,
|
|
887
|
+
amount: this.config.slashDuplicateAttestationPenalty,
|
|
888
|
+
offenseType: getOffenseTypeName(OffenseType.DUPLICATE_ATTESTATION),
|
|
902
889
|
});
|
|
903
890
|
|
|
904
891
|
this.emit(WANT_TO_SLASH_EVENT, [
|
|
@@ -911,10 +898,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
911
898
|
]);
|
|
912
899
|
}
|
|
913
900
|
|
|
914
|
-
private getSlotKey(slot: SlotNumber): string {
|
|
915
|
-
return slot.toString();
|
|
916
|
-
}
|
|
917
|
-
|
|
918
901
|
async createBlockProposal(
|
|
919
902
|
blockHeader: BlockHeader,
|
|
920
903
|
checkpointNumber: CheckpointNumber,
|