@aztec/aztec-node 0.0.0-test.1 → 0.0.1-commit.1142ef1
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 +18 -10
- package/dest/aztec-node/config.d.ts.map +1 -1
- package/dest/aztec-node/config.js +81 -14
- package/dest/aztec-node/node_metrics.d.ts +5 -1
- package/dest/aztec-node/node_metrics.d.ts.map +1 -1
- package/dest/aztec-node/node_metrics.js +17 -7
- package/dest/aztec-node/server.d.ts +123 -86
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +994 -250
- package/dest/bin/index.d.ts +1 -1
- package/dest/bin/index.js +4 -2
- package/dest/index.d.ts +1 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +0 -1
- package/dest/sentinel/config.d.ts +8 -0
- package/dest/sentinel/config.d.ts.map +1 -0
- package/dest/sentinel/config.js +29 -0
- package/dest/sentinel/factory.d.ts +9 -0
- package/dest/sentinel/factory.d.ts.map +1 -0
- package/dest/sentinel/factory.js +17 -0
- package/dest/sentinel/index.d.ts +3 -0
- package/dest/sentinel/index.d.ts.map +1 -0
- package/dest/sentinel/index.js +1 -0
- package/dest/sentinel/sentinel.d.ts +93 -0
- package/dest/sentinel/sentinel.d.ts.map +1 -0
- package/dest/sentinel/sentinel.js +403 -0
- package/dest/sentinel/store.d.ts +35 -0
- package/dest/sentinel/store.d.ts.map +1 -0
- package/dest/sentinel/store.js +170 -0
- package/dest/test/index.d.ts +31 -0
- package/dest/test/index.d.ts.map +1 -0
- package/dest/test/index.js +1 -0
- package/package.json +45 -35
- package/src/aztec-node/config.ts +132 -25
- package/src/aztec-node/node_metrics.ts +24 -14
- package/src/aztec-node/server.ts +809 -330
- package/src/bin/index.ts +4 -2
- package/src/index.ts +0 -1
- package/src/sentinel/config.ts +37 -0
- package/src/sentinel/factory.ts +36 -0
- package/src/sentinel/index.ts +8 -0
- package/src/sentinel/sentinel.ts +510 -0
- package/src/sentinel/store.ts +185 -0
- package/src/test/index.ts +32 -0
- package/dest/aztec-node/http_rpc_server.d.ts +0 -8
- package/dest/aztec-node/http_rpc_server.d.ts.map +0 -1
- package/dest/aztec-node/http_rpc_server.js +0 -9
- package/src/aztec-node/http_rpc_server.ts +0 -11
package/src/aztec-node/server.ts
CHANGED
|
@@ -1,39 +1,57 @@
|
|
|
1
|
-
import { createArchiver } from '@aztec/archiver';
|
|
2
|
-
import { BBCircuitVerifier, TestCircuitVerifier } from '@aztec/bb-prover';
|
|
3
|
-
import { type
|
|
1
|
+
import { Archiver, createArchiver } from '@aztec/archiver';
|
|
2
|
+
import { BBCircuitVerifier, QueuedIVCVerifier, TestCircuitVerifier } from '@aztec/bb-prover';
|
|
3
|
+
import { type BlobClientInterface, createBlobClientWithFileStores } from '@aztec/blob-client/client';
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
ARCHIVE_HEIGHT,
|
|
6
6
|
INITIAL_L2_BLOCK_NUM,
|
|
7
7
|
type L1_TO_L2_MSG_TREE_HEIGHT,
|
|
8
8
|
type NOTE_HASH_TREE_HEIGHT,
|
|
9
9
|
type NULLIFIER_TREE_HEIGHT,
|
|
10
10
|
type PUBLIC_DATA_TREE_HEIGHT,
|
|
11
|
-
REGISTERER_CONTRACT_ADDRESS,
|
|
12
11
|
} from '@aztec/constants';
|
|
13
|
-
import { EpochCache } from '@aztec/epoch-cache';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
12
|
+
import { EpochCache, type EpochCacheInterface } from '@aztec/epoch-cache';
|
|
13
|
+
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
14
|
+
import { getPublicClient } from '@aztec/ethereum/client';
|
|
15
|
+
import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
|
|
16
|
+
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
17
|
+
import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
18
|
+
import { compactArray, pick } from '@aztec/foundation/collection';
|
|
19
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
16
20
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
17
|
-
import {
|
|
21
|
+
import { BadRequestError } from '@aztec/foundation/json-rpc';
|
|
18
22
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
23
|
+
import { count } from '@aztec/foundation/string';
|
|
19
24
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
20
|
-
import { SiblingPath } from '@aztec/foundation/trees';
|
|
21
|
-
import
|
|
22
|
-
import {
|
|
23
|
-
import { SHA256Trunc, StandardTree, UnbalancedTree } from '@aztec/merkle-tree';
|
|
24
|
-
import { type P2P, createP2PClient } from '@aztec/p2p';
|
|
25
|
-
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
25
|
+
import { MembershipWitness, SiblingPath } from '@aztec/foundation/trees';
|
|
26
|
+
import { KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
|
|
27
|
+
import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
|
|
26
28
|
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
} from '@aztec/sequencer-client';
|
|
29
|
+
createForwarderL1TxUtilsFromEthSigner,
|
|
30
|
+
createL1TxUtilsWithBlobsFromEthSigner,
|
|
31
|
+
} from '@aztec/node-lib/factories';
|
|
32
|
+
import { type P2P, type P2PClientDeps, createP2PClient, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
|
|
33
|
+
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
34
|
+
import { BlockBuilder, GlobalVariableBuilder, SequencerClient, type SequencerPublisher } from '@aztec/sequencer-client';
|
|
34
35
|
import { PublicProcessorFactory } from '@aztec/simulator/server';
|
|
36
|
+
import {
|
|
37
|
+
AttestationsBlockWatcher,
|
|
38
|
+
EpochPruneWatcher,
|
|
39
|
+
type SlasherClientInterface,
|
|
40
|
+
type Watcher,
|
|
41
|
+
createSlasher,
|
|
42
|
+
} from '@aztec/slasher';
|
|
43
|
+
import { CollectionLimitsConfig, PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
35
44
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
36
|
-
import
|
|
45
|
+
import {
|
|
46
|
+
type BlockParameter,
|
|
47
|
+
type DataInBlock,
|
|
48
|
+
type L2Block,
|
|
49
|
+
L2BlockHash,
|
|
50
|
+
L2BlockNew,
|
|
51
|
+
type L2BlockSource,
|
|
52
|
+
type PublishedL2Block,
|
|
53
|
+
} from '@aztec/stdlib/block';
|
|
54
|
+
import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
37
55
|
import type {
|
|
38
56
|
ContractClassPublic,
|
|
39
57
|
ContractDataSource,
|
|
@@ -41,34 +59,44 @@ import type {
|
|
|
41
59
|
NodeInfo,
|
|
42
60
|
ProtocolContractAddresses,
|
|
43
61
|
} from '@aztec/stdlib/contract';
|
|
44
|
-
import
|
|
45
|
-
import { computePublicDataTreeLeafSlot
|
|
46
|
-
import
|
|
62
|
+
import { GasFees } from '@aztec/stdlib/gas';
|
|
63
|
+
import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
|
|
64
|
+
import {
|
|
65
|
+
type AztecNode,
|
|
66
|
+
type AztecNodeAdmin,
|
|
67
|
+
type AztecNodeAdminConfig,
|
|
68
|
+
AztecNodeAdminConfigSchema,
|
|
69
|
+
type GetContractClassLogsResponse,
|
|
70
|
+
type GetPublicLogsResponse,
|
|
71
|
+
} from '@aztec/stdlib/interfaces/client';
|
|
47
72
|
import {
|
|
73
|
+
type AllowedElement,
|
|
48
74
|
type ClientProtocolCircuitVerifier,
|
|
49
75
|
type L2LogsSource,
|
|
50
|
-
type ProverConfig,
|
|
51
|
-
type SequencerConfig,
|
|
52
76
|
type Service,
|
|
53
77
|
type WorldStateSyncStatus,
|
|
54
78
|
type WorldStateSynchronizer,
|
|
55
79
|
tryStop,
|
|
56
80
|
} from '@aztec/stdlib/interfaces/server';
|
|
57
|
-
import type { LogFilter,
|
|
58
|
-
import type
|
|
81
|
+
import type { LogFilter, SiloedTag, Tag, TxScopedL2Log } from '@aztec/stdlib/logs';
|
|
82
|
+
import { InboxLeaf, type L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
59
83
|
import { P2PClientType } from '@aztec/stdlib/p2p';
|
|
60
|
-
import {
|
|
84
|
+
import type { Offense, SlashPayloadRound } from '@aztec/stdlib/slashing';
|
|
61
85
|
import type { NullifierLeafPreimage, PublicDataTreeLeaf, PublicDataTreeLeafPreimage } from '@aztec/stdlib/trees';
|
|
86
|
+
import { MerkleTreeId, NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
|
|
62
87
|
import {
|
|
63
88
|
type BlockHeader,
|
|
89
|
+
type GlobalVariableBuilder as GlobalVariableBuilderInterface,
|
|
90
|
+
type IndexedTxEffect,
|
|
64
91
|
PublicSimulationOutput,
|
|
65
92
|
Tx,
|
|
66
|
-
TxEffect,
|
|
67
93
|
type TxHash,
|
|
68
94
|
TxReceipt,
|
|
69
95
|
TxStatus,
|
|
70
96
|
type TxValidationResult,
|
|
71
97
|
} from '@aztec/stdlib/tx';
|
|
98
|
+
import { getPackageVersion } from '@aztec/stdlib/update-checker';
|
|
99
|
+
import type { SingleValidatorStats, ValidatorsStats } from '@aztec/stdlib/validators';
|
|
72
100
|
import {
|
|
73
101
|
Attributes,
|
|
74
102
|
type TelemetryClient,
|
|
@@ -77,19 +105,33 @@ import {
|
|
|
77
105
|
getTelemetryClient,
|
|
78
106
|
trackSpan,
|
|
79
107
|
} from '@aztec/telemetry-client';
|
|
80
|
-
import {
|
|
108
|
+
import {
|
|
109
|
+
FullNodeCheckpointsBuilder as CheckpointsBuilder,
|
|
110
|
+
FullNodeCheckpointsBuilder,
|
|
111
|
+
NodeKeystoreAdapter,
|
|
112
|
+
ValidatorClient,
|
|
113
|
+
createBlockProposalHandler,
|
|
114
|
+
createValidatorClient,
|
|
115
|
+
createValidatorForAcceptingTxs,
|
|
116
|
+
} from '@aztec/validator-client';
|
|
81
117
|
import { createWorldStateSynchronizer } from '@aztec/world-state';
|
|
82
118
|
|
|
83
|
-
import {
|
|
119
|
+
import { createPublicClient, fallback, http } from 'viem';
|
|
120
|
+
|
|
121
|
+
import { createSentinel } from '../sentinel/factory.js';
|
|
122
|
+
import { Sentinel } from '../sentinel/sentinel.js';
|
|
123
|
+
import { type AztecNodeConfig, createKeyStoreForValidator } from './config.js';
|
|
84
124
|
import { NodeMetrics } from './node_metrics.js';
|
|
85
125
|
|
|
86
126
|
/**
|
|
87
127
|
* The aztec node.
|
|
88
128
|
*/
|
|
89
|
-
export class AztecNodeService implements AztecNode, Traceable {
|
|
90
|
-
private packageVersion: string;
|
|
129
|
+
export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
91
130
|
private metrics: NodeMetrics;
|
|
92
131
|
|
|
132
|
+
// Prevent two snapshot operations to happen simultaneously
|
|
133
|
+
private isUploadingSnapshot = false;
|
|
134
|
+
|
|
93
135
|
public readonly tracer: Tracer;
|
|
94
136
|
|
|
95
137
|
constructor(
|
|
@@ -99,17 +141,21 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
99
141
|
protected readonly logsSource: L2LogsSource,
|
|
100
142
|
protected readonly contractDataSource: ContractDataSource,
|
|
101
143
|
protected readonly l1ToL2MessageSource: L1ToL2MessageSource,
|
|
102
|
-
protected readonly nullifierSource: NullifierWithBlockSource,
|
|
103
144
|
protected readonly worldStateSynchronizer: WorldStateSynchronizer,
|
|
104
145
|
protected readonly sequencer: SequencerClient | undefined,
|
|
146
|
+
protected readonly slasherClient: SlasherClientInterface | undefined,
|
|
147
|
+
protected readonly validatorsSentinel: Sentinel | undefined,
|
|
148
|
+
protected readonly epochPruneWatcher: EpochPruneWatcher | undefined,
|
|
105
149
|
protected readonly l1ChainId: number,
|
|
106
150
|
protected readonly version: number,
|
|
107
|
-
protected readonly globalVariableBuilder:
|
|
151
|
+
protected readonly globalVariableBuilder: GlobalVariableBuilderInterface,
|
|
152
|
+
protected readonly epochCache: EpochCacheInterface,
|
|
153
|
+
protected readonly packageVersion: string,
|
|
108
154
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
109
155
|
private telemetry: TelemetryClient = getTelemetryClient(),
|
|
110
156
|
private log = createLogger('node'),
|
|
157
|
+
private blobClient?: BlobClientInterface,
|
|
111
158
|
) {
|
|
112
|
-
this.packageVersion = getPackageVersion();
|
|
113
159
|
this.metrics = new NodeMetrics(telemetry, 'AztecNodeService');
|
|
114
160
|
this.tracer = telemetry.getTracer('AztecNodeService');
|
|
115
161
|
|
|
@@ -132,31 +178,103 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
132
178
|
* @returns - A fully synced Aztec Node for use in development/testing.
|
|
133
179
|
*/
|
|
134
180
|
public static async createAndSync(
|
|
135
|
-
|
|
181
|
+
inputConfig: AztecNodeConfig,
|
|
136
182
|
deps: {
|
|
137
183
|
telemetry?: TelemetryClient;
|
|
138
184
|
logger?: Logger;
|
|
139
185
|
publisher?: SequencerPublisher;
|
|
140
186
|
dateProvider?: DateProvider;
|
|
141
|
-
|
|
187
|
+
p2pClientDeps?: P2PClientDeps<P2PClientType.Full>;
|
|
142
188
|
} = {},
|
|
143
189
|
options: {
|
|
144
190
|
prefilledPublicData?: PublicDataTreeLeaf[];
|
|
191
|
+
dontStartSequencer?: boolean;
|
|
145
192
|
} = {},
|
|
146
193
|
): Promise<AztecNodeService> {
|
|
147
|
-
const
|
|
194
|
+
const config = { ...inputConfig }; // Copy the config so we dont mutate the input object
|
|
148
195
|
const log = deps.logger ?? createLogger('node');
|
|
196
|
+
const packageVersion = getPackageVersion() ?? '';
|
|
197
|
+
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
149
198
|
const dateProvider = deps.dateProvider ?? new DateProvider();
|
|
150
|
-
const blobSinkClient = deps.blobSinkClient ?? createBlobSinkClient(config);
|
|
151
199
|
const ethereumChain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
|
|
152
|
-
|
|
200
|
+
|
|
201
|
+
// Build a key store from file if given or from environment otherwise
|
|
202
|
+
let keyStoreManager: KeystoreManager | undefined;
|
|
203
|
+
const keyStoreProvided = config.keyStoreDirectory !== undefined && config.keyStoreDirectory.length > 0;
|
|
204
|
+
if (keyStoreProvided) {
|
|
205
|
+
const keyStores = loadKeystores(config.keyStoreDirectory!);
|
|
206
|
+
keyStoreManager = new KeystoreManager(mergeKeystores(keyStores));
|
|
207
|
+
} else {
|
|
208
|
+
const keyStore = createKeyStoreForValidator(config);
|
|
209
|
+
if (keyStore) {
|
|
210
|
+
keyStoreManager = new KeystoreManager(keyStore);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
await keyStoreManager?.validateSigners();
|
|
215
|
+
|
|
216
|
+
// If we are a validator, verify our configuration before doing too much more.
|
|
217
|
+
if (!config.disableValidator) {
|
|
218
|
+
if (keyStoreManager === undefined) {
|
|
219
|
+
throw new Error('Failed to create key store, a requirement for running a validator');
|
|
220
|
+
}
|
|
221
|
+
if (!keyStoreProvided) {
|
|
222
|
+
log.warn(
|
|
223
|
+
'KEY STORE CREATED FROM ENVIRONMENT, IT IS RECOMMENDED TO USE A FILE-BASED KEY STORE IN PRODUCTION ENVIRONMENTS',
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
ValidatorClient.validateKeyStoreConfiguration(keyStoreManager, log);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// validate that the actual chain id matches that specified in configuration
|
|
153
230
|
if (config.l1ChainId !== ethereumChain.chainInfo.id) {
|
|
154
231
|
throw new Error(
|
|
155
232
|
`RPC URL configured for chain id ${ethereumChain.chainInfo.id} but expected id ${config.l1ChainId}`,
|
|
156
233
|
);
|
|
157
234
|
}
|
|
158
235
|
|
|
159
|
-
const
|
|
236
|
+
const publicClient = createPublicClient({
|
|
237
|
+
chain: ethereumChain.chainInfo,
|
|
238
|
+
transport: fallback(config.l1RpcUrls.map((url: string) => http(url, { batch: false }))),
|
|
239
|
+
pollingInterval: config.viemPollingIntervalMS,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const l1ContractsAddresses = await RegistryContract.collectAddresses(
|
|
243
|
+
publicClient,
|
|
244
|
+
config.l1Contracts.registryAddress,
|
|
245
|
+
config.rollupVersion ?? 'canonical',
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
// Overwrite the passed in vars.
|
|
249
|
+
config.l1Contracts = { ...config.l1Contracts, ...l1ContractsAddresses };
|
|
250
|
+
|
|
251
|
+
const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
|
|
252
|
+
const [l1GenesisTime, slotDuration, rollupVersionFromRollup] = await Promise.all([
|
|
253
|
+
rollupContract.getL1GenesisTime(),
|
|
254
|
+
rollupContract.getSlotDuration(),
|
|
255
|
+
rollupContract.getVersion(),
|
|
256
|
+
] as const);
|
|
257
|
+
|
|
258
|
+
config.rollupVersion ??= Number(rollupVersionFromRollup);
|
|
259
|
+
|
|
260
|
+
if (config.rollupVersion !== Number(rollupVersionFromRollup)) {
|
|
261
|
+
log.warn(
|
|
262
|
+
`Registry looked up and returned a rollup with version (${config.rollupVersion}), but this does not match with version detected from the rollup directly: (${rollupVersionFromRollup}).`,
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const blobClient = await createBlobClientWithFileStores(config, createLogger('node:blob-client:client'));
|
|
267
|
+
|
|
268
|
+
// attempt snapshot sync if possible
|
|
269
|
+
await trySnapshotSync(config, log);
|
|
270
|
+
|
|
271
|
+
const epochCache = await EpochCache.create(config.l1Contracts.rollupAddress, config, { dateProvider });
|
|
272
|
+
|
|
273
|
+
const archiver = await createArchiver(
|
|
274
|
+
config,
|
|
275
|
+
{ blobClient, epochCache, telemetry, dateProvider },
|
|
276
|
+
{ blockUntilSync: !config.skipArchiverInitialSync },
|
|
277
|
+
);
|
|
160
278
|
|
|
161
279
|
// now create the merkle trees and the world state synchronizer
|
|
162
280
|
const worldStateSynchronizer = await createWorldStateSynchronizer(
|
|
@@ -165,12 +283,14 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
165
283
|
options.prefilledPublicData,
|
|
166
284
|
telemetry,
|
|
167
285
|
);
|
|
168
|
-
const
|
|
286
|
+
const circuitVerifier =
|
|
287
|
+
config.realProofs || config.debugForceTxProofVerification
|
|
288
|
+
? await BBCircuitVerifier.new(config)
|
|
289
|
+
: new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
169
290
|
if (!config.realProofs) {
|
|
170
291
|
log.warn(`Aztec node is accepting fake proofs`);
|
|
171
292
|
}
|
|
172
|
-
|
|
173
|
-
const epochCache = await EpochCache.create(config.l1Contracts.rollupAddress, config, { dateProvider });
|
|
293
|
+
const proofVerifier = new QueuedIVCVerifier(config, circuitVerifier);
|
|
174
294
|
|
|
175
295
|
// create the tx pool and the p2p client, which will need the l2 block source
|
|
176
296
|
const p2pClient = await createP2PClient(
|
|
@@ -180,33 +300,194 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
180
300
|
proofVerifier,
|
|
181
301
|
worldStateSynchronizer,
|
|
182
302
|
epochCache,
|
|
303
|
+
packageVersion,
|
|
304
|
+
dateProvider,
|
|
183
305
|
telemetry,
|
|
306
|
+
deps.p2pClientDeps,
|
|
184
307
|
);
|
|
185
308
|
|
|
186
|
-
|
|
309
|
+
// We should really not be modifying the config object
|
|
310
|
+
config.txPublicSetupAllowList = config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
|
|
187
311
|
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
|
|
312
|
+
// Create BlockBuilder for EpochPruneWatcher (slasher functionality)
|
|
313
|
+
const blockBuilder = new BlockBuilder(
|
|
314
|
+
{ ...config, l1GenesisTime, slotDuration: Number(slotDuration) },
|
|
315
|
+
worldStateSynchronizer,
|
|
316
|
+
archiver,
|
|
317
|
+
dateProvider,
|
|
318
|
+
telemetry,
|
|
319
|
+
);
|
|
191
320
|
|
|
192
|
-
|
|
321
|
+
// Create FullNodeCheckpointsBuilder for validator and non-validator block proposal handling
|
|
322
|
+
const validatorCheckpointsBuilder = new FullNodeCheckpointsBuilder(
|
|
323
|
+
{ ...config, l1GenesisTime, slotDuration: Number(slotDuration) },
|
|
324
|
+
archiver,
|
|
325
|
+
dateProvider,
|
|
326
|
+
telemetry,
|
|
327
|
+
);
|
|
193
328
|
|
|
194
|
-
//
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
329
|
+
// We'll accumulate sentinel watchers here
|
|
330
|
+
const watchers: Watcher[] = [];
|
|
331
|
+
|
|
332
|
+
// Create validator client if required
|
|
333
|
+
const validatorClient = createValidatorClient(config, {
|
|
334
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
335
|
+
worldState: worldStateSynchronizer,
|
|
336
|
+
p2pClient,
|
|
337
|
+
telemetry,
|
|
338
|
+
dateProvider,
|
|
339
|
+
epochCache,
|
|
340
|
+
blockSource: archiver,
|
|
341
|
+
l1ToL2MessageSource: archiver,
|
|
342
|
+
keyStoreManager,
|
|
343
|
+
blobClient,
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// If we have a validator client, register it as a source of offenses for the slasher,
|
|
347
|
+
// and have it register callbacks on the p2p client *before* we start it, otherwise messages
|
|
348
|
+
// like attestations or auths will fail.
|
|
349
|
+
if (validatorClient) {
|
|
350
|
+
watchers.push(validatorClient);
|
|
351
|
+
if (!options.dontStartSequencer) {
|
|
352
|
+
await validatorClient.registerHandlers();
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// If there's no validator client but alwaysReexecuteBlockProposals is enabled,
|
|
357
|
+
// create a BlockProposalHandler to reexecute block proposals for monitoring
|
|
358
|
+
if (!validatorClient && config.alwaysReexecuteBlockProposals) {
|
|
359
|
+
log.info('Setting up block proposal reexecution for monitoring');
|
|
360
|
+
createBlockProposalHandler(config, {
|
|
361
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
362
|
+
worldState: worldStateSynchronizer,
|
|
363
|
+
epochCache,
|
|
364
|
+
blockSource: archiver,
|
|
365
|
+
l1ToL2MessageSource: archiver,
|
|
366
|
+
p2pClient,
|
|
367
|
+
dateProvider,
|
|
368
|
+
telemetry,
|
|
369
|
+
}).registerForReexecution(p2pClient);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Start world state and wait for it to sync to the archiver.
|
|
373
|
+
await worldStateSynchronizer.start();
|
|
374
|
+
|
|
375
|
+
// Start p2p. Note that it depends on world state to be running.
|
|
376
|
+
await p2pClient.start();
|
|
377
|
+
|
|
378
|
+
const validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
|
|
379
|
+
if (validatorsSentinel && config.slashInactivityPenalty > 0n) {
|
|
380
|
+
watchers.push(validatorsSentinel);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
let epochPruneWatcher: EpochPruneWatcher | undefined;
|
|
384
|
+
if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
|
|
385
|
+
epochPruneWatcher = new EpochPruneWatcher(
|
|
386
|
+
archiver,
|
|
387
|
+
archiver,
|
|
388
|
+
epochCache,
|
|
389
|
+
p2pClient.getTxProvider(),
|
|
390
|
+
blockBuilder,
|
|
391
|
+
config,
|
|
392
|
+
);
|
|
393
|
+
watchers.push(epochPruneWatcher);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// We assume we want to slash for invalid attestations unless all max penalties are set to 0
|
|
397
|
+
let attestationsBlockWatcher: AttestationsBlockWatcher | undefined;
|
|
398
|
+
if (config.slashProposeInvalidAttestationsPenalty > 0n || config.slashAttestDescendantOfInvalidPenalty > 0n) {
|
|
399
|
+
attestationsBlockWatcher = new AttestationsBlockWatcher(archiver, epochCache, config);
|
|
400
|
+
watchers.push(attestationsBlockWatcher);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Start p2p-related services once the archiver has completed sync
|
|
404
|
+
void archiver
|
|
405
|
+
.waitForInitialSync()
|
|
406
|
+
.then(async () => {
|
|
407
|
+
await p2pClient.start();
|
|
408
|
+
await validatorsSentinel?.start();
|
|
409
|
+
await epochPruneWatcher?.start();
|
|
410
|
+
await attestationsBlockWatcher?.start();
|
|
411
|
+
log.info(`All p2p services started`);
|
|
412
|
+
})
|
|
413
|
+
.catch(err => log.error('Failed to start p2p services after archiver sync', err));
|
|
414
|
+
|
|
415
|
+
// Validator enabled, create/start relevant service
|
|
416
|
+
let sequencer: SequencerClient | undefined;
|
|
417
|
+
let slasherClient: SlasherClientInterface | undefined;
|
|
418
|
+
if (!config.disableValidator && validatorClient) {
|
|
419
|
+
// We create a slasher only if we have a sequencer, since all slashing actions go through the sequencer publisher
|
|
420
|
+
// as they are executed when the node is selected as proposer.
|
|
421
|
+
const validatorAddresses = keyStoreManager
|
|
422
|
+
? NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager).getAddresses()
|
|
423
|
+
: [];
|
|
424
|
+
|
|
425
|
+
slasherClient = await createSlasher(
|
|
426
|
+
config,
|
|
427
|
+
config.l1Contracts,
|
|
428
|
+
getPublicClient(config),
|
|
429
|
+
watchers,
|
|
430
|
+
dateProvider,
|
|
431
|
+
epochCache,
|
|
432
|
+
validatorAddresses,
|
|
433
|
+
undefined, // logger
|
|
434
|
+
);
|
|
435
|
+
await slasherClient.start();
|
|
436
|
+
|
|
437
|
+
const l1TxUtils = config.publisherForwarderAddress
|
|
438
|
+
? await createForwarderL1TxUtilsFromEthSigner(
|
|
439
|
+
publicClient,
|
|
440
|
+
keyStoreManager!.createAllValidatorPublisherSigners(),
|
|
441
|
+
config.publisherForwarderAddress,
|
|
442
|
+
{ ...config, scope: 'sequencer' },
|
|
443
|
+
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
|
|
444
|
+
)
|
|
445
|
+
: await createL1TxUtilsWithBlobsFromEthSigner(
|
|
446
|
+
publicClient,
|
|
447
|
+
keyStoreManager!.createAllValidatorPublisherSigners(),
|
|
448
|
+
{ ...config, scope: 'sequencer' },
|
|
449
|
+
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
// Create and start the sequencer client
|
|
453
|
+
const checkpointsBuilder = new CheckpointsBuilder(
|
|
454
|
+
{ ...config, l1GenesisTime, slotDuration: Number(slotDuration) },
|
|
455
|
+
archiver,
|
|
456
|
+
dateProvider,
|
|
457
|
+
telemetry,
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
sequencer = await SequencerClient.new(config, {
|
|
461
|
+
...deps,
|
|
462
|
+
epochCache,
|
|
463
|
+
l1TxUtils,
|
|
464
|
+
validatorClient,
|
|
465
|
+
p2pClient,
|
|
466
|
+
worldStateSynchronizer,
|
|
467
|
+
slasherClient,
|
|
468
|
+
checkpointsBuilder,
|
|
469
|
+
l2BlockSource: archiver,
|
|
470
|
+
l1ToL2MessageSource: archiver,
|
|
471
|
+
telemetry,
|
|
472
|
+
dateProvider,
|
|
473
|
+
blobClient,
|
|
474
|
+
nodeKeyStore: keyStoreManager!,
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (!options.dontStartSequencer && sequencer) {
|
|
479
|
+
await sequencer.start();
|
|
480
|
+
log.verbose(`Sequencer started`);
|
|
481
|
+
} else if (sequencer) {
|
|
482
|
+
log.warn(`Sequencer created but not started`);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const globalVariableBuilder = new GlobalVariableBuilder({
|
|
486
|
+
...config,
|
|
487
|
+
rollupVersion: BigInt(config.rollupVersion),
|
|
488
|
+
l1GenesisTime,
|
|
489
|
+
slotDuration: Number(slotDuration),
|
|
490
|
+
});
|
|
210
491
|
|
|
211
492
|
return new AztecNodeService(
|
|
212
493
|
config,
|
|
@@ -215,15 +496,20 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
215
496
|
archiver,
|
|
216
497
|
archiver,
|
|
217
498
|
archiver,
|
|
218
|
-
archiver,
|
|
219
499
|
worldStateSynchronizer,
|
|
220
500
|
sequencer,
|
|
501
|
+
slasherClient,
|
|
502
|
+
validatorsSentinel,
|
|
503
|
+
epochPruneWatcher,
|
|
221
504
|
ethereumChain.chainInfo.id,
|
|
222
|
-
config.
|
|
223
|
-
|
|
505
|
+
config.rollupVersion,
|
|
506
|
+
globalVariableBuilder,
|
|
507
|
+
epochCache,
|
|
508
|
+
packageVersion,
|
|
224
509
|
proofVerifier,
|
|
225
510
|
telemetry,
|
|
226
511
|
log,
|
|
512
|
+
blobClient,
|
|
227
513
|
);
|
|
228
514
|
}
|
|
229
515
|
|
|
@@ -259,6 +545,10 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
259
545
|
return Promise.resolve(this.p2pClient.getEnr()?.encodeTxt());
|
|
260
546
|
}
|
|
261
547
|
|
|
548
|
+
public async getAllowedPublicSetup(): Promise<AllowedElement[]> {
|
|
549
|
+
return this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
|
|
550
|
+
}
|
|
551
|
+
|
|
262
552
|
/**
|
|
263
553
|
* Method to determine if the node is ready to accept transactions.
|
|
264
554
|
* @returns - Flag indicating the readiness for tx submission.
|
|
@@ -268,20 +558,19 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
268
558
|
}
|
|
269
559
|
|
|
270
560
|
public async getNodeInfo(): Promise<NodeInfo> {
|
|
271
|
-
const [nodeVersion,
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
]);
|
|
561
|
+
const [nodeVersion, rollupVersion, chainId, enr, contractAddresses, protocolContractAddresses] = await Promise.all([
|
|
562
|
+
this.getNodeVersion(),
|
|
563
|
+
this.getVersion(),
|
|
564
|
+
this.getChainId(),
|
|
565
|
+
this.getEncodedEnr(),
|
|
566
|
+
this.getL1ContractAddresses(),
|
|
567
|
+
this.getProtocolContractAddresses(),
|
|
568
|
+
]);
|
|
280
569
|
|
|
281
570
|
const nodeInfo: NodeInfo = {
|
|
282
571
|
nodeVersion,
|
|
283
572
|
l1ChainId: chainId,
|
|
284
|
-
|
|
573
|
+
rollupVersion,
|
|
285
574
|
enr,
|
|
286
575
|
l1ContractAddresses: contractAddresses,
|
|
287
576
|
protocolContractAddresses: protocolContractAddresses,
|
|
@@ -295,8 +584,29 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
295
584
|
* @param number - The block number being requested.
|
|
296
585
|
* @returns The requested block.
|
|
297
586
|
*/
|
|
298
|
-
public async getBlock(number:
|
|
299
|
-
|
|
587
|
+
public async getBlock(number: BlockParameter): Promise<L2Block | undefined> {
|
|
588
|
+
const blockNumber = number === 'latest' ? await this.getBlockNumber() : (number as BlockNumber);
|
|
589
|
+
return await this.blockSource.getBlock(blockNumber);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Get a block specified by its hash.
|
|
594
|
+
* @param blockHash - The block hash being requested.
|
|
595
|
+
* @returns The requested block.
|
|
596
|
+
*/
|
|
597
|
+
public async getBlockByHash(blockHash: Fr): Promise<L2Block | undefined> {
|
|
598
|
+
const publishedBlock = await this.blockSource.getPublishedBlockByHash(blockHash);
|
|
599
|
+
return publishedBlock?.block;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Get a block specified by its archive root.
|
|
604
|
+
* @param archive - The archive root being requested.
|
|
605
|
+
* @returns The requested block.
|
|
606
|
+
*/
|
|
607
|
+
public async getBlockByArchive(archive: Fr): Promise<L2Block | undefined> {
|
|
608
|
+
const publishedBlock = await this.blockSource.getPublishedBlockByArchive(archive);
|
|
609
|
+
return publishedBlock?.block;
|
|
300
610
|
}
|
|
301
611
|
|
|
302
612
|
/**
|
|
@@ -305,27 +615,51 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
305
615
|
* @param limit - The maximum number of blocks to obtain.
|
|
306
616
|
* @returns The blocks requested.
|
|
307
617
|
*/
|
|
308
|
-
public async getBlocks(from:
|
|
618
|
+
public async getBlocks(from: BlockNumber, limit: number): Promise<L2Block[]> {
|
|
309
619
|
return (await this.blockSource.getBlocks(from, limit)) ?? [];
|
|
310
620
|
}
|
|
311
621
|
|
|
622
|
+
public async getPublishedBlocks(from: BlockNumber, limit: number): Promise<PublishedL2Block[]> {
|
|
623
|
+
return (await this.blockSource.getPublishedBlocks(from, limit)) ?? [];
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
public async getPublishedCheckpoints(from: CheckpointNumber, limit: number): Promise<PublishedCheckpoint[]> {
|
|
627
|
+
return (await this.blockSource.getPublishedCheckpoints(from, limit)) ?? [];
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
public async getL2BlocksNew(from: BlockNumber, limit: number): Promise<L2BlockNew[]> {
|
|
631
|
+
return (await this.blockSource.getL2BlocksNew(from, limit)) ?? [];
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
public async getCheckpointedBlocks(from: BlockNumber, limit: number, proven?: boolean) {
|
|
635
|
+
return (await this.blockSource.getCheckpointedBlocks(from, limit, proven)) ?? [];
|
|
636
|
+
}
|
|
637
|
+
|
|
312
638
|
/**
|
|
313
|
-
* Method to fetch the current
|
|
314
|
-
* @returns The current
|
|
639
|
+
* Method to fetch the current min L2 fees.
|
|
640
|
+
* @returns The current min L2 fees.
|
|
315
641
|
*/
|
|
316
|
-
public async
|
|
317
|
-
return await this.globalVariableBuilder.
|
|
642
|
+
public async getCurrentMinFees(): Promise<GasFees> {
|
|
643
|
+
return await this.globalVariableBuilder.getCurrentMinFees();
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
public async getMaxPriorityFees(): Promise<GasFees> {
|
|
647
|
+
for await (const tx of this.p2pClient.iteratePendingTxs()) {
|
|
648
|
+
return tx.getGasSettings().maxPriorityFeesPerGas;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
return GasFees.from({ feePerDaGas: 0n, feePerL2Gas: 0n });
|
|
318
652
|
}
|
|
319
653
|
|
|
320
654
|
/**
|
|
321
|
-
* Method to fetch the
|
|
655
|
+
* Method to fetch the latest block number synchronized by the node.
|
|
322
656
|
* @returns The block number.
|
|
323
657
|
*/
|
|
324
|
-
public async getBlockNumber(): Promise<
|
|
658
|
+
public async getBlockNumber(): Promise<BlockNumber> {
|
|
325
659
|
return await this.blockSource.getBlockNumber();
|
|
326
660
|
}
|
|
327
661
|
|
|
328
|
-
public async getProvenBlockNumber(): Promise<
|
|
662
|
+
public async getProvenBlockNumber(): Promise<BlockNumber> {
|
|
329
663
|
return await this.blockSource.getProvenBlockNumber();
|
|
330
664
|
}
|
|
331
665
|
|
|
@@ -353,49 +687,20 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
353
687
|
return Promise.resolve(this.l1ChainId);
|
|
354
688
|
}
|
|
355
689
|
|
|
356
|
-
public
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
// TODO(#10007): Remove this check. This is needed only because we're manually registering
|
|
360
|
-
// some contracts in the archiver so they are available to all nodes (see `registerCommonContracts`
|
|
361
|
-
// in `archiver/src/factory.ts`), but we still want clients to send the registration tx in order
|
|
362
|
-
// to emit the corresponding nullifier, which is now being checked. Note that this method
|
|
363
|
-
// is only called by the PXE to check if a contract is publicly registered.
|
|
364
|
-
if (klazz) {
|
|
365
|
-
const classNullifier = await siloNullifier(AztecAddress.fromNumber(REGISTERER_CONTRACT_ADDRESS), id);
|
|
366
|
-
const worldState = await this.#getWorldState('latest');
|
|
367
|
-
const [index] = await worldState.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [classNullifier.toBuffer()]);
|
|
368
|
-
this.log.debug(`Registration nullifier ${classNullifier} for contract class ${id} found at index ${index}`);
|
|
369
|
-
if (index === undefined) {
|
|
370
|
-
return undefined;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
return klazz;
|
|
690
|
+
public getContractClass(id: Fr): Promise<ContractClassPublic | undefined> {
|
|
691
|
+
return this.contractDataSource.getContractClass(id);
|
|
375
692
|
}
|
|
376
693
|
|
|
377
694
|
public getContract(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
|
|
378
695
|
return this.contractDataSource.getContract(address);
|
|
379
696
|
}
|
|
380
697
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
* @param from - The block number from which to begin retrieving logs.
|
|
384
|
-
* @param limit - The maximum number of blocks to retrieve logs from.
|
|
385
|
-
* @returns An array of private logs from the specified range of blocks.
|
|
386
|
-
*/
|
|
387
|
-
public getPrivateLogs(from: number, limit: number): Promise<PrivateLog[]> {
|
|
388
|
-
return this.logsSource.getPrivateLogs(from, limit);
|
|
698
|
+
public getPrivateLogsByTags(tags: SiloedTag[]): Promise<TxScopedL2Log[][]> {
|
|
699
|
+
return this.logsSource.getPrivateLogsByTags(tags);
|
|
389
700
|
}
|
|
390
701
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
* @param tags - The tags to filter the logs by.
|
|
394
|
-
* @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
|
|
395
|
-
* that tag.
|
|
396
|
-
*/
|
|
397
|
-
public getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
|
|
398
|
-
return this.logsSource.getLogsByTags(tags);
|
|
702
|
+
public getPublicLogsByTagsFromContract(contractAddress: AztecAddress, tags: Tag[]): Promise<TxScopedL2Log[][]> {
|
|
703
|
+
return this.logsSource.getPublicLogsByTagsFromContract(contractAddress, tags);
|
|
399
704
|
}
|
|
400
705
|
|
|
401
706
|
/**
|
|
@@ -421,17 +726,19 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
421
726
|
* @param tx - The transaction to be submitted.
|
|
422
727
|
*/
|
|
423
728
|
public async sendTx(tx: Tx) {
|
|
729
|
+
await this.#sendTx(tx);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
async #sendTx(tx: Tx) {
|
|
424
733
|
const timer = new Timer();
|
|
425
|
-
const txHash =
|
|
734
|
+
const txHash = tx.getTxHash().toString();
|
|
426
735
|
|
|
427
736
|
const valid = await this.isValidTx(tx);
|
|
428
737
|
if (valid.result !== 'valid') {
|
|
429
738
|
const reason = valid.reason.join(', ');
|
|
430
739
|
this.metrics.receivedTx(timer.ms(), false);
|
|
431
|
-
this.log.warn(`
|
|
432
|
-
|
|
433
|
-
// throw new Error(`Invalid tx: ${reason}`);
|
|
434
|
-
return;
|
|
740
|
+
this.log.warn(`Received invalid tx ${txHash}: ${reason}`, { txHash });
|
|
741
|
+
throw new Error(`Invalid tx: ${reason}`);
|
|
435
742
|
}
|
|
436
743
|
|
|
437
744
|
await this.p2pClient!.sendTx(tx);
|
|
@@ -457,7 +764,7 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
457
764
|
return txReceipt;
|
|
458
765
|
}
|
|
459
766
|
|
|
460
|
-
public getTxEffect(txHash: TxHash): Promise<
|
|
767
|
+
public getTxEffect(txHash: TxHash): Promise<IndexedTxEffect | undefined> {
|
|
461
768
|
return this.blockSource.getTxEffect(txHash);
|
|
462
769
|
}
|
|
463
770
|
|
|
@@ -465,89 +772,129 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
465
772
|
* Method to stop the aztec node.
|
|
466
773
|
*/
|
|
467
774
|
public async stop() {
|
|
468
|
-
this.log.info(`Stopping`);
|
|
469
|
-
await this.
|
|
470
|
-
await this.
|
|
471
|
-
await this.
|
|
775
|
+
this.log.info(`Stopping Aztec Node`);
|
|
776
|
+
await tryStop(this.validatorsSentinel);
|
|
777
|
+
await tryStop(this.epochPruneWatcher);
|
|
778
|
+
await tryStop(this.slasherClient);
|
|
779
|
+
await tryStop(this.proofVerifier);
|
|
780
|
+
await tryStop(this.sequencer);
|
|
781
|
+
await tryStop(this.p2pClient);
|
|
782
|
+
await tryStop(this.worldStateSynchronizer);
|
|
472
783
|
await tryStop(this.blockSource);
|
|
473
|
-
await this.
|
|
474
|
-
this.
|
|
784
|
+
await tryStop(this.blobClient);
|
|
785
|
+
await tryStop(this.telemetry);
|
|
786
|
+
this.log.info(`Stopped Aztec Node`);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/**
|
|
790
|
+
* Returns the blob client used by this node.
|
|
791
|
+
* @internal - Exposed for testing purposes only.
|
|
792
|
+
*/
|
|
793
|
+
public getBlobClient(): BlobClientInterface | undefined {
|
|
794
|
+
return this.blobClient;
|
|
475
795
|
}
|
|
476
796
|
|
|
477
797
|
/**
|
|
478
798
|
* Method to retrieve pending txs.
|
|
799
|
+
* @param limit - The number of items to returns
|
|
800
|
+
* @param after - The last known pending tx. Used for pagination
|
|
479
801
|
* @returns - The pending txs.
|
|
480
802
|
*/
|
|
481
|
-
public getPendingTxs() {
|
|
482
|
-
return this.p2pClient!.getPendingTxs();
|
|
803
|
+
public getPendingTxs(limit?: number, after?: TxHash): Promise<Tx[]> {
|
|
804
|
+
return this.p2pClient!.getPendingTxs(limit, after);
|
|
483
805
|
}
|
|
484
806
|
|
|
485
|
-
public
|
|
486
|
-
|
|
487
|
-
return pendingTxs.length;
|
|
807
|
+
public getPendingTxCount(): Promise<number> {
|
|
808
|
+
return this.p2pClient!.getPendingTxCount();
|
|
488
809
|
}
|
|
489
810
|
|
|
490
811
|
/**
|
|
491
|
-
* Method to retrieve a single tx from the mempool or
|
|
812
|
+
* Method to retrieve a single tx from the mempool or unfinalized chain.
|
|
492
813
|
* @param txHash - The transaction hash to return.
|
|
493
814
|
* @returns - The tx if it exists.
|
|
494
815
|
*/
|
|
495
|
-
public getTxByHash(txHash: TxHash) {
|
|
816
|
+
public getTxByHash(txHash: TxHash): Promise<Tx | undefined> {
|
|
496
817
|
return Promise.resolve(this.p2pClient!.getTxByHashFromPool(txHash));
|
|
497
818
|
}
|
|
498
819
|
|
|
499
820
|
/**
|
|
500
|
-
* Method to retrieve txs from the mempool or
|
|
821
|
+
* Method to retrieve txs from the mempool or unfinalized chain.
|
|
501
822
|
* @param txHash - The transaction hash to return.
|
|
502
823
|
* @returns - The txs if it exists.
|
|
503
824
|
*/
|
|
504
|
-
public async getTxsByHash(txHashes: TxHash[]) {
|
|
825
|
+
public async getTxsByHash(txHashes: TxHash[]): Promise<Tx[]> {
|
|
505
826
|
return compactArray(await Promise.all(txHashes.map(txHash => this.getTxByHash(txHash))));
|
|
506
827
|
}
|
|
507
828
|
|
|
508
829
|
/**
|
|
509
|
-
* Find the indexes of the given leaves in the given tree
|
|
510
|
-
*
|
|
830
|
+
* Find the indexes of the given leaves in the given tree along with a block metadata pointing to the block in which
|
|
831
|
+
* the leaves were inserted.
|
|
832
|
+
* @param blockNumber - The block number at which to get the data or 'latest' for latest data.
|
|
511
833
|
* @param treeId - The tree to search in.
|
|
512
|
-
* @param
|
|
513
|
-
* @returns The
|
|
834
|
+
* @param leafValues - The values to search for.
|
|
835
|
+
* @returns The indices of leaves and the block metadata of a block in which the leaves were inserted.
|
|
514
836
|
*/
|
|
515
837
|
public async findLeavesIndexes(
|
|
516
|
-
blockNumber:
|
|
838
|
+
blockNumber: BlockParameter,
|
|
517
839
|
treeId: MerkleTreeId,
|
|
518
840
|
leafValues: Fr[],
|
|
519
|
-
): Promise<(bigint | undefined)[]> {
|
|
841
|
+
): Promise<(DataInBlock<bigint> | undefined)[]> {
|
|
520
842
|
const committedDb = await this.#getWorldState(blockNumber);
|
|
521
|
-
|
|
843
|
+
const maybeIndices = await committedDb.findLeafIndices(
|
|
522
844
|
treeId,
|
|
523
845
|
leafValues.map(x => x.toBuffer()),
|
|
524
846
|
);
|
|
525
|
-
|
|
847
|
+
// We filter out undefined values
|
|
848
|
+
const indices = maybeIndices.filter(x => x !== undefined) as bigint[];
|
|
526
849
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
850
|
+
// Now we find the block numbers for the indices
|
|
851
|
+
const blockNumbers = await committedDb.getBlockNumbersForLeafIndices(treeId, indices);
|
|
852
|
+
|
|
853
|
+
// If any of the block numbers are undefined, we throw an error.
|
|
854
|
+
for (let i = 0; i < indices.length; i++) {
|
|
855
|
+
if (blockNumbers[i] === undefined) {
|
|
856
|
+
throw new Error(`Block number is undefined for leaf index ${indices[i]} in tree ${MerkleTreeId[treeId]}`);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// Get unique block numbers in order to optimize num calls to getLeafValue function.
|
|
861
|
+
const uniqueBlockNumbers = [...new Set(blockNumbers.filter(x => x !== undefined))];
|
|
862
|
+
|
|
863
|
+
// Now we obtain the block hashes from the archive tree by calling await `committedDb.getLeafValue(treeId, index)`
|
|
864
|
+
// (note that block number corresponds to the leaf index in the archive tree).
|
|
865
|
+
const blockHashes = await Promise.all(
|
|
866
|
+
uniqueBlockNumbers.map(blockNumber => {
|
|
867
|
+
return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber));
|
|
868
|
+
}),
|
|
869
|
+
);
|
|
542
870
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
blockNumber = await this.getBlockNumber();
|
|
871
|
+
// If any of the block hashes are undefined, we throw an error.
|
|
872
|
+
for (let i = 0; i < uniqueBlockNumbers.length; i++) {
|
|
873
|
+
if (blockHashes[i] === undefined) {
|
|
874
|
+
throw new Error(`Block hash is undefined for block number ${uniqueBlockNumbers[i]}`);
|
|
875
|
+
}
|
|
549
876
|
}
|
|
550
|
-
|
|
877
|
+
|
|
878
|
+
// Create DataInBlock objects by combining indices, blockNumbers and blockHashes and return them.
|
|
879
|
+
return maybeIndices.map((index, i) => {
|
|
880
|
+
if (index === undefined) {
|
|
881
|
+
return undefined;
|
|
882
|
+
}
|
|
883
|
+
const blockNumber = blockNumbers[i];
|
|
884
|
+
if (blockNumber === undefined) {
|
|
885
|
+
return undefined;
|
|
886
|
+
}
|
|
887
|
+
const blockHashIndex = uniqueBlockNumbers.indexOf(blockNumber);
|
|
888
|
+
const blockHash = blockHashes[blockHashIndex];
|
|
889
|
+
if (!blockHash) {
|
|
890
|
+
return undefined;
|
|
891
|
+
}
|
|
892
|
+
return {
|
|
893
|
+
l2BlockNumber: BlockNumber(Number(blockNumber)),
|
|
894
|
+
l2BlockHash: L2BlockHash.fromField(blockHash),
|
|
895
|
+
data: index,
|
|
896
|
+
};
|
|
897
|
+
});
|
|
551
898
|
}
|
|
552
899
|
|
|
553
900
|
/**
|
|
@@ -557,7 +904,7 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
557
904
|
* @returns The sibling path for the leaf index.
|
|
558
905
|
*/
|
|
559
906
|
public async getNullifierSiblingPath(
|
|
560
|
-
blockNumber:
|
|
907
|
+
blockNumber: BlockParameter,
|
|
561
908
|
leafIndex: bigint,
|
|
562
909
|
): Promise<SiblingPath<typeof NULLIFIER_TREE_HEIGHT>> {
|
|
563
910
|
const committedDb = await this.#getWorldState(blockNumber);
|
|
@@ -571,13 +918,38 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
571
918
|
* @returns The sibling path for the leaf index.
|
|
572
919
|
*/
|
|
573
920
|
public async getNoteHashSiblingPath(
|
|
574
|
-
blockNumber:
|
|
921
|
+
blockNumber: BlockParameter,
|
|
575
922
|
leafIndex: bigint,
|
|
576
923
|
): Promise<SiblingPath<typeof NOTE_HASH_TREE_HEIGHT>> {
|
|
577
924
|
const committedDb = await this.#getWorldState(blockNumber);
|
|
578
925
|
return committedDb.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
|
|
579
926
|
}
|
|
580
927
|
|
|
928
|
+
public async getArchiveMembershipWitness(
|
|
929
|
+
blockNumber: BlockParameter,
|
|
930
|
+
archive: Fr,
|
|
931
|
+
): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
|
|
932
|
+
const committedDb = await this.#getWorldState(blockNumber);
|
|
933
|
+
const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.ARCHIVE>(MerkleTreeId.ARCHIVE, [archive]);
|
|
934
|
+
return pathAndIndex === undefined
|
|
935
|
+
? undefined
|
|
936
|
+
: MembershipWitness.fromSiblingPath(pathAndIndex.index, pathAndIndex.path);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
public async getNoteHashMembershipWitness(
|
|
940
|
+
blockNumber: BlockParameter,
|
|
941
|
+
noteHash: Fr,
|
|
942
|
+
): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
|
|
943
|
+
const committedDb = await this.#getWorldState(blockNumber);
|
|
944
|
+
const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.NOTE_HASH_TREE>(
|
|
945
|
+
MerkleTreeId.NOTE_HASH_TREE,
|
|
946
|
+
[noteHash],
|
|
947
|
+
);
|
|
948
|
+
return pathAndIndex === undefined
|
|
949
|
+
? undefined
|
|
950
|
+
: MembershipWitness.fromSiblingPath(pathAndIndex.index, pathAndIndex.path);
|
|
951
|
+
}
|
|
952
|
+
|
|
581
953
|
/**
|
|
582
954
|
* Returns the index and a sibling path for a leaf in the committed l1 to l2 data tree.
|
|
583
955
|
* @param blockNumber - The block number at which to get the data.
|
|
@@ -585,19 +957,24 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
585
957
|
* @returns A tuple of the index and the sibling path of the L1ToL2Message (undefined if not found).
|
|
586
958
|
*/
|
|
587
959
|
public async getL1ToL2MessageMembershipWitness(
|
|
588
|
-
blockNumber:
|
|
960
|
+
blockNumber: BlockParameter,
|
|
589
961
|
l1ToL2Message: Fr,
|
|
590
962
|
): Promise<[bigint, SiblingPath<typeof L1_TO_L2_MSG_TREE_HEIGHT>] | undefined> {
|
|
591
|
-
const
|
|
592
|
-
|
|
963
|
+
const db = await this.#getWorldState(blockNumber);
|
|
964
|
+
const [witness] = await db.findSiblingPaths(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, [l1ToL2Message]);
|
|
965
|
+
if (!witness) {
|
|
593
966
|
return undefined;
|
|
594
967
|
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
968
|
+
|
|
969
|
+
// REFACTOR: Return a MembershipWitness object
|
|
970
|
+
return [witness.index, witness.path];
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
public async getL1ToL2MessageBlock(l1ToL2Message: Fr): Promise<BlockNumber | undefined> {
|
|
974
|
+
const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
|
|
975
|
+
return messageIndex
|
|
976
|
+
? BlockNumber.fromCheckpointNumber(InboxLeaf.checkpointNumberFromIndex(messageIndex))
|
|
977
|
+
: undefined;
|
|
601
978
|
}
|
|
602
979
|
|
|
603
980
|
/**
|
|
@@ -606,89 +983,33 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
606
983
|
* @returns Whether the message is synced and ready to be included in a block.
|
|
607
984
|
*/
|
|
608
985
|
public async isL1ToL2MessageSynced(l1ToL2Message: Fr): Promise<boolean> {
|
|
609
|
-
|
|
986
|
+
const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
|
|
987
|
+
return messageIndex !== undefined;
|
|
610
988
|
}
|
|
611
989
|
|
|
612
990
|
/**
|
|
613
|
-
* Returns the
|
|
614
|
-
* @
|
|
615
|
-
*
|
|
616
|
-
* The tree is discarded immediately after calculating what we need from it.
|
|
617
|
-
* TODO: Handle the case where two messages in the same tx have the same hash.
|
|
618
|
-
* @param blockNumber - The block number at which to get the data.
|
|
619
|
-
* @param l2ToL1Message - The l2ToL1Message get the index / sibling path for.
|
|
620
|
-
* @returns A tuple of the index and the sibling path of the L2ToL1Message.
|
|
991
|
+
* Returns all the L2 to L1 messages in an epoch.
|
|
992
|
+
* @param epoch - The epoch at which to get the data.
|
|
993
|
+
* @returns The L2 to L1 messages (empty array if the epoch is not found).
|
|
621
994
|
*/
|
|
622
|
-
public async
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
const indexOfMsgTx = l2ToL1Messages.findIndex(msgs => {
|
|
637
|
-
const idx = msgs.findIndex(msg => msg.equals(l2ToL1Message));
|
|
638
|
-
indexOfMsgInSubtree = Math.max(indexOfMsgInSubtree, idx);
|
|
639
|
-
return idx !== -1;
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
if (indexOfMsgTx === -1) {
|
|
643
|
-
throw new Error('The L2ToL1Message you are trying to prove inclusion of does not exist');
|
|
995
|
+
public async getL2ToL1Messages(epoch: EpochNumber): Promise<Fr[][][][]> {
|
|
996
|
+
// Assumes `getBlocksForEpoch` returns blocks in ascending order of block number.
|
|
997
|
+
const blocks = await this.blockSource.getBlocksForEpoch(epoch);
|
|
998
|
+
const blocksInCheckpoints: L2Block[][] = [];
|
|
999
|
+
let previousSlotNumber = SlotNumber.ZERO;
|
|
1000
|
+
let checkpointIndex = -1;
|
|
1001
|
+
for (const block of blocks) {
|
|
1002
|
+
const slotNumber = block.header.globalVariables.slotNumber;
|
|
1003
|
+
if (slotNumber !== previousSlotNumber) {
|
|
1004
|
+
checkpointIndex++;
|
|
1005
|
+
blocksInCheckpoints.push([]);
|
|
1006
|
+
previousSlotNumber = slotNumber;
|
|
1007
|
+
}
|
|
1008
|
+
blocksInCheckpoints[checkpointIndex].push(block);
|
|
644
1009
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
// Construct message subtrees
|
|
649
|
-
const l2toL1Subtrees = await Promise.all(
|
|
650
|
-
l2ToL1Messages.map(async (msgs, i) => {
|
|
651
|
-
const store = openTmpStore(true);
|
|
652
|
-
tempStores.push(store);
|
|
653
|
-
const treeHeight = msgs.length <= 1 ? 1 : Math.ceil(Math.log2(msgs.length));
|
|
654
|
-
const tree = new StandardTree(store, new SHA256Trunc(), `temp_msgs_subtrees_${i}`, treeHeight, 0n, Fr);
|
|
655
|
-
await tree.appendLeaves(msgs);
|
|
656
|
-
return tree;
|
|
657
|
-
}),
|
|
1010
|
+
return blocksInCheckpoints.map(blocks =>
|
|
1011
|
+
blocks.map(block => block.body.txEffects.map(txEffect => txEffect.l2ToL1Msgs)),
|
|
658
1012
|
);
|
|
659
|
-
|
|
660
|
-
// path of the input msg from leaf -> first out hash calculated in base rolllup
|
|
661
|
-
const subtreePathOfL2ToL1Message = await l2toL1Subtrees[indexOfMsgTx].getSiblingPath(
|
|
662
|
-
BigInt(indexOfMsgInSubtree),
|
|
663
|
-
true,
|
|
664
|
-
);
|
|
665
|
-
|
|
666
|
-
const numTxs = block.body.txEffects.length;
|
|
667
|
-
if (numTxs === 1) {
|
|
668
|
-
return [BigInt(indexOfMsgInSubtree), subtreePathOfL2ToL1Message];
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
const l2toL1SubtreeRoots = l2toL1Subtrees.map(t => Fr.fromBuffer(t.getRoot(true)));
|
|
672
|
-
const maxTreeHeight = Math.ceil(Math.log2(l2toL1SubtreeRoots.length));
|
|
673
|
-
// The root of this tree is the out_hash calculated in Noir => we truncate to match Noir's SHA
|
|
674
|
-
const outHashTree = new UnbalancedTree(new SHA256Trunc(), 'temp_outhash_sibling_path', maxTreeHeight, Fr);
|
|
675
|
-
await outHashTree.appendLeaves(l2toL1SubtreeRoots);
|
|
676
|
-
|
|
677
|
-
const pathOfTxInOutHashTree = await outHashTree.getSiblingPath(l2toL1SubtreeRoots[indexOfMsgTx].toBigInt());
|
|
678
|
-
// Append subtree path to out hash tree path
|
|
679
|
-
const mergedPath = subtreePathOfL2ToL1Message.toBufferArray().concat(pathOfTxInOutHashTree.toBufferArray());
|
|
680
|
-
// Append binary index of subtree path to binary index of out hash tree path
|
|
681
|
-
const mergedIndex = parseInt(
|
|
682
|
-
indexOfMsgTx
|
|
683
|
-
.toString(2)
|
|
684
|
-
.concat(indexOfMsgInSubtree.toString(2).padStart(l2toL1Subtrees[indexOfMsgTx].getDepth(), '0')),
|
|
685
|
-
2,
|
|
686
|
-
);
|
|
687
|
-
|
|
688
|
-
// clear the tmp stores
|
|
689
|
-
await Promise.all(tempStores.map(store => store.delete()));
|
|
690
|
-
|
|
691
|
-
return [BigInt(mergedIndex), new SiblingPath(mergedPath.length, mergedPath)];
|
|
692
1013
|
}
|
|
693
1014
|
|
|
694
1015
|
/**
|
|
@@ -698,7 +1019,7 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
698
1019
|
* @returns The sibling path.
|
|
699
1020
|
*/
|
|
700
1021
|
public async getArchiveSiblingPath(
|
|
701
|
-
blockNumber:
|
|
1022
|
+
blockNumber: BlockParameter,
|
|
702
1023
|
leafIndex: bigint,
|
|
703
1024
|
): Promise<SiblingPath<typeof ARCHIVE_HEIGHT>> {
|
|
704
1025
|
const committedDb = await this.#getWorldState(blockNumber);
|
|
@@ -712,7 +1033,7 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
712
1033
|
* @returns The sibling path.
|
|
713
1034
|
*/
|
|
714
1035
|
public async getPublicDataSiblingPath(
|
|
715
|
-
blockNumber:
|
|
1036
|
+
blockNumber: BlockParameter,
|
|
716
1037
|
leafIndex: bigint,
|
|
717
1038
|
): Promise<SiblingPath<typeof PUBLIC_DATA_TREE_HEIGHT>> {
|
|
718
1039
|
const committedDb = await this.#getWorldState(blockNumber);
|
|
@@ -726,28 +1047,22 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
726
1047
|
* @returns The nullifier membership witness (if found).
|
|
727
1048
|
*/
|
|
728
1049
|
public async getNullifierMembershipWitness(
|
|
729
|
-
blockNumber:
|
|
1050
|
+
blockNumber: BlockParameter,
|
|
730
1051
|
nullifier: Fr,
|
|
731
1052
|
): Promise<NullifierMembershipWitness | undefined> {
|
|
732
1053
|
const db = await this.#getWorldState(blockNumber);
|
|
733
|
-
const
|
|
734
|
-
if (!
|
|
1054
|
+
const [witness] = await db.findSiblingPaths(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]);
|
|
1055
|
+
if (!witness) {
|
|
735
1056
|
return undefined;
|
|
736
1057
|
}
|
|
737
1058
|
|
|
738
|
-
const
|
|
739
|
-
const
|
|
740
|
-
MerkleTreeId.NULLIFIER_TREE,
|
|
741
|
-
BigInt(index),
|
|
742
|
-
);
|
|
743
|
-
|
|
744
|
-
const [leafPreimage, siblingPath] = await Promise.all([leafPreimagePromise, siblingPathPromise]);
|
|
745
|
-
|
|
1059
|
+
const { index, path } = witness;
|
|
1060
|
+
const leafPreimage = await db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
|
|
746
1061
|
if (!leafPreimage) {
|
|
747
1062
|
return undefined;
|
|
748
1063
|
}
|
|
749
1064
|
|
|
750
|
-
return new NullifierMembershipWitness(
|
|
1065
|
+
return new NullifierMembershipWitness(index, leafPreimage as NullifierLeafPreimage, path);
|
|
751
1066
|
}
|
|
752
1067
|
|
|
753
1068
|
/**
|
|
@@ -765,7 +1080,7 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
765
1080
|
* TODO: This is a confusing behavior and we should eventually address that.
|
|
766
1081
|
*/
|
|
767
1082
|
public async getLowNullifierMembershipWitness(
|
|
768
|
-
blockNumber:
|
|
1083
|
+
blockNumber: BlockParameter,
|
|
769
1084
|
nullifier: Fr,
|
|
770
1085
|
): Promise<NullifierMembershipWitness | undefined> {
|
|
771
1086
|
const committedDb = await this.#getWorldState(blockNumber);
|
|
@@ -779,14 +1094,11 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
779
1094
|
}
|
|
780
1095
|
const preimageData = (await committedDb.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index))!;
|
|
781
1096
|
|
|
782
|
-
const siblingPath = await committedDb.getSiblingPath
|
|
783
|
-
MerkleTreeId.NULLIFIER_TREE,
|
|
784
|
-
BigInt(index),
|
|
785
|
-
);
|
|
1097
|
+
const siblingPath = await committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
|
|
786
1098
|
return new NullifierMembershipWitness(BigInt(index), preimageData as NullifierLeafPreimage, siblingPath);
|
|
787
1099
|
}
|
|
788
1100
|
|
|
789
|
-
async
|
|
1101
|
+
async getPublicDataWitness(blockNumber: BlockParameter, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
|
|
790
1102
|
const committedDb = await this.#getWorldState(blockNumber);
|
|
791
1103
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
792
1104
|
if (!lowLeafResult) {
|
|
@@ -796,10 +1108,7 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
796
1108
|
MerkleTreeId.PUBLIC_DATA_TREE,
|
|
797
1109
|
lowLeafResult.index,
|
|
798
1110
|
)) as PublicDataTreeLeafPreimage;
|
|
799
|
-
const path = await committedDb.getSiblingPath
|
|
800
|
-
MerkleTreeId.PUBLIC_DATA_TREE,
|
|
801
|
-
lowLeafResult.index,
|
|
802
|
-
);
|
|
1111
|
+
const path = await committedDb.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
|
|
803
1112
|
return new PublicDataWitness(lowLeafResult.index, preimage, path);
|
|
804
1113
|
}
|
|
805
1114
|
}
|
|
@@ -815,7 +1124,7 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
815
1124
|
* @param blockNumber - The block number at which to get the data or 'latest'.
|
|
816
1125
|
* @returns Storage value at the given contract slot.
|
|
817
1126
|
*/
|
|
818
|
-
public async getPublicStorageAt(blockNumber:
|
|
1127
|
+
public async getPublicStorageAt(blockNumber: BlockParameter, contract: AztecAddress, slot: Fr): Promise<Fr> {
|
|
819
1128
|
const committedDb = await this.#getWorldState(blockNumber);
|
|
820
1129
|
const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
|
|
821
1130
|
|
|
@@ -827,36 +1136,69 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
827
1136
|
MerkleTreeId.PUBLIC_DATA_TREE,
|
|
828
1137
|
lowLeafResult.index,
|
|
829
1138
|
)) as PublicDataTreeLeafPreimage;
|
|
830
|
-
return preimage.value;
|
|
1139
|
+
return preimage.leaf.value;
|
|
831
1140
|
}
|
|
832
1141
|
|
|
833
1142
|
/**
|
|
834
1143
|
* Returns the currently committed block header, or the initial header if no blocks have been produced.
|
|
835
1144
|
* @returns The current committed block header.
|
|
836
1145
|
*/
|
|
837
|
-
public async getBlockHeader(blockNumber:
|
|
838
|
-
return blockNumber ===
|
|
1146
|
+
public async getBlockHeader(blockNumber: BlockParameter = 'latest'): Promise<BlockHeader | undefined> {
|
|
1147
|
+
return blockNumber === BlockNumber.ZERO ||
|
|
1148
|
+
(blockNumber === 'latest' && (await this.blockSource.getBlockNumber()) === BlockNumber.ZERO)
|
|
839
1149
|
? this.worldStateSynchronizer.getCommitted().getInitialHeader()
|
|
840
|
-
: this.blockSource.getBlockHeader(blockNumber);
|
|
1150
|
+
: this.blockSource.getBlockHeader(blockNumber === 'latest' ? blockNumber : (blockNumber as BlockNumber));
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
/**
|
|
1154
|
+
* Get a block header specified by its hash.
|
|
1155
|
+
* @param blockHash - The block hash being requested.
|
|
1156
|
+
* @returns The requested block header.
|
|
1157
|
+
*/
|
|
1158
|
+
public async getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
|
|
1159
|
+
return await this.blockSource.getBlockHeaderByHash(blockHash);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* Get a block header specified by its archive root.
|
|
1164
|
+
* @param archive - The archive root being requested.
|
|
1165
|
+
* @returns The requested block header.
|
|
1166
|
+
*/
|
|
1167
|
+
public async getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined> {
|
|
1168
|
+
return await this.blockSource.getBlockHeaderByArchive(archive);
|
|
841
1169
|
}
|
|
842
1170
|
|
|
843
1171
|
/**
|
|
844
1172
|
* Simulates the public part of a transaction with the current state.
|
|
845
1173
|
* @param tx - The transaction to simulate.
|
|
846
1174
|
**/
|
|
847
|
-
@trackSpan('AztecNodeService.simulatePublicCalls',
|
|
848
|
-
[Attributes.TX_HASH]:
|
|
1175
|
+
@trackSpan('AztecNodeService.simulatePublicCalls', (tx: Tx) => ({
|
|
1176
|
+
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
849
1177
|
}))
|
|
850
1178
|
public async simulatePublicCalls(tx: Tx, skipFeeEnforcement = false): Promise<PublicSimulationOutput> {
|
|
851
|
-
|
|
852
|
-
const
|
|
1179
|
+
// Check total gas limit for simulation
|
|
1180
|
+
const gasSettings = tx.data.constants.txContext.gasSettings;
|
|
1181
|
+
const txGasLimit = gasSettings.gasLimits.l2Gas;
|
|
1182
|
+
const teardownGasLimit = gasSettings.teardownGasLimits.l2Gas;
|
|
1183
|
+
if (txGasLimit + teardownGasLimit > this.config.rpcSimulatePublicMaxGasLimit) {
|
|
1184
|
+
throw new BadRequestError(
|
|
1185
|
+
`Transaction total gas limit ${
|
|
1186
|
+
txGasLimit + teardownGasLimit
|
|
1187
|
+
} (${txGasLimit} + ${teardownGasLimit}) exceeds maximum gas limit ${
|
|
1188
|
+
this.config.rpcSimulatePublicMaxGasLimit
|
|
1189
|
+
} for simulation`,
|
|
1190
|
+
);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
const txHash = tx.getTxHash();
|
|
1194
|
+
const blockNumber = BlockNumber((await this.blockSource.getBlockNumber()) + 1);
|
|
853
1195
|
|
|
854
1196
|
// If sequencer is not initialized, we just set these values to zero for simulation.
|
|
855
|
-
const coinbase =
|
|
856
|
-
const feeRecipient =
|
|
1197
|
+
const coinbase = EthAddress.ZERO;
|
|
1198
|
+
const feeRecipient = AztecAddress.ZERO;
|
|
857
1199
|
|
|
858
1200
|
const newGlobalVariables = await this.globalVariableBuilder.buildGlobalVariables(
|
|
859
|
-
|
|
1201
|
+
blockNumber,
|
|
860
1202
|
coinbase,
|
|
861
1203
|
feeRecipient,
|
|
862
1204
|
);
|
|
@@ -865,7 +1207,6 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
865
1207
|
new DateProvider(),
|
|
866
1208
|
this.telemetry,
|
|
867
1209
|
);
|
|
868
|
-
const fork = await this.worldStateSynchronizer.fork();
|
|
869
1210
|
|
|
870
1211
|
this.log.verbose(`Simulating public calls for tx ${txHash}`, {
|
|
871
1212
|
globalVariables: newGlobalVariables.toInspect(),
|
|
@@ -873,11 +1214,22 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
873
1214
|
blockNumber,
|
|
874
1215
|
});
|
|
875
1216
|
|
|
1217
|
+
const merkleTreeFork = await this.worldStateSynchronizer.fork();
|
|
876
1218
|
try {
|
|
877
|
-
const
|
|
1219
|
+
const config = PublicSimulatorConfig.from({
|
|
1220
|
+
skipFeeEnforcement,
|
|
1221
|
+
collectDebugLogs: true,
|
|
1222
|
+
collectHints: false,
|
|
1223
|
+
collectCallMetadata: true,
|
|
1224
|
+
collectStatistics: false,
|
|
1225
|
+
collectionLimits: CollectionLimitsConfig.from({
|
|
1226
|
+
maxDebugLogMemoryReads: this.config.rpcSimulatePublicMaxDebugLogMemoryReads,
|
|
1227
|
+
}),
|
|
1228
|
+
});
|
|
1229
|
+
const processor = publicProcessorFactory.create(merkleTreeFork, newGlobalVariables, config);
|
|
878
1230
|
|
|
879
1231
|
// REFACTOR: Consider merging ProcessReturnValues into ProcessedTx
|
|
880
|
-
const [processedTxs, failedTxs, returns] = await processor.process([tx]);
|
|
1232
|
+
const [processedTxs, failedTxs, _usedTxs, returns] = await processor.process([tx]);
|
|
881
1233
|
// REFACTOR: Consider returning the error rather than throwing
|
|
882
1234
|
if (failedTxs.length) {
|
|
883
1235
|
this.log.warn(`Simulated tx ${txHash} fails: ${failedTxs[0].error}`, { txHash });
|
|
@@ -887,13 +1239,13 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
887
1239
|
const [processedTx] = processedTxs;
|
|
888
1240
|
return new PublicSimulationOutput(
|
|
889
1241
|
processedTx.revertReason,
|
|
890
|
-
processedTx.
|
|
1242
|
+
processedTx.globalVariables,
|
|
891
1243
|
processedTx.txEffect,
|
|
892
1244
|
returns,
|
|
893
1245
|
processedTx.gasUsed,
|
|
894
1246
|
);
|
|
895
1247
|
} finally {
|
|
896
|
-
await
|
|
1248
|
+
await merkleTreeFork.close();
|
|
897
1249
|
}
|
|
898
1250
|
}
|
|
899
1251
|
|
|
@@ -901,24 +1253,42 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
901
1253
|
tx: Tx,
|
|
902
1254
|
{ isSimulation, skipFeeEnforcement }: { isSimulation?: boolean; skipFeeEnforcement?: boolean } = {},
|
|
903
1255
|
): Promise<TxValidationResult> {
|
|
904
|
-
const blockNumber = (await this.blockSource.getBlockNumber()) + 1;
|
|
905
1256
|
const db = this.worldStateSynchronizer.getCommitted();
|
|
906
1257
|
const verifier = isSimulation ? undefined : this.proofVerifier;
|
|
1258
|
+
|
|
1259
|
+
// We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
|
|
1260
|
+
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1261
|
+
const blockNumber = BlockNumber((await this.blockSource.getBlockNumber()) + 1);
|
|
907
1262
|
const validator = createValidatorForAcceptingTxs(db, this.contractDataSource, verifier, {
|
|
1263
|
+
timestamp: nextSlotTimestamp,
|
|
908
1264
|
blockNumber,
|
|
909
1265
|
l1ChainId: this.l1ChainId,
|
|
910
|
-
|
|
911
|
-
|
|
1266
|
+
rollupVersion: this.version,
|
|
1267
|
+
setupAllowList: this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions()),
|
|
1268
|
+
gasFees: await this.getCurrentMinFees(),
|
|
912
1269
|
skipFeeEnforcement,
|
|
1270
|
+
txsPermitted: !this.config.disableTransactions,
|
|
913
1271
|
});
|
|
914
1272
|
|
|
915
1273
|
return await validator.validateTx(tx);
|
|
916
1274
|
}
|
|
917
1275
|
|
|
918
|
-
public
|
|
919
|
-
const
|
|
920
|
-
|
|
1276
|
+
public getConfig(): Promise<AztecNodeAdminConfig> {
|
|
1277
|
+
const schema = AztecNodeAdminConfigSchema;
|
|
1278
|
+
const keys = schema.keyof().options;
|
|
1279
|
+
return Promise.resolve(pick(this.config, ...keys));
|
|
1280
|
+
}
|
|
921
1281
|
|
|
1282
|
+
public async setConfig(config: Partial<AztecNodeAdminConfig>): Promise<void> {
|
|
1283
|
+
const newConfig = { ...this.config, ...config };
|
|
1284
|
+
this.sequencer?.updateConfig(config);
|
|
1285
|
+
this.slasherClient?.updateConfig(config);
|
|
1286
|
+
this.validatorsSentinel?.updateConfig(config);
|
|
1287
|
+
await this.p2pClient.updateP2PConfig(config);
|
|
1288
|
+
const archiver = this.blockSource as Archiver;
|
|
1289
|
+
if ('updateConfig' in archiver) {
|
|
1290
|
+
archiver.updateConfig(config);
|
|
1291
|
+
}
|
|
922
1292
|
if (newConfig.realProofs !== this.config.realProofs) {
|
|
923
1293
|
this.proofVerifier = config.realProofs ? await BBCircuitVerifier.new(newConfig) : new TestCircuitVerifier();
|
|
924
1294
|
}
|
|
@@ -928,42 +1298,151 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
928
1298
|
|
|
929
1299
|
public getProtocolContractAddresses(): Promise<ProtocolContractAddresses> {
|
|
930
1300
|
return Promise.resolve({
|
|
931
|
-
|
|
1301
|
+
classRegistry: ProtocolContractAddress.ContractClassRegistry,
|
|
932
1302
|
feeJuice: ProtocolContractAddress.FeeJuice,
|
|
933
|
-
|
|
1303
|
+
instanceRegistry: ProtocolContractAddress.ContractInstanceRegistry,
|
|
934
1304
|
multiCallEntrypoint: ProtocolContractAddress.MultiCallEntrypoint,
|
|
935
1305
|
});
|
|
936
1306
|
}
|
|
937
1307
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
1308
|
+
public registerContractFunctionSignatures(signatures: string[]): Promise<void> {
|
|
1309
|
+
return this.contractDataSource.registerContractFunctionSignatures(signatures);
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
public getValidatorsStats(): Promise<ValidatorsStats> {
|
|
1313
|
+
return this.validatorsSentinel?.computeStats() ?? Promise.resolve({ stats: {}, slotWindow: 0 });
|
|
942
1314
|
}
|
|
943
1315
|
|
|
944
|
-
public
|
|
945
|
-
|
|
1316
|
+
public getValidatorStats(
|
|
1317
|
+
validatorAddress: EthAddress,
|
|
1318
|
+
fromSlot?: SlotNumber,
|
|
1319
|
+
toSlot?: SlotNumber,
|
|
1320
|
+
): Promise<SingleValidatorStats | undefined> {
|
|
1321
|
+
return this.validatorsSentinel?.getValidatorStats(validatorAddress, fromSlot, toSlot) ?? Promise.resolve(undefined);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
public async startSnapshotUpload(location: string): Promise<void> {
|
|
1325
|
+
// Note that we are forcefully casting the blocksource as an archiver
|
|
1326
|
+
// We break support for archiver running remotely to the node
|
|
1327
|
+
const archiver = this.blockSource as Archiver;
|
|
1328
|
+
if (!('backupTo' in archiver)) {
|
|
1329
|
+
this.metrics.recordSnapshotError();
|
|
1330
|
+
throw new Error('Archiver implementation does not support backups. Cannot generate snapshot.');
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
// Test that the archiver has done an initial sync.
|
|
1334
|
+
if (!archiver.isInitialSyncComplete()) {
|
|
1335
|
+
this.metrics.recordSnapshotError();
|
|
1336
|
+
throw new Error(`Archiver initial sync not complete. Cannot start snapshot.`);
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// And it has an L2 block hash
|
|
1340
|
+
const l2BlockHash = await archiver.getL2Tips().then(tips => tips.proposed.hash);
|
|
1341
|
+
if (!l2BlockHash) {
|
|
1342
|
+
this.metrics.recordSnapshotError();
|
|
1343
|
+
throw new Error(`Archiver has no latest L2 block hash downloaded. Cannot start snapshot.`);
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
if (this.isUploadingSnapshot) {
|
|
1347
|
+
this.metrics.recordSnapshotError();
|
|
1348
|
+
throw new Error(`Snapshot upload already in progress. Cannot start another one until complete.`);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
// Do not wait for the upload to be complete to return to the caller, but flag that an operation is in progress
|
|
1352
|
+
this.isUploadingSnapshot = true;
|
|
1353
|
+
const timer = new Timer();
|
|
1354
|
+
void uploadSnapshot(location, this.blockSource as Archiver, this.worldStateSynchronizer, this.config, this.log)
|
|
1355
|
+
.then(() => {
|
|
1356
|
+
this.isUploadingSnapshot = false;
|
|
1357
|
+
this.metrics.recordSnapshot(timer.ms());
|
|
1358
|
+
})
|
|
1359
|
+
.catch(err => {
|
|
1360
|
+
this.isUploadingSnapshot = false;
|
|
1361
|
+
this.metrics.recordSnapshotError();
|
|
1362
|
+
this.log.error(`Error uploading snapshot: ${err}`);
|
|
1363
|
+
});
|
|
1364
|
+
|
|
1365
|
+
return Promise.resolve();
|
|
946
1366
|
}
|
|
947
1367
|
|
|
948
|
-
public
|
|
949
|
-
|
|
950
|
-
|
|
1368
|
+
public async rollbackTo(targetBlock: BlockNumber, force?: boolean): Promise<void> {
|
|
1369
|
+
const archiver = this.blockSource as Archiver;
|
|
1370
|
+
if (!('rollbackTo' in archiver)) {
|
|
1371
|
+
throw new Error('Archiver implementation does not support rollbacks.');
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
const finalizedBlock = await archiver.getL2Tips().then(tips => tips.finalized.block.number);
|
|
1375
|
+
if (targetBlock < finalizedBlock) {
|
|
1376
|
+
if (force) {
|
|
1377
|
+
this.log.warn(`Clearing world state database to allow rolling back behind finalized block ${finalizedBlock}`);
|
|
1378
|
+
await this.worldStateSynchronizer.clear();
|
|
1379
|
+
await this.p2pClient.clear();
|
|
1380
|
+
} else {
|
|
1381
|
+
throw new Error(`Cannot rollback to block ${targetBlock} as it is before finalized ${finalizedBlock}`);
|
|
1382
|
+
}
|
|
951
1383
|
}
|
|
952
|
-
|
|
1384
|
+
|
|
1385
|
+
try {
|
|
1386
|
+
this.log.info(`Pausing archiver and world state sync to start rollback`);
|
|
1387
|
+
await archiver.stop();
|
|
1388
|
+
await this.worldStateSynchronizer.stopSync();
|
|
1389
|
+
const currentBlock = await archiver.getBlockNumber();
|
|
1390
|
+
const blocksToUnwind = currentBlock - targetBlock;
|
|
1391
|
+
this.log.info(`Unwinding ${count(blocksToUnwind, 'block')} from L2 block ${currentBlock} to ${targetBlock}`);
|
|
1392
|
+
await archiver.rollbackTo(targetBlock);
|
|
1393
|
+
this.log.info(`Unwinding complete.`);
|
|
1394
|
+
} catch (err) {
|
|
1395
|
+
this.log.error(`Error during rollback`, err);
|
|
1396
|
+
throw err;
|
|
1397
|
+
} finally {
|
|
1398
|
+
this.log.info(`Resuming world state and archiver sync.`);
|
|
1399
|
+
this.worldStateSynchronizer.resumeSync();
|
|
1400
|
+
archiver.resume();
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
public async pauseSync(): Promise<void> {
|
|
1405
|
+
this.log.info(`Pausing archiver and world state sync`);
|
|
1406
|
+
await (this.blockSource as Archiver).stop();
|
|
1407
|
+
await this.worldStateSynchronizer.stopSync();
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
public resumeSync(): Promise<void> {
|
|
1411
|
+
this.log.info(`Resuming world state and archiver sync.`);
|
|
1412
|
+
this.worldStateSynchronizer.resumeSync();
|
|
1413
|
+
(this.blockSource as Archiver).resume();
|
|
953
1414
|
return Promise.resolve();
|
|
954
1415
|
}
|
|
955
1416
|
|
|
1417
|
+
public getSlashPayloads(): Promise<SlashPayloadRound[]> {
|
|
1418
|
+
if (!this.slasherClient) {
|
|
1419
|
+
throw new Error(`Slasher client not enabled`);
|
|
1420
|
+
}
|
|
1421
|
+
return this.slasherClient.getSlashPayloads();
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
public getSlashOffenses(round: bigint | 'all' | 'current'): Promise<Offense[]> {
|
|
1425
|
+
if (!this.slasherClient) {
|
|
1426
|
+
throw new Error(`Slasher client not enabled`);
|
|
1427
|
+
}
|
|
1428
|
+
if (round === 'all') {
|
|
1429
|
+
return this.slasherClient.getPendingOffenses();
|
|
1430
|
+
} else {
|
|
1431
|
+
return this.slasherClient.gatherOffensesForRound(round === 'current' ? undefined : BigInt(round));
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
|
|
956
1435
|
/**
|
|
957
1436
|
* Returns an instance of MerkleTreeOperations having first ensured the world state is fully synched
|
|
958
1437
|
* @param blockNumber - The block number at which to get the data.
|
|
959
1438
|
* @returns An instance of a committed MerkleTreeOperations
|
|
960
1439
|
*/
|
|
961
|
-
async #getWorldState(blockNumber:
|
|
1440
|
+
async #getWorldState(blockNumber: BlockParameter) {
|
|
962
1441
|
if (typeof blockNumber === 'number' && blockNumber < INITIAL_L2_BLOCK_NUM - 1) {
|
|
963
1442
|
throw new Error('Invalid block number to get world state for: ' + blockNumber);
|
|
964
1443
|
}
|
|
965
1444
|
|
|
966
|
-
let blockSyncedTo:
|
|
1445
|
+
let blockSyncedTo: BlockNumber = BlockNumber.ZERO;
|
|
967
1446
|
try {
|
|
968
1447
|
// Attempt to sync the world state if necessary
|
|
969
1448
|
blockSyncedTo = await this.#syncWorldState();
|
|
@@ -977,7 +1456,7 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
977
1456
|
return this.worldStateSynchronizer.getCommitted();
|
|
978
1457
|
} else if (blockNumber <= blockSyncedTo) {
|
|
979
1458
|
this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
|
|
980
|
-
return this.worldStateSynchronizer.getSnapshot(blockNumber);
|
|
1459
|
+
return this.worldStateSynchronizer.getSnapshot(blockNumber as BlockNumber);
|
|
981
1460
|
} else {
|
|
982
1461
|
throw new Error(`Block ${blockNumber} not yet synced`);
|
|
983
1462
|
}
|
|
@@ -987,8 +1466,8 @@ export class AztecNodeService implements AztecNode, Traceable {
|
|
|
987
1466
|
* Ensure we fully sync the world state
|
|
988
1467
|
* @returns A promise that fulfils once the world state is synced
|
|
989
1468
|
*/
|
|
990
|
-
async #syncWorldState(): Promise<
|
|
1469
|
+
async #syncWorldState(): Promise<BlockNumber> {
|
|
991
1470
|
const blockSourceHeight = await this.blockSource.getBlockNumber();
|
|
992
|
-
return this.worldStateSynchronizer.syncImmediate(blockSourceHeight);
|
|
1471
|
+
return await this.worldStateSynchronizer.syncImmediate(blockSourceHeight);
|
|
993
1472
|
}
|
|
994
1473
|
}
|