Skip to content

Commit a6191d4

Browse files
committed
feat: implement ViewDU.batchHashTreeRoot()
1 parent 216241d commit a6191d4

35 files changed

+1496
-122
lines changed

packages/ssz/src/type/arrayBasic.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
getNodesAtDepth,
66
packedNodeRootsToBytes,
77
packedRootsBytesToNode,
8+
HashComputationLevel,
9+
levelAtIndex,
810
} from "@chainsafe/persistent-merkle-tree";
911
import {Type, ValueOf, ByteViews} from "./abstract";
1012
import {BasicType} from "./basic";
@@ -39,14 +41,24 @@ export function addLengthNode(chunksNode: Node, length: number): Node {
3941
return new BranchNode(chunksNode, LeafNode.fromUint32(length));
4042
}
4143

42-
export function setChunksNode(rootNode: Node, chunksNode: Node, newLength?: number): Node {
44+
export function setChunksNode(
45+
rootNode: Node,
46+
chunksNode: Node,
47+
newLength: number | null,
48+
hcOffset = 0,
49+
hcByLevel: HashComputationLevel[] | null = null
50+
): Node {
4351
const lengthNode =
44-
newLength !== undefined
52+
newLength !== null
4553
? // If newLength is set, create a new node for length
4654
LeafNode.fromUint32(newLength)
4755
: // else re-use existing node
4856
(rootNode.right as LeafNode);
49-
return new BranchNode(chunksNode, lengthNode);
57+
const branchNode = new BranchNode(chunksNode, lengthNode);
58+
if (hcByLevel !== null) {
59+
levelAtIndex(hcByLevel, hcOffset).push(chunksNode, lengthNode, branchNode);
60+
}
61+
return branchNode;
5062
}
5163

5264
export type ArrayProps = {isList: true; limit: number} | {isList: false; length: number};

packages/ssz/src/type/bitArray.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {concatGindices, Gindex, Node, toGindex, Tree} from "@chainsafe/persistent-merkle-tree";
1+
import {concatGindices, Gindex, Node, toGindex, Tree, HashComputationLevel} from "@chainsafe/persistent-merkle-tree";
22
import {fromHexString, toHexString, byteArrayEquals} from "../util/byteArray";
33
import {splitIntoRootChunks} from "../util/merkleize";
44
import {CompositeType, LENGTH_GINDEX} from "./composite";
@@ -29,8 +29,8 @@ export abstract class BitArrayType extends CompositeType<BitArray, BitArrayTreeV
2929
return view.node;
3030
}
3131

32-
commitViewDU(view: BitArrayTreeViewDU): Node {
33-
view.commit();
32+
commitViewDU(view: BitArrayTreeViewDU, hcOffset = 0, hcByLevel: HashComputationLevel[] | null = null): Node {
33+
view.commit(hcOffset, hcByLevel);
3434
return view.node;
3535
}
3636

packages/ssz/src/type/byteArray.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import {concatGindices, Gindex, Node, toGindex, Tree} from "@chainsafe/persistent-merkle-tree";
1+
import {
2+
concatGindices,
3+
Gindex,
4+
Node,
5+
toGindex,
6+
Tree,
7+
HashComputationLevel,
8+
getHashComputations,
9+
} from "@chainsafe/persistent-merkle-tree";
210
import {fromHexString, toHexString, byteArrayEquals} from "../util/byteArray";
311
import {splitIntoRootChunks} from "../util/merkleize";
412
import {ByteViews} from "./abstract";
@@ -37,11 +45,16 @@ export abstract class ByteArrayType extends CompositeType<ByteArray, ByteArray,
3745
return this.commitViewDU(view);
3846
}
3947

