@aztec/world-state 0.16.4 → 0.16.6
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.
- package/dest/merkle-tree/merkle_tree_operations_facade.d.ts +4 -5
- package/dest/merkle-tree/merkle_tree_operations_facade.d.ts.map +1 -1
- package/dest/merkle-tree/merkle_tree_operations_facade.js +6 -7
- package/dest/merkle-tree/merkle_tree_snapshot_operations_facade.d.ts +2 -2
- package/dest/merkle-tree/merkle_tree_snapshot_operations_facade.d.ts.map +1 -1
- package/dest/merkle-tree/merkle_tree_snapshot_operations_facade.js +5 -5
- package/dest/world-state-db/merkle_tree_db.d.ts +4 -4
- package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
- package/dest/world-state-db/merkle_trees.d.ts +2 -2
- package/dest/world-state-db/merkle_trees.d.ts.map +1 -1
- package/dest/world-state-db/merkle_trees.js +13 -13
- package/package.json +5 -5
- package/src/index.ts +0 -3
- package/src/merkle-tree/merkle_tree_operations_facade.ts +0 -190
- package/src/merkle-tree/merkle_tree_snapshot_operations_facade.ts +0 -143
- package/src/synchronizer/config.ts +0 -27
- package/src/synchronizer/index.ts +0 -2
- package/src/synchronizer/server_world_state_synchronizer.ts +0 -248
- package/src/synchronizer/world_state_synchronizer.ts +0 -73
- package/src/world-state-db/index.ts +0 -2
- package/src/world-state-db/merkle_tree_db.ts +0 -252
- package/src/world-state-db/merkle_trees.ts +0 -619
|
@@ -1,619 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BLOCKS_TREE_HEIGHT,
|
|
3
|
-
CONTRACT_TREE_HEIGHT,
|
|
4
|
-
Fr,
|
|
5
|
-
GlobalVariables,
|
|
6
|
-
L1_TO_L2_MSG_TREE_HEIGHT,
|
|
7
|
-
NOTE_HASH_TREE_HEIGHT,
|
|
8
|
-
NULLIFIER_SUBTREE_HEIGHT,
|
|
9
|
-
NULLIFIER_TREE_HEIGHT,
|
|
10
|
-
NullifierLeaf,
|
|
11
|
-
NullifierLeafPreimage,
|
|
12
|
-
PUBLIC_DATA_TREE_HEIGHT,
|
|
13
|
-
} from '@aztec/circuits.js';
|
|
14
|
-
import { computeBlockHash, computeGlobalsHash } from '@aztec/circuits.js/abis';
|
|
15
|
-
import { Committable } from '@aztec/foundation/committable';
|
|
16
|
-
import { SerialQueue } from '@aztec/foundation/fifo';
|
|
17
|
-
import { createDebugLogger } from '@aztec/foundation/log';
|
|
18
|
-
import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
|
|
19
|
-
import {
|
|
20
|
-
AppendOnlyTree,
|
|
21
|
-
BatchInsertionResult,
|
|
22
|
-
IndexedTree,
|
|
23
|
-
Pedersen,
|
|
24
|
-
SparseTree,
|
|
25
|
-
StandardIndexedTree,
|
|
26
|
-
StandardTree,
|
|
27
|
-
UpdateOnlyTree,
|
|
28
|
-
loadTree,
|
|
29
|
-
newTree,
|
|
30
|
-
} from '@aztec/merkle-tree';
|
|
31
|
-
import { Hasher, L2Block, MerkleTreeId, SiblingPath } from '@aztec/types';
|
|
32
|
-
|
|
33
|
-
import { default as levelup } from 'levelup';
|
|
34
|
-
|
|
35
|
-
import { MerkleTreeOperationsFacade } from '../merkle-tree/merkle_tree_operations_facade.js';
|
|
36
|
-
import {
|
|
37
|
-
CurrentTreeRoots,
|
|
38
|
-
HandleL2BlockResult,
|
|
39
|
-
INITIAL_NULLIFIER_TREE_SIZE,
|
|
40
|
-
IndexedTreeId,
|
|
41
|
-
MerkleTreeDb,
|
|
42
|
-
MerkleTreeOperations,
|
|
43
|
-
PublicTreeId,
|
|
44
|
-
TreeInfo,
|
|
45
|
-
} from './merkle_tree_db.js';
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Data necessary to reinitialize the merkle trees from Db.
|
|
49
|
-
*/
|
|
50
|
-
interface FromDbOptions {
|
|
51
|
-
/**
|
|
52
|
-
* The global variables hash from the last block.
|
|
53
|
-
*/
|
|
54
|
-
globalVariablesHash: Fr;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const LAST_GLOBAL_VARS_HASH = 'lastGlobalVarsHash';
|
|
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
|
-
|
|
68
|
-
/**
|
|
69
|
-
* A convenience class for managing multiple merkle trees.
|
|
70
|
-
*/
|
|
71
|
-
export class MerkleTrees implements MerkleTreeDb {
|
|
72
|
-
private trees: (AppendOnlyTree | UpdateOnlyTree)[] = [];
|
|
73
|
-
private latestGlobalVariablesHash: Committable<Fr>;
|
|
74
|
-
private jobQueue = new SerialQueue();
|
|
75
|
-
|
|
76
|
-
constructor(private db: levelup.LevelUp, private log = createDebugLogger('aztec:merkle_trees')) {
|
|
77
|
-
this.latestGlobalVariablesHash = new Committable(Fr.ZERO);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* initializes the collection of Merkle Trees.
|
|
82
|
-
* @param fromDbOptions - Options to initialize the trees from the database.
|
|
83
|
-
*/
|
|
84
|
-
public async init(fromDbOptions?: FromDbOptions) {
|
|
85
|
-
const fromDb = fromDbOptions !== undefined;
|
|
86
|
-
const initializeTree = fromDb ? loadTree : newTree;
|
|
87
|
-
|
|
88
|
-
const hasher = new Pedersen();
|
|
89
|
-
const contractTree: AppendOnlyTree = await initializeTree(
|
|
90
|
-
StandardTree,
|
|
91
|
-
this.db,
|
|
92
|
-
hasher,
|
|
93
|
-
`${MerkleTreeId[MerkleTreeId.CONTRACT_TREE]}`,
|
|
94
|
-
CONTRACT_TREE_HEIGHT,
|
|
95
|
-
);
|
|
96
|
-
const nullifierTree = await initializeTree(
|
|
97
|
-
NullifierTree,
|
|
98
|
-
this.db,
|
|
99
|
-
hasher,
|
|
100
|
-
`${MerkleTreeId[MerkleTreeId.NULLIFIER_TREE]}`,
|
|
101
|
-
NULLIFIER_TREE_HEIGHT,
|
|
102
|
-
INITIAL_NULLIFIER_TREE_SIZE,
|
|
103
|
-
);
|
|
104
|
-
const noteHashTree: AppendOnlyTree = await initializeTree(
|
|
105
|
-
StandardTree,
|
|
106
|
-
this.db,
|
|
107
|
-
hasher,
|
|
108
|
-
`${MerkleTreeId[MerkleTreeId.NOTE_HASH_TREE]}`,
|
|
109
|
-
NOTE_HASH_TREE_HEIGHT,
|
|
110
|
-
);
|
|
111
|
-
const publicDataTree: UpdateOnlyTree = await initializeTree(
|
|
112
|
-
SparseTree,
|
|
113
|
-
this.db,
|
|
114
|
-
hasher,
|
|
115
|
-
`${MerkleTreeId[MerkleTreeId.PUBLIC_DATA_TREE]}`,
|
|
116
|
-
PUBLIC_DATA_TREE_HEIGHT,
|
|
117
|
-
);
|
|
118
|
-
const l1Tol2MessagesTree: AppendOnlyTree = await initializeTree(
|
|
119
|
-
StandardTree,
|
|
120
|
-
this.db,
|
|
121
|
-
hasher,
|
|
122
|
-
`${MerkleTreeId[MerkleTreeId.L1_TO_L2_MESSAGES_TREE]}`,
|
|
123
|
-
L1_TO_L2_MSG_TREE_HEIGHT,
|
|
124
|
-
);
|
|
125
|
-
const blocksTree: AppendOnlyTree = await initializeTree(
|
|
126
|
-
StandardTree,
|
|
127
|
-
this.db,
|
|
128
|
-
hasher,
|
|
129
|
-
`${MerkleTreeId[MerkleTreeId.BLOCKS_TREE]}`,
|
|
130
|
-
BLOCKS_TREE_HEIGHT,
|
|
131
|
-
);
|
|
132
|
-
this.trees = [contractTree, nullifierTree, noteHashTree, publicDataTree, l1Tol2MessagesTree, blocksTree];
|
|
133
|
-
|
|
134
|
-
this.jobQueue.start();
|
|
135
|
-
|
|
136
|
-
// The first leaf in the blocks tree contains the empty roots of the other trees and empty global variables.
|
|
137
|
-
if (!fromDb) {
|
|
138
|
-
const initialGlobalVariablesHash = computeGlobalsHash(GlobalVariables.empty());
|
|
139
|
-
await this._updateLatestGlobalVariablesHash(initialGlobalVariablesHash);
|
|
140
|
-
await this._updateBlocksTree(initialGlobalVariablesHash, true);
|
|
141
|
-
await this._commit();
|
|
142
|
-
} else {
|
|
143
|
-
await this._updateLatestGlobalVariablesHash(fromDbOptions.globalVariablesHash);
|
|
144
|
-
// make the restored global variables hash and tree roots current
|
|
145
|
-
await this._commit();
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Method to asynchronously create and initialize a MerkleTrees instance.
|
|
151
|
-
* @param db - The db instance to use for data persistance.
|
|
152
|
-
* @returns - A fully initialized MerkleTrees instance.
|
|
153
|
-
*/
|
|
154
|
-
public static async new(db: levelup.LevelUp) {
|
|
155
|
-
const merkleTrees = new MerkleTrees(db);
|
|
156
|
-
const globalVariablesHash: Buffer | undefined = await db.get(LAST_GLOBAL_VARS_HASH).catch(() => undefined);
|
|
157
|
-
await merkleTrees.init(
|
|
158
|
-
globalVariablesHash ? { globalVariablesHash: Fr.fromBuffer(globalVariablesHash) } : undefined,
|
|
159
|
-
);
|
|
160
|
-
return merkleTrees;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Stops the job queue (waits for all jobs to finish).
|
|
165
|
-
*/
|
|
166
|
-
public async stop() {
|
|
167
|
-
await this.jobQueue.end();
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Gets a view of this db that returns uncommitted data.
|
|
172
|
-
* @returns - A facade for this instance.
|
|
173
|
-
*/
|
|
174
|
-
public asLatest(): MerkleTreeOperations {
|
|
175
|
-
return new MerkleTreeOperationsFacade(this, true);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Gets a view of this db that returns committed data only.
|
|
180
|
-
* @returns - A facade for this instance.
|
|
181
|
-
*/
|
|
182
|
-
public asCommitted(): MerkleTreeOperations {
|
|
183
|
-
return new MerkleTreeOperationsFacade(this, false);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Inserts into the roots trees (CONTRACT_TREE_ROOTS_TREE, NOTE_HASH_TREE_ROOTS_TREE, L1_TO_L2_MESSAGES_TREE_ROOTS_TREE)
|
|
188
|
-
* the current roots of the corresponding trees (CONTRACT_TREE, NOTE_HASH_TREE, L1_TO_L2_MESSAGES_TREE).
|
|
189
|
-
* @param globalsHash - The current global variables hash.
|
|
190
|
-
* @param includeUncommitted - Indicates whether to include uncommitted data.
|
|
191
|
-
*/
|
|
192
|
-
public async updateBlocksTree(globalsHash: Fr, includeUncommitted: boolean) {
|
|
193
|
-
await this.synchronize(() => this._updateBlocksTree(globalsHash, includeUncommitted));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Updates the latest global variables hash
|
|
198
|
-
* @param globalVariablesHash - The latest global variables hash
|
|
199
|
-
*/
|
|
200
|
-
public async updateLatestGlobalVariablesHash(globalVariablesHash: Fr) {
|
|
201
|
-
return await this.synchronize(() => this._updateLatestGlobalVariablesHash(globalVariablesHash));
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Gets the global variables hash from the previous block
|
|
206
|
-
* @param includeUncommitted - Indicates whether to include uncommitted data.
|
|
207
|
-
*/
|
|
208
|
-
public async getLatestGlobalVariablesHash(includeUncommitted: boolean): Promise<Fr> {
|
|
209
|
-
return await this.synchronize(() => this._getGlobalVariablesHash(includeUncommitted));
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Gets the tree info for the specified tree.
|
|
214
|
-
* @param treeId - Id of the tree to get information from.
|
|
215
|
-
* @param includeUncommitted - Indicates whether to include uncommitted data.
|
|
216
|
-
* @returns The tree info for the specified tree.
|
|
217
|
-
*/
|
|
218
|
-
public async getTreeInfo(treeId: MerkleTreeId, includeUncommitted: boolean): Promise<TreeInfo> {
|
|
219
|
-
return await this.synchronize(() => this._getTreeInfo(treeId, includeUncommitted));
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Get the current roots of the commitment trees.
|
|
224
|
-
* @param includeUncommitted - Indicates whether to include uncommitted data.
|
|
225
|
-
* @returns The current roots of the trees.
|
|
226
|
-
*/
|
|
227
|
-
public async getTreeRoots(includeUncommitted: boolean): Promise<CurrentTreeRoots> {
|
|
228
|
-
const roots = await this.synchronize(() => Promise.resolve(this._getAllTreeRoots(includeUncommitted)));
|
|
229
|
-
|
|
230
|
-
return {
|
|
231
|
-
noteHashTreeRoot: roots[0],
|
|
232
|
-
nullifierTreeRoot: roots[1],
|
|
233
|
-
contractDataTreeRoot: roots[2],
|
|
234
|
-
l1Tol2MessagesTreeRoot: roots[3],
|
|
235
|
-
publicDataTreeRoot: roots[4],
|
|
236
|
-
blocksTreeRoot: roots[5],
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
private async _getCurrentBlockHash(globalsHash: Fr, includeUncommitted: boolean): Promise<Fr> {
|
|
241
|
-
const roots = (await this._getAllTreeRoots(includeUncommitted)).map(root => Fr.fromBuffer(root));
|
|
242
|
-
return computeBlockHash(globalsHash, roots[0], roots[1], roots[2], roots[3], roots[4]);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
private _getAllTreeRoots(includeUncommitted: boolean): Promise<Buffer[]> {
|
|
246
|
-
const roots = [
|
|
247
|
-
MerkleTreeId.NOTE_HASH_TREE,
|
|
248
|
-
MerkleTreeId.NULLIFIER_TREE,
|
|
249
|
-
MerkleTreeId.CONTRACT_TREE,
|
|
250
|
-
MerkleTreeId.L1_TO_L2_MESSAGES_TREE,
|
|
251
|
-
MerkleTreeId.PUBLIC_DATA_TREE,
|
|
252
|
-
MerkleTreeId.BLOCKS_TREE,
|
|
253
|
-
].map(tree => this.trees[tree].getRoot(includeUncommitted));
|
|
254
|
-
|
|
255
|
-
return Promise.resolve(roots);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Gets the value at the given index.
|
|
260
|
-
* @param treeId - The ID of the tree to get the leaf value from.
|
|
261
|
-
* @param index - The index of the leaf.
|
|
262
|
-
* @param includeUncommitted - Indicates whether to include uncommitted changes.
|
|
263
|
-
* @returns Leaf value at the given index (undefined if not found).
|
|
264
|
-
*/
|
|
265
|
-
public async getLeafValue(
|
|
266
|
-
treeId: MerkleTreeId,
|
|
267
|
-
index: bigint,
|
|
268
|
-
includeUncommitted: boolean,
|
|
269
|
-
): Promise<Buffer | undefined> {
|
|
270
|
-
return await this.synchronize(() => this.trees[treeId].getLeafValue(index, includeUncommitted));
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Gets the sibling path for a leaf in a tree.
|
|
275
|
-
* @param treeId - The ID of the tree.
|
|
276
|
-
* @param index - The index of the leaf.
|
|
277
|
-
* @param includeUncommitted - Indicates whether the sibling path should include uncommitted data.
|
|
278
|
-
* @returns The sibling path for the leaf.
|
|
279
|
-
*/
|
|
280
|
-
public async getSiblingPath<N extends number>(
|
|
281
|
-
treeId: MerkleTreeId,
|
|
282
|
-
index: bigint,
|
|
283
|
-
includeUncommitted: boolean,
|
|
284
|
-
): Promise<SiblingPath<N>> {
|
|
285
|
-
return await this.synchronize(() => this._getSiblingPath(treeId, index, includeUncommitted));
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Appends leaves to a tree.
|
|
290
|
-
* @param treeId - The ID of the tree.
|
|
291
|
-
* @param leaves - The leaves to append.
|
|
292
|
-
* @returns Empty promise.
|
|
293
|
-
*/
|
|
294
|
-
public async appendLeaves(treeId: MerkleTreeId, leaves: Buffer[]): Promise<void> {
|
|
295
|
-
return await this.synchronize(() => this._appendLeaves(treeId, leaves));
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Commits all pending updates.
|
|
300
|
-
* @returns Empty promise.
|
|
301
|
-
*/
|
|
302
|
-
public async commit(): Promise<void> {
|
|
303
|
-
return await this.synchronize(() => this._commit());
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Rolls back all pending updates.
|
|
308
|
-
* @returns Empty promise.
|
|
309
|
-
*/
|
|
310
|
-
public async rollback(): Promise<void> {
|
|
311
|
-
return await this.synchronize(() => this._rollback());
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Finds the index of the largest leaf whose value is less than or equal to the provided value.
|
|
316
|
-
* @param treeId - The ID of the tree to search.
|
|
317
|
-
* @param value - The value to be inserted into the tree.
|
|
318
|
-
* @param includeUncommitted - If true, the uncommitted changes are included in the search.
|
|
319
|
-
* @returns The found leaf index and a flag indicating if the corresponding leaf's value is equal to `newValue`.
|
|
320
|
-
*/
|
|
321
|
-
public async getPreviousValueIndex(
|
|
322
|
-
treeId: IndexedTreeId,
|
|
323
|
-
value: bigint,
|
|
324
|
-
includeUncommitted: boolean,
|
|
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));
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Gets the leaf data at a given index and tree.
|
|
343
|
-
* @param treeId - The ID of the tree get the leaf from.
|
|
344
|
-
* @param index - The index of the leaf to get.
|
|
345
|
-
* @param includeUncommitted - Indicates whether to include uncommitted data.
|
|
346
|
-
* @returns Leaf preimage.
|
|
347
|
-
*/
|
|
348
|
-
public async getLeafPreimage(
|
|
349
|
-
treeId: IndexedTreeId,
|
|
350
|
-
index: bigint,
|
|
351
|
-
includeUncommitted: boolean,
|
|
352
|
-
): Promise<IndexedTreeLeafPreimage | undefined> {
|
|
353
|
-
return await this.synchronize(() =>
|
|
354
|
-
this._getIndexedTree(treeId).getLatestLeafPreimageCopy(index, includeUncommitted),
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Returns the index of a leaf given its value, or undefined if no leaf with that value is found.
|
|
360
|
-
* @param treeId - The ID of the tree.
|
|
361
|
-
* @param value - The leaf value to look for.
|
|
362
|
-
* @param includeUncommitted - Indicates whether to include uncommitted data.
|
|
363
|
-
* @returns The index of the first leaf found with a given value (undefined if not found).
|
|
364
|
-
*/
|
|
365
|
-
public async findLeafIndex(
|
|
366
|
-
treeId: MerkleTreeId,
|
|
367
|
-
value: Buffer,
|
|
368
|
-
includeUncommitted: boolean,
|
|
369
|
-
): Promise<bigint | undefined> {
|
|
370
|
-
return await this.synchronize(async () => {
|
|
371
|
-
const tree = this.trees[treeId];
|
|
372
|
-
return await tree.findLeafIndex(value, includeUncommitted);
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Updates a leaf in a tree at a given index.
|
|
378
|
-
* @param treeId - The ID of the tree.
|
|
379
|
-
* @param leaf - The new leaf value.
|
|
380
|
-
* @param index - The index to insert into.
|
|
381
|
-
* @returns Empty promise.
|
|
382
|
-
*/
|
|
383
|
-
public async updateLeaf(treeId: IndexedTreeId | PublicTreeId, leaf: Buffer, index: bigint): Promise<void> {
|
|
384
|
-
return await this.synchronize(() => this._updateLeaf(treeId, leaf, index));
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Handles a single L2 block (i.e. Inserts the new commitments into the merkle tree).
|
|
389
|
-
* @param block - The L2 block to handle.
|
|
390
|
-
* @returns Whether the block handled was produced by this same node.
|
|
391
|
-
*/
|
|
392
|
-
public async handleL2Block(block: L2Block): Promise<HandleL2BlockResult> {
|
|
393
|
-
return await this.synchronize(() => this._handleL2Block(block));
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Batch insert multiple leaves into the tree.
|
|
398
|
-
* @param treeId - The ID of the tree.
|
|
399
|
-
* @param leaves - Leaves to insert into the tree.
|
|
400
|
-
* @param subtreeHeight - Height of the subtree.
|
|
401
|
-
* @returns The data for the leaves to be updated when inserting the new ones.
|
|
402
|
-
*/
|
|
403
|
-
public async batchInsert<
|
|
404
|
-
TreeHeight extends number,
|
|
405
|
-
SubtreeHeight extends number,
|
|
406
|
-
SubtreeSiblingPathHeight extends number,
|
|
407
|
-
>(
|
|
408
|
-
treeId: MerkleTreeId,
|
|
409
|
-
leaves: Buffer[],
|
|
410
|
-
subtreeHeight: SubtreeHeight,
|
|
411
|
-
): Promise<BatchInsertionResult<TreeHeight, SubtreeSiblingPathHeight>> {
|
|
412
|
-
const tree = this.trees[treeId] as StandardIndexedTree;
|
|
413
|
-
if (!('batchInsert' in tree)) {
|
|
414
|
-
throw new Error('Tree does not support `batchInsert` method');
|
|
415
|
-
}
|
|
416
|
-
return await this.synchronize(() => tree.batchInsert(leaves, subtreeHeight));
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Waits for all jobs to finish before executing the given function.
|
|
421
|
-
* @param fn - The function to execute.
|
|
422
|
-
* @returns Promise containing the result of the function.
|
|
423
|
-
*/
|
|
424
|
-
private async synchronize<T>(fn: () => Promise<T>): Promise<T> {
|
|
425
|
-
return await this.jobQueue.put(fn);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
private _updateLatestGlobalVariablesHash(globalVariablesHash: Fr): Promise<void> {
|
|
429
|
-
this.latestGlobalVariablesHash.set(globalVariablesHash);
|
|
430
|
-
return Promise.resolve();
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
private _getGlobalVariablesHash(includeUncommitted: boolean): Promise<Fr> {
|
|
434
|
-
return Promise.resolve(this.latestGlobalVariablesHash.get(includeUncommitted));
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
private async _updateBlocksTree(globalsHash: Fr, includeUncommitted: boolean) {
|
|
438
|
-
const blockHash = await this._getCurrentBlockHash(globalsHash, includeUncommitted);
|
|
439
|
-
await this._appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Returns the tree info for the specified tree id.
|
|
444
|
-
* @param treeId - Id of the tree to get information from.
|
|
445
|
-
* @param includeUncommitted - Indicates whether to include uncommitted data.
|
|
446
|
-
* @returns The tree info for the specified tree.
|
|
447
|
-
*/
|
|
448
|
-
private _getTreeInfo(treeId: MerkleTreeId, includeUncommitted: boolean): Promise<TreeInfo> {
|
|
449
|
-
const treeInfo = {
|
|
450
|
-
treeId,
|
|
451
|
-
root: this.trees[treeId].getRoot(includeUncommitted),
|
|
452
|
-
size: this.trees[treeId].getNumLeaves(includeUncommitted),
|
|
453
|
-
depth: this.trees[treeId].getDepth(),
|
|
454
|
-
} as TreeInfo;
|
|
455
|
-
return Promise.resolve(treeInfo);
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* Returns an instance of an indexed tree.
|
|
460
|
-
* @param treeId - Id of the tree to get an instance of.
|
|
461
|
-
* @returns The indexed tree for the specified tree id.
|
|
462
|
-
*/
|
|
463
|
-
private _getIndexedTree(treeId: IndexedTreeId): IndexedTree {
|
|
464
|
-
return this.trees[treeId] as IndexedTree;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* Returns the sibling path for a leaf in a tree.
|
|
469
|
-
* @param treeId - Id of the tree to get the sibling path from.
|
|
470
|
-
* @param index - Index of the leaf to get the sibling path for.
|
|
471
|
-
* @param includeUncommitted - Indicates whether to include uncommitted updates in the sibling path.
|
|
472
|
-
* @returns Promise containing the sibling path for the leaf.
|
|
473
|
-
*/
|
|
474
|
-
private _getSiblingPath<N extends number>(
|
|
475
|
-
treeId: MerkleTreeId,
|
|
476
|
-
index: bigint,
|
|
477
|
-
includeUncommitted: boolean,
|
|
478
|
-
): Promise<SiblingPath<N>> {
|
|
479
|
-
return Promise.resolve(this.trees[treeId].getSiblingPath<N>(index, includeUncommitted));
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
/**
|
|
483
|
-
* Appends leaves to a tree.
|
|
484
|
-
* @param treeId - Id of the tree to append leaves to.
|
|
485
|
-
* @param leaves - Leaves to append.
|
|
486
|
-
* @returns Empty promise.
|
|
487
|
-
*/
|
|
488
|
-
private async _appendLeaves(treeId: MerkleTreeId, leaves: Buffer[]): Promise<void> {
|
|
489
|
-
const tree = this.trees[treeId];
|
|
490
|
-
if (!('appendLeaves' in tree)) {
|
|
491
|
-
throw new Error('Tree does not support `appendLeaves` method');
|
|
492
|
-
}
|
|
493
|
-
return await tree.appendLeaves(leaves);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
private async _updateLeaf(treeId: IndexedTreeId | PublicTreeId, leaf: Buffer, index: bigint): Promise<void> {
|
|
497
|
-
const tree = this.trees[treeId];
|
|
498
|
-
if (!('updateLeaf' in tree)) {
|
|
499
|
-
throw new Error('Tree does not support `updateLeaf` method');
|
|
500
|
-
}
|
|
501
|
-
return await tree.updateLeaf(leaf, index);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* Commits all pending updates.
|
|
506
|
-
* @returns Empty promise.
|
|
507
|
-
*/
|
|
508
|
-
private async _commit(): Promise<void> {
|
|
509
|
-
for (const tree of this.trees) {
|
|
510
|
-
await tree.commit();
|
|
511
|
-
}
|
|
512
|
-
this.latestGlobalVariablesHash.commit();
|
|
513
|
-
await this.db.put(LAST_GLOBAL_VARS_HASH, this.latestGlobalVariablesHash.get().toBuffer());
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
/**
|
|
517
|
-
* Rolls back all pending updates.
|
|
518
|
-
* @returns Empty promise.
|
|
519
|
-
*/
|
|
520
|
-
private async _rollback(): Promise<void> {
|
|
521
|
-
for (const tree of this.trees) {
|
|
522
|
-
await tree.rollback();
|
|
523
|
-
}
|
|
524
|
-
this.latestGlobalVariablesHash.rollback();
|
|
525
|
-
}
|
|
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
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Handles a single L2 block (i.e. Inserts the new commitments into the merkle tree).
|
|
539
|
-
* @param l2Block - The L2 block to handle.
|
|
540
|
-
*/
|
|
541
|
-
private async _handleL2Block(l2Block: L2Block): Promise<HandleL2BlockResult> {
|
|
542
|
-
const treeRootWithIdPairs = [
|
|
543
|
-
[l2Block.endContractTreeSnapshot.root, MerkleTreeId.CONTRACT_TREE],
|
|
544
|
-
[l2Block.endNullifierTreeSnapshot.root, MerkleTreeId.NULLIFIER_TREE],
|
|
545
|
-
[l2Block.endNoteHashTreeSnapshot.root, MerkleTreeId.NOTE_HASH_TREE],
|
|
546
|
-
[l2Block.endPublicDataTreeRoot, MerkleTreeId.PUBLIC_DATA_TREE],
|
|
547
|
-
[l2Block.endL1ToL2MessagesTreeSnapshot.root, MerkleTreeId.L1_TO_L2_MESSAGES_TREE],
|
|
548
|
-
[l2Block.endBlocksTreeSnapshot.root, MerkleTreeId.BLOCKS_TREE],
|
|
549
|
-
] as const;
|
|
550
|
-
const compareRoot = (root: Fr, treeId: MerkleTreeId) => {
|
|
551
|
-
const treeRoot = this.trees[treeId].getRoot(true);
|
|
552
|
-
return treeRoot.equals(root.toBuffer());
|
|
553
|
-
};
|
|
554
|
-
const ourBlock = treeRootWithIdPairs.every(([root, id]) => compareRoot(root, id));
|
|
555
|
-
if (ourBlock) {
|
|
556
|
-
this.log(`Block ${l2Block.number} is ours, committing world state`);
|
|
557
|
-
await this._commit();
|
|
558
|
-
} else {
|
|
559
|
-
this.log(`Block ${l2Block.number} is not ours, rolling back world state and committing state from chain`);
|
|
560
|
-
await this._rollback();
|
|
561
|
-
|
|
562
|
-
// Sync the append only trees
|
|
563
|
-
for (const [tree, leaves] of [
|
|
564
|
-
[MerkleTreeId.CONTRACT_TREE, l2Block.newContracts],
|
|
565
|
-
[MerkleTreeId.NOTE_HASH_TREE, l2Block.newCommitments],
|
|
566
|
-
[MerkleTreeId.L1_TO_L2_MESSAGES_TREE, l2Block.newL1ToL2Messages],
|
|
567
|
-
] as const) {
|
|
568
|
-
await this._appendLeaves(
|
|
569
|
-
tree,
|
|
570
|
-
leaves.map(fr => fr.toBuffer()),
|
|
571
|
-
);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// Sync the indexed trees
|
|
575
|
-
await (this.trees[MerkleTreeId.NULLIFIER_TREE] as StandardIndexedTree).batchInsert(
|
|
576
|
-
l2Block.newNullifiers.map(fr => fr.toBuffer()),
|
|
577
|
-
NULLIFIER_SUBTREE_HEIGHT,
|
|
578
|
-
);
|
|
579
|
-
|
|
580
|
-
// Sync the public data tree
|
|
581
|
-
for (const dataWrite of l2Block.newPublicDataWrites) {
|
|
582
|
-
if (dataWrite.isEmpty()) {
|
|
583
|
-
continue;
|
|
584
|
-
}
|
|
585
|
-
const { newValue, leafIndex } = dataWrite;
|
|
586
|
-
await this._updateLeaf(MerkleTreeId.PUBLIC_DATA_TREE, newValue.toBuffer(), leafIndex.value);
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
// Sync and add the block to the blocks tree
|
|
590
|
-
const globalVariablesHash = computeGlobalsHash(l2Block.globalVariables);
|
|
591
|
-
await this._updateLatestGlobalVariablesHash(globalVariablesHash);
|
|
592
|
-
this.log(`Synced global variables with hash ${globalVariablesHash}`);
|
|
593
|
-
|
|
594
|
-
const blockHash = await this._getCurrentBlockHash(globalVariablesHash, true);
|
|
595
|
-
await this._appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]);
|
|
596
|
-
|
|
597
|
-
await this._commit();
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
for (const [root, treeId] of treeRootWithIdPairs) {
|
|
601
|
-
const treeName = MerkleTreeId[treeId];
|
|
602
|
-
const info = await this._getTreeInfo(treeId, false);
|
|
603
|
-
const syncedStr = '0x' + info.root.toString('hex');
|
|
604
|
-
const rootStr = root.toString();
|
|
605
|
-
// Sanity check that the rebuilt trees match the roots published by the L2 block
|
|
606
|
-
if (!info.root.equals(root.toBuffer())) {
|
|
607
|
-
throw new Error(
|
|
608
|
-
`Synced tree root ${treeName} does not match published L2 block root: ${syncedStr} != ${rootStr}`,
|
|
609
|
-
);
|
|
610
|
-
} else {
|
|
611
|
-
this.log(`Tree ${treeName} synched with size ${info.size} root ${rootStr}`);
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
await this._snapshot(l2Block.number);
|
|
616
|
-
|
|
617
|
-
return { isBlockOurs: ourBlock };
|
|
618
|
-
}
|
|
619
|
-
}
|