@aztec-labs/aztec-node 6.0.0-nightly.20260829

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.
Files changed (83) hide show
  1. package/README.md +15 -0
  2. package/dest/aztec-node/block_response_helpers.d.ts +25 -0
  3. package/dest/aztec-node/block_response_helpers.d.ts.map +1 -0
  4. package/dest/aztec-node/block_response_helpers.js +112 -0
  5. package/dest/aztec-node/config.d.ts +52 -0
  6. package/dest/aztec-node/config.d.ts.map +1 -0
  7. package/dest/aztec-node/config.js +129 -0
  8. package/dest/aztec-node/node_metrics.d.ts +12 -0
  9. package/dest/aztec-node/node_metrics.d.ts.map +1 -0
  10. package/dest/aztec-node/node_metrics.js +36 -0
  11. package/dest/aztec-node/node_public_calls_simulator.d.ts +108 -0
  12. package/dest/aztec-node/node_public_calls_simulator.d.ts.map +1 -0
  13. package/dest/aztec-node/node_public_calls_simulator.js +380 -0
  14. package/dest/aztec-node/public_data_overrides.d.ts +13 -0
  15. package/dest/aztec-node/public_data_overrides.d.ts.map +1 -0
  16. package/dest/aztec-node/public_data_overrides.js +21 -0
  17. package/dest/aztec-node/register_node_rpc_handlers.d.ts +11 -0
  18. package/dest/aztec-node/register_node_rpc_handlers.d.ts.map +1 -0
  19. package/dest/aztec-node/register_node_rpc_handlers.js +48 -0
  20. package/dest/aztec-node/server.d.ts +281 -0
  21. package/dest/aztec-node/server.d.ts.map +1 -0
  22. package/dest/aztec-node/server.js +1235 -0
  23. package/dest/bin/index.d.ts +3 -0
  24. package/dest/bin/index.d.ts.map +1 -0
  25. package/dest/bin/index.js +57 -0
  26. package/dest/factory.d.ts +33 -0
  27. package/dest/factory.d.ts.map +1 -0
  28. package/dest/factory.js +539 -0
  29. package/dest/index.d.ts +5 -0
  30. package/dest/index.d.ts.map +1 -0
  31. package/dest/index.js +4 -0
  32. package/dest/modules/block_parameter.d.ts +25 -0
  33. package/dest/modules/block_parameter.d.ts.map +1 -0
  34. package/dest/modules/block_parameter.js +100 -0
  35. package/dest/modules/node_block_provider.d.ts +19 -0
  36. package/dest/modules/node_block_provider.d.ts.map +1 -0
  37. package/dest/modules/node_block_provider.js +112 -0
  38. package/dest/modules/node_tx_receipt.d.ts +24 -0
  39. package/dest/modules/node_tx_receipt.d.ts.map +1 -0
  40. package/dest/modules/node_tx_receipt.js +70 -0
  41. package/dest/modules/node_world_state_queries.d.ts +65 -0
  42. package/dest/modules/node_world_state_queries.d.ts.map +1 -0
  43. package/dest/modules/node_world_state_queries.js +270 -0
  44. package/dest/sentinel/config.d.ts +9 -0
  45. package/dest/sentinel/config.d.ts.map +1 -0
  46. package/dest/sentinel/config.js +39 -0
  47. package/dest/sentinel/factory.d.ts +11 -0
  48. package/dest/sentinel/factory.d.ts.map +1 -0
  49. package/dest/sentinel/factory.js +24 -0
  50. package/dest/sentinel/index.d.ts +3 -0
  51. package/dest/sentinel/index.d.ts.map +1 -0
  52. package/dest/sentinel/index.js +1 -0
  53. package/dest/sentinel/sentinel.d.ts +217 -0
  54. package/dest/sentinel/sentinel.d.ts.map +1 -0
  55. package/dest/sentinel/sentinel.js +551 -0
  56. package/dest/sentinel/store.d.ts +35 -0
  57. package/dest/sentinel/store.d.ts.map +1 -0
  58. package/dest/sentinel/store.js +182 -0
  59. package/dest/test/index.d.ts +31 -0
  60. package/dest/test/index.d.ts.map +1 -0
  61. package/dest/test/index.js +1 -0
  62. package/package.json +118 -0
  63. package/src/aztec-node/block_response_helpers.ts +161 -0
  64. package/src/aztec-node/config.ts +216 -0
  65. package/src/aztec-node/node_metrics.ts +49 -0
  66. package/src/aztec-node/node_public_calls_simulator.ts +437 -0
  67. package/src/aztec-node/public_data_overrides.ts +35 -0
  68. package/src/aztec-node/register_node_rpc_handlers.ts +45 -0
  69. package/src/aztec-node/server.ts +1155 -0
  70. package/src/bin/index.ts +77 -0
  71. package/src/factory.ts +704 -0
  72. package/src/index.ts +4 -0
  73. package/src/modules/block_parameter.ts +93 -0
  74. package/src/modules/node_block_provider.ts +149 -0
  75. package/src/modules/node_tx_receipt.ts +115 -0
  76. package/src/modules/node_world_state_queries.ts +373 -0
  77. package/src/sentinel/README.md +103 -0
  78. package/src/sentinel/config.ts +49 -0
  79. package/src/sentinel/factory.ts +46 -0
  80. package/src/sentinel/index.ts +8 -0
  81. package/src/sentinel/sentinel.ts +694 -0
  82. package/src/sentinel/store.ts +193 -0
  83. package/src/test/index.ts +32 -0
