@aztec/world-state 0.16.1 → 0.16.2

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 (28) hide show
  1. package/README.md +2 -2
  2. package/dest/merkle-tree/merkle_tree_operations_facade.d.ts +11 -9
  3. package/dest/merkle-tree/merkle_tree_operations_facade.d.ts.map +1 -1
  4. package/dest/merkle-tree/merkle_tree_operations_facade.js +7 -6
  5. package/dest/merkle-tree/merkle_tree_snapshot_operations_facade.d.ts +40 -0
  6. package/dest/merkle-tree/merkle_tree_snapshot_operations_facade.d.ts.map +1 -0
  7. package/dest/merkle-tree/merkle_tree_snapshot_operations_facade.js +100 -0
  8. package/dest/synchronizer/server_world_state_synchronizer.d.ts +3 -2
  9. package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
  10. package/dest/synchronizer/server_world_state_synchronizer.js +9 -5
  11. package/dest/synchronizer/world_state_synchronizer.d.ts +8 -2
  12. package/dest/synchronizer/world_state_synchronizer.d.ts.map +1 -1
  13. package/dest/world-state-db/index.d.ts +0 -1
  14. package/dest/world-state-db/index.d.ts.map +1 -1
  15. package/dest/world-state-db/merkle_tree_db.d.ts +16 -8
  16. package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
  17. package/dest/world-state-db/merkle_tree_db.js +1 -1
  18. package/dest/world-state-db/merkle_trees.d.ts +12 -9
  19. package/dest/world-state-db/merkle_trees.d.ts.map +1 -1
  20. package/dest/world-state-db/merkle_trees.js +33 -22
  21. package/package.json +5 -5
  22. package/src/merkle-tree/merkle_tree_operations_facade.ts +29 -27
  23. package/src/merkle-tree/merkle_tree_snapshot_operations_facade.ts +143 -0
  24. package/src/synchronizer/server_world_state_synchronizer.ts +10 -5
  25. package/src/synchronizer/world_state_synchronizer.ts +9 -2
  26. package/src/world-state-db/index.ts +0 -1
  27. package/src/world-state-db/merkle_tree_db.ts +28 -18
  28. package/src/world-state-db/merkle_trees.ts +60 -49
@@ -48,9 +48,9 @@ export interface WorldStateSynchronizer {
48
48
  /**
49
49
  * Forces an immediate sync to an optionally provided minimum block number
50
50
  * @param minBlockNumber - The minimum block number that we must sync to
51
- * @returns A promise that resolves once the sync has completed.
51
+ * @returns A promise that resolves with the block number the world state was synced to
52
52
  */
53
- syncImmediate(minBlockNumber?: number): Promise<void>;
53
+ syncImmediate(minBlockNumber?: number): Promise<number>;
54
54
 
55
55
  /**
56
56
  * Returns an instance of MerkleTreeOperations that will include uncommitted data.
@@ -63,4 +63,11 @@ export interface WorldStateSynchronizer {
63
63
  * @returns An instance of MerkleTreeOperations that will not include uncommitted data.
64
64
  */
65
65
  getCommitted(): MerkleTreeOperations;
66
+
67
+ /**
68
+ * Returns a readonly instance of MerkleTreeOperations where the state is as it was at the given block number
69
+ * @param block - The block number to look at
70
+ * @returns An instance of MerkleTreeOperations
71
+ */
72
+ getSnapshot(block: number): MerkleTreeOperations;
66
73
  }
@@ -1,3 +1,2 @@
1
1
  export * from './merkle_trees.js';
2
2
  export * from './merkle_tree_db.js';
3
- export { LeafData } from '@aztec/merkle-tree';
@@ -1,7 +1,8 @@
1
- import { MAX_NEW_NULLIFIERS_PER_TX } from '@aztec/circuits.js';
1
+ import { MAX_NEW_NULLIFIERS_PER_TX, NullifierLeafPreimage } from '@aztec/circuits.js';
2
2
  import { Fr } from '@aztec/foundation/fields';
3
3
  import { createDebugLogger } from '@aztec/foundation/log';
4
- import { LeafData, LowLeafWitnessData } from '@aztec/merkle-tree';
4
+ import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
5
+ import { BatchInsertionResult, IndexedTreeSnapshot, TreeSnapshot } from '@aztec/merkle-tree';
5
6
  import { L2Block, MerkleTreeId, SiblingPath } from '@aztec/types';
6
7
 
