@aztec/world-state 0.0.1-commit.f504929 → 0.0.1-commit.f5a9928

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 (57) hide show
  1. package/dest/native/fork_checkpoint.d.ts +7 -1
  2. package/dest/native/fork_checkpoint.d.ts.map +1 -1
  3. package/dest/native/fork_checkpoint.js +15 -3
  4. package/dest/native/ipc_world_state_instance.d.ts +50 -0
  5. package/dest/native/ipc_world_state_instance.d.ts.map +1 -0
  6. package/dest/native/ipc_world_state_instance.js +635 -0
  7. package/dest/native/merkle_trees_facade.d.ts +8 -5
  8. package/dest/native/merkle_trees_facade.d.ts.map +1 -1
  9. package/dest/native/merkle_trees_facade.js +32 -12
  10. package/dest/native/message.d.ts +17 -6
  11. package/dest/native/message.d.ts.map +1 -1
  12. package/dest/native/native_world_state.d.ts +31 -5
  13. package/dest/native/native_world_state.d.ts.map +1 -1
  14. package/dest/native/native_world_state.js +83 -27
  15. package/dest/native/native_world_state_instance.d.ts +5 -4
  16. package/dest/native/native_world_state_instance.d.ts.map +1 -1
  17. package/dest/native/native_world_state_instance.js +45 -25
  18. package/dest/native/world_state_ops_queue.js +5 -5
  19. package/dest/synchronizer/config.d.ts +1 -1
  20. package/dest/synchronizer/config.d.ts.map +1 -1
  21. package/dest/synchronizer/config.js +9 -10
  22. package/dest/synchronizer/errors.d.ts +8 -1
  23. package/dest/synchronizer/errors.d.ts.map +1 -1
  24. package/dest/synchronizer/errors.js +8 -1
  25. package/dest/synchronizer/factory.d.ts +5 -5
  26. package/dest/synchronizer/factory.d.ts.map +1 -1
  27. package/dest/synchronizer/factory.js +7 -6
  28. package/dest/synchronizer/index.d.ts +2 -1
  29. package/dest/synchronizer/index.d.ts.map +1 -1
  30. package/dest/synchronizer/index.js +1 -0
  31. package/dest/synchronizer/server_world_state_synchronizer.d.ts +13 -8
  32. package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
  33. package/dest/synchronizer/server_world_state_synchronizer.js +109 -45
  34. package/dest/test/utils.d.ts +1 -1
  35. package/dest/test/utils.d.ts.map +1 -1
  36. package/dest/test/utils.js +6 -1
  37. package/dest/testing.d.ts +4 -3
  38. package/dest/testing.d.ts.map +1 -1
  39. package/dest/testing.js +22 -7
  40. package/dest/world-state-db/merkle_tree_db.d.ts +1 -10
  41. package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
  42. package/package.json +12 -11
  43. package/src/native/fork_checkpoint.ts +19 -3
  44. package/src/native/ipc_world_state_instance.ts +725 -0
  45. package/src/native/merkle_trees_facade.ts +40 -15
  46. package/src/native/message.ts +18 -5
  47. package/src/native/native_world_state.ts +101 -34
  48. package/src/native/native_world_state_instance.ts +55 -28
  49. package/src/native/world_state_ops_queue.ts +5 -5
  50. package/src/synchronizer/config.ts +14 -10
  51. package/src/synchronizer/errors.ts +8 -0
  52. package/src/synchronizer/factory.ts +13 -11
  53. package/src/synchronizer/index.ts +1 -0
  54. package/src/synchronizer/server_world_state_synchronizer.ts +127 -44
  55. package/src/test/utils.ts +10 -1
  56. package/src/testing.ts +19 -10
  57. package/src/world-state-db/merkle_tree_db.ts +0 -10
@@ -1,9 +1,8 @@
1
- import { GENESIS_BLOCK_HEADER_HASH, INITIAL_L2_BLOCK_NUM, INITIAL_L2_CHECKPOINT_NUM } from '@aztec/constants';
2
1
  import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
3
2
  import { createLogger } from '@aztec/foundation/log';
4
3
  import { promiseWithResolvers } from '@aztec/foundation/promise';
5
4
  import { elapsed } from '@aztec/foundation/timer';
6
- import { GENESIS_CHECKPOINT_HEADER_HASH, L2BlockStream } from '@aztec/stdlib/block';
5
+ import { EventDrivenL2BlockStream } from '@aztec/stdlib/block';
7
6
  import { WorldStateRunningState } from '@aztec/stdlib/interfaces/server';
8
7
  import { MerkleTreeId } from '@aztec/stdlib/trees';
9
8
  import { getTelemetryClient } from '@aztec/telemetry-client';
@@ -47,6 +46,39 @@ import { WorldStateSynchronizerError } from './errors.js';
47
46
  getSnapshot(blockNumber) {
48
47
  return this.merkleTreeDb.getSnapshot(blockNumber);
49
48
  }
49
+ async getVerifiedSnapshot(blockNumber, blockHash) {
50
+ const snapshot = this.merkleTreeDb.getSnapshot(blockNumber);
51
+ // Block 0's snapshot is the pre-genesis archive view (size 0), so archive leaf 0 is not visible from it;
52
+ // verify against the initial header hash instead. For later blocks, read archive leaf `blockNumber` from the
53
+ // snapshot's own view so the exact handle we return is validated against the requested fork.
54
+ const actualHash = blockNumber === BlockNumber.ZERO ? (await this.merkleTreeCommitted.getInitialHeader().hash()).toString() : (await snapshot.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber)))?.toString();
55
+ if (actualHash === undefined) {
56
+ // A missing archive leaf means either the block's history has been pruned away (permanent: the block predates
57
+ // the oldest historical block kept by world state) or a reorg flipped the fork between the sync and this read
58
+ // (transient). Only the latter is worth retrying, so it alone surfaces as WorldStateSynchronizerError.
59
+ const { oldestHistoricalBlock } = await this.merkleTreeDb.getStatusSummary();
60
+ if (blockNumber < oldestHistoricalBlock) {
61
+ throw new Error(`Unable to find leaf for block ${blockNumber} in the archive tree: world state history has been pruned to block ${oldestHistoricalBlock}`);
62
+ }
63
+ throw new WorldStateSynchronizerError(`Unable to read block hash at block ${blockNumber} to verify snapshot`, {
64
+ cause: {
65
+ reason: 'block_not_available',
66
+ targetBlockNumber: blockNumber
67
+ }
68
+ });
69
+ }
70
+ if (actualHash !== blockHash.toString()) {
71
+ throw new WorldStateSynchronizerError(`Block hash mismatch at block ${blockNumber} (expected ${blockHash} but got ${actualHash})`, {
72
+ cause: {
73
+ reason: 'block_hash_mismatch',
74
+ targetBlockNumber: blockNumber,
75
+ expectedHash: blockHash.toString(),
76
+ actualHash
77
+ }
78
+ });
79
+ }
80
+ return snapshot;
81
+ }
50
82
  fork(blockNumber, opts) {
51
83
  return this.merkleTreeDb.fork(blockNumber, opts);
52
84
  }
