Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fast tree views demo #197

Closed
wants to merge 81 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
426f235
Demo v2
dapplion Sep 13, 2021
993926e
Add serdes for array types
dapplion Oct 9, 2021
283f563
Implement container serdes
dapplion Oct 10, 2021
fb895c9
WIP
dapplion Oct 10, 2021
bc91f62
Fix Boolean type
dapplion Oct 10, 2021
d2f0423
WIP
dapplion Oct 11, 2021
a177d5d
Get linked subTrees
dapplion Oct 11, 2021
3d1f84d
De-duplicate array views
dapplion Oct 11, 2021
e9f1942
Done
dapplion Oct 11, 2021
798f85f
Modularize container view logic
dapplion Oct 11, 2021
e04164a
Add serialize easy API method
dapplion Oct 11, 2021
9b8b3be
Add tree serdes
dapplion Oct 14, 2021
e8cd12a
Add push and getAll methods
dapplion Oct 15, 2021
b871082
Add spec v2 types
dapplion Dec 24, 2021
6e2c526
Add support for merkleize structs
dapplion Dec 24, 2021
00c99c0
Fix node uint ops
dapplion Dec 25, 2021
33e9d52
Add fromJson support
dapplion Dec 25, 2021
e6fad1f
Fix uint bool and bitlist types
dapplion Dec 25, 2021
cc8311b
Fix packedRootsBytesToNode
dapplion Dec 25, 2021
42d9c4c
Make packedNode routines work with offsets smaller than 4
dapplion Dec 25, 2021
9062c38
Fix serialization issues
dapplion Dec 25, 2021
60a704d
Fix maxChunksToDepth logic
dapplion Dec 25, 2021
7ad9338
Fix container offset in empty composite
dapplion Dec 25, 2021
ba6cef9
Add more bytes validation
dapplion Dec 25, 2021
8286454
Run spec generic tests for v2 types
dapplion Dec 25, 2021
41ce1ef
Add cachePermanentRootStruct option
dapplion Dec 25, 2021
da20f13
Return objects instead of arrays for multi-value return functions
dapplion Dec 25, 2021
c0b16df
Fix build
dapplion Dec 25, 2021
e20c82f
Prevent v2 types from importing from v1
dapplion Dec 25, 2021
bbb9ac9
Fix rogue length variable
dapplion Dec 26, 2021
b5dfcd7
Fix ArrayBasicTreeView logic
dapplion Dec 27, 2021
c5fdf63
Add clone functionality to array tree view
dapplion Dec 27, 2021
82bb83e
Add faster setNodesAtDepth
dapplion Dec 28, 2021
2569919
Fix CI
dapplion Dec 28, 2021
399f093
Fix benchmark types
dapplion Dec 28, 2021
833c87f
Switch fieldsEntries to array
dapplion Dec 31, 2021
e9ccdd3
Remove type from BranchNodeStruct
dapplion Dec 31, 2021
42e9572
Complete commit method for ArrayCompositeTreeView
dapplion Dec 31, 2021
15647fc
Add tree view tests
dapplion Dec 31, 2021
136b312
Expand TreeView abstract class
dapplion Dec 31, 2021
b840cb4
Move view methods to CompositeType only
dapplion Dec 31, 2021
35170f5
Strong type TreeViews
dapplion Dec 31, 2021
2b14902
Merge remote-tracking branch 'origin/master' into dapplion/demo-v2
dapplion Jan 3, 2022
278c52f
WIP TreeViewMutable
dapplion Jan 5, 2022
b51ae5c
Fix Container TreeViewMutable types
dapplion Jan 5, 2022
53f73a8
Add TreeViewMutable
dapplion Jan 7, 2022
3b06bf8
Lint code
dapplion Jan 7, 2022
2e090d0
Rename to viewDU
dapplion Jan 10, 2022
567d415
Placeholder proofs API
dapplion Jan 10, 2022
31eaf7b
Make TreeView generic
dapplion Jan 10, 2022
021af82
Restrict some ContainerType visibility
dapplion Jan 10, 2022
4d7f642
Use underscore notation for non-user methods
dapplion Jan 10, 2022
d777919
Use better type inference
dapplion Jan 10, 2022
72bc307
Organize by value, type, view, viewDU
dapplion Jan 10, 2022
09382f6
Remove any usage where possible
dapplion Jan 10, 2022
8a3b676
Export BitArray
dapplion Jan 10, 2022
78424a8
Add TreeView(s) for BitArray
dapplion Jan 10, 2022
bbc5bfb
Add toJson methods
dapplion Jan 11, 2022
10e1e99
Fix Container viewDU for basic types
dapplion Jan 11, 2022
b16a2bc
Support Infinity in uint type
dapplion Jan 11, 2022
761100a
Implement missing tree methods
dapplion Jan 11, 2022
8370480
Remove unused container state
dapplion Jan 11, 2022
e7c0a61
Fix commit ContainerTreeView condition
dapplion Jan 11, 2022
6c014a0
Support Infinity value in UintType
dapplion Jan 11, 2022
395bc43
Add more containerSwap tests
dapplion Jan 11, 2022
d876d45
Add typeName to all types
dapplion Jan 11, 2022
19ca9dd
Fix node byte manipulation logic
dapplion Jan 11, 2022
fba1e21
Add more tree manipulation tests
dapplion Jan 11, 2022
b621b7d
f
dapplion Jan 11, 2022
4bfb92d
Handle depth 0 in setNodesAtDepth
dapplion Jan 11, 2022
6b57def
Fix ArrayBasicTreeView.set()
dapplion Jan 11, 2022
3f12d25
Fix ArrayComposite maxChunkCount math
dapplion Jan 11, 2022
8b7954c
Fix length offset in array
dapplion Jan 11, 2022
932d831
f
dapplion Jan 11, 2022
390250e
Move v2 to root src
dapplion Jan 12, 2022
20af133
Replace lodestarTypes
dapplion Jan 12, 2022
625bd13
Update tests
dapplion Jan 12, 2022
2056bce
f
dapplion Jan 12, 2022
e8ce097
Add Union and None types
dapplion Jan 12, 2022
18669e9
Update spec tests
dapplion Jan 12, 2022
6fe0b91
Remove old src and lodestar dependencies
dapplion Jan 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ yarn-error.log
.idea/
.vscode

