@aztec/aztec-node 0.0.1-commit.ff7989d6c → 0.0.1-commit.fff30aa
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/server.d.ts +21 -23
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +247 -151
- package/dest/sentinel/sentinel.js +3 -3
- package/package.json +27 -27
- package/src/aztec-node/server.ts +289 -157
- package/src/sentinel/sentinel.ts +3 -3
package/src/aztec-node/server.ts
CHANGED
|
@@ -5,22 +5,29 @@ import { Blob } from '@aztec/blob-lib';
|
|
|
5
5
|
import { ARCHIVE_HEIGHT, type L1_TO_L2_MSG_TREE_HEIGHT, type NOTE_HASH_TREE_HEIGHT } from '@aztec/constants';
|
|
6
6
|
import { EpochCache, type EpochCacheInterface } from '@aztec/epoch-cache';
|
|
7
7
|
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
8
|
-
import { getPublicClient } from '@aztec/ethereum/client';
|
|
8
|
+
import { getPublicClient, makeL1HttpTransport } from '@aztec/ethereum/client';
|
|
9
9
|
import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
|
|
10
10
|
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
11
11
|
import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
12
|
-
import { compactArray, pick, unique } from '@aztec/foundation/collection';
|
|
12
|
+
import { chunkBy, compactArray, pick, unique } from '@aztec/foundation/collection';
|
|
13
13
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
14
14
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
15
15
|
import { BadRequestError } from '@aztec/foundation/json-rpc';
|
|
16
16
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
17
|
+
import { retryUntil } from '@aztec/foundation/retry';
|
|
17
18
|
import { count } from '@aztec/foundation/string';
|
|
18
19
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
19
20
|
import { MembershipWitness, SiblingPath } from '@aztec/foundation/trees';
|
|
20
21
|
import { type KeyStore, KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
|
|
21
22
|
import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
|
|
22
23
|
import { createForwarderL1TxUtilsFromSigners, createL1TxUtilsFromSigners } from '@aztec/node-lib/factories';
|
|
23
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
type P2P,
|
|
26
|
+
type P2PClientDeps,
|
|
27
|
+
createP2PClient,
|
|
28
|
+
createTxValidatorForAcceptingTxsOverRPC,
|
|
29
|
+
getDefaultAllowedSetupFunctions,
|
|
30
|
+
} from '@aztec/p2p';
|
|
24
31
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
25
32
|
import { type ProverNode, type ProverNodeDeps, createProverNode } from '@aztec/prover-node';
|
|
26
33
|
import { createKeyStoreForProver } from '@aztec/prover-node/config';
|
|
@@ -58,6 +65,7 @@ import {
|
|
|
58
65
|
type AztecNodeAdmin,
|
|
59
66
|
type AztecNodeAdminConfig,
|
|
60
67
|
AztecNodeAdminConfigSchema,
|
|
68
|
+
type AztecNodeDebug,
|
|
61
69
|
type GetContractClassLogsResponse,
|
|
62
70
|
type GetPublicLogsResponse,
|
|
63
71
|
} from '@aztec/stdlib/interfaces/client';
|
|
@@ -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';
|
|
@@ -102,13 +110,13 @@ import {
|
|
|
102
110
|
FullNodeCheckpointsBuilder,
|
|
103
111
|
NodeKeystoreAdapter,
|
|
104
112
|
ValidatorClient,
|
|
105
|
-
|
|
113
|
+
createProposalHandler,
|
|
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';
|
|
@@ -118,7 +126,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
118
126
|
/**
|
|
119
127
|
* The aztec node.
|
|
120
128
|
*/
|
|
121
|
-
export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
129
|
+
export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDebug, Traceable {
|
|
122
130
|
private metrics: NodeMetrics;
|
|
123
131
|
private initialHeaderHashPromise: Promise<BlockHash> | undefined = undefined;
|
|
124
132
|
|
|
@@ -151,12 +159,20 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
151
159
|
private blobClient?: BlobClientInterface,
|
|
152
160
|
private validatorClient?: ValidatorClient,
|
|
153
161
|
private keyStoreManager?: KeystoreManager,
|
|
162
|
+
private debugLogStore: DebugLogStore = new NullDebugLogStore(),
|
|
154
163
|
) {
|
|
155
164
|
this.metrics = new NodeMetrics(telemetry, 'AztecNodeService');
|
|
156
165
|
this.tracer = telemetry.getTracer('AztecNodeService');
|
|
157
166
|
|
|
158
167
|
this.log.info(`Aztec Node version: ${this.packageVersion}`);
|
|
159
168
|
this.log.info(`Aztec Node started on chain 0x${l1ChainId.toString(16)}`, config.l1Contracts);
|
|
169
|
+
|
|
170
|
+
// A defensive check that protects us against introducing a bug in the complex `createAndSync` function. We must
|
|
171
|
+
// never have debugLogStore enabled when not in test mode because then we would be accumulating debug logs in
|
|
172
|
+
// memory which could be a DoS vector on the sequencer (since no fees are paid for debug logs).
|
|
173
|
+
if (debugLogStore.isEnabled && config.realProofs) {
|
|
174
|
+
throw new Error('debugLogStore should never be enabled when realProofs are set');
|
|
175
|
+
}
|
|
160
176
|
}
|
|
161
177
|
|
|
162
178
|
public async getWorldStateSyncStatus(): Promise<WorldStateSyncStatus> {
|
|
@@ -180,8 +196,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
180
196
|
logger?: Logger;
|
|
181
197
|
publisher?: SequencerPublisher;
|
|
182
198
|
dateProvider?: DateProvider;
|
|
183
|
-
p2pClientDeps?: P2PClientDeps
|
|
199
|
+
p2pClientDeps?: P2PClientDeps;
|
|
184
200
|
proverNodeDeps?: Partial<ProverNodeDeps>;
|
|
201
|
+
slashingProtectionDb?: SlashingProtectionDatabase;
|
|
185
202
|
} = {},
|
|
186
203
|
options: {
|
|
187
204
|
prefilledPublicData?: PublicDataTreeLeaf[];
|
|
@@ -244,7 +261,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
244
261
|
|
|
245
262
|
const publicClient = createPublicClient({
|
|
246
263
|
chain: ethereumChain.chainInfo,
|
|
247
|
-
transport:
|
|
264
|
+
transport: makeL1HttpTransport(config.l1RpcUrls, { timeout: config.l1HttpTimeoutMS }),
|
|
248
265
|
pollingInterval: config.viemPollingIntervalMS,
|
|
249
266
|
});
|
|
250
267
|
|
|
@@ -258,10 +275,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
258
275
|
config.l1Contracts = { ...config.l1Contracts, ...l1ContractsAddresses };
|
|
259
276
|
|
|
260
277
|
const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
|
|
261
|
-
const [l1GenesisTime, slotDuration, rollupVersionFromRollup] = await Promise.all([
|
|
278
|
+
const [l1GenesisTime, slotDuration, rollupVersionFromRollup, rollupManaLimit] = await Promise.all([
|
|
262
279
|
rollupContract.getL1GenesisTime(),
|
|
263
280
|
rollupContract.getSlotDuration(),
|
|
264
281
|
rollupContract.getVersion(),
|
|
282
|
+
rollupContract.getManaLimit().then(Number),
|
|
265
283
|
] as const);
|
|
266
284
|
|
|
267
285
|
config.rollupVersion ??= Number(rollupVersionFromRollup);
|
|
@@ -296,14 +314,28 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
296
314
|
config.realProofs || config.debugForceTxProofVerification
|
|
297
315
|
? await BBCircuitVerifier.new(config)
|
|
298
316
|
: new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
317
|
+
|
|
318
|
+
let debugLogStore: DebugLogStore;
|
|
299
319
|
if (!config.realProofs) {
|
|
300
320
|
log.warn(`Aztec node is accepting fake proofs`);
|
|
321
|
+
|
|
322
|
+
debugLogStore = new InMemoryDebugLogStore();
|
|
323
|
+
log.info(
|
|
324
|
+
'Aztec node started in test mode (realProofs set to false) hence debug logs from public functions will be collected and served',
|
|
325
|
+
);
|
|
326
|
+
} else {
|
|
327
|
+
debugLogStore = new NullDebugLogStore();
|
|
301
328
|
}
|
|
329
|
+
|
|
302
330
|
const proofVerifier = new QueuedIVCVerifier(config, circuitVerifier);
|
|
303
331
|
|
|
332
|
+
const proverOnly = config.enableProverNode && config.disableValidator;
|
|
333
|
+
if (proverOnly) {
|
|
334
|
+
log.info('Starting in prover-only mode: skipping validator, sequencer, sentinel, and slasher subsystems');
|
|
335
|
+
}
|
|
336
|
+
|
|
304
337
|
// create the tx pool and the p2p client, which will need the l2 block source
|
|
305
338
|
const p2pClient = await createP2PClient(
|
|
306
|
-
P2PClientType.Full,
|
|
307
339
|
config,
|
|
308
340
|
archiver,
|
|
309
341
|
proofVerifier,
|
|
@@ -315,59 +347,72 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
315
347
|
deps.p2pClientDeps,
|
|
316
348
|
);
|
|
317
349
|
|
|
318
|
-
// We
|
|
319
|
-
|
|
350
|
+
// We'll accumulate sentinel watchers here
|
|
351
|
+
const watchers: Watcher[] = [];
|
|
320
352
|
|
|
321
|
-
// Create FullNodeCheckpointsBuilder for
|
|
353
|
+
// Create FullNodeCheckpointsBuilder for block proposal handling and tx validation.
|
|
354
|
+
// Override maxTxsPerCheckpoint with the validator-specific limit if set.
|
|
322
355
|
const validatorCheckpointsBuilder = new FullNodeCheckpointsBuilder(
|
|
323
|
-
{
|
|
356
|
+
{
|
|
357
|
+
...config,
|
|
358
|
+
l1GenesisTime,
|
|
359
|
+
slotDuration: Number(slotDuration),
|
|
360
|
+
rollupManaLimit,
|
|
361
|
+
maxTxsPerCheckpoint: config.validateMaxTxsPerCheckpoint,
|
|
362
|
+
},
|
|
324
363
|
worldStateSynchronizer,
|
|
325
364
|
archiver,
|
|
326
365
|
dateProvider,
|
|
327
366
|
telemetry,
|
|
328
367
|
);
|
|
329
368
|
|
|
330
|
-
|
|
331
|
-
const watchers: Watcher[] = [];
|
|
369
|
+
let validatorClient: ValidatorClient | undefined;
|
|
332
370
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
371
|
+
if (!proverOnly) {
|
|
372
|
+
// Create validator client if required
|
|
373
|
+
validatorClient = await createValidatorClient(config, {
|
|
374
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
375
|
+
worldState: worldStateSynchronizer,
|
|
376
|
+
p2pClient,
|
|
377
|
+
telemetry,
|
|
378
|
+
dateProvider,
|
|
379
|
+
epochCache,
|
|
380
|
+
blockSource: archiver,
|
|
381
|
+
l1ToL2MessageSource: archiver,
|
|
382
|
+
keyStoreManager,
|
|
383
|
+
blobClient,
|
|
384
|
+
slashingProtectionDb: deps.slashingProtectionDb,
|
|
385
|
+
});
|
|
346
386
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
387
|
+
// If we have a validator client, register it as a source of offenses for the slasher,
|
|
388
|
+
// and have it register callbacks on the p2p client *before* we start it, otherwise messages
|
|
389
|
+
// like attestations or auths will fail.
|
|
390
|
+
if (validatorClient) {
|
|
391
|
+
watchers.push(validatorClient);
|
|
392
|
+
if (!options.dontStartSequencer) {
|
|
393
|
+
await validatorClient.registerHandlers();
|
|
394
|
+
}
|
|
354
395
|
}
|
|
355
396
|
}
|
|
356
397
|
|
|
357
|
-
// If there's no validator client
|
|
358
|
-
//
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
398
|
+
// If there's no validator client, create a ProposalHandler to handle block and checkpoint proposals
|
|
399
|
+
// for monitoring or reexecution. Reexecution (default) allows us to follow the pending chain,
|
|
400
|
+
// while non-reexecution is used for validating the proposals and collecting their txs.
|
|
401
|
+
// Checkpoint proposals are handled if the blob client can upload blobs.
|
|
402
|
+
if (!validatorClient) {
|
|
403
|
+
const reexecute = !!config.alwaysReexecuteBlockProposals;
|
|
404
|
+
log.info(`Setting up proposal handler` + (reexecute ? ' with reexecution of proposals' : ''));
|
|
405
|
+
createProposalHandler(config, {
|
|
362
406
|
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
363
407
|
worldState: worldStateSynchronizer,
|
|
364
408
|
epochCache,
|
|
365
409
|
blockSource: archiver,
|
|
366
410
|
l1ToL2MessageSource: archiver,
|
|
367
411
|
p2pClient,
|
|
412
|
+
blobClient,
|
|
368
413
|
dateProvider,
|
|
369
414
|
telemetry,
|
|
370
|
-
}).
|
|
415
|
+
}).register(p2pClient, reexecute);
|
|
371
416
|
}
|
|
372
417
|
|
|
373
418
|
// Start world state and wait for it to sync to the archiver.
|
|
@@ -376,29 +421,33 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
376
421
|
// Start p2p. Note that it depends on world state to be running.
|
|
377
422
|
await p2pClient.start();
|
|
378
423
|
|
|
379
|
-
|
|
380
|
-
if (validatorsSentinel && config.slashInactivityPenalty > 0n) {
|
|
381
|
-
watchers.push(validatorsSentinel);
|
|
382
|
-
}
|
|
383
|
-
|
|
424
|
+
let validatorsSentinel: Awaited<ReturnType<typeof createSentinel>> | undefined;
|
|
384
425
|
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
426
|
let attestationsBlockWatcher: AttestationsBlockWatcher | undefined;
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
427
|
+
|
|
428
|
+
if (!proverOnly) {
|
|
429
|
+
validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
|
|
430
|
+
if (validatorsSentinel && config.slashInactivityPenalty > 0n) {
|
|
431
|
+
watchers.push(validatorsSentinel);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
|
|
435
|
+
epochPruneWatcher = new EpochPruneWatcher(
|
|
436
|
+
archiver,
|
|
437
|
+
archiver,
|
|
438
|
+
epochCache,
|
|
439
|
+
p2pClient.getTxProvider(),
|
|
440
|
+
validatorCheckpointsBuilder,
|
|
441
|
+
config,
|
|
442
|
+
);
|
|
443
|
+
watchers.push(epochPruneWatcher);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// We assume we want to slash for invalid attestations unless all max penalties are set to 0
|
|
447
|
+
if (config.slashProposeInvalidAttestationsPenalty > 0n || config.slashAttestDescendantOfInvalidPenalty > 0n) {
|
|
448
|
+
attestationsBlockWatcher = new AttestationsBlockWatcher(archiver, epochCache, config);
|
|
449
|
+
watchers.push(attestationsBlockWatcher);
|
|
450
|
+
}
|
|
402
451
|
}
|
|
403
452
|
|
|
404
453
|
// Start p2p-related services once the archiver has completed sync
|
|
@@ -413,6 +462,14 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
413
462
|
})
|
|
414
463
|
.catch(err => log.error('Failed to start p2p services after archiver sync', err));
|
|
415
464
|
|
|
465
|
+
const globalVariableBuilder = new GlobalVariableBuilder(dateProvider, publicClient, {
|
|
466
|
+
l1Contracts: config.l1Contracts,
|
|
467
|
+
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
468
|
+
rollupVersion: BigInt(config.rollupVersion),
|
|
469
|
+
l1GenesisTime,
|
|
470
|
+
slotDuration: Number(slotDuration),
|
|
471
|
+
});
|
|
472
|
+
|
|
416
473
|
// Validator enabled, create/start relevant service
|
|
417
474
|
let sequencer: SequencerClient | undefined;
|
|
418
475
|
let slasherClient: SlasherClientInterface | undefined;
|
|
@@ -452,11 +509,12 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
452
509
|
|
|
453
510
|
// Create and start the sequencer client
|
|
454
511
|
const checkpointsBuilder = new CheckpointsBuilder(
|
|
455
|
-
{ ...config, l1GenesisTime, slotDuration: Number(slotDuration) },
|
|
512
|
+
{ ...config, l1GenesisTime, slotDuration: Number(slotDuration), rollupManaLimit },
|
|
456
513
|
worldStateSynchronizer,
|
|
457
514
|
archiver,
|
|
458
515
|
dateProvider,
|
|
459
516
|
telemetry,
|
|
517
|
+
debugLogStore,
|
|
460
518
|
);
|
|
461
519
|
|
|
462
520
|
sequencer = await SequencerClient.new(config, {
|
|
@@ -474,6 +532,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
474
532
|
dateProvider,
|
|
475
533
|
blobClient,
|
|
476
534
|
nodeKeyStore: keyStoreManager!,
|
|
535
|
+
globalVariableBuilder,
|
|
477
536
|
});
|
|
478
537
|
}
|
|
479
538
|
|
|
@@ -507,13 +566,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
507
566
|
}
|
|
508
567
|
}
|
|
509
568
|
|
|
510
|
-
const globalVariableBuilder = new GlobalVariableBuilder({
|
|
511
|
-
...config,
|
|
512
|
-
rollupVersion: BigInt(config.rollupVersion),
|
|
513
|
-
l1GenesisTime,
|
|
514
|
-
slotDuration: Number(slotDuration),
|
|
515
|
-
});
|
|
516
|
-
|
|
517
569
|
const node = new AztecNodeService(
|
|
518
570
|
config,
|
|
519
571
|
p2pClient,
|
|
@@ -538,6 +590,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
538
590
|
blobClient,
|
|
539
591
|
validatorClient,
|
|
540
592
|
keyStoreManager,
|
|
593
|
+
debugLogStore,
|
|
541
594
|
);
|
|
542
595
|
|
|
543
596
|
return node;
|
|
@@ -581,7 +634,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
581
634
|
}
|
|
582
635
|
|
|
583
636
|
public async getAllowedPublicSetup(): Promise<AllowedElement[]> {
|
|
584
|
-
return this.config.
|
|
637
|
+
return [...(await getDefaultAllowedSetupFunctions()), ...(this.config.txPublicSetupAllowListExtend ?? [])];
|
|
585
638
|
}
|
|
586
639
|
|
|
587
640
|
/**
|
|
@@ -676,6 +729,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
676
729
|
return (await this.blockSource.getCheckpointedBlocks(from, limit)) ?? [];
|
|
677
730
|
}
|
|
678
731
|
|
|
732
|
+
public getCheckpointsDataForEpoch(epochNumber: EpochNumber) {
|
|
733
|
+
return this.blockSource.getCheckpointsDataForEpoch(epochNumber);
|
|
734
|
+
}
|
|
735
|
+
|
|
679
736
|
/**
|
|
680
737
|
* Method to fetch the current min L2 fees.
|
|
681
738
|
* @returns The current min L2 fees.
|
|
@@ -708,6 +765,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
708
765
|
return await this.blockSource.getCheckpointedL2BlockNumber();
|
|
709
766
|
}
|
|
710
767
|
|
|
768
|
+
public getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
769
|
+
return this.blockSource.getCheckpointNumber();
|
|
770
|
+
}
|
|
771
|
+
|
|
711
772
|
/**
|
|
712
773
|
* Method to fetch the version of the package.
|
|
713
774
|
* @returns The node package version
|
|
@@ -818,8 +879,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
818
879
|
}
|
|
819
880
|
|
|
820
881
|
await this.p2pClient!.sendTx(tx);
|
|
821
|
-
|
|
822
|
-
this.
|
|
882
|
+
const duration = timer.ms();
|
|
883
|
+
this.metrics.receivedTx(duration, true);
|
|
884
|
+
this.log.info(`Received tx ${txHash} in ${duration}ms`, { txHash });
|
|
823
885
|
}
|
|
824
886
|
|
|
825
887
|
public async getTxReceipt(txHash: TxHash): Promise<TxReceipt> {
|
|
@@ -831,18 +893,22 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
831
893
|
// Then get the actual tx from the archiver, which tracks every tx in a mined block.
|
|
832
894
|
const settledTxReceipt = await this.blockSource.getSettledTxReceipt(txHash);
|
|
833
895
|
|
|
896
|
+
let receipt: TxReceipt;
|
|
834
897
|
if (settledTxReceipt) {
|
|
835
|
-
|
|
836
|
-
return settledTxReceipt;
|
|
898
|
+
receipt = settledTxReceipt;
|
|
837
899
|
} else if (isKnownToPool) {
|
|
838
900
|
// If the tx is in the pool but not in the archiver, it's pending.
|
|
839
901
|
// This handles race conditions between archiver and p2p, where the archiver
|
|
840
902
|
// has pruned the block in which a tx was mined, but p2p has not caught up yet.
|
|
841
|
-
|
|
903
|
+
receipt = new TxReceipt(txHash, TxStatus.PENDING, undefined, undefined);
|
|
842
904
|
} else {
|
|
843
905
|
// Otherwise, if we don't know the tx, we consider it dropped.
|
|
844
|
-
|
|
906
|
+
receipt = new TxReceipt(txHash, TxStatus.DROPPED, undefined, 'Tx dropped by P2P node');
|
|
845
907
|
}
|
|
908
|
+
|
|
909
|
+
this.debugLogStore.decorateReceiptWithLogs(txHash.toString(), receipt);
|
|
910
|
+
|
|
911
|
+
return receipt;
|
|
846
912
|
}
|
|
847
913
|
|
|
848
914
|
public getTxEffect(txHash: TxHash): Promise<IndexedTxEffect | undefined> {
|
|
@@ -913,58 +979,64 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
913
979
|
treeId: MerkleTreeId,
|
|
914
980
|
leafValues: Fr[],
|
|
915
981
|
): Promise<(DataInBlock<bigint> | undefined)[]> {
|
|
916
|
-
const committedDb = await this
|
|
982
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
917
983
|
const maybeIndices = await committedDb.findLeafIndices(
|
|
918
984
|
treeId,
|
|
919
985
|
leafValues.map(x => x.toBuffer()),
|
|
920
986
|
);
|
|
921
|
-
//
|
|
922
|
-
const
|
|
987
|
+
// Filter out undefined values to query block numbers only for found leaves
|
|
988
|
+
const definedIndices = maybeIndices.filter(x => x !== undefined);
|
|
923
989
|
|
|
924
|
-
// Now we find the block numbers for the indices
|
|
925
|
-
const blockNumbers = await committedDb.getBlockNumbersForLeafIndices(treeId,
|
|
990
|
+
// Now we find the block numbers for the defined indices
|
|
991
|
+
const blockNumbers = await committedDb.getBlockNumbersForLeafIndices(treeId, definedIndices);
|
|
926
992
|
|
|
927
|
-
//
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
993
|
+
// Build a map from leaf index to block number
|
|
994
|
+
const indexToBlockNumber = new Map<bigint, BlockNumber>();
|
|
995
|
+
for (let i = 0; i < definedIndices.length; i++) {
|
|
996
|
+
const blockNumber = blockNumbers[i];
|
|
997
|
+
if (blockNumber === undefined) {
|
|
998
|
+
throw new Error(
|
|
999
|
+
`Block number is undefined for leaf index ${definedIndices[i]} in tree ${MerkleTreeId[treeId]}`,
|
|
1000
|
+
);
|
|
931
1001
|
}
|
|
1002
|
+
indexToBlockNumber.set(definedIndices[i], blockNumber);
|
|
932
1003
|
}
|
|
933
1004
|
|
|
934
1005
|
// Get unique block numbers in order to optimize num calls to getLeafValue function.
|
|
935
|
-
const uniqueBlockNumbers = [...new Set(
|
|
1006
|
+
const uniqueBlockNumbers = [...new Set(indexToBlockNumber.values())];
|
|
936
1007
|
|
|
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).
|
|
1008
|
+
// Now we obtain the block hashes from the archive tree (block number = leaf index in archive tree).
|
|
939
1009
|
const blockHashes = await Promise.all(
|
|
940
1010
|
uniqueBlockNumbers.map(blockNumber => {
|
|
941
1011
|
return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber));
|
|
942
1012
|
}),
|
|
943
1013
|
);
|
|
944
1014
|
|
|
945
|
-
//
|
|
1015
|
+
// Build a map from block number to block hash
|
|
1016
|
+
const blockNumberToHash = new Map<BlockNumber, Fr>();
|
|
946
1017
|
for (let i = 0; i < uniqueBlockNumbers.length; i++) {
|
|
947
|
-
|
|
1018
|
+
const blockHash = blockHashes[i];
|
|
1019
|
+
if (blockHash === undefined) {
|
|
948
1020
|
throw new Error(`Block hash is undefined for block number ${uniqueBlockNumbers[i]}`);
|
|
949
1021
|
}
|
|
1022
|
+
blockNumberToHash.set(uniqueBlockNumbers[i], blockHash);
|
|
950
1023
|
}
|
|
951
1024
|
|
|
952
1025
|
// Create DataInBlock objects by combining indices, blockNumbers and blockHashes and return them.
|
|
953
|
-
return maybeIndices.map(
|
|
1026
|
+
return maybeIndices.map(index => {
|
|
954
1027
|
if (index === undefined) {
|
|
955
1028
|
return undefined;
|
|
956
1029
|
}
|
|
957
|
-
const blockNumber =
|
|
1030
|
+
const blockNumber = indexToBlockNumber.get(index);
|
|
958
1031
|
if (blockNumber === undefined) {
|
|
959
|
-
|
|
1032
|
+
throw new Error(`Block number not found for leaf index ${index} in tree ${MerkleTreeId[treeId]}`);
|
|
960
1033
|
}
|
|
961
|
-
const
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
return undefined;
|
|
1034
|
+
const blockHash = blockNumberToHash.get(blockNumber);
|
|
1035
|
+
if (blockHash === undefined) {
|
|
1036
|
+
throw new Error(`Block hash not found for block number ${blockNumber}`);
|
|
965
1037
|
}
|
|
966
1038
|
return {
|
|
967
|
-
l2BlockNumber:
|
|
1039
|
+
l2BlockNumber: blockNumber,
|
|
968
1040
|
l2BlockHash: new BlockHash(blockHash),
|
|
969
1041
|
data: index,
|
|
970
1042
|
};
|
|
@@ -975,7 +1047,21 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
975
1047
|
referenceBlock: BlockParameter,
|
|
976
1048
|
blockHash: BlockHash,
|
|
977
1049
|
): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
|
|
978
|
-
|
|
1050
|
+
// Block 0 (the initial block) has an empty archive, so no membership witness can exist.
|
|
1051
|
+
if (referenceBlock === BlockNumber.ZERO) {
|
|
1052
|
+
return undefined;
|
|
1053
|
+
}
|
|
1054
|
+
if (BlockHash.isBlockHash(referenceBlock)) {
|
|
1055
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1056
|
+
if (referenceBlock.equals(initialBlockHash)) {
|
|
1057
|
+
return undefined;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
// The Noir circuit checks the archive membership proof against `anchor_block_header.last_archive.root`,
|
|
1061
|
+
// which is the archive tree root BEFORE the anchor block was added (i.e. the state after block N-1).
|
|
1062
|
+
// So we need the world state at block N-1, not block N, to produce a sibling path matching that root.
|
|
1063
|
+
const referenceBlockNumber = await this.resolveBlockNumber(referenceBlock);
|
|
1064
|
+
const committedDb = await this.getWorldState(BlockNumber(referenceBlockNumber - 1));
|
|
979
1065
|
const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.ARCHIVE>(MerkleTreeId.ARCHIVE, [blockHash]);
|
|
980
1066
|
return pathAndIndex === undefined
|
|
981
1067
|
? undefined
|
|
@@ -986,7 +1072,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
986
1072
|
referenceBlock: BlockParameter,
|
|
987
1073
|
noteHash: Fr,
|
|
988
1074
|
): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
|
|
989
|
-
const committedDb = await this
|
|
1075
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
990
1076
|
const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.NOTE_HASH_TREE>(
|
|
991
1077
|
MerkleTreeId.NOTE_HASH_TREE,
|
|
992
1078
|
[noteHash],
|
|
@@ -1000,7 +1086,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1000
1086
|
referenceBlock: BlockParameter,
|
|
1001
1087
|
l1ToL2Message: Fr,
|
|
1002
1088
|
): Promise<[bigint, SiblingPath<typeof L1_TO_L2_MSG_TREE_HEIGHT>] | undefined> {
|
|
1003
|
-
const db = await this
|
|
1089
|
+
const db = await this.getWorldState(referenceBlock);
|
|
1004
1090
|
const [witness] = await db.findSiblingPaths(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, [l1ToL2Message]);
|
|
1005
1091
|
if (!witness) {
|
|
1006
1092
|
return undefined;
|
|
@@ -1010,11 +1096,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1010
1096
|
return [witness.index, witness.path];
|
|
1011
1097
|
}
|
|
1012
1098
|
|
|
1013
|
-
public async
|
|
1099
|
+
public async getL1ToL2MessageCheckpoint(l1ToL2Message: Fr): Promise<CheckpointNumber | undefined> {
|
|
1014
1100
|
const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
|
|
1015
|
-
return messageIndex
|
|
1016
|
-
? BlockNumber.fromCheckpointNumber(InboxLeaf.checkpointNumberFromIndex(messageIndex))
|
|
1017
|
-
: undefined;
|
|
1101
|
+
return messageIndex ? InboxLeaf.checkpointNumberFromIndex(messageIndex) : undefined;
|
|
1018
1102
|
}
|
|
1019
1103
|
|
|
1020
1104
|
/**
|
|
@@ -1035,19 +1119,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1035
1119
|
public async getL2ToL1Messages(epoch: EpochNumber): Promise<Fr[][][][]> {
|
|
1036
1120
|
// Assumes `getCheckpointedBlocksForEpoch` returns blocks in ascending order of block number.
|
|
1037
1121
|
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
|
-
}
|
|
1122
|
+
const blocksInCheckpoints = chunkBy(checkpointedBlocks, cb => cb.block.header.globalVariables.slotNumber).map(
|
|
1123
|
+
group => group.map(cb => cb.block),
|
|
1124
|
+
);
|
|
1051
1125
|
return blocksInCheckpoints.map(blocks =>
|
|
1052
1126
|
blocks.map(block => block.body.txEffects.map(txEffect => txEffect.l2ToL1Msgs)),
|
|
1053
1127
|
);
|
|
@@ -1057,7 +1131,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1057
1131
|
referenceBlock: BlockParameter,
|
|
1058
1132
|
nullifier: Fr,
|
|
1059
1133
|
): Promise<NullifierMembershipWitness | undefined> {
|
|
1060
|
-
const db = await this
|
|
1134
|
+
const db = await this.getWorldState(referenceBlock);
|
|
1061
1135
|
const [witness] = await db.findSiblingPaths(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]);
|
|
1062
1136
|
if (!witness) {
|
|
1063
1137
|
return undefined;
|
|
@@ -1072,33 +1146,20 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1072
1146
|
return new NullifierMembershipWitness(index, leafPreimage as NullifierLeafPreimage, path);
|
|
1073
1147
|
}
|
|
1074
1148
|
|
|
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
1149
|
public async getLowNullifierMembershipWitness(
|
|
1091
1150
|
referenceBlock: BlockParameter,
|
|
1092
1151
|
nullifier: Fr,
|
|
1093
1152
|
): Promise<NullifierMembershipWitness | undefined> {
|
|
1094
|
-
const committedDb = await this
|
|
1153
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
1095
1154
|
const findResult = await committedDb.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
|
|
1096
1155
|
if (!findResult) {
|
|
1097
1156
|
return undefined;
|
|
1098
1157
|
}
|
|
1099
1158
|
const { index, alreadyPresent } = findResult;
|
|
1100
1159
|
if (alreadyPresent) {
|
|
1101
|
-
|
|
1160
|
+
throw new Error(
|
|
1161
|
+
`Cannot prove nullifier non-inclusion: nullifier ${nullifier.toBigInt()} already exists in the tree`,
|
|
1162
|
+
);
|
|
1102
1163
|
}
|
|
1103
1164
|
const preimageData = (await committedDb.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index))!;
|
|
1104
1165
|
|
|
@@ -1107,7 +1168,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1107
1168
|
}
|
|
1108
1169
|
|
|
1109
1170
|
async getPublicDataWitness(referenceBlock: BlockParameter, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
|
|
1110
|
-
const committedDb = await this
|
|
1171
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
1111
1172
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
1112
1173
|
if (!lowLeafResult) {
|
|
1113
1174
|
return undefined;
|
|
@@ -1122,7 +1183,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1122
1183
|
}
|
|
1123
1184
|
|
|
1124
1185
|
public async getPublicStorageAt(referenceBlock: BlockParameter, contract: AztecAddress, slot: Fr): Promise<Fr> {
|
|
1125
|
-
const committedDb = await this
|
|
1186
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
1126
1187
|
const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
|
|
1127
1188
|
|
|
1128
1189
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
@@ -1236,7 +1297,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1236
1297
|
const processor = publicProcessorFactory.create(merkleTreeFork, newGlobalVariables, config);
|
|
1237
1298
|
|
|
1238
1299
|
// REFACTOR: Consider merging ProcessReturnValues into ProcessedTx
|
|
1239
|
-
const [processedTxs, failedTxs, _usedTxs, returns,
|
|
1300
|
+
const [processedTxs, failedTxs, _usedTxs, returns, debugLogs] = await processor.process([tx]);
|
|
1240
1301
|
// REFACTOR: Consider returning the error rather than throwing
|
|
1241
1302
|
if (failedTxs.length) {
|
|
1242
1303
|
this.log.warn(`Simulated tx ${txHash} fails: ${failedTxs[0].error}`, { txHash });
|
|
@@ -1267,7 +1328,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1267
1328
|
// We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
|
|
1268
1329
|
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1269
1330
|
const blockNumber = BlockNumber((await this.blockSource.getBlockNumber()) + 1);
|
|
1270
|
-
const
|
|
1331
|
+
const l1Constants = await this.blockSource.getL1Constants();
|
|
1332
|
+
const validator = createTxValidatorForAcceptingTxsOverRPC(
|
|
1271
1333
|
db,
|
|
1272
1334
|
this.contractDataSource,
|
|
1273
1335
|
verifier,
|
|
@@ -1276,10 +1338,16 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1276
1338
|
blockNumber,
|
|
1277
1339
|
l1ChainId: this.l1ChainId,
|
|
1278
1340
|
rollupVersion: this.version,
|
|
1279
|
-
setupAllowList:
|
|
1341
|
+
setupAllowList: [
|
|
1342
|
+
...(await getDefaultAllowedSetupFunctions()),
|
|
1343
|
+
...(this.config.txPublicSetupAllowListExtend ?? []),
|
|
1344
|
+
],
|
|
1280
1345
|
gasFees: await this.getCurrentMinFees(),
|
|
1281
1346
|
skipFeeEnforcement,
|
|
1282
1347
|
txsPermitted: !this.config.disableTransactions,
|
|
1348
|
+
rollupManaLimit: l1Constants.rollupManaLimit,
|
|
1349
|
+
maxBlockL2Gas: this.config.validateMaxL2BlockGas,
|
|
1350
|
+
maxBlockDAGas: this.config.validateMaxDABlockGas,
|
|
1283
1351
|
},
|
|
1284
1352
|
this.log.getBindings(),
|
|
1285
1353
|
);
|
|
@@ -1534,6 +1602,40 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1534
1602
|
this.log.info('Keystore reloaded: coinbase, feeRecipient, and attester keys updated');
|
|
1535
1603
|
}
|
|
1536
1604
|
|
|
1605
|
+
public async mineBlock(): Promise<void> {
|
|
1606
|
+
if (!this.sequencer) {
|
|
1607
|
+
throw new BadRequestError('Cannot mine block: no sequencer is running');
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
const currentBlockNumber = await this.getBlockNumber();
|
|
1611
|
+
|
|
1612
|
+
// Use slot duration + 50% buffer as the timeout so this works on running networks too
|
|
1613
|
+
const { slotDuration } = await this.blockSource.getL1Constants();
|
|
1614
|
+
const timeoutSeconds = Math.ceil(slotDuration * 1.5);
|
|
1615
|
+
|
|
1616
|
+
// Temporarily set minTxsPerBlock to 0 so the sequencer produces a block even with no txs
|
|
1617
|
+
const originalMinTxsPerBlock = this.sequencer.getSequencer().getConfig().minTxsPerBlock;
|
|
1618
|
+
this.sequencer.updateConfig({ minTxsPerBlock: 0 });
|
|
1619
|
+
|
|
1620
|
+
try {
|
|
1621
|
+
// Trigger the sequencer to produce a block immediately
|
|
1622
|
+
void this.sequencer.trigger();
|
|
1623
|
+
|
|
1624
|
+
// Wait for the new L2 block to appear
|
|
1625
|
+
await retryUntil(
|
|
1626
|
+
async () => {
|
|
1627
|
+
const newBlockNumber = await this.getBlockNumber();
|
|
1628
|
+
return newBlockNumber > currentBlockNumber ? true : undefined;
|
|
1629
|
+
},
|
|
1630
|
+
'mineBlock',
|
|
1631
|
+
timeoutSeconds,
|
|
1632
|
+
0.1,
|
|
1633
|
+
);
|
|
1634
|
+
} finally {
|
|
1635
|
+
this.sequencer.updateConfig({ minTxsPerBlock: originalMinTxsPerBlock });
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1537
1639
|
#getInitialHeaderHash(): Promise<BlockHash> {
|
|
1538
1640
|
if (!this.initialHeaderHashPromise) {
|
|
1539
1641
|
this.initialHeaderHashPromise = this.worldStateSynchronizer.getCommitted().getInitialHeader().hash();
|
|
@@ -1546,7 +1648,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1546
1648
|
* @param block - The block parameter (block number, block hash, or 'latest') at which to get the data.
|
|
1547
1649
|
* @returns An instance of a committed MerkleTreeOperations
|
|
1548
1650
|
*/
|
|
1549
|
-
async
|
|
1651
|
+
protected async getWorldState(block: BlockParameter) {
|
|
1550
1652
|
let blockSyncedTo: BlockNumber = BlockNumber.ZERO;
|
|
1551
1653
|
try {
|
|
1552
1654
|
// Attempt to sync the world state if necessary
|
|
@@ -1560,6 +1662,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1560
1662
|
return this.worldStateSynchronizer.getCommitted();
|
|
1561
1663
|
}
|
|
1562
1664
|
|
|
1665
|
+
// Get the block number, either directly from the parameter or by quering the archiver with the block hash
|
|
1666
|
+
let blockNumber: BlockNumber;
|
|
1563
1667
|
if (BlockHash.isBlockHash(block)) {
|
|
1564
1668
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1565
1669
|
if (block.equals(initialBlockHash)) {
|
|
@@ -1573,22 +1677,50 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1573
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.`,
|
|
1574
1678
|
);
|
|
1575
1679
|
}
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1680
|
+
|
|
1681
|
+
blockNumber = header.getBlockNumber();
|
|
1682
|
+
} else {
|
|
1683
|
+
blockNumber = block as BlockNumber;
|
|
1579
1684
|
}
|
|
1580
1685
|
|
|
1581
|
-
//
|
|
1582
|
-
{
|
|
1583
|
-
|
|
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);
|
|
1584
1693
|
|
|
1585
|
-
|
|
1586
|
-
|
|
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
|
+
);
|
|
1587
1701
|
}
|
|
1702
|
+
}
|
|
1588
1703
|
|
|
1589
|
-
|
|
1590
|
-
|
|
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();
|
|
1591
1722
|
}
|
|
1723
|
+
return block as BlockNumber;
|
|
1592
1724
|
}
|
|
1593
1725
|
|
|
1594
1726
|
/**
|