@@ -83,7 +115,7 @@ import { WorldStateSynchronizerError } from './errors.js';
83
115
  }
84
116
  createBlockStream() {
85
117
  const logger = createLogger('world-state:block_stream');
86
- return new L2BlockStream(this.l2BlockSource, this, this, logger, {
118
+ return new EventDrivenL2BlockStream(this.l2BlockSource, this, this, logger, {
87
119
  pollIntervalMS: this.config.worldStateBlockCheckIntervalMS,
88
120
  batchSize: this.config.worldStateBlockRequestBatchSize,
89
121
  ignoreCheckpoints: true
@@ -130,9 +162,9 @@ import { WorldStateSynchronizerError } from './errors.js';
130
162
  /**
131
163
  * Forces an immediate sync.
132
164
  * @param targetBlockNumber - The target block number that we must sync to. Will download unproven blocks if needed to reach it.
133
- * @param skipThrowIfTargetNotReached - Whether to skip throwing if the target block number is not reached.
165
+ * @param blockHash - If provided, verifies the block at targetBlockNumber matches this hash. On mismatch, triggers a resync (reorg detection).
134
166
  * @returns A promise that resolves with the block number the world state was synced to
135
- */ async syncImmediate(targetBlockNumber, skipThrowIfTargetNotReached) {
167
+ */ async syncImmediate(targetBlockNumber, blockHash) {
136
168
  if (this.currentState !== WorldStateRunningState.RUNNING) {
137
169
  throw new Error(`World State is not running. Unable to perform sync.`);
138
170
  }
@@ -142,7 +174,16 @@ import { WorldStateSynchronizerError } from './errors.js';
142
174
  // If we have been given a block number to sync to and we have reached that number then return
143
175
  const currentBlockNumber = await this.getLatestBlockNumber();
144
176
  if (targetBlockNumber !== undefined && targetBlockNumber <= currentBlockNumber) {
145
- return currentBlockNumber;
177
+ if (blockHash === undefined) {
178
+ return currentBlockNumber;
179
+ }
180
+ // If a block hash was provided, verify we're on the expected fork
181
+ const currentHash = await this.getL2BlockHash(targetBlockNumber);
182
+ if (currentHash === blockHash.toString()) {
183
+ return currentBlockNumber;
184
+ }
185
+ // Hash mismatch: a reorg may have occurred, fall through to trigger sync
186
+ this.log.debug(`World state block hash mismatch at ${targetBlockNumber} (expected ${blockHash}, got ${currentHash}). Triggering resync.`);
146
187
  }
147
188
  this.log.debug(`World State at ${currentBlockNumber} told to sync to ${targetBlockNumber ?? 'latest'}`);
148
189
  // If the archiver is behind the target block, force an archiver sync
@@ -157,7 +198,7 @@ import { WorldStateSynchronizerError } from './errors.js';
157
198
  await this.blockStream.sync();
158
199
  // If we have been given a block number to sync to and we have not reached that number then fail
159
200
  const updatedBlockNumber = await this.getLatestBlockNumber();
160
- if (!skipThrowIfTargetNotReached && targetBlockNumber !== undefined && targetBlockNumber > updatedBlockNumber) {
201
+ if (targetBlockNumber !== undefined && targetBlockNumber > updatedBlockNumber) {
161
202
  throw new WorldStateSynchronizerError(`Unable to sync to block number ${targetBlockNumber} (last synced is ${updatedBlockNumber})`, {
162
203
  cause: {
163
204
  reason: 'block_not_available',
@@ -167,6 +208,20 @@ import { WorldStateSynchronizerError } from './errors.js';
167
208
  }
168
209
  });
169
210
  }
211
+ // If a block hash was provided, verify we're on the expected fork after syncing, throw otherwise
212
+ if (blockHash !== undefined && targetBlockNumber !== undefined) {
213
+ const updatedHash = await this.getL2BlockHash(targetBlockNumber);
214
+ if (updatedHash !== blockHash.toString()) {
215
+ throw new WorldStateSynchronizerError(`Block hash mismatch at block ${targetBlockNumber} (expected ${blockHash} but got ${updatedHash})`, {
216
+ cause: {
217
+ reason: 'block_hash_mismatch',
218
+ targetBlockNumber,
219
+ expectedHash: blockHash.toString(),
220
+ actualHash: updatedHash
221
+ }
222
+ });
223
+ }
224
+ }
170
225
  return updatedBlockNumber;
171
226
  }
172
227
  /** Returns the L2 block hash for a given number. Used by the L2BlockStream for detecting reorgs. */ async getL2BlockHash(number) {
@@ -175,7 +230,11 @@ import { WorldStateSynchronizerError } from './errors.js';
175
230
  }
176
231
  return this.merkleTreeCommitted.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(number)).then((leaf)=>leaf?.toString());
177
232
  }
178
- /** Returns the latest L2 block number for each tip of the chain (latest, proven, finalized). */ async getL2Tips() {
233
+ /**
234
+ * Returns the proposed, proven, and finalized block tips of the chain. World state drives its block stream with
235
+ * `ignoreCheckpoints`, so it does not track checkpointed blocks or checkpoints and omits `checkpointed` from the tips
236
+ * it reports.
237
+ */ async getL2Tips() {
179
238
  const status = await this.merkleTreeDb.getStatusSummary();
180
239
  const unfinalizedBlockHashPromise = this.getL2BlockHash(status.unfinalizedBlockNumber);
181
240
  const finalizedBlockHashPromise = this.getL2BlockHash(status.finalizedBlockNumber);
@@ -186,44 +245,21 @@ import { WorldStateSynchronizerError } from './errors.js';
186
245
  finalizedBlockHashPromise,
187
246
  provenBlockHashPromise
188
247
  ]);
189
- const latestBlockId = {
190
- number: status.unfinalizedBlockNumber,
191
- hash: unfinalizedBlockHash
192
- };
193
- // World state doesn't track checkpointed blocks or checkpoints themselves.
194
- // but we use a block stream so we need to provide 'local' L2Tips.
195
- // We configure the block stream to ignore checkpoints and set checkpoint values to genesis here.
196
- const genesisCheckpointHeaderHash = GENESIS_CHECKPOINT_HEADER_HASH.toString();
197
248
  return {
198
- proposed: latestBlockId,
199
- checkpointed: {
200
- block: {
201
- number: INITIAL_L2_BLOCK_NUM,
202
- hash: GENESIS_BLOCK_HEADER_HASH.toString()
203
- },
204
- checkpoint: {
205
- number: INITIAL_L2_CHECKPOINT_NUM,
206
- hash: genesisCheckpointHeaderHash
207
- }
249
+ proposed: {
250
+ number: status.unfinalizedBlockNumber,
251
+ hash: unfinalizedBlockHash
208
252
  },
209
253
  finalized: {
210
254
  block: {
211
255
  number: status.finalizedBlockNumber,
212
- hash: finalizedBlockHash ?? ''
213
- },
214
- checkpoint: {
215
- number: INITIAL_L2_CHECKPOINT_NUM,
216
- hash: genesisCheckpointHeaderHash
256
+ hash: finalizedBlockHash
217
257
  }
218
258
  },
219
259
  proven: {
220
260
  block: {
221
261
  number: provenBlockNumber,
222
- hash: provenBlockHash ?? ''
223
- },
224
- checkpoint: {
225
- number: INITIAL_L2_CHECKPOINT_NUM,
226
- hash: genesisCheckpointHeaderHash
262
+ hash: provenBlockHash
227
263
  }
228
264
  }
229
265
  };
@@ -242,6 +278,16 @@ import { WorldStateSynchronizerError } from './errors.js';
242
278
  case 'chain-finalized':
243
279
  await this.handleChainFinalized(event.block.number);
244
280
  break;
281
+ // World state runs in block mode with ignoreCheckpoints: it tracks tips via blocks-added/pruned/proven/finalized
282
+ // and ignores the thin tip events (it never anchors on them).
283
+ case 'chain-proposed':
284
+ case 'chain-checkpointed':
285
+ break;
286
+ default:
287
+ {
288
+ const _ = event;
289
+ break;
290
+ }
245
291
  }
246
292
  }
247
293
  /**
@@ -296,34 +342,50 @@ import { WorldStateSynchronizerError } from './errors.js';
296
342
  }
297
343
  async handleChainFinalized(blockNumber) {
298
344
  this.log.verbose(`Finalized chain is now at block ${blockNumber}`);
345
+ // If the finalized block number is older than the oldest available block in world state,
346
+ // skip entirely. The finalized block number can jump backwards (e.g. when the finalization
347
+ // heuristic changes) and try to read block data that has already been pruned. When this
348
+ // happens, there is nothing useful to do — the native world state is already finalized
349
+ // past this point and pruning has already happened.
350
+ const currentSummary = await this.merkleTreeDb.getStatusSummary();
351
+ if (blockNumber < currentSummary.oldestHistoricalBlock || blockNumber < 1) {
352
+ this.log.trace(`Finalized block ${blockNumber} is older than the oldest available block ${currentSummary.oldestHistoricalBlock}. Skipping.`);
353
+ return;
354
+ }
299
355
  const summary = await this.merkleTreeDb.setFinalized(blockNumber);
300
356
  if (this.historyToKeep === undefined) {
301
357
  return;
302
358
  }
303
- // Get the checkpointed block for the finalized block number
304
- const finalisedCheckpoint = await this.l2BlockSource.getCheckpointedBlock(summary.finalizedBlockNumber);
305
- if (finalisedCheckpoint === undefined) {
359
+ const finalisedBlockData = await this.l2BlockSource.getBlockData({
360
+ number: summary.finalizedBlockNumber
361
+ });
362
+ if (finalisedBlockData === undefined) {
306
363
  this.log.warn(`Failed to retrieve checkpointed block for finalized block number: ${summary.finalizedBlockNumber}`);
307
364
  return;
308
365
  }
309
366
  // Compute the required historic checkpoint number
310
- const newHistoricCheckpointNumber = finalisedCheckpoint.checkpointNumber - this.historyToKeep + 1;
367
+ const newHistoricCheckpointNumber = finalisedBlockData.checkpointNumber - this.historyToKeep + 1;
311
368
  if (newHistoricCheckpointNumber <= 1) {
312
369
  return;
313
370
  }
314
371
  // Retrieve the historic checkpoint
315
- const historicCheckpoints = await this.l2BlockSource.getCheckpoints(CheckpointNumber(newHistoricCheckpointNumber), 1);
316
- if (historicCheckpoints.length === 0 || historicCheckpoints[0] === undefined) {
372
+ const historicCheckpoint = await this.l2BlockSource.getCheckpoint({
373
+ number: CheckpointNumber(newHistoricCheckpointNumber)
374
+ });
375
+ if (!historicCheckpoint) {
317
376
  this.log.warn(`Failed to retrieve checkpoint number ${newHistoricCheckpointNumber} from Archiver`);
318
377
  return;
319
378
  }
320
- const historicCheckpoint = historicCheckpoints[0];
321
379
  if (historicCheckpoint.checkpoint.blocks.length === 0 || historicCheckpoint.checkpoint.blocks[0] === undefined) {
322
380
  this.log.warn(`Retrieved checkpoint number ${newHistoricCheckpointNumber} has no blocks!`);
323
381
  return;
324
382
  }
325
383
  // Find the block at the start of the checkpoint and remove blocks up to this one
326
384
  const newHistoricBlock = historicCheckpoint.checkpoint.blocks[0];
385
+ if (newHistoricBlock.number <= currentSummary.oldestHistoricalBlock) {
386
+ this.log.debug(`Historic block ${newHistoricBlock.number} is not newer than oldest available ${currentSummary.oldestHistoricalBlock}. Skipping prune.`);
387
+ return;
388
+ }
327
389
  this.log.verbose(`Pruning historic blocks to ${newHistoricBlock.number}`);
328
390
  const status = await this.merkleTreeDb.removeHistoricalBlocks(BlockNumber(newHistoricBlock.number));
329
391
  this.log.debug(`World state summary `, status.summary);
@@ -334,9 +396,11 @@ import { WorldStateSynchronizerError } from './errors.js';
334
396
  return Promise.resolve();
335
397
  }
336
398
  async handleChainPruned(blockNumber) {
337
- this.log.warn(`Chain pruned to block ${blockNumber}`);
399
+ this.log.info(`Chain pruned to block ${blockNumber}`);
338
400
  const status = await this.merkleTreeDb.unwindBlocks(blockNumber);
339
- this.provenBlockNumber = undefined;
401
+ if (this.provenBlockNumber !== undefined && this.provenBlockNumber > blockNumber) {
402
+ this.provenBlockNumber = undefined;
403
+ }
340
404
  this.instrumentation.updateWorldStateMetrics(status);
341
405
  }
342
406
  /**
@@ -23,4 +23,4 @@ export declare function mockCheckpoint(checkpointNumber: CheckpointNumber, fork:
23
23
  }>;
24
24
  export declare function assertSameState(forkA: MerkleTreeReadOperations, forkB: MerkleTreeReadOperations): Promise<void>;
25
25
  export declare function compareChains(left: MerkleTreeReadOperations, right: MerkleTreeReadOperations): Promise<void>;
26
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0L3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQU9BLE9BQU8sRUFBRSxXQUFXLEVBQUUsS0FBSyxnQkFBZ0IsRUFBeUIsTUFBTSxpQ0FBaUMsQ0FBQztBQUU1RyxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDcEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzlDLE9BQU8sS0FBSyxFQUVWLHdCQUF3QixFQUN4Qix5QkFBeUIsRUFDMUIsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQUUseUJBQXlCLEVBQXNCLE1BQU0sdUJBQXVCLENBQUM7QUFJdEYsT0FBTyxLQUFLLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUUvRSx3QkFBc0IsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxjQUFjLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLHlCQUF5QixpQkE4QzNHO0FBRUQsd0JBQXNCLFNBQVMsQ0FDN0IsUUFBUSxFQUFFLFdBQVcsRUFDckIsSUFBSSxFQUFFLE1BQU0sRUFDWixJQUFJLEVBQUUseUJBQXlCLEVBQy9CLFVBQVUsR0FBRSxNQUFNLEdBQUcsU0FBZ0IsRUFDckMsaUJBQWlCLEdBQUUsTUFBNEMsRUFDL0Qsd0JBQXdCLEdBQUUsT0FBYzs7O0dBZXpDO0FBRUQsd0JBQXNCLGNBQWMsQ0FBQyxRQUFRLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSx5QkFBeUI7OztHQVkxRjtBQUVELHdCQUFzQixVQUFVLENBQzlCLElBQUksRUFBRSxXQUFXLEVBQ2pCLEtBQUssRUFBRSxNQUFNLEVBQ2IsTUFBTSxFQUFFLE1BQU0sRUFDZCxVQUFVLEVBQUUsdUJBQXVCOzs7R0FlcEM7QUFFRCx3QkFBc0IsY0FBYyxDQUNsQyxnQkFBZ0IsRUFBRSxnQkFBZ0IsRUFDbEMsSUFBSSxFQUFFLHlCQUF5QixFQUMvQixPQUFPLEdBQUUsT0FBTyxDQUFDLFVBQVUsQ0FBQyxPQUFPLHlCQUF5QixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQU07OztHQU92RTtBQUVELHdCQUFzQixlQUFlLENBQUMsS0FBSyxFQUFFLHdCQUF3QixFQUFFLEtBQUssRUFBRSx3QkFBd0IsaUJBUXJHO0FBRUQsd0JBQXNCLGFBQWEsQ0FBQyxJQUFJLEVBQUUsd0JBQXdCLEVBQUUsS0FBSyxFQUFFLHdCQUF3QixpQkFZbEcifQ==
26
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0L3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQU9BLE9BQU8sRUFBRSxXQUFXLEVBQUUsS0FBSyxnQkFBZ0IsRUFBeUIsTUFBTSxpQ0FBaUMsQ0FBQztBQUU1RyxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDcEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzlDLE9BQU8sS0FBSyxFQUVWLHdCQUF3QixFQUN4Qix5QkFBeUIsRUFDMUIsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQUUseUJBQXlCLEVBQXNCLE1BQU0sdUJBQXVCLENBQUM7QUFJdEYsT0FBTyxLQUFLLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUUvRSx3QkFBc0IsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxjQUFjLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLHlCQUF5QixpQkF1RDNHO0FBRUQsd0JBQXNCLFNBQVMsQ0FDN0IsUUFBUSxFQUFFLFdBQVcsRUFDckIsSUFBSSxFQUFFLE1BQU0sRUFDWixJQUFJLEVBQUUseUJBQXlCLEVBQy9CLFVBQVUsR0FBRSxNQUFNLEdBQUcsU0FBZ0IsRUFDckMsaUJBQWlCLEdBQUUsTUFBNEMsRUFDL0Qsd0JBQXdCLEdBQUUsT0FBYzs7O0dBZXpDO0FBRUQsd0JBQXNCLGNBQWMsQ0FBQyxRQUFRLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSx5QkFBeUI7OztHQVkxRjtBQUVELHdCQUFzQixVQUFVLENBQzlCLElBQUksRUFBRSxXQUFXLEVBQ2pCLEtBQUssRUFBRSxNQUFNLEVBQ2IsTUFBTSxFQUFFLE1BQU0sRUFDZCxVQUFVLEVBQUUsdUJBQXVCOzs7R0FlcEM7QUFFRCx3QkFBc0IsY0FBYyxDQUNsQyxnQkFBZ0IsRUFBRSxnQkFBZ0IsRUFDbEMsSUFBSSxFQUFFLHlCQUF5QixFQUMvQixPQUFPLEdBQUUsT0FBTyxDQUFDLFVBQVUsQ0FBQyxPQUFPLHlCQUF5QixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQU07OztHQU92RTtBQUVELHdCQUFzQixlQUFlLENBQUMsS0FBSyxFQUFFLHdCQUF3QixFQUFFLEtBQUssRUFBRSx3QkFBd0IsaUJBUXJHO0FBRUQsd0JBQXNCLGFBQWEsQ0FBQyxJQUFJLEVBQUUsd0JBQXdCLEVBQUUsS0FBSyxFQUFFLHdCQUF3QixpQkFZbEcifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/test/utils.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAyB,MAAM,iCAAiC,CAAC;AAE5G,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,KAAK,EAEV,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAsB,MAAM,uBAAuB,CAAC;AAItF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE/E,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,yBAAyB,iBA8C3G;AAED,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,yBAAyB,EAC/B,UAAU,GAAE,MAAM,GAAG,SAAgB,EACrC,iBAAiB,GAAE,MAA4C,EAC/D,wBAAwB,GAAE,OAAc;;;GAezC;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,yBAAyB;;;GAY1F;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,uBAAuB;;;GAepC;AAED,wBAAsB,cAAc,CAClC,gBAAgB,EAAE,gBAAgB,EAClC,IAAI,EAAE,yBAAyB,EAC/B,OAAO,GAAE,OAAO,CAAC,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAAM;;;GAOvE;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,wBAAwB,EAAE,KAAK,EAAE,wBAAwB,iBAQrG;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,wBAAwB,iBAYlG"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/test/utils.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAyB,MAAM,iCAAiC,CAAC;AAE5G,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,KAAK,EAEV,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAsB,MAAM,uBAAuB,CAAC;AAItF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE/E,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,yBAAyB,iBAuD3G;AAED,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,yBAAyB,EAC/B,UAAU,GAAE,MAAM,GAAG,SAAgB,EACrC,iBAAiB,GAAE,MAA4C,EAC/D,wBAAwB,GAAE,OAAc;;;GAezC;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,yBAAyB;;;GAY1F;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,uBAAuB;;;GAepC;AAED,wBAAsB,cAAc,CAClC,gBAAgB,EAAE,gBAAgB,EAClC,IAAI,EAAE,yBAAyB,EAC/B,OAAO,GAAE,OAAO,CAAC,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAAM;;;GAOvE;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,wBAAwB,EAAE,KAAK,EAAE,wBAAwB,iBAQrG;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,wBAAwB,iBAYlG"}
@@ -26,9 +26,14 @@ export async function updateBlockState(block, l1ToL2Messages, fork) {
26
26
  messageInsert
27
27
  ]);
28
28
  const state = await fork.getStateReference();
29
+ // Capture the archive root *before* appending this block so the header's lastArchive chains off the previous block.
30
+ // sync_block now verifies lastArchive against the committed archive root, so a block carrying an unchained value
31
+ // (e.g. the random lastArchive from L2Block.random) would be rejected as a divergence from the canonical chain.
32
+ const previousArchive = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
29
33
  block.header = BlockHeader.from({
30
34
  ...block.header,
31
- state
35
+ state,
36
+ lastArchive: new AppendOnlyTreeSnapshot(Fr.fromBuffer(previousArchive.root), Number(previousArchive.size))
32
37
  });
33
38
  await fork.updateArchive(block.header);
34
39
  const archiveState = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
package/dest/testing.d.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { Fr } from '@aztec/foundation/curves/bn254';
2
2
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
3
3
  import { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
4
+ import type { GenesisData } from '@aztec/stdlib/world-state';
4
5
  export declare const defaultInitialAccountFeeJuice: Fr;
5
- export declare function getGenesisValues(initialAccounts: AztecAddress[], initialAccountFeeJuice?: Fr, genesisPublicData?: PublicDataTreeLeaf[]): Promise<{
6
+ export declare function getGenesisValues(initialAccounts: AztecAddress[], initialAccountFeeJuice?: Fr, genesisPublicData?: PublicDataTreeLeaf[], genesisTimestamp?: bigint, prefilledNullifiers?: Fr[]): Promise<{
6
7
  genesisArchiveRoot: Fr;
7
- prefilledPublicData: PublicDataTreeLeaf[];
8
+ genesis: GenesisData;
8
9
  fundingNeeded: bigint;
9
10
  }>;
10
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdGluZy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Rlc3RpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRXBELE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2hFLE9BQU8sRUFBZ0Isa0JBQWtCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQXlCdkUsZUFBTyxNQUFNLDZCQUE2QixJQUFxQixDQUFDO0FBRWhFLHdCQUFzQixnQkFBZ0IsQ0FDcEMsZUFBZSxFQUFFLFlBQVksRUFBRSxFQUMvQixzQkFBc0IsS0FBZ0MsRUFDdEQsaUJBQWlCLEdBQUUsa0JBQWtCLEVBQU87Ozs7R0FxQjdDIn0=
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdGluZy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Rlc3RpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRXBELE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2hFLE9BQU8sRUFBZ0Isa0JBQWtCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RSxPQUFPLEtBQUssRUFBRSxXQUFXLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQTBCN0QsZUFBTyxNQUFNLDZCQUE2QixJQUFxQixDQUFDO0FBRWhFLHdCQUFzQixnQkFBZ0IsQ0FDcEMsZUFBZSxFQUFFLFlBQVksRUFBRSxFQUMvQixzQkFBc0IsS0FBZ0MsRUFDdEQsaUJBQWlCLEdBQUUsa0JBQWtCLEVBQU8sRUFDNUMsZ0JBQWdCLEdBQUUsTUFBVyxFQUM3QixtQkFBbUIsR0FBRSxFQUFFLEVBQU87Ozs7R0EwQi9CIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAgB,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAyBvE,eAAO,MAAM,6BAA6B,IAAqB,CAAC;AAEhE,wBAAsB,gBAAgB,CACpC,eAAe,EAAE,YAAY,EAAE,EAC/B,sBAAsB,KAAgC,EACtD,iBAAiB,GAAE,kBAAkB,EAAO;;;;GAqB7C"}
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAgB,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AA0B7D,eAAO,MAAM,6BAA6B,IAAqB,CAAC;AAEhE,wBAAsB,gBAAgB,CACpC,eAAe,EAAE,YAAY,EAAE,EAC/B,sBAAsB,KAAgC,EACtD,iBAAiB,GAAE,kBAAkB,EAAO,EAC5C,gBAAgB,GAAE,MAAW,EAC7B,mBAAmB,GAAE,EAAE,EAAO;;;;GA0B/B"}
package/dest/testing.js CHANGED
@@ -3,14 +3,19 @@ import { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import { computeFeePayerBalanceLeafSlot } from '@aztec/protocol-contracts/fee-juice';
4
4
  import { MerkleTreeId, PublicDataTreeLeaf } from '@aztec/stdlib/trees';
5
5
  import { NativeWorldStateService } from './native/index.js';
6
- async function generateGenesisValues(prefilledPublicData) {
7
- if (!prefilledPublicData.length) {
6
+ async function generateGenesisValues(genesis) {
7
+ // The GENESIS_ARCHIVE_ROOT constant reflects the canonical empty genesis (no public data, no prefilled nullifiers,
8
+ // timestamp 0), so we can only short-circuit when this genesis adds none of those on top.
9
+ if (!genesis.prefilledPublicData.length && genesis.genesisTimestamp === 0n && !genesis.prefilledNullifiers?.length) {
8
10
  return {
9
11
  genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT)
10
12
  };
11
13
  }
12
- // Create a temporary world state to compute the genesis values.
13
- const ws = await NativeWorldStateService.tmp(undefined /* rollupAddress */ , true, prefilledPublicData);
14
+ // Compute the genesis values on a throwaway world state. The archive root derives deterministically from the
15
+ // prefilled public data, the prefilled nullifiers, and the genesis timestamp, so the fsync-off ephemeral store (no
16
+ // version manager, no crash-recoverability) produces an identical root while skipping the fsync overhead that `tmp`
17
+ // pays. close() removes the tmpdir.
18
+ const ws = await NativeWorldStateService.ephemeral(genesis);
14
19
  const genesisArchiveRoot = new Fr((await ws.getCommitted().getTreeInfo(MerkleTreeId.ARCHIVE)).root);
15
20
  await ws.close();
16
21
  return {
@@ -18,16 +23,26 @@ async function generateGenesisValues(prefilledPublicData) {
18
23
  };
19
24
  }
20
25
  export const defaultInitialAccountFeeJuice = new Fr(10n ** 22n);
21
- export async function getGenesisValues(initialAccounts, initialAccountFeeJuice = defaultInitialAccountFeeJuice, genesisPublicData = []) {
26
+ export async function getGenesisValues(initialAccounts, initialAccountFeeJuice = defaultInitialAccountFeeJuice, genesisPublicData = [], genesisTimestamp = 0n, prefilledNullifiers = []) {
22
27
  // Top up the accounts with fee juice.
23
28
  let prefilledPublicData = await Promise.all(initialAccounts.map(async (address)=>new PublicDataTreeLeaf(await computeFeePayerBalanceLeafSlot(address), initialAccountFeeJuice)));
24
29
  // Add user-defined public data
25
30
  prefilledPublicData = prefilledPublicData.concat(genesisPublicData);
26
31
  prefilledPublicData.sort((a, b)=>b.slot.lt(a.slot) ? 1 : -1);
27
- const { genesisArchiveRoot } = await generateGenesisValues(prefilledPublicData);
32
+ // The indexed nullifier tree requires its prefilled leaves to be unique and strictly increasing, so sort ascending
33
+ // here (a copy, to avoid mutating the caller's array) rather than relying on the caller's ordering.
34
+ const sortedNullifiers = [
35
+ ...prefilledNullifiers
36
+ ].sort((a, b)=>a.toBigInt() < b.toBigInt() ? -1 : 1);
37
+ const genesis = {
38
+ prefilledPublicData,
39
+ prefilledNullifiers: sortedNullifiers,
40
+ genesisTimestamp
41
+ };
42
+ const { genesisArchiveRoot } = await generateGenesisValues(genesis);
28
43
  return {
29
44
  genesisArchiveRoot,
30
- prefilledPublicData,
45
+ genesis,
31
46
  fundingNeeded: BigInt(initialAccounts.length) * initialAccountFeeJuice.toBigInt()
32
47
  };
33
48
  }
@@ -1,9 +1,7 @@
1
1
  import type { BlockNumber } from '@aztec/foundation/branded-types';
2
2
  import type { Fr } from '@aztec/foundation/curves/bn254';
3
- import type { IndexedTreeSnapshot, TreeSnapshot } from '@aztec/merkle-tree';
4
3
  import type { L2Block } from '@aztec/stdlib/block';
5
4
  import type { ForkMerkleTreeOperations, MerkleTreeReadOperations, ReadonlyWorldStateAccess } from '@aztec/stdlib/interfaces/server';
6
- import type { MerkleTreeId } from '@aztec/stdlib/trees';
7
5
  import type { WorldStateStatusFull, WorldStateStatusSummary } from '../native/message.js';
8
6
  /**
9
7
  *
@@ -22,13 +20,6 @@ import type { WorldStateStatusFull, WorldStateStatusSummary } from '../native/me
22
20
  */
23
21
  export declare const INITIAL_NULLIFIER_TREE_SIZE: number;
24
22
  export declare const INITIAL_PUBLIC_DATA_TREE_SIZE: number;
25
- export type TreeSnapshots = {
26
- [MerkleTreeId.NULLIFIER_TREE]: IndexedTreeSnapshot;
27
- [MerkleTreeId.NOTE_HASH_TREE]: TreeSnapshot<Fr>;
28
- [MerkleTreeId.PUBLIC_DATA_TREE]: IndexedTreeSnapshot;
29
- [MerkleTreeId.L1_TO_L2_MESSAGE_TREE]: TreeSnapshot<Fr>;
30
- [MerkleTreeId.ARCHIVE]: TreeSnapshot<Fr>;
31
- };
32
23
  export interface MerkleTreeAdminDatabase extends ForkMerkleTreeOperations, ReadonlyWorldStateAccess {
33
24
  /**
34
25
  * Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree).
@@ -68,4 +59,4 @@ export interface MerkleTreeAdminDatabase extends ForkMerkleTreeOperations, Reado
68
59
  /** Deletes the db. */
69
60
  clear(): Promise<void>;
70
61
  }
71
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVya2xlX3RyZWVfZGIuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93b3JsZC1zdGF0ZS1kYi9tZXJrbGVfdHJlZV9kYi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEtBQUssRUFBRSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNuRSxPQUFPLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN6RCxPQUFPLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxZQUFZLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM1RSxPQUFPLEtBQUssRUFBRSxPQUFPLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNuRCxPQUFPLEtBQUssRUFDVix3QkFBd0IsRUFDeEIsd0JBQXdCLEVBQ3hCLHdCQUF3QixFQUN6QixNQUFNLGlDQUFpQyxDQUFDO0FBQ3pDLE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRXhELE9BQU8sS0FBSyxFQUFFLG9CQUFvQixFQUFFLHVCQUF1QixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFMUY7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxlQUFPLE1BQU0sMkJBQTJCLFFBQTRCLENBQUM7QUFFckUsZUFBTyxNQUFNLDZCQUE2QixRQUFtRCxDQUFDO0FBRTlGLE1BQU0sTUFBTSxhQUFhLEdBQUc7SUFDMUIsQ0FBQyxZQUFZLENBQUMsY0FBYyxDQUFDLEVBQUUsbUJBQW1CLENBQUM7SUFDbkQsQ0FBQyxZQUFZLENBQUMsY0FBYyxDQUFDLEVBQUUsWUFBWSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2hELENBQUMsWUFBWSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsbUJBQW1CLENBQUM7SUFDckQsQ0FBQyxZQUFZLENBQUMscUJBQXFCLENBQUMsRUFBRSxZQUFZLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdkQsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLEVBQUUsWUFBWSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0NBQzFDLENBQUM7QUFFRixNQUFNLFdBQVcsdUJBQXdCLFNBQVEsd0JBQXdCLEVBQUUsd0JBQXdCO0lBQ2pHOzs7O09BSUc7SUFDSCx3QkFBd0IsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxFQUFFLEVBQUUsR0FBRyxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUU5Rjs7T0FFRztJQUNILFlBQVksSUFBSSx3QkFBd0IsQ0FBQztJQUV6Qzs7OztPQUlHO0lBQ0gsc0JBQXNCLENBQUMsYUFBYSxFQUFFLFdBQVcsR0FBRyxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUVsRjs7OztPQUlHO0lBQ0gsWUFBWSxDQUFDLGFBQWEsRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQUM7SUFFeEU7Ozs7T0FJRztJQUNILFlBQVksQ0FBQyxhQUFhLEVBQUUsV0FBVyxHQUFHLE9BQU8sQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0lBRTNFOzs7T0FHRztJQUNILGdCQUFnQixJQUFJLE9BQU8sQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0lBRXJELHlCQUF5QjtJQUN6QixLQUFLLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRXZCLHNCQUFzQjtJQUN0QixLQUFLLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0NBQ3hCIn0=
62
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVya2xlX3RyZWVfZGIuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93b3JsZC1zdGF0ZS1kYi9tZXJrbGVfdHJlZV9kYi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEtBQUssRUFBRSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNuRSxPQUFPLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN6RCxPQUFPLEtBQUssRUFBRSxPQUFPLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNuRCxPQUFPLEtBQUssRUFDVix3QkFBd0IsRUFDeEIsd0JBQXdCLEVBQ3hCLHdCQUF3QixFQUN6QixNQUFNLGlDQUFpQyxDQUFDO0FBRXpDLE9BQU8sS0FBSyxFQUFFLG9CQUFvQixFQUFFLHVCQUF1QixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFMUY7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxlQUFPLE1BQU0sMkJBQTJCLFFBQTRCLENBQUM7QUFFckUsZUFBTyxNQUFNLDZCQUE2QixRQUFtRCxDQUFDO0FBRTlGLE1BQU0sV0FBVyx1QkFBd0IsU0FBUSx3QkFBd0IsRUFBRSx3QkFBd0I7SUFDakc7Ozs7T0FJRztJQUNILHdCQUF3QixDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsY0FBYyxFQUFFLEVBQUUsRUFBRSxHQUFHLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO0lBRTlGOztPQUVHO0lBQ0gsWUFBWSxJQUFJLHdCQUF3QixDQUFDO0lBRXpDOzs7O09BSUc7SUFDSCxzQkFBc0IsQ0FBQyxhQUFhLEVBQUUsV0FBVyxHQUFHLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO0lBRWxGOzs7O09BSUc7SUFDSCxZQUFZLENBQUMsYUFBYSxFQUFFLFdBQVcsR0FBRyxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUV4RTs7OztPQUlHO0lBQ0gsWUFBWSxDQUFDLGFBQWEsRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLHVCQUF1QixDQUFDLENBQUM7SUFFM0U7OztPQUdHO0lBQ0gsZ0JBQWdCLElBQUksT0FBTyxDQUFDLHVCQUF1QixDQUFDLENBQUM7SUFFckQseUJBQXlCO0lBQ3pCLEtBQUssSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFdkIsc0JBQXNCO0lBQ3RCLEtBQUssSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7Q0FDeEIifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"merkle_tree_db.d.ts","sourceRoot":"","sources":["../../src/world-state-db/merkle_tree_db.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EACV,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAE1F;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,2BAA2B,QAA4B,CAAC;AAErE,eAAO,MAAM,6BAA6B,QAAmD,CAAC;AAE9F,MAAM,MAAM,aAAa,GAAG;IAC1B,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACnD,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC;IAChD,CAAC,YAAY,CAAC,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;IACrD,CAAC,YAAY,CAAC,qBAAqB,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC;CAC1C,CAAC;AAEF,MAAM,WAAW,uBAAwB,SAAQ,wBAAwB,EAAE,wBAAwB;IACjG;;;;OAIG;IACH,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAE9F;;OAEG;IACH,YAAY,IAAI,wBAAwB,CAAC;IAEzC;;;;OAIG;IACH,sBAAsB,CAAC,aAAa,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAElF;;;;OAIG;IACH,YAAY,CAAC,aAAa,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAExE;;;;OAIG;IACH,YAAY,CAAC,aAAa,EAAE,WAAW,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAE3E;;;OAGG;IACH,gBAAgB,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAErD,yBAAyB;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB,sBAAsB;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
1
+ {"version":3,"file":"merkle_tree_db.d.ts","sourceRoot":"","sources":["../../src/world-state-db/merkle_tree_db.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EACV,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAE1F;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,2BAA2B,QAA4B,CAAC;AAErE,eAAO,MAAM,6BAA6B,QAAmD,CAAC;AAE9F,MAAM,WAAW,uBAAwB,SAAQ,wBAAwB,EAAE,wBAAwB;IACjG;;;;OAIG;IACH,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAE9F;;OAEG;IACH,YAAY,IAAI,wBAAwB,CAAC;IAEzC;;;;OAIG;IACH,sBAAsB,CAAC,aAAa,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAElF;;;;OAIG;IACH,YAAY,CAAC,aAAa,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAExE;;;;OAIG;IACH,YAAY,CAAC,aAAa,EAAE,WAAW,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAE3E;;;OAGG;IACH,gBAAgB,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAErD,yBAAyB;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB,sBAAsB;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/world-state",
3
- "version": "0.0.1-commit.f504929",
3
+ "version": "0.0.1-commit.f5a9928",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -64,19 +64,20 @@
64
64
  ]
65
65
  },
66
66
  "dependencies": {
67
- "@aztec/constants": "0.0.1-commit.f504929",
68
- "@aztec/foundation": "0.0.1-commit.f504929",
69
- "@aztec/kv-store": "0.0.1-commit.f504929",
70
- "@aztec/merkle-tree": "0.0.1-commit.f504929",
71
- "@aztec/native": "0.0.1-commit.f504929",
72
- "@aztec/protocol-contracts": "0.0.1-commit.f504929",
73
- "@aztec/stdlib": "0.0.1-commit.f504929",
74
- "@aztec/telemetry-client": "0.0.1-commit.f504929",
67
+ "@aztec/bb.js": "0.0.1-commit.f5a9928",
68
+ "@aztec/constants": "0.0.1-commit.f5a9928",
69
+ "@aztec/foundation": "0.0.1-commit.f5a9928",
70
+ "@aztec/kv-store": "0.0.1-commit.f5a9928",
71
+ "@aztec/native": "0.0.1-commit.f5a9928",
72
+ "@aztec/protocol-contracts": "0.0.1-commit.f5a9928",
73
+ "@aztec/stdlib": "0.0.1-commit.f5a9928",
74
+ "@aztec/telemetry-client": "0.0.1-commit.f5a9928",
75
+ "msgpackr": "^1.11.2",
75
76
  "tslib": "^2.4.0",
76
- "zod": "^3.23.8"
77
+ "zod": "^4"
77
78
  },
78
79
  "devDependencies": {
79
- "@aztec/archiver": "0.0.1-commit.f504929",
80
+ "@aztec/archiver": "0.0.1-commit.f5a9928",
80
81
  "@jest/globals": "^30.0.0",
81
82
  "@types/jest": "^30.0.0",
82
83
  "@types/node": "^22.15.17",
@@ -3,11 +3,14 @@ import type { MerkleTreeCheckpointOperations } from '@aztec/stdlib/interfaces/se
3
3
  export class ForkCheckpoint {
4
4
  private completed = false;
5
5
 
6
- private constructor(private readonly fork: MerkleTreeCheckpointOperations) {}
6
+ private constructor(
7
+ private readonly fork: MerkleTreeCheckpointOperations,
8
+ public readonly depth: number,
9
+ ) {}
7
10
 
8
11
  static async new(fork: MerkleTreeCheckpointOperations): Promise<ForkCheckpoint> {
9
- await fork.createCheckpoint();
10
- return new ForkCheckpoint(fork);
12
+ const depth = await fork.createCheckpoint();
13
+ return new ForkCheckpoint(fork, depth);
11
14
  }
12
15
 
13
16
  async commit(): Promise<void> {
@@ -27,4 +30,17 @@ export class ForkCheckpoint {
27
30
  await this.fork.revertCheckpoint();
28
31
  this.completed = true;
29
32
  }
33
+
34
+ /**
35
+ * Reverts this checkpoint and any nested checkpoints created on top of it,
36
+ * leaving the checkpoint depth at the level it was before this checkpoint was created.
37
+ */
38
+ async revertToCheckpoint(): Promise<void> {
39
+ if (this.completed) {
40
+ return;
41
+ }
42
+
43
+ await this.fork.revertAllCheckpointsTo(this.depth - 1);
44
+ this.completed = true;
45
+ }
30
46
  }