coverage
lib
packages/*/package-lock.json
packages/ssz/spec-tests

benchmark_data/
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"check-types": "lerna run check-types --no-bail",
"coverage": "lerna run coverage --no-bail",
"test": "lerna run test --no-bail",
"benchmark": "NODE_OPTIONS=--max_old_space_size=4096 benchmark --config .benchrc.yaml 'packages/*/test/perf/**/*.test.ts'",
"benchmark:files": "NODE_OPTIONS=--max_old_space_size=4096 benchmark --config .benchrc.yaml",
"benchmark": "yarn benchmark:files 'packages/*/test/perf/**/*.test.ts'",
"benchmark:local": "yarn benchmark --local",
"publish:release": "lerna publish from-package --yes --no-verify-access",
"release": "lerna version --no-push --sign-git-commit",
Expand Down
5 changes: 3 additions & 2 deletions packages/persistent-merkle-tree/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export * from "./gindex";
export * from "./hash";
export * from "./node";
export * from "./zeroNode";
export * from "./packedNode";
export * from "./proof";
export * from "./subtree";
export * from "./tree";
export * from "./proof";
export * from "./zeroNode";
213 changes: 210 additions & 3 deletions packages/persistent-merkle-tree/src/node.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {HashObject} from "@chainsafe/as-sha256";
import {hashObjectToUint8Array, hashTwoObjects, isHashObject, uint8ArrayToHashObject} from "./hash";

