@aztec/aztec-node 0.0.1-commit.cd76b27 → 0.0.1-commit.ce4f8c4f2
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/aztec-node/config.d.ts +2 -2
- package/dest/aztec-node/config.d.ts.map +1 -1
- package/dest/aztec-node/config.js +1 -1
- package/dest/aztec-node/server.d.ts +22 -22
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +277 -163
- package/dest/sentinel/factory.d.ts +2 -2
- package/dest/sentinel/factory.d.ts.map +1 -1
- package/dest/sentinel/sentinel.js +8 -8
- package/package.json +26 -27
- package/src/aztec-node/config.ts +1 -1
- package/src/aztec-node/server.ts +303 -170
- package/src/sentinel/factory.ts +1 -1
- package/src/sentinel/sentinel.ts +8 -8
package/src/aztec-node/server.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { Archiver, createArchiver } from '@aztec/archiver';
|
|
2
|
-
import { BBCircuitVerifier,
|
|
2
|
+
import { BBCircuitVerifier, BatchChonkVerifier, QueuedIVCVerifier } from '@aztec/bb-prover';
|
|
3
|
+
import { TestCircuitVerifier } from '@aztec/bb-prover/test';
|
|
3
4
|
import { type BlobClientInterface, createBlobClientWithFileStores } from '@aztec/blob-client/client';
|
|
4
5
|
import { Blob } from '@aztec/blob-lib';
|
|
5
6
|
import { ARCHIVE_HEIGHT, type L1_TO_L2_MSG_TREE_HEIGHT, type NOTE_HASH_TREE_HEIGHT } from '@aztec/constants';
|
|
6
7
|
import { EpochCache, type EpochCacheInterface } from '@aztec/epoch-cache';
|
|
7
8
|
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
8
|
-
import { getPublicClient } from '@aztec/ethereum/client';
|
|
9
|
+
import { getPublicClient, makeL1HttpTransport } from '@aztec/ethereum/client';
|
|
9
10
|
import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
|
|
10
11
|
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
12
|
+
import type { L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
|
|
11
13
|
import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
12
|
-
import { compactArray, pick, unique } from '@aztec/foundation/collection';
|
|
14
|
+
import { chunkBy, compactArray, pick, unique } from '@aztec/foundation/collection';
|
|
13
15
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
14
16
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
15
17
|
import { BadRequestError } from '@aztec/foundation/json-rpc';
|
|
@@ -20,7 +22,13 @@ import { MembershipWitness, SiblingPath } from '@aztec/foundation/trees';
|
|
|
20
22
|
import { type KeyStore, KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
|
|
21
23
|
import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
|
|
22
24
|
import { createForwarderL1TxUtilsFromSigners, createL1TxUtilsFromSigners } from '@aztec/node-lib/factories';
|
|
23
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
type P2P,
|
|
27
|
+
type P2PClientDeps,
|
|
28
|
+
createP2PClient,
|
|
29
|
+
createTxValidatorForAcceptingTxsOverRPC,
|
|
30
|
+
getDefaultAllowedSetupFunctions,
|
|
31
|
+
} from '@aztec/p2p';
|
|
24
32
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
25
33
|
import { type ProverNode, type ProverNodeDeps, createProverNode } from '@aztec/prover-node';
|
|
26
34
|
import { createKeyStoreForProver } from '@aztec/prover-node/config';
|
|
@@ -70,9 +78,9 @@ import {
|
|
|
70
78
|
type WorldStateSynchronizer,
|
|
71
79
|
tryStop,
|
|
72
80
|
} from '@aztec/stdlib/interfaces/server';
|
|
73
|
-
import type { LogFilter, SiloedTag, Tag, TxScopedL2Log } from '@aztec/stdlib/logs';
|
|
81
|
+
import type { DebugLogStore, LogFilter, SiloedTag, Tag, TxScopedL2Log } from '@aztec/stdlib/logs';
|
|
82
|
+
import { InMemoryDebugLogStore, NullDebugLogStore } from '@aztec/stdlib/logs';
|
|
74
83
|
import { InboxLeaf, type L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
75
|
-
import { P2PClientType } from '@aztec/stdlib/p2p';
|
|
76
84
|
import type { Offense, SlashPayloadRound } from '@aztec/stdlib/slashing';
|
|
77
85
|
import type { NullifierLeafPreimage, PublicDataTreeLeaf, PublicDataTreeLeafPreimage } from '@aztec/stdlib/trees';
|
|
78
86
|
import { MerkleTreeId, NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
|
|
@@ -104,11 +112,11 @@ import {
|
|
|
104
112
|
ValidatorClient,
|
|
105
113
|
createBlockProposalHandler,
|
|
106
114
|
createValidatorClient,
|
|
107
|
-
createValidatorForAcceptingTxs,
|
|
108
115
|
} from '@aztec/validator-client';
|
|
116
|
+
import type { SlashingProtectionDatabase } from '@aztec/validator-ha-signer/types';
|
|
109
117
|
import { createWorldStateSynchronizer } from '@aztec/world-state';
|
|
110
118
|
|
|
111
|
-
import { createPublicClient
|
|
119
|
+
import { createPublicClient } from 'viem';
|
|
112
120
|
|
|
113
121
|
import { createSentinel } from '../sentinel/factory.js';
|
|
114
122
|
import { Sentinel } from '../sentinel/sentinel.js';
|
|
@@ -145,18 +153,32 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
145
153
|
protected readonly globalVariableBuilder: GlobalVariableBuilderInterface,
|
|
146
154
|
protected readonly epochCache: EpochCacheInterface,
|
|
147
155
|
protected readonly packageVersion: string,
|
|
148
|
-
private
|
|
156
|
+
private peerProofVerifier: ClientProtocolCircuitVerifier,
|
|
157
|
+
private rpcProofVerifier: ClientProtocolCircuitVerifier,
|
|
149
158
|
private telemetry: TelemetryClient = getTelemetryClient(),
|
|
150
159
|
private log = createLogger('node'),
|
|
151
160
|
private blobClient?: BlobClientInterface,
|
|
152
161
|
private validatorClient?: ValidatorClient,
|
|
153
162
|
private keyStoreManager?: KeystoreManager,
|
|
163
|
+
private debugLogStore: DebugLogStore = new NullDebugLogStore(),
|
|
154
164
|
) {
|
|
155
165
|
this.metrics = new NodeMetrics(telemetry, 'AztecNodeService');
|
|
156
166
|
this.tracer = telemetry.getTracer('AztecNodeService');
|
|
157
167
|
|
|
158
168
|
this.log.info(`Aztec Node version: ${this.packageVersion}`);
|
|
159
169
|
this.log.info(`Aztec Node started on chain 0x${l1ChainId.toString(16)}`, config.l1Contracts);
|
|
170
|
+
|
|
171
|
+
// A defensive check that protects us against introducing a bug in the complex `createAndSync` function. We must
|
|
172
|
+
// never have debugLogStore enabled when not in test mode because then we would be accumulating debug logs in
|
|
173
|
+
// memory which could be a DoS vector on the sequencer (since no fees are paid for debug logs).
|
|
174
|
+
if (debugLogStore.isEnabled && config.realProofs) {
|
|
175
|
+
throw new Error('debugLogStore should never be enabled when realProofs are set');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** @internal Exposed for testing — returns the RPC proof verifier. */
|
|
180
|
+
public getProofVerifier(): ClientProtocolCircuitVerifier {
|
|
181
|
+
return this.rpcProofVerifier;
|
|
160
182
|
}
|
|
161
183
|
|
|
162
184
|
public async getWorldStateSyncStatus(): Promise<WorldStateSyncStatus> {
|
|
@@ -180,8 +202,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
180
202
|
logger?: Logger;
|
|
181
203
|
publisher?: SequencerPublisher;
|
|
182
204
|
dateProvider?: DateProvider;
|
|
183
|
-
p2pClientDeps?: P2PClientDeps
|
|
205
|
+
p2pClientDeps?: P2PClientDeps;
|
|
184
206
|
proverNodeDeps?: Partial<ProverNodeDeps>;
|
|
207
|
+
slashingProtectionDb?: SlashingProtectionDatabase;
|
|
185
208
|
} = {},
|
|
186
209
|
options: {
|
|
187
210
|
prefilledPublicData?: PublicDataTreeLeaf[];
|
|
@@ -244,7 +267,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
244
267
|
|
|
245
268
|
const publicClient = createPublicClient({
|
|
246
269
|
chain: ethereumChain.chainInfo,
|
|
247
|
-
transport:
|
|
270
|
+
transport: makeL1HttpTransport(config.l1RpcUrls, { timeout: config.l1HttpTimeoutMS }),
|
|
248
271
|
pollingInterval: config.viemPollingIntervalMS,
|
|
249
272
|
});
|
|
250
273
|
|
|
@@ -258,10 +281,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
258
281
|
config.l1Contracts = { ...config.l1Contracts, ...l1ContractsAddresses };
|
|
259
282
|
|
|
260
283
|
const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
|
|
261
|
-
const [l1GenesisTime, slotDuration, rollupVersionFromRollup] = await Promise.all([
|
|
284
|
+
const [l1GenesisTime, slotDuration, rollupVersionFromRollup, rollupManaLimit] = await Promise.all([
|
|
262
285
|
rollupContract.getL1GenesisTime(),
|
|
263
286
|
rollupContract.getSlotDuration(),
|
|
264
287
|
rollupContract.getVersion(),
|
|
288
|
+
rollupContract.getManaLimit().then(Number),
|
|
265
289
|
] as const);
|
|
266
290
|
|
|
267
291
|
config.rollupVersion ??= Number(rollupVersionFromRollup);
|
|
@@ -292,21 +316,40 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
292
316
|
options.prefilledPublicData,
|
|
293
317
|
telemetry,
|
|
294
318
|
);
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
319
|
+
const useRealVerifiers = config.realProofs || config.debugForceTxProofVerification;
|
|
320
|
+
let peerProofVerifier: ClientProtocolCircuitVerifier;
|
|
321
|
+
let rpcProofVerifier: ClientProtocolCircuitVerifier;
|
|
322
|
+
if (useRealVerifiers) {
|
|
323
|
+
peerProofVerifier = await BatchChonkVerifier.new(config, config.bbChonkVerifyMaxBatch, 'peer');
|
|
324
|
+
const rpcVerifier = await BBCircuitVerifier.new(config);
|
|
325
|
+
rpcProofVerifier = new QueuedIVCVerifier(rpcVerifier, config.numConcurrentIVCVerifiers);
|
|
326
|
+
} else {
|
|
327
|
+
peerProofVerifier = new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
328
|
+
rpcProofVerifier = new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
let debugLogStore: DebugLogStore;
|
|
299
332
|
if (!config.realProofs) {
|
|
300
333
|
log.warn(`Aztec node is accepting fake proofs`);
|
|
334
|
+
|
|
335
|
+
debugLogStore = new InMemoryDebugLogStore();
|
|
336
|
+
log.info(
|
|
337
|
+
'Aztec node started in test mode (realProofs set to false) hence debug logs from public functions will be collected and served',
|
|
338
|
+
);
|
|
339
|
+
} else {
|
|
340
|
+
debugLogStore = new NullDebugLogStore();
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const proverOnly = config.enableProverNode && config.disableValidator;
|
|
344
|
+
if (proverOnly) {
|
|
345
|
+
log.info('Starting in prover-only mode: skipping validator, sequencer, sentinel, and slasher subsystems');
|
|
301
346
|
}
|
|
302
|
-
const proofVerifier = new QueuedIVCVerifier(config, circuitVerifier);
|
|
303
347
|
|
|
304
348
|
// create the tx pool and the p2p client, which will need the l2 block source
|
|
305
349
|
const p2pClient = await createP2PClient(
|
|
306
|
-
P2PClientType.Full,
|
|
307
350
|
config,
|
|
308
351
|
archiver,
|
|
309
|
-
|
|
352
|
+
peerProofVerifier,
|
|
310
353
|
worldStateSynchronizer,
|
|
311
354
|
epochCache,
|
|
312
355
|
packageVersion,
|
|
@@ -315,49 +358,60 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
315
358
|
deps.p2pClientDeps,
|
|
316
359
|
);
|
|
317
360
|
|
|
318
|
-
// We
|
|
319
|
-
|
|
361
|
+
// We'll accumulate sentinel watchers here
|
|
362
|
+
const watchers: Watcher[] = [];
|
|
320
363
|
|
|
321
|
-
// Create FullNodeCheckpointsBuilder for
|
|
364
|
+
// Create FullNodeCheckpointsBuilder for block proposal handling and tx validation.
|
|
365
|
+
// Override maxTxsPerCheckpoint with the validator-specific limit if set.
|
|
322
366
|
const validatorCheckpointsBuilder = new FullNodeCheckpointsBuilder(
|
|
323
|
-
{
|
|
367
|
+
{
|
|
368
|
+
...config,
|
|
369
|
+
l1GenesisTime,
|
|
370
|
+
slotDuration: Number(slotDuration),
|
|
371
|
+
rollupManaLimit,
|
|
372
|
+
maxTxsPerCheckpoint: config.validateMaxTxsPerCheckpoint,
|
|
373
|
+
},
|
|
324
374
|
worldStateSynchronizer,
|
|
325
375
|
archiver,
|
|
326
376
|
dateProvider,
|
|
327
377
|
telemetry,
|
|
328
378
|
);
|
|
329
379
|
|
|
330
|
-
|
|
331
|
-
const watchers: Watcher[] = [];
|
|
380
|
+
let validatorClient: ValidatorClient | undefined;
|
|
332
381
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
382
|
+
if (!proverOnly) {
|
|
383
|
+
// Create validator client if required
|
|
384
|
+
validatorClient = await createValidatorClient(config, {
|
|
385
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
386
|
+
worldState: worldStateSynchronizer,
|
|
387
|
+
p2pClient,
|
|
388
|
+
telemetry,
|
|
389
|
+
dateProvider,
|
|
390
|
+
epochCache,
|
|
391
|
+
blockSource: archiver,
|
|
392
|
+
l1ToL2MessageSource: archiver,
|
|
393
|
+
keyStoreManager,
|
|
394
|
+
blobClient,
|
|
395
|
+
slashingProtectionDb: deps.slashingProtectionDb,
|
|
396
|
+
});
|
|
346
397
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
398
|
+
// If we have a validator client, register it as a source of offenses for the slasher,
|
|
399
|
+
// and have it register callbacks on the p2p client *before* we start it, otherwise messages
|
|
400
|
+
// like attestations or auths will fail.
|
|
401
|
+
if (validatorClient) {
|
|
402
|
+
watchers.push(validatorClient);
|
|
403
|
+
if (!options.dontStartSequencer) {
|
|
404
|
+
await validatorClient.registerHandlers();
|
|
405
|
+
}
|
|
354
406
|
}
|
|
355
407
|
}
|
|
356
408
|
|
|
357
|
-
// If there's no validator client
|
|
358
|
-
//
|
|
359
|
-
|
|
360
|
-
|
|
409
|
+
// If there's no validator client, create a BlockProposalHandler to handle block proposals
|
|
410
|
+
// for monitoring or reexecution. Reexecution (default) allows us to follow the pending chain,
|
|
411
|
+
// while non-reexecution is used for validating the proposals and collecting their txs.
|
|
412
|
+
if (!validatorClient) {
|
|
413
|
+
const reexecute = !!config.alwaysReexecuteBlockProposals;
|
|
414
|
+
log.info(`Setting up block proposal handler` + (reexecute ? ' with reexecution of proposals' : ''));
|
|
361
415
|
createBlockProposalHandler(config, {
|
|
362
416
|
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
363
417
|
worldState: worldStateSynchronizer,
|
|
@@ -367,7 +421,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
367
421
|
p2pClient,
|
|
368
422
|
dateProvider,
|
|
369
423
|
telemetry,
|
|
370
|
-
}).
|
|
424
|
+
}).register(p2pClient, reexecute);
|
|
371
425
|
}
|
|
372
426
|
|
|
373
427
|
// Start world state and wait for it to sync to the archiver.
|
|
@@ -376,29 +430,33 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
376
430
|
// Start p2p. Note that it depends on world state to be running.
|
|
377
431
|
await p2pClient.start();
|
|
378
432
|
|
|
379
|
-
|
|
380
|
-
if (validatorsSentinel && config.slashInactivityPenalty > 0n) {
|
|
381
|
-
watchers.push(validatorsSentinel);
|
|
382
|
-
}
|
|
383
|
-
|
|
433
|
+
let validatorsSentinel: Awaited<ReturnType<typeof createSentinel>> | undefined;
|
|
384
434
|
let epochPruneWatcher: EpochPruneWatcher | undefined;
|
|
385
|
-
if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
|
|
386
|
-
epochPruneWatcher = new EpochPruneWatcher(
|
|
387
|
-
archiver,
|
|
388
|
-
archiver,
|
|
389
|
-
epochCache,
|
|
390
|
-
p2pClient.getTxProvider(),
|
|
391
|
-
validatorCheckpointsBuilder,
|
|
392
|
-
config,
|
|
393
|
-
);
|
|
394
|
-
watchers.push(epochPruneWatcher);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// We assume we want to slash for invalid attestations unless all max penalties are set to 0
|
|
398
435
|
let attestationsBlockWatcher: AttestationsBlockWatcher | undefined;
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
436
|
+
|
|
437
|
+
if (!proverOnly) {
|
|
438
|
+
validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
|
|
439
|
+
if (validatorsSentinel && config.slashInactivityPenalty > 0n) {
|
|
440
|
+
watchers.push(validatorsSentinel);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
|
|
444
|
+
epochPruneWatcher = new EpochPruneWatcher(
|
|
445
|
+
archiver,
|
|
446
|
+
archiver,
|
|
447
|
+
epochCache,
|
|
448
|
+
p2pClient.getTxProvider(),
|
|
449
|
+
validatorCheckpointsBuilder,
|
|
450
|
+
config,
|
|
451
|
+
);
|
|
452
|
+
watchers.push(epochPruneWatcher);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// We assume we want to slash for invalid attestations unless all max penalties are set to 0
|
|
456
|
+
if (config.slashProposeInvalidAttestationsPenalty > 0n || config.slashAttestDescendantOfInvalidPenalty > 0n) {
|
|
457
|
+
attestationsBlockWatcher = new AttestationsBlockWatcher(archiver, epochCache, config);
|
|
458
|
+
watchers.push(attestationsBlockWatcher);
|
|
459
|
+
}
|
|
402
460
|
}
|
|
403
461
|
|
|
404
462
|
// Start p2p-related services once the archiver has completed sync
|
|
@@ -413,6 +471,14 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
413
471
|
})
|
|
414
472
|
.catch(err => log.error('Failed to start p2p services after archiver sync', err));
|
|
415
473
|
|
|
474
|
+
const globalVariableBuilder = new GlobalVariableBuilder(dateProvider, publicClient, {
|
|
475
|
+
l1Contracts: config.l1Contracts,
|
|
476
|
+
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
477
|
+
rollupVersion: BigInt(config.rollupVersion),
|
|
478
|
+
l1GenesisTime,
|
|
479
|
+
slotDuration: Number(slotDuration),
|
|
480
|
+
});
|
|
481
|
+
|
|
416
482
|
// Validator enabled, create/start relevant service
|
|
417
483
|
let sequencer: SequencerClient | undefined;
|
|
418
484
|
let slasherClient: SlasherClientInterface | undefined;
|
|
@@ -450,19 +516,34 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
450
516
|
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider, kzg: Blob.getViemKzgInstance() },
|
|
451
517
|
);
|
|
452
518
|
|
|
519
|
+
// Create a funder L1TxUtils from the keystore funding account (if configured)
|
|
520
|
+
const fundingSigner = keyStoreManager?.createFundingSigner();
|
|
521
|
+
let funderL1TxUtils: L1TxUtils | undefined;
|
|
522
|
+
if (fundingSigner) {
|
|
523
|
+
const [funder] = await createL1TxUtilsFromSigners(
|
|
524
|
+
publicClient,
|
|
525
|
+
[fundingSigner],
|
|
526
|
+
{ ...config, scope: 'sequencer' },
|
|
527
|
+
{ telemetry, logger: log.createChild('l1-tx-utils:funder'), dateProvider },
|
|
528
|
+
);
|
|
529
|
+
funderL1TxUtils = funder;
|
|
530
|
+
}
|
|
531
|
+
|
|
453
532
|
// Create and start the sequencer client
|
|
454
533
|
const checkpointsBuilder = new CheckpointsBuilder(
|
|
455
|
-
{ ...config, l1GenesisTime, slotDuration: Number(slotDuration) },
|
|
534
|
+
{ ...config, l1GenesisTime, slotDuration: Number(slotDuration), rollupManaLimit },
|
|
456
535
|
worldStateSynchronizer,
|
|
457
536
|
archiver,
|
|
458
537
|
dateProvider,
|
|
459
538
|
telemetry,
|
|
539
|
+
debugLogStore,
|
|
460
540
|
);
|
|
461
541
|
|
|
462
542
|
sequencer = await SequencerClient.new(config, {
|
|
463
543
|
...deps,
|
|
464
544
|
epochCache,
|
|
465
545
|
l1TxUtils,
|
|
546
|
+
funderL1TxUtils,
|
|
466
547
|
validatorClient,
|
|
467
548
|
p2pClient,
|
|
468
549
|
worldStateSynchronizer,
|
|
@@ -474,6 +555,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
474
555
|
dateProvider,
|
|
475
556
|
blobClient,
|
|
476
557
|
nodeKeyStore: keyStoreManager!,
|
|
558
|
+
globalVariableBuilder,
|
|
477
559
|
});
|
|
478
560
|
}
|
|
479
561
|
|
|
@@ -507,13 +589,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
507
589
|
}
|
|
508
590
|
}
|
|
509
591
|
|
|
510
|
-
const globalVariableBuilder = new GlobalVariableBuilder({
|
|
511
|
-
...config,
|
|
512
|
-
rollupVersion: BigInt(config.rollupVersion),
|
|
513
|
-
l1GenesisTime,
|
|
514
|
-
slotDuration: Number(slotDuration),
|
|
515
|
-
});
|
|
516
|
-
|
|
517
592
|
const node = new AztecNodeService(
|
|
518
593
|
config,
|
|
519
594
|
p2pClient,
|
|
@@ -532,12 +607,14 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
532
607
|
globalVariableBuilder,
|
|
533
608
|
epochCache,
|
|
534
609
|
packageVersion,
|
|
535
|
-
|
|
610
|
+
peerProofVerifier,
|
|
611
|
+
rpcProofVerifier,
|
|
536
612
|
telemetry,
|
|
537
613
|
log,
|
|
538
614
|
blobClient,
|
|
539
615
|
validatorClient,
|
|
540
616
|
keyStoreManager,
|
|
617
|
+
debugLogStore,
|
|
541
618
|
);
|
|
542
619
|
|
|
543
620
|
return node;
|
|
@@ -581,7 +658,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
581
658
|
}
|
|
582
659
|
|
|
583
660
|
public async getAllowedPublicSetup(): Promise<AllowedElement[]> {
|
|
584
|
-
return this.config.
|
|
661
|
+
return [...(await getDefaultAllowedSetupFunctions()), ...(this.config.txPublicSetupAllowListExtend ?? [])];
|
|
585
662
|
}
|
|
586
663
|
|
|
587
664
|
/**
|
|
@@ -676,6 +753,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
676
753
|
return (await this.blockSource.getCheckpointedBlocks(from, limit)) ?? [];
|
|
677
754
|
}
|
|
678
755
|
|
|
756
|
+
public getCheckpointsDataForEpoch(epochNumber: EpochNumber) {
|
|
757
|
+
return this.blockSource.getCheckpointsDataForEpoch(epochNumber);
|
|
758
|
+
}
|
|
759
|
+
|
|
679
760
|
/**
|
|
680
761
|
* Method to fetch the current min L2 fees.
|
|
681
762
|
* @returns The current min L2 fees.
|
|
@@ -708,6 +789,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
708
789
|
return await this.blockSource.getCheckpointedL2BlockNumber();
|
|
709
790
|
}
|
|
710
791
|
|
|
792
|
+
public getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
793
|
+
return this.blockSource.getCheckpointNumber();
|
|
794
|
+
}
|
|
795
|
+
|
|
711
796
|
/**
|
|
712
797
|
* Method to fetch the version of the package.
|
|
713
798
|
* @returns The node package version
|
|
@@ -745,18 +830,22 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
745
830
|
page?: number,
|
|
746
831
|
referenceBlock?: BlockHash,
|
|
747
832
|
): Promise<TxScopedL2Log[][]> {
|
|
833
|
+
let upToBlockNumber: BlockNumber | undefined;
|
|
748
834
|
if (referenceBlock) {
|
|
749
835
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
750
|
-
if (
|
|
836
|
+
if (referenceBlock.equals(initialBlockHash)) {
|
|
837
|
+
upToBlockNumber = BlockNumber(0);
|
|
838
|
+
} else {
|
|
751
839
|
const header = await this.blockSource.getBlockHeaderByHash(referenceBlock);
|
|
752
840
|
if (!header) {
|
|
753
841
|
throw new Error(
|
|
754
842
|
`Block ${referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`,
|
|
755
843
|
);
|
|
756
844
|
}
|
|
845
|
+
upToBlockNumber = header.globalVariables.blockNumber;
|
|
757
846
|
}
|
|
758
847
|
}
|
|
759
|
-
return this.logsSource.getPrivateLogsByTags(tags, page);
|
|
848
|
+
return this.logsSource.getPrivateLogsByTags(tags, page, upToBlockNumber);
|
|
760
849
|
}
|
|
761
850
|
|
|
762
851
|
public async getPublicLogsByTagsFromContract(
|
|
@@ -765,18 +854,22 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
765
854
|
page?: number,
|
|
766
855
|
referenceBlock?: BlockHash,
|
|
767
856
|
): Promise<TxScopedL2Log[][]> {
|
|
857
|
+
let upToBlockNumber: BlockNumber | undefined;
|
|
768
858
|
if (referenceBlock) {
|
|
769
859
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
770
|
-
if (
|
|
860
|
+
if (referenceBlock.equals(initialBlockHash)) {
|
|
861
|
+
upToBlockNumber = BlockNumber(0);
|
|
862
|
+
} else {
|
|
771
863
|
const header = await this.blockSource.getBlockHeaderByHash(referenceBlock);
|
|
772
864
|
if (!header) {
|
|
773
865
|
throw new Error(
|
|
774
866
|
`Block ${referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`,
|
|
775
867
|
);
|
|
776
868
|
}
|
|
869
|
+
upToBlockNumber = header.globalVariables.blockNumber;
|
|
777
870
|
}
|
|
778
871
|
}
|
|
779
|
-
return this.logsSource.getPublicLogsByTagsFromContract(contractAddress, tags, page);
|
|
872
|
+
return this.logsSource.getPublicLogsByTagsFromContract(contractAddress, tags, page, upToBlockNumber);
|
|
780
873
|
}
|
|
781
874
|
|
|
782
875
|
/**
|
|
@@ -818,8 +911,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
818
911
|
}
|
|
819
912
|
|
|
820
913
|
await this.p2pClient!.sendTx(tx);
|
|
821
|
-
|
|
822
|
-
this.
|
|
914
|
+
const duration = timer.ms();
|
|
915
|
+
this.metrics.receivedTx(duration, true);
|
|
916
|
+
this.log.info(`Received tx ${txHash} in ${duration}ms`, { txHash });
|
|
823
917
|
}
|
|
824
918
|
|
|
825
919
|
public async getTxReceipt(txHash: TxHash): Promise<TxReceipt> {
|
|
@@ -831,18 +925,22 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
831
925
|
// Then get the actual tx from the archiver, which tracks every tx in a mined block.
|
|
832
926
|
const settledTxReceipt = await this.blockSource.getSettledTxReceipt(txHash);
|
|
833
927
|
|
|
928
|
+
let receipt: TxReceipt;
|
|
834
929
|
if (settledTxReceipt) {
|
|
835
|
-
|
|
836
|
-
return settledTxReceipt;
|
|
930
|
+
receipt = settledTxReceipt;
|
|
837
931
|
} else if (isKnownToPool) {
|
|
838
932
|
// If the tx is in the pool but not in the archiver, it's pending.
|
|
839
933
|
// This handles race conditions between archiver and p2p, where the archiver
|
|
840
934
|
// has pruned the block in which a tx was mined, but p2p has not caught up yet.
|
|
841
|
-
|
|
935
|
+
receipt = new TxReceipt(txHash, TxStatus.PENDING, undefined, undefined);
|
|
842
936
|
} else {
|
|
843
937
|
// Otherwise, if we don't know the tx, we consider it dropped.
|
|
844
|
-
|
|
938
|
+
receipt = new TxReceipt(txHash, TxStatus.DROPPED, undefined, 'Tx dropped by P2P node');
|
|
845
939
|
}
|
|
940
|
+
|
|
941
|
+
this.debugLogStore.decorateReceiptWithLogs(txHash.toString(), receipt);
|
|
942
|
+
|
|
943
|
+
return receipt;
|
|
846
944
|
}
|
|
847
945
|
|
|
848
946
|
public getTxEffect(txHash: TxHash): Promise<IndexedTxEffect | undefined> {
|
|
@@ -857,7 +955,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
857
955
|
await tryStop(this.validatorsSentinel);
|
|
858
956
|
await tryStop(this.epochPruneWatcher);
|
|
859
957
|
await tryStop(this.slasherClient);
|
|
860
|
-
await tryStop(this.
|
|
958
|
+
await Promise.all([tryStop(this.peerProofVerifier), tryStop(this.rpcProofVerifier)]);
|
|
861
959
|
await tryStop(this.sequencer);
|
|
862
960
|
await tryStop(this.proverNode);
|
|
863
961
|
await tryStop(this.p2pClient);
|
|
@@ -913,58 +1011,64 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
913
1011
|
treeId: MerkleTreeId,
|
|
914
1012
|
leafValues: Fr[],
|
|
915
1013
|
): Promise<(DataInBlock<bigint> | undefined)[]> {
|
|
916
|
-
const committedDb = await this
|
|
1014
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
917
1015
|
const maybeIndices = await committedDb.findLeafIndices(
|
|
918
1016
|
treeId,
|
|
919
1017
|
leafValues.map(x => x.toBuffer()),
|
|
920
1018
|
);
|
|
921
|
-
//
|
|
922
|
-
const
|
|
1019
|
+
// Filter out undefined values to query block numbers only for found leaves
|
|
1020
|
+
const definedIndices = maybeIndices.filter(x => x !== undefined);
|
|
923
1021
|
|
|
924
|
-
// Now we find the block numbers for the indices
|
|
925
|
-
const blockNumbers = await committedDb.getBlockNumbersForLeafIndices(treeId,
|
|
1022
|
+
// Now we find the block numbers for the defined indices
|
|
1023
|
+
const blockNumbers = await committedDb.getBlockNumbersForLeafIndices(treeId, definedIndices);
|
|
926
1024
|
|
|
927
|
-
//
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
1025
|
+
// Build a map from leaf index to block number
|
|
1026
|
+
const indexToBlockNumber = new Map<bigint, BlockNumber>();
|
|
1027
|
+
for (let i = 0; i < definedIndices.length; i++) {
|
|
1028
|
+
const blockNumber = blockNumbers[i];
|
|
1029
|
+
if (blockNumber === undefined) {
|
|
1030
|
+
throw new Error(
|
|
1031
|
+
`Block number is undefined for leaf index ${definedIndices[i]} in tree ${MerkleTreeId[treeId]}`,
|
|
1032
|
+
);
|
|
931
1033
|
}
|
|
1034
|
+
indexToBlockNumber.set(definedIndices[i], blockNumber);
|
|
932
1035
|
}
|
|
933
1036
|
|
|
934
1037
|
// Get unique block numbers in order to optimize num calls to getLeafValue function.
|
|
935
|
-
const uniqueBlockNumbers = [...new Set(
|
|
1038
|
+
const uniqueBlockNumbers = [...new Set(indexToBlockNumber.values())];
|
|
936
1039
|
|
|
937
|
-
// Now we obtain the block hashes from the archive tree
|
|
938
|
-
// (note that block number corresponds to the leaf index in the archive tree).
|
|
1040
|
+
// Now we obtain the block hashes from the archive tree (block number = leaf index in archive tree).
|
|
939
1041
|
const blockHashes = await Promise.all(
|
|
940
1042
|
uniqueBlockNumbers.map(blockNumber => {
|
|
941
1043
|
return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber));
|
|
942
1044
|
}),
|
|
943
1045
|
);
|
|
944
1046
|
|
|
945
|
-
//
|
|
1047
|
+
// Build a map from block number to block hash
|
|
1048
|
+
const blockNumberToHash = new Map<BlockNumber, Fr>();
|
|
946
1049
|
for (let i = 0; i < uniqueBlockNumbers.length; i++) {
|
|
947
|
-
|
|
1050
|
+
const blockHash = blockHashes[i];
|
|
1051
|
+
if (blockHash === undefined) {
|
|
948
1052
|
throw new Error(`Block hash is undefined for block number ${uniqueBlockNumbers[i]}`);
|
|
949
1053
|
}
|
|
1054
|
+
blockNumberToHash.set(uniqueBlockNumbers[i], blockHash);
|
|
950
1055
|
}
|
|
951
1056
|
|
|
952
1057
|
// Create DataInBlock objects by combining indices, blockNumbers and blockHashes and return them.
|
|
953
|
-
return maybeIndices.map(
|
|
1058
|
+
return maybeIndices.map(index => {
|
|
954
1059
|
if (index === undefined) {
|
|
955
1060
|
return undefined;
|
|
956
1061
|
}
|
|
957
|
-
const blockNumber =
|
|
1062
|
+
const blockNumber = indexToBlockNumber.get(index);
|
|
958
1063
|
if (blockNumber === undefined) {
|
|
959
|
-
|
|
1064
|
+
throw new Error(`Block number not found for leaf index ${index} in tree ${MerkleTreeId[treeId]}`);
|
|
960
1065
|
}
|
|
961
|
-
const
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
return undefined;
|
|
1066
|
+
const blockHash = blockNumberToHash.get(blockNumber);
|
|
1067
|
+
if (blockHash === undefined) {
|
|
1068
|
+
throw new Error(`Block hash not found for block number ${blockNumber}`);
|
|
965
1069
|
}
|
|
966
1070
|
return {
|
|
967
|
-
l2BlockNumber:
|
|
1071
|
+
l2BlockNumber: blockNumber,
|
|
968
1072
|
l2BlockHash: new BlockHash(blockHash),
|
|
969
1073
|
data: index,
|
|
970
1074
|
};
|
|
@@ -975,7 +1079,15 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
975
1079
|
referenceBlock: BlockParameter,
|
|
976
1080
|
blockHash: BlockHash,
|
|
977
1081
|
): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
|
|
978
|
-
|
|
1082
|
+
// The Noir circuit checks the archive membership proof against `anchor_block_header.last_archive.root`,
|
|
1083
|
+
// which is the archive tree root BEFORE the anchor block was added (i.e. the state after block N-1).
|
|
1084
|
+
// So we need the world state at block N-1, not block N, to produce a sibling path matching that root.
|
|
1085
|
+
const referenceBlockNumber = await this.resolveBlockNumber(referenceBlock);
|
|
1086
|
+
if (referenceBlockNumber === BlockNumber.ZERO) {
|
|
1087
|
+
// Block 0 (the initial block) has an empty archive, so no membership witness can exist.
|
|
1088
|
+
return undefined;
|
|
1089
|
+
}
|
|
1090
|
+
const committedDb = await this.getWorldState(BlockNumber(referenceBlockNumber - 1));
|
|
979
1091
|
const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.ARCHIVE>(MerkleTreeId.ARCHIVE, [blockHash]);
|
|
980
1092
|
return pathAndIndex === undefined
|
|
981
1093
|
? undefined
|
|
@@ -986,7 +1098,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
986
1098
|
referenceBlock: BlockParameter,
|
|
987
1099
|
noteHash: Fr,
|
|
988
1100
|
): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
|
|
989
|
-
const committedDb = await this
|
|
1101
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
990
1102
|
const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.NOTE_HASH_TREE>(
|
|
991
1103
|
MerkleTreeId.NOTE_HASH_TREE,
|
|
992
1104
|
[noteHash],
|
|
@@ -1000,7 +1112,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1000
1112
|
referenceBlock: BlockParameter,
|
|
1001
1113
|
l1ToL2Message: Fr,
|
|
1002
1114
|
): Promise<[bigint, SiblingPath<typeof L1_TO_L2_MSG_TREE_HEIGHT>] | undefined> {
|
|
1003
|
-
const db = await this
|
|
1115
|
+
const db = await this.getWorldState(referenceBlock);
|
|
1004
1116
|
const [witness] = await db.findSiblingPaths(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, [l1ToL2Message]);
|
|
1005
1117
|
if (!witness) {
|
|
1006
1118
|
return undefined;
|
|
@@ -1010,11 +1122,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1010
1122
|
return [witness.index, witness.path];
|
|
1011
1123
|
}
|
|
1012
1124
|
|
|
1013
|
-
public async
|
|
1125
|
+
public async getL1ToL2MessageCheckpoint(l1ToL2Message: Fr): Promise<CheckpointNumber | undefined> {
|
|
1014
1126
|
const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
|
|
1015
|
-
return messageIndex
|
|
1016
|
-
? BlockNumber.fromCheckpointNumber(InboxLeaf.checkpointNumberFromIndex(messageIndex))
|
|
1017
|
-
: undefined;
|
|
1127
|
+
return messageIndex ? InboxLeaf.checkpointNumberFromIndex(messageIndex) : undefined;
|
|
1018
1128
|
}
|
|
1019
1129
|
|
|
1020
1130
|
/**
|
|
@@ -1035,19 +1145,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1035
1145
|
public async getL2ToL1Messages(epoch: EpochNumber): Promise<Fr[][][][]> {
|
|
1036
1146
|
// Assumes `getCheckpointedBlocksForEpoch` returns blocks in ascending order of block number.
|
|
1037
1147
|
const checkpointedBlocks = await this.blockSource.getCheckpointedBlocksForEpoch(epoch);
|
|
1038
|
-
const blocksInCheckpoints
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
for (const checkpointedBlock of checkpointedBlocks) {
|
|
1042
|
-
const block = checkpointedBlock.block;
|
|
1043
|
-
const slotNumber = block.header.globalVariables.slotNumber;
|
|
1044
|
-
if (slotNumber !== previousSlotNumber) {
|
|
1045
|
-
checkpointIndex++;
|
|
1046
|
-
blocksInCheckpoints.push([]);
|
|
1047
|
-
previousSlotNumber = slotNumber;
|
|
1048
|
-
}
|
|
1049
|
-
blocksInCheckpoints[checkpointIndex].push(block);
|
|
1050
|
-
}
|
|
1148
|
+
const blocksInCheckpoints = chunkBy(checkpointedBlocks, cb => cb.block.header.globalVariables.slotNumber).map(
|
|
1149
|
+
group => group.map(cb => cb.block),
|
|
1150
|
+
);
|
|
1051
1151
|
return blocksInCheckpoints.map(blocks =>
|
|
1052
1152
|
blocks.map(block => block.body.txEffects.map(txEffect => txEffect.l2ToL1Msgs)),
|
|
1053
1153
|
);
|
|
@@ -1057,7 +1157,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1057
1157
|
referenceBlock: BlockParameter,
|
|
1058
1158
|
nullifier: Fr,
|
|
1059
1159
|
): Promise<NullifierMembershipWitness | undefined> {
|
|
1060
|
-
const db = await this
|
|
1160
|
+
const db = await this.getWorldState(referenceBlock);
|
|
1061
1161
|
const [witness] = await db.findSiblingPaths(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]);
|
|
1062
1162
|
if (!witness) {
|
|
1063
1163
|
return undefined;
|
|
@@ -1072,33 +1172,20 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1072
1172
|
return new NullifierMembershipWitness(index, leafPreimage as NullifierLeafPreimage, path);
|
|
1073
1173
|
}
|
|
1074
1174
|
|
|
1075
|
-
/**
|
|
1076
|
-
* Returns a low nullifier membership witness for a given nullifier at a given block.
|
|
1077
|
-
* @param referenceBlock - The block parameter (block number, block hash, or 'latest') at which to get the data
|
|
1078
|
-
* (which contains the root of the nullifier tree in which we are searching for the nullifier).
|
|
1079
|
-
* @param nullifier - Nullifier we try to find the low nullifier witness for.
|
|
1080
|
-
* @returns The low nullifier membership witness (if found).
|
|
1081
|
-
* @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
|
|
1082
|
-
* list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier
|
|
1083
|
-
* we are trying to prove non-inclusion for.
|
|
1084
|
-
*
|
|
1085
|
-
* Note: This function returns the membership witness of the nullifier itself and not the low nullifier when
|
|
1086
|
-
* the nullifier already exists in the tree. This is because the `getPreviousValueIndex` function returns the
|
|
1087
|
-
* index of the nullifier itself when it already exists in the tree.
|
|
1088
|
-
* TODO: This is a confusing behavior and we should eventually address that.
|
|
1089
|
-
*/
|
|
1090
1175
|
public async getLowNullifierMembershipWitness(
|
|
1091
1176
|
referenceBlock: BlockParameter,
|
|
1092
1177
|
nullifier: Fr,
|
|
1093
1178
|
): Promise<NullifierMembershipWitness | undefined> {
|
|
1094
|
-
const committedDb = await this
|
|
1179
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
1095
1180
|
const findResult = await committedDb.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
|
|
1096
1181
|
if (!findResult) {
|
|
1097
1182
|
return undefined;
|
|
1098
1183
|
}
|
|
1099
1184
|
const { index, alreadyPresent } = findResult;
|
|
1100
1185
|
if (alreadyPresent) {
|
|
1101
|
-
|
|
1186
|
+
throw new Error(
|
|
1187
|
+
`Cannot prove nullifier non-inclusion: nullifier ${nullifier.toBigInt()} already exists in the tree`,
|
|
1188
|
+
);
|
|
1102
1189
|
}
|
|
1103
1190
|
const preimageData = (await committedDb.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index))!;
|
|
1104
1191
|
|
|
@@ -1107,7 +1194,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1107
1194
|
}
|
|
1108
1195
|
|
|
1109
1196
|
async getPublicDataWitness(referenceBlock: BlockParameter, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
|
|
1110
|
-
const committedDb = await this
|
|
1197
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
1111
1198
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
1112
1199
|
if (!lowLeafResult) {
|
|
1113
1200
|
return undefined;
|
|
@@ -1122,7 +1209,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1122
1209
|
}
|
|
1123
1210
|
|
|
1124
1211
|
public async getPublicStorageAt(referenceBlock: BlockParameter, contract: AztecAddress, slot: Fr): Promise<Fr> {
|
|
1125
|
-
const committedDb = await this
|
|
1212
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
1126
1213
|
const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
|
|
1127
1214
|
|
|
1128
1215
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
@@ -1236,7 +1323,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1236
1323
|
const processor = publicProcessorFactory.create(merkleTreeFork, newGlobalVariables, config);
|
|
1237
1324
|
|
|
1238
1325
|
// REFACTOR: Consider merging ProcessReturnValues into ProcessedTx
|
|
1239
|
-
const [processedTxs, failedTxs, _usedTxs, returns] = await processor.process([tx]);
|
|
1326
|
+
const [processedTxs, failedTxs, _usedTxs, returns, debugLogs] = await processor.process([tx]);
|
|
1240
1327
|
// REFACTOR: Consider returning the error rather than throwing
|
|
1241
1328
|
if (failedTxs.length) {
|
|
1242
1329
|
this.log.warn(`Simulated tx ${txHash} fails: ${failedTxs[0].error}`, { txHash });
|
|
@@ -1250,6 +1337,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1250
1337
|
processedTx.txEffect,
|
|
1251
1338
|
returns,
|
|
1252
1339
|
processedTx.gasUsed,
|
|
1340
|
+
debugLogs,
|
|
1253
1341
|
);
|
|
1254
1342
|
} finally {
|
|
1255
1343
|
await merkleTreeFork.close();
|
|
@@ -1261,12 +1349,13 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1261
1349
|
{ isSimulation, skipFeeEnforcement }: { isSimulation?: boolean; skipFeeEnforcement?: boolean } = {},
|
|
1262
1350
|
): Promise<TxValidationResult> {
|
|
1263
1351
|
const db = this.worldStateSynchronizer.getCommitted();
|
|
1264
|
-
const verifier = isSimulation ? undefined : this.
|
|
1352
|
+
const verifier = isSimulation ? undefined : this.rpcProofVerifier;
|
|
1265
1353
|
|
|
1266
1354
|
// We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
|
|
1267
1355
|
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1268
1356
|
const blockNumber = BlockNumber((await this.blockSource.getBlockNumber()) + 1);
|
|
1269
|
-
const
|
|
1357
|
+
const l1Constants = await this.blockSource.getL1Constants();
|
|
1358
|
+
const validator = createTxValidatorForAcceptingTxsOverRPC(
|
|
1270
1359
|
db,
|
|
1271
1360
|
this.contractDataSource,
|
|
1272
1361
|
verifier,
|
|
@@ -1275,10 +1364,16 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1275
1364
|
blockNumber,
|
|
1276
1365
|
l1ChainId: this.l1ChainId,
|
|
1277
1366
|
rollupVersion: this.version,
|
|
1278
|
-
setupAllowList:
|
|
1367
|
+
setupAllowList: [
|
|
1368
|
+
...(await getDefaultAllowedSetupFunctions()),
|
|
1369
|
+
...(this.config.txPublicSetupAllowListExtend ?? []),
|
|
1370
|
+
],
|
|
1279
1371
|
gasFees: await this.getCurrentMinFees(),
|
|
1280
1372
|
skipFeeEnforcement,
|
|
1281
1373
|
txsPermitted: !this.config.disableTransactions,
|
|
1374
|
+
rollupManaLimit: l1Constants.rollupManaLimit,
|
|
1375
|
+
maxBlockL2Gas: this.config.validateMaxL2BlockGas,
|
|
1376
|
+
maxBlockDAGas: this.config.validateMaxDABlockGas,
|
|
1282
1377
|
},
|
|
1283
1378
|
this.log.getBindings(),
|
|
1284
1379
|
);
|
|
@@ -1303,7 +1398,15 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1303
1398
|
archiver.updateConfig(config);
|
|
1304
1399
|
}
|
|
1305
1400
|
if (newConfig.realProofs !== this.config.realProofs) {
|
|
1306
|
-
|
|
1401
|
+
await Promise.all([tryStop(this.peerProofVerifier), tryStop(this.rpcProofVerifier)]);
|
|
1402
|
+
if (newConfig.realProofs) {
|
|
1403
|
+
this.peerProofVerifier = await BatchChonkVerifier.new(newConfig, newConfig.bbChonkVerifyMaxBatch, 'peer');
|
|
1404
|
+
const rpcVerifier = await BBCircuitVerifier.new(newConfig);
|
|
1405
|
+
this.rpcProofVerifier = new QueuedIVCVerifier(rpcVerifier, newConfig.numConcurrentIVCVerifiers);
|
|
1406
|
+
} else {
|
|
1407
|
+
this.peerProofVerifier = new TestCircuitVerifier();
|
|
1408
|
+
this.rpcProofVerifier = new TestCircuitVerifier();
|
|
1409
|
+
}
|
|
1307
1410
|
}
|
|
1308
1411
|
|
|
1309
1412
|
this.config = newConfig;
|
|
@@ -1545,7 +1648,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1545
1648
|
* @param block - The block parameter (block number, block hash, or 'latest') at which to get the data.
|
|
1546
1649
|
* @returns An instance of a committed MerkleTreeOperations
|
|
1547
1650
|
*/
|
|
1548
|
-
async
|
|
1651
|
+
protected async getWorldState(block: BlockParameter) {
|
|
1549
1652
|
let blockSyncedTo: BlockNumber = BlockNumber.ZERO;
|
|
1550
1653
|
try {
|
|
1551
1654
|
// Attempt to sync the world state if necessary
|
|
@@ -1559,6 +1662,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1559
1662
|
return this.worldStateSynchronizer.getCommitted();
|
|
1560
1663
|
}
|
|
1561
1664
|
|
|
1665
|
+
// Get the block number, either directly from the parameter or by quering the archiver with the block hash
|
|
1666
|
+
let blockNumber: BlockNumber;
|
|
1562
1667
|
if (BlockHash.isBlockHash(block)) {
|
|
1563
1668
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1564
1669
|
if (block.equals(initialBlockHash)) {
|
|
@@ -1572,22 +1677,50 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1572
1677
|
`Block hash ${block.toString()} not found when querying world state. If the node API has been queried with anchor block hash possibly a reorg has occurred.`,
|
|
1573
1678
|
);
|
|
1574
1679
|
}
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1680
|
+
|
|
1681
|
+
blockNumber = header.getBlockNumber();
|
|
1682
|
+
} else {
|
|
1683
|
+
blockNumber = block as BlockNumber;
|
|
1578
1684
|
}
|
|
1579
1685
|
|
|
1580
|
-
//
|
|
1581
|
-
{
|
|
1582
|
-
|
|
1686
|
+
// Check it's within world state sync range
|
|
1687
|
+
if (blockNumber > blockSyncedTo) {
|
|
1688
|
+
throw new Error(`Queried block ${block} not yet synced by the node (node is synced upto ${blockSyncedTo}).`);
|
|
1689
|
+
}
|
|
1690
|
+
this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
|
|
1691
|
+
|
|
1692
|
+
const snapshot = this.worldStateSynchronizer.getSnapshot(blockNumber);
|
|
1583
1693
|
|
|
1584
|
-
|
|
1585
|
-
|
|
1694
|
+
// Double-check world-state synced to the same block hash as was requested
|
|
1695
|
+
if (BlockHash.isBlockHash(block)) {
|
|
1696
|
+
const blockHash = await snapshot.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber));
|
|
1697
|
+
if (!blockHash || !new BlockHash(blockHash).equals(block)) {
|
|
1698
|
+
throw new Error(
|
|
1699
|
+
`Block hash ${block.toString()} not found in world state at block number ${blockNumber}. If the node API has been queried with anchor block hash possibly a reorg has occurred.`,
|
|
1700
|
+
);
|
|
1586
1701
|
}
|
|
1702
|
+
}
|
|
1587
1703
|
|
|
1588
|
-
|
|
1589
|
-
|
|
1704
|
+
return snapshot;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
/** Resolves a block parameter to a block number. */
|
|
1708
|
+
protected async resolveBlockNumber(block: BlockParameter): Promise<BlockNumber> {
|
|
1709
|
+
if (block === 'latest') {
|
|
1710
|
+
return BlockNumber(await this.blockSource.getBlockNumber());
|
|
1711
|
+
}
|
|
1712
|
+
if (BlockHash.isBlockHash(block)) {
|
|
1713
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1714
|
+
if (block.equals(initialBlockHash)) {
|
|
1715
|
+
return BlockNumber.ZERO;
|
|
1716
|
+
}
|
|
1717
|
+
const header = await this.blockSource.getBlockHeaderByHash(block);
|
|
1718
|
+
if (!header) {
|
|
1719
|
+
throw new Error(`Block hash ${block.toString()} not found.`);
|
|
1720
|
+
}
|
|
1721
|
+
return header.getBlockNumber();
|
|
1590
1722
|
}
|
|
1723
|
+
return block as BlockNumber;
|
|
1591
1724
|
}
|
|
1592
1725
|
|
|
1593
1726
|
/**
|