@aztec/validator-client 0.0.1-commit.8f9871590 → 0.0.1-commit.934299a21
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/dest/block_proposal_handler.d.ts +2 -2
- package/dest/block_proposal_handler.d.ts.map +1 -1
- package/dest/block_proposal_handler.js +19 -33
- package/dest/checkpoint_builder.d.ts +6 -3
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +15 -10
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +1 -1
- package/dest/index.d.ts +1 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +0 -1
- package/dest/validator.d.ts +10 -4
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +39 -12
- package/package.json +19 -19
- package/src/block_proposal_handler.ts +27 -48
- package/src/checkpoint_builder.ts +12 -5
- package/src/config.ts +1 -1
- package/src/index.ts +0 -1
- package/src/validator.ts +44 -13
- 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/dest/validator.js
CHANGED
|
@@ -42,6 +42,7 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
42
42
|
l1ToL2MessageSource;
|
|
43
43
|
config;
|
|
44
44
|
blobClient;
|
|
45
|
+
haSigner;
|
|
45
46
|
dateProvider;
|
|
46
47
|
tracer;
|
|
47
48
|
validationService;
|
|
@@ -55,8 +56,8 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
55
56
|
epochCacheUpdateLoop;
|
|
56
57
|
proposersOfInvalidBlocks;
|
|
57
58
|
/** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */ lastAttestedProposal;
|
|
58
|
-
constructor(keyStore, epochCache, p2pClient, blockProposalHandler, blockSource, checkpointsBuilder, worldState, l1ToL2MessageSource, config, blobClient, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator')){
|
|
59
|
-
super(), this.keyStore = keyStore, this.epochCache = epochCache, this.p2pClient = p2pClient, this.blockProposalHandler = blockProposalHandler, this.blockSource = blockSource, this.checkpointsBuilder = checkpointsBuilder, this.worldState = worldState, this.l1ToL2MessageSource = l1ToL2MessageSource, this.config = config, this.blobClient = blobClient, this.dateProvider = dateProvider, this.hasRegisteredHandlers = false, this.proposersOfInvalidBlocks = new Set();
|
|
59
|
+
constructor(keyStore, epochCache, p2pClient, blockProposalHandler, blockSource, checkpointsBuilder, worldState, l1ToL2MessageSource, config, blobClient, haSigner, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator')){
|
|
60
|
+
super(), this.keyStore = keyStore, this.epochCache = epochCache, this.p2pClient = p2pClient, this.blockProposalHandler = blockProposalHandler, this.blockSource = blockSource, this.checkpointsBuilder = checkpointsBuilder, this.worldState = worldState, this.l1ToL2MessageSource = l1ToL2MessageSource, this.config = config, this.blobClient = blobClient, this.haSigner = haSigner, this.dateProvider = dateProvider, this.hasRegisteredHandlers = false, this.proposersOfInvalidBlocks = new Set();
|
|
60
61
|
// Create child logger with fisherman prefix if in fisherman mode
|
|
61
62
|
this.log = config.fishermanMode ? log.createChild('[FISHERMAN]') : log;
|
|
62
63
|
this.tracer = telemetry.getTracer('Validator');
|
|
@@ -116,17 +117,23 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
116
117
|
txsPermitted: !config.disableTransactions
|
|
117
118
|
});
|
|
118
119
|
const blockProposalHandler = new BlockProposalHandler(checkpointsBuilder, worldState, blockSource, l1ToL2MessageSource, txProvider, blockProposalValidator, epochCache, config, metrics, dateProvider, telemetry);
|
|
119
|
-
|
|
120
|
+
const nodeKeystoreAdapter = NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager);
|
|
121
|
+
let validatorKeyStore = nodeKeystoreAdapter;
|
|
122
|
+
let haSigner;
|
|
120
123
|
if (config.haSigningEnabled) {
|
|
121
124
|
// If maxStuckDutiesAgeMs is not explicitly set, compute it from Aztec slot duration
|
|
122
125
|
const haConfig = {
|
|
123
126
|
...config,
|
|
124
127
|
maxStuckDutiesAgeMs: config.maxStuckDutiesAgeMs ?? epochCache.getL1Constants().slotDuration * 2 * 1000
|
|
125
128
|
};
|
|
126
|
-
const { signer } = await createHASigner(haConfig
|
|
127
|
-
|
|
129
|
+
const { signer } = await createHASigner(haConfig, {
|
|
130
|
+
telemetryClient: telemetry,
|
|
131
|
+
dateProvider
|
|
132
|
+
});
|
|
133
|
+
haSigner = signer;
|
|
134
|
+
validatorKeyStore = new HAKeyStore(nodeKeystoreAdapter, signer);
|
|
128
135
|
}
|
|
129
|
-
const validator = new ValidatorClient(validatorKeyStore, epochCache, p2pClient, blockProposalHandler, blockSource, checkpointsBuilder, worldState, l1ToL2MessageSource, config, blobClient, dateProvider, telemetry);
|
|
136
|
+
const validator = new ValidatorClient(validatorKeyStore, epochCache, p2pClient, blockProposalHandler, blockSource, checkpointsBuilder, worldState, l1ToL2MessageSource, config, blobClient, haSigner, dateProvider, telemetry);
|
|
130
137
|
return validator;
|
|
131
138
|
}
|
|
132
139
|
getValidatorAddresses() {
|
|
@@ -153,6 +160,20 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
153
160
|
...config
|
|
154
161
|
};
|
|
155
162
|
}
|
|
163
|
+
reloadKeystore(newManager) {
|
|
164
|
+
if (this.config.haSigningEnabled && !this.haSigner) {
|
|
165
|
+
this.log.warn('HA signing is enabled in config but was not initialized at startup. ' + 'Restart the node to enable HA signing.');
|
|
166
|
+
} else if (!this.config.haSigningEnabled && this.haSigner) {
|
|
167
|
+
this.log.warn('HA signing was disabled via config update but the HA signer is still active. ' + 'Restart the node to fully disable HA signing.');
|
|
168
|
+
}
|
|
169
|
+
const newAdapter = NodeKeystoreAdapter.fromKeyStoreManager(newManager);
|
|
170
|
+
if (this.haSigner) {
|
|
171
|
+
this.keyStore = new HAKeyStore(newAdapter, this.haSigner);
|
|
172
|
+
} else {
|
|
173
|
+
this.keyStore = newAdapter;
|
|
174
|
+
}
|
|
175
|
+
this.validationService = new ValidationService(this.keyStore, this.log.createChild('validation-service'));
|
|
176
|
+
}
|
|
156
177
|
async start() {
|
|
157
178
|
if (this.epochCacheUpdateLoop.isRunning()) {
|
|
158
179
|
this.log.warn(`Validator client already started`);
|
|
@@ -442,6 +463,14 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
442
463
|
reason: 'no_blocks_for_slot'
|
|
443
464
|
};
|
|
444
465
|
}
|
|
466
|
+
// Ensure the last block for this slot matches the archive in the checkpoint proposal
|
|
467
|
+
if (!blocks.at(-1)?.archive.root.equals(proposal.archive)) {
|
|
468
|
+
this.log.warn(`Last block archive mismatch for checkpoint proposal`, proposalInfo);
|
|
469
|
+
return {
|
|
470
|
+
isValid: false,
|
|
471
|
+
reason: 'last_block_archive_mismatch'
|
|
472
|
+
};
|
|
473
|
+
}
|
|
445
474
|
this.log.debug(`Found ${blocks.length} blocks for slot ${slot}`, {
|
|
446
475
|
...proposalInfo,
|
|
447
476
|
blockNumbers: blocks.map((b)=>b.number)
|
|
@@ -452,12 +481,9 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
452
481
|
const checkpointNumber = firstBlock.checkpointNumber;
|
|
453
482
|
// Get L1-to-L2 messages for this checkpoint
|
|
454
483
|
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
455
|
-
//
|
|
456
|
-
// TODO: There can be a more efficient way to get the previous checkpoint out hashes without having to fetch the
|
|
457
|
-
// actual checkpoints and the blocks/txs in them.
|
|
484
|
+
// Collect the out hashes of all the checkpoints before this one in the same epoch
|
|
458
485
|
const epoch = getEpochAtSlot(slot, this.epochCache.getL1Constants());
|
|
459
|
-
const
|
|
460
|
-
const previousCheckpointOutHashes = previousCheckpoints.map((c)=>c.getCheckpointOutHash());
|
|
486
|
+
const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch)).filter((c)=>c.checkpointNumber < checkpointNumber).map((c)=>c.checkpointOutHash);
|
|
461
487
|
// Fork world state at the block before the first block
|
|
462
488
|
const parentBlockNumber = BlockNumber(firstBlock.number - 1);
|
|
463
489
|
const fork = await this.worldState.fork(parentBlockNumber);
|
|
@@ -527,6 +553,7 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
527
553
|
chainId: gv.chainId,
|
|
528
554
|
version: gv.version,
|
|
529
555
|
slotNumber: gv.slotNumber,
|
|
556
|
+
timestamp: gv.timestamp,
|
|
530
557
|
coinbase: gv.coinbase,
|
|
531
558
|
feeRecipient: gv.feeRecipient,
|
|
532
559
|
gasFees: gv.gasFees
|
|
@@ -547,7 +574,7 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
547
574
|
return;
|
|
548
575
|
}
|
|
549
576
|
const blobFields = blocks.flatMap((b)=>b.toBlobFields());
|
|
550
|
-
const blobs = getBlobsPerL1Block(blobFields);
|
|
577
|
+
const blobs = await getBlobsPerL1Block(blobFields);
|
|
551
578
|
await this.blobClient.sendBlobsToFilestore(blobs);
|
|
552
579
|
this.log.debug(`Uploaded ${blobs.length} blobs to filestore for checkpoint at slot ${proposal.slotNumber}`, {
|
|
553
580
|
...proposalInfo,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/validator-client",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.934299a21",
|
|
4
4
|
"main": "dest/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -64,30 +64,30 @@
|
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@aztec/blob-client": "0.0.1-commit.
|
|
68
|
-
"@aztec/blob-lib": "0.0.1-commit.
|
|
69
|
-
"@aztec/constants": "0.0.1-commit.
|
|
70
|
-
"@aztec/epoch-cache": "0.0.1-commit.
|
|
71
|
-
"@aztec/ethereum": "0.0.1-commit.
|
|
72
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
73
|
-
"@aztec/node-keystore": "0.0.1-commit.
|
|
74
|
-
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.
|
|
75
|
-
"@aztec/p2p": "0.0.1-commit.
|
|
76
|
-
"@aztec/protocol-contracts": "0.0.1-commit.
|
|
77
|
-
"@aztec/prover-client": "0.0.1-commit.
|
|
78
|
-
"@aztec/simulator": "0.0.1-commit.
|
|
79
|
-
"@aztec/slasher": "0.0.1-commit.
|
|
80
|
-
"@aztec/stdlib": "0.0.1-commit.
|
|
81
|
-
"@aztec/telemetry-client": "0.0.1-commit.
|
|
82
|
-
"@aztec/validator-ha-signer": "0.0.1-commit.
|
|
67
|
+
"@aztec/blob-client": "0.0.1-commit.934299a21",
|
|
68
|
+
"@aztec/blob-lib": "0.0.1-commit.934299a21",
|
|
69
|
+
"@aztec/constants": "0.0.1-commit.934299a21",
|
|
70
|
+
"@aztec/epoch-cache": "0.0.1-commit.934299a21",
|
|
71
|
+
"@aztec/ethereum": "0.0.1-commit.934299a21",
|
|
72
|
+
"@aztec/foundation": "0.0.1-commit.934299a21",
|
|
73
|
+
"@aztec/node-keystore": "0.0.1-commit.934299a21",
|
|
74
|
+
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.934299a21",
|
|
75
|
+
"@aztec/p2p": "0.0.1-commit.934299a21",
|
|
76
|
+
"@aztec/protocol-contracts": "0.0.1-commit.934299a21",
|
|
77
|
+
"@aztec/prover-client": "0.0.1-commit.934299a21",
|
|
78
|
+
"@aztec/simulator": "0.0.1-commit.934299a21",
|
|
79
|
+
"@aztec/slasher": "0.0.1-commit.934299a21",
|
|
80
|
+
"@aztec/stdlib": "0.0.1-commit.934299a21",
|
|
81
|
+
"@aztec/telemetry-client": "0.0.1-commit.934299a21",
|
|
82
|
+
"@aztec/validator-ha-signer": "0.0.1-commit.934299a21",
|
|
83
83
|
"koa": "^2.16.1",
|
|
84
84
|
"koa-router": "^13.1.1",
|
|
85
85
|
"tslib": "^2.4.0",
|
|
86
86
|
"viem": "npm:@aztec/viem@2.38.2"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
|
-
"@aztec/archiver": "0.0.1-commit.
|
|
90
|
-
"@aztec/world-state": "0.0.1-commit.
|
|
89
|
+
"@aztec/archiver": "0.0.1-commit.934299a21",
|
|
90
|
+
"@aztec/world-state": "0.0.1-commit.934299a21",
|
|
91
91
|
"@electric-sql/pglite": "^0.3.14",
|
|
92
92
|
"@jest/globals": "^30.0.0",
|
|
93
93
|
"@types/jest": "^30.0.0",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
2
|
import type { EpochCache } from '@aztec/epoch-cache';
|
|
3
3
|
import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
4
|
-
import { chunkBy } from '@aztec/foundation/collection';
|
|
5
4
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
6
5
|
import { TimeoutError } from '@aztec/foundation/error';
|
|
7
6
|
import { createLogger } from '@aztec/foundation/log';
|
|
@@ -9,16 +8,12 @@ import { retryUntil } from '@aztec/foundation/retry';
|
|
|
9
8
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
10
9
|
import type { P2P, PeerId } from '@aztec/p2p';
|
|
11
10
|
import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
|
|
12
|
-
import type { L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
11
|
+
import type { BlockData, L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
13
12
|
import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
14
13
|
import type { ITxProvider, ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
15
|
-
import {
|
|
16
|
-
type L1ToL2MessageSource,
|
|
17
|
-
computeCheckpointOutHash,
|
|
18
|
-
computeInHashFromL1ToL2Messages,
|
|
19
|
-
} from '@aztec/stdlib/messaging';
|
|
14
|
+
import { type L1ToL2MessageSource, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
20
15
|
import type { BlockProposal } from '@aztec/stdlib/p2p';
|
|
21
|
-
import {
|
|
16
|
+
import type { CheckpointGlobalVariables, FailedTx, Tx } from '@aztec/stdlib/tx';
|
|
22
17
|
import {
|
|
23
18
|
ReExFailedTxsError,
|
|
24
19
|
ReExStateMismatchError,
|
|
@@ -153,16 +148,16 @@ export class BlockProposalHandler {
|
|
|
153
148
|
}
|
|
154
149
|
|
|
155
150
|
// Check that the parent proposal is a block we know, otherwise reexecution would fail
|
|
156
|
-
const
|
|
157
|
-
if (
|
|
151
|
+
const parentBlock = await this.getParentBlock(proposal);
|
|
152
|
+
if (parentBlock === undefined) {
|
|
158
153
|
this.log.warn(`Parent block for proposal not found, skipping processing`, proposalInfo);
|
|
159
154
|
return { isValid: false, reason: 'parent_block_not_found' };
|
|
160
155
|
}
|
|
161
156
|
|
|
162
157
|
// Check that the parent block's slot is not greater than the proposal's slot.
|
|
163
|
-
if (
|
|
158
|
+
if (parentBlock !== 'genesis' && parentBlock.header.getSlot() > slotNumber) {
|
|
164
159
|
this.log.warn(`Parent block slot is greater than proposal slot, skipping processing`, {
|
|
165
|
-
parentBlockSlot:
|
|
160
|
+
parentBlockSlot: parentBlock.header.getSlot().toString(),
|
|
166
161
|
proposalSlot: slotNumber.toString(),
|
|
167
162
|
...proposalInfo,
|
|
168
163
|
});
|
|
@@ -171,9 +166,9 @@ export class BlockProposalHandler {
|
|
|
171
166
|
|
|
172
167
|
// Compute the block number based on the parent block
|
|
173
168
|
const blockNumber =
|
|
174
|
-
|
|
169
|
+
parentBlock === 'genesis'
|
|
175
170
|
? BlockNumber(INITIAL_L2_BLOCK_NUM)
|
|
176
|
-
: BlockNumber(
|
|
171
|
+
: BlockNumber(parentBlock.header.getBlockNumber() + 1);
|
|
177
172
|
|
|
178
173
|
// Check that this block number does not exist already
|
|
179
174
|
const existingBlock = await this.blockSource.getBlockHeader(blockNumber);
|
|
@@ -190,7 +185,7 @@ export class BlockProposalHandler {
|
|
|
190
185
|
});
|
|
191
186
|
|
|
192
187
|
// Compute the checkpoint number for this block and validate checkpoint consistency
|
|
193
|
-
const checkpointResult =
|
|
188
|
+
const checkpointResult = this.computeCheckpointNumber(proposal, parentBlock, proposalInfo);
|
|
194
189
|
if (checkpointResult.reason) {
|
|
195
190
|
return { isValid: false, blockNumber, reason: checkpointResult.reason };
|
|
196
191
|
}
|
|
@@ -218,17 +213,11 @@ export class BlockProposalHandler {
|
|
|
218
213
|
// Try re-executing the transactions in the proposal if needed
|
|
219
214
|
let reexecutionResult;
|
|
220
215
|
if (shouldReexecute) {
|
|
221
|
-
//
|
|
222
|
-
// TODO(leila/mbps): There can be a more efficient way to get the previous checkpoint out
|
|
223
|
-
// hashes without having to fetch all the blocks.
|
|
216
|
+
// Collect the out hashes of all the checkpoints before this one in the same epoch
|
|
224
217
|
const epoch = getEpochAtSlot(slotNumber, this.epochCache.getL1Constants());
|
|
225
|
-
const
|
|
226
|
-
.filter(
|
|
227
|
-
.
|
|
228
|
-
const blocksByCheckpoint = chunkBy(checkpointedBlocks, b => b.checkpointNumber);
|
|
229
|
-
const previousCheckpointOutHashes = blocksByCheckpoint.map(checkpointBlocks =>
|
|
230
|
-
computeCheckpointOutHash(checkpointBlocks.map(b => b.block.body.txEffects.map(tx => tx.l2ToL1Msgs))),
|
|
231
|
-
);
|
|
218
|
+
const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch))
|
|
219
|
+
.filter(c => c.checkpointNumber < checkpointNumber)
|
|
220
|
+
.map(c => c.checkpointOutHash);
|
|
232
221
|
|
|
233
222
|
try {
|
|
234
223
|
this.log.verbose(`Re-executing transactions in the proposal`, proposalInfo);
|
|
@@ -260,7 +249,7 @@ export class BlockProposalHandler {
|
|
|
260
249
|
return { isValid: true, blockNumber, reexecutionResult };
|
|
261
250
|
}
|
|
262
251
|
|
|
263
|
-
private async getParentBlock(proposal: BlockProposal): Promise<'genesis' |
|
|
252
|
+
private async getParentBlock(proposal: BlockProposal): Promise<'genesis' | BlockData | undefined> {
|
|
264
253
|
const parentArchive = proposal.blockHeader.lastArchive.root;
|
|
265
254
|
const slot = proposal.slotNumber;
|
|
266
255
|
const config = this.checkpointsBuilder.getConfig();
|
|
@@ -276,12 +265,11 @@ export class BlockProposalHandler {
|
|
|
276
265
|
|
|
277
266
|
try {
|
|
278
267
|
return (
|
|
279
|
-
(await this.blockSource.
|
|
268
|
+
(await this.blockSource.getBlockDataByArchive(parentArchive)) ??
|
|
280
269
|
(timeoutDurationMs <= 0
|
|
281
270
|
? undefined
|
|
282
271
|
: await retryUntil(
|
|
283
|
-
() =>
|
|
284
|
-
this.blockSource.syncImmediate().then(() => this.blockSource.getBlockHeaderByArchive(parentArchive)),
|
|
272
|
+
() => this.blockSource.syncImmediate().then(() => this.blockSource.getBlockDataByArchive(parentArchive)),
|
|
285
273
|
'force archiver sync',
|
|
286
274
|
timeoutDurationMs / 1000,
|
|
287
275
|
0.5,
|
|
@@ -297,12 +285,12 @@ export class BlockProposalHandler {
|
|
|
297
285
|
}
|
|
298
286
|
}
|
|
299
287
|
|
|
300
|
-
private
|
|
288
|
+
private computeCheckpointNumber(
|
|
301
289
|
proposal: BlockProposal,
|
|
302
|
-
|
|
290
|
+
parentBlock: 'genesis' | BlockData,
|
|
303
291
|
proposalInfo: object,
|
|
304
|
-
):
|
|
305
|
-
if (
|
|
292
|
+
): CheckpointComputationResult {
|
|
293
|
+
if (parentBlock === 'genesis') {
|
|
306
294
|
// First block is in checkpoint 1
|
|
307
295
|
if (proposal.indexWithinCheckpoint !== 0) {
|
|
308
296
|
this.log.warn(`First block proposal has non-zero indexWithinCheckpoint`, proposalInfo);
|
|
@@ -311,19 +299,9 @@ export class BlockProposalHandler {
|
|
|
311
299
|
return { checkpointNumber: CheckpointNumber.INITIAL };
|
|
312
300
|
}
|
|
313
301
|
|
|
314
|
-
// Get the parent block to find its checkpoint number
|
|
315
|
-
// TODO(palla/mbps): The block header should include the checkpoint number to avoid this lookup,
|
|
316
|
-
// or at least the L2BlockSource should return a different struct that includes it.
|
|
317
|
-
const parentBlockNumber = parentBlockHeader.getBlockNumber();
|
|
318
|
-
const parentBlock = await this.blockSource.getL2Block(parentBlockNumber);
|
|
319
|
-
if (!parentBlock) {
|
|
320
|
-
this.log.warn(`Parent block ${parentBlockNumber} not found in archiver`, proposalInfo);
|
|
321
|
-
return { reason: 'invalid_proposal' };
|
|
322
|
-
}
|
|
323
|
-
|
|
324
302
|
if (proposal.indexWithinCheckpoint === 0) {
|
|
325
303
|
// If this is the first block in a new checkpoint, increment the checkpoint number
|
|
326
|
-
if (!(proposal.blockHeader.getSlot() >
|
|
304
|
+
if (!(proposal.blockHeader.getSlot() > parentBlock.header.getSlot())) {
|
|
327
305
|
this.log.warn(`Slot should be greater than parent block slot for first block in checkpoint`, proposalInfo);
|
|
328
306
|
return { reason: 'invalid_proposal' };
|
|
329
307
|
}
|
|
@@ -335,7 +313,7 @@ export class BlockProposalHandler {
|
|
|
335
313
|
this.log.warn(`Non-sequential indexWithinCheckpoint`, proposalInfo);
|
|
336
314
|
return { reason: 'invalid_proposal' };
|
|
337
315
|
}
|
|
338
|
-
if (proposal.blockHeader.getSlot() !==
|
|
316
|
+
if (proposal.blockHeader.getSlot() !== parentBlock.header.getSlot()) {
|
|
339
317
|
this.log.warn(`Slot should be equal to parent block slot for non-first block in checkpoint`, proposalInfo);
|
|
340
318
|
return { reason: 'invalid_proposal' };
|
|
341
319
|
}
|
|
@@ -356,7 +334,7 @@ export class BlockProposalHandler {
|
|
|
356
334
|
*/
|
|
357
335
|
private validateNonFirstBlockInCheckpoint(
|
|
358
336
|
proposal: BlockProposal,
|
|
359
|
-
parentBlock:
|
|
337
|
+
parentBlock: BlockData,
|
|
360
338
|
proposalInfo: object,
|
|
361
339
|
): CheckpointComputationResult | undefined {
|
|
362
340
|
const proposalGlobals = proposal.blockHeader.globalVariables;
|
|
@@ -475,13 +453,14 @@ export class BlockProposalHandler {
|
|
|
475
453
|
// Fork before the block to be built
|
|
476
454
|
const parentBlockNumber = BlockNumber(blockNumber - 1);
|
|
477
455
|
await this.worldState.syncImmediate(parentBlockNumber);
|
|
478
|
-
using fork = await this.worldState.fork(parentBlockNumber);
|
|
456
|
+
await using fork = await this.worldState.fork(parentBlockNumber);
|
|
479
457
|
|
|
480
|
-
// Build checkpoint constants from proposal (excludes blockNumber
|
|
458
|
+
// Build checkpoint constants from proposal (excludes blockNumber which is per-block)
|
|
481
459
|
const constants: CheckpointGlobalVariables = {
|
|
482
460
|
chainId: new Fr(config.l1ChainId),
|
|
483
461
|
version: new Fr(config.rollupVersion),
|
|
484
462
|
slotNumber: slot,
|
|
463
|
+
timestamp: blockHeader.globalVariables.timestamp,
|
|
485
464
|
coinbase: blockHeader.globalVariables.coinbase,
|
|
486
465
|
feeRecipient: blockHeader.globalVariables.feeRecipient,
|
|
487
466
|
gasFees: blockHeader.globalVariables.gasFees,
|
|
@@ -4,7 +4,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
4
4
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
5
5
|
import { bufferToHex } from '@aztec/foundation/string';
|
|
6
6
|
import { DateProvider, elapsed } from '@aztec/foundation/timer';
|
|
7
|
-
import { getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
|
|
7
|
+
import { createTxValidatorForBlockBuilding, getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
|
|
8
8
|
import { LightweightCheckpointBuilder } from '@aztec/prover-client/light';
|
|
9
9
|
import {
|
|
10
10
|
GuardedMerkleTreeOperations,
|
|
@@ -28,12 +28,11 @@ import {
|
|
|
28
28
|
type PublicProcessorLimits,
|
|
29
29
|
type WorldStateSynchronizer,
|
|
30
30
|
} from '@aztec/stdlib/interfaces/server';
|
|
31
|
+
import { type DebugLogStore, NullDebugLogStore } from '@aztec/stdlib/logs';
|
|
31
32
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
32
33
|
import { type CheckpointGlobalVariables, GlobalVariables, StateReference, Tx } from '@aztec/stdlib/tx';
|
|
33
34
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
34
35
|
|
|
35
|
-
import { createValidatorForBlockBuilding } from './tx_validator/tx_validator_factory.js';
|
|
36
|
-
|
|
37
36
|
// Re-export for backward compatibility
|
|
38
37
|
export type { BuildBlockInCheckpointResult } from '@aztec/stdlib/interfaces/server';
|
|
39
38
|
|
|
@@ -52,6 +51,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
52
51
|
private dateProvider: DateProvider,
|
|
53
52
|
private telemetryClient: TelemetryClient,
|
|
54
53
|
bindings?: LoggerBindings,
|
|
54
|
+
private debugLogStore: DebugLogStore = new NullDebugLogStore(),
|
|
55
55
|
) {
|
|
56
56
|
this.log = createLogger('checkpoint-builder', {
|
|
57
57
|
...bindings,
|
|
@@ -105,7 +105,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
// Add block to checkpoint
|
|
108
|
-
const block = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
|
|
108
|
+
const { block } = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
|
|
109
109
|
expectedEndState: opts.expectedEndState,
|
|
110
110
|
});
|
|
111
111
|
|
|
@@ -152,6 +152,8 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
152
152
|
const contractsDB = new PublicContractsDB(this.contractDataSource, this.log.getBindings());
|
|
153
153
|
const guardedFork = new GuardedMerkleTreeOperations(fork);
|
|
154
154
|
|
|
155
|
+
const collectDebugLogs = this.debugLogStore.isEnabled;
|
|
156
|
+
|
|
155
157
|
const bindings = this.log.getBindings();
|
|
156
158
|
const publicTxSimulator = createPublicTxSimulatorForBlockBuilding(
|
|
157
159
|
guardedFork,
|
|
@@ -159,6 +161,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
159
161
|
globalVariables,
|
|
160
162
|
this.telemetryClient,
|
|
161
163
|
bindings,
|
|
164
|
+
collectDebugLogs,
|
|
162
165
|
);
|
|
163
166
|
|
|
164
167
|
const processor = new PublicProcessor(
|
|
@@ -170,9 +173,10 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
170
173
|
this.telemetryClient,
|
|
171
174
|
createLogger('simulator:public-processor', bindings),
|
|
172
175
|
this.config,
|
|
176
|
+
this.debugLogStore,
|
|
173
177
|
);
|
|
174
178
|
|
|
175
|
-
const validator =
|
|
179
|
+
const validator = createTxValidatorForBlockBuilding(
|
|
176
180
|
fork,
|
|
177
181
|
this.contractDataSource,
|
|
178
182
|
globalVariables,
|
|
@@ -197,6 +201,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
197
201
|
private contractDataSource: ContractDataSource,
|
|
198
202
|
private dateProvider: DateProvider,
|
|
199
203
|
private telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
204
|
+
private debugLogStore: DebugLogStore = new NullDebugLogStore(),
|
|
200
205
|
) {
|
|
201
206
|
this.log = createLogger('checkpoint-builder');
|
|
202
207
|
}
|
|
@@ -251,6 +256,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
251
256
|
this.dateProvider,
|
|
252
257
|
this.telemetryClient,
|
|
253
258
|
bindings,
|
|
259
|
+
this.debugLogStore,
|
|
254
260
|
);
|
|
255
261
|
}
|
|
256
262
|
|
|
@@ -311,6 +317,7 @@ export class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
311
317
|
this.dateProvider,
|
|
312
318
|
this.telemetryClient,
|
|
313
319
|
bindings,
|
|
320
|
+
this.debugLogStore,
|
|
314
321
|
);
|
|
315
322
|
}
|
|
316
323
|
|
package/src/config.ts
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
secretValueConfigHelper,
|
|
7
7
|
} from '@aztec/foundation/config';
|
|
8
8
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
9
|
+
import { validatorHASignerConfigMappings } from '@aztec/stdlib/ha-signing';
|
|
9
10
|
import type { ValidatorClientConfig } from '@aztec/stdlib/interfaces/server';
|
|
10
|
-
import { validatorHASignerConfigMappings } from '@aztec/validator-ha-signer/config';
|
|
11
11
|
|
|
12
12
|
export type { ValidatorClientConfig };
|
|
13
13
|
|
package/src/index.ts
CHANGED
package/src/validator.ts
CHANGED
|
@@ -47,6 +47,7 @@ import { AttestationTimeoutError } from '@aztec/stdlib/validators';
|
|
|
47
47
|
import { type TelemetryClient, type Tracer, getTelemetryClient } from '@aztec/telemetry-client';
|
|
48
48
|
import { createHASigner } from '@aztec/validator-ha-signer/factory';
|
|
49
49
|
import { DutyType, type SigningContext } from '@aztec/validator-ha-signer/types';
|
|
50
|
+
import type { ValidatorHASigner } from '@aztec/validator-ha-signer/validator-ha-signer';
|
|
50
51
|
|
|
51
52
|
import { EventEmitter } from 'events';
|
|
52
53
|
import type { TypedDataDefinition } from 'viem';
|
|
@@ -77,7 +78,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
77
78
|
private validationService: ValidationService;
|
|
78
79
|
private metrics: ValidatorMetrics;
|
|
79
80
|
private log: Logger;
|
|
80
|
-
|
|
81
81
|
// Whether it has already registered handlers on the p2p client
|
|
82
82
|
private hasRegisteredHandlers = false;
|
|
83
83
|
|
|
@@ -106,6 +106,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
106
106
|
private l1ToL2MessageSource: L1ToL2MessageSource,
|
|
107
107
|
private config: ValidatorClientFullConfig,
|
|
108
108
|
private blobClient: BlobClientInterface,
|
|
109
|
+
private haSigner: ValidatorHASigner | undefined,
|
|
109
110
|
private dateProvider: DateProvider = new DateProvider(),
|
|
110
111
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
111
112
|
log = createLogger('validator'),
|
|
@@ -211,15 +212,18 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
211
212
|
telemetry,
|
|
212
213
|
);
|
|
213
214
|
|
|
214
|
-
|
|
215
|
+
const nodeKeystoreAdapter = NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager);
|
|
216
|
+
let validatorKeyStore: ExtendedValidatorKeyStore = nodeKeystoreAdapter;
|
|
217
|
+
let haSigner: ValidatorHASigner | undefined;
|
|
215
218
|
if (config.haSigningEnabled) {
|
|
216
219
|
// If maxStuckDutiesAgeMs is not explicitly set, compute it from Aztec slot duration
|
|
217
220
|
const haConfig = {
|
|
218
221
|
...config,
|
|
219
222
|
maxStuckDutiesAgeMs: config.maxStuckDutiesAgeMs ?? epochCache.getL1Constants().slotDuration * 2 * 1000,
|
|
220
223
|
};
|
|
221
|
-
const { signer } = await createHASigner(haConfig);
|
|
222
|
-
|
|
224
|
+
const { signer } = await createHASigner(haConfig, { telemetryClient: telemetry, dateProvider });
|
|
225
|
+
haSigner = signer;
|
|
226
|
+
validatorKeyStore = new HAKeyStore(nodeKeystoreAdapter, signer);
|
|
223
227
|
}
|
|
224
228
|
|
|
225
229
|
const validator = new ValidatorClient(
|
|
@@ -233,6 +237,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
233
237
|
l1ToL2MessageSource,
|
|
234
238
|
config,
|
|
235
239
|
blobClient,
|
|
240
|
+
haSigner,
|
|
236
241
|
dateProvider,
|
|
237
242
|
telemetry,
|
|
238
243
|
);
|
|
@@ -270,6 +275,28 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
270
275
|
this.config = { ...this.config, ...config };
|
|
271
276
|
}
|
|
272
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
|
+
|
|
273
300
|
public async start() {
|
|
274
301
|
if (this.epochCacheUpdateLoop.isRunning()) {
|
|
275
302
|
this.log.warn(`Validator client already started`);
|
|
@@ -643,6 +670,12 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
643
670
|
return { isValid: false, reason: 'no_blocks_for_slot' };
|
|
644
671
|
}
|
|
645
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
|
+
|
|
646
679
|
this.log.debug(`Found ${blocks.length} blocks for slot ${slot}`, {
|
|
647
680
|
...proposalInfo,
|
|
648
681
|
blockNumbers: blocks.map(b => b.number),
|
|
@@ -656,14 +689,11 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
656
689
|
// Get L1-to-L2 messages for this checkpoint
|
|
657
690
|
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
658
691
|
|
|
659
|
-
//
|
|
660
|
-
// TODO: There can be a more efficient way to get the previous checkpoint out hashes without having to fetch the
|
|
661
|
-
// actual checkpoints and the blocks/txs in them.
|
|
692
|
+
// Collect the out hashes of all the checkpoints before this one in the same epoch
|
|
662
693
|
const epoch = getEpochAtSlot(slot, this.epochCache.getL1Constants());
|
|
663
|
-
const
|
|
664
|
-
.filter(
|
|
665
|
-
.
|
|
666
|
-
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);
|
|
667
697
|
|
|
668
698
|
// Fork world state at the block before the first block
|
|
669
699
|
const parentBlockNumber = BlockNumber(firstBlock.number - 1);
|
|
@@ -737,6 +767,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
737
767
|
chainId: gv.chainId,
|
|
738
768
|
version: gv.version,
|
|
739
769
|
slotNumber: gv.slotNumber,
|
|
770
|
+
timestamp: gv.timestamp,
|
|
740
771
|
coinbase: gv.coinbase,
|
|
741
772
|
feeRecipient: gv.feeRecipient,
|
|
742
773
|
gasFees: gv.gasFees,
|
|
@@ -746,7 +777,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
746
777
|
/**
|
|
747
778
|
* Uploads blobs for a checkpoint to the filestore (fire and forget).
|
|
748
779
|
*/
|
|
749
|
-
|
|
780
|
+
protected async uploadBlobsForCheckpoint(proposal: CheckpointProposalCore, proposalInfo: LogData): Promise<void> {
|
|
750
781
|
try {
|
|
751
782
|
const lastBlockHeader = await this.blockSource.getBlockHeaderByArchive(proposal.archive);
|
|
752
783
|
if (!lastBlockHeader) {
|
|
@@ -761,7 +792,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
761
792
|
}
|
|
762
793
|
|
|
763
794
|
const blobFields = blocks.flatMap(b => b.toBlobFields());
|
|
764
|
-
const blobs: Blob[] = getBlobsPerL1Block(blobFields);
|
|
795
|
+
const blobs: Blob[] = await getBlobsPerL1Block(blobFields);
|
|
765
796
|
await this.blobClient.sendBlobsToFilestore(blobs);
|
|
766
797
|
this.log.debug(`Uploaded ${blobs.length} blobs to filestore for checkpoint at slot ${proposal.slotNumber}`, {
|
|
767
798
|
...proposalInfo,
|
|
@@ -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"}
|