@aztec/validator-client 0.0.1-commit.f2ce05ee → 0.0.1-commit.f81dbcf
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 +54 -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 +124 -62
- package/dest/checkpoint_builder.d.ts +16 -5
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +112 -44
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +24 -0
- 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 +169 -31
- package/package.json +19 -19
- package/src/block_proposal_handler.ts +151 -80
- package/src/checkpoint_builder.ts +129 -39
- package/src/config.ts +24 -0
- 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 +221 -37
- 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
49
|
import { createHASigner } 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 haSigner: ValidatorHASigner | undefined,
|
|
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,7 +217,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
204
217
|
telemetry,
|
|
205
218
|
);
|
|
206
219
|
|
|
207
|
-
|
|
220
|
+
const nodeKeystoreAdapter = NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager);
|
|
221
|
+
let validatorKeyStore: ExtendedValidatorKeyStore = nodeKeystoreAdapter;
|
|
222
|
+
let haSigner: ValidatorHASigner | undefined;
|
|
208
223
|
if (config.haSigningEnabled) {
|
|
209
224
|
// If maxStuckDutiesAgeMs is not explicitly set, compute it from Aztec slot duration
|
|
210
225
|
const haConfig = {
|
|
@@ -212,7 +227,8 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
212
227
|
maxStuckDutiesAgeMs: config.maxStuckDutiesAgeMs ?? epochCache.getL1Constants().slotDuration * 2 * 1000,
|
|
213
228
|
};
|
|
214
229
|
const { signer } = await createHASigner(haConfig);
|
|
215
|
-
|
|
230
|
+
haSigner = signer;
|
|
231
|
+
validatorKeyStore = new HAKeyStore(nodeKeystoreAdapter, signer);
|
|
216
232
|
}
|
|
217
233
|
|
|
218
234
|
const validator = new ValidatorClient(
|
|
@@ -226,6 +242,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
226
242
|
l1ToL2MessageSource,
|
|
227
243
|
config,
|
|
228
244
|
blobClient,
|
|
245
|
+
haSigner,
|
|
229
246
|
dateProvider,
|
|
230
247
|
telemetry,
|
|
231
248
|
);
|
|
@@ -263,6 +280,28 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
263
280
|
this.config = { ...this.config, ...config };
|
|
264
281
|
}
|
|
265
282
|
|
|
283
|
+
public reloadKeystore(newManager: KeystoreManager): void {
|
|
284
|
+
if (this.config.haSigningEnabled && !this.haSigner) {
|
|
285
|
+
this.log.warn(
|
|
286
|
+
'HA signing is enabled in config but was not initialized at startup. ' +
|
|
287
|
+
'Restart the node to enable HA signing.',
|
|
288
|
+
);
|
|
289
|
+
} else if (!this.config.haSigningEnabled && this.haSigner) {
|
|
290
|
+
this.log.warn(
|
|
291
|
+
'HA signing was disabled via config update but the HA signer is still active. ' +
|
|
292
|
+
'Restart the node to fully disable HA signing.',
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const newAdapter = NodeKeystoreAdapter.fromKeyStoreManager(newManager);
|
|
297
|
+
if (this.haSigner) {
|
|
298
|
+
this.keyStore = new HAKeyStore(newAdapter, this.haSigner);
|
|
299
|
+
} else {
|
|
300
|
+
this.keyStore = newAdapter;
|
|
301
|
+
}
|
|
302
|
+
this.validationService = new ValidationService(this.keyStore, this.log.createChild('validation-service'));
|
|
303
|
+
}
|
|
304
|
+
|
|
266
305
|
public async start() {
|
|
267
306
|
if (this.epochCacheUpdateLoop.isRunning()) {
|
|
268
307
|
this.log.warn(`Validator client already started`);
|
|
@@ -314,6 +353,11 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
314
353
|
this.handleDuplicateProposal(info);
|
|
315
354
|
});
|
|
316
355
|
|
|
356
|
+
// Duplicate attestation handler - triggers slashing for attestation equivocation
|
|
357
|
+
this.p2pClient.registerDuplicateAttestationCallback((info: DuplicateAttestationInfo) => {
|
|
358
|
+
this.handleDuplicateAttestation(info);
|
|
359
|
+
});
|
|
360
|
+
|
|
317
361
|
const myAddresses = this.getValidatorAddresses();
|
|
318
362
|
this.p2pClient.registerThisValidatorAddresses(myAddresses);
|
|
319
363
|
|
|
@@ -341,6 +385,15 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
341
385
|
return false;
|
|
342
386
|
}
|
|
343
387
|
|
|
388
|
+
// Ignore proposals from ourselves (may happen in HA setups)
|
|
389
|
+
if (this.getValidatorAddresses().some(addr => addr.equals(proposer))) {
|
|
390
|
+
this.log.debug(`Ignoring block proposal from self for slot ${slotNumber}`, {
|
|
391
|
+
proposer: proposer.toString(),
|
|
392
|
+
slotNumber,
|
|
393
|
+
});
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
|
|
344
397
|
// Check if we're in the committee (for metrics purposes)
|
|
345
398
|
const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.getValidatorAddresses());
|
|
346
399
|
const partOfCommittee = inCommittee.length > 0;
|
|
@@ -370,9 +423,10 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
370
423
|
);
|
|
371
424
|
|
|
372
425
|
if (!validationResult.isValid) {
|
|
373
|
-
this.log.warn(`Block proposal validation failed: ${validationResult.reason}`, proposalInfo);
|
|
374
|
-
|
|
375
426
|
const reason = validationResult.reason || 'unknown';
|
|
427
|
+
|
|
428
|
+
this.log.warn(`Block proposal validation failed: ${reason}`, proposalInfo);
|
|
429
|
+
|
|
376
430
|
// Classify failure reason: bad proposal vs node issue
|
|
377
431
|
const badProposalReasons: BlockProposalValidationFailureReason[] = [
|
|
378
432
|
'invalid_proposal',
|
|
@@ -442,6 +496,23 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
442
496
|
return undefined;
|
|
443
497
|
}
|
|
444
498
|
|
|
499
|
+
// Ignore proposals from ourselves (may happen in HA setups)
|
|
500
|
+
if (this.getValidatorAddresses().some(addr => addr.equals(proposer))) {
|
|
501
|
+
this.log.debug(`Ignoring block proposal from self for slot ${slotNumber}`, {
|
|
502
|
+
proposer: proposer.toString(),
|
|
503
|
+
slotNumber,
|
|
504
|
+
});
|
|
505
|
+
return undefined;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Validate fee asset price modifier is within allowed range
|
|
509
|
+
if (!validateFeeAssetPriceModifier(proposal.feeAssetPriceModifier)) {
|
|
510
|
+
this.log.warn(
|
|
511
|
+
`Received checkpoint proposal with invalid feeAssetPriceModifier ${proposal.feeAssetPriceModifier} for slot ${slotNumber}`,
|
|
512
|
+
);
|
|
513
|
+
return undefined;
|
|
514
|
+
}
|
|
515
|
+
|
|
445
516
|
// Check that I have any address in current committee before attesting
|
|
446
517
|
const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.getValidatorAddresses());
|
|
447
518
|
const partOfCommittee = inCommittee.length > 0;
|
|
@@ -450,11 +521,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
450
521
|
slotNumber,
|
|
451
522
|
archive: proposal.archive.toString(),
|
|
452
523
|
proposer: proposer.toString(),
|
|
453
|
-
txCount: proposal.txHashes.length,
|
|
454
524
|
};
|
|
455
525
|
this.log.info(`Received checkpoint proposal for slot ${slotNumber}`, {
|
|
456
526
|
...proposalInfo,
|
|
457
|
-
txHashes: proposal.txHashes.map(t => t.toString()),
|
|
458
527
|
fishermanMode: this.config.fishermanMode || false,
|
|
459
528
|
});
|
|
460
529
|
|
|
@@ -490,6 +559,17 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
490
559
|
|
|
491
560
|
this.metrics.incSuccessfulAttestations(inCommittee.length);
|
|
492
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
|
+
|
|
493
573
|
// Determine which validators should attest
|
|
494
574
|
let attestors: EthAddress[];
|
|
495
575
|
if (partOfCommittee) {
|
|
@@ -515,14 +595,44 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
515
595
|
return undefined;
|
|
516
596
|
}
|
|
517
597
|
|
|
518
|
-
return this.createCheckpointAttestationsFromProposal(proposal, attestors);
|
|
598
|
+
return await this.createCheckpointAttestationsFromProposal(proposal, attestors);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Checks if we should attest to a slot based on equivocation prevention rules.
|
|
603
|
+
* @returns true if we should attest, false if we should skip
|
|
604
|
+
*/
|
|
605
|
+
private shouldAttestToSlot(slotNumber: SlotNumber): boolean {
|
|
606
|
+
// If attestToEquivocatedProposals is true, always allow
|
|
607
|
+
if (this.config.attestToEquivocatedProposals) {
|
|
608
|
+
return true;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Check if incoming slot is strictly greater than last attested
|
|
612
|
+
if (this.lastAttestedProposal && slotNumber <= this.lastAttestedProposal.slotNumber) {
|
|
613
|
+
this.log.warn(
|
|
614
|
+
`Refusing to process a proposal for slot ${slotNumber} given we already attested to a proposal for slot ${this.lastAttestedProposal.slotNumber}`,
|
|
615
|
+
);
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
return true;
|
|
519
620
|
}
|
|
520
621
|
|
|
521
622
|
private async createCheckpointAttestationsFromProposal(
|
|
522
623
|
proposal: CheckpointProposalCore,
|
|
523
624
|
attestors: EthAddress[] = [],
|
|
524
|
-
): Promise<CheckpointAttestation[]> {
|
|
625
|
+
): Promise<CheckpointAttestation[] | undefined> {
|
|
626
|
+
// Equivocation check: must happen right before signing to minimize the race window
|
|
627
|
+
if (!this.shouldAttestToSlot(proposal.slotNumber)) {
|
|
628
|
+
return undefined;
|
|
629
|
+
}
|
|
630
|
+
|
|
525
631
|
const attestations = await this.validationService.attestToCheckpointProposal(proposal, attestors);
|
|
632
|
+
|
|
633
|
+
// Track the proposal we attested to (to prevent equivocation)
|
|
634
|
+
this.lastAttestedProposal = proposal;
|
|
635
|
+
|
|
526
636
|
await this.p2pClient.addOwnCheckpointAttestations(attestations);
|
|
527
637
|
return attestations;
|
|
528
638
|
}
|
|
@@ -536,7 +646,11 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
536
646
|
proposalInfo: LogData,
|
|
537
647
|
): Promise<{ isValid: true } | { isValid: false; reason: string }> {
|
|
538
648
|
const slot = proposal.slotNumber;
|
|
539
|
-
|
|
649
|
+
|
|
650
|
+
// Timeout block syncing at the start of the next slot
|
|
651
|
+
const config = this.checkpointsBuilder.getConfig();
|
|
652
|
+
const nextSlotTimestampSeconds = Number(getTimestampForSlot(SlotNumber(slot + 1), config));
|
|
653
|
+
const timeoutSeconds = Math.max(1, nextSlotTimestampSeconds - Math.floor(this.dateProvider.now() / 1000));
|
|
540
654
|
|
|
541
655
|
// Wait for last block to sync by archive
|
|
542
656
|
let lastBlockHeader: BlockHeader | undefined;
|
|
@@ -571,6 +685,12 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
571
685
|
return { isValid: false, reason: 'no_blocks_for_slot' };
|
|
572
686
|
}
|
|
573
687
|
|
|
688
|
+
// Ensure the last block for this slot matches the archive in the checkpoint proposal
|
|
689
|
+
if (!blocks.at(-1)?.archive.root.equals(proposal.archive)) {
|
|
690
|
+
this.log.warn(`Last block archive mismatch for checkpoint proposal`, proposalInfo);
|
|
691
|
+
return { isValid: false, reason: 'last_block_archive_mismatch' };
|
|
692
|
+
}
|
|
693
|
+
|
|
574
694
|
this.log.debug(`Found ${blocks.length} blocks for slot ${slot}`, {
|
|
575
695
|
...proposalInfo,
|
|
576
696
|
blockNumbers: blocks.map(b => b.number),
|
|
@@ -584,14 +704,11 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
584
704
|
// Get L1-to-L2 messages for this checkpoint
|
|
585
705
|
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
586
706
|
|
|
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.
|
|
707
|
+
// Collect the out hashes of all the checkpoints before this one in the same epoch
|
|
590
708
|
const epoch = getEpochAtSlot(slot, this.epochCache.getL1Constants());
|
|
591
|
-
const
|
|
592
|
-
.filter(
|
|
593
|
-
.
|
|
594
|
-
const previousCheckpointOutHashes = previousCheckpoints.map(c => c.getCheckpointOutHash());
|
|
709
|
+
const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch))
|
|
710
|
+
.filter(c => c.checkpointNumber < checkpointNumber)
|
|
711
|
+
.map(c => c.checkpointOutHash);
|
|
595
712
|
|
|
596
713
|
// Fork world state at the block before the first block
|
|
597
714
|
const parentBlockNumber = BlockNumber(firstBlock.number - 1);
|
|
@@ -602,6 +719,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
602
719
|
const checkpointBuilder = await this.checkpointsBuilder.openCheckpoint(
|
|
603
720
|
checkpointNumber,
|
|
604
721
|
constants,
|
|
722
|
+
proposal.feeAssetPriceModifier,
|
|
605
723
|
l1ToL2Messages,
|
|
606
724
|
previousCheckpointOutHashes,
|
|
607
725
|
fork,
|
|
@@ -648,6 +766,20 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
648
766
|
return { isValid: false, reason: 'out_hash_mismatch' };
|
|
649
767
|
}
|
|
650
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
|
+
|
|
651
783
|
this.log.verbose(`Checkpoint proposal validation successful for slot ${slot}`, proposalInfo);
|
|
652
784
|
return { isValid: true };
|
|
653
785
|
} finally {
|
|
@@ -664,6 +796,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
664
796
|
chainId: gv.chainId,
|
|
665
797
|
version: gv.version,
|
|
666
798
|
slotNumber: gv.slotNumber,
|
|
799
|
+
timestamp: gv.timestamp,
|
|
667
800
|
coinbase: gv.coinbase,
|
|
668
801
|
feeRecipient: gv.feeRecipient,
|
|
669
802
|
gasFees: gv.gasFees,
|
|
@@ -673,7 +806,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
673
806
|
/**
|
|
674
807
|
* Uploads blobs for a checkpoint to the filestore (fire and forget).
|
|
675
808
|
*/
|
|
676
|
-
|
|
809
|
+
protected async uploadBlobsForCheckpoint(proposal: CheckpointProposalCore, proposalInfo: LogData): Promise<void> {
|
|
677
810
|
try {
|
|
678
811
|
const lastBlockHeader = await this.blockSource.getBlockHeaderByArchive(proposal.archive);
|
|
679
812
|
if (!lastBlockHeader) {
|
|
@@ -688,7 +821,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
688
821
|
}
|
|
689
822
|
|
|
690
823
|
const blobFields = blocks.flatMap(b => b.toBlobFields());
|
|
691
|
-
const blobs: Blob[] = getBlobsPerL1Block(blobFields);
|
|
824
|
+
const blobs: Blob[] = await getBlobsPerL1Block(blobFields);
|
|
692
825
|
await this.blobClient.sendBlobsToFilestore(blobs);
|
|
693
826
|
this.log.debug(`Uploaded ${blobs.length} blobs to filestore for checkpoint at slot ${proposal.slotNumber}`, {
|
|
694
827
|
...proposalInfo,
|
|
@@ -750,6 +883,28 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
750
883
|
]);
|
|
751
884
|
}
|
|
752
885
|
|
|
886
|
+
/**
|
|
887
|
+
* Handle detection of a duplicate attestation (equivocation).
|
|
888
|
+
* Emits a slash event when an attester signs attestations for different proposals at the same slot.
|
|
889
|
+
*/
|
|
890
|
+
private handleDuplicateAttestation(info: DuplicateAttestationInfo): void {
|
|
891
|
+
const { slot, attester } = info;
|
|
892
|
+
|
|
893
|
+
this.log.warn(`Triggering slash event for duplicate attestation from ${attester.toString()} at slot ${slot}`, {
|
|
894
|
+
attester: attester.toString(),
|
|
895
|
+
slot,
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
this.emit(WANT_TO_SLASH_EVENT, [
|
|
899
|
+
{
|
|
900
|
+
validator: attester,
|
|
901
|
+
amount: this.config.slashDuplicateAttestationPenalty,
|
|
902
|
+
offenseType: OffenseType.DUPLICATE_ATTESTATION,
|
|
903
|
+
epochOrSlot: BigInt(slot),
|
|
904
|
+
},
|
|
905
|
+
]);
|
|
906
|
+
}
|
|
907
|
+
|
|
753
908
|
async createBlockProposal(
|
|
754
909
|
blockHeader: BlockHeader,
|
|
755
910
|
indexWithinCheckpoint: IndexWithinCheckpoint,
|
|
@@ -759,11 +914,19 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
759
914
|
proposerAddress: EthAddress | undefined,
|
|
760
915
|
options: BlockProposalOptions = {},
|
|
761
916
|
): Promise<BlockProposal> {
|
|
762
|
-
//
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
917
|
+
// Validate that we're not creating a proposal for an older or equal position
|
|
918
|
+
if (this.lastProposedBlock) {
|
|
919
|
+
const lastSlot = this.lastProposedBlock.slotNumber;
|
|
920
|
+
const lastIndex = this.lastProposedBlock.indexWithinCheckpoint;
|
|
921
|
+
const newSlot = blockHeader.globalVariables.slotNumber;
|
|
922
|
+
|
|
923
|
+
if (newSlot < lastSlot || (newSlot === lastSlot && indexWithinCheckpoint <= lastIndex)) {
|
|
924
|
+
throw new Error(
|
|
925
|
+
`Cannot create block proposal for slot ${newSlot} index ${indexWithinCheckpoint}: ` +
|
|
926
|
+
`already proposed block for slot ${lastSlot} index ${lastIndex}`,
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
767
930
|
|
|
768
931
|
this.log.info(
|
|
769
932
|
`Assembling block proposal for block ${blockHeader.globalVariables.blockNumber} slot ${blockHeader.globalVariables.slotNumber}`,
|
|
@@ -780,25 +943,42 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
780
943
|
broadcastInvalidBlockProposal: this.config.broadcastInvalidBlockProposal,
|
|
781
944
|
},
|
|
782
945
|
);
|
|
783
|
-
this.
|
|
946
|
+
this.lastProposedBlock = newProposal;
|
|
784
947
|
return newProposal;
|
|
785
948
|
}
|
|
786
949
|
|
|
787
950
|
async createCheckpointProposal(
|
|
788
951
|
checkpointHeader: CheckpointHeader,
|
|
789
952
|
archive: Fr,
|
|
953
|
+
feeAssetPriceModifier: bigint,
|
|
790
954
|
lastBlockInfo: CreateCheckpointProposalLastBlockData | undefined,
|
|
791
955
|
proposerAddress: EthAddress | undefined,
|
|
792
956
|
options: CheckpointProposalOptions = {},
|
|
793
957
|
): Promise<CheckpointProposal> {
|
|
958
|
+
// Validate that we're not creating a proposal for an older or equal slot
|
|
959
|
+
if (this.lastProposedCheckpoint) {
|
|
960
|
+
const lastSlot = this.lastProposedCheckpoint.slotNumber;
|
|
961
|
+
const newSlot = checkpointHeader.slotNumber;
|
|
962
|
+
|
|
963
|
+
if (newSlot <= lastSlot) {
|
|
964
|
+
throw new Error(
|
|
965
|
+
`Cannot create checkpoint proposal for slot ${newSlot}: ` +
|
|
966
|
+
`already proposed checkpoint for slot ${lastSlot}`,
|
|
967
|
+
);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
794
971
|
this.log.info(`Assembling checkpoint proposal for slot ${checkpointHeader.slotNumber}`);
|
|
795
|
-
|
|
972
|
+
const newProposal = await this.validationService.createCheckpointProposal(
|
|
796
973
|
checkpointHeader,
|
|
797
974
|
archive,
|
|
975
|
+
feeAssetPriceModifier,
|
|
798
976
|
lastBlockInfo,
|
|
799
977
|
proposerAddress,
|
|
800
978
|
options,
|
|
801
979
|
);
|
|
980
|
+
this.lastProposedCheckpoint = newProposal;
|
|
981
|
+
return newProposal;
|
|
802
982
|
}
|
|
803
983
|
|
|
804
984
|
async broadcastBlockProposal(proposal: BlockProposal): Promise<void> {
|
|
@@ -820,6 +1000,10 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
820
1000
|
this.log.debug(`Collecting ${inCommittee.length} self-attestations for slot ${slot}`, { inCommittee });
|
|
821
1001
|
const attestations = await this.createCheckpointAttestationsFromProposal(proposal, inCommittee);
|
|
822
1002
|
|
|
1003
|
+
if (!attestations) {
|
|
1004
|
+
return [];
|
|
1005
|
+
}
|
|
1006
|
+
|
|
823
1007
|
// We broadcast our own attestations to our peers so, in case our block does not get mined on L1,
|
|
824
1008
|
// other nodes can see that our validators did attest to this block proposal, and do not slash us
|
|
825
1009
|
// 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
|
-
}
|