@@ -0,0 +1,380 @@
1
+ function _ts_add_disposable_resource(env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() {
16
+ try {
17
+ inner.call(this);
18
+ } catch (e) {
19
+ return Promise.reject(e);
20
+ }
21
+ };
22
+ env.stack.push({
23
+ value: value,
24
+ dispose: dispose,
25
+ async: async
26
+ });
27
+ } else if (async) {
28
+ env.stack.push({
29
+ async: true
30
+ });
31
+ }
32
+ return value;
33
+ }
34
+ function _ts_dispose_resources(env) {
35
+ var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
36
+ var e = new Error(message);
37
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
38
+ };
39
+ return (_ts_dispose_resources = function _ts_dispose_resources(env) {
40
+ function fail(e) {
41
+ env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
42
+ env.hasError = true;
43
+ }
44
+ var r, s = 0;
45
+ function next() {
46
+ while(r = env.stack.pop()){
47
+ try {
48
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
49
+ if (r.dispose) {
50
+ var result = r.dispose.call(r.value);
51
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
52
+ fail(e);
53
+ return next();
54
+ });
55
+ } else s |= 1;
56
+ } catch (e) {
57
+ fail(e);
58
+ }
59
+ }
60
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
61
+ if (env.hasError) throw env.error;
62
+ }
63
+ return next();
64
+ })(env);
65
+ }
66
+ import { MAX_L1_TO_L2_MSGS_PER_BLOCK, MAX_L1_TO_L2_MSGS_PER_CHECKPOINT } from '@aztec-labs/constants';
67
+ import { PROPOSER_PIPELINING_SLOT_OFFSET } from '@aztec-labs/epoch-cache';
68
+ import { SimulationOverridesBuilder } from '@aztec-labs/ethereum/contracts';
69
+ import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec-labs/foundation/branded-types';
70
+ import { compactArray } from '@aztec-labs/foundation/collection';
71
+ import { EthAddress } from '@aztec-labs/foundation/eth-address';
72
+ import { BadRequestError } from '@aztec-labs/foundation/json-rpc';
73
+ import { createLogger } from '@aztec-labs/foundation/log';
74
+ import { DateProvider } from '@aztec-labs/foundation/timer';
75
+ import { selectInboxBucketForBlock } from '@aztec-labs/sequencer-client';
76
+ import { PublicContractsDB, PublicProcessorFactory } from '@aztec-labs/simulator/server';
77
+ import { CollectionLimitsConfig, PublicSimulatorConfig } from '@aztec-labs/stdlib/avm';
78
+ import { AztecAddress } from '@aztec-labs/stdlib/aztec-address';
79
+ import { buildCheckpointSimulationOverridesPlan } from '@aztec-labs/stdlib/checkpoint';
80
+ import { appendL1ToL2MessagesToTree, getInboxCutoffTimestamp } from '@aztec-labs/stdlib/messaging';
81
+ import { MerkleTreeId } from '@aztec-labs/stdlib/trees';
82
+ import { GlobalVariables, PublicSimulationOutput } from '@aztec-labs/stdlib/tx';
83
+ import { getTelemetryClient } from '@aztec-labs/telemetry-client';
84
+ import { applyPublicDataOverrides } from './public_data_overrides.js';
85
+ /**
86
+ * Simulates the public part of a transaction against a fresh world-state fork.
87
+ *
88
+ * Extracted from `AztecNodeService` so the slot/globals selection can be unit-tested without
89
+ * standing up the whole node, and to keep `server.ts` smaller.
90
+ *
91
+ * The simulator picks globals in one of two ways, mirroring how the sequencer builds the next block:
92
+ * - **When the next block continues an in-progress checkpoint** (the latest proposed block is ahead of
93
+ * the proposed-checkpoint frontier): every block in a checkpoint shares the same
94
+ * `CheckpointGlobalVariables`, so we copy the latest proposed block's globals verbatim and only
95
+ * bump the block number. No L1 calls.
96
+ * - **When the next block opens a new checkpoint** (the latest proposed block coincides with the
97
+ * proposed-checkpoint frontier): we compute fresh globals for the slot the next block will land in,
98
+ * applying the same `SimulationOverridesPlan` the sequencer applies so the simulated mana min fee
99
+ * matches what the sequencer will write into the block header.
100
+ *
101
+ * Either way it also predicts the L1-to-L2 message bundle the next block would consume and appends it
102
+ * to the fork, so a transaction consuming a message that is in the Inbox but not yet in a block
103
+ * simulates against the state it will actually run in.
104
+ */ export class NodePublicCallsSimulator {
105
+ blockSource;
106
+ worldStateSynchronizer;
107
+ l1ToL2MessageSource;
108
+ contractDataSource;
109
+ globalVariableBuilder;
110
+ rollupContract;
111
+ epochCache;
112
+ signatureContext;
113
+ config;
114
+ avmSimulator;
115
+ telemetry;
116
+ log;
117
+ dateProvider = new DateProvider();
118
+ constructor(deps){
119
+ this.blockSource = deps.blockSource;
120
+ this.worldStateSynchronizer = deps.worldStateSynchronizer;
121
+ this.l1ToL2MessageSource = deps.l1ToL2MessageSource;
122
+ this.contractDataSource = deps.contractDataSource;
123
+ this.globalVariableBuilder = deps.globalVariableBuilder;
124
+ this.rollupContract = deps.rollupContract;
125
+ this.epochCache = deps.epochCache;
126
+ this.signatureContext = deps.signatureContext;
127
+ this.config = deps.config;
128
+ this.avmSimulator = deps.avmSimulator;
129
+ this.telemetry = deps.telemetry ?? getTelemetryClient();
130
+ this.log = deps.log ?? createLogger('node:public-calls-simulator');
131
+ }
132
+ /**
133
+ * Simulates the public part of a transaction with the current state.
134
+ * @param tx - The transaction to simulate.
135
+ * @param skipFeeEnforcement - If true, fee enforcement is skipped.
136
+ * @param overrides - Optional pre-simulation overrides applied to the ephemeral fork and contract DB.
137
+ */ async simulate(tx, skipFeeEnforcement = false, overrides) {
138
+ const env = {
139
+ stack: [],
140
+ error: void 0,
141
+ hasError: false
142
+ };
143
+ try {
144
+ // Check total gas limit for simulation
145
+ const gasSettings = tx.data.constants.txContext.gasSettings;
146
+ const txGasLimit = gasSettings.gasLimits.l2Gas;
147
+ const teardownGasLimit = gasSettings.teardownGasLimits.l2Gas;
148
+ if (txGasLimit + teardownGasLimit > this.config.rpcSimulatePublicMaxGasLimit) {
149
+ throw new BadRequestError(`Transaction total gas limit ${txGasLimit + teardownGasLimit} (${txGasLimit} + ${teardownGasLimit}) exceeds maximum gas limit ${this.config.rpcSimulatePublicMaxGasLimit} for simulation`);
150
+ }
151
+ const txHash = tx.getTxHash();
152
+ const [l2Tips, proposedCheckpointData] = await Promise.all([
153
+ this.blockSource.getL2Tips(),
154
+ this.blockSource.getProposedCheckpointData()
155
+ ]);
156
+ const latestBlockNumber = l2Tips.proposed.number;
157
+ const blockNumber = BlockNumber.add(latestBlockNumber, 1);
158
+ // Terminating block of the proposed-checkpoint frontier. `getProposedCheckpointData()` returns the
159
+ // leading proposed (not-yet-L1-confirmed) checkpoint, whose last block is `startBlock + blockCount
160
+ // - 1`; with no proposed checkpoint the frontier coincides with the checkpointed tip.
161
+ const proposedCheckpointLastBlock = proposedCheckpointData ? BlockNumber.add(proposedCheckpointData.startBlock, proposedCheckpointData.blockCount - 1) : l2Tips.checkpointed.block.number;
162
+ // The next block continues the in-progress checkpoint when the latest proposed block is ahead of
163
+ // the proposed-checkpoint terminating block; it opens a new checkpoint when they coincide.
164
+ const atCheckpointBoundary = proposedCheckpointLastBlock === l2Tips.proposed.number;
165
+ const { globalVariables: newGlobalVariables } = atCheckpointBoundary ? await this.buildGlobalVariablesForNewCheckpoint(l2Tips, proposedCheckpointData, blockNumber) : {
166
+ globalVariables: await this.copyGlobalVariablesFromLatestProposedBlock(latestBlockNumber, blockNumber)
167
+ };
168
+ if (!this.avmSimulator) {
169
+ throw new Error('NodePublicCallsSimulator.simulate requires an AVM simulator, but none was configured');
170
+ }
171
+ const publicProcessorFactory = new PublicProcessorFactory(this.contractDataSource, this.avmSimulator, this.dateProvider, this.telemetry, this.log.getBindings());
172
+ this.log.verbose(`Simulating public calls for tx ${txHash}`, {
173
+ globalVariables: newGlobalVariables.toInspect(),
174
+ txHash,
175
+ blockNumber,
176
+ atCheckpointBoundary
177
+ });
178
+ // Ensure world-state has caught up with the latest block we loaded from the archiver
179
+ await this.worldStateSynchronizer.syncImmediate(latestBlockNumber);
180
+ const merkleTreeFork = _ts_add_disposable_resource(env, await this.worldStateSynchronizer.fork(latestBlockNumber), true);
181
+ await this.appendPredictedL1ToL2Messages(merkleTreeFork, {
182
+ slotNumber: newGlobalVariables.slotNumber,
183
+ checkpointStartBlock: atCheckpointBoundary ? undefined : proposedCheckpointLastBlock
184
+ });
185
+ await applyPublicDataOverrides(merkleTreeFork, overrides?.publicStorage);
186
+ const config = PublicSimulatorConfig.from({
187
+ skipFeeEnforcement,
188
+ collectDebugLogs: true,
189
+ collectHints: false,
190
+ collectCallMetadata: true,
191
+ collectStatistics: false,
192
+ collectionLimits: CollectionLimitsConfig.from({
193
+ maxDebugLogMemoryReads: this.config.rpcSimulatePublicMaxDebugLogMemoryReads
194
+ })
195
+ });
196
+ const contractsDB = new PublicContractsDB(this.contractDataSource, this.log.getBindings());
197
+ if (overrides?.contracts) {
198
+ contractsDB.addContracts(Object.values(overrides.contracts).map(({ instance })=>instance));
199
+ }
200
+ const processor = publicProcessorFactory.create(merkleTreeFork, newGlobalVariables, config, contractsDB);
201
+ // REFACTOR: Consider merging ProcessReturnValues into ProcessedTx
202
+ const [processedTxs, failedTxs, _usedTxs, returns, debugLogs] = await processor.process([
203
+ tx
204
+ ]);
205
+ // REFACTOR: Consider returning the error rather than throwing
206
+ if (failedTxs.length) {
207
+ this.log.warn(`Simulated tx ${txHash} fails: ${failedTxs[0].error}`, {
208
+ txHash
209
+ });
210
+ throw failedTxs[0].error;
211
+ }
212
+ const [processedTx] = processedTxs;
213
+ return new PublicSimulationOutput(processedTx.revertReason, processedTx.globalVariables, processedTx.txEffect, returns, processedTx.gasUsed, debugLogs);
214
+ } catch (e) {
215
+ env.error = e;
216
+ env.hasError = true;
217
+ } finally{
218
+ const result = _ts_dispose_resources(env);
219
+ if (result) await result;
220
+ }
221
+ }
222
+ /**
223
+ * Appends the L1-to-L2 message bundle the next block would consume to the simulation fork, so a transaction
224
+ * consuming a message that has reached the Inbox but no block yet simulates against the state it will run in.
225
+ * Runs the same bucket selection the sequencer runs (lag eligibility plus the per-block and per-checkpoint caps),
226
+ * treating the next block as non-final: the censorship cutoff only widens consumption on a checkpoint's last
227
+ * block, and the node cannot know whether the next block is it.
228
+ *
229
+ * Best-effort. Any failure — Inbox buckets not synced yet, a torn archiver snapshot — leaves the fork at the tip
230
+ * state, which is what the transaction sees if the next block consumes nothing.
231
+ */ async appendPredictedL1ToL2Messages(fork, opts) {
232
+ try {
233
+ const parentTotalMsgCount = (await fork.getTreeInfo(MerkleTreeId.L1_TO_L2_MESSAGE_TREE)).size;
234
+ const parentBucket = await this.l1ToL2MessageSource.getInboxBucketByTotalMsgCount(parentTotalMsgCount);
235
+ if (parentBucket === undefined) {
236
+ this.log.debug(`Inbox bucket at message total ${parentTotalMsgCount} not synced; simulating against the tip`, {
237
+ parentTotalMsgCount
238
+ });
239
+ return;
240
+ }
241
+ // Origin of the per-checkpoint cap: the total consumed as of the checkpoint's parent. A block extending an
242
+ // in-progress checkpoint reads it off that checkpoint's parent block; a block opening one starts from the tip.
243
+ const checkpointStartTotalMsgCount = opts.checkpointStartBlock === undefined ? parentTotalMsgCount : await this.getConsumedMessageTotal(opts.checkpointStartBlock);
244
+ if (checkpointStartTotalMsgCount === undefined) {
245
+ this.log.debug(`Block ${opts.checkpointStartBlock} has no header on this node; simulating against the tip`);
246
+ return;
247
+ }
248
+ const l1Constants = this.epochCache.getL1Constants();
249
+ const selection = await selectInboxBucketForBlock({
250
+ messageSource: this.l1ToL2MessageSource,
251
+ now: BigInt(Math.floor(this.dateProvider.now() / 1000)),
252
+ minBucketAgeSeconds: BigInt(l1Constants.ethereumSlotDuration),
253
+ parent: {
254
+ seq: parentBucket.seq,
255
+ totalMsgCount: parentBucket.totalMsgCount
256
+ },
257
+ checkpointStartTotalMsgCount,
258
+ perBlockCap: MAX_L1_TO_L2_MSGS_PER_BLOCK,
259
+ perCheckpointCap: MAX_L1_TO_L2_MSGS_PER_CHECKPOINT,
260
+ isLastBlock: false,
261
+ cutoffTimestamp: getInboxCutoffTimestamp(opts.slotNumber, l1Constants)
262
+ });
263
+ if (!selection.consume || selection.bundle.length === 0) {
264
+ return;
265
+ }
266
+ await appendL1ToL2MessagesToTree(fork, selection.bundle);
267
+ this.log.debug(`Appended ${selection.bundle.length} predicted L1-to-L2 messages to the simulation fork`, {
268
+ bucketSeq: selection.bucket.seq,
269
+ messageCount: selection.bundle.length
270
+ });
271
+ } catch (err) {
272
+ this.log.verbose(`Could not predict the next block's L1-to-L2 messages, simulating against the tip: ${err}`);
273
+ }
274
+ }
275
+ /** Cumulative Inbox message total consumed as of `blockNumber`, i.e. its L1-to-L2 message tree leaf count. */ async getConsumedMessageTotal(blockNumber) {
276
+ if (blockNumber === BlockNumber.ZERO) {
277
+ return 0n;
278
+ }
279
+ const block = await this.blockSource.getBlockData({
280
+ number: blockNumber
281
+ });
282
+ return block === undefined ? undefined : BigInt(block.header.state.l1ToL2MessageTree.nextAvailableLeafIndex);
283
+ }
284
+ /**
285
+ * Continues an in-progress checkpoint: the next block extends the checkpoint the latest proposed
286
+ * block belongs to. Every block in a checkpoint shares the same `CheckpointGlobalVariables`, so the
287
+ * next block's globals are the latest proposed block's globals with only the block number bumped —
288
+ * including the proposer's real coinbase/feeRecipient. No L1 reads happen here.
289
+ *
290
+ * A missing header means the archiver reported a proposed tip via `getL2Tips` but no longer has its
291
+ * data (a torn snapshot). We throw a transient/retryable error rather than treating the next block as
292
+ * opening a new checkpoint, whose globals would be built for the wrong slot.
293
+ */ async copyGlobalVariablesFromLatestProposedBlock(latestBlockNumber, blockNumber) {
294
+ const latestBlockData = await this.blockSource.getBlockData({
295
+ number: latestBlockNumber
296
+ });
297
+ if (!latestBlockData) {
298
+ throw new Error(`Cannot simulate public calls: latest proposed block ${latestBlockNumber} has no header on this node ` + `(torn archiver snapshot); retry`);
299
+ }
300
+ return GlobalVariables.from({
301
+ ...latestBlockData.header.globalVariables,
302
+ blockNumber
303
+ });
304
+ }
305
+ /**
306
+ * Opens a new checkpoint: the next block is the first of a fresh checkpoint. Picks the slot the next
307
+ * block will land in, mirroring the sequencer, and builds the same `SimulationOverridesPlan` the
308
+ * sequencer applies so the simulated mana min fee matches what the sequencer will write into the
309
+ * block header. Coinbase and fee recipient stay zero (we cannot know the future proposer's payout
310
+ * addresses), unlike continuing an in-progress checkpoint which inherits the real ones from the
311
+ * proposed header.
312
+ */ async buildGlobalVariablesForNewCheckpoint(l2Tips, proposedCheckpointData, blockNumber) {
313
+ const checkpointedCheckpointNumber = l2Tips.checkpointed.checkpoint.number;
314
+ const targetSlot = this.computeTargetSlot(proposedCheckpointData);
315
+ const plan = await this.buildSimulationOverridesPlan(proposedCheckpointData, checkpointedCheckpointNumber);
316
+ const checkpointGlobalVariables = await this.globalVariableBuilder.buildCheckpointGlobalVariables(EthAddress.ZERO, AztecAddress.ZERO, targetSlot, plan);
317
+ return {
318
+ globalVariables: GlobalVariables.from({
319
+ blockNumber,
320
+ ...checkpointGlobalVariables
321
+ })
322
+ };
323
+ }
324
+ /**
325
+ * Slot the next block will land in. The first term is the sequencer's exact formula
326
+ * (`getEpochAndSlotInNextL1Slot().slot + PROPOSER_PIPELINING_SLOT_OFFSET`). The `max` with
327
+ * `proposedCheckpointSlot + 1` is an RPC-side approximation of the next build: when a proposed
328
+ * checkpoint is gossiped before its L1 slot starts, the next build (once its wall clock arrives)
329
+ * will target `parentSlot + 1`. The sequencer never advances its own target past wall clock — it
330
+ * just declines to build — so this is a prediction of inclusion globals, not literal sequencer
331
+ * behavior. The parent slot comes from the proposed checkpoint header so the slot and the
332
+ * overrides plan cannot derive from different snapshots.
333
+ */ computeTargetSlot(proposedCheckpointData) {
334
+ const slotFromNextL1Timestamp = this.epochCache.getEpochAndSlotInNextL1Slot().slot + PROPOSER_PIPELINING_SLOT_OFFSET;
335
+ const slotAfterProposedCheckpoint = proposedCheckpointData ? proposedCheckpointData.header.slotNumber + 1 : undefined;
336
+ return SlotNumber(Math.max(...compactArray([
337
+ slotFromNextL1Timestamp,
338
+ slotAfterProposedCheckpoint
339
+ ])));
340
+ }
341
+ /**
342
+ * Builds the chain-state overrides plan the simulator passes to `buildCheckpointGlobalVariables`,
343
+ * mirroring the sequencer (which always pins tips to neutralize prunes). When pipelining, the plan
344
+ * carries the proposed parent's archive, temp-checkpoint-log cell, and locally-derived fee header.
345
+ *
346
+ * Both the pipelining and invalid-pending-chain paths need a rollup contract for the L1 fee reads.
347
+ * Environments that omit it (e.g. TXE, which never has a proposed checkpoint and whose pending chain
348
+ * is always valid) fall back to pinning both pending and proven tips to the checkpointed tip, which
349
+ * neutralizes prunes in fee computation at the cost of non-pipelined fees.
350
+ */ async buildSimulationOverridesPlan(proposedCheckpointData, checkpointedCheckpointNumber) {
351
+ const rollup = this.rollupContract;
352
+ if (rollup) {
353
+ if (proposedCheckpointData) {
354
+ return buildCheckpointSimulationOverridesPlan({
355
+ checkpointNumber: CheckpointNumber(proposedCheckpointData.checkpointNumber + 1),
356
+ proposedCheckpointData,
357
+ checkpointedCheckpointNumber,
358
+ rollup,
359
+ signatureContext: this.signatureContext,
360
+ log: this.log
361
+ });
362
+ }
363
+ const validationStatus = await this.blockSource.getPendingChainValidationStatus();
364
+ if (!validationStatus.valid) {
365
+ return buildCheckpointSimulationOverridesPlan({
366
+ checkpointNumber: CheckpointNumber(checkpointedCheckpointNumber + 1),
367
+ invalidateToPendingCheckpointNumber: CheckpointNumber(validationStatus.checkpoint.checkpointNumber - 1),
368
+ checkpointedCheckpointNumber,
369
+ rollup,
370
+ signatureContext: this.signatureContext,
371
+ log: this.log
372
+ });
373
+ }
374
+ }
375
+ return new SimulationOverridesBuilder().withChainTips({
376
+ pending: checkpointedCheckpointNumber,
377
+ proven: checkpointedCheckpointNumber
378
+ }).build();
379
+ }
380
+ }
@@ -0,0 +1,13 @@
1
+ import type { PublicStorageOverride } from '@aztec-labs/stdlib/interfaces/client';
2
+ import type { MerkleTreeWriteOperations } from '@aztec-labs/stdlib/interfaces/server';
3
+ /**
4
+ * Injects public-state overrides into an (ephemeral) world-state fork before simulation.
5
+ *
6
+ * Each override is written via the same `sequentialInsert` path the public processor
7
+ * uses during real transaction execution, so low-leaf updates and root coherence are
8
+ * handled identically for both simulation and proof generation.
9
+ *
10
+ * Writes never reach committed world state — the fork is thrown away after simulation.
11
+ */
12
+ export declare function applyPublicDataOverrides(fork: MerkleTreeWriteOperations, publicStorage: PublicStorageOverride[] | undefined): Promise<void>;
13
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljX2RhdGFfb3ZlcnJpZGVzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXp0ZWMtbm9kZS9wdWJsaWNfZGF0YV9vdmVycmlkZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxLQUFLLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUNsRixPQUFPLEtBQUssRUFBRSx5QkFBeUIsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBR3RGOzs7Ozs7OztHQVFHO0FBQ0gsd0JBQXNCLHdCQUF3QixDQUM1QyxJQUFJLEVBQUUseUJBQXlCLEVBQy9CLGFBQWEsRUFBRSxxQkFBcUIsRUFBRSxHQUFHLFNBQVMsR0FDakQsT0FBTyxDQUFDLElBQUksQ0FBQyxDQWdCZiJ9
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public_data_overrides.d.ts","sourceRoot":"","sources":["../../src/aztec-node/public_data_overrides.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAClF,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAGtF;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,yBAAyB,EAC/B,aAAa,EAAE,qBAAqB,EAAE,GAAG,SAAS,GACjD,OAAO,CAAC,IAAI,CAAC,CAgBf"}
@@ -0,0 +1,21 @@
1
+ import { PublicDataWrite } from '@aztec-labs/stdlib/avm';
2
+ import { computePublicDataTreeLeafSlot } from '@aztec-labs/stdlib/hash';
3
+ import { MerkleTreeId } from '@aztec-labs/stdlib/trees';
4
+ /**
5
+ * Injects public-state overrides into an (ephemeral) world-state fork before simulation.
6
+ *
7
+ * Each override is written via the same `sequentialInsert` path the public processor
8
+ * uses during real transaction execution, so low-leaf updates and root coherence are
9
+ * handled identically for both simulation and proof generation.
10
+ *
11
+ * Writes never reach committed world state — the fork is thrown away after simulation.
12
+ */ export async function applyPublicDataOverrides(fork, publicStorage) {
13
+ if (!publicStorage?.length) {
14
+ return;
15
+ }
16
+ const writes = await Promise.all(publicStorage.map(async (o)=>{
17
+ const leafSlot = await computePublicDataTreeLeafSlot(o.contract, o.slot);
18
+ return new PublicDataWrite(leafSlot, o.value);
19
+ }));
20
+ await fork.sequentialInsert(MerkleTreeId.PUBLIC_DATA_TREE, writes.map((w)=>w.toBuffer()));
21
+ }
@@ -0,0 +1,11 @@
1
+ import type { NamespacedApiHandlers } from '@aztec-labs/foundation/json-rpc/server';
2
+ import type { AztecNodeService } from './server.js';
3
+ /**
4
+ * Registers the Aztec node RPC handlers (`aztec_*`, `aztecAdmin_*`, and optionally `aztecDebug_*`), along with the
5
+ * legacy pre-v5 namespaces (`node_*`, `nodeAdmin_*`, `nodeDebug_*`, `p2p_*`) for backwards compatibility.
6
+ */
7
+ export declare function registerAztecNodeRpcHandlers(node: AztecNodeService, services: NamespacedApiHandlers, adminServices?: NamespacedApiHandlers, options?: {
8
+ debug?: boolean;
9
+ p2pHealthMinPeers?: number;
10
+ }): void;
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaXN0ZXJfbm9kZV9ycGNfaGFuZGxlcnMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9henRlYy1ub2RlL3JlZ2lzdGVyX25vZGVfcnBjX2hhbmRsZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLHFCQUFxQixFQUFpQixNQUFNLHdDQUF3QyxDQUFDO0FBUW5HLE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBYXBEOzs7R0FHRztBQUVILHdCQUFnQiw0QkFBNEIsQ0FDMUMsSUFBSSxFQUFFLGdCQUFnQixFQUN0QixRQUFRLEVBQUUscUJBQXFCLEVBQy9CLGFBQWEsQ0FBQyxFQUFFLHFCQUFxQixFQUNyQyxPQUFPLEdBQUU7SUFBRSxLQUFLLENBQUMsRUFBRSxPQUFPLENBQUM7SUFBQyxpQkFBaUIsQ0FBQyxFQUFFLE1BQU0sQ0FBQTtDQUFPLEdBQzVELElBQUksQ0FhTiJ9
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register_node_rpc_handlers.d.ts","sourceRoot":"","sources":["../../src/aztec-node/register_node_rpc_handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAiB,MAAM,wCAAwC,CAAC;AAQnG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAapD;;;GAGG;AAEH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,gBAAgB,EACtB,QAAQ,EAAE,qBAAqB,EAC/B,aAAa,CAAC,EAAE,qBAAqB,EACrC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,IAAI,CAaN"}
@@ -0,0 +1,48 @@
1
+ import { AztecNodeAdminApiSchema, AztecNodeApiSchema, AztecNodeDebugApiSchema } from '@aztec-labs/stdlib/interfaces/client';
2
+ import { P2PApiSchema } from '@aztec-labs/stdlib/interfaces/server';
3
+ /**
4
+ * Health check for the p2p component: reports whether p2p is enabled and how many peers are connected, and fails
5
+ * when p2p is enabled but connected to fewer peers than the given minimum. A minimum of zero never fails.
6
+ */ function makeP2PHealthCheck(p2p, minPeers) {
7
+ return async ()=>{
8
+ const { enabled, connectedPeers } = await p2p.getP2PConnectivity();
9
+ return {
10
+ healthy: !enabled || connectedPeers >= minPeers,
11
+ details: {
12
+ enabled,
13
+ connectedPeers
14
+ }
15
+ };
16
+ };
17
+ }
18
+ /**
19
+ * Registers the Aztec node RPC handlers (`aztec_*`, `aztecAdmin_*`, and optionally `aztecDebug_*`), along with the
20
+ * legacy pre-v5 namespaces (`node_*`, `nodeAdmin_*`, `nodeDebug_*`, `p2p_*`) for backwards compatibility.
21
+ */ // TODO: Legacy support for node, nodeAdmin, nodeDebug, p2p namespaces. New namespaces introduced in v5. Remove on future release. A-1169
22
+ export function registerAztecNodeRpcHandlers(node, services, adminServices, options = {}) {
23
+ const p2p = node.getP2P();
24
+ services.aztec = [
25
+ node,
26
+ AztecNodeApiSchema
27
+ ];
28
+ services.node = services.aztec;
29
+ services.p2p = [
30
+ p2p,
31
+ P2PApiSchema,
32
+ makeP2PHealthCheck(p2p, options.p2pHealthMinPeers ?? 0)
33
+ ];
34
+ if (adminServices) {
35
+ adminServices.aztecAdmin = [
36
+ node,
37
+ AztecNodeAdminApiSchema
38
+ ];
39
+ adminServices.nodeAdmin = adminServices.aztecAdmin;
40
+ }
41
+ if (options.debug) {
42
+ services.aztecDebug = [
43
+ node,
44
+ AztecNodeDebugApiSchema
45
+ ];
46
+ services.nodeDebug = services.aztecDebug;
47
+ }
48
+ }