@aztec/validator-client 0.0.1-commit.87a0206 → 0.0.1-commit.88c5703d4
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 +55 -10
- package/dest/block_proposal_handler.d.ts +5 -4
- package/dest/block_proposal_handler.d.ts.map +1 -1
- package/dest/block_proposal_handler.js +122 -62
- package/dest/checkpoint_builder.d.ts +16 -5
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +121 -44
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +26 -1
- 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 +6 -12
- package/dest/factory.d.ts +1 -1
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +2 -1
- 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.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 +30 -8
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +171 -33
- package/package.json +19 -19
- package/src/block_proposal_handler.ts +149 -80
- package/src/checkpoint_builder.ts +137 -39
- package/src/config.ts +26 -1
- package/src/duties/validation_service.ts +12 -11
- package/src/factory.ts +1 -0
- package/src/index.ts +0 -1
- package/src/key_store/ha_key_store.ts +1 -1
- package/src/metrics.ts +18 -0
- package/src/validator.ts +216 -39
- 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 -19
- 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 -154
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,13 @@ 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 { DuplicateProposalInfo, 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 {
|
|
27
|
+
import { validateCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
28
|
+
import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
27
29
|
import type {
|
|
28
30
|
CreateCheckpointProposalLastBlockData,
|
|
29
31
|
ITxProvider,
|
|
@@ -32,20 +34,21 @@ import type {
|
|
|
32
34
|
WorldStateSynchronizer,
|
|
33
35
|
} from '@aztec/stdlib/interfaces/server';
|
|
34
36
|
import { type L1ToL2MessageSource, accumulateCheckpointOutHashes } from '@aztec/stdlib/messaging';
|
|
35
|
-
import
|
|
36
|
-
BlockProposal,
|
|
37
|
-
BlockProposalOptions,
|
|
38
|
-
CheckpointAttestation,
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
import {
|
|
38
|
+
type BlockProposal,
|
|
39
|
+
type BlockProposalOptions,
|
|
40
|
+
type CheckpointAttestation,
|
|
41
|
+
CheckpointProposal,
|
|
42
|
+
type CheckpointProposalCore,
|
|
43
|
+
type CheckpointProposalOptions,
|
|
41
44
|
} from '@aztec/stdlib/p2p';
|
|
42
|
-
import { CheckpointProposal } from '@aztec/stdlib/p2p';
|
|
43
45
|
import type { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
44
46
|
import type { BlockHeader, CheckpointGlobalVariables, Tx } from '@aztec/stdlib/tx';
|
|
45
47
|
import { AttestationTimeoutError } from '@aztec/stdlib/validators';
|
|
46
48
|
import { type TelemetryClient, type Tracer, getTelemetryClient } from '@aztec/telemetry-client';
|
|
47
|
-
import { createHASigner } from '@aztec/validator-ha-signer/factory';
|
|
49
|
+
import { createHASigner, createLocalSignerWithProtection } from '@aztec/validator-ha-signer/factory';
|
|
48
50
|
import { DutyType, type SigningContext } from '@aztec/validator-ha-signer/types';
|
|
51
|
+
import type { ValidatorHASigner } from '@aztec/validator-ha-signer/validator-ha-signer';
|
|
49
52
|
|
|
50
53
|
import { EventEmitter } from 'events';
|
|
51
54
|
import type { TypedDataDefinition } from 'viem';
|
|
@@ -76,18 +79,25 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
76
79
|
private validationService: ValidationService;
|
|
77
80
|
private metrics: ValidatorMetrics;
|
|
78
81
|
private log: Logger;
|
|
79
|
-
|
|
80
82
|
// Whether it has already registered handlers on the p2p client
|
|
81
83
|
private hasRegisteredHandlers = false;
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
private
|
|
85
|
+
/** Tracks the last block proposal we created, to detect duplicate proposal attempts. */
|
|
86
|
+
private lastProposedBlock?: BlockProposal;
|
|
87
|
+
|
|
88
|
+
/** Tracks the last checkpoint proposal we created. */
|
|
89
|
+
private lastProposedCheckpoint?: CheckpointProposal;
|
|
85
90
|
|
|
86
91
|
private lastEpochForCommitteeUpdateLoop: EpochNumber | undefined;
|
|
87
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();
|
|
88
95
|
|
|
89
96
|
private proposersOfInvalidBlocks: Set<string> = new Set();
|
|
90
97
|
|
|
98
|
+
/** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */
|
|
99
|
+
private lastAttestedProposal?: CheckpointProposalCore;
|
|
100
|
+
|
|
91
101
|
protected constructor(
|
|
92
102
|
private keyStore: ExtendedValidatorKeyStore,
|
|
93
103
|
private epochCache: EpochCache,
|
|
@@ -99,6 +109,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
99
109
|
private l1ToL2MessageSource: L1ToL2MessageSource,
|
|
100
110
|
private config: ValidatorClientFullConfig,
|
|
101
111
|
private blobClient: BlobClientInterface,
|
|
112
|
+
private slashingProtectionSigner: ValidatorHASigner,
|
|
102
113
|
private dateProvider: DateProvider = new DateProvider(),
|
|
103
114
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
104
115
|
log = createLogger('validator'),
|
|
@@ -152,6 +163,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
152
163
|
this.log.trace(`No committee found for slot`);
|
|
153
164
|
return;
|
|
154
165
|
}
|
|
166
|
+
this.metrics.setCurrentEpoch(epoch);
|
|
155
167
|
if (epoch !== this.lastEpochForCommitteeUpdateLoop) {
|
|
156
168
|
const me = this.getValidatorAddresses();
|
|
157
169
|
const committeeSet = new Set(committee.map(v => v.toString()));
|
|
@@ -189,6 +201,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
189
201
|
const metrics = new ValidatorMetrics(telemetry);
|
|
190
202
|
const blockProposalValidator = new BlockProposalValidator(epochCache, {
|
|
191
203
|
txsPermitted: !config.disableTransactions,
|
|
204
|
+
maxTxsPerBlock: config.validateMaxTxsPerBlock,
|
|
192
205
|
});
|
|
193
206
|
const blockProposalHandler = new BlockProposalHandler(
|
|
194
207
|
checkpointsBuilder,
|
|
@@ -204,16 +217,28 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
204
217
|
telemetry,
|
|
205
218
|
);
|
|
206
219
|
|
|
207
|
-
|
|
220
|
+
const nodeKeystoreAdapter = NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager);
|
|
221
|
+
let slashingProtectionSigner: ValidatorHASigner;
|
|
208
222
|
if (config.haSigningEnabled) {
|
|
223
|
+
// Multi-node HA mode: use PostgreSQL-backed distributed locking.
|
|
209
224
|
// If maxStuckDutiesAgeMs is not explicitly set, compute it from Aztec slot duration
|
|
210
225
|
const haConfig = {
|
|
211
226
|
...config,
|
|
212
227
|
maxStuckDutiesAgeMs: config.maxStuckDutiesAgeMs ?? epochCache.getL1Constants().slotDuration * 2 * 1000,
|
|
213
228
|
};
|
|
214
|
-
|
|
215
|
-
|
|
229
|
+
({ signer: slashingProtectionSigner } = await createHASigner(haConfig, {
|
|
230
|
+
telemetryClient: telemetry,
|
|
231
|
+
dateProvider,
|
|
232
|
+
}));
|
|
233
|
+
} else {
|
|
234
|
+
// Single-node mode: use LMDB-backed local signing protection.
|
|
235
|
+
// This prevents double-signing if the node crashes and restarts mid-proposal.
|
|
236
|
+
({ signer: slashingProtectionSigner } = await createLocalSignerWithProtection(config, {
|
|
237
|
+
telemetryClient: telemetry,
|
|
238
|
+
dateProvider,
|
|
239
|
+
}));
|
|
216
240
|
}
|
|
241
|
+
const validatorKeyStore: ExtendedValidatorKeyStore = new HAKeyStore(nodeKeystoreAdapter, slashingProtectionSigner);
|
|
217
242
|
|
|
218
243
|
const validator = new ValidatorClient(
|
|
219
244
|
validatorKeyStore,
|
|
@@ -226,6 +251,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
226
251
|
l1ToL2MessageSource,
|
|
227
252
|
config,
|
|
228
253
|
blobClient,
|
|
254
|
+
slashingProtectionSigner,
|
|
229
255
|
dateProvider,
|
|
230
256
|
telemetry,
|
|
231
257
|
);
|
|
@@ -263,6 +289,12 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
263
289
|
this.config = { ...this.config, ...config };
|
|
264
290
|
}
|
|
265
291
|
|
|
292
|
+
public reloadKeystore(newManager: KeystoreManager): void {
|
|
293
|
+
const newAdapter = NodeKeystoreAdapter.fromKeyStoreManager(newManager);
|
|
294
|
+
this.keyStore = new HAKeyStore(newAdapter, this.slashingProtectionSigner);
|
|
295
|
+
this.validationService = new ValidationService(this.keyStore, this.log.createChild('validation-service'));
|
|
296
|
+
}
|
|
297
|
+
|
|
266
298
|
public async start() {
|
|
267
299
|
if (this.epochCacheUpdateLoop.isRunning()) {
|
|
268
300
|
this.log.warn(`Validator client already started`);
|
|
@@ -314,6 +346,11 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
314
346
|
this.handleDuplicateProposal(info);
|
|
315
347
|
});
|
|
316
348
|
|
|
349
|
+
// Duplicate attestation handler - triggers slashing for attestation equivocation
|
|
350
|
+
this.p2pClient.registerDuplicateAttestationCallback((info: DuplicateAttestationInfo) => {
|
|
351
|
+
this.handleDuplicateAttestation(info);
|
|
352
|
+
});
|
|
353
|
+
|
|
317
354
|
const myAddresses = this.getValidatorAddresses();
|
|
318
355
|
this.p2pClient.registerThisValidatorAddresses(myAddresses);
|
|
319
356
|
|
|
@@ -341,6 +378,15 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
341
378
|
return false;
|
|
342
379
|
}
|
|
343
380
|
|
|
381
|
+
// Ignore proposals from ourselves (may happen in HA setups)
|
|
382
|
+
if (this.getValidatorAddresses().some(addr => addr.equals(proposer))) {
|
|
383
|
+
this.log.debug(`Ignoring block proposal from self for slot ${slotNumber}`, {
|
|
384
|
+
proposer: proposer.toString(),
|
|
385
|
+
slotNumber,
|
|
386
|
+
});
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
|
|
344
390
|
// Check if we're in the committee (for metrics purposes)
|
|
345
391
|
const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.getValidatorAddresses());
|
|
346
392
|
const partOfCommittee = inCommittee.length > 0;
|
|
@@ -370,9 +416,10 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
370
416
|
);
|
|
371
417
|
|
|
372
418
|
if (!validationResult.isValid) {
|
|
373
|
-
this.log.warn(`Block proposal validation failed: ${validationResult.reason}`, proposalInfo);
|
|
374
|
-
|
|
375
419
|
const reason = validationResult.reason || 'unknown';
|
|
420
|
+
|
|
421
|
+
this.log.warn(`Block proposal validation failed: ${reason}`, proposalInfo);
|
|
422
|
+
|
|
376
423
|
// Classify failure reason: bad proposal vs node issue
|
|
377
424
|
const badProposalReasons: BlockProposalValidationFailureReason[] = [
|
|
378
425
|
'invalid_proposal',
|
|
@@ -442,6 +489,23 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
442
489
|
return undefined;
|
|
443
490
|
}
|
|
444
491
|
|
|
492
|
+
// Ignore proposals from ourselves (may happen in HA setups)
|
|
493
|
+
if (this.getValidatorAddresses().some(addr => addr.equals(proposer))) {
|
|
494
|
+
this.log.debug(`Ignoring block proposal from self for slot ${slotNumber}`, {
|
|
495
|
+
proposer: proposer.toString(),
|
|
496
|
+
slotNumber,
|
|
497
|
+
});
|
|
498
|
+
return undefined;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Validate fee asset price modifier is within allowed range
|
|
502
|
+
if (!validateFeeAssetPriceModifier(proposal.feeAssetPriceModifier)) {
|
|
503
|
+
this.log.warn(
|
|
504
|
+
`Received checkpoint proposal with invalid feeAssetPriceModifier ${proposal.feeAssetPriceModifier} for slot ${slotNumber}`,
|
|
505
|
+
);
|
|
506
|
+
return undefined;
|
|
507
|
+
}
|
|
508
|
+
|
|
445
509
|
// Check that I have any address in current committee before attesting
|
|
446
510
|
const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.getValidatorAddresses());
|
|
447
511
|
const partOfCommittee = inCommittee.length > 0;
|
|
@@ -450,11 +514,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
450
514
|
slotNumber,
|
|
451
515
|
archive: proposal.archive.toString(),
|
|
452
516
|
proposer: proposer.toString(),
|
|
453
|
-
txCount: proposal.txHashes.length,
|
|
454
517
|
};
|
|
455
518
|
this.log.info(`Received checkpoint proposal for slot ${slotNumber}`, {
|
|
456
519
|
...proposalInfo,
|
|
457
|
-
txHashes: proposal.txHashes.map(t => t.toString()),
|
|
458
520
|
fishermanMode: this.config.fishermanMode || false,
|
|
459
521
|
});
|
|
460
522
|
|
|
@@ -490,6 +552,17 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
490
552
|
|
|
491
553
|
this.metrics.incSuccessfulAttestations(inCommittee.length);
|
|
492
554
|
|
|
555
|
+
// Track epoch participation per attester: count each (attester, epoch) pair at most once
|
|
556
|
+
const proposalEpoch = getEpochAtSlot(slotNumber, this.epochCache.getL1Constants());
|
|
557
|
+
for (const attester of inCommittee) {
|
|
558
|
+
const key = attester.toString();
|
|
559
|
+
const lastEpoch = this.lastAttestedEpochByAttester.get(key);
|
|
560
|
+
if (lastEpoch === undefined || proposalEpoch > lastEpoch) {
|
|
561
|
+
this.lastAttestedEpochByAttester.set(key, proposalEpoch);
|
|
562
|
+
this.metrics.incAttestedEpochCount(attester);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
493
566
|
// Determine which validators should attest
|
|
494
567
|
let attestors: EthAddress[];
|
|
495
568
|
if (partOfCommittee) {
|
|
@@ -515,14 +588,44 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
515
588
|
return undefined;
|
|
516
589
|
}
|
|
517
590
|
|
|
518
|
-
return this.createCheckpointAttestationsFromProposal(proposal, attestors);
|
|
591
|
+
return await this.createCheckpointAttestationsFromProposal(proposal, attestors);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Checks if we should attest to a slot based on equivocation prevention rules.
|
|
596
|
+
* @returns true if we should attest, false if we should skip
|
|
597
|
+
*/
|
|
598
|
+
private shouldAttestToSlot(slotNumber: SlotNumber): boolean {
|
|
599
|
+
// If attestToEquivocatedProposals is true, always allow
|
|
600
|
+
if (this.config.attestToEquivocatedProposals) {
|
|
601
|
+
return true;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Check if incoming slot is strictly greater than last attested
|
|
605
|
+
if (this.lastAttestedProposal && slotNumber <= this.lastAttestedProposal.slotNumber) {
|
|
606
|
+
this.log.warn(
|
|
607
|
+
`Refusing to process a proposal for slot ${slotNumber} given we already attested to a proposal for slot ${this.lastAttestedProposal.slotNumber}`,
|
|
608
|
+
);
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
return true;
|
|
519
613
|
}
|
|
520
614
|
|
|
521
615
|
private async createCheckpointAttestationsFromProposal(
|
|
522
616
|
proposal: CheckpointProposalCore,
|
|
523
617
|
attestors: EthAddress[] = [],
|
|
524
|
-
): Promise<CheckpointAttestation[]> {
|
|
618
|
+
): Promise<CheckpointAttestation[] | undefined> {
|
|
619
|
+
// Equivocation check: must happen right before signing to minimize the race window
|
|
620
|
+
if (!this.shouldAttestToSlot(proposal.slotNumber)) {
|
|
621
|
+
return undefined;
|
|
622
|
+
}
|
|
623
|
+
|
|
525
624
|
const attestations = await this.validationService.attestToCheckpointProposal(proposal, attestors);
|
|
625
|
+
|
|
626
|
+
// Track the proposal we attested to (to prevent equivocation)
|
|
627
|
+
this.lastAttestedProposal = proposal;
|
|
628
|
+
|
|
526
629
|
await this.p2pClient.addOwnCheckpointAttestations(attestations);
|
|
527
630
|
return attestations;
|
|
528
631
|
}
|
|
@@ -536,7 +639,11 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
536
639
|
proposalInfo: LogData,
|
|
537
640
|
): Promise<{ isValid: true } | { isValid: false; reason: string }> {
|
|
538
641
|
const slot = proposal.slotNumber;
|
|
539
|
-
|
|
642
|
+
|
|
643
|
+
// Timeout block syncing at the start of the next slot
|
|
644
|
+
const config = this.checkpointsBuilder.getConfig();
|
|
645
|
+
const nextSlotTimestampSeconds = Number(getTimestampForSlot(SlotNumber(slot + 1), config));
|
|
646
|
+
const timeoutSeconds = Math.max(1, nextSlotTimestampSeconds - Math.floor(this.dateProvider.now() / 1000));
|
|
540
647
|
|
|
541
648
|
// Wait for last block to sync by archive
|
|
542
649
|
let lastBlockHeader: BlockHeader | undefined;
|
|
@@ -571,6 +678,12 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
571
678
|
return { isValid: false, reason: 'no_blocks_for_slot' };
|
|
572
679
|
}
|
|
573
680
|
|
|
681
|
+
// Ensure the last block for this slot matches the archive in the checkpoint proposal
|
|
682
|
+
if (!blocks.at(-1)?.archive.root.equals(proposal.archive)) {
|
|
683
|
+
this.log.warn(`Last block archive mismatch for checkpoint proposal`, proposalInfo);
|
|
684
|
+
return { isValid: false, reason: 'last_block_archive_mismatch' };
|
|
685
|
+
}
|
|
686
|
+
|
|
574
687
|
this.log.debug(`Found ${blocks.length} blocks for slot ${slot}`, {
|
|
575
688
|
...proposalInfo,
|
|
576
689
|
blockNumbers: blocks.map(b => b.number),
|
|
@@ -584,14 +697,11 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
584
697
|
// Get L1-to-L2 messages for this checkpoint
|
|
585
698
|
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
586
699
|
|
|
587
|
-
//
|
|
588
|
-
// TODO: There can be a more efficient way to get the previous checkpoint out hashes without having to fetch the
|
|
589
|
-
// actual checkpoints and the blocks/txs in them.
|
|
700
|
+
// Collect the out hashes of all the checkpoints before this one in the same epoch
|
|
590
701
|
const epoch = getEpochAtSlot(slot, this.epochCache.getL1Constants());
|
|
591
|
-
const
|
|
592
|
-
.filter(
|
|
593
|
-
.
|
|
594
|
-
const previousCheckpointOutHashes = previousCheckpoints.map(c => c.getCheckpointOutHash());
|
|
702
|
+
const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch))
|
|
703
|
+
.filter(c => c.checkpointNumber < checkpointNumber)
|
|
704
|
+
.map(c => c.checkpointOutHash);
|
|
595
705
|
|
|
596
706
|
// Fork world state at the block before the first block
|
|
597
707
|
const parentBlockNumber = BlockNumber(firstBlock.number - 1);
|
|
@@ -602,6 +712,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
602
712
|
const checkpointBuilder = await this.checkpointsBuilder.openCheckpoint(
|
|
603
713
|
checkpointNumber,
|
|
604
714
|
constants,
|
|
715
|
+
proposal.feeAssetPriceModifier,
|
|
605
716
|
l1ToL2Messages,
|
|
606
717
|
previousCheckpointOutHashes,
|
|
607
718
|
fork,
|
|
@@ -648,6 +759,20 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
648
759
|
return { isValid: false, reason: 'out_hash_mismatch' };
|
|
649
760
|
}
|
|
650
761
|
|
|
762
|
+
// Final round of validations on the checkpoint, just in case.
|
|
763
|
+
try {
|
|
764
|
+
validateCheckpoint(computedCheckpoint, {
|
|
765
|
+
rollupManaLimit: this.checkpointsBuilder.getConfig().rollupManaLimit,
|
|
766
|
+
maxDABlockGas: this.config.validateMaxDABlockGas,
|
|
767
|
+
maxL2BlockGas: this.config.validateMaxL2BlockGas,
|
|
768
|
+
maxTxsPerBlock: this.config.validateMaxTxsPerBlock,
|
|
769
|
+
maxTxsPerCheckpoint: this.config.validateMaxTxsPerCheckpoint,
|
|
770
|
+
});
|
|
771
|
+
} catch (err) {
|
|
772
|
+
this.log.warn(`Checkpoint validation failed: ${err}`, proposalInfo);
|
|
773
|
+
return { isValid: false, reason: 'checkpoint_validation_failed' };
|
|
774
|
+
}
|
|
775
|
+
|
|
651
776
|
this.log.verbose(`Checkpoint proposal validation successful for slot ${slot}`, proposalInfo);
|
|
652
777
|
return { isValid: true };
|
|
653
778
|
} finally {
|
|
@@ -664,6 +789,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
664
789
|
chainId: gv.chainId,
|
|
665
790
|
version: gv.version,
|
|
666
791
|
slotNumber: gv.slotNumber,
|
|
792
|
+
timestamp: gv.timestamp,
|
|
667
793
|
coinbase: gv.coinbase,
|
|
668
794
|
feeRecipient: gv.feeRecipient,
|
|
669
795
|
gasFees: gv.gasFees,
|
|
@@ -673,7 +799,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
673
799
|
/**
|
|
674
800
|
* Uploads blobs for a checkpoint to the filestore (fire and forget).
|
|
675
801
|
*/
|
|
676
|
-
|
|
802
|
+
protected async uploadBlobsForCheckpoint(proposal: CheckpointProposalCore, proposalInfo: LogData): Promise<void> {
|
|
677
803
|
try {
|
|
678
804
|
const lastBlockHeader = await this.blockSource.getBlockHeaderByArchive(proposal.archive);
|
|
679
805
|
if (!lastBlockHeader) {
|
|
@@ -688,7 +814,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
688
814
|
}
|
|
689
815
|
|
|
690
816
|
const blobFields = blocks.flatMap(b => b.toBlobFields());
|
|
691
|
-
const blobs: Blob[] = getBlobsPerL1Block(blobFields);
|
|
817
|
+
const blobs: Blob[] = await getBlobsPerL1Block(blobFields);
|
|
692
818
|
await this.blobClient.sendBlobsToFilestore(blobs);
|
|
693
819
|
this.log.debug(`Uploaded ${blobs.length} blobs to filestore for checkpoint at slot ${proposal.slotNumber}`, {
|
|
694
820
|
...proposalInfo,
|
|
@@ -750,6 +876,28 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
750
876
|
]);
|
|
751
877
|
}
|
|
752
878
|
|
|
879
|
+
/**
|
|
880
|
+
* Handle detection of a duplicate attestation (equivocation).
|
|
881
|
+
* Emits a slash event when an attester signs attestations for different proposals at the same slot.
|
|
882
|
+
*/
|
|
883
|
+
private handleDuplicateAttestation(info: DuplicateAttestationInfo): void {
|
|
884
|
+
const { slot, attester } = info;
|
|
885
|
+
|
|
886
|
+
this.log.warn(`Triggering slash event for duplicate attestation from ${attester.toString()} at slot ${slot}`, {
|
|
887
|
+
attester: attester.toString(),
|
|
888
|
+
slot,
|
|
889
|
+
});
|
|
890
|
+
|
|
891
|
+
this.emit(WANT_TO_SLASH_EVENT, [
|
|
892
|
+
{
|
|
893
|
+
validator: attester,
|
|
894
|
+
amount: this.config.slashDuplicateAttestationPenalty,
|
|
895
|
+
offenseType: OffenseType.DUPLICATE_ATTESTATION,
|
|
896
|
+
epochOrSlot: BigInt(slot),
|
|
897
|
+
},
|
|
898
|
+
]);
|
|
899
|
+
}
|
|
900
|
+
|
|
753
901
|
async createBlockProposal(
|
|
754
902
|
blockHeader: BlockHeader,
|
|
755
903
|
indexWithinCheckpoint: IndexWithinCheckpoint,
|
|
@@ -759,11 +907,19 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
759
907
|
proposerAddress: EthAddress | undefined,
|
|
760
908
|
options: BlockProposalOptions = {},
|
|
761
909
|
): Promise<BlockProposal> {
|
|
762
|
-
//
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
910
|
+
// Validate that we're not creating a proposal for an older or equal position
|
|
911
|
+
if (this.lastProposedBlock) {
|
|
912
|
+
const lastSlot = this.lastProposedBlock.slotNumber;
|
|
913
|
+
const lastIndex = this.lastProposedBlock.indexWithinCheckpoint;
|
|
914
|
+
const newSlot = blockHeader.globalVariables.slotNumber;
|
|
915
|
+
|
|
916
|
+
if (newSlot < lastSlot || (newSlot === lastSlot && indexWithinCheckpoint <= lastIndex)) {
|
|
917
|
+
throw new Error(
|
|
918
|
+
`Cannot create block proposal for slot ${newSlot} index ${indexWithinCheckpoint}: ` +
|
|
919
|
+
`already proposed block for slot ${lastSlot} index ${lastIndex}`,
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
767
923
|
|
|
768
924
|
this.log.info(
|
|
769
925
|
`Assembling block proposal for block ${blockHeader.globalVariables.blockNumber} slot ${blockHeader.globalVariables.slotNumber}`,
|
|
@@ -780,25 +936,42 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
780
936
|
broadcastInvalidBlockProposal: this.config.broadcastInvalidBlockProposal,
|
|
781
937
|
},
|
|
782
938
|
);
|
|
783
|
-
this.
|
|
939
|
+
this.lastProposedBlock = newProposal;
|
|
784
940
|
return newProposal;
|
|
785
941
|
}
|
|
786
942
|
|
|
787
943
|
async createCheckpointProposal(
|
|
788
944
|
checkpointHeader: CheckpointHeader,
|
|
789
945
|
archive: Fr,
|
|
946
|
+
feeAssetPriceModifier: bigint,
|
|
790
947
|
lastBlockInfo: CreateCheckpointProposalLastBlockData | undefined,
|
|
791
948
|
proposerAddress: EthAddress | undefined,
|
|
792
949
|
options: CheckpointProposalOptions = {},
|
|
793
950
|
): Promise<CheckpointProposal> {
|
|
951
|
+
// Validate that we're not creating a proposal for an older or equal slot
|
|
952
|
+
if (this.lastProposedCheckpoint) {
|
|
953
|
+
const lastSlot = this.lastProposedCheckpoint.slotNumber;
|
|
954
|
+
const newSlot = checkpointHeader.slotNumber;
|
|
955
|
+
|
|
956
|
+
if (newSlot <= lastSlot) {
|
|
957
|
+
throw new Error(
|
|
958
|
+
`Cannot create checkpoint proposal for slot ${newSlot}: ` +
|
|
959
|
+
`already proposed checkpoint for slot ${lastSlot}`,
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
|
|
794
964
|
this.log.info(`Assembling checkpoint proposal for slot ${checkpointHeader.slotNumber}`);
|
|
795
|
-
|
|
965
|
+
const newProposal = await this.validationService.createCheckpointProposal(
|
|
796
966
|
checkpointHeader,
|
|
797
967
|
archive,
|
|
968
|
+
feeAssetPriceModifier,
|
|
798
969
|
lastBlockInfo,
|
|
799
970
|
proposerAddress,
|
|
800
971
|
options,
|
|
801
972
|
);
|
|
973
|
+
this.lastProposedCheckpoint = newProposal;
|
|
974
|
+
return newProposal;
|
|
802
975
|
}
|
|
803
976
|
|
|
804
977
|
async broadcastBlockProposal(proposal: BlockProposal): Promise<void> {
|
|
@@ -820,6 +993,10 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
820
993
|
this.log.debug(`Collecting ${inCommittee.length} self-attestations for slot ${slot}`, { inCommittee });
|
|
821
994
|
const attestations = await this.createCheckpointAttestationsFromProposal(proposal, inCommittee);
|
|
822
995
|
|
|
996
|
+
if (!attestations) {
|
|
997
|
+
return [];
|
|
998
|
+
}
|
|
999
|
+
|
|
823
1000
|
// We broadcast our own attestations to our peers so, in case our block does not get mined on L1,
|
|
824
1001
|
// other nodes can see that our validators did attest to this block proposal, and do not slash us
|
|
825
1002
|
// 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,19 +0,0 @@
|
|
|
1
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import type { LoggerBindings } from '@aztec/foundation/log';
|
|
3
|
-
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
4
|
-
import type { GasFees } from '@aztec/stdlib/gas';
|
|
5
|
-
import type { AllowedElement, ClientProtocolCircuitVerifier, MerkleTreeReadOperations, PublicProcessorValidator } from '@aztec/stdlib/interfaces/server';
|
|
6
|
-
import { GlobalVariables, type Tx, type TxValidator } from '@aztec/stdlib/tx';
|
|
7
|
-
import type { UInt64 } from '@aztec/stdlib/types';
|
|
8
|
-
export declare function createValidatorForAcceptingTxs(db: MerkleTreeReadOperations, contractDataSource: ContractDataSource, verifier: ClientProtocolCircuitVerifier | undefined, { l1ChainId, rollupVersion, setupAllowList, gasFees, skipFeeEnforcement, timestamp, blockNumber, txsPermitted }: {
|
|
9
|
-
l1ChainId: number;
|
|
10
|
-
rollupVersion: number;
|
|
11
|
-
setupAllowList: AllowedElement[];
|
|
12
|
-
gasFees: GasFees;
|
|
13
|
-
skipFeeEnforcement?: boolean;
|
|
14
|
-
timestamp: UInt64;
|
|
15
|
-
blockNumber: BlockNumber;
|
|
16
|
-
txsPermitted: boolean;
|
|
17
|
-
}, bindings?: LoggerBindings): TxValidator<Tx>;
|
|
18
|
-
export declare function createValidatorForBlockBuilding(db: MerkleTreeReadOperations, contractDataSource: ContractDataSource, globalVariables: GlobalVariables, setupAllowList: AllowedElement[], bindings?: LoggerBindings): PublicProcessorValidator;
|
|
19
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhfdmFsaWRhdG9yX2ZhY3RvcnkuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90eF92YWxpZGF0b3IvdHhfdmFsaWRhdG9yX2ZhY3RvcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRTlELE9BQU8sS0FBSyxFQUFFLGNBQWMsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBaUI1RCxPQUFPLEtBQUssRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2pFLE9BQU8sS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ2pELE9BQU8sS0FBSyxFQUNWLGNBQWMsRUFDZCw2QkFBNkIsRUFDN0Isd0JBQXdCLEVBQ3hCLHdCQUF3QixFQUN6QixNQUFNLGlDQUFpQyxDQUFDO0FBRXpDLE9BQU8sRUFBRSxlQUFlLEVBQUUsS0FBSyxFQUFFLEVBQUUsS0FBSyxXQUFXLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUM5RSxPQUFPLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUlsRCx3QkFBZ0IsOEJBQThCLENBQzVDLEVBQUUsRUFBRSx3QkFBd0IsRUFDNUIsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQ3RDLFFBQVEsRUFBRSw2QkFBNkIsR0FBRyxTQUFTLEVBQ25ELEVBQ0UsU0FBUyxFQUNULGFBQWEsRUFDYixjQUFjLEVBQ2QsT0FBTyxFQUNQLGtCQUFrQixFQUNsQixTQUFTLEVBQ1QsV0FBVyxFQUNYLFlBQVksRUFDYixFQUFFO0lBQ0QsU0FBUyxFQUFFLE1BQU0sQ0FBQztJQUNsQixhQUFhLEVBQUUsTUFBTSxDQUFDO0lBQ3RCLGNBQWMsRUFBRSxjQUFjLEVBQUUsQ0FBQztJQUNqQyxPQUFPLEVBQUUsT0FBTyxDQUFDO0lBQ2pCLGtCQUFrQixDQUFDLEVBQUUsT0FBTyxDQUFDO0lBQzdCLFNBQVMsRUFBRSxNQUFNLENBQUM7SUFDbEIsV0FBVyxFQUFFLFdBQVcsQ0FBQztJQUN6QixZQUFZLEVBQUUsT0FBTyxDQUFDO0NBQ3ZCLEVBQ0QsUUFBUSxDQUFDLEVBQUUsY0FBYyxHQUN4QixXQUFXLENBQUMsRUFBRSxDQUFDLENBcUNqQjtBQUVELHdCQUFnQiwrQkFBK0IsQ0FDN0MsRUFBRSxFQUFFLHdCQUF3QixFQUM1QixrQkFBa0IsRUFBRSxrQkFBa0IsRUFDdEMsZUFBZSxFQUFFLGVBQWUsRUFDaEMsY0FBYyxFQUFFLGNBQWMsRUFBRSxFQUNoQyxRQUFRLENBQUMsRUFBRSxjQUFjLEdBQ3hCLHdCQUF3QixDQWlCMUIifQ==
|
|
@@ -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;AAE9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAiB5D,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,EACD,QAAQ,CAAC,EAAE,cAAc,GACxB,WAAW,CAAC,EAAE,CAAC,CAqCjB;AAED,wBAAgB,+BAA+B,CAC7C,EAAE,EAAE,wBAAwB,EAC5B,kBAAkB,EAAE,kBAAkB,EACtC,eAAe,EAAE,eAAe,EAChC,cAAc,EAAE,cAAc,EAAE,EAChC,QAAQ,CAAC,EAAE,cAAc,GACxB,wBAAwB,CAiB1B"}
|
|
@@ -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 }, bindings) {
|
|
8
|
-
const validators = [
|
|
9
|
-
new TxPermittedValidator(txsPermitted, bindings),
|
|
10
|
-
new SizeTxValidator(bindings),
|
|
11
|
-
new DataTxValidator(bindings),
|
|
12
|
-
new MetadataTxValidator({
|
|
13
|
-
l1ChainId: new Fr(l1ChainId),
|
|
14
|
-
rollupVersion: new Fr(rollupVersion),
|
|
15
|
-
protocolContractsHash,
|
|
16
|
-
vkTreeRoot: getVKTreeRoot()
|
|
17
|
-
}, bindings),
|
|
18
|
-
new TimestampTxValidator({
|
|
19
|
-
timestamp,
|
|
20
|
-
blockNumber
|
|
21
|
-
}, bindings),
|
|
22
|
-
new DoubleSpendTxValidator(new NullifierCache(db), bindings),
|
|
23
|
-
new PhasesTxValidator(contractDataSource, setupAllowList, timestamp, bindings),
|
|
24
|
-
new BlockHeaderTxValidator(new ArchiveCache(db), bindings)
|
|
25
|
-
];
|
|
26
|
-
if (!skipFeeEnforcement) {
|
|
27
|
-
validators.push(new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, gasFees, bindings));
|
|
28
|
-
}
|
|
29
|
-
if (verifier) {
|
|
30
|
-
validators.push(new TxProofValidator(verifier, bindings));
|
|
31
|
-
}
|
|
32
|
-
return new AggregateTxValidator(...validators);
|
|
33
|
-
}
|
|
34
|
-
export function createValidatorForBlockBuilding(db, contractDataSource, globalVariables, setupAllowList, bindings) {
|
|
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, bindings),
|
|
40
|
-
nullifierCache
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
function preprocessValidator(nullifierCache, archiveCache, publicStateSource, contractDataSource, globalVariables, setupAllowList, bindings) {
|
|
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
|
-
}, bindings), new TimestampTxValidator({
|
|
51
|
-
timestamp: globalVariables.timestamp,
|
|
52
|
-
blockNumber: globalVariables.blockNumber
|
|
53
|
-
}, bindings), new DoubleSpendTxValidator(nullifierCache, bindings), new PhasesTxValidator(contractDataSource, setupAllowList, globalVariables.timestamp, bindings), new GasTxValidator(publicStateSource, ProtocolContractAddress.FeeJuice, globalVariables.gasFees, bindings), new BlockHeaderTxValidator(archiveCache, bindings));
|
|
54
|
-
}
|