@aztec/world-state 0.30.1 → 0.32.0

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 (25) hide show
  1. package/dest/synchronizer/server_world_state_synchronizer.d.ts +8 -4
  2. package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
  3. package/dest/synchronizer/server_world_state_synchronizer.js +40 -8
  4. package/dest/world-state-db/merkle_tree_db.d.ts +11 -2
  5. package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
  6. package/dest/world-state-db/merkle_tree_db.js +2 -1
  7. package/dest/world-state-db/merkle_tree_operations.d.ts +36 -12
  8. package/dest/world-state-db/merkle_tree_operations.d.ts.map +1 -1
  9. package/dest/world-state-db/merkle_tree_operations.js +2 -1
  10. package/dest/world-state-db/merkle_tree_operations_facade.d.ts +18 -10
  11. package/dest/world-state-db/merkle_tree_operations_facade.d.ts.map +1 -1
  12. package/dest/world-state-db/merkle_tree_operations_facade.js +13 -3
  13. package/dest/world-state-db/merkle_tree_snapshot_operations_facade.d.ts +7 -7
  14. package/dest/world-state-db/merkle_tree_snapshot_operations_facade.d.ts.map +1 -1
  15. package/dest/world-state-db/merkle_tree_snapshot_operations_facade.js +13 -7
  16. package/dest/world-state-db/merkle_trees.d.ts +18 -9
  17. package/dest/world-state-db/merkle_trees.d.ts.map +1 -1
  18. package/dest/world-state-db/merkle_trees.js +60 -24
  19. package/package.json +7 -7
  20. package/src/synchronizer/server_world_state_synchronizer.ts +52 -10
  21. package/src/world-state-db/merkle_tree_db.ts +18 -3
  22. package/src/world-state-db/merkle_tree_operations.ts +48 -14
  23. package/src/world-state-db/merkle_tree_operations_facade.ts +40 -14
  24. package/src/world-state-db/merkle_tree_snapshot_operations_facade.ts +36 -16
  25. package/src/world-state-db/merkle_trees.ts +108 -33
@@ -1,8 +1,8 @@
1
1
  import { L2Block, MerkleTreeId, SiblingPath } from '@aztec/circuit-types';
2
- import { Header, NullifierLeafPreimage, StateReference } from '@aztec/circuits.js';
2
+ import { Fr, Header, NullifierLeafPreimage, StateReference } from '@aztec/circuits.js';
3
3
  import { createDebugLogger } from '@aztec/foundation/log';
4
4
  import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
5
- import { BatchInsertionResult } from '@aztec/merkle-tree';
5
+ import { AppendOnlyTree, BatchInsertionResult, IndexedTree } from '@aztec/merkle-tree';
6
6
 
7
7
  /**
8
8
  * Type alias for the nullifier tree ID.
@@ -32,6 +32,24 @@ export interface TreeInfo {
32
32
  depth: number;
33
33
  }
34
34
 
35
+ export type MerkleTreeMap = {
36
+ [MerkleTreeId.NULLIFIER_TREE]: IndexedTree;
37
+ [MerkleTreeId.NOTE_HASH_TREE]: AppendOnlyTree<Fr>;
38
+ [MerkleTreeId.PUBLIC_DATA_TREE]: IndexedTree;
39
+ [MerkleTreeId.L1_TO_L2_MESSAGE_TREE]: AppendOnlyTree<Fr>;
40
+ [MerkleTreeId.ARCHIVE]: AppendOnlyTree<Fr>;
41
+ };
42
+
43
+ type LeafTypes = {
44
+ [MerkleTreeId.NULLIFIER_TREE]: Buffer;
45
+ [MerkleTreeId.NOTE_HASH_TREE]: Fr;
46
+ [MerkleTreeId.PUBLIC_DATA_TREE]: Buffer;
47
+ [MerkleTreeId.L1_TO_L2_MESSAGE_TREE]: Fr;
48
+ [MerkleTreeId.ARCHIVE]: Fr;
49
+ };
50
+
51
+ export type MerkleTreeLeafType<ID extends MerkleTreeId> = LeafTypes[ID];
52
+
35
53
  /**
36
54
  * Defines the interface for operations on a set of Merkle Trees.
37
55
  */
