@aztec/world-state 0.0.1-commit.c2eed6949 → 0.0.1-commit.c52d6e7

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 (69) hide show
  1. package/dest/index.d.ts +2 -1
  2. package/dest/index.d.ts.map +1 -1
  3. package/dest/index.js +1 -0
  4. package/dest/instrumentation/instrumentation.d.ts +4 -3
  5. package/dest/instrumentation/instrumentation.d.ts.map +1 -1
  6. package/dest/instrumentation/instrumentation.js +4 -9
  7. package/dest/native/index.d.ts +2 -1
  8. package/dest/native/index.d.ts.map +1 -1
  9. package/dest/native/index.js +1 -0
  10. package/dest/native/ipc_world_state_instance.d.ts +89 -0
  11. package/dest/native/ipc_world_state_instance.d.ts.map +1 -0
  12. package/dest/native/ipc_world_state_instance.js +670 -0
  13. package/dest/native/merkle_trees_facade.d.ts +8 -4
  14. package/dest/native/merkle_trees_facade.d.ts.map +1 -1
  15. package/dest/native/merkle_trees_facade.js +60 -115
  16. package/dest/native/message.d.ts +14 -230
  17. package/dest/native/message.d.ts.map +1 -1
  18. package/dest/native/message.js +0 -42
  19. package/dest/native/native_world_state.d.ts +19 -7
  20. package/dest/native/native_world_state.d.ts.map +1 -1
  21. package/dest/native/native_world_state.js +120 -58
  22. package/dest/native/native_world_state_instance.d.ts +56 -42
  23. package/dest/native/native_world_state_instance.d.ts.map +1 -1
  24. package/dest/native/native_world_state_instance.js +1 -203
  25. package/dest/native/world_state_operation.d.ts +7 -0
  26. package/dest/native/world_state_operation.d.ts.map +1 -0
  27. package/dest/native/world_state_operation.js +5 -0
  28. package/dest/synchronizer/config.d.ts +1 -1
  29. package/dest/synchronizer/config.d.ts.map +1 -1
  30. package/dest/synchronizer/config.js +9 -10
  31. package/dest/synchronizer/errors.d.ts +8 -1
  32. package/dest/synchronizer/errors.d.ts.map +1 -1
  33. package/dest/synchronizer/errors.js +8 -1
  34. package/dest/synchronizer/factory.d.ts +4 -4
  35. package/dest/synchronizer/factory.d.ts.map +1 -1
  36. package/dest/synchronizer/factory.js +7 -6
  37. package/dest/synchronizer/index.d.ts +2 -1
  38. package/dest/synchronizer/index.d.ts.map +1 -1
  39. package/dest/synchronizer/index.js +1 -0
  40. package/dest/synchronizer/server_world_state_synchronizer.d.ts +11 -6
  41. package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
  42. package/dest/synchronizer/server_world_state_synchronizer.js +67 -40
  43. package/dest/test/utils.d.ts +1 -1
  44. package/dest/test/utils.d.ts.map +1 -1
  45. package/dest/test/utils.js +6 -1
  46. package/dest/testing.d.ts +4 -3
  47. package/dest/testing.d.ts.map +1 -1
  48. package/dest/testing.js +22 -7
  49. package/package.json +13 -10
  50. package/src/index.ts +1 -0
  51. package/src/instrumentation/instrumentation.ts +6 -18
  52. package/src/native/index.ts +1 -0
  53. package/src/native/ipc_world_state_instance.ts +847 -0
  54. package/src/native/merkle_trees_facade.ts +85 -112
  55. package/src/native/message.ts +13 -297
  56. package/src/native/native_world_state.ts +144 -97
  57. package/src/native/native_world_state_instance.ts +94 -281
  58. package/src/native/world_state_operation.ts +33 -0
  59. package/src/synchronizer/config.ts +14 -10
  60. package/src/synchronizer/errors.ts +8 -0
  61. package/src/synchronizer/factory.ts +11 -10
  62. package/src/synchronizer/index.ts +1 -0
  63. package/src/synchronizer/server_world_state_synchronizer.ts +73 -36
  64. package/src/test/utils.ts +10 -1
  65. package/src/testing.ts +19 -10
  66. package/dest/native/world_state_ops_queue.d.ts +0 -19
  67. package/dest/native/world_state_ops_queue.d.ts.map +0 -1
  68. package/dest/native/world_state_ops_queue.js +0 -146
  69. package/src/native/world_state_ops_queue.ts +0 -190
@@ -1,9 +1,8 @@
1
- import { GENESIS_BLOCK_HEADER_HASH, INITIAL_CHECKPOINT_NUMBER, INITIAL_L2_BLOCK_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
@@ -198,7 +230,11 @@ import { WorldStateSynchronizerError } from './errors.js';
198
230
  }
199
231
  return this.merkleTreeCommitted.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(number)).then((leaf)=>leaf?.toString());
200
232
  }
