@aztec/aztec-node 0.76.4-devnet-test-rc3 → 0.77.0-testnet-ignition.17

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.
@@ -1,718 +1,724 @@
1
- import { __classPrivateFieldGet, __esDecorate, __runInitializers } from "tslib";
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
2
7
  import { createArchiver } from '@aztec/archiver';
3
8
  import { BBCircuitVerifier, TestCircuitVerifier } from '@aztec/bb-prover';
4
9
  import { createBlobSinkClient } from '@aztec/blob-sink/client';
5
- import { MerkleTreeId, NullifierMembershipWitness, P2PClientType, PublicDataWitness, PublicSimulationOutput, SiblingPath, TxReceipt, TxStatus, tryStop, } from '@aztec/circuit-types';
6
- import { EthAddress, Fr, INITIAL_L2_BLOCK_NUM, REGISTERER_CONTRACT_ADDRESS, } from '@aztec/circuits.js';
7
- import { computePublicDataTreeLeafSlot, siloNullifier } from '@aztec/circuits.js/hash';
10
+ import { INITIAL_L2_BLOCK_NUM, REGISTERER_CONTRACT_ADDRESS } from '@aztec/constants';
8
11
  import { EpochCache } from '@aztec/epoch-cache';
9
12
  import { createEthereumChain } from '@aztec/ethereum';
10
- import { AztecAddress } from '@aztec/foundation/aztec-address';
11
13
  import { compactArray } from '@aztec/foundation/collection';
14
+ import { EthAddress } from '@aztec/foundation/eth-address';
15
+ import { Fr } from '@aztec/foundation/fields';
12
16
  import { createLogger } from '@aztec/foundation/log';
13
17
  import { DateProvider, Timer } from '@aztec/foundation/timer';
18
+ import { SiblingPath } from '@aztec/foundation/trees';
14
19
  import { openTmpStore } from '@aztec/kv-store/lmdb';
15
20
  import { SHA256Trunc, StandardTree, UnbalancedTree } from '@aztec/merkle-tree';
16
21
  import { createP2PClient } from '@aztec/p2p';
17
22
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
18
- import { GlobalVariableBuilder, SequencerClient, createSlasherClient, createValidatorForAcceptingTxs, getDefaultAllowedSetupFunctions, } from '@aztec/sequencer-client';
23
+ import { GlobalVariableBuilder, SequencerClient, createSlasherClient, createValidatorForAcceptingTxs, getDefaultAllowedSetupFunctions } from '@aztec/sequencer-client';
19
24
  import { PublicProcessorFactory } from '@aztec/simulator/server';
