@aztec/validator-client 0.0.1-commit.358457c → 0.0.1-commit.381b1a9
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 +42 -0
- package/dest/block_proposal_handler.d.ts +4 -3
- package/dest/block_proposal_handler.d.ts.map +1 -1
- package/dest/block_proposal_handler.js +106 -30
- package/dest/checkpoint_builder.d.ts +9 -1
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +89 -28
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +21 -1
- package/dest/duties/validation_service.d.ts +1 -1
- package/dest/duties/validation_service.d.ts.map +1 -1
- package/dest/duties/validation_service.js +3 -9
- package/dest/factory.d.ts +1 -1
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +2 -1
- package/dest/key_store/ha_key_store.js +1 -1
- package/dest/metrics.d.ts +9 -1
- package/dest/metrics.d.ts.map +1 -1
- package/dest/metrics.js +12 -0
- package/dest/validator.d.ts +3 -1
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +37 -12
- package/package.json +19 -19
- package/src/block_proposal_handler.ts +128 -37
- package/src/checkpoint_builder.ts +111 -35
- package/src/config.ts +21 -1
- package/src/duties/validation_service.ts +3 -9
- package/src/factory.ts +1 -0
- package/src/key_store/ha_key_store.ts +1 -1
- package/src/metrics.ts +18 -0
- package/src/validator.ts +36 -7
package/src/validator.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { AuthRequest, AuthResponse, BlockProposalValidator, ReqRespSubProtocol }
|
|
|
24
24
|
import { OffenseType, WANT_TO_SLASH_EVENT, type Watcher, type WatcherEmitter } from '@aztec/slasher';
|
|
25
25
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
26
26
|
import type { CommitteeAttestationsAndSigners, L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
27
|
+
import { validateCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
27
28
|
import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
28
29
|
import type {
|
|
29
30
|
CreateCheckpointProposalLastBlockData,
|
|
@@ -89,6 +90,8 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
89
90
|
|
|
90
91
|
private lastEpochForCommitteeUpdateLoop: EpochNumber | undefined;
|
|
91
92
|
private epochCacheUpdateLoop: RunningPromise;
|
|
93
|
+
/** Tracks the last epoch in which each attester successfully submitted at least one attestation. */
|
|
94
|
+
private lastAttestedEpochByAttester: Map<string, EpochNumber> = new Map();
|
|
92
95
|
|
|
93
96
|
private proposersOfInvalidBlocks: Set<string> = new Set();
|
|
94
97
|
|
|
@@ -160,6 +163,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
160
163
|
this.log.trace(`No committee found for slot`);
|
|
161
164
|
return;
|
|
162
165
|
}
|
|
166
|
+
this.metrics.setCurrentEpoch(epoch);
|
|
163
167
|
if (epoch !== this.lastEpochForCommitteeUpdateLoop) {
|
|
164
168
|
const me = this.getValidatorAddresses();
|
|
165
169
|
const committeeSet = new Set(committee.map(v => v.toString()));
|
|
@@ -197,6 +201,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
197
201
|
const metrics = new ValidatorMetrics(telemetry);
|
|
198
202
|
const blockProposalValidator = new BlockProposalValidator(epochCache, {
|
|
199
203
|
txsPermitted: !config.disableTransactions,
|
|
204
|
+
maxTxsPerBlock: config.validateMaxTxsPerBlock,
|
|
200
205
|
});
|
|
201
206
|
const blockProposalHandler = new BlockProposalHandler(
|
|
202
207
|
checkpointsBuilder,
|
|
@@ -221,7 +226,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
221
226
|
...config,
|
|
222
227
|
maxStuckDutiesAgeMs: config.maxStuckDutiesAgeMs ?? epochCache.getL1Constants().slotDuration * 2 * 1000,
|
|
223
228
|
};
|
|
224
|
-
const { signer } = await createHASigner(haConfig
|
|
229
|
+
const { signer } = await createHASigner(haConfig);
|
|
225
230
|
haSigner = signer;
|
|
226
231
|
validatorKeyStore = new HAKeyStore(nodeKeystoreAdapter, signer);
|
|
227
232
|
}
|
|
@@ -382,7 +387,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
382
387
|
|
|
383
388
|
// Ignore proposals from ourselves (may happen in HA setups)
|
|
384
389
|
if (this.getValidatorAddresses().some(addr => addr.equals(proposer))) {
|
|
385
|
-
this.log.
|
|
390
|
+
this.log.debug(`Ignoring block proposal from self for slot ${slotNumber}`, {
|
|
386
391
|
proposer: proposer.toString(),
|
|
387
392
|
slotNumber,
|
|
388
393
|
});
|
|
@@ -418,9 +423,10 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
418
423
|
);
|
|
419
424
|
|
|
420
425
|
if (!validationResult.isValid) {
|
|
421
|
-
this.log.warn(`Block proposal validation failed: ${validationResult.reason}`, proposalInfo);
|
|
422
|
-
|
|
423
426
|
const reason = validationResult.reason || 'unknown';
|
|
427
|
+
|
|
428
|
+
this.log.warn(`Block proposal validation failed: ${reason}`, proposalInfo);
|
|
429
|
+
|
|
424
430
|
// Classify failure reason: bad proposal vs node issue
|
|
425
431
|
const badProposalReasons: BlockProposalValidationFailureReason[] = [
|
|
426
432
|
'invalid_proposal',
|
|
@@ -492,7 +498,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
492
498
|
|
|
493
499
|
// Ignore proposals from ourselves (may happen in HA setups)
|
|
494
500
|
if (this.getValidatorAddresses().some(addr => addr.equals(proposer))) {
|
|
495
|
-
this.log.
|
|
501
|
+
this.log.debug(`Ignoring block proposal from self for slot ${slotNumber}`, {
|
|
496
502
|
proposer: proposer.toString(),
|
|
497
503
|
slotNumber,
|
|
498
504
|
});
|
|
@@ -515,11 +521,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
515
521
|
slotNumber,
|
|
516
522
|
archive: proposal.archive.toString(),
|
|
517
523
|
proposer: proposer.toString(),
|
|
518
|
-
txCount: proposal.txHashes.length,
|
|
519
524
|
};
|
|
520
525
|
this.log.info(`Received checkpoint proposal for slot ${slotNumber}`, {
|
|
521
526
|
...proposalInfo,
|
|
522
|
-
txHashes: proposal.txHashes.map(t => t.toString()),
|
|
523
527
|
fishermanMode: this.config.fishermanMode || false,
|
|
524
528
|
});
|
|
525
529
|
|
|
@@ -555,6 +559,17 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
555
559
|
|
|
556
560
|
this.metrics.incSuccessfulAttestations(inCommittee.length);
|
|
557
561
|
|
|
562
|
+
// Track epoch participation per attester: count each (attester, epoch) pair at most once
|
|
563
|
+
const proposalEpoch = getEpochAtSlot(slotNumber, this.epochCache.getL1Constants());
|
|
564
|
+
for (const attester of inCommittee) {
|
|
565
|
+
const key = attester.toString();
|
|
566
|
+
const lastEpoch = this.lastAttestedEpochByAttester.get(key);
|
|
567
|
+
if (lastEpoch === undefined || proposalEpoch > lastEpoch) {
|
|
568
|
+
this.lastAttestedEpochByAttester.set(key, proposalEpoch);
|
|
569
|
+
this.metrics.incAttestedEpochCount(attester);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
558
573
|
// Determine which validators should attest
|
|
559
574
|
let attestors: EthAddress[];
|
|
560
575
|
if (partOfCommittee) {
|
|
@@ -751,6 +766,20 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
751
766
|
return { isValid: false, reason: 'out_hash_mismatch' };
|
|
752
767
|
}
|
|
753
768
|
|
|
769
|
+
// Final round of validations on the checkpoint, just in case.
|
|
770
|
+
try {
|
|
771
|
+
validateCheckpoint(computedCheckpoint, {
|
|
772
|
+
rollupManaLimit: this.checkpointsBuilder.getConfig().rollupManaLimit,
|
|
773
|
+
maxDABlockGas: this.config.validateMaxDABlockGas,
|
|
774
|
+
maxL2BlockGas: this.config.validateMaxL2BlockGas,
|
|
775
|
+
maxTxsPerBlock: this.config.validateMaxTxsPerBlock,
|
|
776
|
+
maxTxsPerCheckpoint: this.config.validateMaxTxsPerCheckpoint,
|
|
777
|
+
});
|
|
778
|
+
} catch (err) {
|
|
779
|
+
this.log.warn(`Checkpoint validation failed: ${err}`, proposalInfo);
|
|
780
|
+
return { isValid: false, reason: 'checkpoint_validation_failed' };
|
|
781
|
+
}
|
|
782
|
+
|
|
754
783
|
this.log.verbose(`Checkpoint proposal validation successful for slot ${slot}`, proposalInfo);
|
|
755
784
|
return { isValid: true };
|
|
756
785
|
} finally {
|