@aztec/world-state 0.0.1-fake-ceab37513c → 0.0.6-commit.a2d1860fe9

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/index.d.ts +1 -1
  2. package/dest/instrumentation/instrumentation.d.ts +1 -1
  3. package/dest/instrumentation/instrumentation.d.ts.map +1 -1
  4. package/dest/instrumentation/instrumentation.js +17 -41
  5. package/dest/native/bench_metrics.d.ts +1 -1
  6. package/dest/native/bench_metrics.d.ts.map +1 -1
  7. package/dest/native/fork_checkpoint.d.ts +1 -1
  8. package/dest/native/fork_checkpoint.d.ts.map +1 -1
  9. package/dest/native/index.d.ts +1 -1
  10. package/dest/native/merkle_trees_facade.d.ts +13 -5
  11. package/dest/native/merkle_trees_facade.d.ts.map +1 -1
  12. package/dest/native/merkle_trees_facade.js +41 -7
  13. package/dest/native/message.d.ts +15 -18
  14. package/dest/native/message.d.ts.map +1 -1
  15. package/dest/native/message.js +14 -20
  16. package/dest/native/native_world_state.d.ts +14 -11
  17. package/dest/native/native_world_state.d.ts.map +1 -1
  18. package/dest/native/native_world_state.js +26 -18
  19. package/dest/native/native_world_state_instance.d.ts +12 -3
  20. package/dest/native/native_world_state_instance.d.ts.map +1 -1
  21. package/dest/native/native_world_state_instance.js +25 -4
  22. package/dest/native/world_state_ops_queue.d.ts +1 -1
  23. package/dest/native/world_state_ops_queue.d.ts.map +1 -1
  24. package/dest/synchronizer/config.d.ts +3 -5
  25. package/dest/synchronizer/config.d.ts.map +1 -1
  26. package/dest/synchronizer/config.js +7 -9
  27. package/dest/synchronizer/errors.d.ts +1 -1
  28. package/dest/synchronizer/errors.d.ts.map +1 -1
  29. package/dest/synchronizer/factory.d.ts +4 -3
  30. package/dest/synchronizer/factory.d.ts.map +1 -1
  31. package/dest/synchronizer/factory.js +5 -5
  32. package/dest/synchronizer/index.d.ts +1 -1
  33. package/dest/synchronizer/server_world_state_synchronizer.d.ts +10 -27
  34. package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
  35. package/dest/synchronizer/server_world_state_synchronizer.js +107 -75
  36. package/dest/test/index.d.ts +1 -1
  37. package/dest/test/utils.d.ts +12 -5
  38. package/dest/test/utils.d.ts.map +1 -1
  39. package/dest/test/utils.js +54 -50
  40. package/dest/testing.d.ts +2 -2
  41. package/dest/testing.d.ts.map +1 -1
  42. package/dest/testing.js +1 -1
  43. package/dest/world-state-db/index.d.ts +1 -1
  44. package/dest/world-state-db/merkle_tree_db.d.ts +8 -7
  45. package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
  46. package/package.json +13 -12
  47. package/src/instrumentation/instrumentation.ts +17 -41
  48. package/src/native/merkle_trees_facade.ts +44 -6
  49. package/src/native/message.ts +26 -40
  50. package/src/native/native_world_state.ts +62 -22
  51. package/src/native/native_world_state_instance.ts +34 -4
  52. package/src/synchronizer/config.ts +8 -19
  53. package/src/synchronizer/factory.ts +7 -1
  54. package/src/synchronizer/server_world_state_synchronizer.ts +126 -101
  55. package/src/test/utils.ts +87 -92
  56. package/src/testing.ts +1 -1
  57. package/src/world-state-db/merkle_tree_db.ts +11 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/world-state",
3
- "version": "0.0.1-fake-ceab37513c",
3
+ "version": "0.0.6-commit.a2d1860fe9",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -18,8 +18,8 @@
18
18
  "tsconfig": "./tsconfig.json"
19
19
  },
20
20
  "scripts": {
21
- "build": "yarn clean && tsc -b",
22
- "build:dev": "tsc -b --watch",
21
+ "build": "yarn clean && ../scripts/tsc.sh",
22
+ "build:dev": "../scripts/tsc.sh --watch",
23
23
  "clean": "rm -rf ./dest .tsbuildinfo",
24
24
  "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}"
25
25
  },
@@ -64,22 +64,23 @@
64
64
  ]
65
65
  },