7
8
  /**
@@ -91,7 +92,13 @@ export type MerkleTreeDb = {
91
92
  [Property in keyof MerkleTreeOperations as Exclude<Property, MerkleTreeSetters>]: WithIncludeUncommitted<
92
93
  MerkleTreeOperations[Property]
93
94
  >;
94
- } & Pick<MerkleTreeOperations, MerkleTreeSetters>;
95
+ } & Pick<MerkleTreeOperations, MerkleTreeSetters> & {
96
+ /**
97
+ * Returns a snapshot of the current state of the trees.
98
+ * @param block - The block number to take the snapshot at.
99
+ */
100
+ getSnapshot(block: number): Promise<ReadonlyArray<TreeSnapshot | IndexedTreeSnapshot>>;
101
+ };
95
102
 
96
103
  /**
97
104
  * Defines the interface for operations on a set of Merkle Trees.
@@ -130,23 +137,26 @@ export interface MerkleTreeOperations {
130
137
  getPreviousValueIndex(
131
138
  treeId: IndexedTreeId,
132
139
  value: bigint,
133
- ): Promise<{
134
- /**
135
- * The index of the found leaf.
136
- */
137
- index: number;
138
- /**
139
- * A flag indicating if the corresponding leaf's value is equal to `newValue`.
140
- */
141
- alreadyPresent: boolean;
142
- }>;
140
+ ): Promise<
141
+ | {
142
+ /**
143
+ * The index of the found leaf.
144
+ */
145
+ index: bigint;
146
+ /**
147
+ * A flag indicating if the corresponding leaf's value is equal to `newValue`.
148
+ */
149
+ alreadyPresent: boolean;
150
+ }
151
+ | undefined
152
+ >;
143
153
 
144
154
  /**
145
155
  * Returns the data at a specific leaf.
146
156
  * @param treeId - The tree for which leaf data should be returned.
147
157
  * @param index - The index of the leaf required.
148
158
  */
149
- getLeafData(treeId: IndexedTreeId, index: number): Promise<LeafData | undefined>;
159
+ getLeafPreimage(treeId: IndexedTreeId, index: bigint): Promise<IndexedTreeLeafPreimage | undefined>;
150
160
 
151
161
  /**
152
162
  * Update the leaf data at the given index.
@@ -154,7 +164,7 @@ export interface MerkleTreeOperations {
154
164
  * @param leaf - The updated leaf value.
155
165
  * @param index - The index of the leaf to be updated.
156
166
  */
157
- updateLeaf(treeId: IndexedTreeId | PublicTreeId, leaf: LeafData | Buffer, index: bigint): Promise<void>;
167
+ updateLeaf(treeId: IndexedTreeId | PublicTreeId, leaf: NullifierLeafPreimage | Buffer, index: bigint): Promise<void>;
158
168
 
159
169
  /**
160
170
  * Returns the index containing a leaf value.
@@ -175,7 +185,7 @@ export interface MerkleTreeOperations {
175
185
  * This includes all of the current roots of all of the data trees and the current blocks global vars.
176
186
  * @param globalVariablesHash - The global variables hash to insert into the block hash.
177
187
  */
178
- updateHistoricBlocksTree(globalVariablesHash: Fr): Promise<void>;
188
+ updateBlocksTree(globalVariablesHash: Fr): Promise<void>;
179
189
 
180
190
  /**
181
191
  * Updates the latest global variables hash
@@ -195,11 +205,11 @@ export interface MerkleTreeOperations {
195
205
  * @param subtreeHeight - Height of the subtree.
196
206
  * @returns The witness data for the leaves to be updated when inserting the new ones.
197
207
  */
198
- batchInsert(
208
+ batchInsert<TreeHeight extends number, SubtreeSiblingPathHeight extends number>(
199
209
  treeId: MerkleTreeId,
200
210
  leaves: Buffer[],
201
211
  subtreeHeight: number,
202
- ): Promise<[LowLeafWitnessData<number>[], SiblingPath<number>] | [undefined, SiblingPath<number>]>;
212
+ ): Promise<BatchInsertionResult<TreeHeight, SubtreeSiblingPathHeight>>;
203
213
 