40-
commitViewDU(view: ByteArray): Node {
48+
// there is no respective ViewDU for this type
49+
commitViewDU(view: ByteArray, hcOffset = 0, hcByLevel: HashComputationLevel[] | null = null): Node {
4150
const uint8Array = new Uint8Array(this.value_serializedSize(view));
4251
const dataView = new DataView(uint8Array.buffer, uint8Array.byteOffset, uint8Array.byteLength);
4352
this.value_serializeToBytes({uint8Array, dataView}, 0, view);
44-
return this.tree_deserializeFromBytes({uint8Array, dataView}, 0, uint8Array.length);
53+
const node = this.tree_deserializeFromBytes({uint8Array, dataView}, 0, uint8Array.length);
54+
if (hcByLevel !== null && node.h0 === null) {
55+
getHashComputations(node, hcOffset, hcByLevel);
56+
}
57+
return node;
4558
}
4659

4760
cacheOfViewDU(): unknown {

packages/ssz/src/type/composite.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
Proof,
88
ProofType,
99
Tree,
10+
HashComputationLevel,
1011
} from "@chainsafe/persistent-merkle-tree";
1112
import {byteArrayEquals} from "../util/byteArray";
1213
import {merkleize, symbolCachedPermanentRoot, ValueWithCachedPermanentRoot} from "../util/merkleize";
@@ -126,7 +127,7 @@ export abstract class CompositeType<V, TV, TVDU> extends Type<V> {
126127
/** INTERNAL METHOD: Given a Tree View, returns a `Node` with all its updated data */
127128
abstract commitView(view: TV): Node;
128129
/** INTERNAL METHOD: Given a Deferred Update Tree View returns a `Node` with all its updated data */
129-
abstract commitViewDU(view: TVDU): Node;
130+
abstract commitViewDU(view: TVDU, hcOffset?: number, hcByLevel?: HashComputationLevel[] | null): Node;
130131
/** INTERNAL METHOD: Return the cache of a Deferred Update Tree View. May return `undefined` if this ViewDU has no cache */
131132
abstract cacheOfViewDU(view: TVDU): unknown;
132133

packages/ssz/src/type/container.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
toGindex,
88
concatGindices,
99
getNode,
10+
HashComputationLevel,
1011
} from "@chainsafe/persistent-merkle-tree";
1112
import {maxChunksToDepth} from "../util/merkleize";
1213
import {Require} from "../util/types";
@@ -162,8 +163,12 @@ export class ContainerType<Fields extends Record<string, Type<unknown>>> extends
162163
return view.node;
163164
}
164165

165-
commitViewDU(view: ContainerTreeViewDUType<Fields>): Node {
166-
view.commit();
166+
commitViewDU(
167+
view: ContainerTreeViewDUType<Fields>,
168+
hcOffset = 0,
169+
hcByLevel: HashComputationLevel[] | null = null
170+
): Node {
171+
view.commit(hcOffset, hcByLevel);
167172
return view.node;
168173
}
169174

packages/ssz/src/type/listBasic.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {LeafNode, Node, Tree} from "@chainsafe/persistent-merkle-tree";
1+
import {LeafNode, Node, Tree, HashComputationLevel} from "@chainsafe/persistent-merkle-tree";
22
import {ValueOf} from "./abstract";
33
import {BasicType} from "./basic";
44
import {ByteViews} from "./composite";
@@ -93,8 +93,12 @@ export class ListBasicType<ElementType extends BasicType<unknown>>
9393
return view.node;
9494
}
9595

96-
commitViewDU(view: ListBasicTreeViewDU<ElementType>): Node {
97-
view.commit();
96+
commitViewDU(
97+
view: ListBasicTreeViewDU<ElementType>,
98+
hcOffset = 0,
99+
hcByLevel: HashComputationLevel[] | null = null
100+
): Node {
101+
view.commit(hcOffset, hcByLevel);
98102
return view.node;
99103
}
100104

@@ -144,8 +148,19 @@ export class ListBasicType<ElementType extends BasicType<unknown>>
144148
return node.left;
145149
}
146150

147-
tree_setChunksNode(rootNode: Node, chunksNode: Node, newLength?: number): Node {
148-
return setChunksNode(rootNode, chunksNode, newLength);
151+
tree_chunksNodeOffset(): number {
152+
// one more level for length, see setChunksNode below
153+
return 1;
154+
}
155+
156+
tree_setChunksNode(
157+
rootNode: Node,
158+
chunksNode: Node,
159+
newLength: number | null,
160+
hcOffset = 0,
161+
hcByLevel: HashComputationLevel[] | null = null
162+
): Node {
163+
return setChunksNode(rootNode, chunksNode, newLength, hcOffset, hcByLevel);
149164
}
150165

151166
// Merkleization

packages/ssz/src/type/listComposite.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Node, Tree} from "@chainsafe/persistent-merkle-tree";
1+
import {Node, Tree, HashComputationLevel} from "@chainsafe/persistent-merkle-tree";
22
import {
33
mixInLength,
44
maxChunksToDepth,
@@ -97,8 +97,12 @@ export class ListCompositeType<
9797
return view.node;
9898
}
9999

100-
commitViewDU(view: ListCompositeTreeViewDU<ElementType>): Node {
101-
view.commit();
100+
commitViewDU(
101+
view: ListCompositeTreeViewDU<ElementType>,
102+
hcOffset = 0,
103+
hcByLevel: HashComputationLevel[] | null = null
104+
): Node {
105+
view.commit(hcOffset, hcByLevel);
102106
return view.node;
103107
}
104108

@@ -150,8 +154,19 @@ export class ListCompositeType<
150154
return node.left;
151155
}
152156