66
66
  "dependencies": {
67
- "@aztec/constants": "0.0.1-fake-ceab37513c",
68
- "@aztec/foundation": "0.0.1-fake-ceab37513c",
69
- "@aztec/kv-store": "0.0.1-fake-ceab37513c",
70
- "@aztec/merkle-tree": "0.0.1-fake-ceab37513c",
71
- "@aztec/native": "0.0.1-fake-ceab37513c",
72
- "@aztec/protocol-contracts": "0.0.1-fake-ceab37513c",
73
- "@aztec/stdlib": "0.0.1-fake-ceab37513c",
74
- "@aztec/telemetry-client": "0.0.1-fake-ceab37513c",
67
+ "@aztec/constants": "0.0.6-commit.a2d1860fe9",
68
+ "@aztec/foundation": "0.0.6-commit.a2d1860fe9",
69
+ "@aztec/kv-store": "0.0.6-commit.a2d1860fe9",
70
+ "@aztec/merkle-tree": "0.0.6-commit.a2d1860fe9",
71
+ "@aztec/native": "0.0.6-commit.a2d1860fe9",
72
+ "@aztec/protocol-contracts": "0.0.6-commit.a2d1860fe9",
73
+ "@aztec/stdlib": "0.0.6-commit.a2d1860fe9",
74
+ "@aztec/telemetry-client": "0.0.6-commit.a2d1860fe9",
75
75
  "tslib": "^2.4.0",
76
76
  "zod": "^3.23.8"
77
77
  },
