Skip to content

Commit ef7bf79

Browse files
alexghrspalladino
andauthored
refactor: append-only merkle tree generics (#5355)
Give Merkle Trees generic type arguments for the leaves they store. --------- Co-authored-by: Santiago Palladino <[email protected]>
1 parent ae5126a commit ef7bf79

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+477
-209
lines changed

cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"erc",
8080
"falsey",
8181
"fargate",
82+
"Fieldeable",
8283
"filestat",
8384
"flatmap",
8485
"foundryup",

yarn-project/aztec-node/src/aztec-node/server.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,8 +458,15 @@ export class AztecNodeService implements AztecNode {
458458

459459
const treeHeight = Math.ceil(Math.log2(l2ToL1Messages.length));
460460
// The root of this tree is the out_hash calculated in Noir => we truncate to match Noir's SHA
461-
const tree = new StandardTree(openTmpStore(true), new SHA256Trunc(), 'temp_outhash_sibling_path', treeHeight);
462-
await tree.appendLeaves(l2ToL1Messages.map(l2ToL1Msg => l2ToL1Msg.toBuffer()));
461+
const tree = new StandardTree(
462+
openTmpStore(true),
463+
new SHA256Trunc(),
464+
'temp_outhash_sibling_path',
465+
treeHeight,
466+
0n,
467+
Fr,
468+
);
469+
await tree.appendLeaves(l2ToL1Messages);
463470

464471
return [indexOfL2ToL1Message, await tree.getSiblingPath(indexOfL2ToL1Message, true)];
465472
}

yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ describe('e2e_blacklist_token_contract', () => {
3838

3939
let tokenSim: TokenSimulator;
4040

41-
let slowUpdateTreeSimulator: SparseTree;
41+
let slowUpdateTreeSimulator: SparseTree<Fr>;
4242

4343
let cheatCodes: CheatCodes;
4444

4545
const getMembershipProof = async (index: bigint, includeUncommitted: boolean) => {
4646
return {
4747
index,
48-
value: Fr.fromBuffer(slowUpdateTreeSimulator.getLeafValue(index, includeUncommitted)!),
48+
value: slowUpdateTreeSimulator.getLeafValue(index, includeUncommitted)!,
4949
// eslint-disable-next-line camelcase
5050
sibling_path: (await slowUpdateTreeSimulator.getSiblingPath(index, includeUncommitted)).toFields(),
5151
};
@@ -101,9 +101,9 @@ describe('e2e_blacklist_token_contract', () => {
101101
await wallets[accountIndex].addNote(extendedNote);
102102
};
103103

104-
const updateSlowTree = async (tree: SparseTree, wallet: Wallet, index: AztecAddress, value: bigint) => {
104+
const updateSlowTree = async (tree: SparseTree<Fr>, wallet: Wallet, index: AztecAddress, value: bigint) => {
105105
await wallet.addCapsule(getUpdateCapsule(await getUpdateProof(value, index.toBigInt())));
106-
await tree.updateLeaf(new Fr(value).toBuffer(), index.toBigInt());
106+
await tree.updateLeaf(new Fr(value), index.toBigInt());
107107
};
108108

109109
beforeAll(async () => {
@@ -113,7 +113,7 @@ describe('e2e_blacklist_token_contract', () => {
113113
slowTree = await SlowTreeContract.deploy(wallets[0]).send().deployed();
114114

115115
const depth = 254;
116-
slowUpdateTreeSimulator = await newTree(SparseTree, openTmpStore(), new Pedersen(), 'test', depth);
116+
slowUpdateTreeSimulator = await newTree(SparseTree, openTmpStore(), new Pedersen(), 'test', Fr, depth);
117117

118118
// Add account[0] as admin
119119
await updateSlowTree(slowUpdateTreeSimulator, wallets[0], accounts[0].address, 4n);

yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
setup,
2929
} from './fixtures/utils.js';
3030

31-
jest.setTimeout(1_000_000);
31+
jest.setTimeout(100_000);
3232

3333
const TOKEN_NAME = 'BananaCoin';
3434
const TOKEN_SYMBOL = 'BC';

yarn-project/end-to-end/src/e2e_slow_tree.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ describe('e2e_slow_tree', () => {
2323

2424
it('Messing around with noir slow tree', async () => {
2525
const depth = 254;
26-
const slowUpdateTreeSimulator = await newTree(SparseTree, openTmpStore(), new Pedersen(), 'test', depth);
26+
const slowUpdateTreeSimulator = await newTree(SparseTree, openTmpStore(), new Pedersen(), 'test', Fr, depth);
2727
const getMembershipProof = async (index: bigint, includeUncommitted: boolean) => {
2828
return {
2929
index,
30-
value: Fr.fromBuffer(slowUpdateTreeSimulator.getLeafValue(index, includeUncommitted)!),
30+
value: slowUpdateTreeSimulator.getLeafValue(index, includeUncommitted)!,
3131
// eslint-disable-next-line camelcase
3232
sibling_path: (await slowUpdateTreeSimulator.getSiblingPath(index, includeUncommitted)).toFields(),
3333
};
@@ -102,7 +102,7 @@ describe('e2e_slow_tree', () => {
102102
.update_at_public(await getUpdateProof(1n, key))
103103
.send()
104104
.wait();
105-
await slowUpdateTreeSimulator.updateLeaf(new Fr(1).toBuffer(), key);
105+
await slowUpdateTreeSimulator.updateLeaf(new Fr(1), key);
106106

107107
// Update below.
108108
_root = {
@@ -140,7 +140,7 @@ describe('e2e_slow_tree', () => {
140140
const t2 = computeNextChange(BigInt(await cheatCodes.eth.timestamp()));
141141
await wallet.addCapsule(getUpdateCapsule(await getUpdateProof(4n, key)));
142142
await contract.methods.update_at_private(key, 4n).send().wait();
143-
await slowUpdateTreeSimulator.updateLeaf(new Fr(4).toBuffer(), key);
143+
await slowUpdateTreeSimulator.updateLeaf(new Fr(4), key);
144144
_root = {
145145
before: Fr.fromBuffer(slowUpdateTreeSimulator.getRoot(false)).toBigInt(),
146146
after: Fr.fromBuffer(slowUpdateTreeSimulator.getRoot(true)).toBigInt(),

yarn-project/end-to-end/src/integration_l1_publisher.test.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,15 @@ describe('L1Publisher integration', () => {
428428

429429
const treeHeight = Math.ceil(Math.log2(newL2ToL1MsgsArray.length));
430430

431-
const tree = new StandardTree(openTmpStore(true), new SHA256Trunc(), 'temp_outhash_sibling_path', treeHeight);
432-
await tree.appendLeaves(newL2ToL1MsgsArray.map(l2ToL1Msg => l2ToL1Msg.toBuffer()));
431+
const tree = new StandardTree(
432+
openTmpStore(true),
433+
new SHA256Trunc(),
434+
'temp_outhash_sibling_path',
435+
treeHeight,
436+
0n,
437+
Fr,
438+
);
439+
await tree.appendLeaves(newL2ToL1MsgsArray);
433440

434441
const expectedRoot = tree.getRoot(true);
435442
const [actualRoot] = await outbox.read.roots([block.header.globalVariables.blockNumber.toBigInt()]);

yarn-project/foundation/src/serialize/buffer_reader.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,3 +312,14 @@ export class BufferReader {
312312
return this.buffer.length;
313313
}
314314
}
315+
316+
/**
317+
* A deserializer
318+
*/
319+
export interface FromBuffer<T> {
320+
/**
321+
* Deserializes an object from a buffer
322+
* @param buffer - The buffer to deserialize.
323+
*/
324+
fromBuffer(buffer: Buffer): T;
325+
}
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
import { TreeSnapshotBuilder } from '../snapshots/snapshot_builder.js';
1+
import { Bufferable } from '@aztec/foundation/serialize';
2+
3+
import { TreeSnapshot, TreeSnapshotBuilder } from '../snapshots/snapshot_builder.js';
24
import { MerkleTree } from './merkle_tree.js';
35

46
/**
57
* A Merkle tree that supports only appending leaves and not updating existing leaves.
68
*/
7-
export interface AppendOnlyTree extends MerkleTree, TreeSnapshotBuilder {
9+
export interface AppendOnlyTree<T extends Bufferable = Buffer>
10+
extends MerkleTree<T>,
11+
TreeSnapshotBuilder<TreeSnapshot<T>> {
812
/**
913
* Appends a set of leaf values to the tree.
1014
* @param leaves - The set of leaves to be appended.
1115
*/
12-
appendLeaves(leaves: Buffer[]): Promise<void>;
16+
appendLeaves(leaves: T[]): Promise<void>;
1317
}

yarn-project/merkle-tree/src/interfaces/indexed_tree.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { SiblingPath } from '@aztec/circuit-types';
22
import { IndexedTreeLeaf, IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
33

4+
import { IndexedTreeSnapshot, TreeSnapshot, TreeSnapshotBuilder } from '../snapshots/snapshot_builder.js';
45
import { AppendOnlyTree } from './append_only_tree.js';
6+
import { MerkleTree } from './merkle_tree.js';
57

68
/**
79
* Factory for creating leaf preimages.
@@ -73,7 +75,10 @@ export interface BatchInsertionResult<TreeHeight extends number, SubtreeSiblingP
7375
/**
7476
* Indexed merkle tree.
7577
*/
76-
export interface IndexedTree extends AppendOnlyTree {
78+
export interface IndexedTree
79+
extends MerkleTree<Buffer>,
80+
TreeSnapshotBuilder<IndexedTreeSnapshot>,
81+
Omit<AppendOnlyTree<Buffer>, keyof TreeSnapshotBuilder<TreeSnapshot<Buffer>>> {
7782
/**
7883
* Finds the index of the largest leaf whose value is less than or equal to the provided value.
7984
* @param newValue - The new value to be inserted into the tree.

yarn-project/merkle-tree/src/interfaces/merkle_tree.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { SiblingPath } from '@aztec/circuit-types';
2+
import { Bufferable } from '@aztec/foundation/serialize';
23

34
/**
45
* Defines the interface for a source of sibling paths.
@@ -15,7 +16,7 @@ export interface SiblingPathSource {
1516
/**
1617
* Defines the interface for a Merkle tree.
1718
*/
18-
export interface MerkleTree extends SiblingPathSource {
19+
export interface MerkleTree<T extends Bufferable = Buffer> extends SiblingPathSource {
1920
/**
2021
* Returns the current root of the tree.
2122
* @param includeUncommitted - Set to true to include uncommitted updates in the calculated root.
@@ -48,15 +49,15 @@ export interface MerkleTree extends SiblingPathSource {
4849
* @param index - The index of the leaf value to be returned.
4950
* @param includeUncommitted - Set to true to include uncommitted updates in the data set.
5051
*/
51-
getLeafValue(index: bigint, includeUncommitted: boolean): Buffer | undefined;
52+
getLeafValue(index: bigint, includeUncommitted: boolean): T | undefined;
5253

5354
/**
5455
* Returns the index of a leaf given its value, or undefined if no leaf with that value is found.
5556
* @param leaf - The leaf value to look for.
5657
* @param includeUncommitted - Indicates whether to include uncommitted data.
5758
* @returns The index of the first leaf found with a given value (undefined if not found).
5859
*/
59-
findLeafIndex(leaf: Buffer, includeUncommitted: boolean): bigint | undefined;
60+
findLeafIndex(leaf: T, includeUncommitted: boolean): bigint | undefined;
6061

6162
/**
6263
* Returns the first index containing a leaf value after `startIndex`.
@@ -65,5 +66,5 @@ export interface MerkleTree extends SiblingPathSource {
6566
* @param includeUncommitted - Indicates whether to include uncommitted data.
6667
* @returns The index of the first leaf found with a given value (undefined if not found).
6768
*/
68-
findLeafIndexAfter(leaf: Buffer, startIndex: bigint, includeUncommitted: boolean): bigint | undefined;
69+
findLeafIndexAfter(leaf: T, startIndex: bigint, includeUncommitted: boolean): bigint | undefined;
6970
}

0 commit comments

Comments
 (0)