153-
tree_setChunksNode(rootNode: Node, chunksNode: Node, newLength?: number): Node {
154-
return setChunksNode(rootNode, chunksNode, newLength);
157+
tree_chunksNodeOffset(): number {
158+
// one more level for length, see setChunksNode below
159+
return 1;
160+
}
161+
162+
tree_setChunksNode(
163+
rootNode: Node,
164+
chunksNode: Node,
165+
newLength: number | null,
166+
hcOffset = 0,
167+
hcByLevel: HashComputationLevel[] | null = null
168+
): Node {
169+
return setChunksNode(rootNode, chunksNode, newLength, hcOffset, hcByLevel);
155170
}
156171

157172
// Merkleization

packages/ssz/src/type/optional.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import {concatGindices, Gindex, Node, Tree, zeroNode} from "@chainsafe/persistent-merkle-tree";
1+
import {
2+
concatGindices,
3+
Gindex,
4+
Node,
5+
Tree,
6+
zeroNode,
7+
HashComputationLevel,
8+
getHashComputations,
9+
} from "@chainsafe/persistent-merkle-tree";
210
import {mixInLength} from "../util/merkleize";
311
import {Require} from "../util/types";
412
import {namedClass} from "../util/named";
@@ -75,8 +83,12 @@ export class OptionalType<ElementType extends Type<unknown>> extends CompositeTy
7583
}
7684

7785
// TODO add an OptionalViewDU
78-
commitViewDU(view: ValueOfType<ElementType>): Node {
79-
return this.value_toTree(view);
86+
commitViewDU(view: ValueOfType<ElementType>, hcOffset = 0, hcByLevel: HashComputationLevel[] | null = null): Node {
87+
const node = this.value_toTree(view);
88+
if (hcByLevel !== null && node.h0 === null) {
89+
getHashComputations(node, hcOffset, hcByLevel);
90+
}
91+
return node;
8092
}
8193

8294
// TODO add an OptionalViewDU

packages/ssz/src/type/union.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import {concatGindices, getNode, Gindex, Node, Tree} from "@chainsafe/persistent-merkle-tree";
1+
import {
2+
concatGindices,
3+
getNode,
4+
Gindex,
5+
Node,
6+
Tree,
7+
HashComputationLevel,
8+
getHashComputations,
9+
} from "@chainsafe/persistent-merkle-tree";
210
import {mixInLength} from "../util/merkleize";
311
import {Require} from "../util/types";
412
import {namedClass} from "../util/named";
@@ -106,8 +114,12 @@ export class UnionType<Types extends Type<unknown>[]> extends CompositeType<
106114
return this.value_toTree(view);
107115
}
108116

109-
commitViewDU(view: ValueOfTypes<Types>): Node {
110-
return this.value_toTree(view);
117+
commitViewDU(view: ValueOfTypes<Types>, hcOffset = 0, hcByLevel: HashComputationLevel[] | null = null): Node {
118+
const node = this.value_toTree(view);
119+
if (hcByLevel !== null && node.h0 === null) {
120+
getHashComputations(node, hcOffset, hcByLevel);
121+
}
122+
return node;
111123
}
112124

113125
value_serializedSize(value: ValueOfTypes<Types>): number {

packages/ssz/src/type/vectorBasic.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Node, Tree} from "@chainsafe/persistent-merkle-tree";
1+
import {Node, Tree, HashComputationLevel} from "@chainsafe/persistent-merkle-tree";
22
import {maxChunksToDepth, splitIntoRootChunks} from "../util/merkleize";
33
import {Require} from "../util/types";
44
import {namedClass} from "../util/named";
@@ -83,8 +83,12 @@ export class VectorBasicType<ElementType extends BasicType<unknown>>
8383
return view.node;
8484
}
8585

86-
commitViewDU(view: ArrayBasicTreeViewDU<ElementType>): Node {
87-
view.commit();
86+
commitViewDU(
87+
view: ArrayBasicTreeViewDU<ElementType>,
88+
hcOffset = 0,
89+
hcByLevel: HashComputationLevel[] | null = null
90+
): Node {
91+
view.commit(hcOffset, hcByLevel);
8892
return view.node;
8993
}
9094

@@ -132,6 +136,10 @@ export class VectorBasicType<ElementType extends BasicType<unknown>>
132136
return node;
133137
}
134138

139+
tree_chunksNodeOffset(): number {
140+
return 0;
141+
}
142+
135143
tree_setChunksNode(rootNode: Node, chunksNode: Node): Node {
136144
return chunksNode;
137145
}

0 commit comments

Comments
 (0)