78
78
  "devDependencies": {
79
- "@aztec/archiver": "0.0.1-fake-ceab37513c",
79
+ "@aztec/archiver": "0.0.6-commit.a2d1860fe9",
80
80
  "@jest/globals": "^30.0.0",
81
81
  "@types/jest": "^30.0.0",
82
82
  "@types/node": "^22.15.17",
83
+ "@typescript/native-preview": "7.0.0-dev.20260113.1",
83
84
  "jest": "^30.0.0",
84
85
  "jest-mock-extended": "^4.0.0",
85
86
  "ts-node": "^10.9.1",
@@ -7,7 +7,7 @@ import {
7
7
  Metrics,
8
8
  type TelemetryClient,
9
9
  type UpDownCounter,
10
- ValueType,
10
+ createUpDownCounterWithDefault,
11
11
  } from '@aztec/telemetry-client';
12
12
 
13
13
  import {
@@ -46,55 +46,31 @@ export class WorldStateInstrumentation {
46
46
  private log: Logger = createLogger('world-state:instrumentation'),
47
47
  ) {
48
48
  const meter = telemetry.getMeter('World State');
49
- this.dbMapSize = meter.createGauge(Metrics.WORLD_STATE_DB_MAP_SIZE, {
50
- description: `The current configured map size for each merkle tree`,
51
- valueType: ValueType.INT,
52
- });
49
+ this.dbMapSize = meter.createGauge(Metrics.WORLD_STATE_DB_MAP_SIZE);
53
50
 
54
- this.dbPhysicalSize = meter.createGauge(Metrics.WORLD_STATE_DB_PHYSICAL_SIZE, {
55
- description: `The current physical disk space used for each database`,
56
- valueType: ValueType.INT,
57
- });
51
+ this.dbPhysicalSize = meter.createGauge(Metrics.WORLD_STATE_DB_PHYSICAL_SIZE);
58
52
 
59
- this.treeSize = meter.createGauge(Metrics.WORLD_STATE_TREE_SIZE, {
60
- description: `The current number of leaves in each merkle tree`,
61
- valueType: ValueType.INT,
62
- });
53
+ this.treeSize = meter.createGauge(Metrics.WORLD_STATE_TREE_SIZE);
63
54
 
64
- this.unfinalizedHeight = meter.createGauge(Metrics.WORLD_STATE_UNFINALIZED_HEIGHT, {
65
- description: `The unfinalized block height of each merkle tree`,
66
- valueType: ValueType.INT,
67
- });
55
+ this.unfinalizedHeight = meter.createGauge(Metrics.WORLD_STATE_UNFINALIZED_HEIGHT);
68
56
 
69
- this.finalizedHeight = meter.createGauge(Metrics.WORLD_STATE_FINALIZED_HEIGHT, {
70
- description: `The finalized block height of each merkle tree`,
71
- valueType: ValueType.INT,
72
- });
57
+ this.finalizedHeight = meter.createGauge(Metrics.WORLD_STATE_FINALIZED_HEIGHT);
73
58
 
74
- this.oldestBlock = meter.createGauge(Metrics.WORLD_STATE_OLDEST_BLOCK, {
75
- description: `The oldest historical block of each merkle tree`,
76
- valueType: ValueType.INT,
77
- });
59
+ this.oldestBlock = meter.createGauge(Metrics.WORLD_STATE_OLDEST_BLOCK);
78
60
 
79
- this.dbUsedSize = meter.createGauge(Metrics.WORLD_STATE_DB_USED_SIZE, {
80
- description: `The current used database size for each db of each merkle tree`,
81
- valueType: ValueType.INT,
82
- });
61
+ this.dbUsedSize = meter.createGauge(Metrics.WORLD_STATE_DB_USED_SIZE);
83
62
 
84
- this.dbNumItems = meter.createGauge(Metrics.WORLD_STATE_DB_NUM_ITEMS, {
85
- description: `The current number of items in each database of each merkle tree`,
86
- valueType: ValueType.INT,
87
- });
63
+ this.dbNumItems = meter.createGauge(Metrics.WORLD_STATE_DB_NUM_ITEMS);
88
64
 
89
- this.requestHistogram = meter.createHistogram(Metrics.WORLD_STATE_REQUEST_TIME, {
90
- description: 'The round trip time of world state requests',
91
- unit: 'us',
92
- valueType: ValueType.INT,
93
- });
65
+ this.requestHistogram = meter.createHistogram(Metrics.WORLD_STATE_REQUEST_TIME);
94
66
 
95
- this.criticalErrors = meter.createUpDownCounter(Metrics.WORLD_STATE_CRITICAL_ERROR_COUNT, {
96
- description: 'The number of critical errors in the world state',
97
- valueType: ValueType.INT,
67
+ this.criticalErrors = createUpDownCounterWithDefault(meter, Metrics.WORLD_STATE_CRITICAL_ERROR_COUNT, {
68
+ [Attributes.ERROR_TYPE]: [
69
+ 'synch_pending_block',
70
+ 'finalize_block',
71
+ 'prune_pending_block',
72
+ 'prune_historical_block',
73
+ ],
98
74
  });
99
75
  }
100
76
 
@@ -1,5 +1,8 @@
1
- import { Fr } from '@aztec/foundation/fields';
1
+ import { BlockNumber } from '@aztec/foundation/branded-types';
2
+ import { Fr } from '@aztec/foundation/curves/bn254';
3
+ import { createLogger } from '@aztec/foundation/log';
2
4
  import { serializeToBuffer } from '@aztec/foundation/serialize';
5
+ import { sleep } from '@aztec/foundation/sleep';
3
6
  import { type IndexedTreeLeafPreimage, SiblingPath } from '@aztec/foundation/trees';
4
7
  import type {
5
8
  BatchInsertionResult,
@@ -18,6 +21,7 @@ import {
18
21
  PublicDataTreeLeafPreimage,
19
22
  } from '@aztec/stdlib/trees';
20
23
  import { type BlockHeader, PartialStateReference, StateReference } from '@aztec/stdlib/tx';
24
+ import { type WorldStateRevision, WorldStateRevisionWithHandle } from '@aztec/stdlib/world-state';
21
25
 
22
26
  import assert from 'assert';
23
27
 
@@ -25,7 +29,6 @@ import {
25
29
  type SerializedIndexedLeaf,
26
30
  type SerializedLeafValue,
27
31
  WorldStateMessageType,
28
- type WorldStateRevision,
29
32
  blockStateReference,
30
33
  treeStateReferenceToSnapshot,
31
34
  } from './message.js';
@@ -42,6 +45,10 @@ export class MerkleTreesFacade implements MerkleTreeReadOperations {
42
45
  return this.initialHeader;
43
46
  }
44
47
 
48
+ getRevision(): WorldStateRevisionWithHandle {
49
+ return WorldStateRevisionWithHandle.fromWorldStateRevision(this.revision, this.instance.getHandle());
50
+ }
51
+
45
52
  findLeafIndices(treeId: MerkleTreeId, values: MerkleTreeLeafType<MerkleTreeId>[]): Promise<(bigint | undefined)[]> {
46
53
  return this.findLeafIndicesAfter(treeId, values, 0n);
47
54
  }
@@ -187,19 +194,26 @@ export class MerkleTreesFacade implements MerkleTreeReadOperations {
187
194
  async getBlockNumbersForLeafIndices<ID extends MerkleTreeId>(
188
195
  treeId: ID,
189
196
  leafIndices: bigint[],
190
- ): Promise<(bigint | undefined)[]> {
197
+ ): Promise<(BlockNumber | undefined)[]> {
191
198
  const response = await this.instance.call(WorldStateMessageType.GET_BLOCK_NUMBERS_FOR_LEAF_INDICES, {
192
199
  treeId,
193
200
  revision: this.revision,
194
201
  leafIndices,
195
202
  });
196
203
 
197
- return response.blockNumbers.map(x => (x === undefined || x === null ? undefined : BigInt(x)));
204
+ return response.blockNumbers.map(x => (x === undefined || x === null ? undefined : BlockNumber(Number(x))));
198
205
  }
199
206
  }
200
207
 
201
208
  export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTreeWriteOperations {
202
- constructor(instance: NativeWorldStateInstance, initialHeader: BlockHeader, revision: WorldStateRevision) {
209
+ private log = createLogger('world-state:merkle-trees-fork-facade');
210
+
211
+ constructor(
212
+ instance: NativeWorldStateInstance,
213
+ initialHeader: BlockHeader,
214
+ revision: WorldStateRevision,
215
+ private opts: { closeDelayMs?: number },
216
+ ) {
203
217
  assert.notEqual(revision.forkId, 0, 'Fork ID must be set');
204
218
  assert.equal(revision.includeUncommitted, true, 'Fork must include uncommitted data');
205
219
  super(instance, initialHeader, revision);
@@ -278,7 +292,31 @@ export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTr
278
292
 
279
293
  public async close(): Promise<void> {
280
294
  assert.notEqual(this.revision.forkId, 0, 'Fork ID must be set');
281
- await this.instance.call(WorldStateMessageType.DELETE_FORK, { forkId: this.revision.forkId });
295
+ try {
296
+ await this.instance.call(WorldStateMessageType.DELETE_FORK, { forkId: this.revision.forkId });
297
+ } catch (err: any) {
298
+ // Ignore errors due to native instance being closed during shutdown.
299
+ // This can happen when validators are still processing block proposals while the node is stopping.
300
+ if (err?.message === 'Native instance is closed') {
301
+ return;
302
+ }
303
+ throw err;
304
+ }
305
+ }
306
+
307
+ async [Symbol.asyncDispose](): Promise<void> {
308
+ if (this.opts.closeDelayMs) {
309
+ void sleep(this.opts.closeDelayMs)
310
+ .then(() => this.close())
311
+ .catch(err => {
312
+ if (err && 'message' in err && err.message === 'Native instance is closed') {
313
+ return; // Ignore errors due to native instance being closed
314
+ }
315
+ this.log.warn('Error closing MerkleTreesForkFacade after delay', { err });
316
+ });
317
+ } else {
318
+ await this.close();
319
+ }
282
320
  }
283
321
 
284
322
  public async createCheckpoint(): Promise<void> {
@@ -1,8 +1,11 @@
1
- import { Fr } from '@aztec/foundation/fields';
1
+ import { BlockNumber } from '@aztec/foundation/branded-types';
2
+ import { Fr } from '@aztec/foundation/curves/bn254';
2
3
  import type { Tuple } from '@aztec/foundation/serialize';
4
+ import type { BlockHash } from '@aztec/stdlib/block';
3
5
  import { AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
4
6
  import type { StateReference } from '@aztec/stdlib/tx';
5
7
  import type { UInt32 } from '@aztec/stdlib/types';
8
+ import type { WorldStateRevision } from '@aztec/stdlib/world-state';
6
9
 
7
10
  export enum WorldStateMessageType {
8
11
  GET_TREE_INFO = 100,
@@ -55,11 +58,11 @@ interface WithTreeId {
55
58
 
56
59
  export interface WorldStateStatusSummary {
57
60
  /** Last block number that can still be unwound. */
58
- unfinalizedBlockNumber: bigint;
61
+ unfinalizedBlockNumber: BlockNumber;
59
62
  /** Last block number that is finalized and cannot be unwound. */
60
- finalizedBlockNumber: bigint;
63
+ finalizedBlockNumber: BlockNumber;
61
64
  /** Oldest block still available for historical queries and forks. */
62
- oldestHistoricalBlock: bigint;
65
+ oldestHistoricalBlock: BlockNumber;
63
66
  /** Whether the trees are in sync with each other */
64
67
  treesAreSynched: boolean;
65
68
  }
@@ -80,11 +83,11 @@ export interface TreeMeta {
80
83
  /** The tree's initial root value */
81
84
  initialRoot: Fr;
82
85
  /** The current oldest historical block number of the tree */
83
- oldestHistoricBlock: bigint;
86
+ oldestHistoricBlock: BlockNumber;
84
87
  /** The current unfinalized block number of the tree */
85
- unfinalizedBlockHeight: bigint;
88
+ unfinalizedBlockHeight: BlockNumber;
86
89
  /** The current finalized block number of the tree */
87
- finalizedBlockHeight: bigint;
90
+ finalizedBlockHeight: BlockNumber;
88
91
  }
89
92
 
90
93
  export interface DBStats {
@@ -172,9 +175,9 @@ export function buildEmptyTreeMeta() {
172
175
  depth: 0,
173
176
  size: 0n,
174
177
  committedSize: 0n,
175
- unfinalizedBlockHeight: 0n,
176
- finalizedBlockHeight: 0n,
177
- oldestHistoricBlock: 0n,
178
+ unfinalizedBlockHeight: BlockNumber.ZERO,
179
+ finalizedBlockHeight: BlockNumber.ZERO,
180
+ oldestHistoricBlock: BlockNumber.ZERO,
178
181
  root: Fr.ZERO,
179
182
  initialRoot: Fr.ZERO,
180
183
  initialSize: 0n,
@@ -203,9 +206,9 @@ export function buildEmptyWorldStateDBStats() {
203
206
 
204
207
  export function buildEmptyWorldStateSummary() {
205
208
  return {
206
- unfinalizedBlockNumber: 0n,
207
- finalizedBlockNumber: 0n,
208
- oldestHistoricalBlock: 0n,
209
+ unfinalizedBlockNumber: BlockNumber.ZERO,
210
+ finalizedBlockNumber: BlockNumber.ZERO,
211
+ oldestHistoricalBlock: BlockNumber.ZERO,
209
212
  treesAreSynched: true,
210
213
  } as WorldStateStatusSummary;
211
214
  }
@@ -219,9 +222,9 @@ export function buildEmptyWorldStateStatusFull() {
219
222
  }
220
223
 
221
224
  export function sanitizeSummary(summary: WorldStateStatusSummary) {
222
- summary.finalizedBlockNumber = BigInt(summary.finalizedBlockNumber);
223
- summary.unfinalizedBlockNumber = BigInt(summary.unfinalizedBlockNumber);
224
- summary.oldestHistoricalBlock = BigInt(summary.oldestHistoricalBlock);
225
+ summary.finalizedBlockNumber = BlockNumber.fromBigInt(BigInt(summary.finalizedBlockNumber));
226
+ summary.unfinalizedBlockNumber = BlockNumber.fromBigInt(BigInt(summary.unfinalizedBlockNumber));
227
+ summary.oldestHistoricalBlock = BlockNumber.fromBigInt(BigInt(summary.oldestHistoricalBlock));
225
228
  return summary;
226
229
  }
227
230
 
@@ -233,11 +236,11 @@ export function sanitizeDBStats(stats: DBStats) {
233
236
 
234
237
  export function sanitizeMeta(meta: TreeMeta) {
235
238
  meta.committedSize = BigInt(meta.committedSize);
236
- meta.finalizedBlockHeight = BigInt(meta.finalizedBlockHeight);
239
+ meta.finalizedBlockHeight = BlockNumber.fromBigInt(BigInt(meta.finalizedBlockHeight));
237
240
  meta.initialSize = BigInt(meta.initialSize);
238
- meta.oldestHistoricBlock = BigInt(meta.oldestHistoricBlock);
241
+ meta.oldestHistoricBlock = BlockNumber.fromBigInt(BigInt(meta.oldestHistoricBlock));
239
242
  meta.size = BigInt(meta.size);
240
- meta.unfinalizedBlockHeight = BigInt(meta.unfinalizedBlockHeight);
243
+ meta.unfinalizedBlockHeight = BlockNumber.fromBigInt(BigInt(meta.unfinalizedBlockHeight));
241
244
  return meta;
242
245
  }
243
246
 
@@ -309,7 +312,7 @@ interface WithLeafValues {
309
312
  }
310
313
 
311
314
  interface BlockShiftRequest extends WithCanonicalForkId {
312
- toBlockNumber: bigint;
315
+ toBlockNumber: BlockNumber;
313
316
  }
314
317
 
315
318
  interface WithLeaves {
@@ -408,9 +411,9 @@ interface UpdateArchiveRequest extends WithForkId {
408
411
  }
409
412
 
410
413
  interface SyncBlockRequest extends WithCanonicalForkId {
411
- blockNumber: number;
414
+ blockNumber: BlockNumber;
412
415
  blockStateRef: BlockStateReference;
413
- blockHeaderHash: Fr;
416
+ blockHeaderHash: BlockHash;
414
417
  paddedNoteHashes: readonly SerializedLeafValue[];
415
418
  paddedL1ToL2Messages: readonly SerializedLeafValue[];
416
419
  paddedNullifiers: readonly SerializedLeafValue[];
@@ -419,7 +422,7 @@ interface SyncBlockRequest extends WithCanonicalForkId {
419
422
 
420
423
  interface CreateForkRequest extends WithCanonicalForkId {
421
424
  latest: boolean;
422
- blockNumber: number;
425
+ blockNumber: BlockNumber;
423
426
  }
424
427
 
425
428
  interface CreateForkResponse {
@@ -537,23 +540,6 @@ export type WorldStateResponse = {
537
540
  [WorldStateMessageType.CLOSE]: void;
538
541
  };
539
542
 
540
- export type WorldStateRevision = {
541
- forkId: number;
542
- blockNumber: number;
543
- includeUncommitted: boolean;
544
- };
545
- export function worldStateRevision(
546
- includeUncommitted: boolean,
547
- forkId: number | undefined,
548
- blockNumber: number | undefined,
549
- ): WorldStateRevision {
550
- return {
551
- forkId: forkId ?? 0,
552
- blockNumber: blockNumber ?? 0,
553
- includeUncommitted,
554
- };
555
- }
556
-
557
543
  type TreeStateReference = readonly [Buffer, number | bigint];
558
544
  type BlockStateReference = Map<Exclude<MerkleTreeId, MerkleTreeId.ARCHIVE>, TreeStateReference>;
559
545
 
@@ -1,11 +1,12 @@
1
1
  import { MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
+ import { BlockNumber } from '@aztec/foundation/branded-types';
2
3
  import { fromEntries, padArrayEnd } from '@aztec/foundation/collection';
4
+ import { Fr } from '@aztec/foundation/curves/bn254';
3
5
  import { EthAddress } from '@aztec/foundation/eth-address';
4
- import { Fr } from '@aztec/foundation/fields';
5
6
  import { tryRmDir } from '@aztec/foundation/fs';
6
- import { type Logger, createLogger } from '@aztec/foundation/log';
7
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
7
8
  import type { L2Block } from '@aztec/stdlib/block';
8
- import { DatabaseVersionManager } from '@aztec/stdlib/database-version';
9
+ import { DatabaseVersionManager } from '@aztec/stdlib/database-version/manager';
9
10
  import type {
10
11
  IndexedTreeId,
11
12
  MerkleTreeReadOperations,
@@ -14,6 +15,7 @@ import type {
14
15
  import type { SnapshotDataKeys } from '@aztec/stdlib/snapshots';
15
16
  import { MerkleTreeId, NullifierLeaf, type NullifierLeafPreimage, PublicDataTreeLeaf } from '@aztec/stdlib/trees';
16
17
  import { BlockHeader, PartialStateReference, StateReference } from '@aztec/stdlib/tx';
18
+ import { WorldStateRevision } from '@aztec/stdlib/world-state';
17
19
  import { getTelemetryClient } from '@aztec/telemetry-client';
18
20
 
19
21
  import assert from 'assert/strict';
@@ -33,7 +35,6 @@ import {
33
35
  sanitizeFullStatus,
34
36
  sanitizeSummary,
35
37
  treeStateReferenceToSnapshot,
36
- worldStateRevision,
37
38
  } from './message.js';
38
39
  import { NativeWorldState } from './native_world_state_instance.js';
39
40
 
@@ -51,7 +52,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
51
52
  protected constructor(
52
53
  protected instance: NativeWorldState,
53
54
  protected readonly worldStateInstrumentation: WorldStateInstrumentation,
54
- protected readonly log: Logger = createLogger('world-state:database'),
55
+ protected readonly log: Logger,
55
56
  private readonly cleanup = () => Promise.resolve(),
56
57
  ) {}
57
58
 
@@ -61,9 +62,10 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
61
62
  wsTreeMapSizes: WorldStateTreeMapSizes,
62
63
  prefilledPublicData: PublicDataTreeLeaf[] = [],
63
64
  instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
64
- log = createLogger('world-state:database'),
65
+ bindings?: LoggerBindings,
65
66
  cleanup = () => Promise.resolve(),
66
67
  ): Promise<NativeWorldStateService> {
68
+ const log = createLogger('world-state:database', bindings);
67
69
  const worldStateDirectory = join(dataDir, WORLD_STATE_DIR);
68
70
  // Create a version manager to handle versioning
69
71
  const versionManager = new DatabaseVersionManager({
@@ -71,7 +73,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
71
73
  rollupAddress,
72
74
  dataDirectory: worldStateDirectory,
73
75
  onOpen: (dir: string) => {
74
- return Promise.resolve(new NativeWorldState(dir, wsTreeMapSizes, prefilledPublicData, instrumentation));
76
+ return Promise.resolve(
77
+ new NativeWorldState(dir, wsTreeMapSizes, prefilledPublicData, instrumentation, bindings),
78
+ );
75
79
  },
76
80
  });
77
81
 
@@ -92,8 +96,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
92
96
  cleanupTmpDir = true,
93
97
  prefilledPublicData: PublicDataTreeLeaf[] = [],
94
98
  instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
99
+ bindings?: LoggerBindings,
95
100
  ): Promise<NativeWorldStateService> {
96
- const log = createLogger('world-state:database');
101
+ const log = createLogger('world-state:database', bindings);
97
102
  const dataDir = await mkdtemp(join(tmpdir(), 'aztec-world-state-'));
98
103
  const dbMapSizeKb = 10 * 1024 * 1024;
99
104
  const worldStateTreeMapSizes: WorldStateTreeMapSizes = {
@@ -115,7 +120,15 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
115
120
  }
116
121
  };
117
122
 
118
- return this.new(rollupAddress, dataDir, worldStateTreeMapSizes, prefilledPublicData, instrumentation, log, cleanup);
123
+ return this.new(
124
+ rollupAddress,
125
+ dataDir,
126
+ worldStateTreeMapSizes,
127
+ prefilledPublicData,
128
+ instrumentation,
129
+ bindings,
130
+ cleanup,
131
+ );
119
132
  }
120
133
 
121
134
  protected async init() {
@@ -134,7 +147,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
134
147
 
135
148
  // the initial header _must_ be the first element in the archive tree
136
149
  // if this assertion fails, check that the hashing done in Header in yarn-project matches the initial header hash done in world_state.cpp
137
- const indices = await committed.findLeafIndices(MerkleTreeId.ARCHIVE, [await this.initialHeader.hash()]);
150
+ const indices = await committed.findLeafIndices(MerkleTreeId.ARCHIVE, [(await this.initialHeader.hash()).toFr()]);
138
151
  const initialHeaderIndex = indices[0];
139
152
  assert.strictEqual(initialHeaderIndex, 0n, 'Invalid initial archive state');
140
153
  }
@@ -147,20 +160,36 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
147
160
  }
148
161
 
149
162
  public getCommitted(): MerkleTreeReadOperations {
150
- return new MerkleTreesFacade(this.instance, this.initialHeader!, worldStateRevision(false, 0, 0));
163
+ return new MerkleTreesFacade(this.instance, this.initialHeader!, WorldStateRevision.empty());
151
164
  }
152
165
 
153
- public getSnapshot(blockNumber: number): MerkleTreeReadOperations {
154
- return new MerkleTreesFacade(this.instance, this.initialHeader!, worldStateRevision(false, 0, blockNumber));
166
+ public getSnapshot(blockNumber: BlockNumber): MerkleTreeReadOperations {
167
+ return new MerkleTreesFacade(
168
+ this.instance,
169
+ this.initialHeader!,
170
+ new WorldStateRevision(/*forkId=*/ 0, /* blockNumber=*/ blockNumber, /* includeUncommitted=*/ false),
171
+ );
155
172
  }
156
173
 
157
- public async fork(blockNumber?: number): Promise<MerkleTreeWriteOperations> {
174
+ public async fork(
175
+ blockNumber?: BlockNumber,
176
+ opts: { closeDelayMs?: number } = {},
177
+ ): Promise<MerkleTreeWriteOperations> {
158
178
  const resp = await this.instance.call(WorldStateMessageType.CREATE_FORK, {
159
179
  latest: blockNumber === undefined,
160
- blockNumber: blockNumber ?? 0,
180
+ blockNumber: blockNumber ?? BlockNumber.ZERO,
161
181
  canonical: true,
162
182
  });
163
- return new MerkleTreesForkFacade(this.instance, this.initialHeader!, worldStateRevision(true, resp.forkId, 0));
183
+ return new MerkleTreesForkFacade(
184
+ this.instance,
185
+ this.initialHeader!,
186
+ new WorldStateRevision(
187
+ /*forkId=*/ resp.forkId,
188
+ /* blockNumber=*/ BlockNumber.ZERO,
189
+ /* includeUncommitted=*/ true,
190
+ ),
191
+ opts,
192
+ );
164
193
  }
165
194
 
166
195
  public getInitialHeader(): BlockHeader {
@@ -168,11 +197,22 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
168
197
  }
169
198
 
170
199
  public async handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
171
- // We have to pad both the values within tx effects because that's how the trees are built by circuits.
200
+ const isFirstBlock = l2Block.indexWithinCheckpoint === 0;
201
+ if (!isFirstBlock && l1ToL2Messages.length > 0) {
202
+ throw new Error(
203
+ `L1 to L2 messages must be empty for non-first blocks, but got ${l1ToL2Messages.length} messages for block ${l2Block.number}.`,
204
+ );
205
+ }
206
+
207
+ // We have to pad the given l1 to l2 messages, and the note hashes and nullifiers within tx effects, because that's
208
+ // how the trees are built by circuits.
209
+ const paddedL1ToL2Messages = isFirstBlock
210
+ ? padArrayEnd<Fr, number>(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP)
211
+ : [];
212
+
172
213
  const paddedNoteHashes = l2Block.body.txEffects.flatMap(txEffect =>
173
214
  padArrayEnd(txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
174
215
  );
175
- const paddedL1ToL2Messages = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
176
216
 
177
217
  const paddedNullifiers = l2Block.body.txEffects
178
218
  .flatMap(txEffect => padArrayEnd(txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX))
@@ -192,7 +232,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
192
232
  WorldStateMessageType.SYNC_BLOCK,
193
233
  {
194
234
  blockNumber: l2Block.number,
195
- blockHeaderHash: await l2Block.header.hash(),
235
+ blockHeaderHash: await l2Block.hash(),
196
236
  paddedL1ToL2Messages: paddedL1ToL2Messages.map(serializeLeaf),
197
237
  paddedNoteHashes: paddedNoteHashes.map(serializeLeaf),
198
238
  paddedNullifiers: paddedNullifiers.map(serializeLeaf),
@@ -240,7 +280,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
240
280
  * @param toBlockNumber The block number that is now the tip of the finalized chain
241
281
  * @returns The new WorldStateStatus
242
282
  */
243
- public async setFinalized(toBlockNumber: bigint) {
283
+ public async setFinalized(toBlockNumber: BlockNumber) {
244
284
  try {
245
285
  await this.instance.call(
246
286
  WorldStateMessageType.FINALIZE_BLOCKS,
@@ -263,7 +303,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
263
303
  * @param toBlockNumber The block number of the new oldest historical block
264
304
  * @returns The new WorldStateStatus
265
305
  */
266
- public async removeHistoricalBlocks(toBlockNumber: bigint) {
306
+ public async removeHistoricalBlocks(toBlockNumber: BlockNumber) {
267
307
  try {
268
308
  return await this.instance.call(
269
309
  WorldStateMessageType.REMOVE_HISTORICAL_BLOCKS,
@@ -285,7 +325,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
285
325
  * @param toBlockNumber The block number of the new tip of the pending chain,
286
326
  * @returns The new WorldStateStatus
287
327
  */
288
- public async unwindBlocks(toBlockNumber: bigint) {
328
+ public async unwindBlocks(toBlockNumber: BlockNumber) {
289
329
  try {
290
330
  return await this.instance.call(
291
331
  WorldStateMessageType.UNWIND_BLOCKS,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ARCHIVE_HEIGHT,
3
- GeneratorIndex,
3
+ DomainSeparator,
4
4
  L1_TO_L2_MSG_TREE_HEIGHT,
5
5
  MAX_NULLIFIERS_PER_TX,
6
6
  MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
@@ -8,7 +8,7 @@ import {
8
8
  NULLIFIER_TREE_HEIGHT,
9
9
  PUBLIC_DATA_TREE_HEIGHT,
10
10
  } from '@aztec/constants';
11
- import { type Logger, createLogger } from '@aztec/foundation/log';
11
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
12
12
  import { NativeWorldState as BaseNativeWorldState, MsgpackChannel } from '@aztec/native';
13
13
  import { MerkleTreeId } from '@aztec/stdlib/trees';
14
14
  import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
@@ -36,6 +36,8 @@ export interface NativeWorldStateInstance {
36
36
  messageType: T,
37
37
  body: WorldStateRequest[T] & WorldStateRequestCategories,
38
38
  ): Promise<WorldStateResponse[T]>;
39
+ // TODO(dbanks12): this returns any type, but we should strongly type it
40
+ getHandle(): any;
39
41
  }
40
42
 
41
43
  /**
@@ -55,7 +57,8 @@ export class NativeWorldState implements NativeWorldStateInstance {
55
57
  private readonly wsTreeMapSizes: WorldStateTreeMapSizes,
56
58
  private readonly prefilledPublicData: PublicDataTreeLeaf[] = [],
57
59
  private readonly instrumentation: WorldStateInstrumentation,
58
- private readonly log: Logger = createLogger('world-state:database'),
60
+ bindings?: LoggerBindings,
61
+ private readonly log: Logger = createLogger('world-state:database', bindings),
59
62
  ) {
60
63
  const threads = Math.min(cpus().length, MAX_WORLD_STATE_THREADS);
61
64
  log.info(
@@ -78,7 +81,7 @@ export class NativeWorldState implements NativeWorldStateInstance {
78
81
  [MerkleTreeId.PUBLIC_DATA_TREE]: 2 * MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
79
82
  },
80
83
  prefilledPublicDataBufferArray,
81
- GeneratorIndex.BLOCK_HASH,
84
+ DomainSeparator.BLOCK_HEADER_HASH,
82
85
  {
83
86
  [MerkleTreeId.NULLIFIER_TREE]: wsTreeMapSizes.nullifierTreeMapSizeKb,
84
87
  [MerkleTreeId.NOTE_HASH_TREE]: wsTreeMapSizes.noteHashTreeMapSizeKb,
@@ -103,10 +106,37 @@ export class NativeWorldState implements NativeWorldStateInstance {
103
106
  this.wsTreeMapSizes,
104
107
  this.prefilledPublicData,
105
108
  this.instrumentation,
109
+ this.log.getBindings(),
106
110
  this.log,
107
111
  );
108
112
  }
109
113
 
114
+ /**
115
+ * Gets the native WorldState handle from the underlying native instance.
116
+ * We call the getHandle() method on the native WorldState to get a NAPI External
117
+ * that wraps the underlying C++ WorldState pointer.
118
+ * @returns The NAPI External handle to the native WorldState instance,since
119
+ * the NAPI external type is opaque, we return any (we could also use an opaque symbol type)
120
+ */
121
+ public getHandle(): any {
122
+ const worldStateWrapper = (this.instance as any).dest;
123
+
124
+ if (!worldStateWrapper) {
125
+ throw new Error('No WorldStateWrapper found');
126
+ }
127
+
128
+ if (typeof worldStateWrapper.getHandle !== 'function') {
129
+ throw new Error('WorldStateWrapper does not have getHandle method');
130
+ }
131
+
132
+ // Call getHandle() to get the NAPI External
133
+ try {
134
+ return worldStateWrapper.getHandle();
135
+ } catch (error) {
136
+ this.log.error('Failed to get native WorldState handle', error);
137
+ }
138
+ }
139
+
110
140
  /**
111
141
  * Sends a message to the native instance and returns the response.
112
142
  * @param messageType - The type of message to send