204
214
  /**
205
215
  * Handles a single L2 block (i.e. Inserts the new commitments into the merkle tree).
@@ -1,23 +1,25 @@
1
1
  import {
2
+ BLOCKS_TREE_HEIGHT,
2
3
  CONTRACT_TREE_HEIGHT,
3
4
  Fr,
4
5
  GlobalVariables,
5
- HISTORIC_BLOCKS_TREE_HEIGHT,
6
6
  L1_TO_L2_MSG_TREE_HEIGHT,
7
7
  NOTE_HASH_TREE_HEIGHT,
8
8
  NULLIFIER_SUBTREE_HEIGHT,
9
9
  NULLIFIER_TREE_HEIGHT,
10
+ NullifierLeaf,
11
+ NullifierLeafPreimage,
10
12
  PUBLIC_DATA_TREE_HEIGHT,
11
13
  } from '@aztec/circuits.js';
12
14
  import { computeBlockHash, computeGlobalsHash } from '@aztec/circuits.js/abis';
13
15
  import { Committable } from '@aztec/foundation/committable';
14
16
  import { SerialQueue } from '@aztec/foundation/fifo';
15
17
  import { createDebugLogger } from '@aztec/foundation/log';
18
+ import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
16
19
  import {
17
20
  AppendOnlyTree,
21
+ BatchInsertionResult,
18
22
  IndexedTree,
19
- LeafData,
20
- LowLeafWitnessData,
21
23
  Pedersen,
22
24
  SparseTree,
23
25
  StandardIndexedTree,
@@ -26,7 +28,7 @@ import {
26
28
  loadTree,
27
29
  newTree,
28
30
  } from '@aztec/merkle-tree';
29
- import { L2Block, MerkleTreeId, SiblingPath } from '@aztec/types';
31
+ import { Hasher, L2Block, MerkleTreeId, SiblingPath } from '@aztec/types';
30
32
 
31
33
  import { default as levelup } from 'levelup';
32
34
 
@@ -54,6 +56,15 @@ interface FromDbOptions {
54
56
 
55
57
  const LAST_GLOBAL_VARS_HASH = 'lastGlobalVarsHash';
56
58
 
59
+ /**
60
+ * The nullifier tree is an indexed tree.
61
+ */
62
+ class NullifierTree extends StandardIndexedTree {
63
+ constructor(db: levelup.LevelUp, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) {
64
+ super(db, hasher, name, depth, size, NullifierLeafPreimage, NullifierLeaf, root);
65
+ }
66
+ }
67
+
57
68
  /**
58
69
  * A convenience class for managing multiple merkle trees.
59
70
  */
@@ -83,7 +94,7 @@ export class MerkleTrees implements MerkleTreeDb {
83
94
  CONTRACT_TREE_HEIGHT,
84
95
  );