20
- import { Attributes, getTelemetryClient, trackSpan, } from '@aztec/telemetry-client';
25
+ import { AztecAddress } from '@aztec/stdlib/aztec-address';
26
+ import { computePublicDataTreeLeafSlot, siloNullifier } from '@aztec/stdlib/hash';
27
+ import { tryStop } from '@aztec/stdlib/interfaces/server';
28
+ import { P2PClientType } from '@aztec/stdlib/p2p';
29
+ import { MerkleTreeId, NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
30
+ import { PublicSimulationOutput, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
31
+ import { Attributes, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
21
32
  import { createValidatorClient } from '@aztec/validator-client';
22
33
  import { createWorldStateSynchronizer } from '@aztec/world-state';
23
34
  import { getPackageInfo } from './config.js';
24
35
  import { NodeMetrics } from './node_metrics.js';
25
36
  /**
26
37
  * The aztec node.
27
- */
28
- let AztecNodeService = (() => {
29
- var _AztecNodeService_instances, _a, _AztecNodeService_getWorldState, _AztecNodeService_syncWorldState;
30
- let _instanceExtraInitializers = [];
31
- let _simulatePublicCalls_decorators;
32
- return _a = class AztecNodeService {
33
- constructor(config, p2pClient, blockSource, logsSource, contractDataSource, l1ToL2MessageSource, nullifierSource, worldStateSynchronizer, sequencer, l1ChainId, version, globalVariableBuilder, proofVerifier, telemetry = getTelemetryClient(), log = createLogger('node')) {
34
- _AztecNodeService_instances.add(this);
35
- this.config = (__runInitializers(this, _instanceExtraInitializers), config);
36
- this.p2pClient = p2pClient;
37
- this.blockSource = blockSource;
38
- this.logsSource = logsSource;
39
- this.contractDataSource = contractDataSource;
40
- this.l1ToL2MessageSource = l1ToL2MessageSource;
41
- this.nullifierSource = nullifierSource;
42
- this.worldStateSynchronizer = worldStateSynchronizer;
43
- this.sequencer = sequencer;
44
- this.l1ChainId = l1ChainId;
45
- this.version = version;
46
- this.globalVariableBuilder = globalVariableBuilder;
47
- this.proofVerifier = proofVerifier;
48
- this.telemetry = telemetry;
49
- this.log = log;
50
- this.packageVersion = getPackageInfo().version;
51
- this.metrics = new NodeMetrics(telemetry, 'AztecNodeService');
52
- this.tracer = telemetry.getTracer('AztecNodeService');
53
- this.log.info(`Aztec Node started on chain 0x${l1ChainId.toString(16)}`, config.l1Contracts);
54
- }
55
- addEpochProofQuote(quote) {
56
- return Promise.resolve(this.p2pClient.addEpochProofQuote(quote));
57
- }
58
- getEpochProofQuotes(epoch) {
59
- return this.p2pClient.getEpochProofQuotes(epoch);
60
- }
61
- getL2Tips() {
62
- return this.blockSource.getL2Tips();
63
- }
64
- /**
65
- * initializes the Aztec Node, wait for component to sync.
66
- * @param config - The configuration to be used by the aztec node.
67
- * @returns - A fully synced Aztec Node for use in development/testing.
68
- */
69
- static async createAndSync(config, deps = {}) {
70
- const telemetry = deps.telemetry ?? getTelemetryClient();
71
- const log = deps.logger ?? createLogger('node');
72
- const dateProvider = deps.dateProvider ?? new DateProvider();
73
- const blobSinkClient = deps.blobSinkClient ?? createBlobSinkClient(config);
74
- const ethereumChain = createEthereumChain(config.l1RpcUrl, config.l1ChainId);
75
- //validate that the actual chain id matches that specified in configuration
76
- if (config.l1ChainId !== ethereumChain.chainInfo.id) {
77
- throw new Error(`RPC URL configured for chain id ${ethereumChain.chainInfo.id} but expected id ${config.l1ChainId}`);
78
- }
79
- const archiver = await createArchiver(config, blobSinkClient, { blockUntilSync: true }, telemetry);
80
- // now create the merkle trees and the world state synchronizer
81
- const worldStateSynchronizer = await createWorldStateSynchronizer(config, archiver, telemetry);
82
- const proofVerifier = config.realProofs ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier();
83
- if (!config.realProofs) {
84
- log.warn(`Aztec node is accepting fake proofs`);
85
- }
86
- const epochCache = await EpochCache.create(config.l1Contracts.rollupAddress, config, { dateProvider });
87
- // create the tx pool and the p2p client, which will need the l2 block source
88
- const p2pClient = await createP2PClient(P2PClientType.Full, config, archiver, proofVerifier, worldStateSynchronizer, epochCache, telemetry);
89
- const slasherClient = await createSlasherClient(config, archiver, telemetry);
90
- // start both and wait for them to sync from the block source
91
- await Promise.all([p2pClient.start(), worldStateSynchronizer.start(), slasherClient.start()]);
92
- const validatorClient = createValidatorClient(config, { p2pClient, telemetry, dateProvider, epochCache });
93
- // now create the sequencer
94
- const sequencer = config.disableValidator
95
- ? undefined
96
- : await SequencerClient.new(config, {
97
- ...deps,
98
- validatorClient,
99
- p2pClient,
100
- worldStateSynchronizer,
101
- slasherClient,
102
- contractDataSource: archiver,
103
- l2BlockSource: archiver,
104
- l1ToL2MessageSource: archiver,
105
- telemetry,
106
- dateProvider,
107
- blobSinkClient,
108
- });
109
- return new _a(config, p2pClient, archiver, archiver, archiver, archiver, archiver, worldStateSynchronizer, sequencer, ethereumChain.chainInfo.id, config.version, new GlobalVariableBuilder(config), proofVerifier, telemetry, log);
110
- }
111
- /**
112
- * Returns the sequencer client instance.
113
- * @returns The sequencer client instance.
114
- */
115
- getSequencer() {
116
- return this.sequencer;
117
- }
118
- getBlockSource() {
119
- return this.blockSource;
120
- }
121
- getContractDataSource() {
122
- return this.contractDataSource;
123
- }
124
- getP2P() {
125
- return this.p2pClient;
126
- }
127
- /**
128
- * Method to return the currently deployed L1 contract addresses.
129
- * @returns - The currently deployed L1 contract addresses.
130
- */
131
- getL1ContractAddresses() {
132
- return Promise.resolve(this.config.l1Contracts);
133
- }
134
- getEncodedEnr() {
135
- return Promise.resolve(this.p2pClient.getEnr()?.encodeTxt());
136
- }
137
- /**
138
- * Method to determine if the node is ready to accept transactions.
139
- * @returns - Flag indicating the readiness for tx submission.
140
- */
141
- isReady() {
142
- return Promise.resolve(this.p2pClient.isReady() ?? false);
143
- }
144
- async getNodeInfo() {
145
- const [nodeVersion, protocolVersion, chainId, enr, contractAddresses, protocolContractAddresses] = await Promise.all([
146
- this.getNodeVersion(),
147
- this.getVersion(),
148
- this.getChainId(),
149
- this.getEncodedEnr(),
150
- this.getL1ContractAddresses(),
151
- this.getProtocolContractAddresses(),
152
- ]);
153
- const nodeInfo = {
154
- nodeVersion,
155
- l1ChainId: chainId,
156
- protocolVersion,
157
- enr,
158
- l1ContractAddresses: contractAddresses,
159
- protocolContractAddresses: protocolContractAddresses,
160
- };
161
- return nodeInfo;
162
- }
163
- /**
164
- * Get a block specified by its number.
165
- * @param number - The block number being requested.
166
- * @returns The requested block.
167
- */
168
- async getBlock(number) {
169
- return await this.blockSource.getBlock(number);
170
- }
171
- /**
172
- * Method to request blocks. Will attempt to return all requested blocks but will return only those available.
173
- * @param from - The start of the range of blocks to return.
174
- * @param limit - The maximum number of blocks to obtain.
175
- * @returns The blocks requested.
176
- */
177
- async getBlocks(from, limit) {
178
- return (await this.blockSource.getBlocks(from, limit)) ?? [];
179
- }
180
- /**
181
- * Method to fetch the current base fees.
182
- * @returns The current base fees.
183
- */
184
- async getCurrentBaseFees() {
185
- return await this.globalVariableBuilder.getCurrentBaseFees();
186
- }
187
- /**
188
- * Method to fetch the current block number.
189
- * @returns The block number.
190
- */
191
- async getBlockNumber() {
192
- return await this.blockSource.getBlockNumber();
193
- }
194
- async getProvenBlockNumber() {
195
- return await this.blockSource.getProvenBlockNumber();
196
- }
197
- /**
198
- * Method to fetch the version of the package.
199
- * @returns The node package version
200
- */
201
- getNodeVersion() {
202
- return Promise.resolve(this.packageVersion);
203
- }
204
- /**
205
- * Method to fetch the version of the rollup the node is connected to.
206
- * @returns The rollup version.
207
- */
208
- getVersion() {
209
- return Promise.resolve(this.version);
210
- }
211
- /**
212
- * Method to fetch the chain id of the base-layer for the rollup.
213
- * @returns The chain id.
214
- */
215
- getChainId() {
216
- return Promise.resolve(this.l1ChainId);
217
- }
218
- async getContractClass(id) {
219
- const klazz = await this.contractDataSource.getContractClass(id);
220
- // TODO(#10007): Remove this check. This is needed only because we're manually registering
221
- // some contracts in the archiver so they are available to all nodes (see `registerCommonContracts`
222
- // in `archiver/src/factory.ts`), but we still want clients to send the registration tx in order
223
- // to emit the corresponding nullifier, which is now being checked. Note that this method
224
- // is only called by the PXE to check if a contract is publicly registered.
225
- if (klazz) {
226
- const classNullifier = await siloNullifier(AztecAddress.fromNumber(REGISTERER_CONTRACT_ADDRESS), id);
227
- const worldState = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_getWorldState).call(this, 'latest');
228
- const [index] = await worldState.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [classNullifier.toBuffer()]);
229
- this.log.debug(`Registration nullifier ${classNullifier} for contract class ${id} found at index ${index}`);
230
- if (index === undefined) {
231
- return undefined;
232
- }
233
- }
234
- return klazz;
235
- }
236
- getContract(address) {
237
- return this.contractDataSource.getContract(address);
238
- }
239
- /**
240
- * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`.
241
- * @param from - The block number from which to begin retrieving logs.
242
- * @param limit - The maximum number of blocks to retrieve logs from.
243
- * @returns An array of private logs from the specified range of blocks.
244
- */
245
- getPrivateLogs(from, limit) {
246
- return this.logsSource.getPrivateLogs(from, limit);
247
- }
248
- /**
249
- * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
250
- * @param tags - The tags to filter the logs by.
251
- * @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
252
- * that tag.
253
- */
254
- getLogsByTags(tags) {
255
- return this.logsSource.getLogsByTags(tags);
256
- }
257
- /**
258
- * Gets public logs based on the provided filter.
259
- * @param filter - The filter to apply to the logs.
260
- * @returns The requested logs.
261
- */
262
- getPublicLogs(filter) {
263
- return this.logsSource.getPublicLogs(filter);
264
- }
265
- /**
266
- * Gets contract class logs based on the provided filter.
267
- * @param filter - The filter to apply to the logs.
268
- * @returns The requested logs.
269
- */
270
- getContractClassLogs(filter) {
271
- return this.logsSource.getContractClassLogs(filter);
272
- }
273
- /**
274
- * Method to submit a transaction to the p2p pool.
275
- * @param tx - The transaction to be submitted.
276
- */
277
- async sendTx(tx) {
278
- const timer = new Timer();
279
- const txHash = (await tx.getTxHash()).toString();
280
- const valid = await this.isValidTx(tx);
281
- if (valid.result !== 'valid') {
282
- const reason = valid.reason.join(', ');
283
- this.metrics.receivedTx(timer.ms(), false);
284
- this.log.warn(`Invalid tx ${txHash}: ${reason}`, { txHash });
285
- // TODO(#10967): Throw when receiving an invalid tx instead of just returning
286
- // throw new Error(`Invalid tx: ${reason}`);
287
- return;
288
- }
289
- await this.p2pClient.sendTx(tx);
290
- this.metrics.receivedTx(timer.ms(), true);
291
- this.log.info(`Received tx ${txHash}`, { txHash });
292
- }
293
- async getTxReceipt(txHash) {
294
- let txReceipt = new TxReceipt(txHash, TxStatus.DROPPED, 'Tx dropped by P2P node.');
295
- // We first check if the tx is in pending (instead of first checking if it is mined) because if we first check
296
- // for mined and then for pending there could be a race condition where the tx is mined between the two checks
297
- // and we would incorrectly return a TxReceipt with status DROPPED
298
- if ((await this.p2pClient.getTxStatus(txHash)) === 'pending') {
299
- txReceipt = new TxReceipt(txHash, TxStatus.PENDING, '');
300
- }
301
- const settledTxReceipt = await this.blockSource.getSettledTxReceipt(txHash);
302
- if (settledTxReceipt) {
303
- txReceipt = settledTxReceipt;
304
- }
305
- return txReceipt;
306
- }
307
- getTxEffect(txHash) {
308
- return this.blockSource.getTxEffect(txHash);
309
- }
310
- /**
311
- * Method to stop the aztec node.
312
- */
313
- async stop() {
314
- this.log.info(`Stopping`);
315
- await this.sequencer?.stop();
316
- await this.p2pClient.stop();
317
- await this.worldStateSynchronizer.stop();
318
- await tryStop(this.blockSource);
319
- await this.telemetry.stop();
320
- this.log.info(`Stopped`);
321
- }
322
- /**
323
- * Method to retrieve pending txs.
324
- * @returns - The pending txs.
325
- */
326
- getPendingTxs() {
327
- return this.p2pClient.getPendingTxs();
328
- }
329
- async getPendingTxCount() {
330
- const pendingTxs = await this.getPendingTxs();
331
- return pendingTxs.length;
332
- }
333
- /**
334
- * Method to retrieve a single tx from the mempool or unfinalised chain.
335
- * @param txHash - The transaction hash to return.
336
- * @returns - The tx if it exists.
337
- */
338
- getTxByHash(txHash) {
339
- return Promise.resolve(this.p2pClient.getTxByHashFromPool(txHash));
340
- }
341
- /**
342
- * Method to retrieve txs from the mempool or unfinalised chain.
343
- * @param txHash - The transaction hash to return.
344
- * @returns - The txs if it exists.
345
- */
346
- async getTxsByHash(txHashes) {
347
- return compactArray(await Promise.all(txHashes.map(txHash => this.getTxByHash(txHash))));
348
- }
349
- /**
350
- * Find the indexes of the given leaves in the given tree.
351
- * @param blockNumber - The block number at which to get the data or 'latest' for latest data
352
- * @param treeId - The tree to search in.
353
- * @param leafValue - The values to search for
354
- * @returns The indexes of the given leaves in the given tree or undefined if not found.
355
- */
356
- async findLeavesIndexes(blockNumber, treeId, leafValues) {
357
- const committedDb = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_getWorldState).call(this, blockNumber);
358
- return await committedDb.findLeafIndices(treeId, leafValues.map(x => x.toBuffer()));
359
- }
360
- /**
361
- * Find the block numbers of the given leaf indices in the given tree.
362
- * @param blockNumber - The block number at which to get the data or 'latest' for latest data
363
- * @param treeId - The tree to search in.
364
- * @param leafIndices - The values to search for
365
- * @returns The indexes of the given leaves in the given tree or undefined if not found.
366
- */
367
- async findBlockNumbersForIndexes(blockNumber, treeId, leafIndices) {
368
- const committedDb = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_getWorldState).call(this, blockNumber);
369
- return await committedDb.getBlockNumbersForLeafIndices(treeId, leafIndices);
370
- }
371
- async findNullifiersIndexesWithBlock(blockNumber, nullifiers) {
372
- if (blockNumber === 'latest') {
373
- blockNumber = await this.getBlockNumber();
374
- }
375
- return this.nullifierSource.findNullifiersIndexesWithBlock(blockNumber, nullifiers);
376
- }
377
- /**
378
- * Returns a sibling path for the given index in the nullifier tree.
379
- * @param blockNumber - The block number at which to get the data.
380
- * @param leafIndex - The index of the leaf for which the sibling path is required.
381
- * @returns The sibling path for the leaf index.
382
- */
383
- async getNullifierSiblingPath(blockNumber, leafIndex) {
384
- const committedDb = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_getWorldState).call(this, blockNumber);
385
- return committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex);
386
- }
387
- /**
388
- * Returns a sibling path for the given index in the data tree.
389
- * @param blockNumber - The block number at which to get the data.
390
- * @param leafIndex - The index of the leaf for which the sibling path is required.
391
- * @returns The sibling path for the leaf index.
392
- */
393
- async getNoteHashSiblingPath(blockNumber, leafIndex) {
394
- const committedDb = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_getWorldState).call(this, blockNumber);
395
- return committedDb.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
396
- }
397
- /**
398
- * Returns the index and a sibling path for a leaf in the committed l1 to l2 data tree.
399
- * @param blockNumber - The block number at which to get the data.
400
- * @param l1ToL2Message - The l1ToL2Message to get the index / sibling path for.
401
- * @returns A tuple of the index and the sibling path of the L1ToL2Message (undefined if not found).
402
- */
403
- async getL1ToL2MessageMembershipWitness(blockNumber, l1ToL2Message) {
404
- const index = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
405
- if (index === undefined) {
406
- return undefined;
407
- }
408
- const committedDb = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_getWorldState).call(this, blockNumber);
409
- const siblingPath = await committedDb.getSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, index);
410
- return [index, siblingPath];
411
- }
412
- /**
413
- * Returns whether an L1 to L2 message is synced by archiver and if it's ready to be included in a block.
414
- * @param l1ToL2Message - The L1 to L2 message to check.
415
- * @returns Whether the message is synced and ready to be included in a block.
416
- */
417
- async isL1ToL2MessageSynced(l1ToL2Message) {
418
- return (await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message)) !== undefined;
419
- }
420
- /**
421
- * Returns the index of a l2ToL1Message in a ephemeral l2 to l1 data tree as well as its sibling path.
422
- * @remarks This tree is considered ephemeral because it is created on-demand by: taking all the l2ToL1 messages
423
- * in a single block, and then using them to make a variable depth append-only tree with these messages as leaves.
424
- * The tree is discarded immediately after calculating what we need from it.
425
- * TODO: Handle the case where two messages in the same tx have the same hash.
426
- * @param blockNumber - The block number at which to get the data.
427
- * @param l2ToL1Message - The l2ToL1Message get the index / sibling path for.
428
- * @returns A tuple of the index and the sibling path of the L2ToL1Message.
429
- */
430
- async getL2ToL1MessageMembershipWitness(blockNumber, l2ToL1Message) {
431
- const block = await this.blockSource.getBlock(blockNumber === 'latest' ? await this.getBlockNumber() : blockNumber);
432
- if (block === undefined) {
433
- throw new Error('Block is not defined');
434
- }
435
- const l2ToL1Messages = block.body.txEffects.map(txEffect => txEffect.l2ToL1Msgs);
436
- // Find index of message
437
- let indexOfMsgInSubtree = -1;
438
- const indexOfMsgTx = l2ToL1Messages.findIndex(msgs => {
439
- const idx = msgs.findIndex(msg => msg.equals(l2ToL1Message));
440
- indexOfMsgInSubtree = Math.max(indexOfMsgInSubtree, idx);
441
- return idx !== -1;
38
+ */ export class AztecNodeService {
39
+ config;
40
+ p2pClient;
41
+ blockSource;
42
+ logsSource;
43
+ contractDataSource;
44
+ l1ToL2MessageSource;
45
+ nullifierSource;
46
+ worldStateSynchronizer;
47
+ sequencer;
48
+ l1ChainId;
49
+ version;
50
+ globalVariableBuilder;
51
+ proofVerifier;
52
+ telemetry;
53
+ log;
54
+ packageVersion;
55
+ metrics;
56
+ tracer;
57
+ constructor(config, p2pClient, blockSource, logsSource, contractDataSource, l1ToL2MessageSource, nullifierSource, worldStateSynchronizer, sequencer, l1ChainId, version, globalVariableBuilder, proofVerifier, telemetry = getTelemetryClient(), log = createLogger('node')){
58
+ this.config = config;
59
+ this.p2pClient = p2pClient;
60
+ this.blockSource = blockSource;
61
+ this.logsSource = logsSource;
62
+ this.contractDataSource = contractDataSource;
63
+ this.l1ToL2MessageSource = l1ToL2MessageSource;
64
+ this.nullifierSource = nullifierSource;
65
+ this.worldStateSynchronizer = worldStateSynchronizer;
66
+ this.sequencer = sequencer;
67
+ this.l1ChainId = l1ChainId;
68
+ this.version = version;
69
+ this.globalVariableBuilder = globalVariableBuilder;
70
+ this.proofVerifier = proofVerifier;
71
+ this.telemetry = telemetry;
72
+ this.log = log;
73
+ this.packageVersion = getPackageInfo().version;
74
+ this.metrics = new NodeMetrics(telemetry, 'AztecNodeService');
75
+ this.tracer = telemetry.getTracer('AztecNodeService');
76
+ this.log.info(`Aztec Node started on chain 0x${l1ChainId.toString(16)}`, config.l1Contracts);
77
+ }
78
+ async getWorldStateSyncStatus() {
79
+ const status = await this.worldStateSynchronizer.status();
80
+ return status.syncSummary;
81
+ }
82
+ getL2Tips() {
83
+ return this.blockSource.getL2Tips();
84
+ }
85
+ /**
86
+ * initializes the Aztec Node, wait for component to sync.
87
+ * @param config - The configuration to be used by the aztec node.
88
+ * @returns - A fully synced Aztec Node for use in development/testing.
89
+ */ static async createAndSync(config, deps = {}, options = {}) {
90
+ const telemetry = deps.telemetry ?? getTelemetryClient();
91
+ const log = deps.logger ?? createLogger('node');
92
+ const dateProvider = deps.dateProvider ?? new DateProvider();
93
+ const blobSinkClient = deps.blobSinkClient ?? createBlobSinkClient(config);
94
+ const ethereumChain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
95
+ //validate that the actual chain id matches that specified in configuration
96
+ if (config.l1ChainId !== ethereumChain.chainInfo.id) {
97
+ throw new Error(`RPC URL configured for chain id ${ethereumChain.chainInfo.id} but expected id ${config.l1ChainId}`);
98
+ }
99
+ const archiver = await createArchiver(config, blobSinkClient, {
100
+ blockUntilSync: true
101
+ }, telemetry);
102
+ // now create the merkle trees and the world state synchronizer
103
+ const worldStateSynchronizer = await createWorldStateSynchronizer(config, archiver, options.prefilledPublicData, telemetry);
104
+ const proofVerifier = config.realProofs ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier();
105
+ if (!config.realProofs) {
106
+ log.warn(`Aztec node is accepting fake proofs`);
107
+ }
108
+ const epochCache = await EpochCache.create(config.l1Contracts.rollupAddress, config, {
109
+ dateProvider
110
+ });
111
+ // create the tx pool and the p2p client, which will need the l2 block source
112
+ const p2pClient = await createP2PClient(P2PClientType.Full, config, archiver, proofVerifier, worldStateSynchronizer, epochCache, telemetry);
113
+ const slasherClient = await createSlasherClient(config, archiver, telemetry);
114
+ // start both and wait for them to sync from the block source
115
+ await Promise.all([
116
+ p2pClient.start(),
117
+ worldStateSynchronizer.start(),
118
+ slasherClient.start()
119
+ ]);
120
+ log.verbose(`All Aztec Node subsystems synced`);
121
+ const validatorClient = createValidatorClient(config, {
122
+ p2pClient,
123
+ telemetry,
124
+ dateProvider,
125
+ epochCache
126
+ });
127
+ // now create the sequencer
128
+ const sequencer = config.disableValidator ? undefined : await SequencerClient.new(config, {
129
+ ...deps,
130
+ validatorClient,
131
+ p2pClient,
132
+ worldStateSynchronizer,
133
+ slasherClient,
134
+ contractDataSource: archiver,
135
+ l2BlockSource: archiver,
136
+ l1ToL2MessageSource: archiver,
137
+ telemetry,
138
+ dateProvider,
139
+ blobSinkClient
140
+ });
141
+ return new AztecNodeService(config, p2pClient, archiver, archiver, archiver, archiver, archiver, worldStateSynchronizer, sequencer, ethereumChain.chainInfo.id, config.version, new GlobalVariableBuilder(config), proofVerifier, telemetry, log);
142
+ }
143
+ /**
144
+ * Returns the sequencer client instance.
145
+ * @returns The sequencer client instance.
146
+ */ getSequencer() {
147
+ return this.sequencer;
148
+ }
149
+ getBlockSource() {
150
+ return this.blockSource;
151
+ }
152
+ getContractDataSource() {
153
+ return this.contractDataSource;
154
+ }
155
+ getP2P() {
156
+ return this.p2pClient;
157
+ }
158
+ /**
159
+ * Method to return the currently deployed L1 contract addresses.
160
+ * @returns - The currently deployed L1 contract addresses.
161
+ */ getL1ContractAddresses() {
162
+ return Promise.resolve(this.config.l1Contracts);
163
+ }
164
+ getEncodedEnr() {
165
+ return Promise.resolve(this.p2pClient.getEnr()?.encodeTxt());
166
+ }
167
+ /**
168
+ * Method to determine if the node is ready to accept transactions.
169
+ * @returns - Flag indicating the readiness for tx submission.
170
+ */ isReady() {
171
+ return Promise.resolve(this.p2pClient.isReady() ?? false);
172
+ }
173
+ async getNodeInfo() {
174
+ const [nodeVersion, protocolVersion, chainId, enr, contractAddresses, protocolContractAddresses] = await Promise.all([
175
+ this.getNodeVersion(),
176
+ this.getVersion(),
177
+ this.getChainId(),
178
+ this.getEncodedEnr(),
179
+ this.getL1ContractAddresses(),
180
+ this.getProtocolContractAddresses()
181
+ ]);
182
+ const nodeInfo = {
183
+ nodeVersion,
184
+ l1ChainId: chainId,
185
+ protocolVersion,
186
+ enr,
187
+ l1ContractAddresses: contractAddresses,
188
+ protocolContractAddresses: protocolContractAddresses
189
+ };
190
+ return nodeInfo;
191
+ }
192
+ /**
193
+ * Get a block specified by its number.
194
+ * @param number - The block number being requested.
195
+ * @returns The requested block.
196
+ */ async getBlock(number) {
197
+ return await this.blockSource.getBlock(number);
198
+ }
199
+ /**
200
+ * Method to request blocks. Will attempt to return all requested blocks but will return only those available.
201
+ * @param from - The start of the range of blocks to return.
202
+ * @param limit - The maximum number of blocks to obtain.
203
+ * @returns The blocks requested.
204
+ */ async getBlocks(from, limit) {
205
+ return await this.blockSource.getBlocks(from, limit) ?? [];
206
+ }
207
+ /**
208
+ * Method to fetch the current base fees.
209
+ * @returns The current base fees.
210
+ */ async getCurrentBaseFees() {
211
+ return await this.globalVariableBuilder.getCurrentBaseFees();
212
+ }
213
+ /**
214
+ * Method to fetch the current block number.
215
+ * @returns The block number.
216
+ */ async getBlockNumber() {
217
+ return await this.blockSource.getBlockNumber();
218
+ }
219
+ async getProvenBlockNumber() {
220
+ return await this.blockSource.getProvenBlockNumber();
221
+ }
222
+ /**
223
+ * Method to fetch the version of the package.
224
+ * @returns The node package version
225
+ */ getNodeVersion() {
226
+ return Promise.resolve(this.packageVersion);
227
+ }
228
+ /**
229
+ * Method to fetch the version of the rollup the node is connected to.
230
+ * @returns The rollup version.
231
+ */ getVersion() {
232
+ return Promise.resolve(this.version);
233
+ }
234
+ /**
235
+ * Method to fetch the chain id of the base-layer for the rollup.
236
+ * @returns The chain id.
237
+ */ getChainId() {
238
+ return Promise.resolve(this.l1ChainId);
239
+ }
240
+ async getContractClass(id) {
241
+ const klazz = await this.contractDataSource.getContractClass(id);
242
+ // TODO(#10007): Remove this check. This is needed only because we're manually registering
243
+ // some contracts in the archiver so they are available to all nodes (see `registerCommonContracts`
244
+ // in `archiver/src/factory.ts`), but we still want clients to send the registration tx in order
245
+ // to emit the corresponding nullifier, which is now being checked. Note that this method
246
+ // is only called by the PXE to check if a contract is publicly registered.
247
+ if (klazz) {
248
+ const classNullifier = await siloNullifier(AztecAddress.fromNumber(REGISTERER_CONTRACT_ADDRESS), id);
249
+ const worldState = await this.#getWorldState('latest');
250
+ const [index] = await worldState.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [
251
+ classNullifier.toBuffer()
252
+ ]);
253
+ this.log.debug(`Registration nullifier ${classNullifier} for contract class ${id} found at index ${index}`);
254
+ if (index === undefined) {
255
+ return undefined;
256
+ }
257
+ }
258
+ return klazz;
259
+ }
260
+ getContract(address) {
261
+ return this.contractDataSource.getContract(address);
262
+ }
263
+ /**
264
+ * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`.
265
+ * @param from - The block number from which to begin retrieving logs.
266
+ * @param limit - The maximum number of blocks to retrieve logs from.
267
+ * @returns An array of private logs from the specified range of blocks.
268
+ */ getPrivateLogs(from, limit) {
269
+ return this.logsSource.getPrivateLogs(from, limit);
270
+ }
271
+ /**
272
+ * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
273
+ * @param tags - The tags to filter the logs by.
274
+ * @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
275
+ * that tag.
276
+ */ getLogsByTags(tags) {
277
+ return this.logsSource.getLogsByTags(tags);
278
+ }
279
+ /**
280
+ * Gets public logs based on the provided filter.
281
+ * @param filter - The filter to apply to the logs.
282
+ * @returns The requested logs.
283
+ */ getPublicLogs(filter) {
284
+ return this.logsSource.getPublicLogs(filter);
285
+ }
286
+ /**
287
+ * Gets contract class logs based on the provided filter.
288
+ * @param filter - The filter to apply to the logs.
289
+ * @returns The requested logs.
290
+ */ getContractClassLogs(filter) {
291
+ return this.logsSource.getContractClassLogs(filter);
292
+ }
293
+ /**
294
+ * Method to submit a transaction to the p2p pool.
295
+ * @param tx - The transaction to be submitted.
296
+ */ async sendTx(tx) {
297
+ const timer = new Timer();
298
+ const txHash = (await tx.getTxHash()).toString();
299
+ const valid = await this.isValidTx(tx);
300
+ if (valid.result !== 'valid') {
301
+ const reason = valid.reason.join(', ');
302
+ this.metrics.receivedTx(timer.ms(), false);
303
+ this.log.warn(`Invalid tx ${txHash}: ${reason}`, {
304
+ txHash
305
+ });
306
+ // TODO(#10967): Throw when receiving an invalid tx instead of just returning
307
+ // throw new Error(`Invalid tx: ${reason}`);
308
+ return;
309
+ }
310
+ await this.p2pClient.sendTx(tx);
311
+ this.metrics.receivedTx(timer.ms(), true);
312
+ this.log.info(`Received tx ${txHash}`, {
313
+ txHash
314
+ });
315
+ }
316
+ async getTxReceipt(txHash) {
317
+ let txReceipt = new TxReceipt(txHash, TxStatus.DROPPED, 'Tx dropped by P2P node.');
318
+ // We first check if the tx is in pending (instead of first checking if it is mined) because if we first check
319
+ // for mined and then for pending there could be a race condition where the tx is mined between the two checks
320
+ // and we would incorrectly return a TxReceipt with status DROPPED
321
+ if (await this.p2pClient.getTxStatus(txHash) === 'pending') {
322
+ txReceipt = new TxReceipt(txHash, TxStatus.PENDING, '');
323
+ }
324
+ const settledTxReceipt = await this.blockSource.getSettledTxReceipt(txHash);
325
+ if (settledTxReceipt) {
326
+ txReceipt = settledTxReceipt;
327
+ }
328
+ return txReceipt;
329
+ }
330
+ getTxEffect(txHash) {
331
+ return this.blockSource.getTxEffect(txHash);
332
+ }
333
+ /**
334
+ * Method to stop the aztec node.
335
+ */ async stop() {
336
+ this.log.info(`Stopping`);
337
+ await this.sequencer?.stop();
338
+ await this.p2pClient.stop();
339
+ await this.worldStateSynchronizer.stop();
340
+ await tryStop(this.blockSource);
341
+ await this.telemetry.stop();
342
+ this.log.info(`Stopped`);
343
+ }
344
+ /**
345
+ * Method to retrieve pending txs.
346
+ * @returns - The pending txs.
347
+ */ getPendingTxs() {
348
+ return this.p2pClient.getPendingTxs();
349
+ }
350
+ async getPendingTxCount() {
351
+ const pendingTxs = await this.getPendingTxs();
352
+ return pendingTxs.length;
353
+ }
354
+ /**
355
+ * Method to retrieve a single tx from the mempool or unfinalised chain.
356
+ * @param txHash - The transaction hash to return.
357
+ * @returns - The tx if it exists.
358
+ */ getTxByHash(txHash) {
359
+ return Promise.resolve(this.p2pClient.getTxByHashFromPool(txHash));
360
+ }
361
+ /**
362
+ * Method to retrieve txs from the mempool or unfinalised chain.
363
+ * @param txHash - The transaction hash to return.
364
+ * @returns - The txs if it exists.
365
+ */ async getTxsByHash(txHashes) {
366
+ return compactArray(await Promise.all(txHashes.map((txHash)=>this.getTxByHash(txHash))));
367
+ }
368
+ /**
369
+ * Find the indexes of the given leaves in the given tree.
370
+ * @param blockNumber - The block number at which to get the data or 'latest' for latest data
371
+ * @param treeId - The tree to search in.
372
+ * @param leafValue - The values to search for
373
+ * @returns The indexes of the given leaves in the given tree or undefined if not found.
374
+ */ async findLeavesIndexes(blockNumber, treeId, leafValues) {
375
+ const committedDb = await this.#getWorldState(blockNumber);
376
+ return await committedDb.findLeafIndices(treeId, leafValues.map((x)=>x.toBuffer()));
377
+ }
378
+ /**
379
+ * Find the block numbers of the given leaf indices in the given tree.
380
+ * @param blockNumber - The block number at which to get the data or 'latest' for latest data
381
+ * @param treeId - The tree to search in.
382
+ * @param leafIndices - The values to search for
383
+ * @returns The indexes of the given leaves in the given tree or undefined if not found.
384
+ */ async findBlockNumbersForIndexes(blockNumber, treeId, leafIndices) {
385
+ const committedDb = await this.#getWorldState(blockNumber);
386
+ return await committedDb.getBlockNumbersForLeafIndices(treeId, leafIndices);
387
+ }
388
+ async findNullifiersIndexesWithBlock(blockNumber, nullifiers) {
389
+ if (blockNumber === 'latest') {
390
+ blockNumber = await this.getBlockNumber();
391
+ }
392
+ return this.nullifierSource.findNullifiersIndexesWithBlock(blockNumber, nullifiers);
393
+ }
394
+ /**
395
+ * Returns a sibling path for the given index in the nullifier tree.
396
+ * @param blockNumber - The block number at which to get the data.
397
+ * @param leafIndex - The index of the leaf for which the sibling path is required.
398
+ * @returns The sibling path for the leaf index.
399
+ */ async getNullifierSiblingPath(blockNumber, leafIndex) {
400
+ const committedDb = await this.#getWorldState(blockNumber);
401
+ return committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex);
402
+ }
403
+ /**
404
+ * Returns a sibling path for the given index in the data tree.
405
+ * @param blockNumber - The block number at which to get the data.
406
+ * @param leafIndex - The index of the leaf for which the sibling path is required.
407
+ * @returns The sibling path for the leaf index.
408
+ */ async getNoteHashSiblingPath(blockNumber, leafIndex) {
409
+ const committedDb = await this.#getWorldState(blockNumber);
410
+ return committedDb.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
411
+ }
412
+ /**
413
+ * Returns the index and a sibling path for a leaf in the committed l1 to l2 data tree.
414
+ * @param blockNumber - The block number at which to get the data.
415
+ * @param l1ToL2Message - The l1ToL2Message to get the index / sibling path for.
416
+ * @returns A tuple of the index and the sibling path of the L1ToL2Message (undefined if not found).
417
+ */ async getL1ToL2MessageMembershipWitness(blockNumber, l1ToL2Message) {
418
+ const index = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
419
+ if (index === undefined) {
420
+ return undefined;
421
+ }
422
+ const committedDb = await this.#getWorldState(blockNumber);
423
+ const siblingPath = await committedDb.getSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, index);
424
+ return [
425
+ index,
426
+ siblingPath
427
+ ];
428
+ }
429
+ /**
430
+ * Returns whether an L1 to L2 message is synced by archiver and if it's ready to be included in a block.
431
+ * @param l1ToL2Message - The L1 to L2 message to check.
432
+ * @returns Whether the message is synced and ready to be included in a block.
433
+ */ async isL1ToL2MessageSynced(l1ToL2Message) {
434
+ return await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message) !== undefined;
435
+ }
436
+ /**
437
+ * Returns the index of a l2ToL1Message in a ephemeral l2 to l1 data tree as well as its sibling path.
438
+ * @remarks This tree is considered ephemeral because it is created on-demand by: taking all the l2ToL1 messages
439
+ * in a single block, and then using them to make a variable depth append-only tree with these messages as leaves.
440
+ * The tree is discarded immediately after calculating what we need from it.
441
+ * TODO: Handle the case where two messages in the same tx have the same hash.
442
+ * @param blockNumber - The block number at which to get the data.
443
+ * @param l2ToL1Message - The l2ToL1Message get the index / sibling path for.
444
+ * @returns A tuple of the index and the sibling path of the L2ToL1Message.
445
+ */ async getL2ToL1MessageMembershipWitness(blockNumber, l2ToL1Message) {
446
+ const block = await this.blockSource.getBlock(blockNumber === 'latest' ? await this.getBlockNumber() : blockNumber);
447
+ if (block === undefined) {
448
+ throw new Error('Block is not defined');
449
+ }
450
+ const l2ToL1Messages = block.body.txEffects.map((txEffect)=>txEffect.l2ToL1Msgs);
451
+ // Find index of message
452
+ let indexOfMsgInSubtree = -1;
453
+ const indexOfMsgTx = l2ToL1Messages.findIndex((msgs)=>{
454
+ const idx = msgs.findIndex((msg)=>msg.equals(l2ToL1Message));
455
+ indexOfMsgInSubtree = Math.max(indexOfMsgInSubtree, idx);
456
+ return idx !== -1;
457
+ });
458
+ if (indexOfMsgTx === -1) {
459
+ throw new Error('The L2ToL1Message you are trying to prove inclusion of does not exist');
460
+ }
461
+ const tempStores = [];
462
+ // Construct message subtrees
463
+ const l2toL1Subtrees = await Promise.all(l2ToL1Messages.map(async (msgs, i)=>{
464
+ const store = openTmpStore(true);
465
+ tempStores.push(store);
466
+ const treeHeight = msgs.length <= 1 ? 1 : Math.ceil(Math.log2(msgs.length));
467
+ const tree = new StandardTree(store, new SHA256Trunc(), `temp_msgs_subtrees_${i}`, treeHeight, 0n, Fr);
468
+ await tree.appendLeaves(msgs);
469
+ return tree;
470
+ }));
471
+ // path of the input msg from leaf -> first out hash calculated in base rolllup
472
+ const subtreePathOfL2ToL1Message = await l2toL1Subtrees[indexOfMsgTx].getSiblingPath(BigInt(indexOfMsgInSubtree), true);
473
+ const numTxs = block.body.txEffects.length;
474
+ if (numTxs === 1) {
475
+ return [
476
+ BigInt(indexOfMsgInSubtree),
477
+ subtreePathOfL2ToL1Message
478
+ ];
479
+ }
480
+ const l2toL1SubtreeRoots = l2toL1Subtrees.map((t)=>Fr.fromBuffer(t.getRoot(true)));
481
+ const maxTreeHeight = Math.ceil(Math.log2(l2toL1SubtreeRoots.length));
482
+ // The root of this tree is the out_hash calculated in Noir => we truncate to match Noir's SHA
483
+ const outHashTree = new UnbalancedTree(new SHA256Trunc(), 'temp_outhash_sibling_path', maxTreeHeight, Fr);
484
+ await outHashTree.appendLeaves(l2toL1SubtreeRoots);
485
+ const pathOfTxInOutHashTree = await outHashTree.getSiblingPath(l2toL1SubtreeRoots[indexOfMsgTx].toBigInt());
486
+ // Append subtree path to out hash tree path
487
+ const mergedPath = subtreePathOfL2ToL1Message.toBufferArray().concat(pathOfTxInOutHashTree.toBufferArray());
488
+ // Append binary index of subtree path to binary index of out hash tree path
489
+ const mergedIndex = parseInt(indexOfMsgTx.toString(2).concat(indexOfMsgInSubtree.toString(2).padStart(l2toL1Subtrees[indexOfMsgTx].getDepth(), '0')), 2);
490
+ // clear the tmp stores
491
+ await Promise.all(tempStores.map((store)=>store.delete()));
492
+ return [
493
+ BigInt(mergedIndex),
494
+ new SiblingPath(mergedPath.length, mergedPath)
495
+ ];
496
+ }
497
+ /**
498
+ * Returns a sibling path for a leaf in the committed blocks tree.
499
+ * @param blockNumber - The block number at which to get the data.
500
+ * @param leafIndex - Index of the leaf in the tree.
501
+ * @returns The sibling path.
502
+ */ async getArchiveSiblingPath(blockNumber, leafIndex) {
503
+ const committedDb = await this.#getWorldState(blockNumber);
504
+ return committedDb.getSiblingPath(MerkleTreeId.ARCHIVE, leafIndex);
505
+ }
506
+ /**
507
+ * Returns a sibling path for a leaf in the committed public data tree.
508
+ * @param blockNumber - The block number at which to get the data.
509
+ * @param leafIndex - Index of the leaf in the tree.
510
+ * @returns The sibling path.
511
+ */ async getPublicDataSiblingPath(blockNumber, leafIndex) {
512
+ const committedDb = await this.#getWorldState(blockNumber);
513
+ return committedDb.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex);
514
+ }
515
+ /**
516
+ * Returns a nullifier membership witness for a given nullifier at a given block.
517
+ * @param blockNumber - The block number at which to get the index.
518
+ * @param nullifier - Nullifier we try to find witness for.
519
+ * @returns The nullifier membership witness (if found).
520
+ */ async getNullifierMembershipWitness(blockNumber, nullifier) {
521
+ const db = await this.#getWorldState(blockNumber);
522
+ const index = (await db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [
523
+ nullifier.toBuffer()
524
+ ]))[0];
525
+ if (!index) {
526
+ return undefined;
527
+ }
528
+ const leafPreimagePromise = db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
529
+ const siblingPathPromise = db.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
530
+ const [leafPreimage, siblingPath] = await Promise.all([
531
+ leafPreimagePromise,
532
+ siblingPathPromise
533
+ ]);
534
+ if (!leafPreimage) {
535
+ return undefined;
536
+ }
537
+ return new NullifierMembershipWitness(BigInt(index), leafPreimage, siblingPath);
538
+ }
539
+ /**
540
+ * Returns a low nullifier membership witness for a given nullifier at a given block.
541
+ * @param blockNumber - The block number at which to get the index.
542
+ * @param nullifier - Nullifier we try to find the low nullifier witness for.
543
+ * @returns The low nullifier membership witness (if found).
544
+ * @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
545
+ * list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier
546
+ * we are trying to prove non-inclusion for.
547
+ *
548
+ * Note: This function returns the membership witness of the nullifier itself and not the low nullifier when
549
+ * the nullifier already exists in the tree. This is because the `getPreviousValueIndex` function returns the
550
+ * index of the nullifier itself when it already exists in the tree.
551
+ * TODO: This is a confusing behavior and we should eventually address that.
552
+ */ async getLowNullifierMembershipWitness(blockNumber, nullifier) {
553
+ const committedDb = await this.#getWorldState(blockNumber);
554
+ const findResult = await committedDb.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
555
+ if (!findResult) {
556
+ return undefined;
557
+ }
558
+ const { index, alreadyPresent } = findResult;
559
+ if (alreadyPresent) {
560
+ this.log.warn(`Nullifier ${nullifier.toBigInt()} already exists in the tree`);
561
+ }
562
+ const preimageData = await committedDb.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
563
+ const siblingPath = await committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
564
+ return new NullifierMembershipWitness(BigInt(index), preimageData, siblingPath);
565
+ }
566
+ async getPublicDataTreeWitness(blockNumber, leafSlot) {
567
+ const committedDb = await this.#getWorldState(blockNumber);
568
+ const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
569
+ if (!lowLeafResult) {
570
+ return undefined;
571
+ } else {
572
+ const preimage = await committedDb.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
573
+ const path = await committedDb.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
574
+ return new PublicDataWitness(lowLeafResult.index, preimage, path);
575
+ }
576
+ }
577
+ /**
578
+ * Gets the storage value at the given contract storage slot.
579
+ *
580
+ * @remarks The storage slot here refers to the slot as it is defined in Noir not the index in the merkle tree.
581
+ * Aztec's version of `eth_getStorageAt`.
582
+ *
583
+ * @param contract - Address of the contract to query.
584
+ * @param slot - Slot to query.
585
+ * @param blockNumber - The block number at which to get the data or 'latest'.
586
+ * @returns Storage value at the given contract slot.
587
+ */ async getPublicStorageAt(contract, slot, blockNumber) {
588
+ const committedDb = await this.#getWorldState(blockNumber);
589
+ const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
590
+ const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
591
+ if (!lowLeafResult || !lowLeafResult.alreadyPresent) {
592
+ return Fr.ZERO;
593
+ }
594
+ const preimage = await committedDb.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
595
+ return preimage.value;
596
+ }
597
+ /**
598
+ * Returns the currently committed block header, or the initial header if no blocks have been produced.
599
+ * @returns The current committed block header.
600
+ */ async getBlockHeader(blockNumber = 'latest') {
601
+ return blockNumber === 0 || blockNumber === 'latest' && await this.blockSource.getBlockNumber() === 0 ? this.worldStateSynchronizer.getCommitted().getInitialHeader() : this.blockSource.getBlockHeader(blockNumber);
602
+ }
603
+ /**
604
+ * Simulates the public part of a transaction with the current state.
605
+ * @param tx - The transaction to simulate.
606
+ **/ async simulatePublicCalls(tx, skipFeeEnforcement = false) {
607
+ const txHash = await tx.getTxHash();
608
+ const blockNumber = await this.blockSource.getBlockNumber() + 1;
609
+ // If sequencer is not initialized, we just set these values to zero for simulation.
610
+ const coinbase = this.sequencer?.coinbase || EthAddress.ZERO;
611
+ const feeRecipient = this.sequencer?.feeRecipient || AztecAddress.ZERO;
612
+ const newGlobalVariables = await this.globalVariableBuilder.buildGlobalVariables(new Fr(blockNumber), coinbase, feeRecipient);
613
+ const publicProcessorFactory = new PublicProcessorFactory(this.contractDataSource, new DateProvider(), this.telemetry);
614
+ const fork = await this.worldStateSynchronizer.fork();
615
+ this.log.verbose(`Simulating public calls for tx ${txHash}`, {
616
+ globalVariables: newGlobalVariables.toInspect(),
617
+ txHash,
618
+ blockNumber
619
+ });
620
+ try {
621
+ const processor = publicProcessorFactory.create(fork, newGlobalVariables, skipFeeEnforcement);
622
+ // REFACTOR: Consider merging ProcessReturnValues into ProcessedTx
623
+ const [processedTxs, failedTxs, returns] = await processor.process([
624
+ tx
625
+ ]);
626
+ // REFACTOR: Consider returning the error rather than throwing
627
+ if (failedTxs.length) {
628
+ this.log.warn(`Simulated tx ${txHash} fails: ${failedTxs[0].error}`, {
629
+ txHash
442
630
  });
443
- if (indexOfMsgTx === -1) {
444
- throw new Error('The L2ToL1Message you are trying to prove inclusion of does not exist');
445
- }
446
- const tempStores = [];
447
- // Construct message subtrees
448
- const l2toL1Subtrees = await Promise.all(l2ToL1Messages.map(async (msgs, i) => {
449
- const store = openTmpStore(true);
450
- tempStores.push(store);
451
- const treeHeight = msgs.length <= 1 ? 1 : Math.ceil(Math.log2(msgs.length));
452
- const tree = new StandardTree(store, new SHA256Trunc(), `temp_msgs_subtrees_${i}`, treeHeight, 0n, Fr);
453
- await tree.appendLeaves(msgs);
454
- return tree;
455
- }));
456
- // path of the input msg from leaf -> first out hash calculated in base rolllup
457
- const subtreePathOfL2ToL1Message = await l2toL1Subtrees[indexOfMsgTx].getSiblingPath(BigInt(indexOfMsgInSubtree), true);
458
- const numTxs = block.body.txEffects.length;
459
- if (numTxs === 1) {
460
- return [BigInt(indexOfMsgInSubtree), subtreePathOfL2ToL1Message];
461
- }
462
- const l2toL1SubtreeRoots = l2toL1Subtrees.map(t => Fr.fromBuffer(t.getRoot(true)));
463
- const maxTreeHeight = Math.ceil(Math.log2(l2toL1SubtreeRoots.length));
464
- // The root of this tree is the out_hash calculated in Noir => we truncate to match Noir's SHA
465
- const outHashTree = new UnbalancedTree(new SHA256Trunc(), 'temp_outhash_sibling_path', maxTreeHeight, Fr);
466
- await outHashTree.appendLeaves(l2toL1SubtreeRoots);
467
- const pathOfTxInOutHashTree = await outHashTree.getSiblingPath(l2toL1SubtreeRoots[indexOfMsgTx].toBigInt());
468
- // Append subtree path to out hash tree path
469
- const mergedPath = subtreePathOfL2ToL1Message.toBufferArray().concat(pathOfTxInOutHashTree.toBufferArray());
470
- // Append binary index of subtree path to binary index of out hash tree path
471
- const mergedIndex = parseInt(indexOfMsgTx
472
- .toString(2)
473
- .concat(indexOfMsgInSubtree.toString(2).padStart(l2toL1Subtrees[indexOfMsgTx].getDepth(), '0')), 2);
474
- // clear the tmp stores
475
- await Promise.all(tempStores.map(store => store.delete()));
476
- return [BigInt(mergedIndex), new SiblingPath(mergedPath.length, mergedPath)];
477
- }
478
- /**
479
- * Returns a sibling path for a leaf in the committed blocks tree.
480
- * @param blockNumber - The block number at which to get the data.
481
- * @param leafIndex - Index of the leaf in the tree.
482
- * @returns The sibling path.
483
- */
484
- async getArchiveSiblingPath(blockNumber, leafIndex) {
485
- const committedDb = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_getWorldState).call(this, blockNumber);
486
- return committedDb.getSiblingPath(MerkleTreeId.ARCHIVE, leafIndex);
487
- }
488
- /**
489
- * Returns a sibling path for a leaf in the committed public data tree.
490
- * @param blockNumber - The block number at which to get the data.
491
- * @param leafIndex - Index of the leaf in the tree.
492
- * @returns The sibling path.
493
- */
494
- async getPublicDataSiblingPath(blockNumber, leafIndex) {
495
- const committedDb = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_getWorldState).call(this, blockNumber);
496
- return committedDb.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex);
497
- }
498
- /**
499
- * Returns a nullifier membership witness for a given nullifier at a given block.
500
- * @param blockNumber - The block number at which to get the index.
501
- * @param nullifier - Nullifier we try to find witness for.
502
- * @returns The nullifier membership witness (if found).
503
- */
504
- async getNullifierMembershipWitness(blockNumber, nullifier) {
505
- const db = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_getWorldState).call(this, blockNumber);
506
- const index = (await db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]))[0];
507
- if (!index) {
508
- return undefined;
509
- }
510
- const leafPreimagePromise = db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
511
- const siblingPathPromise = db.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
512
- const [leafPreimage, siblingPath] = await Promise.all([leafPreimagePromise, siblingPathPromise]);
513
- if (!leafPreimage) {
514
- return undefined;
515
- }
516
- return new NullifierMembershipWitness(BigInt(index), leafPreimage, siblingPath);
517
- }
518
- /**
519
- * Returns a low nullifier membership witness for a given nullifier at a given block.
520
- * @param blockNumber - The block number at which to get the index.
521
- * @param nullifier - Nullifier we try to find the low nullifier witness for.
522
- * @returns The low nullifier membership witness (if found).
523
- * @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
524
- * list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier
525
- * we are trying to prove non-inclusion for.
526
- *
527
- * Note: This function returns the membership witness of the nullifier itself and not the low nullifier when
528
- * the nullifier already exists in the tree. This is because the `getPreviousValueIndex` function returns the
529
- * index of the nullifier itself when it already exists in the tree.
530
- * TODO: This is a confusing behavior and we should eventually address that.
531
- */
532
- async getLowNullifierMembershipWitness(blockNumber, nullifier) {
533
- const committedDb = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_getWorldState).call(this, blockNumber);
534
- const findResult = await committedDb.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
535
- if (!findResult) {
536
- return undefined;
537
- }
538
- const { index, alreadyPresent } = findResult;
539
- if (alreadyPresent) {
540
- this.log.warn(`Nullifier ${nullifier.toBigInt()} already exists in the tree`);
541
- }
542
- const preimageData = (await committedDb.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index));
543
- const siblingPath = await committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
544
- return new NullifierMembershipWitness(BigInt(index), preimageData, siblingPath);
545
- }
546
- async getPublicDataTreeWitness(blockNumber, leafSlot) {
547
- const committedDb = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_getWorldState).call(this, blockNumber);
548
- const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
549
- if (!lowLeafResult) {
550
- return undefined;
551
- }
552
- else {
553
- const preimage = (await committedDb.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index));
554
- const path = await committedDb.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
555
- return new PublicDataWitness(lowLeafResult.index, preimage, path);
556
- }
557
- }
558
- /**
559
- * Gets the storage value at the given contract storage slot.
560
- *
561
- * @remarks The storage slot here refers to the slot as it is defined in Noir not the index in the merkle tree.
562
- * Aztec's version of `eth_getStorageAt`.
563
- *
564
- * @param contract - Address of the contract to query.
565
- * @param slot - Slot to query.
566
- * @param blockNumber - The block number at which to get the data or 'latest'.
567
- * @returns Storage value at the given contract slot.
568
- */
569
- async getPublicStorageAt(contract, slot, blockNumber) {
570
- const committedDb = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_getWorldState).call(this, blockNumber);
571
- const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
572
- const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
573
- if (!lowLeafResult || !lowLeafResult.alreadyPresent) {
574
- return Fr.ZERO;
575
- }
576
- const preimage = (await committedDb.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index));
577
- return preimage.value;
578
- }
579
- /**
580
- * Returns the currently committed block header, or the initial header if no blocks have been produced.
581
- * @returns The current committed block header.
582
- */
583
- async getBlockHeader(blockNumber = 'latest') {
584
- return ((await this.getBlock(blockNumber === 'latest' ? -1 : blockNumber))?.header ??
585
- this.worldStateSynchronizer.getCommitted().getInitialHeader());
586
- }
587
- /**
588
- * Simulates the public part of a transaction with the current state.
589
- * @param tx - The transaction to simulate.
590
- **/
591
- async simulatePublicCalls(tx, enforceFeePayment = true) {
592
- const txHash = await tx.getTxHash();
593
- const blockNumber = (await this.blockSource.getBlockNumber()) + 1;
594
- // If sequencer is not initialized, we just set these values to zero for simulation.
595
- const coinbase = this.sequencer?.coinbase || EthAddress.ZERO;
596
- const feeRecipient = this.sequencer?.feeRecipient || AztecAddress.ZERO;
597
- const newGlobalVariables = await this.globalVariableBuilder.buildGlobalVariables(new Fr(blockNumber), coinbase, feeRecipient);
598
- const publicProcessorFactory = new PublicProcessorFactory(this.contractDataSource, new DateProvider(), this.telemetry);
599
- const fork = await this.worldStateSynchronizer.fork();
600
- this.log.verbose(`Simulating public calls for tx ${txHash}`, {
601
- globalVariables: newGlobalVariables.toInspect(),
602
- txHash,
603
- blockNumber,
604
- });
605
- try {
606
- const processor = publicProcessorFactory.create(fork, newGlobalVariables, enforceFeePayment);
607
- // REFACTOR: Consider merging ProcessReturnValues into ProcessedTx
608
- const [processedTxs, failedTxs, returns] = await processor.process([tx]);
609
- // REFACTOR: Consider returning the error rather than throwing
610
- if (failedTxs.length) {
611
- this.log.warn(`Simulated tx ${txHash} fails: ${failedTxs[0].error}`, { txHash });
612
- throw failedTxs[0].error;
613
- }
614
- const [processedTx] = processedTxs;
615
- return new PublicSimulationOutput(processedTx.revertReason, processedTx.constants, processedTx.txEffect, returns, processedTx.gasUsed);
616
- }
617
- finally {
618
- await fork.close();
619
- }
620
- }
621
- async isValidTx(tx, isSimulation = false) {
622
- const blockNumber = (await this.blockSource.getBlockNumber()) + 1;
623
- const db = this.worldStateSynchronizer.getCommitted();
624
- const verifier = isSimulation ? undefined : this.proofVerifier;
625
- const validator = createValidatorForAcceptingTxs(db, this.contractDataSource, verifier, {
626
- blockNumber,
627
- l1ChainId: this.l1ChainId,
628
- enforceFees: !!this.config.enforceFees,
629
- setupAllowList: this.config.allowedInSetup ?? (await getDefaultAllowedSetupFunctions()),
630
- gasFees: await this.getCurrentBaseFees(),
631
- });
632
- return await validator.validateTx(tx);
633
- }
634
- async setConfig(config) {
635
- const newConfig = { ...this.config, ...config };
636
- await this.sequencer?.updateSequencerConfig(config);
637
- if (newConfig.realProofs !== this.config.realProofs) {
638
- this.proofVerifier = config.realProofs ? await BBCircuitVerifier.new(newConfig) : new TestCircuitVerifier();
639
- }
640
- this.config = newConfig;
641
- }
642
- getProtocolContractAddresses() {
643
- return Promise.resolve({
644
- classRegisterer: ProtocolContractAddress.ContractClassRegisterer,
645
- feeJuice: ProtocolContractAddress.FeeJuice,
646
- instanceDeployer: ProtocolContractAddress.ContractInstanceDeployer,
647
- multiCallEntrypoint: ProtocolContractAddress.MultiCallEntrypoint,
648
- });
649
- }
650
- // TODO(#10007): Remove this method
651
- addContractClass(contractClass) {
652
- this.log.info(`Adding contract class via API ${contractClass.id}`);
653
- return this.contractDataSource.addContractClass(contractClass);
654
- }
655
- registerContractFunctionSignatures(_address, signatures) {
656
- return this.contractDataSource.registerContractFunctionSignatures(_address, signatures);
657
- }
658
- flushTxs() {
659
- if (!this.sequencer) {
660
- throw new Error(`Sequencer is not initialized`);
661
- }
662
- this.sequencer.flush();
663
- return Promise.resolve();
664
- }
665
- },
666
- _AztecNodeService_instances = new WeakSet(),
667
- _AztecNodeService_getWorldState =
668
- /**
669
- * Returns an instance of MerkleTreeOperations having first ensured the world state is fully synched
670
- * @param blockNumber - The block number at which to get the data.
671
- * @returns An instance of a committed MerkleTreeOperations
672
- */
673
- async function _AztecNodeService_getWorldState(blockNumber) {
674
- if (typeof blockNumber === 'number' && blockNumber < INITIAL_L2_BLOCK_NUM - 1) {
675
- throw new Error('Invalid block number to get world state for: ' + blockNumber);
676
- }
677
- let blockSyncedTo = 0;
678
- try {
679
- // Attempt to sync the world state if necessary
680
- blockSyncedTo = await __classPrivateFieldGet(this, _AztecNodeService_instances, "m", _AztecNodeService_syncWorldState).call(this);
681
- }
682
- catch (err) {
683
- this.log.error(`Error getting world state: ${err}`);
684
- }
685
- // using a snapshot could be less efficient than using the committed db
686
- if (blockNumber === 'latest' /*|| blockNumber === blockSyncedTo*/) {
687
- this.log.debug(`Using committed db for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
688
- return this.worldStateSynchronizer.getCommitted();
689
- }
690
- else if (blockNumber <= blockSyncedTo) {
691
- this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
692
- return this.worldStateSynchronizer.getSnapshot(blockNumber);
693
- }
694
- else {
695
- throw new Error(`Block ${blockNumber} not yet synced`);
696
- }
697
- },
698
- _AztecNodeService_syncWorldState =
699
- /**
700
- * Ensure we fully sync the world state
701
- * @returns A promise that fulfils once the world state is synced
702
- */
703
- async function _AztecNodeService_syncWorldState() {
704
- const blockSourceHeight = await this.blockSource.getBlockNumber();
705
- return this.worldStateSynchronizer.syncImmediate(blockSourceHeight);
706
- },
707
- (() => {
708
- const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
709
- _simulatePublicCalls_decorators = [trackSpan('AztecNodeService.simulatePublicCalls', async (tx) => ({
710
- [Attributes.TX_HASH]: (await tx.getTxHash()).toString(),
711
- }))];
712
- __esDecorate(_a, null, _simulatePublicCalls_decorators, { kind: "method", name: "simulatePublicCalls", static: false, private: false, access: { has: obj => "simulatePublicCalls" in obj, get: obj => obj.simulatePublicCalls }, metadata: _metadata }, null, _instanceExtraInitializers);
713
- if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
714
- })(),
715
- _a;
716
- })();
717
- export { AztecNodeService };
718
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2F6dGVjLW5vZGUvc2VydmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDakQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLG1CQUFtQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDMUUsT0FBTyxFQUFnQyxvQkFBb0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzdGLE9BQU8sRUFhTCxZQUFZLEVBQ1osMEJBQTBCLEVBRTFCLGFBQWEsRUFFYixpQkFBaUIsRUFDakIsc0JBQXNCLEVBR3RCLFdBQVcsRUFJWCxTQUFTLEVBRVQsUUFBUSxFQUdSLE9BQU8sR0FDUixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFNTCxVQUFVLEVBQ1YsRUFBRSxFQUVGLG9CQUFvQixFQVVwQiwyQkFBMkIsR0FDNUIsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQUUsNkJBQTZCLEVBQUUsYUFBYSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDdkYsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sRUFBNEIsbUJBQW1CLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDL0QsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzVELE9BQU8sRUFBZSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRTlELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNwRCxPQUFPLEVBQUUsV0FBVyxFQUFFLFlBQVksRUFBRSxjQUFjLEVBQUUsTUFBTSxvQkFBb0Is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
631
+ throw failedTxs[0].error;
632
+ }
633
+ const [processedTx] = processedTxs;
634
+ return new PublicSimulationOutput(processedTx.revertReason, processedTx.constants, processedTx.txEffect, returns, processedTx.gasUsed);
635
+ } finally{
636
+ await fork.close();
637
+ }
638
+ }
639
+ async isValidTx(tx, { isSimulation, skipFeeEnforcement } = {}) {
640
+ const blockNumber = await this.blockSource.getBlockNumber() + 1;
641
+ const db = this.worldStateSynchronizer.getCommitted();
642
+ const verifier = isSimulation ? undefined : this.proofVerifier;
643
+ const validator = createValidatorForAcceptingTxs(db, this.contractDataSource, verifier, {
644
+ blockNumber,
645
+ l1ChainId: this.l1ChainId,
646
+ setupAllowList: this.config.allowedInSetup ?? await getDefaultAllowedSetupFunctions(),
647
+ gasFees: await this.getCurrentBaseFees(),
648
+ skipFeeEnforcement
649
+ });
650
+ return await validator.validateTx(tx);
651
+ }
652
+ async setConfig(config) {
653
+ const newConfig = {
654
+ ...this.config,
655
+ ...config
656
+ };
657
+ await this.sequencer?.updateSequencerConfig(config);
658
+ if (newConfig.realProofs !== this.config.realProofs) {
659
+ this.proofVerifier = config.realProofs ? await BBCircuitVerifier.new(newConfig) : new TestCircuitVerifier();
660
+ }
661
+ this.config = newConfig;
662
+ }
663
+ getProtocolContractAddresses() {
664
+ return Promise.resolve({
665
+ classRegisterer: ProtocolContractAddress.ContractClassRegisterer,
666
+ feeJuice: ProtocolContractAddress.FeeJuice,
667
+ instanceDeployer: ProtocolContractAddress.ContractInstanceDeployer,
668
+ multiCallEntrypoint: ProtocolContractAddress.MultiCallEntrypoint
669
+ });
670
+ }
671
+ // TODO(#10007): Remove this method
672
+ addContractClass(contractClass) {
673
+ this.log.info(`Adding contract class via API ${contractClass.id}`);
674
+ return this.contractDataSource.addContractClass(contractClass);
675
+ }
676
+ registerContractFunctionSignatures(_address, signatures) {
677
+ return this.contractDataSource.registerContractFunctionSignatures(_address, signatures);
678
+ }
679
+ flushTxs() {
680
+ if (!this.sequencer) {
681
+ throw new Error(`Sequencer is not initialized`);
682
+ }
683
+ this.sequencer.flush();
684
+ return Promise.resolve();
685
+ }
686
+ /**
687
+ * Returns an instance of MerkleTreeOperations having first ensured the world state is fully synched
688
+ * @param blockNumber - The block number at which to get the data.
689
+ * @returns An instance of a committed MerkleTreeOperations
690
+ */ async #getWorldState(blockNumber) {
691
+ if (typeof blockNumber === 'number' && blockNumber < INITIAL_L2_BLOCK_NUM - 1) {
692
+ throw new Error('Invalid block number to get world state for: ' + blockNumber);
693
+ }
694
+ let blockSyncedTo = 0;
695
+ try {
696
+ // Attempt to sync the world state if necessary
697
+ blockSyncedTo = await this.#syncWorldState();
698
+ } catch (err) {
699
+ this.log.error(`Error getting world state: ${err}`);
700
+ }
701
+ // using a snapshot could be less efficient than using the committed db
702
+ if (blockNumber === 'latest' /*|| blockNumber === blockSyncedTo*/ ) {
703
+ this.log.debug(`Using committed db for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
704
+ return this.worldStateSynchronizer.getCommitted();
705
+ } else if (blockNumber <= blockSyncedTo) {
706
+ this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
707
+ return this.worldStateSynchronizer.getSnapshot(blockNumber);
708
+ } else {
709
+ throw new Error(`Block ${blockNumber} not yet synced`);
710
+ }
711
+ }
712
+ /**
713
+ * Ensure we fully sync the world state
714
+ * @returns A promise that fulfils once the world state is synced
715
+ */ async #syncWorldState() {
716
+ const blockSourceHeight = await this.blockSource.getBlockNumber();
717
+ return this.worldStateSynchronizer.syncImmediate(blockSourceHeight);
718
+ }
719
+ }
720
+ _ts_decorate([
721
+ trackSpan('AztecNodeService.simulatePublicCalls', async (tx)=>({
722
+ [Attributes.TX_HASH]: (await tx.getTxHash()).toString()
723
+ }))
724
+ ], AztecNodeService.prototype, "simulatePublicCalls", null);