@aztec/merkle-tree 0.31.0 → 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.
- package/dest/interfaces/append_only_tree.d.ts +4 -3
- package/dest/interfaces/append_only_tree.d.ts.map +1 -1
- package/dest/interfaces/indexed_tree.d.ts +3 -1
- package/dest/interfaces/indexed_tree.d.ts.map +1 -1
- package/dest/interfaces/merkle_tree.d.ts +5 -4
- package/dest/interfaces/merkle_tree.d.ts.map +1 -1
- package/dest/interfaces/update_only_tree.d.ts +4 -3
- package/dest/interfaces/update_only_tree.d.ts.map +1 -1
- package/dest/load_tree.d.ts +2 -1
- package/dest/load_tree.d.ts.map +1 -1
- package/dest/load_tree.js +3 -3
- package/dest/new_tree.d.ts +2 -1
- package/dest/new_tree.d.ts.map +1 -1
- package/dest/new_tree.js +3 -3
- package/dest/snapshots/append_only_snapshot.d.ts +6 -4
- package/dest/snapshots/append_only_snapshot.d.ts.map +1 -1
- package/dest/snapshots/append_only_snapshot.js +13 -8
- package/dest/snapshots/base_full_snapshot.d.ts +9 -7
- package/dest/snapshots/base_full_snapshot.d.ts.map +1 -1
- package/dest/snapshots/base_full_snapshot.js +7 -4
- package/dest/snapshots/full_snapshot.d.ts +6 -2
- package/dest/snapshots/full_snapshot.d.ts.map +1 -1
- package/dest/snapshots/full_snapshot.js +6 -2
- package/dest/snapshots/indexed_tree_snapshot.d.ts +2 -2
- package/dest/snapshots/indexed_tree_snapshot.d.ts.map +1 -1
- package/dest/snapshots/indexed_tree_snapshot.js +2 -2
- package/dest/snapshots/snapshot_builder.d.ts +7 -6
- package/dest/snapshots/snapshot_builder.d.ts.map +1 -1
- package/dest/snapshots/snapshot_builder_test_suite.d.ts +3 -2
- package/dest/snapshots/snapshot_builder_test_suite.d.ts.map +1 -1
- package/dest/snapshots/snapshot_builder_test_suite.js +5 -2
- package/dest/sparse_tree/sparse_tree.d.ts +7 -7
- package/dest/sparse_tree/sparse_tree.d.ts.map +1 -1
- package/dest/sparse_tree/sparse_tree.js +6 -4
- package/dest/standard_indexed_tree/standard_indexed_tree.d.ts +3 -1
- package/dest/standard_indexed_tree/standard_indexed_tree.d.ts.map +1 -1
- package/dest/standard_indexed_tree/standard_indexed_tree.js +5 -2
- package/dest/standard_tree/standard_tree.d.ts +7 -6
- package/dest/standard_tree/standard_tree.d.ts.map +1 -1
- package/dest/standard_tree/standard_tree.js +5 -3
- package/dest/tree_base.d.ts +15 -6
- package/dest/tree_base.d.ts.map +1 -1
- package/dest/tree_base.js +20 -3
- package/package.json +5 -5
- package/src/interfaces/append_only_tree.ts +7 -3
- package/src/interfaces/indexed_tree.ts +6 -1
- package/src/interfaces/merkle_tree.ts +5 -4
- package/src/interfaces/update_only_tree.ts +7 -3
- package/src/load_tree.ts +13 -3
- package/src/new_tree.ts +5 -3
- package/src/snapshots/append_only_snapshot.ts +23 -11
- package/src/snapshots/base_full_snapshot.ts +11 -8
- package/src/snapshots/full_snapshot.ts +12 -5
- package/src/snapshots/indexed_tree_snapshot.ts +5 -5
- package/src/snapshots/snapshot_builder.ts +7 -6
- package/src/snapshots/snapshot_builder_test_suite.ts +13 -7
- package/src/sparse_tree/sparse_tree.ts +11 -8
- package/src/standard_indexed_tree/standard_indexed_tree.ts +7 -2
- package/src/standard_tree/standard_tree.ts +10 -8
- package/src/tree_base.ts +23 -6
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Bufferable, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
2
|
+
|
|
1
3
|
import { UpdateOnlyTree } from '../interfaces/update_only_tree.js';
|
|
2
4
|
import { FullTreeSnapshotBuilder } from '../snapshots/full_snapshot.js';
|
|
3
5
|
import { TreeSnapshot } from '../snapshots/snapshot_builder.js';
|
|
@@ -6,20 +8,21 @@ import { INITIAL_LEAF, TreeBase } from '../tree_base.js';
|
|
|
6
8
|
/**
|
|
7
9
|
* A Merkle tree implementation that uses a LevelDB database to store the tree.
|
|
8
10
|
*/
|
|
9
|
-
export class SparseTree extends TreeBase implements UpdateOnlyTree {
|
|
10
|
-
#snapshotBuilder = new FullTreeSnapshotBuilder(this.store, this);
|
|
11
|
+
export class SparseTree<T extends Bufferable> extends TreeBase<T> implements UpdateOnlyTree<T> {
|
|
12
|
+
#snapshotBuilder = new FullTreeSnapshotBuilder(this.store, this, this.deserializer);
|
|
11
13
|
/**
|
|
12
14
|
* Updates a leaf in the tree.
|
|
13
15
|
* @param leaf - New contents of the leaf.
|
|
14
16
|
* @param index - Index of the leaf to be updated.
|
|
15
17
|
*/
|
|
16
|
-
public updateLeaf(
|
|
18
|
+
public updateLeaf(value: T, index: bigint): Promise<void> {
|
|
17
19
|
if (index > this.maxIndex) {
|
|
18
20
|
throw Error(`Index out of bounds. Index ${index}, max index: ${this.maxIndex}.`);
|
|
19
21
|
}
|
|
20
22
|
|
|
23
|
+
const leaf = serializeToBuffer(value);
|
|
21
24
|
const insertingZeroElement = leaf.equals(INITIAL_LEAF);
|
|
22
|
-
const originallyZeroElement = this.
|
|
25
|
+
const originallyZeroElement = this.getLeafBuffer(index, true)?.equals(INITIAL_LEAF);
|
|
23
26
|
if (insertingZeroElement && originallyZeroElement) {
|
|
24
27
|
return Promise.resolve();
|
|
25
28
|
}
|
|
@@ -35,19 +38,19 @@ export class SparseTree extends TreeBase implements UpdateOnlyTree {
|
|
|
35
38
|
return Promise.resolve();
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
public snapshot(block: number): Promise<TreeSnapshot
|
|
41
|
+
public snapshot(block: number): Promise<TreeSnapshot<T>> {
|
|
39
42
|
return this.#snapshotBuilder.snapshot(block);
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
public getSnapshot(block: number): Promise<TreeSnapshot
|
|
45
|
+
public getSnapshot(block: number): Promise<TreeSnapshot<T>> {
|
|
43
46
|
return this.#snapshotBuilder.getSnapshot(block);
|
|
44
47
|
}
|
|
45
48
|
|
|
46
|
-
public findLeafIndex(_value:
|
|
49
|
+
public findLeafIndex(_value: T, _includeUncommitted: boolean): bigint | undefined {
|
|
47
50
|
throw new Error('Finding leaf index is not supported for sparse trees');
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
public findLeafIndexAfter(_value:
|
|
53
|
+
public findLeafIndexAfter(_value: T, _startIndex: bigint, _includeUncommitted: boolean): bigint | undefined {
|
|
51
54
|
throw new Error('Finding leaf index is not supported for sparse trees');
|
|
52
55
|
}
|
|
53
56
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SiblingPath } from '@aztec/circuit-types';
|
|
2
2
|
import { TreeInsertionStats } from '@aztec/circuit-types/stats';
|
|
3
3
|
import { toBufferBE } from '@aztec/foundation/bigint-buffer';
|
|
4
|
+
import { FromBuffer } from '@aztec/foundation/serialize';
|
|
4
5
|
import { Timer } from '@aztec/foundation/timer';
|
|
5
6
|
import { IndexedTreeLeaf, IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
|
|
6
7
|
import { AztecKVStore, AztecMap } from '@aztec/kv-store';
|
|
@@ -51,10 +52,14 @@ function getEmptyLowLeafWitness<N extends number>(
|
|
|
51
52
|
};
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
export const noopDeserializer: FromBuffer<Buffer> = {
|
|
56
|
+
fromBuffer: (buf: Buffer) => buf,
|
|
57
|
+
};
|
|
58
|
+
|
|
54
59
|
/**
|
|
55
60
|
* Standard implementation of an indexed tree.
|
|
56
61
|
*/
|
|
57
|
-
export class StandardIndexedTree extends TreeBase implements IndexedTree {
|
|
62
|
+
export class StandardIndexedTree extends TreeBase<Buffer> implements IndexedTree {
|
|
58
63
|
#snapshotBuilder = new IndexedTreeSnapshotBuilder(this.store, this, this.leafPreimageFactory);
|
|
59
64
|
|
|
60
65
|
protected cachedLeafPreimages: { [key: string]: IndexedTreeLeafPreimage } = {};
|
|
@@ -71,7 +76,7 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree {
|
|
|
71
76
|
protected leafFactory: LeafFactory,
|
|
72
77
|
root?: Buffer,
|
|
73
78
|
) {
|
|
74
|
-
super(store, hasher, name, depth, size, root);
|
|
79
|
+
super(store, hasher, name, depth, size, noopDeserializer, root);
|
|
75
80
|
this.leaves = store.openMap(`tree_${name}_leaves`);
|
|
76
81
|
this.leafIndex = store.openMap(`tree_${name}_leaf_index`);
|
|
77
82
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TreeInsertionStats } from '@aztec/circuit-types/stats';
|
|
2
|
+
import { Bufferable, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
2
3
|
import { Timer } from '@aztec/foundation/timer';
|
|
3
4
|
|
|
4
5
|
import { AppendOnlyTree } from '../interfaces/append_only_tree.js';
|
|
@@ -9,15 +10,15 @@ import { TreeBase } from '../tree_base.js';
|
|
|
9
10
|
/**
|
|
10
11
|
* A Merkle tree implementation that uses a LevelDB database to store the tree.
|
|
11
12
|
*/
|
|
12
|
-
export class StandardTree extends TreeBase implements AppendOnlyTree {
|
|
13
|
-
#snapshotBuilder = new AppendOnlySnapshotBuilder(this.store, this, this.hasher);
|
|
13
|
+
export class StandardTree<T extends Bufferable = Buffer> extends TreeBase<T> implements AppendOnlyTree<T> {
|
|
14
|
+
#snapshotBuilder = new AppendOnlySnapshotBuilder(this.store, this, this.hasher, this.deserializer);
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Appends the given leaves to the tree.
|
|
17
18
|
* @param leaves - The leaves to append.
|
|
18
19
|
* @returns Empty promise.
|
|
19
20
|
*/
|
|
20
|
-
public appendLeaves(leaves:
|
|
21
|
+
public appendLeaves(leaves: T[]): Promise<void> {
|
|
21
22
|
this.hasher.reset();
|
|
22
23
|
const timer = new Timer();
|
|
23
24
|
super.appendLeaves(leaves);
|
|
@@ -34,22 +35,23 @@ export class StandardTree extends TreeBase implements AppendOnlyTree {
|
|
|
34
35
|
return Promise.resolve();
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
public snapshot(blockNumber: number): Promise<TreeSnapshot
|
|
38
|
+
public snapshot(blockNumber: number): Promise<TreeSnapshot<T>> {
|
|
38
39
|
return this.#snapshotBuilder.snapshot(blockNumber);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
public getSnapshot(blockNumber: number): Promise<TreeSnapshot
|
|
42
|
+
public getSnapshot(blockNumber: number): Promise<TreeSnapshot<T>> {
|
|
42
43
|
return this.#snapshotBuilder.getSnapshot(blockNumber);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
public findLeafIndex(value:
|
|
46
|
+
public findLeafIndex(value: T, includeUncommitted: boolean): bigint | undefined {
|
|
46
47
|
return this.findLeafIndexAfter(value, 0n, includeUncommitted);
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
public findLeafIndexAfter(value:
|
|
50
|
+
public findLeafIndexAfter(value: T, startIndex: bigint, includeUncommitted: boolean): bigint | undefined {
|
|
51
|
+
const buffer = serializeToBuffer(value);
|
|
50
52
|
for (let i = startIndex; i < this.getNumLeaves(includeUncommitted); i++) {
|
|
51
53
|
const currentValue = this.getLeafValue(i, includeUncommitted);
|
|
52
|
-
if (currentValue && currentValue.equals(
|
|
54
|
+
if (currentValue && serializeToBuffer(currentValue).equals(buffer)) {
|
|
53
55
|
return i;
|
|
54
56
|
}
|
|
55
57
|
}
|
package/src/tree_base.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SiblingPath } from '@aztec/circuit-types';
|
|
2
2
|
import { toBigIntLE, toBufferLE } from '@aztec/foundation/bigint-buffer';
|
|
3
3
|
import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';
|
|
4
|
+
import { Bufferable, FromBuffer, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
4
5
|
import { AztecKVStore, AztecMap, AztecSingleton } from '@aztec/kv-store';
|
|
5
6
|
import { Hasher } from '@aztec/types/interfaces';
|
|
6
7
|
|
|
@@ -44,7 +45,7 @@ export const INITIAL_LEAF = Buffer.from('000000000000000000000000000000000000000
|
|
|
44
45
|
/**
|
|
45
46
|
* A Merkle tree implementation that uses a LevelDB database to store the tree.
|
|
46
47
|
*/
|
|
47
|
-
export abstract class TreeBase implements MerkleTree {
|
|
48
|
+
export abstract class TreeBase<T extends Bufferable> implements MerkleTree<T> {
|
|
48
49
|
protected readonly maxIndex: bigint;
|
|
49
50
|
protected cachedSize?: bigint;
|
|
50
51
|
private root!: Buffer;
|
|
@@ -62,6 +63,7 @@ export abstract class TreeBase implements MerkleTree {
|
|
|
62
63
|
private name: string,
|
|
63
64
|
private depth: number,
|
|
64
65
|
protected size: bigint = 0n,
|
|
66
|
+
protected deserializer: FromBuffer<T>,
|
|
65
67
|
root?: Buffer,
|
|
66
68
|
) {
|
|
67
69
|
if (!(depth >= 1 && depth <= MAX_DEPTH)) {
|
|
@@ -173,7 +175,22 @@ export abstract class TreeBase implements MerkleTree {
|
|
|
173
175
|
* @param includeUncommitted - Indicates whether to include uncommitted changes.
|
|
174
176
|
* @returns Leaf value at the given index or undefined.
|
|
175
177
|
*/
|
|
176
|
-
public getLeafValue(index: bigint, includeUncommitted: boolean):
|
|
178
|
+
public getLeafValue(index: bigint, includeUncommitted: boolean): T | undefined {
|
|
179
|
+
const buf = this.getLatestValueAtIndex(this.depth, index, includeUncommitted);
|
|
180
|
+
if (buf) {
|
|
181
|
+
return this.deserializer.fromBuffer(buf);
|
|
182
|
+
} else {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Gets the value at the given index.
|
|
189
|
+
* @param index - The index of the leaf.
|
|
190
|
+
* @param includeUncommitted - Indicates whether to include uncommitted changes.
|
|
191
|
+
* @returns Leaf value at the given index or undefined.
|
|
192
|
+
*/
|
|
193
|
+
public getLeafBuffer(index: bigint, includeUncommitted: boolean): Buffer | undefined {
|
|
177
194
|
return this.getLatestValueAtIndex(this.depth, index, includeUncommitted);
|
|
178
195
|
}
|
|
179
196
|
|
|
@@ -292,7 +309,7 @@ export abstract class TreeBase implements MerkleTree {
|
|
|
292
309
|
* `getLatestValueAtIndex` will return a value from cache (because at least one of the 2 children was
|
|
293
310
|
* touched in previous iteration).
|
|
294
311
|
*/
|
|
295
|
-
protected appendLeaves(leaves:
|
|
312
|
+
protected appendLeaves(leaves: T[]): void {
|
|
296
313
|
const numLeaves = this.getNumLeaves(true);
|
|
297
314
|
if (numLeaves + BigInt(leaves.length) - 1n > this.maxIndex) {
|
|
298
315
|
throw Error(`Can't append beyond max index. Max index: ${this.maxIndex}`);
|
|
@@ -303,7 +320,7 @@ export abstract class TreeBase implements MerkleTree {
|
|
|
303
320
|
let level = this.depth;
|
|
304
321
|
for (let i = 0; i < leaves.length; i++) {
|
|
305
322
|
const cacheKey = indexToKeyHash(this.name, level, firstIndex + BigInt(i));
|
|
306
|
-
this.cache[cacheKey] = leaves[i];
|
|
323
|
+
this.cache[cacheKey] = serializeToBuffer(leaves[i]);
|
|
307
324
|
}
|
|
308
325
|
|
|
309
326
|
let lastIndex = firstIndex + BigInt(leaves.length);
|
|
@@ -330,7 +347,7 @@ export abstract class TreeBase implements MerkleTree {
|
|
|
330
347
|
* @param includeUncommitted - Indicates whether to include uncommitted data.
|
|
331
348
|
* @returns The index of the first leaf found with a given value (undefined if not found).
|
|
332
349
|
*/
|
|
333
|
-
abstract findLeafIndex(value:
|
|
350
|
+
abstract findLeafIndex(value: T, includeUncommitted: boolean): bigint | undefined;
|
|
334
351
|
|
|
335
352
|
/**
|
|
336
353
|
* Returns the first index containing a leaf value after `startIndex`.
|
|
@@ -339,5 +356,5 @@ export abstract class TreeBase implements MerkleTree {
|
|
|
339
356
|
* @param includeUncommitted - Indicates whether to include uncommitted data.
|
|
340
357
|
* @returns The index of the first leaf found with a given value (undefined if not found).
|
|
341
358
|
*/
|
|
342
|
-
abstract findLeafIndexAfter(leaf:
|
|
359
|
+
abstract findLeafIndexAfter(leaf: T, startIndex: bigint, includeUncommitted: boolean): bigint | undefined;
|
|
343
360
|
}
|