201
- /** 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() {
202
238
  const status = await this.merkleTreeDb.getStatusSummary();
203
239
  const unfinalizedBlockHashPromise = this.getL2BlockHash(status.unfinalizedBlockNumber);
204
240
  const finalizedBlockHashPromise = this.getL2BlockHash(status.finalizedBlockNumber);
@@ -209,44 +245,21 @@ import { WorldStateSynchronizerError } from './errors.js';
209
245
  finalizedBlockHashPromise,
210
246
  provenBlockHashPromise
211
247
  ]);
212
- const latestBlockId = {
213
- number: status.unfinalizedBlockNumber,
214
- hash: unfinalizedBlockHash
215
- };
216
- // World state doesn't track checkpointed blocks or checkpoints themselves.
217
- // but we use a block stream so we need to provide 'local' L2Tips.
218
- // We configure the block stream to ignore checkpoints and set checkpoint values to genesis here.
219
- const genesisCheckpointHeaderHash = GENESIS_CHECKPOINT_HEADER_HASH.toString();
220
248
  return {
221
- proposed: latestBlockId,
222
- checkpointed: {
223
- block: {
224
- number: INITIAL_L2_BLOCK_NUM,
225
- hash: GENESIS_BLOCK_HEADER_HASH.toString()
226
- },
227
- checkpoint: {
228
- number: INITIAL_CHECKPOINT_NUMBER,
229
- hash: genesisCheckpointHeaderHash
230
- }
249
+ proposed: {
250
+ number: status.unfinalizedBlockNumber,
251
+ hash: unfinalizedBlockHash
231
252
  },
232
253
  finalized: {
233
254
  block: {
234
255
  number: status.finalizedBlockNumber,
235
- hash: finalizedBlockHash ?? ''
236
- },
237
- checkpoint: {
238
- number: INITIAL_CHECKPOINT_NUMBER,
239
- hash: genesisCheckpointHeaderHash
256
+ hash: finalizedBlockHash
240
257
  }
241
258
  },
242
259
  proven: {
243
260
  block: {
244
261
  number: provenBlockNumber,
245
- hash: provenBlockHash ?? ''
246
- },
247
- checkpoint: {
248
- number: INITIAL_CHECKPOINT_NUMBER,
249
- hash: genesisCheckpointHeaderHash
262
+ hash: provenBlockHash
250
263
  }
251
264
  }
252
265
  };
@@ -265,6 +278,16 @@ import { WorldStateSynchronizerError } from './errors.js';
265
278
  case 'chain-finalized':
266
279
  await this.handleChainFinalized(event.block.number);
267
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
+ }
268
291
  }
269
292
  }
270
293
  /**
@@ -333,24 +356,26 @@ import { WorldStateSynchronizerError } from './errors.js';
333
356
  if (this.historyToKeep === undefined) {
334
357
  return;
335
358
  }
336
- // Get the checkpointed block for the finalized block number
337
- const finalisedCheckpoint = await this.l2BlockSource.getCheckpointedBlock(summary.finalizedBlockNumber);
338
- if (finalisedCheckpoint === undefined) {
359
+ const finalisedBlockData = await this.l2BlockSource.getBlockData({
360
+ number: summary.finalizedBlockNumber
361
+ });
362
+ if (finalisedBlockData === undefined) {
339
363
  this.log.warn(`Failed to retrieve checkpointed block for finalized block number: ${summary.finalizedBlockNumber}`);
340
364
  return;
341
365
  }
342
366
  // Compute the required historic checkpoint number
343
- const newHistoricCheckpointNumber = finalisedCheckpoint.checkpointNumber - this.historyToKeep + 1;
367
+ const newHistoricCheckpointNumber = finalisedBlockData.checkpointNumber - this.historyToKeep + 1;
344
368
  if (newHistoricCheckpointNumber <= 1) {
345
369
  return;
346
370
  }
347
371
  // Retrieve the historic checkpoint
348
- const historicCheckpoints = await this.l2BlockSource.getCheckpoints(CheckpointNumber(newHistoricCheckpointNumber), 1);
349
- if (historicCheckpoints.length === 0 || historicCheckpoints[0] === undefined) {
372
+ const historicCheckpoint = await this.l2BlockSource.getCheckpoint({
373
+ number: CheckpointNumber(newHistoricCheckpointNumber)
374
+ });
375
+ if (!historicCheckpoint) {
350
376
  this.log.warn(`Failed to retrieve checkpoint number ${newHistoricCheckpointNumber} from Archiver`);
351
377
  return;
352
378
  }
353
- const historicCheckpoint = historicCheckpoints[0];
354
379
  if (historicCheckpoint.checkpoint.blocks.length === 0 || historicCheckpoint.checkpoint.blocks[0] === undefined) {
355
380
  this.log.warn(`Retrieved checkpoint number ${newHistoricCheckpointNumber} has no blocks!`);
356
381
  return;
@@ -373,7 +398,9 @@ import { WorldStateSynchronizerError } from './errors.js';
373
398
  async handleChainPruned(blockNumber) {
374
399
  this.log.info(`Chain pruned to block ${blockNumber}`);
375
400
  const status = await this.merkleTreeDb.unwindBlocks(blockNumber);
376
- this.provenBlockNumber = undefined;
401
+ if (this.provenBlockNumber !== undefined && this.provenBlockNumber > blockNumber) {
402
+ this.provenBlockNumber = undefined;
403
+ }
377
404
  this.instrumentation.updateWorldStateMetrics(status);
378
405
  }
379
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/world-state",
3
- "version": "0.0.1-commit.c2eed6949",
3
+ "version": "0.0.1-commit.c52d6e7",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -64,18 +64,21 @@
64
64
  ]
65
65
  },
66
66
  "dependencies": {
67
- "@aztec/constants": "0.0.1-commit.c2eed6949",
68
- "@aztec/foundation": "0.0.1-commit.c2eed6949",
69
- "@aztec/kv-store": "0.0.1-commit.c2eed6949",
70
- "@aztec/native": "0.0.1-commit.c2eed6949",
71
- "@aztec/protocol-contracts": "0.0.1-commit.c2eed6949",
72
- "@aztec/stdlib": "0.0.1-commit.c2eed6949",
73
- "@aztec/telemetry-client": "0.0.1-commit.c2eed6949",
67
+ "@aztec/bb.js": "6.0.0-nightly.20260807",
68
+ "@aztec/constants": "0.0.1-commit.c52d6e7",
69
+ "@aztec/foundation": "0.0.1-commit.c52d6e7",
70
+ "@aztec/kv-store": "0.0.1-commit.c52d6e7",
71
+ "@aztec/protocol-contracts": "0.0.1-commit.c52d6e7",
72
+ "@aztec/stdlib": "0.0.1-commit.c52d6e7",
73
+ "@aztec/telemetry-client": "0.0.1-commit.c52d6e7",
74
+ "@aztec/wsdb": "6.0.0-nightly.20260807",
75
+ "msgpackr": "^1.11.2",
74
76
  "tslib": "^2.4.0",
75
- "zod": "^3.23.8"
77
+ "zod": "^4"
76
78
  },
77
79
  "devDependencies": {
78
- "@aztec/archiver": "0.0.1-commit.c2eed6949",
80
+ "@aztec/archiver": "0.0.1-commit.c52d6e7",
81
+ "@aztec/ipc-runtime": "6.0.0-nightly.20260807",
79
82
  "@jest/globals": "^30.0.0",
80
83
  "@types/jest": "^30.0.0",
81
84
  "@types/node": "^22.15.17",
package/src/index.ts CHANGED
@@ -2,3 +2,4 @@ export * from './synchronizer/index.js';
2
2
  export * from './world-state-db/index.js';
3
3
  export * from './synchronizer/config.js';
4
4
  export * from './native/index.js';
5
+ export { WorldStateInstrumentation } from './instrumentation/instrumentation.js';
@@ -10,24 +10,12 @@ import {
10
10
  createUpDownCounterWithDefault,
11
11
  } from '@aztec/telemetry-client';
12
12
 
13
- import {
14
- type DBStats,
15
- type TreeDBStats,
16
- type TreeMeta,
17
- WorldStateMessageType,
18
- type WorldStateStatusFull,
19
- } from '../native/message.js';
13
+ import type { DBStats, TreeDBStats, TreeMeta, WorldStateStatusFull } from '../native/message.js';
14
+ import type { WorldStateOperationName } from '../native/world_state_operation.js';
20
15
 
21
16
  type DBTypeString = 'leaf_preimage' | 'leaf_indices' | 'nodes' | 'blocks' | 'block_indices';
22
17
 
23
- const durationTrackDenylist = new Set<WorldStateMessageType>([
24
- WorldStateMessageType.GET_INITIAL_STATE_REFERENCE,
25
- WorldStateMessageType.CLOSE,
26
-
27
- // these aren't used anymore, should be removed from the API
28
- WorldStateMessageType.COMMIT,
29
- WorldStateMessageType.ROLLBACK,
30
- ]);
18
+ const durationTrackDenylist = new Set<WorldStateOperationName>(['getInitialStateReference']);
31
19
 
32
20
  export class WorldStateInstrumentation {
33
21
  private dbMapSize: Gauge;
@@ -144,10 +132,10 @@ export class WorldStateInstrumentation {
144
132
  );
145
133
  }
146
134
 
147
- public recordRoundTrip(timeUs: number, request: WorldStateMessageType) {
148
- if (!durationTrackDenylist.has(request)) {
135
+ public recordRoundTrip(timeUs: number, operation: WorldStateOperationName) {
136
+ if (!durationTrackDenylist.has(operation)) {
149
137
  this.requestHistogram.record(Math.ceil(timeUs), {
150
- [Attributes.WORLD_STATE_REQUEST_TYPE]: WorldStateMessageType[request],
138
+ [Attributes.WORLD_STATE_REQUEST_TYPE]: operation,
151
139
  });
152
140
  }
153
141
  }
@@ -1,2 +1,3 @@
1
1
  export * from './native_world_state.js';
2
2
  export * from './fork_checkpoint.js';
3
+ export { IpcWorldState, getWsdbOptions } from './ipc_world_state_instance.js';