@aztec/validator-client 0.0.1-commit.bf2612ae → 0.0.1-commit.c0b82b2
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 +21 -18
- package/dest/block_proposal_handler.d.ts +2 -2
- package/dest/block_proposal_handler.d.ts.map +1 -1
- package/dest/block_proposal_handler.js +20 -34
- package/dest/checkpoint_builder.d.ts +13 -11
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +50 -30
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +7 -4
- package/dest/duties/validation_service.d.ts +2 -2
- package/dest/duties/validation_service.d.ts.map +1 -1
- package/dest/duties/validation_service.js +3 -3
- package/dest/index.d.ts +1 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +0 -1
- 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/validator.d.ts +33 -9
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +167 -44
- package/package.json +19 -19
- package/src/block_proposal_handler.ts +29 -48
- package/src/checkpoint_builder.ts +73 -29
- package/src/config.ts +7 -4
- package/src/duties/validation_service.ts +9 -2
- package/src/index.ts +0 -1
- package/src/key_store/ha_key_store.ts +2 -2
- package/src/metrics.ts +45 -6
- package/src/validator.ts +221 -53
- package/dest/tx_validator/index.d.ts +0 -3
- package/dest/tx_validator/index.d.ts.map +0 -1
- package/dest/tx_validator/index.js +0 -2
- package/dest/tx_validator/nullifier_cache.d.ts +0 -14
- package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
- package/dest/tx_validator/nullifier_cache.js +0 -24
- package/dest/tx_validator/tx_validator_factory.d.ts +0 -18
- package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
- package/dest/tx_validator/tx_validator_factory.js +0 -54
- package/src/tx_validator/index.ts +0 -2
- package/src/tx_validator/nullifier_cache.ts +0 -30
- package/src/tx_validator/tx_validator_factory.ts +0 -135
package/src/validator.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BlobClientInterface } from '@aztec/blob-client/client';
|
|
2
2
|
import { type Blob, getBlobsPerL1Block } from '@aztec/blob-lib';
|
|
3
3
|
import type { EpochCache } from '@aztec/epoch-cache';
|
|
4
|
+
import { validateFeeAssetPriceModifier } from '@aztec/ethereum/contracts';
|
|
4
5
|
import {
|
|
5
6
|
BlockNumber,
|
|
6
7
|
CheckpointNumber,
|
|
@@ -18,12 +19,12 @@ import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
|
18
19
|
import { sleep } from '@aztec/foundation/sleep';
|
|
19
20
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
20
21
|
import type { KeystoreManager } from '@aztec/node-keystore';
|
|
21
|
-
import type { P2P, PeerId } from '@aztec/p2p';
|
|
22
|
+
import type { DuplicateAttestationInfo, DuplicateProposalInfo, P2P, PeerId } from '@aztec/p2p';
|
|
22
23
|
import { AuthRequest, AuthResponse, BlockProposalValidator, ReqRespSubProtocol } from '@aztec/p2p';
|
|
23
24
|
import { OffenseType, WANT_TO_SLASH_EVENT, type Watcher, type WatcherEmitter } from '@aztec/slasher';
|
|
24
25
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
25
26
|
import type { CommitteeAttestationsAndSigners, L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
26
|
-
import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
|
|
27
|
+
import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
27
28
|
import type {
|
|
28
29
|
CreateCheckpointProposalLastBlockData,
|
|
29
30
|
ITxProvider,
|
|
@@ -32,20 +33,21 @@ import type {
|
|
|
32
33
|
WorldStateSynchronizer,
|
|
33
34
|
} from '@aztec/stdlib/interfaces/server';
|
|
34
35
|
import { type L1ToL2MessageSource, accumulateCheckpointOutHashes } from '@aztec/stdlib/messaging';
|
|
35
|
-
import
|
|
36
|
-
BlockProposal,
|
|
37
|
-
BlockProposalOptions,
|
|
38
|
-
CheckpointAttestation,
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
import {
|
|
37
|
+
type BlockProposal,
|
|
38
|
+
type BlockProposalOptions,
|
|
39
|
+
type CheckpointAttestation,
|
|
40
|
+
CheckpointProposal,
|
|
41
|
+
type CheckpointProposalCore,
|
|
42
|
+
type CheckpointProposalOptions,
|
|
41
43
|
} from '@aztec/stdlib/p2p';
|
|
42
|
-
import { CheckpointProposal } from '@aztec/stdlib/p2p';
|
|
43
44
|
import type { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
44
45
|
import type { BlockHeader, CheckpointGlobalVariables, Tx } from '@aztec/stdlib/tx';
|
|
45
46
|
import { AttestationTimeoutError } from '@aztec/stdlib/validators';
|
|
46
47
|
import { type TelemetryClient, type Tracer, getTelemetryClient } from '@aztec/telemetry-client';
|
|
47
48
|
import { createHASigner } from '@aztec/validator-ha-signer/factory';
|
|
48
49
|
import { DutyType, type SigningContext } from '@aztec/validator-ha-signer/types';
|
|
50
|
+
import type { ValidatorHASigner } from '@aztec/validator-ha-signer/validator-ha-signer';
|
|
49
51
|
|
|
50
52
|
import { EventEmitter } from 'events';
|
|
51
53
|
import type { TypedDataDefinition } from 'viem';
|
|
@@ -76,22 +78,22 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
76
78
|
private validationService: ValidationService;
|
|
77
79
|
private metrics: ValidatorMetrics;
|
|
78
80
|
private log: Logger;
|
|
79
|
-
|
|
80
81
|
// Whether it has already registered handlers on the p2p client
|
|
81
82
|
private hasRegisteredHandlers = false;
|
|
82
83
|
|
|
83
|
-
|
|
84
|
-
private
|
|
84
|
+
/** Tracks the last block proposal we created, to detect duplicate proposal attempts. */
|
|
85
|
+
private lastProposedBlock?: BlockProposal;
|
|
86
|
+
|
|
87
|
+
/** Tracks the last checkpoint proposal we created. */
|
|
88
|
+
private lastProposedCheckpoint?: CheckpointProposal;
|
|
85
89
|
|
|
86
90
|
private lastEpochForCommitteeUpdateLoop: EpochNumber | undefined;
|
|
87
91
|
private epochCacheUpdateLoop: RunningPromise;
|
|
88
92
|
|
|
89
93
|
private proposersOfInvalidBlocks: Set<string> = new Set();
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
|
|
94
|
-
private validatedBlockSlots: Set<SlotNumber> = new Set();
|
|
95
|
+
/** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */
|
|
96
|
+
private lastAttestedProposal?: CheckpointProposalCore;
|
|
95
97
|
|
|
96
98
|
protected constructor(
|
|
97
99
|
private keyStore: ExtendedValidatorKeyStore,
|
|
@@ -104,6 +106,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
104
106
|
private l1ToL2MessageSource: L1ToL2MessageSource,
|
|
105
107
|
private config: ValidatorClientFullConfig,
|
|
106
108
|
private blobClient: BlobClientInterface,
|
|
109
|
+
private haSigner: ValidatorHASigner | undefined,
|
|
107
110
|
private dateProvider: DateProvider = new DateProvider(),
|
|
108
111
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
109
112
|
log = createLogger('validator'),
|
|
@@ -209,15 +212,18 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
209
212
|
telemetry,
|
|
210
213
|
);
|
|
211
214
|
|
|
212
|
-
|
|
215
|
+
const nodeKeystoreAdapter = NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager);
|
|
216
|
+
let validatorKeyStore: ExtendedValidatorKeyStore = nodeKeystoreAdapter;
|
|
217
|
+
let haSigner: ValidatorHASigner | undefined;
|
|
213
218
|
if (config.haSigningEnabled) {
|
|
214
219
|
// If maxStuckDutiesAgeMs is not explicitly set, compute it from Aztec slot duration
|
|
215
220
|
const haConfig = {
|
|
216
221
|
...config,
|
|
217
222
|
maxStuckDutiesAgeMs: config.maxStuckDutiesAgeMs ?? epochCache.getL1Constants().slotDuration * 2 * 1000,
|
|
218
223
|
};
|
|
219
|
-
const { signer } = await createHASigner(haConfig);
|
|
220
|
-
|
|
224
|
+
const { signer } = await createHASigner(haConfig, { telemetryClient: telemetry, dateProvider });
|
|
225
|
+
haSigner = signer;
|
|
226
|
+
validatorKeyStore = new HAKeyStore(nodeKeystoreAdapter, signer);
|
|
221
227
|
}
|
|
222
228
|
|
|
223
229
|
const validator = new ValidatorClient(
|
|
@@ -231,6 +237,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
231
237
|
l1ToL2MessageSource,
|
|
232
238
|
config,
|
|
233
239
|
blobClient,
|
|
240
|
+
haSigner,
|
|
234
241
|
dateProvider,
|
|
235
242
|
telemetry,
|
|
236
243
|
);
|
|
@@ -268,6 +275,28 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
268
275
|
this.config = { ...this.config, ...config };
|
|
269
276
|
}
|
|
270
277
|
|
|
278
|
+
public reloadKeystore(newManager: KeystoreManager): void {
|
|
279
|
+
if (this.config.haSigningEnabled && !this.haSigner) {
|
|
280
|
+
this.log.warn(
|
|
281
|
+
'HA signing is enabled in config but was not initialized at startup. ' +
|
|
282
|
+
'Restart the node to enable HA signing.',
|
|
283
|
+
);
|
|
284
|
+
} else if (!this.config.haSigningEnabled && this.haSigner) {
|
|
285
|
+
this.log.warn(
|
|
286
|
+
'HA signing was disabled via config update but the HA signer is still active. ' +
|
|
287
|
+
'Restart the node to fully disable HA signing.',
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const newAdapter = NodeKeystoreAdapter.fromKeyStoreManager(newManager);
|
|
292
|
+
if (this.haSigner) {
|
|
293
|
+
this.keyStore = new HAKeyStore(newAdapter, this.haSigner);
|
|
294
|
+
} else {
|
|
295
|
+
this.keyStore = newAdapter;
|
|
296
|
+
}
|
|
297
|
+
this.validationService = new ValidationService(this.keyStore, this.log.createChild('validation-service'));
|
|
298
|
+
}
|
|
299
|
+
|
|
271
300
|
public async start() {
|
|
272
301
|
if (this.epochCacheUpdateLoop.isRunning()) {
|
|
273
302
|
this.log.warn(`Validator client already started`);
|
|
@@ -314,6 +343,16 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
314
343
|
): Promise<CheckpointAttestation[] | undefined> => this.attestToCheckpointProposal(checkpoint, proposalSender);
|
|
315
344
|
this.p2pClient.registerCheckpointProposalHandler(checkpointHandler);
|
|
316
345
|
|
|
346
|
+
// Duplicate proposal handler - triggers slashing for equivocation
|
|
347
|
+
this.p2pClient.registerDuplicateProposalCallback((info: DuplicateProposalInfo) => {
|
|
348
|
+
this.handleDuplicateProposal(info);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
// Duplicate attestation handler - triggers slashing for attestation equivocation
|
|
352
|
+
this.p2pClient.registerDuplicateAttestationCallback((info: DuplicateAttestationInfo) => {
|
|
353
|
+
this.handleDuplicateAttestation(info);
|
|
354
|
+
});
|
|
355
|
+
|
|
317
356
|
const myAddresses = this.getValidatorAddresses();
|
|
318
357
|
this.p2pClient.registerThisValidatorAddresses(myAddresses);
|
|
319
358
|
|
|
@@ -341,6 +380,15 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
341
380
|
return false;
|
|
342
381
|
}
|
|
343
382
|
|
|
383
|
+
// Ignore proposals from ourselves (may happen in HA setups)
|
|
384
|
+
if (this.getValidatorAddresses().some(addr => addr.equals(proposer))) {
|
|
385
|
+
this.log.warn(`Ignoring block proposal from self for slot ${slotNumber}`, {
|
|
386
|
+
proposer: proposer.toString(),
|
|
387
|
+
slotNumber,
|
|
388
|
+
});
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
|
|
344
392
|
// Check if we're in the committee (for metrics purposes)
|
|
345
393
|
const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.getValidatorAddresses());
|
|
346
394
|
const partOfCommittee = inCommittee.length > 0;
|
|
@@ -414,10 +462,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
414
462
|
return false;
|
|
415
463
|
}
|
|
416
464
|
|
|
417
|
-
// TODO(palla/mbps): Remove this once checkpoint validation is stable.
|
|
418
|
-
// Track that we successfully validated a block for this slot, so we can attest to checkpoint proposals for it.
|
|
419
|
-
this.validatedBlockSlots.add(slotNumber);
|
|
420
|
-
|
|
421
465
|
return true;
|
|
422
466
|
}
|
|
423
467
|
|
|
@@ -446,6 +490,23 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
446
490
|
return undefined;
|
|
447
491
|
}
|
|
448
492
|
|
|
493
|
+
// Ignore proposals from ourselves (may happen in HA setups)
|
|
494
|
+
if (this.getValidatorAddresses().some(addr => addr.equals(proposer))) {
|
|
495
|
+
this.log.warn(`Ignoring block proposal from self for slot ${slotNumber}`, {
|
|
496
|
+
proposer: proposer.toString(),
|
|
497
|
+
slotNumber,
|
|
498
|
+
});
|
|
499
|
+
return undefined;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Validate fee asset price modifier is within allowed range
|
|
503
|
+
if (!validateFeeAssetPriceModifier(proposal.feeAssetPriceModifier)) {
|
|
504
|
+
this.log.warn(
|
|
505
|
+
`Received checkpoint proposal with invalid feeAssetPriceModifier ${proposal.feeAssetPriceModifier} for slot ${slotNumber}`,
|
|
506
|
+
);
|
|
507
|
+
return undefined;
|
|
508
|
+
}
|
|
509
|
+
|
|
449
510
|
// Check that I have any address in current committee before attesting
|
|
450
511
|
const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.getValidatorAddresses());
|
|
451
512
|
const partOfCommittee = inCommittee.length > 0;
|
|
@@ -462,17 +523,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
462
523
|
fishermanMode: this.config.fishermanMode || false,
|
|
463
524
|
});
|
|
464
525
|
|
|
465
|
-
// TODO(palla/mbps): Remove this once checkpoint validation is stable.
|
|
466
|
-
// Check that we have successfully validated a block for this slot before attesting to the checkpoint.
|
|
467
|
-
if (!this.validatedBlockSlots.has(slotNumber)) {
|
|
468
|
-
this.log.warn(`No validated block found for slot ${slotNumber}, refusing to attest to checkpoint`, proposalInfo);
|
|
469
|
-
return undefined;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
526
|
// Validate the checkpoint proposal before attesting (unless skipCheckpointProposalValidation is set)
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
this.log.verbose(`Skipping checkpoint proposal validation for slot ${slotNumber}`, proposalInfo);
|
|
527
|
+
if (this.config.skipCheckpointProposalValidation) {
|
|
528
|
+
this.log.warn(`Skipping checkpoint proposal validation for slot ${slotNumber}`, proposalInfo);
|
|
476
529
|
} else {
|
|
477
530
|
const validationResult = await this.validateCheckpointProposal(proposal, proposalInfo);
|
|
478
531
|
if (!validationResult.isValid) {
|
|
@@ -527,15 +580,45 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
527
580
|
return undefined;
|
|
528
581
|
}
|
|
529
582
|
|
|
530
|
-
return this.createCheckpointAttestationsFromProposal(proposal, attestors);
|
|
583
|
+
return await this.createCheckpointAttestationsFromProposal(proposal, attestors);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Checks if we should attest to a slot based on equivocation prevention rules.
|
|
588
|
+
* @returns true if we should attest, false if we should skip
|
|
589
|
+
*/
|
|
590
|
+
private shouldAttestToSlot(slotNumber: SlotNumber): boolean {
|
|
591
|
+
// If attestToEquivocatedProposals is true, always allow
|
|
592
|
+
if (this.config.attestToEquivocatedProposals) {
|
|
593
|
+
return true;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Check if incoming slot is strictly greater than last attested
|
|
597
|
+
if (this.lastAttestedProposal && slotNumber <= this.lastAttestedProposal.slotNumber) {
|
|
598
|
+
this.log.warn(
|
|
599
|
+
`Refusing to process a proposal for slot ${slotNumber} given we already attested to a proposal for slot ${this.lastAttestedProposal.slotNumber}`,
|
|
600
|
+
);
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
return true;
|
|
531
605
|
}
|
|
532
606
|
|
|
533
607
|
private async createCheckpointAttestationsFromProposal(
|
|
534
608
|
proposal: CheckpointProposalCore,
|
|
535
609
|
attestors: EthAddress[] = [],
|
|
536
|
-
): Promise<CheckpointAttestation[]> {
|
|
610
|
+
): Promise<CheckpointAttestation[] | undefined> {
|
|
611
|
+
// Equivocation check: must happen right before signing to minimize the race window
|
|
612
|
+
if (!this.shouldAttestToSlot(proposal.slotNumber)) {
|
|
613
|
+
return undefined;
|
|
614
|
+
}
|
|
615
|
+
|
|
537
616
|
const attestations = await this.validationService.attestToCheckpointProposal(proposal, attestors);
|
|
538
|
-
|
|
617
|
+
|
|
618
|
+
// Track the proposal we attested to (to prevent equivocation)
|
|
619
|
+
this.lastAttestedProposal = proposal;
|
|
620
|
+
|
|
621
|
+
await this.p2pClient.addOwnCheckpointAttestations(attestations);
|
|
539
622
|
return attestations;
|
|
540
623
|
}
|
|
541
624
|
|
|
@@ -548,7 +631,11 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
548
631
|
proposalInfo: LogData,
|
|
549
632
|
): Promise<{ isValid: true } | { isValid: false; reason: string }> {
|
|
550
633
|
const slot = proposal.slotNumber;
|
|
551
|
-
|
|
634
|
+
|
|
635
|
+
// Timeout block syncing at the start of the next slot
|
|
636
|
+
const config = this.checkpointsBuilder.getConfig();
|
|
637
|
+
const nextSlotTimestampSeconds = Number(getTimestampForSlot(SlotNumber(slot + 1), config));
|
|
638
|
+
const timeoutSeconds = Math.max(1, nextSlotTimestampSeconds - Math.floor(this.dateProvider.now() / 1000));
|
|
552
639
|
|
|
553
640
|
// Wait for last block to sync by archive
|
|
554
641
|
let lastBlockHeader: BlockHeader | undefined;
|
|
@@ -583,6 +670,12 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
583
670
|
return { isValid: false, reason: 'no_blocks_for_slot' };
|
|
584
671
|
}
|
|
585
672
|
|
|
673
|
+
// Ensure the last block for this slot matches the archive in the checkpoint proposal
|
|
674
|
+
if (!blocks.at(-1)?.archive.root.equals(proposal.archive)) {
|
|
675
|
+
this.log.warn(`Last block archive mismatch for checkpoint proposal`, proposalInfo);
|
|
676
|
+
return { isValid: false, reason: 'last_block_archive_mismatch' };
|
|
677
|
+
}
|
|
678
|
+
|
|
586
679
|
this.log.debug(`Found ${blocks.length} blocks for slot ${slot}`, {
|
|
587
680
|
...proposalInfo,
|
|
588
681
|
blockNumbers: blocks.map(b => b.number),
|
|
@@ -596,14 +689,11 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
596
689
|
// Get L1-to-L2 messages for this checkpoint
|
|
597
690
|
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
598
691
|
|
|
599
|
-
//
|
|
600
|
-
// TODO: There can be a more efficient way to get the previous checkpoint out hashes without having to fetch the
|
|
601
|
-
// actual checkpoints and the blocks/txs in them.
|
|
692
|
+
// Collect the out hashes of all the checkpoints before this one in the same epoch
|
|
602
693
|
const epoch = getEpochAtSlot(slot, this.epochCache.getL1Constants());
|
|
603
|
-
const
|
|
604
|
-
.filter(
|
|
605
|
-
.
|
|
606
|
-
const previousCheckpointOutHashes = previousCheckpoints.map(c => c.getCheckpointOutHash());
|
|
694
|
+
const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch))
|
|
695
|
+
.filter(c => c.checkpointNumber < checkpointNumber)
|
|
696
|
+
.map(c => c.checkpointOutHash);
|
|
607
697
|
|
|
608
698
|
// Fork world state at the block before the first block
|
|
609
699
|
const parentBlockNumber = BlockNumber(firstBlock.number - 1);
|
|
@@ -614,10 +704,12 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
614
704
|
const checkpointBuilder = await this.checkpointsBuilder.openCheckpoint(
|
|
615
705
|
checkpointNumber,
|
|
616
706
|
constants,
|
|
707
|
+
proposal.feeAssetPriceModifier,
|
|
617
708
|
l1ToL2Messages,
|
|
618
709
|
previousCheckpointOutHashes,
|
|
619
710
|
fork,
|
|
620
711
|
blocks,
|
|
712
|
+
this.log.getBindings(),
|
|
621
713
|
);
|
|
622
714
|
|
|
623
715
|
// Complete the checkpoint to get computed values
|
|
@@ -675,6 +767,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
675
767
|
chainId: gv.chainId,
|
|
676
768
|
version: gv.version,
|
|
677
769
|
slotNumber: gv.slotNumber,
|
|
770
|
+
timestamp: gv.timestamp,
|
|
678
771
|
coinbase: gv.coinbase,
|
|
679
772
|
feeRecipient: gv.feeRecipient,
|
|
680
773
|
gasFees: gv.gasFees,
|
|
@@ -684,7 +777,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
684
777
|
/**
|
|
685
778
|
* Uploads blobs for a checkpoint to the filestore (fire and forget).
|
|
686
779
|
*/
|
|
687
|
-
|
|
780
|
+
protected async uploadBlobsForCheckpoint(proposal: CheckpointProposalCore, proposalInfo: LogData): Promise<void> {
|
|
688
781
|
try {
|
|
689
782
|
const lastBlockHeader = await this.blockSource.getBlockHeaderByArchive(proposal.archive);
|
|
690
783
|
if (!lastBlockHeader) {
|
|
@@ -699,7 +792,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
699
792
|
}
|
|
700
793
|
|
|
701
794
|
const blobFields = blocks.flatMap(b => b.toBlobFields());
|
|
702
|
-
const blobs: Blob[] = getBlobsPerL1Block(blobFields);
|
|
795
|
+
const blobs: Blob[] = await getBlobsPerL1Block(blobFields);
|
|
703
796
|
await this.blobClient.sendBlobsToFilestore(blobs);
|
|
704
797
|
this.log.debug(`Uploaded ${blobs.length} blobs to filestore for checkpoint at slot ${proposal.slotNumber}`, {
|
|
705
798
|
...proposalInfo,
|
|
@@ -737,6 +830,52 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
737
830
|
]);
|
|
738
831
|
}
|
|
739
832
|
|
|
833
|
+
/**
|
|
834
|
+
* Handle detection of a duplicate proposal (equivocation).
|
|
835
|
+
* Emits a slash event when a proposer sends multiple proposals for the same position.
|
|
836
|
+
*/
|
|
837
|
+
private handleDuplicateProposal(info: DuplicateProposalInfo): void {
|
|
838
|
+
const { slot, proposer, type } = info;
|
|
839
|
+
|
|
840
|
+
this.log.warn(`Triggering slash event for duplicate ${type} proposal from ${proposer.toString()} at slot ${slot}`, {
|
|
841
|
+
proposer: proposer.toString(),
|
|
842
|
+
slot,
|
|
843
|
+
type,
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
// Emit slash event
|
|
847
|
+
this.emit(WANT_TO_SLASH_EVENT, [
|
|
848
|
+
{
|
|
849
|
+
validator: proposer,
|
|
850
|
+
amount: this.config.slashDuplicateProposalPenalty,
|
|
851
|
+
offenseType: OffenseType.DUPLICATE_PROPOSAL,
|
|
852
|
+
epochOrSlot: BigInt(slot),
|
|
853
|
+
},
|
|
854
|
+
]);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Handle detection of a duplicate attestation (equivocation).
|
|
859
|
+
* Emits a slash event when an attester signs attestations for different proposals at the same slot.
|
|
860
|
+
*/
|
|
861
|
+
private handleDuplicateAttestation(info: DuplicateAttestationInfo): void {
|
|
862
|
+
const { slot, attester } = info;
|
|
863
|
+
|
|
864
|
+
this.log.warn(`Triggering slash event for duplicate attestation from ${attester.toString()} at slot ${slot}`, {
|
|
865
|
+
attester: attester.toString(),
|
|
866
|
+
slot,
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
this.emit(WANT_TO_SLASH_EVENT, [
|
|
870
|
+
{
|
|
871
|
+
validator: attester,
|
|
872
|
+
amount: this.config.slashDuplicateAttestationPenalty,
|
|
873
|
+
offenseType: OffenseType.DUPLICATE_ATTESTATION,
|
|
874
|
+
epochOrSlot: BigInt(slot),
|
|
875
|
+
},
|
|
876
|
+
]);
|
|
877
|
+
}
|
|
878
|
+
|
|
740
879
|
async createBlockProposal(
|
|
741
880
|
blockHeader: BlockHeader,
|
|
742
881
|
indexWithinCheckpoint: IndexWithinCheckpoint,
|
|
@@ -746,11 +885,19 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
746
885
|
proposerAddress: EthAddress | undefined,
|
|
747
886
|
options: BlockProposalOptions = {},
|
|
748
887
|
): Promise<BlockProposal> {
|
|
749
|
-
//
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
888
|
+
// Validate that we're not creating a proposal for an older or equal position
|
|
889
|
+
if (this.lastProposedBlock) {
|
|
890
|
+
const lastSlot = this.lastProposedBlock.slotNumber;
|
|
891
|
+
const lastIndex = this.lastProposedBlock.indexWithinCheckpoint;
|
|
892
|
+
const newSlot = blockHeader.globalVariables.slotNumber;
|
|
893
|
+
|
|
894
|
+
if (newSlot < lastSlot || (newSlot === lastSlot && indexWithinCheckpoint <= lastIndex)) {
|
|
895
|
+
throw new Error(
|
|
896
|
+
`Cannot create block proposal for slot ${newSlot} index ${indexWithinCheckpoint}: ` +
|
|
897
|
+
`already proposed block for slot ${lastSlot} index ${lastIndex}`,
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
754
901
|
|
|
755
902
|
this.log.info(
|
|
756
903
|
`Assembling block proposal for block ${blockHeader.globalVariables.blockNumber} slot ${blockHeader.globalVariables.slotNumber}`,
|
|
@@ -767,25 +914,42 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
767
914
|
broadcastInvalidBlockProposal: this.config.broadcastInvalidBlockProposal,
|
|
768
915
|
},
|
|
769
916
|
);
|
|
770
|
-
this.
|
|
917
|
+
this.lastProposedBlock = newProposal;
|
|
771
918
|
return newProposal;
|
|
772
919
|
}
|
|
773
920
|
|
|
774
921
|
async createCheckpointProposal(
|
|
775
922
|
checkpointHeader: CheckpointHeader,
|
|
776
923
|
archive: Fr,
|
|
924
|
+
feeAssetPriceModifier: bigint,
|
|
777
925
|
lastBlockInfo: CreateCheckpointProposalLastBlockData | undefined,
|
|
778
926
|
proposerAddress: EthAddress | undefined,
|
|
779
927
|
options: CheckpointProposalOptions = {},
|
|
780
928
|
): Promise<CheckpointProposal> {
|
|
929
|
+
// Validate that we're not creating a proposal for an older or equal slot
|
|
930
|
+
if (this.lastProposedCheckpoint) {
|
|
931
|
+
const lastSlot = this.lastProposedCheckpoint.slotNumber;
|
|
932
|
+
const newSlot = checkpointHeader.slotNumber;
|
|
933
|
+
|
|
934
|
+
if (newSlot <= lastSlot) {
|
|
935
|
+
throw new Error(
|
|
936
|
+
`Cannot create checkpoint proposal for slot ${newSlot}: ` +
|
|
937
|
+
`already proposed checkpoint for slot ${lastSlot}`,
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
781
942
|
this.log.info(`Assembling checkpoint proposal for slot ${checkpointHeader.slotNumber}`);
|
|
782
|
-
|
|
943
|
+
const newProposal = await this.validationService.createCheckpointProposal(
|
|
783
944
|
checkpointHeader,
|
|
784
945
|
archive,
|
|
946
|
+
feeAssetPriceModifier,
|
|
785
947
|
lastBlockInfo,
|
|
786
948
|
proposerAddress,
|
|
787
949
|
options,
|
|
788
950
|
);
|
|
951
|
+
this.lastProposedCheckpoint = newProposal;
|
|
952
|
+
return newProposal;
|
|
789
953
|
}
|
|
790
954
|
|
|
791
955
|
async broadcastBlockProposal(proposal: BlockProposal): Promise<void> {
|
|
@@ -807,6 +971,10 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
807
971
|
this.log.debug(`Collecting ${inCommittee.length} self-attestations for slot ${slot}`, { inCommittee });
|
|
808
972
|
const attestations = await this.createCheckpointAttestationsFromProposal(proposal, inCommittee);
|
|
809
973
|
|
|
974
|
+
if (!attestations) {
|
|
975
|
+
return [];
|
|
976
|
+
}
|
|
977
|
+
|
|
810
978
|
// We broadcast our own attestations to our peers so, in case our block does not get mined on L1,
|
|
811
979
|
// other nodes can see that our validators did attest to this block proposal, and do not slash us
|
|
812
980
|
// due to inactivity for missed attestations.
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
export * from './nullifier_cache.js';
|
|
2
|
-
export * from './tx_validator_factory.js';
|
|
3
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90eF92YWxpZGF0b3IvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxzQkFBc0IsQ0FBQztBQUNyQyxjQUFjLDJCQUEyQixDQUFDIn0=
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tx_validator/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { NullifierSource } from '@aztec/p2p';
|
|
2
|
-
import type { MerkleTreeReadOperations } from '@aztec/stdlib/interfaces/server';
|
|
3
|
-
/**
|
|
4
|
-
* Implements a nullifier source by checking a DB and an in-memory collection.
|
|
5
|
-
* Intended for validating transactions as they are added to a block.
|
|
6
|
-
*/
|
|
7
|
-
export declare class NullifierCache implements NullifierSource {
|
|
8
|
-
private db;
|
|
9
|
-
nullifiers: Set<string>;
|
|
10
|
-
constructor(db: MerkleTreeReadOperations);
|
|
11
|
-
nullifiersExist(nullifiers: Buffer[]): Promise<boolean[]>;
|
|
12
|
-
addNullifiers(nullifiers: Buffer[]): void;
|
|
13
|
-
}
|
|
14
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVsbGlmaWVyX2NhY2hlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHhfdmFsaWRhdG9yL251bGxpZmllcl9jYWNoZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxlQUFlLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDbEQsT0FBTyxLQUFLLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUdoRjs7O0dBR0c7QUFDSCxxQkFBYSxjQUFlLFlBQVcsZUFBZTtJQUd4QyxPQUFPLENBQUMsRUFBRTtJQUZ0QixVQUFVLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBRXhCLFlBQW9CLEVBQUUsRUFBRSx3QkFBd0IsRUFFL0M7SUFFWSxlQUFlLENBQUMsVUFBVSxFQUFFLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQU9yRTtJQUVNLGFBQWEsQ0FBQyxVQUFVLEVBQUUsTUFBTSxFQUFFLFFBSXhDO0NBQ0YifQ==
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"nullifier_cache.d.ts","sourceRoot":"","sources":["../../src/tx_validator/nullifier_cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAGhF;;;GAGG;AACH,qBAAa,cAAe,YAAW,eAAe;IAGxC,OAAO,CAAC,EAAE;IAFtB,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAExB,YAAoB,EAAE,EAAE,wBAAwB,EAE/C;IAEY,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAOrE;IAEM,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,QAIxC;CACF"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
2
|
-
/**
|
|
3
|
-
* Implements a nullifier source by checking a DB and an in-memory collection.
|
|
4
|
-
* Intended for validating transactions as they are added to a block.
|
|
5
|
-
*/ export class NullifierCache {
|
|
6
|
-
db;
|
|
7
|
-
nullifiers;
|
|
8
|
-
constructor(db){
|
|
9
|
-
this.db = db;
|
|
10
|
-
this.nullifiers = new Set();
|
|
11
|
-
}
|
|
12
|
-
async nullifiersExist(nullifiers) {
|
|
13
|
-
const cacheResults = nullifiers.map((n)=>this.nullifiers.has(n.toString()));
|
|
14
|
-
const toCheckDb = nullifiers.filter((_n, index)=>!cacheResults[index]);
|
|
15
|
-
const dbHits = await this.db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, toCheckDb);
|
|
16
|
-
let dbIndex = 0;
|
|
17
|
-
return nullifiers.map((_n, index)=>cacheResults[index] || dbHits[dbIndex++] !== undefined);
|
|
18
|
-
}
|
|
19
|
-
addNullifiers(nullifiers) {
|
|
20
|
-
for (const nullifier of nullifiers){
|
|
21
|
-
this.nullifiers.add(nullifier.toString());
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
3
|
-
import type { GasFees } from '@aztec/stdlib/gas';
|
|
4
|
-
import type { AllowedElement, ClientProtocolCircuitVerifier, MerkleTreeReadOperations, PublicProcessorValidator } from '@aztec/stdlib/interfaces/server';
|
|
5
|
-
import { GlobalVariables, type Tx, type TxValidator } from '@aztec/stdlib/tx';
|
|
6
|
-
import type { UInt64 } from '@aztec/stdlib/types';
|
|
7
|
-
export declare function createValidatorForAcceptingTxs(db: MerkleTreeReadOperations, contractDataSource: ContractDataSource, verifier: ClientProtocolCircuitVerifier | undefined, { l1ChainId, rollupVersion, setupAllowList, gasFees, skipFeeEnforcement, timestamp, blockNumber, txsPermitted }: {
|
|
8
|
-
l1ChainId: number;
|
|
9
|
-
rollupVersion: number;
|
|
10
|
-
setupAllowList: AllowedElement[];
|
|
11
|
-
gasFees: GasFees;
|
|
12
|
-
skipFeeEnforcement?: boolean;
|
|
13
|
-
timestamp: UInt64;
|
|
14
|
-
blockNumber: BlockNumber;
|
|
15
|
-
txsPermitted: boolean;
|
|
16
|
-
}): TxValidator<Tx>;
|
|
17
|
-
export declare function createValidatorForBlockBuilding(db: MerkleTreeReadOperations, contractDataSource: ContractDataSource, globalVariables: GlobalVariables, setupAllowList: AllowedElement[]): PublicProcessorValidator;
|
|
18
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhfdmFsaWRhdG9yX2ZhY3RvcnkuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90eF92YWxpZGF0b3IvdHhfdmFsaWRhdG9yX2ZhY3RvcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBa0I5RCxPQUFPLEtBQUssRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2pFLE9BQU8sS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ2pELE9BQU8sS0FBSyxFQUNWLGNBQWMsRUFDZCw2QkFBNkIsRUFDN0Isd0JBQXdCLEVBQ3hCLHdCQUF3QixFQUN6QixNQUFNLGlDQUFpQyxDQUFDO0FBRXpDLE9BQU8sRUFBRSxlQUFlLEVBQUUsS0FBSyxFQUFFLEVBQUUsS0FBSyxXQUFXLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUM5RSxPQUFPLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUlsRCx3QkFBZ0IsOEJBQThCLENBQzVDLEVBQUUsRUFBRSx3QkFBd0IsRUFDNUIsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQ3RDLFFBQVEsRUFBRSw2QkFBNkIsR0FBRyxTQUFTLEVBQ25ELEVBQ0UsU0FBUyxFQUNULGFBQWEsRUFDYixjQUFjLEVBQ2QsT0FBTyxFQUNQLGtCQUFrQixFQUNsQixTQUFTLEVBQ1QsV0FBVyxFQUNYLFlBQVksRUFDYixFQUFFO0lBQ0QsU0FBUyxFQUFFLE1BQU0sQ0FBQztJQUNsQixhQUFhLEVBQUUsTUFBTSxDQUFDO0lBQ3RCLGNBQWMsRUFBRSxjQUFjLEVBQUUsQ0FBQztJQUNqQyxPQUFPLEVBQUUsT0FBTyxDQUFDO0lBQ2pCLGtCQUFrQixDQUFDLEVBQUUsT0FBTyxDQUFDO0lBQzdCLFNBQVMsRUFBRSxNQUFNLENBQUM7SUFDbEIsV0FBVyxFQUFFLFdBQVcsQ0FBQztJQUN6QixZQUFZLEVBQUUsT0FBTyxDQUFDO0NBQ3ZCLEdBQ0EsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQTZCakI7QUFFRCx3QkFBZ0IsK0JBQStCLENBQzdDLEVBQUUsRUFBRSx3QkFBd0IsRUFDNUIsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQ3RDLGVBQWUsRUFBRSxlQUFlLEVBQ2hDLGNBQWMsRUFBRSxjQUFjLEVBQUUsR0FDL0Isd0JBQXdCLENBZ0IxQiJ9
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tx_validator_factory.d.ts","sourceRoot":"","sources":["../../src/tx_validator/tx_validator_factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAkB9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EACV,cAAc,EACd,6BAA6B,EAC7B,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAIlD,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,wBAAwB,EAC5B,kBAAkB,EAAE,kBAAkB,EACtC,QAAQ,EAAE,6BAA6B,GAAG,SAAS,EACnD,EACE,SAAS,EACT,aAAa,EACb,cAAc,EACd,OAAO,EACP,kBAAkB,EAClB,SAAS,EACT,WAAW,EACX,YAAY,EACb,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,cAAc,EAAE,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,OAAO,CAAC;CACvB,GACA,WAAW,CAAC,EAAE,CAAC,CA6BjB;AAED,wBAAgB,+BAA+B,CAC7C,EAAE,EAAE,wBAAwB,EAC5B,kBAAkB,EAAE,kBAAkB,EACtC,eAAe,EAAE,eAAe,EAChC,cAAc,EAAE,cAAc,EAAE,GAC/B,wBAAwB,CAgB1B"}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
|
-
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
3
|
-
import { AggregateTxValidator, ArchiveCache, BlockHeaderTxValidator, DataTxValidator, DoubleSpendTxValidator, GasTxValidator, MetadataTxValidator, PhasesTxValidator, SizeTxValidator, TimestampTxValidator, TxPermittedValidator, TxProofValidator } from '@aztec/p2p';
|
|
4
|
-
import { ProtocolContractAddress, protocolContractsHash } from '@aztec/protocol-contracts';
|
|
5
|
-
import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
|
|
6
|
-
import { NullifierCache } from './nullifier_cache.js';
|
|
7
|
-
export function createValidatorForAcceptingTxs(db, contractDataSource, verifier, { l1ChainId, rollupVersion, setupAllowList, gasFees, skipFeeEnforcement, timestamp, blockNumber, txsPermitted }) {
|
|
8
|
-
const validators = [
|
|
9
|
-
new TxPermittedValidator(txsPermitted),
|
|
10
|
-
new SizeTxValidator(),
|
|
11
|
-
new DataTxValidator(),
|
|
12
|
-
new MetadataTxValidator({
|
|
13
|
-
l1ChainId: new Fr(l1ChainId),
|
|
14
|
-
rollupVersion: new Fr(rollupVersion),
|
|
15
|
-
protocolContractsHash,
|
|
16
|
-
vkTreeRoot: getVKTreeRoot()
|
|
17
|
-
}),
|
|
18
|
-
new TimestampTxValidator({
|
|
19
|
-
timestamp,
|
|
20
|
-
blockNumber
|
|
21
|
-
}),
|
|
22
|
-
new DoubleSpendTxValidator(new NullifierCache(db)),
|
|
23
|
-
new PhasesTxValidator(contractDataSource, setupAllowList, timestamp),
|
|
24
|
-
new BlockHeaderTxValidator(new ArchiveCache(db))
|
|
25
|
-
];
|
|
26
|
-
if (!skipFeeEnforcement) {
|
|
27
|
-
validators.push(new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, gasFees));
|
|
28
|
-
}
|
|
29
|
-
if (verifier) {
|
|
30
|
-
validators.push(new TxProofValidator(verifier));
|
|
31
|
-
}
|
|
32
|
-
return new AggregateTxValidator(...validators);
|
|
33
|
-
}
|
|
34
|
-
export function createValidatorForBlockBuilding(db, contractDataSource, globalVariables, setupAllowList) {
|
|
35
|
-
const nullifierCache = new NullifierCache(db);
|
|
36
|
-
const archiveCache = new ArchiveCache(db);
|
|
37
|
-
const publicStateSource = new DatabasePublicStateSource(db);
|
|
38
|
-
return {
|
|
39
|
-
preprocessValidator: preprocessValidator(nullifierCache, archiveCache, publicStateSource, contractDataSource, globalVariables, setupAllowList),
|
|
40
|
-
nullifierCache
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
function preprocessValidator(nullifierCache, archiveCache, publicStateSource, contractDataSource, globalVariables, setupAllowList) {
|
|
44
|
-
// We don't include the TxProofValidator nor the DataTxValidator here because they are already checked by the time we get to block building.
|
|
45
|
-
return new AggregateTxValidator(new MetadataTxValidator({
|
|
46
|
-
l1ChainId: globalVariables.chainId,
|
|
47
|
-
rollupVersion: globalVariables.version,
|
|
48
|
-
protocolContractsHash,
|
|
49
|
-
vkTreeRoot: getVKTreeRoot()
|
|
50
|
-
}), new TimestampTxValidator({
|
|
51
|
-
timestamp: globalVariables.timestamp,
|
|
52
|
-
blockNumber: globalVariables.blockNumber
|
|
53
|
-
}), new DoubleSpendTxValidator(nullifierCache), new PhasesTxValidator(contractDataSource, setupAllowList, globalVariables.timestamp), new GasTxValidator(publicStateSource, ProtocolContractAddress.FeeJuice, globalVariables.gasFees), new BlockHeaderTxValidator(archiveCache));
|
|
54
|
-
}
|