@aztec/validator-client 0.0.1-commit.f295ac2 → 0.0.1-commit.f2ce05ee
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 +11 -10
- package/dest/block_proposal_handler.d.ts +5 -7
- package/dest/block_proposal_handler.d.ts.map +1 -1
- package/dest/block_proposal_handler.js +17 -32
- package/dest/checkpoint_builder.d.ts +11 -12
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +38 -25
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +4 -6
- package/dest/key_store/ha_key_store.d.ts +1 -1
- package/dest/key_store/ha_key_store.d.ts.map +1 -1
- package/dest/key_store/ha_key_store.js +2 -2
- package/dest/metrics.d.ts +4 -3
- package/dest/metrics.d.ts.map +1 -1
- package/dest/metrics.js +34 -5
- package/dest/tx_validator/tx_validator_factory.d.ts +4 -3
- package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
- package/dest/tx_validator/tx_validator_factory.js +17 -16
- package/dest/validator.d.ts +12 -8
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +46 -28
- package/package.json +19 -17
- package/src/block_proposal_handler.ts +25 -46
- package/src/checkpoint_builder.ts +57 -27
- package/src/config.ts +4 -6
- package/src/key_store/ha_key_store.ts +2 -2
- package/src/metrics.ts +45 -6
- package/src/tx_validator/tx_validator_factory.ts +52 -31
- package/src/validator.ts +52 -34
package/src/validator.ts
CHANGED
|
@@ -18,19 +18,20 @@ import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
|
18
18
|
import { sleep } from '@aztec/foundation/sleep';
|
|
19
19
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
20
20
|
import type { KeystoreManager } from '@aztec/node-keystore';
|
|
21
|
-
import type { P2P, PeerId
|
|
21
|
+
import type { DuplicateProposalInfo, P2P, PeerId } from '@aztec/p2p';
|
|
22
22
|
import { AuthRequest, AuthResponse, BlockProposalValidator, ReqRespSubProtocol } from '@aztec/p2p';
|
|
23
23
|
import { OffenseType, WANT_TO_SLASH_EVENT, type Watcher, type WatcherEmitter } from '@aztec/slasher';
|
|
24
24
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
25
|
-
import type { CommitteeAttestationsAndSigners,
|
|
25
|
+
import type { CommitteeAttestationsAndSigners, L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
26
26
|
import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
|
|
27
27
|
import type {
|
|
28
28
|
CreateCheckpointProposalLastBlockData,
|
|
29
|
+
ITxProvider,
|
|
29
30
|
Validator,
|
|
30
31
|
ValidatorClientFullConfig,
|
|
31
32
|
WorldStateSynchronizer,
|
|
32
33
|
} from '@aztec/stdlib/interfaces/server';
|
|
33
|
-
import type
|
|
34
|
+
import { type L1ToL2MessageSource, accumulateCheckpointOutHashes } from '@aztec/stdlib/messaging';
|
|
34
35
|
import type {
|
|
35
36
|
BlockProposal,
|
|
36
37
|
BlockProposalOptions,
|
|
@@ -87,11 +88,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
87
88
|
|
|
88
89
|
private proposersOfInvalidBlocks: Set<string> = new Set();
|
|
89
90
|
|
|
90
|
-
// TODO(palla/mbps): Remove this once checkpoint validation is stable and we can validate all blocks properly.
|
|
91
|
-
// Tracks slots for which we have successfully validated a block proposal, so we can attest to checkpoint proposals for those slots.
|
|
92
|
-
// eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
|
|
93
|
-
private validatedBlockSlots: Set<SlotNumber> = new Set();
|
|
94
|
-
|
|
95
91
|
protected constructor(
|
|
96
92
|
private keyStore: ExtendedValidatorKeyStore,
|
|
97
93
|
private epochCache: EpochCache,
|
|
@@ -184,7 +180,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
184
180
|
p2pClient: P2P,
|
|
185
181
|
blockSource: L2BlockSource & L2BlockSink,
|
|
186
182
|
l1ToL2MessageSource: L1ToL2MessageSource,
|
|
187
|
-
txProvider:
|
|
183
|
+
txProvider: ITxProvider,
|
|
188
184
|
keyStoreManager: KeystoreManager,
|
|
189
185
|
blobClient: BlobClientInterface,
|
|
190
186
|
dateProvider: DateProvider = new DateProvider(),
|
|
@@ -313,6 +309,11 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
313
309
|
): Promise<CheckpointAttestation[] | undefined> => this.attestToCheckpointProposal(checkpoint, proposalSender);
|
|
314
310
|
this.p2pClient.registerCheckpointProposalHandler(checkpointHandler);
|
|
315
311
|
|
|
312
|
+
// Duplicate proposal handler - triggers slashing for equivocation
|
|
313
|
+
this.p2pClient.registerDuplicateProposalCallback((info: DuplicateProposalInfo) => {
|
|
314
|
+
this.handleDuplicateProposal(info);
|
|
315
|
+
});
|
|
316
|
+
|
|
316
317
|
const myAddresses = this.getValidatorAddresses();
|
|
317
318
|
this.p2pClient.registerThisValidatorAddresses(myAddresses);
|
|
318
319
|
|
|
@@ -413,10 +414,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
413
414
|
return false;
|
|
414
415
|
}
|
|
415
416
|
|
|
416
|
-
// TODO(palla/mbps): Remove this once checkpoint validation is stable.
|
|
417
|
-
// Track that we successfully validated a block for this slot, so we can attest to checkpoint proposals for it.
|
|
418
|
-
this.validatedBlockSlots.add(slotNumber);
|
|
419
|
-
|
|
420
417
|
return true;
|
|
421
418
|
}
|
|
422
419
|
|
|
@@ -461,17 +458,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
461
458
|
fishermanMode: this.config.fishermanMode || false,
|
|
462
459
|
});
|
|
463
460
|
|
|
464
|
-
// TODO(palla/mbps): Remove this once checkpoint validation is stable.
|
|
465
|
-
// Check that we have successfully validated a block for this slot before attesting to the checkpoint.
|
|
466
|
-
if (!this.validatedBlockSlots.has(slotNumber)) {
|
|
467
|
-
this.log.warn(`No validated block found for slot ${slotNumber}, refusing to attest to checkpoint`, proposalInfo);
|
|
468
|
-
return undefined;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
461
|
// Validate the checkpoint proposal before attesting (unless skipCheckpointProposalValidation is set)
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
this.log.verbose(`Skipping checkpoint proposal validation for slot ${slotNumber}`, proposalInfo);
|
|
462
|
+
if (this.config.skipCheckpointProposalValidation) {
|
|
463
|
+
this.log.warn(`Skipping checkpoint proposal validation for slot ${slotNumber}`, proposalInfo);
|
|
475
464
|
} else {
|
|
476
465
|
const validationResult = await this.validateCheckpointProposal(proposal, proposalInfo);
|
|
477
466
|
if (!validationResult.isValid) {
|
|
@@ -534,7 +523,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
534
523
|
attestors: EthAddress[] = [],
|
|
535
524
|
): Promise<CheckpointAttestation[]> {
|
|
536
525
|
const attestations = await this.validationService.attestToCheckpointProposal(proposal, attestors);
|
|
537
|
-
await this.p2pClient.
|
|
526
|
+
await this.p2pClient.addOwnCheckpointAttestations(attestations);
|
|
538
527
|
return attestations;
|
|
539
528
|
}
|
|
540
529
|
|
|
@@ -547,7 +536,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
547
536
|
proposalInfo: LogData,
|
|
548
537
|
): Promise<{ isValid: true } | { isValid: false; reason: string }> {
|
|
549
538
|
const slot = proposal.slotNumber;
|
|
550
|
-
const timeoutSeconds = 10;
|
|
539
|
+
const timeoutSeconds = 10; // TODO(palla/mbps): This should map to the timetable settings
|
|
551
540
|
|
|
552
541
|
// Wait for last block to sync by archive
|
|
553
542
|
let lastBlockHeader: BlockHeader | undefined;
|
|
@@ -617,6 +606,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
617
606
|
previousCheckpointOutHashes,
|
|
618
607
|
fork,
|
|
619
608
|
blocks,
|
|
609
|
+
this.log.getBindings(),
|
|
620
610
|
);
|
|
621
611
|
|
|
622
612
|
// Complete the checkpoint to get computed values
|
|
@@ -642,13 +632,17 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
642
632
|
return { isValid: false, reason: 'archive_mismatch' };
|
|
643
633
|
}
|
|
644
634
|
|
|
645
|
-
// Check that the accumulated out hash matches the value in the proposal.
|
|
646
|
-
|
|
647
|
-
const
|
|
648
|
-
|
|
635
|
+
// Check that the accumulated epoch out hash matches the value in the proposal.
|
|
636
|
+
// The epoch out hash is the accumulated hash of all checkpoint out hashes in the epoch.
|
|
637
|
+
const checkpointOutHash = computedCheckpoint.getCheckpointOutHash();
|
|
638
|
+
const computedEpochOutHash = accumulateCheckpointOutHashes([...previousCheckpointOutHashes, checkpointOutHash]);
|
|
639
|
+
const proposalEpochOutHash = proposal.checkpointHeader.epochOutHash;
|
|
640
|
+
if (!computedEpochOutHash.equals(proposalEpochOutHash)) {
|
|
649
641
|
this.log.warn(`Epoch out hash mismatch`, {
|
|
650
|
-
|
|
651
|
-
|
|
642
|
+
proposalEpochOutHash: proposalEpochOutHash.toString(),
|
|
643
|
+
computedEpochOutHash: computedEpochOutHash.toString(),
|
|
644
|
+
checkpointOutHash: checkpointOutHash.toString(),
|
|
645
|
+
previousCheckpointOutHashes: previousCheckpointOutHashes.map(h => h.toString()),
|
|
652
646
|
...proposalInfo,
|
|
653
647
|
});
|
|
654
648
|
return { isValid: false, reason: 'out_hash_mismatch' };
|
|
@@ -664,7 +658,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
664
658
|
/**
|
|
665
659
|
* Extract checkpoint global variables from a block.
|
|
666
660
|
*/
|
|
667
|
-
private extractCheckpointConstants(block:
|
|
661
|
+
private extractCheckpointConstants(block: L2Block): CheckpointGlobalVariables {
|
|
668
662
|
const gv = block.header.globalVariables;
|
|
669
663
|
return {
|
|
670
664
|
chainId: gv.chainId,
|
|
@@ -732,6 +726,30 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
732
726
|
]);
|
|
733
727
|
}
|
|
734
728
|
|
|
729
|
+
/**
|
|
730
|
+
* Handle detection of a duplicate proposal (equivocation).
|
|
731
|
+
* Emits a slash event when a proposer sends multiple proposals for the same position.
|
|
732
|
+
*/
|
|
733
|
+
private handleDuplicateProposal(info: DuplicateProposalInfo): void {
|
|
734
|
+
const { slot, proposer, type } = info;
|
|
735
|
+
|
|
736
|
+
this.log.warn(`Triggering slash event for duplicate ${type} proposal from ${proposer.toString()} at slot ${slot}`, {
|
|
737
|
+
proposer: proposer.toString(),
|
|
738
|
+
slot,
|
|
739
|
+
type,
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
// Emit slash event
|
|
743
|
+
this.emit(WANT_TO_SLASH_EVENT, [
|
|
744
|
+
{
|
|
745
|
+
validator: proposer,
|
|
746
|
+
amount: this.config.slashDuplicateProposalPenalty,
|
|
747
|
+
offenseType: OffenseType.DUPLICATE_PROPOSAL,
|
|
748
|
+
epochOrSlot: BigInt(slot),
|
|
749
|
+
},
|
|
750
|
+
]);
|
|
751
|
+
}
|
|
752
|
+
|
|
735
753
|
async createBlockProposal(
|
|
736
754
|
blockHeader: BlockHeader,
|
|
737
755
|
indexWithinCheckpoint: IndexWithinCheckpoint,
|
|
@@ -739,7 +757,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
739
757
|
archive: Fr,
|
|
740
758
|
txs: Tx[],
|
|
741
759
|
proposerAddress: EthAddress | undefined,
|
|
742
|
-
options: BlockProposalOptions,
|
|
760
|
+
options: BlockProposalOptions = {},
|
|
743
761
|
): Promise<BlockProposal> {
|
|
744
762
|
// TODO(palla/mbps): Prevent double proposals properly
|
|
745
763
|
// if (this.previousProposal?.slotNumber === blockHeader.globalVariables.slotNumber) {
|
|
@@ -771,7 +789,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
771
789
|
archive: Fr,
|
|
772
790
|
lastBlockInfo: CreateCheckpointProposalLastBlockData | undefined,
|
|
773
791
|
proposerAddress: EthAddress | undefined,
|
|
774
|
-
options: CheckpointProposalOptions,
|
|
792
|
+
options: CheckpointProposalOptions = {},
|
|
775
793
|
): Promise<CheckpointProposal> {
|
|
776
794
|
this.log.info(`Assembling checkpoint proposal for slot ${checkpointHeader.slotNumber}`);
|
|
777
795
|
return await this.validationService.createCheckpointProposal(
|