const ERR_INVALID_TREE = "Invalid tree";
const TWO_POWER_32 = 2 ** 32;

export abstract class Node implements HashObject {
// this is to save an extra variable to check if a node has a root or not
Expand Down Expand Up @@ -38,7 +38,8 @@ export abstract class Node implements HashObject {
export class BranchNode extends Node {
constructor(private _left: Node, private _right: Node) {
super();
if (!_left || !_right) throw new Error(ERR_INVALID_TREE);
if (!_left) throw new Error("Left node is undefined");
if (!_right) throw new Error("Right node is undefined");
}

get rootHashObject(): HashObject {
Expand Down Expand Up @@ -79,7 +80,7 @@ export class LeafNode extends Node {
if (isHashObject(_root)) {
this.applyHash(_root);
} else {
if (_root.length !== 32) throw new Error(ERR_INVALID_TREE);
if (_root.length !== 32) throw new Error(`Root length ${_root.length} must be 32`);
this.applyHash(uint8ArrayToHashObject(_root));
}
}
Expand Down Expand Up @@ -111,6 +112,176 @@ export class LeafNode extends Node {
rebindRight(): Node {
throw Error("LeafNode has no right node");
}

writeToBytes(data: Uint8Array, start: number, size: number): void {
// TODO: Optimize
data.set(this.root.slice(0, size), start);
}

getUint(uintBytes: number, offsetBytes: number, clipInfinity?: boolean): number {
const hIndex = Math.floor(offsetBytes / 4);

// number has to be masked from an h value
if (uintBytes < 4) {
const bitIndex = (offsetBytes % 4) * 8;
const h = getNodeH(this, hIndex);
if (uintBytes === 1) {
return 0xff & (h >> bitIndex);
} else {
return 0xffff & (h >> bitIndex);
}
}

// number equals the h value
else if (uintBytes === 4) {
return getNodeH(this, hIndex) >>> 0;
}

// number spans 2 h values
else if (uintBytes === 8) {
const low = getNodeH(this, hIndex);
const high = getNodeH(this, hIndex + 1);
if (high === 0) {
return low >>> 0;
} else if (high === -1 && low === -1 && clipInfinity) {
// Limit uint returns
return Infinity;
} else {
return (low >>> 0) + (high >>> 0) * TWO_POWER_32;
}
}

// Bigger uint can't be represented
else {
throw Error("uintBytes > 8");
}
}

getUintBigint(uintBytes: number, offsetBytes: number): bigint {
const hIndex = Math.floor(offsetBytes / 4);

// number has to be masked from an h value
if (uintBytes < 4) {
const bitIndex = (offsetBytes % 4) * 8;
const h = getNodeH(this, hIndex);
if (uintBytes === 1) {
return BigInt(0xff & (h >> bitIndex));
} else {
return BigInt(0xffff & (h >> bitIndex));
}
}

// number equals the h value
else if (uintBytes === 4) {
return BigInt(getNodeH(this, hIndex));
}

// number spans multiple h values
else {
const hRange = Math.ceil(uintBytes / 4);
let v = BigInt(0);
for (let i = 0; i < hRange; i++) {
v += BigInt(getNodeH(this, hIndex + i)) << BigInt(32 * i);
}
return v;
}
}

setUint(uintBytes: number, offsetBytes: number, value: number, clipInfinity?: boolean): void {
const hIndex = Math.floor(offsetBytes / 4);

// number has to be masked from an h value
if (uintBytes < 4) {
const bitIndex = (offsetBytes % 4) * 8;
let h = getNodeH(this, hIndex);
if (uintBytes === 1) {
h &= ~(0xff << bitIndex);
h |= (0xff && value) << bitIndex;
} else {
h &= ~(0xffff << bitIndex);
h |= (0xffff && value) << bitIndex;
}
setNodeH(this, hIndex, h);
}

// number equals the h value
else if (uintBytes === 4) {
setNodeH(this, hIndex, value);
}

// number spans 2 h values
else if (uintBytes === 8) {
if (value === Infinity && clipInfinity) {
setNodeH(this, hIndex, -1);
setNodeH(this, hIndex + 1, -1);
} else {
setNodeH(this, hIndex, value & 0xffffffff);
setNodeH(this, hIndex + 1, (value / TWO_POWER_32) & 0xffffffff);
}
}

// Bigger uint can't be represented
else {
throw Error("uintBytes > 8");
}
}

setUintBigint(uintBytes: number, offsetBytes: number, valueBN: bigint): void {
const hIndex = Math.floor(offsetBytes / 4);

// number has to be masked from an h value
if (uintBytes < 4) {
const value = Number(valueBN);
const bitIndex = (offsetBytes % 4) * 8;
let h = getNodeH(this, hIndex);
if (uintBytes === 1) {
h &= ~(0xff << bitIndex);
h |= (0xff && value) << bitIndex;
} else {
h &= ~(0xffff << bitIndex);
h |= (0xffff && value) << bitIndex;
}
setNodeH(this, hIndex, h);
}

// number equals the h value
else if (uintBytes === 4) {
setNodeH(this, hIndex, Number(valueBN));
}

// number spans multiple h values
else {
const hEnd = hIndex + Math.ceil(uintBytes / 4);
for (let i = hIndex; i < hEnd; i++) {
setNodeH(this, i, Number(valueBN & BigInt(0xffffffff)));
valueBN = valueBN >> BigInt(32);
}
}
}

bitwiseOrUint(uintBytes: number, offsetBytes: number, value: number): void {
const hIndex = Math.floor(offsetBytes / 4);

// number has to be masked from an h value
if (uintBytes < 4) {
const bitIndex = (offsetBytes % 4) * 8;
bitwiseOrNodeH(this, hIndex, value << bitIndex);
}

// number equals the h value
else if (uintBytes === 4) {
bitwiseOrNodeH(this, hIndex, value);
}

// number spans multiple h values
else {
const hEnd = hIndex + Math.ceil(uintBytes / 4);
for (let i = hIndex; i < hEnd; i++) {
bitwiseOrNodeH(this, i, value & 0xffffffff);
value >>= 32;
}
}
}
}

// setter helpers
Expand All @@ -126,3 +297,39 @@ export function compose(inner: Link, outer: Link): Link {
return outer(inner(n));
};
}

export function getNodeH(node: Node, hIndex: number): number {
if (hIndex === 0) return node.h0;
else if (hIndex === 1) return node.h1;
else if (hIndex === 2) return node.h2;
else if (hIndex === 3) return node.h3;
else if (hIndex === 4) return node.h4;
else if (hIndex === 5) return node.h5;
else if (hIndex === 6) return node.h6;
else if (hIndex === 7) return node.h7;
else throw Error("hIndex > 7");
}

export function setNodeH(node: Node, hIndex: number, value: number): void {
if (hIndex === 0) node.h0 = value;
else if (hIndex === 1) node.h1 = value;
else if (hIndex === 2) node.h2 = value;
else if (hIndex === 3) node.h3 = value;
else if (hIndex === 4) node.h4 = value;
else if (hIndex === 5) node.h5 = value;
else if (hIndex === 6) node.h6 = value;
else if (hIndex === 7) node.h7 = value;
else throw Error("hIndex > 7");
}

export function bitwiseOrNodeH(node: Node, hIndex: number, value: number): void {
if (hIndex === 0) node.h0 |= value;
else if (hIndex === 1) node.h1 |= value;
else if (hIndex === 2) node.h2 |= value;
else if (hIndex === 3) node.h3 |= value;
else if (hIndex === 4) node.h4 |= value;
else if (hIndex === 5) node.h5 |= value;
else if (hIndex === 6) node.h6 |= value;
else if (hIndex === 7) node.h7 |= value;
else throw Error("hIndex > 7");
}
Loading