@@ -41,7 +59,7 @@ export interface MerkleTreeOperations {
41
59
  * @param treeId - The tree to be updated.
42
60
  * @param leaves - The set of leaves to be appended.
43
61
  */
44
- appendLeaves(treeId: MerkleTreeId, leaves: Buffer[]): Promise<void>;
62
+ appendLeaves<ID extends MerkleTreeId>(treeId: ID, leaves: MerkleTreeLeafType<ID>[]): Promise<void>;
45
63
 
46
64
  /**
47
65
  * Returns information about the given tree.
@@ -71,8 +89,8 @@ export interface MerkleTreeOperations {
71
89
  * @param treeId - The tree for which the previous value index is required.
72
90
  * @param value - The value to be queried.
73
91
  */
74
- getPreviousValueIndex(
75
- treeId: IndexedTreeId,
92
+ getPreviousValueIndex<ID extends IndexedTreeId>(
93
+ treeId: ID,
76
94
  value: bigint,
77
95
  ): Promise<
78
96
  | {
@@ -93,7 +111,7 @@ export interface MerkleTreeOperations {
93
111
  * @param treeId - The tree for which leaf data should be returned.
94
112
  * @param index - The index of the leaf required.
95
113
  */
96
- getLeafPreimage(treeId: IndexedTreeId, index: bigint): Promise<IndexedTreeLeafPreimage | undefined>;
114
+ getLeafPreimage<ID extends IndexedTreeId>(treeId: ID, index: bigint): Promise<IndexedTreeLeafPreimage | undefined>;
97
115
 
98
116
  /**
99
117
  * Update the leaf data at the given index.
@@ -101,21 +119,36 @@ export interface MerkleTreeOperations {
101
119
  * @param leaf - The updated leaf value.
102
120
  * @param index - The index of the leaf to be updated.
103
121
  */
104
- updateLeaf(treeId: IndexedTreeId, leaf: NullifierLeafPreimage | Buffer, index: bigint): Promise<void>;
122
+ updateLeaf<ID extends IndexedTreeId>(treeId: ID, leaf: NullifierLeafPreimage | Buffer, index: bigint): Promise<void>;
105
123
 
106
124
  /**
107
125
  * Returns the index containing a leaf value.
108
126
  * @param treeId - The tree for which the index should be returned.
109
127
  * @param value - The value to search for in the tree.
110
128
  */
111
- findLeafIndex(treeId: MerkleTreeId, value: Buffer): Promise<bigint | undefined>;
129
+ findLeafIndex<ID extends MerkleTreeId>(treeId: ID, value: MerkleTreeLeafType<ID>): Promise<bigint | undefined>;
130
+
131
+ /**
132
+ * Returns the first index containing a leaf value after `startIndex`.
133
+ * @param treeId - The tree for which the index should be returned.
134
+ * @param value - The value to search for in the tree.
135
+ * @param startIndex - The index to start searching from (used when skipping nullified messages)
136
+ */
137
+ findLeafIndexAfter<ID extends MerkleTreeId>(
138
+ treeId: ID,
139
+ value: MerkleTreeLeafType<ID>,
140
+ startIndex: bigint,
141
+ ): Promise<bigint | undefined>;
112
142
 
113
143
  /**
114
144
  * Gets the value for a leaf in the tree.
115
145
  * @param treeId - The tree for which the index should be returned.
116
146
  * @param index - The index of the leaf.
117
147
  */
118
- getLeafValue(treeId: MerkleTreeId, index: bigint): Promise<Buffer | undefined>;
148
+ getLeafValue<ID extends MerkleTreeId>(
149
+ treeId: ID,
150
+ index: bigint,
151
+ ): Promise<MerkleTreeLeafType<typeof treeId> | undefined>;
119
152
 
120
153
  /**
121
154
  * Inserts the block hash into the archive.
@@ -131,8 +164,8 @@ export interface MerkleTreeOperations {
131
164
  * @param subtreeHeight - Height of the subtree.
132
165
  * @returns The witness data for the leaves to be updated when inserting the new ones.
133
166
  */
134
- batchInsert<TreeHeight extends number, SubtreeSiblingPathHeight extends number>(
135
- treeId: MerkleTreeId,
167
+ batchInsert<TreeHeight extends number, SubtreeSiblingPathHeight extends number, ID extends IndexedTreeId>(
168
+ treeId: ID,
136
169
  leaves: Buffer[],
137
170
  subtreeHeight: number,
138
171
  ): Promise<BatchInsertionResult<TreeHeight, SubtreeSiblingPathHeight>>;
@@ -140,8 +173,9 @@ export interface MerkleTreeOperations {
140
173
  /**
141
174
  * Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree).
142
175
  * @param block - The L2 block to handle.
176
+ * @param l1ToL2Messages - The L1 to L2 messages for the block.
143
177
  */
144
- handleL2Block(block: L2Block): Promise<HandleL2BlockResult>;
178
+ handleL2BlockAndMessages(block: L2Block, l1ToL2Messages: Fr[]): Promise<HandleL2BlockAndMessagesResult>;
145
179
 
146
180
  /**
147
181
  * Commits pending changes to the underlying store.
@@ -154,8 +188,8 @@ export interface MerkleTreeOperations {
154
188
  rollback(): Promise<void>;
155
189
  }
156
190
 
157
- /** Return type for handleL2Block */
158
- export type HandleL2BlockResult = {
191
+ /** Return type for handleL2BlockAndMessages */
192
+ export type HandleL2BlockAndMessagesResult = {
159
193
  /** Whether the block processed was emitted by our sequencer */ isBlockOurs: boolean;
160
194
  };
161
195
 
@@ -1,10 +1,16 @@
1
1
  import { L2Block, MerkleTreeId, SiblingPath } from '@aztec/circuit-types';
2
- import { Header, NullifierLeafPreimage, StateReference } from '@aztec/circuits.js';
2
+ import { Fr, Header, NullifierLeafPreimage, StateReference } from '@aztec/circuits.js';
3
3
  import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
4
4
  import { BatchInsertionResult } from '@aztec/merkle-tree';
5
5
 
6
6
  import { MerkleTreeDb } from './merkle_tree_db.js';
7
- import { HandleL2BlockResult, MerkleTreeOperations, TreeInfo } from './merkle_tree_operations.js';
7
+ import {
8
+ HandleL2BlockAndMessagesResult,
9
+ IndexedTreeId,
10
+ MerkleTreeLeafType,
11
+ MerkleTreeOperations,
12
+ TreeInfo,
13
+ } from './merkle_tree_operations.js';
8
14
 
9
15
  /**
10
16
  * Wraps a MerkleTreeDbOperations to call all functions with a preset includeUncommitted flag.
@@ -44,7 +50,7 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations {
44
50
  * @param leaves - The set of leaves to be appended.
45
51
  * @returns The tree info of the specified tree.
46
52
  */
47
- appendLeaves(treeId: MerkleTreeId, leaves: Buffer[]): Promise<void> {
53
+ appendLeaves<ID extends MerkleTreeId>(treeId: ID, leaves: MerkleTreeLeafType<ID>[]): Promise<void> {
48
54
  return this.trees.appendLeaves(treeId, leaves);
49
55
  }
50
56
 
@@ -66,8 +72,8 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations {
66
72
  * @param includeUncommitted - If true, the uncommitted changes are included in the search.
67
73
  * @returns The found leaf index and a flag indicating if the corresponding leaf's value is equal to `newValue`.
68
74
  */
69
- getPreviousValueIndex(
70
- treeId: MerkleTreeId.NULLIFIER_TREE,
75
+ getPreviousValueIndex<ID extends IndexedTreeId>(
76
+ treeId: ID,
71
77
  value: bigint,
72
78
  ): Promise<
73
79
  | {
@@ -92,7 +98,7 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations {
92
98
  * @param index - The index to insert into.
93
99
  * @returns Empty promise.
94
100
  */
95
- updateLeaf(treeId: MerkleTreeId.NULLIFIER_TREE, leaf: NullifierLeafPreimage, index: bigint): Promise<void> {
101
+ updateLeaf<ID extends IndexedTreeId>(treeId: ID, leaf: NullifierLeafPreimage, index: bigint): Promise<void> {
96
102
  return this.trees.updateLeaf(treeId, leaf, index);
97
103
  }
98
104
 
@@ -102,8 +108,8 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations {
102
108
  * @param index - The index of the leaf to get.
103
109
  * @returns Leaf preimage.
104
110
  */
105
- async getLeafPreimage(
106
- treeId: MerkleTreeId.NULLIFIER_TREE,
111
+ async getLeafPreimage<ID extends IndexedTreeId>(
112
+ treeId: ID,
107
113
  index: bigint,
108
114
  ): Promise<IndexedTreeLeafPreimage | undefined> {
109
115
  const preimage = await this.trees.getLeafPreimage(treeId, index, this.includeUncommitted);
@@ -116,10 +122,24 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations {
116
122
  * @param value - The leaf value to look for.
117
123
  * @returns The index of the first leaf found with a given value (undefined if not found).
118
124
  */
119
- findLeafIndex(treeId: MerkleTreeId, value: Buffer): Promise<bigint | undefined> {
125
+ findLeafIndex<ID extends MerkleTreeId>(treeId: ID, value: MerkleTreeLeafType<ID>): Promise<bigint | undefined> {
120
126
  return this.trees.findLeafIndex(treeId, value, this.includeUncommitted);
121
127
  }
122
128
 
129
+ /**
130
+ * Returns the first index containing a leaf value after `startIndex`.
131
+ * @param treeId - The tree for which the index should be returned.
132
+ * @param value - The value to search for in the tree.
133
+ * @param startIndex - The index to start searching from (used when skipping nullified messages)
134
+ */
135
+ findLeafIndexAfter<ID extends MerkleTreeId>(
136
+ treeId: ID,
137
+ value: MerkleTreeLeafType<ID>,
138
+ startIndex: bigint,
139
+ ): Promise<bigint | undefined> {
140
+ return this.trees.findLeafIndexAfter(treeId, value, startIndex, this.includeUncommitted);
141
+ }
142
+
123
143
  /**
124
144
  * Gets the value at the given index.
125
145
  * @param treeId - The ID of the tree to get the leaf value from.
@@ -127,8 +147,13 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations {
127
147
  * @param includeUncommitted - Indicates whether to include uncommitted changes.
128
148
  * @returns Leaf value at the given index (undefined if not found).
129
149
  */
130
- getLeafValue(treeId: MerkleTreeId, index: bigint): Promise<Buffer | undefined> {
131
- return this.trees.getLeafValue(treeId, index, this.includeUncommitted);
150
+ getLeafValue<ID extends MerkleTreeId>(
151
+ treeId: ID,
152
+ index: bigint,
153
+ ): Promise<MerkleTreeLeafType<typeof treeId> | undefined> {
154
+ return this.trees.getLeafValue(treeId, index, this.includeUncommitted) as Promise<
155
+ MerkleTreeLeafType<typeof treeId> | undefined
156
+ >;
132
157
  }
133
158
 
134
159
  /**
@@ -143,10 +168,11 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations {
143
168
  /**
144
169
  * Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree).
145
170
  * @param block - The L2 block to handle.
171
+ * @param l1ToL2Messages - The L1 to L2 messages for the block.
146
172
  * @returns Whether the block handled was produced by this same node.
147
173
  */
148
- public handleL2Block(block: L2Block): Promise<HandleL2BlockResult> {
149
- return this.trees.handleL2Block(block);
174
+ public handleL2BlockAndMessages(block: L2Block, l1ToL2Messages: Fr[]): Promise<HandleL2BlockAndMessagesResult> {
175
+ return this.trees.handleL2BlockAndMessages(block, l1ToL2Messages);
150
176
  }
151
177
 
152
178
  /**
@@ -173,7 +199,7 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations {
173
199
  * @returns The data for the leaves to be updated when inserting the new ones.
174
200
  */
175
201
  public batchInsert<TreeHeight extends number, SubtreeSiblingPathHeight extends number>(
176
- treeId: MerkleTreeId,
202
+ treeId: IndexedTreeId,
177
203
  leaves: Buffer[],
178
204
  subtreeHeight: number,
179
205
  ): Promise<BatchInsertionResult<TreeHeight, SubtreeSiblingPathHeight>> {
@@ -1,10 +1,16 @@
1
1
  import { MerkleTreeId, SiblingPath } from '@aztec/circuit-types';
2
2
  import { AppendOnlyTreeSnapshot, Fr, Header, PartialStateReference, StateReference } from '@aztec/circuits.js';
3
3
  import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
4
- import { BatchInsertionResult, IndexedTreeSnapshot, TreeSnapshot } from '@aztec/merkle-tree';
4
+ import { BatchInsertionResult, IndexedTreeSnapshot } from '@aztec/merkle-tree';
5
5
 
6
- import { MerkleTreeDb } from './merkle_tree_db.js';
7
- import { HandleL2BlockResult, MerkleTreeOperations, TreeInfo } from './merkle_tree_operations.js';
6
+ import { MerkleTreeDb, TreeSnapshots } from './merkle_tree_db.js';
7
+ import {
8
+ HandleL2BlockAndMessagesResult,
9
+ IndexedTreeId,
10
+ MerkleTreeLeafType,
11
+ MerkleTreeOperations,
12
+ TreeInfo,
13
+ } from './merkle_tree_operations.js';
8
14
 
9
15
  /**
10
16
  * Merkle tree operations on readonly tree snapshots.
@@ -12,42 +18,56 @@ import { HandleL2BlockResult, MerkleTreeOperations, TreeInfo } from './merkle_tr
12
18
  export class MerkleTreeSnapshotOperationsFacade implements MerkleTreeOperations {
13
19
  #treesDb: MerkleTreeDb;
14
20
  #blockNumber: number;
15
- #treeSnapshots: ReadonlyArray<TreeSnapshot | IndexedTreeSnapshot> = [];
21
+ #treeSnapshots: TreeSnapshots = {} as any;
16
22
 
17
23
  constructor(trees: MerkleTreeDb, blockNumber: number) {
18
24
  this.#treesDb = trees;
19
25
  this.#blockNumber = blockNumber;
20
26
  }
21
27
 
22
- async #getTreeSnapshot(merkleTreeId: number): Promise<TreeSnapshot | IndexedTreeSnapshot> {
23
- if (this.#treeSnapshots[merkleTreeId]) {
24
- return this.#treeSnapshots[merkleTreeId];
28
+ async #getTreeSnapshot(treeId: MerkleTreeId): Promise<TreeSnapshots[typeof treeId]> {
29
+ if (this.#treeSnapshots[treeId]) {
30
+ return this.#treeSnapshots[treeId];
25
31
  }
26
32
 
27
33
  this.#treeSnapshots = await this.#treesDb.getSnapshot(this.#blockNumber);
28
- return this.#treeSnapshots[merkleTreeId]!;
34
+ return this.#treeSnapshots[treeId]!;
29
35
  }
30
36
 
31
- async findLeafIndex(treeId: MerkleTreeId, value: Buffer): Promise<bigint | undefined> {
37
+ async findLeafIndex<ID extends MerkleTreeId>(treeId: ID, value: MerkleTreeLeafType<ID>): Promise<bigint | undefined> {
32
38
  const tree = await this.#getTreeSnapshot(treeId);
33
- return tree.findLeafIndex(value);
39
+ // TODO #5448 fix "as any"
40
+ return tree.findLeafIndex(value as any);
34
41
  }
35
42
 
36
- async getLeafPreimage(
37
- treeId: MerkleTreeId.NULLIFIER_TREE,
43
+ async findLeafIndexAfter<ID extends MerkleTreeId>(
44
+ treeId: MerkleTreeId,
45
+ value: MerkleTreeLeafType<ID>,
46
+ startIndex: bigint,
47
+ ): Promise<bigint | undefined> {
48
+ const tree = await this.#getTreeSnapshot(treeId);
49
+ // TODO #5448 fix "as any"
50
+ return tree.findLeafIndexAfter(value as any, startIndex);
51
+ }
52
+
53
+ async getLeafPreimage<ID extends IndexedTreeId>(
54
+ treeId: ID,
38
55
  index: bigint,
39
56
  ): Promise<IndexedTreeLeafPreimage | undefined> {
40
57
  const snapshot = (await this.#getTreeSnapshot(treeId)) as IndexedTreeSnapshot;
41
58
  return snapshot.getLatestLeafPreimageCopy(BigInt(index));
42
59
  }
43
60
 
44
- async getLeafValue(treeId: MerkleTreeId, index: bigint): Promise<Buffer | undefined> {
61
+ async getLeafValue<ID extends MerkleTreeId>(
62
+ treeId: ID,
63
+ index: bigint,
64
+ ): Promise<MerkleTreeLeafType<typeof treeId> | undefined> {
45
65
  const snapshot = await this.#getTreeSnapshot(treeId);
46
- return snapshot.getLeafValue(BigInt(index));
66
+ return snapshot.getLeafValue(BigInt(index)) as MerkleTreeLeafType<typeof treeId> | undefined;
47
67
  }
48
68
 
49
69
  async getPreviousValueIndex(
50
- treeId: MerkleTreeId.NULLIFIER_TREE,
70
+ treeId: IndexedTreeId,
51
71
  value: bigint,
52
72
  ): Promise<
53
73
  | {
@@ -130,7 +150,7 @@ export class MerkleTreeSnapshotOperationsFacade implements MerkleTreeOperations
130
150
  return Promise.reject(new Error('Tree snapshot operations are read-only'));
131
151
  }
132
152
 
133
- handleL2Block(): Promise<HandleL2BlockResult> {
153
+ handleL2BlockAndMessages(): Promise<HandleL2BlockAndMessagesResult> {
134
154
  return Promise.reject(new Error('Tree snapshot operations are read-only'));
135
155
  }
136
156
 
@@ -11,6 +11,7 @@ import {
11
11
  NOTE_HASH_TREE_HEIGHT,
12
12
  NULLIFIER_SUBTREE_HEIGHT,
13
13
  NULLIFIER_TREE_HEIGHT,
14
+ NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
14
15
  NullifierLeaf,
15
16
  NullifierLeafPreimage,
16
17
  PUBLIC_DATA_SUBTREE_HEIGHT,
@@ -20,6 +21,7 @@ import {
20
21
  PublicDataTreeLeafPreimage,
21
22
  StateReference,
22
23
  } from '@aztec/circuits.js';
24
+ import { padArrayEnd } from '@aztec/foundation/collection';
23
25
  import { SerialQueue } from '@aztec/foundation/fifo';
24
26
  import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';
25
27
  import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
@@ -38,15 +40,35 @@ import {
38
40
  } from '@aztec/merkle-tree';
39
41
  import { Hasher } from '@aztec/types/interfaces';
40
42
 
41
- import { INITIAL_NULLIFIER_TREE_SIZE, INITIAL_PUBLIC_DATA_TREE_SIZE, MerkleTreeDb } from './merkle_tree_db.js';
42
- import { HandleL2BlockResult, IndexedTreeId, MerkleTreeOperations, TreeInfo } from './merkle_tree_operations.js';
43
+ import {
44
+ INITIAL_NULLIFIER_TREE_SIZE,
45
+ INITIAL_PUBLIC_DATA_TREE_SIZE,
46
+ MerkleTreeDb,
47
+ TreeSnapshots,
48
+ } from './merkle_tree_db.js';
49
+ import {
50
+ HandleL2BlockAndMessagesResult,
51
+ IndexedTreeId,
52
+ MerkleTreeLeafType,
53
+ MerkleTreeMap,
54
+ MerkleTreeOperations,
55
+ TreeInfo,
56
+ } from './merkle_tree_operations.js';
43
57
  import { MerkleTreeOperationsFacade } from './merkle_tree_operations_facade.js';
44
58
 
45
59
  /**
46
60
  * The nullifier tree is an indexed tree.
47
61
  */
48
62
  class NullifierTree extends StandardIndexedTree {
49
- constructor(store: AztecKVStore, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) {
63
+ constructor(
64
+ store: AztecKVStore,
65
+ hasher: Hasher,
66
+ name: string,
67
+ depth: number,
68
+ size: bigint = 0n,
69
+ _noop: any,
70
+ root?: Buffer,
71
+ ) {
50
72
  super(store, hasher, name, depth, size, NullifierLeafPreimage, NullifierLeaf, root);
51
73
  }
52
74
  }
@@ -55,7 +77,15 @@ class NullifierTree extends StandardIndexedTree {
55
77
  * The public data tree is an indexed tree.
56
78
  */
57
79
  class PublicDataTree extends StandardIndexedTree {
58
- constructor(store: AztecKVStore, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) {
80
+ constructor(
81
+ store: AztecKVStore,
82
+ hasher: Hasher,
83
+ name: string,
84
+ depth: number,
85
+ size: bigint = 0n,
86
+ _noop: any,
87
+ root?: Buffer,
88
+ ) {
59
89
  super(store, hasher, name, depth, size, PublicDataTreeLeafPreimage, PublicDataTreeLeaf, root);
60
90
  }
61
91
  }
@@ -64,7 +94,8 @@ class PublicDataTree extends StandardIndexedTree {
64
94
  * A convenience class for managing multiple merkle trees.
65
95
  */
66
96
  export class MerkleTrees implements MerkleTreeDb {
67
- private trees: (AppendOnlyTree | UpdateOnlyTree)[] = [];
97
+ // gets initialized in #init
98
+ private trees: MerkleTreeMap = null as any;
68
99
  private jobQueue = new SerialQueue();
69
100
 
70
101
  private constructor(private store: AztecKVStore, private log: DebugLogger) {}
@@ -94,14 +125,16 @@ export class MerkleTrees implements MerkleTreeDb {
94
125
  this.store,
95
126
  hasher,
96
127
  `${MerkleTreeId[MerkleTreeId.NULLIFIER_TREE]}`,
128
+ {},
97
129
  NULLIFIER_TREE_HEIGHT,
98
130
  INITIAL_NULLIFIER_TREE_SIZE,
99
131
  );
100
- const noteHashTree: AppendOnlyTree = await initializeTree(
132
+ const noteHashTree: AppendOnlyTree<Fr> = await initializeTree(
101
133
  StandardTree,
102
134
  this.store,
103
135
  hasher,
104
136
  `${MerkleTreeId[MerkleTreeId.NOTE_HASH_TREE]}`,
137
+ Fr,
105
138
  NOTE_HASH_TREE_HEIGHT,
106
139
  );
107
140
  const publicDataTree = await initializeTree(
@@ -109,21 +142,24 @@ export class MerkleTrees implements MerkleTreeDb {
109
142
  this.store,
110
143
  hasher,
111
144
  `${MerkleTreeId[MerkleTreeId.PUBLIC_DATA_TREE]}`,
145
+ {},
112
146
  PUBLIC_DATA_TREE_HEIGHT,
113
147
  INITIAL_PUBLIC_DATA_TREE_SIZE,
114
148
  );
115
- const l1Tol2MessageTree: AppendOnlyTree = await initializeTree(
149
+ const l1Tol2MessageTree: AppendOnlyTree<Fr> = await initializeTree(
116
150
  StandardTree,
117
151
  this.store,
118
152
  hasher,
119
153
  `${MerkleTreeId[MerkleTreeId.L1_TO_L2_MESSAGE_TREE]}`,
154
+ Fr,
120
155
  L1_TO_L2_MSG_TREE_HEIGHT,
121
156
  );
122
- const archive: AppendOnlyTree = await initializeTree(
157
+ const archive: AppendOnlyTree<Fr> = await initializeTree(
123
158
  StandardTree,
124
159
  this.store,
125
160
  hasher,
126
161
  `${MerkleTreeId[MerkleTreeId.ARCHIVE]}`,
162
+ Fr,
127
163
  ARCHIVE_HEIGHT,
128
164
  );
129
165
  this.trees = [nullifierTree, noteHashTree, publicDataTree, l1Tol2MessageTree, archive];
@@ -223,7 +259,7 @@ export class MerkleTrees implements MerkleTreeDb {
223
259
  treeId: MerkleTreeId,
224
260
  index: bigint,
225
261
  includeUncommitted: boolean,
226
- ): Promise<Buffer | undefined> {
262
+ ): Promise<MerkleTreeLeafType<typeof treeId> | undefined> {
227
263
  return await this.synchronize(() => Promise.resolve(this.trees[treeId].getLeafValue(index, includeUncommitted)));
228
264
  }
229
265
 
@@ -248,7 +284,7 @@ export class MerkleTrees implements MerkleTreeDb {
248
284
  * @param leaves - The leaves to append.
249
285
  * @returns Empty promise.
250
286
  */
251
- public async appendLeaves(treeId: MerkleTreeId, leaves: Buffer[]): Promise<void> {
287
+ public async appendLeaves<ID extends MerkleTreeId>(treeId: ID, leaves: MerkleTreeLeafType<ID>[]): Promise<void> {
252
288
  return await this.synchronize(() => this.#appendLeaves(treeId, leaves));
253
289
  }
254
290
 
@@ -321,14 +357,35 @@ export class MerkleTrees implements MerkleTreeDb {
321
357
  * @param includeUncommitted - Indicates whether to include uncommitted data.
322
358
  * @returns The index of the first leaf found with a given value (undefined if not found).
323
359
  */
324
- public async findLeafIndex(
325
- treeId: MerkleTreeId,
326
- value: Buffer,
360
+ public async findLeafIndex<ID extends MerkleTreeId>(
361
+ treeId: ID,
362
+ value: MerkleTreeLeafType<ID>,
363
+ includeUncommitted: boolean,
364
+ ): Promise<bigint | undefined> {
365
+ return await this.synchronize(() => {
366
+ const tree = this.trees[treeId];
367
+ // TODO #5448 fix "as any"
368
+ return Promise.resolve(tree.findLeafIndex(value as any, includeUncommitted));
369
+ });
370
+ }
371
+
372
+ /**
373
+ * Returns the first index containing a leaf value after `startIndex`.
374
+ * @param treeId - The tree for which the index should be returned.
375
+ * @param value - The value to search for in the tree.
376
+ * @param startIndex - The index to start searching from (used when skipping nullified messages)
377
+ * @param includeUncommitted - Indicates whether to include uncommitted data.
378
+ */
379
+ public async findLeafIndexAfter<ID extends MerkleTreeId>(
380
+ treeId: ID,
381
+ value: MerkleTreeLeafType<ID>,
382
+ startIndex: bigint,
327
383
  includeUncommitted: boolean,
328
384
  ): Promise<bigint | undefined> {
329
385
  return await this.synchronize(() => {
330
386
  const tree = this.trees[treeId];
331
- return Promise.resolve(tree.findLeafIndex(value, includeUncommitted));
387
+ // TODO #5448 fix "as any"
388
+ return Promise.resolve(tree.findLeafIndexAfter(value as any, startIndex, includeUncommitted));
332
389
  });
333
390
  }
334
391
 
@@ -346,10 +403,11 @@ export class MerkleTrees implements MerkleTreeDb {
346
403
  /**
347
404
  * Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree).
348
405
  * @param block - The L2 block to handle.
406
+ * @param l1ToL2Messages - The L1 to L2 messages for the block.
349
407
  * @returns Whether the block handled was produced by this same node.
350
408
  */
351
- public async handleL2Block(block: L2Block): Promise<HandleL2BlockResult> {
352
- return await this.synchronize(() => this.#handleL2Block(block));
409
+ public async handleL2BlockAndMessages(block: L2Block, l1ToL2Messages: Fr[]): Promise<HandleL2BlockAndMessagesResult> {
410
+ return await this.synchronize(() => this.#handleL2BlockAndMessages(block, l1ToL2Messages));
353
411
  }
354
412
 
355
413
  /**
@@ -364,7 +422,7 @@ export class MerkleTrees implements MerkleTreeDb {
364
422
  SubtreeHeight extends number,
365
423
  SubtreeSiblingPathHeight extends number,
366
424
  >(
367
- treeId: MerkleTreeId,
425
+ treeId: IndexedTreeId,
368
426
  leaves: Buffer[],
369
427
  subtreeHeight: SubtreeHeight,
370
428
  ): Promise<BatchInsertionResult<TreeHeight, SubtreeSiblingPathHeight>> {
@@ -394,7 +452,7 @@ export class MerkleTrees implements MerkleTreeDb {
394
452
  }
395
453
 
396
454
  const blockHash = header.hash();
397
- await this.#appendLeaves(MerkleTreeId.ARCHIVE, [blockHash.toBuffer()]);
455
+ await this.#appendLeaves(MerkleTreeId.ARCHIVE, [blockHash]);
398
456
  }
399
457
 
400
458
  /**
@@ -428,20 +486,21 @@ export class MerkleTrees implements MerkleTreeDb {
428
486
  * @param leaves - Leaves to append.
429
487
  * @returns Empty promise.
430
488
  */
431
- async #appendLeaves(treeId: MerkleTreeId, leaves: Buffer[]): Promise<void> {
489
+ async #appendLeaves<ID extends MerkleTreeId>(treeId: ID, leaves: MerkleTreeLeafType<typeof treeId>[]): Promise<void> {
432
490
  const tree = this.trees[treeId];
433
491
  if (!('appendLeaves' in tree)) {
434
492
  throw new Error('Tree does not support `appendLeaves` method');
435
493
  }
436
- return await tree.appendLeaves(leaves);
494
+ // TODO #5448 fix "as any"
495
+ return await tree.appendLeaves(leaves as any[]);
437
496
  }
438
497
 
439
- async #updateLeaf(treeId: IndexedTreeId, leaf: Buffer, index: bigint): Promise<void> {
498
+ async #updateLeaf(treeId: IndexedTreeId, leaf: MerkleTreeLeafType<typeof treeId>, index: bigint): Promise<void> {
440
499
  const tree = this.trees[treeId];
441
500
  if (!('updateLeaf' in tree)) {
442
501
  throw new Error('Tree does not support `updateLeaf` method');
443
502
  }
444
- return await tree.updateLeaf(leaf, index);
503
+ return await (tree as UpdateOnlyTree<typeof leaf>).updateLeaf(leaf, index);
445
504
  }
446
505
 
447
506
  /**
@@ -449,7 +508,7 @@ export class MerkleTrees implements MerkleTreeDb {
449
508
  * @returns Empty promise.
450
509
  */
451
510
  async #commit(): Promise<void> {
452
- for (const tree of this.trees) {
511
+ for (const tree of Object.values(this.trees)) {
453
512
  await tree.commit();
454
513
  }
455
514
  }
@@ -459,17 +518,31 @@ export class MerkleTrees implements MerkleTreeDb {
459
518
  * @returns Empty promise.
460
519
  */
461
520
  async #rollback(): Promise<void> {
462
- for (const tree of this.trees) {
521
+ for (const tree of Object.values(this.trees)) {
463
522
  await tree.rollback();
464
523
  }
465
524
  }
466
525
 
467
- public getSnapshot(blockNumber: number) {
468
- return Promise.all(this.trees.map(tree => tree.getSnapshot(blockNumber)));
526
+ public async getSnapshot(blockNumber: number): Promise<TreeSnapshots> {
527
+ const snapshots = await Promise.all([
528
+ this.trees[MerkleTreeId.NULLIFIER_TREE].getSnapshot(blockNumber),
529
+ this.trees[MerkleTreeId.NOTE_HASH_TREE].getSnapshot(blockNumber),
530
+ this.trees[MerkleTreeId.PUBLIC_DATA_TREE].getSnapshot(blockNumber),
531
+ this.trees[MerkleTreeId.L1_TO_L2_MESSAGE_TREE].getSnapshot(blockNumber),
532
+ this.trees[MerkleTreeId.ARCHIVE].getSnapshot(blockNumber),
533
+ ]);
534
+
535
+ return {
536
+ [MerkleTreeId.NULLIFIER_TREE]: snapshots[0],
537
+ [MerkleTreeId.NOTE_HASH_TREE]: snapshots[1],
538
+ [MerkleTreeId.PUBLIC_DATA_TREE]: snapshots[2],
539
+ [MerkleTreeId.L1_TO_L2_MESSAGE_TREE]: snapshots[3],
540
+ [MerkleTreeId.ARCHIVE]: snapshots[4],
541
+ };
469
542
  }
470
543
 
471
544
  async #snapshot(blockNumber: number): Promise<void> {
472
- for (const tree of this.trees) {
545
+ for (const tree of Object.values(this.trees)) {
473
546
  await tree.snapshot(blockNumber);
474
547
  }
475
548
  }
@@ -477,8 +550,9 @@ export class MerkleTrees implements MerkleTreeDb {
477
550
  /**
478
551
  * Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree).
479
552
  * @param l2Block - The L2 block to handle.
553
+ * @param l1ToL2Messages - The L1 to L2 messages for the block.
480
554
  */
481
- async #handleL2Block(l2Block: L2Block): Promise<HandleL2BlockResult> {
555
+ async #handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<HandleL2BlockAndMessagesResult> {
482
556
  const treeRootWithIdPairs = [
483
557
  [l2Block.header.state.partial.nullifierTree.root, MerkleTreeId.NULLIFIER_TREE],
484
558
  [l2Block.header.state.partial.noteHashTree.root, MerkleTreeId.NOTE_HASH_TREE],
@@ -498,15 +572,16 @@ export class MerkleTrees implements MerkleTreeDb {
498
572
  this.log(`Block ${l2Block.number} is not ours, rolling back world state and committing state from chain`);
499
573
  await this.#rollback();
500
574
 
575
+ // We pad the messages because always a fixed number of messages is inserted and we need
576
+ // the `nextAvailableLeafIndex` to correctly progress.
577
+ const l1ToL2MessagesPadded = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
578
+
501
579
  // Sync the append only trees
502
580
  for (const [tree, leaves] of [
503
581
  [MerkleTreeId.NOTE_HASH_TREE, l2Block.body.txEffects.flatMap(txEffect => txEffect.noteHashes)],
504
- [MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l2Block.body.l1ToL2Messages],
582
+ [MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded],
505
583
  ] as const) {
506
- await this.#appendLeaves(
507
- tree,
508
- leaves.map(fr => fr.toBuffer()),
509
- );
584
+ await this.#appendLeaves(tree, leaves);
510
585
  }
511
586
 
512
587
  // Sync the indexed trees