@aztec/aztec-node 0.0.1-commit.5914bae → 0.0.1-commit.59a0419c6
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 +15 -14
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +312 -239
- package/dest/sentinel/factory.d.ts +2 -2
- package/dest/sentinel/factory.d.ts.map +1 -1
- package/dest/sentinel/sentinel.js +6 -6
- package/package.json +26 -27
- package/src/aztec-node/config.ts +1 -1
- package/src/aztec-node/server.ts +384 -317
- package/src/sentinel/factory.ts +1 -1
- package/src/sentinel/sentinel.ts +6 -6
package/src/aztec-node/server.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
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';
|
|
@@ -8,6 +9,7 @@ import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
|
8
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
14
|
import { chunkBy, compactArray, pick, unique } from '@aztec/foundation/collection';
|
|
13
15
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
@@ -31,7 +33,12 @@ import {
|
|
|
31
33
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
32
34
|
import { type ProverNode, type ProverNodeDeps, createProverNode } from '@aztec/prover-node';
|
|
33
35
|
import { createKeyStoreForProver } from '@aztec/prover-node/config';
|
|
34
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
FeeProviderImpl,
|
|
38
|
+
GlobalVariableBuilder,
|
|
39
|
+
SequencerClient,
|
|
40
|
+
type SequencerPublisher,
|
|
41
|
+
} from '@aztec/sequencer-client';
|
|
35
42
|
import { PublicProcessorFactory } from '@aztec/simulator/server';
|
|
36
43
|
import {
|
|
37
44
|
AttestationsBlockWatcher,
|
|
@@ -58,7 +65,7 @@ import type {
|
|
|
58
65
|
NodeInfo,
|
|
59
66
|
ProtocolContractAddresses,
|
|
60
67
|
} from '@aztec/stdlib/contract';
|
|
61
|
-
import { GasFees } from '@aztec/stdlib/gas';
|
|
68
|
+
import { GasFees, type ManaUsageEstimate } from '@aztec/stdlib/gas';
|
|
62
69
|
import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
|
|
63
70
|
import {
|
|
64
71
|
type AztecNode,
|
|
@@ -81,11 +88,12 @@ import {
|
|
|
81
88
|
import type { DebugLogStore, LogFilter, SiloedTag, Tag, TxScopedL2Log } from '@aztec/stdlib/logs';
|
|
82
89
|
import { InMemoryDebugLogStore, NullDebugLogStore } from '@aztec/stdlib/logs';
|
|
83
90
|
import { InboxLeaf, type L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
84
|
-
import type { Offense
|
|
85
|
-
import type { NullifierLeafPreimage,
|
|
91
|
+
import type { Offense } from '@aztec/stdlib/slashing';
|
|
92
|
+
import type { NullifierLeafPreimage, PublicDataTreeLeafPreimage } from '@aztec/stdlib/trees';
|
|
86
93
|
import { MerkleTreeId, NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
|
|
87
94
|
import {
|
|
88
95
|
type BlockHeader,
|
|
96
|
+
type FeeProvider,
|
|
89
97
|
type GlobalVariableBuilder as GlobalVariableBuilderInterface,
|
|
90
98
|
type IndexedTxEffect,
|
|
91
99
|
PublicSimulationOutput,
|
|
@@ -97,6 +105,7 @@ import {
|
|
|
97
105
|
} from '@aztec/stdlib/tx';
|
|
98
106
|
import { getPackageVersion } from '@aztec/stdlib/update-checker';
|
|
99
107
|
import type { SingleValidatorStats, ValidatorsStats } from '@aztec/stdlib/validators';
|
|
108
|
+
import type { GenesisData } from '@aztec/stdlib/world-state';
|
|
100
109
|
import {
|
|
101
110
|
Attributes,
|
|
102
111
|
type TelemetryClient,
|
|
@@ -151,9 +160,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
151
160
|
protected readonly l1ChainId: number,
|
|
152
161
|
protected readonly version: number,
|
|
153
162
|
protected readonly globalVariableBuilder: GlobalVariableBuilderInterface,
|
|
163
|
+
protected readonly feeProvider: FeeProvider,
|
|
154
164
|
protected readonly epochCache: EpochCacheInterface,
|
|
155
165
|
protected readonly packageVersion: string,
|
|
156
|
-
private
|
|
166
|
+
private peerProofVerifier: ClientProtocolCircuitVerifier,
|
|
167
|
+
private rpcProofVerifier: ClientProtocolCircuitVerifier,
|
|
157
168
|
private telemetry: TelemetryClient = getTelemetryClient(),
|
|
158
169
|
private log = createLogger('node'),
|
|
159
170
|
private blobClient?: BlobClientInterface,
|
|
@@ -175,6 +186,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
175
186
|
}
|
|
176
187
|
}
|
|
177
188
|
|
|
189
|
+
/** @internal Exposed for testing — returns the RPC proof verifier. */
|
|
190
|
+
public getProofVerifier(): ClientProtocolCircuitVerifier {
|
|
191
|
+
return this.rpcProofVerifier;
|
|
192
|
+
}
|
|
193
|
+
|
|
178
194
|
public async getWorldStateSyncStatus(): Promise<WorldStateSyncStatus> {
|
|
179
195
|
const status = await this.worldStateSynchronizer.status();
|
|
180
196
|
return status.syncSummary;
|
|
@@ -201,7 +217,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
201
217
|
slashingProtectionDb?: SlashingProtectionDatabase;
|
|
202
218
|
} = {},
|
|
203
219
|
options: {
|
|
204
|
-
|
|
220
|
+
genesis?: GenesisData;
|
|
205
221
|
dontStartSequencer?: boolean;
|
|
206
222
|
dontStartProverNode?: boolean;
|
|
207
223
|
} = {},
|
|
@@ -297,303 +313,344 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
297
313
|
|
|
298
314
|
const epochCache = await EpochCache.create(config.l1Contracts.rollupAddress, config, { dateProvider });
|
|
299
315
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
const worldStateSynchronizer = await createWorldStateSynchronizer(
|
|
308
|
-
config,
|
|
309
|
-
archiver,
|
|
310
|
-
options.prefilledPublicData,
|
|
311
|
-
telemetry,
|
|
312
|
-
);
|
|
313
|
-
const circuitVerifier =
|
|
314
|
-
config.realProofs || config.debugForceTxProofVerification
|
|
315
|
-
? await BBCircuitVerifier.new(config)
|
|
316
|
-
: new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
317
|
-
|
|
318
|
-
let debugLogStore: DebugLogStore;
|
|
319
|
-
if (!config.realProofs) {
|
|
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',
|
|
316
|
+
// Track started resources so we can clean up on partial failure during node creation.
|
|
317
|
+
const started: { stop?(): Promise<void> | void }[] = [];
|
|
318
|
+
try {
|
|
319
|
+
const archiver = await createArchiver(
|
|
320
|
+
config,
|
|
321
|
+
{ blobClient, epochCache, telemetry, dateProvider },
|
|
322
|
+
{ blockUntilSync: !config.skipArchiverInitialSync },
|
|
325
323
|
);
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
324
|
+
started.push(archiver);
|
|
325
|
+
|
|
326
|
+
// now create the merkle trees and the world state synchronizer
|
|
327
|
+
const worldStateSynchronizer = await createWorldStateSynchronizer(config, archiver, options.genesis, telemetry);
|
|
328
|
+
started.push(worldStateSynchronizer);
|
|
329
|
+
const useRealVerifiers = config.realProofs || config.debugForceTxProofVerification;
|
|
330
|
+
let peerProofVerifier: ClientProtocolCircuitVerifier;
|
|
331
|
+
let rpcProofVerifier: ClientProtocolCircuitVerifier;
|
|
332
|
+
if (useRealVerifiers) {
|
|
333
|
+
peerProofVerifier = await BatchChonkVerifier.new(config, config.bbChonkVerifyMaxBatch, 'peer');
|
|
334
|
+
const rpcVerifier = await BBCircuitVerifier.new(config);
|
|
335
|
+
rpcProofVerifier = new QueuedIVCVerifier(rpcVerifier, config.numConcurrentIVCVerifiers);
|
|
336
|
+
} else {
|
|
337
|
+
peerProofVerifier = new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
338
|
+
rpcProofVerifier = new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
339
|
+
}
|
|
340
|
+
started.push(peerProofVerifier, rpcProofVerifier);
|
|
336
341
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
archiver,
|
|
341
|
-
proofVerifier,
|
|
342
|
-
worldStateSynchronizer,
|
|
343
|
-
epochCache,
|
|
344
|
-
packageVersion,
|
|
345
|
-
dateProvider,
|
|
346
|
-
telemetry,
|
|
347
|
-
deps.p2pClientDeps,
|
|
348
|
-
);
|
|
342
|
+
let debugLogStore: DebugLogStore;
|
|
343
|
+
if (!config.realProofs) {
|
|
344
|
+
log.warn(`Aztec node is accepting fake proofs`);
|
|
349
345
|
|
|
350
|
-
|
|
351
|
-
|
|
346
|
+
debugLogStore = new InMemoryDebugLogStore();
|
|
347
|
+
log.info(
|
|
348
|
+
'Aztec node started in test mode (realProofs set to false) hence debug logs from public functions will be collected and served',
|
|
349
|
+
);
|
|
350
|
+
} else {
|
|
351
|
+
debugLogStore = new NullDebugLogStore();
|
|
352
|
+
}
|
|
352
353
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
...config,
|
|
354
|
+
const globalVariableBuilderConfig = {
|
|
355
|
+
l1Contracts: config.l1Contracts,
|
|
356
|
+
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
357
|
+
rollupVersion: BigInt(config.rollupVersion),
|
|
358
358
|
l1GenesisTime,
|
|
359
359
|
slotDuration: Number(slotDuration),
|
|
360
|
-
|
|
361
|
-
maxTxsPerCheckpoint: config.validateMaxTxsPerCheckpoint,
|
|
362
|
-
},
|
|
363
|
-
worldStateSynchronizer,
|
|
364
|
-
archiver,
|
|
365
|
-
dateProvider,
|
|
366
|
-
telemetry,
|
|
367
|
-
);
|
|
360
|
+
};
|
|
368
361
|
|
|
369
|
-
|
|
362
|
+
const globalVariableBuilder = new GlobalVariableBuilder(dateProvider, publicClient, globalVariableBuilderConfig);
|
|
363
|
+
const feeProvider = new FeeProviderImpl(dateProvider, publicClient, globalVariableBuilderConfig);
|
|
370
364
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
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
|
-
});
|
|
386
|
-
|
|
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
|
-
}
|
|
365
|
+
const proverOnly = config.enableProverNode && config.disableValidator;
|
|
366
|
+
if (proverOnly) {
|
|
367
|
+
log.info('Starting in prover-only mode: skipping validator, sequencer, sentinel, and slasher subsystems');
|
|
395
368
|
}
|
|
396
|
-
}
|
|
397
369
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
log.info(`Setting up proposal handler` + (reexecute ? ' with reexecution of proposals' : ''));
|
|
405
|
-
createProposalHandler(config, {
|
|
406
|
-
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
407
|
-
worldState: worldStateSynchronizer,
|
|
370
|
+
// create the tx pool and the p2p client, which will need the l2 block source
|
|
371
|
+
const p2pClient = await createP2PClient(
|
|
372
|
+
config,
|
|
373
|
+
archiver,
|
|
374
|
+
peerProofVerifier,
|
|
375
|
+
worldStateSynchronizer,
|
|
408
376
|
epochCache,
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
p2pClient,
|
|
412
|
-
blobClient,
|
|
377
|
+
feeProvider,
|
|
378
|
+
packageVersion,
|
|
413
379
|
dateProvider,
|
|
414
380
|
telemetry,
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
381
|
+
deps.p2pClientDeps,
|
|
382
|
+
);
|
|
383
|
+
started.push(p2pClient);
|
|
384
|
+
|
|
385
|
+
// We'll accumulate sentinel watchers here
|
|
386
|
+
const watchers: Watcher[] = [];
|
|
387
|
+
|
|
388
|
+
// Create FullNodeCheckpointsBuilder for block proposal handling and tx validation.
|
|
389
|
+
// Override maxTxsPerCheckpoint with the validator-specific limit if set.
|
|
390
|
+
const validatorCheckpointsBuilder = new FullNodeCheckpointsBuilder(
|
|
391
|
+
{
|
|
392
|
+
...config,
|
|
393
|
+
l1GenesisTime,
|
|
394
|
+
slotDuration: Number(slotDuration),
|
|
395
|
+
rollupManaLimit,
|
|
396
|
+
maxTxsPerCheckpoint: config.validateMaxTxsPerCheckpoint,
|
|
397
|
+
},
|
|
398
|
+
worldStateSynchronizer,
|
|
399
|
+
archiver,
|
|
400
|
+
dateProvider,
|
|
401
|
+
telemetry,
|
|
402
|
+
);
|
|
423
403
|
|
|
424
|
-
|
|
425
|
-
let epochPruneWatcher: EpochPruneWatcher | undefined;
|
|
426
|
-
let attestationsBlockWatcher: AttestationsBlockWatcher | undefined;
|
|
404
|
+
let validatorClient: ValidatorClient | undefined;
|
|
427
405
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
406
|
+
if (!proverOnly) {
|
|
407
|
+
// Create validator client if required
|
|
408
|
+
validatorClient = await createValidatorClient(config, {
|
|
409
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
410
|
+
worldState: worldStateSynchronizer,
|
|
411
|
+
p2pClient,
|
|
412
|
+
telemetry,
|
|
413
|
+
dateProvider,
|
|
414
|
+
epochCache,
|
|
415
|
+
blockSource: archiver,
|
|
416
|
+
l1ToL2MessageSource: archiver,
|
|
417
|
+
keyStoreManager,
|
|
418
|
+
blobClient,
|
|
419
|
+
slashingProtectionDb: deps.slashingProtectionDb,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// If we have a validator client, register it as a source of offenses for the slasher,
|
|
423
|
+
// and have it register callbacks on the p2p client *before* we start it, otherwise messages
|
|
424
|
+
// like attestations or auths will fail.
|
|
425
|
+
if (validatorClient) {
|
|
426
|
+
watchers.push(validatorClient);
|
|
427
|
+
|
|
428
|
+
const vc = validatorClient;
|
|
429
|
+
const getValidatorAddresses = () => vc.getValidatorAddresses().map(a => a.toString());
|
|
430
|
+
validatorClient.getProposalHandler().register(p2pClient, true, archiver, getValidatorAddresses);
|
|
431
|
+
|
|
432
|
+
if (!options.dontStartSequencer) {
|
|
433
|
+
await validatorClient.registerHandlers();
|
|
434
|
+
}
|
|
435
|
+
}
|
|
432
436
|
}
|
|
433
437
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
+
// If there's no validator client, create a ProposalHandler to handle block and checkpoint proposals
|
|
439
|
+
// for monitoring or reexecution. Reexecution (default) allows us to follow the pending chain,
|
|
440
|
+
// while non-reexecution is used for validating the proposals and collecting their txs.
|
|
441
|
+
// Checkpoint proposals rebuild blobs if the blob client can upload blobs.
|
|
442
|
+
if (!validatorClient) {
|
|
443
|
+
const reexecute = !!config.alwaysReexecuteBlockProposals;
|
|
444
|
+
log.info(`Setting up proposal handler` + (reexecute ? ' with reexecution of proposals' : ''));
|
|
445
|
+
createProposalHandler(config, {
|
|
446
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
447
|
+
worldState: worldStateSynchronizer,
|
|
438
448
|
epochCache,
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
449
|
+
blockSource: archiver,
|
|
450
|
+
l1ToL2MessageSource: archiver,
|
|
451
|
+
p2pClient,
|
|
452
|
+
blobClient,
|
|
453
|
+
dateProvider,
|
|
454
|
+
telemetry,
|
|
455
|
+
}).register(p2pClient, reexecute, archiver);
|
|
444
456
|
}
|
|
445
457
|
|
|
446
|
-
//
|
|
447
|
-
|
|
448
|
-
attestationsBlockWatcher = new AttestationsBlockWatcher(archiver, epochCache, config);
|
|
449
|
-
watchers.push(attestationsBlockWatcher);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
458
|
+
// Start world state and wait for it to sync to the archiver.
|
|
459
|
+
await worldStateSynchronizer.start();
|
|
452
460
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
.waitForInitialSync()
|
|
456
|
-
.then(async () => {
|
|
457
|
-
await p2pClient.start();
|
|
458
|
-
await validatorsSentinel?.start();
|
|
459
|
-
await epochPruneWatcher?.start();
|
|
460
|
-
await attestationsBlockWatcher?.start();
|
|
461
|
-
log.info(`All p2p services started`);
|
|
462
|
-
})
|
|
463
|
-
.catch(err => log.error('Failed to start p2p services after archiver sync', err));
|
|
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
|
-
});
|
|
461
|
+
// Start p2p. Note that it depends on world state to be running.
|
|
462
|
+
await p2pClient.start();
|
|
472
463
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
if (!config.disableValidator && validatorClient) {
|
|
477
|
-
// We create a slasher only if we have a sequencer, since all slashing actions go through the sequencer publisher
|
|
478
|
-
// as they are executed when the node is selected as proposer.
|
|
479
|
-
const validatorAddresses = keyStoreManager
|
|
480
|
-
? NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager).getAddresses()
|
|
481
|
-
: [];
|
|
482
|
-
|
|
483
|
-
slasherClient = await createSlasher(
|
|
484
|
-
config,
|
|
485
|
-
config.l1Contracts,
|
|
486
|
-
getPublicClient(config),
|
|
487
|
-
watchers,
|
|
488
|
-
dateProvider,
|
|
489
|
-
epochCache,
|
|
490
|
-
validatorAddresses,
|
|
491
|
-
undefined, // logger
|
|
492
|
-
);
|
|
493
|
-
await slasherClient.start();
|
|
464
|
+
let validatorsSentinel: Awaited<ReturnType<typeof createSentinel>> | undefined;
|
|
465
|
+
let epochPruneWatcher: EpochPruneWatcher | undefined;
|
|
466
|
+
let attestationsBlockWatcher: AttestationsBlockWatcher | undefined;
|
|
494
467
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
468
|
+
if (!proverOnly) {
|
|
469
|
+
validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
|
|
470
|
+
if (validatorsSentinel && config.slashInactivityPenalty > 0n) {
|
|
471
|
+
watchers.push(validatorsSentinel);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
|
|
475
|
+
epochPruneWatcher = new EpochPruneWatcher(
|
|
476
|
+
archiver,
|
|
477
|
+
archiver,
|
|
478
|
+
epochCache,
|
|
479
|
+
p2pClient.getTxProvider(),
|
|
480
|
+
validatorCheckpointsBuilder,
|
|
481
|
+
config,
|
|
482
|
+
);
|
|
483
|
+
watchers.push(epochPruneWatcher);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// We assume we want to slash for invalid attestations unless all max penalties are set to 0
|
|
487
|
+
if (config.slashProposeInvalidAttestationsPenalty > 0n || config.slashAttestDescendantOfInvalidPenalty > 0n) {
|
|
488
|
+
attestationsBlockWatcher = new AttestationsBlockWatcher(archiver, epochCache, config);
|
|
489
|
+
watchers.push(attestationsBlockWatcher);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Start p2p-related services once the archiver has completed sync
|
|
494
|
+
void archiver
|
|
495
|
+
.waitForInitialSync()
|
|
496
|
+
.then(async () => {
|
|
497
|
+
await validatorsSentinel?.start();
|
|
498
|
+
await epochPruneWatcher?.start();
|
|
499
|
+
await attestationsBlockWatcher?.start();
|
|
500
|
+
log.info(`All p2p services started`);
|
|
501
|
+
})
|
|
502
|
+
.catch(err => log.error('Failed to start p2p services after archiver sync', err));
|
|
503
|
+
|
|
504
|
+
// Validator enabled, create/start relevant service
|
|
505
|
+
let sequencer: SequencerClient | undefined;
|
|
506
|
+
let slasherClient: SlasherClientInterface | undefined;
|
|
507
|
+
if (!config.disableValidator && validatorClient) {
|
|
508
|
+
// We create a slasher only if we have a sequencer, since all slashing actions go through the sequencer publisher
|
|
509
|
+
// as they are executed when the node is selected as proposer.
|
|
510
|
+
const validatorAddresses = keyStoreManager
|
|
511
|
+
? NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager).getAddresses()
|
|
512
|
+
: [];
|
|
513
|
+
|
|
514
|
+
slasherClient = await createSlasher(
|
|
515
|
+
config,
|
|
516
|
+
config.l1Contracts,
|
|
517
|
+
getPublicClient(config),
|
|
518
|
+
watchers,
|
|
519
|
+
dateProvider,
|
|
520
|
+
epochCache,
|
|
521
|
+
validatorAddresses,
|
|
522
|
+
undefined, // logger
|
|
523
|
+
);
|
|
524
|
+
await slasherClient.start();
|
|
525
|
+
started.push(slasherClient);
|
|
526
|
+
|
|
527
|
+
const l1TxUtils = config.sequencerPublisherForwarderAddress
|
|
528
|
+
? await createForwarderL1TxUtilsFromSigners(
|
|
529
|
+
publicClient,
|
|
530
|
+
keyStoreManager!.createAllValidatorPublisherSigners(),
|
|
531
|
+
config.sequencerPublisherForwarderAddress,
|
|
532
|
+
{ ...config, scope: 'sequencer' },
|
|
533
|
+
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider, kzg: Blob.getViemKzgInstance() },
|
|
534
|
+
)
|
|
535
|
+
: await createL1TxUtilsFromSigners(
|
|
536
|
+
publicClient,
|
|
537
|
+
keyStoreManager!.createAllValidatorPublisherSigners(),
|
|
538
|
+
{ ...config, scope: 'sequencer' },
|
|
539
|
+
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider, kzg: Blob.getViemKzgInstance() },
|
|
540
|
+
);
|
|
541
|
+
|
|
542
|
+
// Create a funder L1TxUtils from the keystore funding account (if configured)
|
|
543
|
+
const fundingSigner = keyStoreManager?.createFundingSigner();
|
|
544
|
+
let funderL1TxUtils: L1TxUtils | undefined;
|
|
545
|
+
if (fundingSigner) {
|
|
546
|
+
const [funder] = await createL1TxUtilsFromSigners(
|
|
504
547
|
publicClient,
|
|
505
|
-
|
|
548
|
+
[fundingSigner],
|
|
506
549
|
{ ...config, scope: 'sequencer' },
|
|
507
|
-
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider
|
|
550
|
+
{ telemetry, logger: log.createChild('l1-tx-utils:funder'), dateProvider },
|
|
508
551
|
);
|
|
552
|
+
funderL1TxUtils = funder;
|
|
553
|
+
}
|
|
509
554
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
555
|
+
// Create and start the sequencer client
|
|
556
|
+
const checkpointsBuilder = new CheckpointsBuilder(
|
|
557
|
+
{ ...config, l1GenesisTime, slotDuration: Number(slotDuration), rollupManaLimit },
|
|
558
|
+
worldStateSynchronizer,
|
|
559
|
+
archiver,
|
|
560
|
+
dateProvider,
|
|
561
|
+
telemetry,
|
|
562
|
+
debugLogStore,
|
|
563
|
+
);
|
|
519
564
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
565
|
+
sequencer = await SequencerClient.new(config, {
|
|
566
|
+
...deps,
|
|
567
|
+
epochCache,
|
|
568
|
+
l1TxUtils,
|
|
569
|
+
funderL1TxUtils,
|
|
570
|
+
validatorClient,
|
|
571
|
+
p2pClient,
|
|
572
|
+
worldStateSynchronizer,
|
|
573
|
+
slasherClient,
|
|
574
|
+
checkpointsBuilder,
|
|
575
|
+
l2BlockSource: archiver,
|
|
576
|
+
l1ToL2MessageSource: archiver,
|
|
577
|
+
telemetry,
|
|
578
|
+
dateProvider,
|
|
579
|
+
blobClient,
|
|
580
|
+
nodeKeyStore: keyStoreManager!,
|
|
581
|
+
globalVariableBuilder,
|
|
582
|
+
});
|
|
583
|
+
}
|
|
538
584
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
585
|
+
if (!options.dontStartSequencer && sequencer) {
|
|
586
|
+
await sequencer.start();
|
|
587
|
+
started.push(sequencer);
|
|
588
|
+
log.verbose(`Sequencer started`);
|
|
589
|
+
} else if (sequencer) {
|
|
590
|
+
log.warn(`Sequencer created but not started`);
|
|
591
|
+
}
|
|
545
592
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
593
|
+
// Create prover node subsystem if enabled
|
|
594
|
+
let proverNode: ProverNode | undefined;
|
|
595
|
+
if (config.enableProverNode) {
|
|
596
|
+
proverNode = await createProverNode(config, {
|
|
597
|
+
...deps.proverNodeDeps,
|
|
598
|
+
telemetry,
|
|
599
|
+
dateProvider,
|
|
600
|
+
archiver,
|
|
601
|
+
worldStateSynchronizer,
|
|
602
|
+
p2pClient,
|
|
603
|
+
epochCache,
|
|
604
|
+
blobClient,
|
|
605
|
+
keyStoreManager,
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
if (!options.dontStartProverNode) {
|
|
609
|
+
await proverNode.start();
|
|
610
|
+
started.push(proverNode);
|
|
611
|
+
log.info(`Prover node subsystem started`);
|
|
612
|
+
} else {
|
|
613
|
+
log.info(`Prover node subsystem created but not started`);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const node = new AztecNodeService(
|
|
618
|
+
config,
|
|
619
|
+
p2pClient,
|
|
620
|
+
archiver,
|
|
621
|
+
archiver,
|
|
622
|
+
archiver,
|
|
553
623
|
archiver,
|
|
554
624
|
worldStateSynchronizer,
|
|
555
|
-
|
|
625
|
+
sequencer,
|
|
626
|
+
proverNode,
|
|
627
|
+
slasherClient,
|
|
628
|
+
validatorsSentinel,
|
|
629
|
+
epochPruneWatcher,
|
|
630
|
+
ethereumChain.chainInfo.id,
|
|
631
|
+
config.rollupVersion,
|
|
632
|
+
globalVariableBuilder,
|
|
633
|
+
feeProvider,
|
|
556
634
|
epochCache,
|
|
635
|
+
packageVersion,
|
|
636
|
+
peerProofVerifier,
|
|
637
|
+
rpcProofVerifier,
|
|
638
|
+
telemetry,
|
|
639
|
+
log,
|
|
557
640
|
blobClient,
|
|
641
|
+
validatorClient,
|
|
558
642
|
keyStoreManager,
|
|
559
|
-
|
|
643
|
+
debugLogStore,
|
|
644
|
+
);
|
|
560
645
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
646
|
+
return node;
|
|
647
|
+
} catch (err) {
|
|
648
|
+
log.error('Failed during node creation, stopping started resources', err);
|
|
649
|
+
for (const resource of started.reverse()) {
|
|
650
|
+
await tryStop(resource);
|
|
566
651
|
}
|
|
652
|
+
throw err;
|
|
567
653
|
}
|
|
568
|
-
|
|
569
|
-
const node = new AztecNodeService(
|
|
570
|
-
config,
|
|
571
|
-
p2pClient,
|
|
572
|
-
archiver,
|
|
573
|
-
archiver,
|
|
574
|
-
archiver,
|
|
575
|
-
archiver,
|
|
576
|
-
worldStateSynchronizer,
|
|
577
|
-
sequencer,
|
|
578
|
-
proverNode,
|
|
579
|
-
slasherClient,
|
|
580
|
-
validatorsSentinel,
|
|
581
|
-
epochPruneWatcher,
|
|
582
|
-
ethereumChain.chainInfo.id,
|
|
583
|
-
config.rollupVersion,
|
|
584
|
-
globalVariableBuilder,
|
|
585
|
-
epochCache,
|
|
586
|
-
packageVersion,
|
|
587
|
-
proofVerifier,
|
|
588
|
-
telemetry,
|
|
589
|
-
log,
|
|
590
|
-
blobClient,
|
|
591
|
-
validatorClient,
|
|
592
|
-
keyStoreManager,
|
|
593
|
-
debugLogStore,
|
|
594
|
-
);
|
|
595
|
-
|
|
596
|
-
return node;
|
|
597
654
|
}
|
|
598
655
|
|
|
599
656
|
/**
|
|
@@ -733,12 +790,13 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
733
790
|
return this.blockSource.getCheckpointsDataForEpoch(epochNumber);
|
|
734
791
|
}
|
|
735
792
|
|
|
736
|
-
/**
|
|
737
|
-
* Method to fetch the current min L2 fees.
|
|
738
|
-
* @returns The current min L2 fees.
|
|
739
|
-
*/
|
|
740
793
|
public async getCurrentMinFees(): Promise<GasFees> {
|
|
741
|
-
return await this.
|
|
794
|
+
return await this.feeProvider.getCurrentMinFees();
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/** Returns predicted min fees for the current slot and next N slots. */
|
|
798
|
+
public async getPredictedMinFees(manaUsage?: ManaUsageEstimate): Promise<GasFees[]> {
|
|
799
|
+
return await this.feeProvider.getPredictedMinFees(manaUsage);
|
|
742
800
|
}
|
|
743
801
|
|
|
744
802
|
public async getMaxPriorityFees(): Promise<GasFees> {
|
|
@@ -806,18 +864,22 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
806
864
|
page?: number,
|
|
807
865
|
referenceBlock?: BlockHash,
|
|
808
866
|
): Promise<TxScopedL2Log[][]> {
|
|
867
|
+
let upToBlockNumber: BlockNumber | undefined;
|
|
809
868
|
if (referenceBlock) {
|
|
810
869
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
811
|
-
if (
|
|
870
|
+
if (referenceBlock.equals(initialBlockHash)) {
|
|
871
|
+
upToBlockNumber = BlockNumber(0);
|
|
872
|
+
} else {
|
|
812
873
|
const header = await this.blockSource.getBlockHeaderByHash(referenceBlock);
|
|
813
874
|
if (!header) {
|
|
814
875
|
throw new Error(
|
|
815
876
|
`Block ${referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`,
|
|
816
877
|
);
|
|
817
878
|
}
|
|
879
|
+
upToBlockNumber = header.globalVariables.blockNumber;
|
|
818
880
|
}
|
|
819
881
|
}
|
|
820
|
-
return this.logsSource.getPrivateLogsByTags(tags, page);
|
|
882
|
+
return this.logsSource.getPrivateLogsByTags(tags, page, upToBlockNumber);
|
|
821
883
|
}
|
|
822
884
|
|
|
823
885
|
public async getPublicLogsByTagsFromContract(
|
|
@@ -826,18 +888,22 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
826
888
|
page?: number,
|
|
827
889
|
referenceBlock?: BlockHash,
|
|
828
890
|
): Promise<TxScopedL2Log[][]> {
|
|
891
|
+
let upToBlockNumber: BlockNumber | undefined;
|
|
829
892
|
if (referenceBlock) {
|
|
830
893
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
831
|
-
if (
|
|
894
|
+
if (referenceBlock.equals(initialBlockHash)) {
|
|
895
|
+
upToBlockNumber = BlockNumber(0);
|
|
896
|
+
} else {
|
|
832
897
|
const header = await this.blockSource.getBlockHeaderByHash(referenceBlock);
|
|
833
898
|
if (!header) {
|
|
834
899
|
throw new Error(
|
|
835
900
|
`Block ${referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`,
|
|
836
901
|
);
|
|
837
902
|
}
|
|
903
|
+
upToBlockNumber = header.globalVariables.blockNumber;
|
|
838
904
|
}
|
|
839
905
|
}
|
|
840
|
-
return this.logsSource.getPublicLogsByTagsFromContract(contractAddress, tags, page);
|
|
906
|
+
return this.logsSource.getPublicLogsByTagsFromContract(contractAddress, tags, page, upToBlockNumber);
|
|
841
907
|
}
|
|
842
908
|
|
|
843
909
|
/**
|
|
@@ -923,7 +989,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
923
989
|
await tryStop(this.validatorsSentinel);
|
|
924
990
|
await tryStop(this.epochPruneWatcher);
|
|
925
991
|
await tryStop(this.slasherClient);
|
|
926
|
-
await tryStop(this.
|
|
992
|
+
await Promise.all([tryStop(this.peerProofVerifier), tryStop(this.rpcProofVerifier)]);
|
|
927
993
|
await tryStop(this.sequencer);
|
|
928
994
|
await tryStop(this.proverNode);
|
|
929
995
|
await tryStop(this.p2pClient);
|
|
@@ -1013,7 +1079,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1013
1079
|
);
|
|
1014
1080
|
|
|
1015
1081
|
// Build a map from block number to block hash
|
|
1016
|
-
const blockNumberToHash = new Map<BlockNumber,
|
|
1082
|
+
const blockNumberToHash = new Map<BlockNumber, BlockHash>();
|
|
1017
1083
|
for (let i = 0; i < uniqueBlockNumbers.length; i++) {
|
|
1018
1084
|
const blockHash = blockHashes[i];
|
|
1019
1085
|
if (blockHash === undefined) {
|
|
@@ -1031,13 +1097,13 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1031
1097
|
if (blockNumber === undefined) {
|
|
1032
1098
|
throw new Error(`Block number not found for leaf index ${index} in tree ${MerkleTreeId[treeId]}`);
|
|
1033
1099
|
}
|
|
1034
|
-
const
|
|
1035
|
-
if (
|
|
1100
|
+
const l2BlockHash = blockNumberToHash.get(blockNumber);
|
|
1101
|
+
if (l2BlockHash === undefined) {
|
|
1036
1102
|
throw new Error(`Block hash not found for block number ${blockNumber}`);
|
|
1037
1103
|
}
|
|
1038
1104
|
return {
|
|
1039
1105
|
l2BlockNumber: blockNumber,
|
|
1040
|
-
l2BlockHash
|
|
1106
|
+
l2BlockHash,
|
|
1041
1107
|
data: index,
|
|
1042
1108
|
};
|
|
1043
1109
|
});
|
|
@@ -1047,20 +1113,14 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1047
1113
|
referenceBlock: BlockParameter,
|
|
1048
1114
|
blockHash: BlockHash,
|
|
1049
1115
|
): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
|
|
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
1116
|
// The Noir circuit checks the archive membership proof against `anchor_block_header.last_archive.root`,
|
|
1061
1117
|
// which is the archive tree root BEFORE the anchor block was added (i.e. the state after block N-1).
|
|
1062
1118
|
// So we need the world state at block N-1, not block N, to produce a sibling path matching that root.
|
|
1063
1119
|
const referenceBlockNumber = await this.resolveBlockNumber(referenceBlock);
|
|
1120
|
+
if (referenceBlockNumber === BlockNumber.ZERO) {
|
|
1121
|
+
// Block 0 (the initial block) has an empty archive, so no membership witness can exist.
|
|
1122
|
+
return undefined;
|
|
1123
|
+
}
|
|
1064
1124
|
const committedDb = await this.getWorldState(BlockNumber(referenceBlockNumber - 1));
|
|
1065
1125
|
const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.ARCHIVE>(MerkleTreeId.ARCHIVE, [blockHash]);
|
|
1066
1126
|
return pathAndIndex === undefined
|
|
@@ -1323,7 +1383,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1323
1383
|
{ isSimulation, skipFeeEnforcement }: { isSimulation?: boolean; skipFeeEnforcement?: boolean } = {},
|
|
1324
1384
|
): Promise<TxValidationResult> {
|
|
1325
1385
|
const db = this.worldStateSynchronizer.getCommitted();
|
|
1326
|
-
const verifier = isSimulation ? undefined : this.
|
|
1386
|
+
const verifier = isSimulation ? undefined : this.rpcProofVerifier;
|
|
1327
1387
|
|
|
1328
1388
|
// We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
|
|
1329
1389
|
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
@@ -1372,7 +1432,15 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1372
1432
|
archiver.updateConfig(config);
|
|
1373
1433
|
}
|
|
1374
1434
|
if (newConfig.realProofs !== this.config.realProofs) {
|
|
1375
|
-
|
|
1435
|
+
await Promise.all([tryStop(this.peerProofVerifier), tryStop(this.rpcProofVerifier)]);
|
|
1436
|
+
if (newConfig.realProofs) {
|
|
1437
|
+
this.peerProofVerifier = await BatchChonkVerifier.new(newConfig, newConfig.bbChonkVerifyMaxBatch, 'peer');
|
|
1438
|
+
const rpcVerifier = await BBCircuitVerifier.new(newConfig);
|
|
1439
|
+
this.rpcProofVerifier = new QueuedIVCVerifier(rpcVerifier, newConfig.numConcurrentIVCVerifiers);
|
|
1440
|
+
} else {
|
|
1441
|
+
this.peerProofVerifier = new TestCircuitVerifier();
|
|
1442
|
+
this.rpcProofVerifier = new TestCircuitVerifier();
|
|
1443
|
+
}
|
|
1376
1444
|
}
|
|
1377
1445
|
|
|
1378
1446
|
this.config = newConfig;
|
|
@@ -1447,7 +1515,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1447
1515
|
return Promise.resolve();
|
|
1448
1516
|
}
|
|
1449
1517
|
|
|
1450
|
-
public async rollbackTo(targetBlock: BlockNumber, force?: boolean): Promise<void> {
|
|
1518
|
+
public async rollbackTo(targetBlock: BlockNumber, force?: boolean, resumeSync = true): Promise<void> {
|
|
1451
1519
|
const archiver = this.blockSource as Archiver;
|
|
1452
1520
|
if (!('rollbackTo' in archiver)) {
|
|
1453
1521
|
throw new Error('Archiver implementation does not support rollbacks.');
|
|
@@ -1477,9 +1545,13 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1477
1545
|
this.log.error(`Error during rollback`, err);
|
|
1478
1546
|
throw err;
|
|
1479
1547
|
} finally {
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1548
|
+
if (resumeSync) {
|
|
1549
|
+
this.log.info(`Resuming world state and archiver sync.`);
|
|
1550
|
+
this.worldStateSynchronizer.resumeSync();
|
|
1551
|
+
archiver.resume();
|
|
1552
|
+
} else {
|
|
1553
|
+
this.log.info(`Sync left paused after rollback (resumeSync=false).`);
|
|
1554
|
+
}
|
|
1483
1555
|
}
|
|
1484
1556
|
}
|
|
1485
1557
|
|
|
@@ -1496,19 +1568,12 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1496
1568
|
return Promise.resolve();
|
|
1497
1569
|
}
|
|
1498
1570
|
|
|
1499
|
-
public getSlashPayloads(): Promise<SlashPayloadRound[]> {
|
|
1500
|
-
if (!this.slasherClient) {
|
|
1501
|
-
throw new Error(`Slasher client not enabled`);
|
|
1502
|
-
}
|
|
1503
|
-
return this.slasherClient.getSlashPayloads();
|
|
1504
|
-
}
|
|
1505
|
-
|
|
1506
1571
|
public getSlashOffenses(round: bigint | 'all' | 'current'): Promise<Offense[]> {
|
|
1507
1572
|
if (!this.slasherClient) {
|
|
1508
1573
|
throw new Error(`Slasher client not enabled`);
|
|
1509
1574
|
}
|
|
1510
1575
|
if (round === 'all') {
|
|
1511
|
-
return this.slasherClient.
|
|
1576
|
+
return this.slasherClient.getOffenses();
|
|
1512
1577
|
} else {
|
|
1513
1578
|
return this.slasherClient.gatherOffensesForRound(round === 'current' ? undefined : BigInt(round));
|
|
1514
1579
|
}
|
|
@@ -1667,18 +1732,19 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1667
1732
|
if (BlockHash.isBlockHash(block)) {
|
|
1668
1733
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1669
1734
|
if (block.equals(initialBlockHash)) {
|
|
1670
|
-
// Block
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1735
|
+
// Block 0 is a first-class historical block: its state lives in the trees' persisted
|
|
1736
|
+
// block-0 payload. Resolving the genesis hash to block number 0 lets the snapshot path
|
|
1737
|
+
// pin reads to genesis state even after the node has advanced past it.
|
|
1738
|
+
blockNumber = BlockNumber.ZERO;
|
|
1739
|
+
} else {
|
|
1740
|
+
const header = await this.blockSource.getBlockHeaderByHash(block);
|
|
1741
|
+
if (!header) {
|
|
1742
|
+
throw new Error(
|
|
1743
|
+
`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.`,
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1746
|
+
blockNumber = header.getBlockNumber();
|
|
1679
1747
|
}
|
|
1680
|
-
|
|
1681
|
-
blockNumber = header.getBlockNumber();
|
|
1682
1748
|
} else {
|
|
1683
1749
|
blockNumber = block as BlockNumber;
|
|
1684
1750
|
}
|
|
@@ -1694,9 +1760,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1694
1760
|
// Double-check world-state synced to the same block hash as was requested
|
|
1695
1761
|
if (BlockHash.isBlockHash(block)) {
|
|
1696
1762
|
const blockHash = await snapshot.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber));
|
|
1697
|
-
if (!blockHash || !
|
|
1763
|
+
if (!blockHash || !block.equals(blockHash)) {
|
|
1764
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1698
1765
|
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.`,
|
|
1766
|
+
`Block hash ${block.toString()} not found in world state at block number ${blockNumber} (world state has ${blockHash?.toString() ?? 'no hash'} at that index, genesis header hash is ${initialBlockHash.toString()}). If the node API has been queried with anchor block hash possibly a reorg has occurred.`,
|
|
1700
1767
|
);
|
|
1701
1768
|
}
|
|
1702
1769
|
}
|