85
96
  const nullifierTree = await initializeTree(
86
- StandardIndexedTree,
97
+ NullifierTree,
87
98
  this.db,
88
99
  hasher,
89
100
  `${MerkleTreeId[MerkleTreeId.NULLIFIER_TREE]}`,
@@ -111,14 +122,14 @@ export class MerkleTrees implements MerkleTreeDb {
111
122
  `${MerkleTreeId[MerkleTreeId.L1_TO_L2_MESSAGES_TREE]}`,
112
123
  L1_TO_L2_MSG_TREE_HEIGHT,
113
124
  );
114
- const historicBlocksTree: AppendOnlyTree = await initializeTree(
125
+ const blocksTree: AppendOnlyTree = await initializeTree(
115
126
  StandardTree,
116
127
  this.db,
117
128
  hasher,
118
129
  `${MerkleTreeId[MerkleTreeId.BLOCKS_TREE]}`,
119
- HISTORIC_BLOCKS_TREE_HEIGHT,
130
+ BLOCKS_TREE_HEIGHT,
120
131
  );
121
- this.trees = [contractTree, nullifierTree, noteHashTree, publicDataTree, l1Tol2MessagesTree, historicBlocksTree];
132
+ this.trees = [contractTree, nullifierTree, noteHashTree, publicDataTree, l1Tol2MessagesTree, blocksTree];
122
133
 
123
134
  this.jobQueue.start();
124
135
 
@@ -126,7 +137,7 @@ export class MerkleTrees implements MerkleTreeDb {
126
137
  if (!fromDb) {
127
138
  const initialGlobalVariablesHash = computeGlobalsHash(GlobalVariables.empty());
128
139
  await this._updateLatestGlobalVariablesHash(initialGlobalVariablesHash);
129
- await this._updateHistoricBlocksTree(initialGlobalVariablesHash, true);
140
+ await this._updateBlocksTree(initialGlobalVariablesHash, true);
130
141
  await this._commit();
131
142
  } else {
132
143
  await this._updateLatestGlobalVariablesHash(fromDbOptions.globalVariablesHash);
@@ -178,8 +189,8 @@ export class MerkleTrees implements MerkleTreeDb {
178
189
  * @param globalsHash - The current global variables hash.
179
190
  * @param includeUncommitted - Indicates whether to include uncommitted data.
180
191
  */
181
- public async updateHistoricBlocksTree(globalsHash: Fr, includeUncommitted: boolean) {
182
- await this.synchronize(() => this._updateHistoricBlocksTree(globalsHash, includeUncommitted));
192
+ public async updateBlocksTree(globalsHash: Fr, includeUncommitted: boolean) {
193
+ await this.synchronize(() => this._updateBlocksTree(globalsHash, includeUncommitted));
183
194
  }
184
195
 
185
196
  /**
@@ -311,19 +322,20 @@ export class MerkleTrees implements MerkleTreeDb {
311
322
  treeId: IndexedTreeId,
312
323
  value: bigint,
313
324
  includeUncommitted: boolean,
314
- ): Promise<{
315
- /**
316
- * The index of the found leaf.
317
- */
318
- index: number;
319
- /**
320
- * A flag indicating if the corresponding leaf's value is equal to `newValue`.
321
- */
322
- alreadyPresent: boolean;
323
- }> {
324
- return await this.synchronize(() =>
325
- Promise.resolve(this._getIndexedTree(treeId).findIndexOfPreviousValue(value, includeUncommitted)),
326
- );
325
+ ): Promise<
326
+ | {
327
+ /**
328
+ * The index of the found leaf.
329
+ */
330
+ index: bigint;
331
+ /**
332
+ * A flag indicating if the corresponding leaf's value is equal to `newValue`.
333
+ */
334
+ alreadyPresent: boolean;
335
+ }
336
+ | undefined
337
+ > {
338
+ return await this.synchronize(() => this._getIndexedTree(treeId).findIndexOfPreviousKey(value, includeUncommitted));
327
339
  }
328
340
 
329
341
  /**
@@ -331,15 +343,15 @@ export class MerkleTrees implements MerkleTreeDb {
331
343
  * @param treeId - The ID of the tree get the leaf from.
332
344
  * @param index - The index of the leaf to get.
333
345
  * @param includeUncommitted - Indicates whether to include uncommitted data.
334
- * @returns Leaf data.
346
+ * @returns Leaf preimage.
335
347
  */
336
- public async getLeafData(
348
+ public async getLeafPreimage(
337
349
  treeId: IndexedTreeId,
338
- index: number,
350
+ index: bigint,
339
351
  includeUncommitted: boolean,
340
- ): Promise<LeafData | undefined> {
352
+ ): Promise<IndexedTreeLeafPreimage | undefined> {
341
353
  return await this.synchronize(() =>
342
- Promise.resolve(this._getIndexedTree(treeId).getLatestLeafDataCopy(index, includeUncommitted)),
354
+ this._getIndexedTree(treeId).getLatestLeafPreimageCopy(index, includeUncommitted),
343
355
  );
344
356
  }
345
357
 
@@ -357,13 +369,7 @@ export class MerkleTrees implements MerkleTreeDb {
357
369
  ): Promise<bigint | undefined> {
358
370
  return await this.synchronize(async () => {
359
371
  const tree = this.trees[treeId];
360
- for (let i = 0n; i < tree.getNumLeaves(includeUncommitted); i++) {
361
- const currentValue = await tree.getLeafValue(i, includeUncommitted);
362
- if (currentValue && currentValue.equals(value)) {
363
- return i;
364
- }
365
- }
366
- return undefined;
372
+ return await tree.findLeafIndex(value, includeUncommitted);
367
373
  });
368
374
  }
369
375
 
@@ -374,7 +380,7 @@ export class MerkleTrees implements MerkleTreeDb {
374
380
  * @param index - The index to insert into.
375
381
  * @returns Empty promise.
376
382
  */
377
- public async updateLeaf(treeId: IndexedTreeId | PublicTreeId, leaf: LeafData | Buffer, index: bigint): Promise<void> {
383
+ public async updateLeaf(treeId: IndexedTreeId | PublicTreeId, leaf: Buffer, index: bigint): Promise<void> {
378
384
  return await this.synchronize(() => this._updateLeaf(treeId, leaf, index));
379
385
  }
380
386
 
@@ -402,10 +408,7 @@ export class MerkleTrees implements MerkleTreeDb {
402
408
  treeId: MerkleTreeId,
403
409
  leaves: Buffer[],
404
410
  subtreeHeight: SubtreeHeight,
405
- ): Promise<
406
- | [LowLeafWitnessData<TreeHeight>[], SiblingPath<SubtreeSiblingPathHeight>]
407
- | [undefined, SiblingPath<SubtreeSiblingPathHeight>]
408
- > {
411
+ ): Promise<BatchInsertionResult<TreeHeight, SubtreeSiblingPathHeight>> {
409
412
  const tree = this.trees[treeId] as StandardIndexedTree;
410
413
  if (!('batchInsert' in tree)) {
411
414
  throw new Error('Tree does not support `batchInsert` method');
@@ -431,7 +434,7 @@ export class MerkleTrees implements MerkleTreeDb {
431
434
  return Promise.resolve(this.latestGlobalVariablesHash.get(includeUncommitted));
432
435
  }
433
436
 
434
- private async _updateHistoricBlocksTree(globalsHash: Fr, includeUncommitted: boolean) {
437
+ private async _updateBlocksTree(globalsHash: Fr, includeUncommitted: boolean) {
435
438
  const blockHash = await this._getCurrentBlockHash(globalsHash, includeUncommitted);
436
439
  await this._appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]);
437
440
  }
@@ -490,11 +493,7 @@ export class MerkleTrees implements MerkleTreeDb {
490
493
  return await tree.appendLeaves(leaves);
491
494
  }
492
495
 
493
- private async _updateLeaf(
494
- treeId: IndexedTreeId | PublicTreeId,
495
- leaf: LeafData | Buffer,
496
- index: bigint,
497
- ): Promise<void> {
496
+ private async _updateLeaf(treeId: IndexedTreeId | PublicTreeId, leaf: Buffer, index: bigint): Promise<void> {
498
497
  const tree = this.trees[treeId];
499
498
  if (!('updateLeaf' in tree)) {
500
499
  throw new Error('Tree does not support `updateLeaf` method');
@@ -525,6 +524,16 @@ export class MerkleTrees implements MerkleTreeDb {
525
524
  this.latestGlobalVariablesHash.rollback();
526
525
  }
527
526
 
527
+ public getSnapshot(blockNumber: number) {
528
+ return Promise.all(this.trees.map(tree => tree.getSnapshot(blockNumber)));
529
+ }
530
+
531
+ private async _snapshot(blockNumber: number): Promise<void> {
532
+ for (const tree of this.trees) {
533
+ await tree.snapshot(blockNumber);
534
+ }
535
+ }
536
+
528
537
  /**
529
538
  * Handles a single L2 block (i.e. Inserts the new commitments into the merkle tree).
530
539
  * @param l2Block - The L2 block to handle.
@@ -536,7 +545,7 @@ export class MerkleTrees implements MerkleTreeDb {
536
545
  [l2Block.endNoteHashTreeSnapshot.root, MerkleTreeId.NOTE_HASH_TREE],
537
546
  [l2Block.endPublicDataTreeRoot, MerkleTreeId.PUBLIC_DATA_TREE],
538
547
  [l2Block.endL1ToL2MessagesTreeSnapshot.root, MerkleTreeId.L1_TO_L2_MESSAGES_TREE],
539
- [l2Block.endHistoricBlocksTreeSnapshot.root, MerkleTreeId.BLOCKS_TREE],
548
+ [l2Block.endBlocksTreeSnapshot.root, MerkleTreeId.BLOCKS_TREE],
540
549
  ] as const;
541
550
  const compareRoot = (root: Fr, treeId: MerkleTreeId) => {
542
551
  const treeRoot = this.trees[treeId].getRoot(true);
@@ -577,7 +586,7 @@ export class MerkleTrees implements MerkleTreeDb {
577
586
  await this._updateLeaf(MerkleTreeId.PUBLIC_DATA_TREE, newValue.toBuffer(), leafIndex.value);
578
587
  }
579
588
 
580
- // Sync and add the block to the historic blocks tree
589
+ // Sync and add the block to the blocks tree
581
590
  const globalVariablesHash = computeGlobalsHash(l2Block.globalVariables);
582
591
  await this._updateLatestGlobalVariablesHash(globalVariablesHash);
583
592
  this.log(`Synced global variables with hash ${globalVariablesHash}`);
@@ -603,6 +612,8 @@ export class MerkleTrees implements MerkleTreeDb {
603
612
  }
604
613
  }
605
614
 
615
+ await this._snapshot(l2Block.number);
616
+
606
617
  return { isBlockOurs: ourBlock };
607
618
  }
608
619
  }