Skip to content

Commit

Permalink
feat: add swappable hasher, default to noble-hashes (#314)
Browse files Browse the repository at this point in the history
* Add swappable hasher, default to noble-hashes

* Use as-sha256 hasher in benchmarks

* Add some comments

* Use as-sha256 hasher in tests

* Increase test timeout
  • Loading branch information
wemeetagain authored Apr 5, 2023
1 parent dbae75a commit 4b44614
Show file tree
Hide file tree
Showing 24 changed files with 163 additions and 86 deletions.
1 change: 1 addition & 0 deletions .benchrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
colors: true
require:
- ts-node/register
- setHasher.mjs

# benchmark opts
threshold: 3
Expand Down
3 changes: 3 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ module.exports = {

// Prevents accidentally pushing a commit with .only in Mocha tests
"no-only-tests/no-only-tests": "error",

// TEMP Disabled while eslint-plugin-import support ESM (Typescript does support it) https://github.com/import-js/eslint-plugin-import/issues/2170
"import/no-unresolved": "off",
},
overrides: [
{
Expand Down
13 changes: 13 additions & 0 deletions packages/as-sha256/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@
"url": "git+https://github.com/chainsafe/as-sha256.git"
},
"main": "lib/index.js",
"exports": {
".": "./lib/index.js",
"./hashObject": "./lib/hashObject.js"
},
"typesVersions": {
"*": {
"*": [
"*",
"lib/*",
"lib/*/index"
]
}
},
"types": "lib/index.d.ts",
"files": [
"lib",
Expand Down
4 changes: 3 additions & 1 deletion packages/persistent-merkle-tree/.mocharc.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
colors: true
require: ts-node/register
require:
- ts-node/register
- ../../setHasher.mjs
18 changes: 17 additions & 1 deletion packages/persistent-merkle-tree/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@
"version": "0.5.0",
"description": "Merkle tree implemented as a persistent datastructure",
"main": "lib/index.js",
"exports": {
".": "./lib/index.js",
"./hasher": "./lib/hasher/index.js",
"./hasher/as-sha256": "./lib/hasher/as-sha256.js",
"./hasher/noble": "./lib/hasher/noble.js"
},
"typesVersions": {
"*": {
"*": [
"*",
"lib/*",
"lib/*/index"
]
}
},
"files": [
"lib"
],
Expand Down Expand Up @@ -35,6 +50,7 @@
},
"homepage": "https://github.com/ChainSafe/persistent-merkle-tree#readme",
"dependencies": {
"@chainsafe/as-sha256": "^0.3.1"
"@chainsafe/as-sha256": "^0.3.1",
"@noble/hashes": "^1.3.0"
}
}
40 changes: 0 additions & 40 deletions packages/persistent-merkle-tree/src/hash.ts

This file was deleted.

7 changes: 7 additions & 0 deletions packages/persistent-merkle-tree/src/hasher/as-sha256.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {digest2Bytes32, digest64HashObjects} from "@chainsafe/as-sha256";
import type {Hasher} from "./types";

export const hasher: Hasher = {
digest64: digest2Bytes32,
digest64HashObjects,
};
20 changes: 20 additions & 0 deletions packages/persistent-merkle-tree/src/hasher/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {Hasher} from "./types";
import {hasher as nobleHasher} from "./noble";

export {HashObject} from "@chainsafe/as-sha256/hashObject";
export * from "./types";
export * from "./util";

/**
* Hasher used across the SSZ codebase
*/
export let hasher: Hasher = nobleHasher;

/**
* Set the hasher to be used across the SSZ codebase
*
* WARNING: This function is intended for power users and must be executed before any other SSZ code is imported
*/
export function setHasher(newHasher: Hasher): void {
hasher = newHasher;
}
10 changes: 10 additions & 0 deletions packages/persistent-merkle-tree/src/hasher/noble.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {sha256} from "@noble/hashes/sha256";
import type {Hasher} from "./types";
import {hashObjectToUint8Array, uint8ArrayToHashObject} from "./util";

const digest64 = (a: Uint8Array, b: Uint8Array): Uint8Array => sha256.create().update(a).update(b).digest();

export const hasher: Hasher = {
digest64,
digest64HashObjects: (a, b) => uint8ArrayToHashObject(digest64(hashObjectToUint8Array(a), hashObjectToUint8Array(b))),
};
12 changes: 12 additions & 0 deletions packages/persistent-merkle-tree/src/hasher/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type {HashObject} from "@chainsafe/as-sha256/hashObject";

export type Hasher = {
/**
* Hash two 32-byte Uint8Arrays
*/
digest64(a32Bytes: Uint8Array, b32Bytes: Uint8Array): Uint8Array;
/**
* Hash two 32-byte HashObjects
*/
digest64HashObjects(a: HashObject, b: HashObject): HashObject;
};
11 changes: 11 additions & 0 deletions packages/persistent-merkle-tree/src/hasher/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {byteArrayToHashObject, HashObject, hashObjectToByteArray} from "@chainsafe/as-sha256/hashObject";

export function hashObjectToUint8Array(obj: HashObject): Uint8Array {
const byteArr = new Uint8Array(32);
hashObjectToByteArray(obj, byteArr, 0);
return byteArr;
}

export function uint8ArrayToHashObject(byteArr: Uint8Array): HashObject {
return byteArrayToHashObject(byteArr);
}
2 changes: 1 addition & 1 deletion packages/persistent-merkle-tree/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * from "./gindex";
export * from "./hash";
export * from "./hasher";
export * from "./node";
export * from "./packedNode";
export * from "./proof";
Expand Down
6 changes: 3 additions & 3 deletions packages/persistent-merkle-tree/src/node.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {HashObject} from "@chainsafe/as-sha256";
import {hashObjectToUint8Array, hashTwoObjects, uint8ArrayToHashObject} from "./hash";
import {HashObject} from "@chainsafe/as-sha256/hashObject";
import {hashObjectToUint8Array, hasher, uint8ArrayToHashObject} from "./hasher";

const TWO_POWER_32 = 2 ** 32;

Expand Down Expand Up @@ -72,7 +72,7 @@ export class BranchNode extends Node {

get rootHashObject(): HashObject {
if (this.h0 === null) {
super.applyHash(hashTwoObjects(this.left.rootHashObject, this.right.rootHashObject));
super.applyHash(hasher.digest64HashObjects(this.left.rootHashObject, this.right.rootHashObject));
}
return this;
}
Expand Down
26 changes: 0 additions & 26 deletions packages/persistent-merkle-tree/test/perf/hash.test.ts

This file was deleted.

33 changes: 33 additions & 0 deletions packages/persistent-merkle-tree/test/perf/hasher.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {itBench} from "@dapplion/benchmark";
import {uint8ArrayToHashObject} from "../../src/hasher";
import {hasher as asShaHasher} from "../../src/hasher/as-sha256";
import {hasher as nobleHasher} from "../../src/hasher/noble";

describe("hasher", () => {
const root1 = new Uint8Array(32);
const root2 = new Uint8Array(32);
for (let i = 0; i < root1.length; i++) {
root1[i] = 1;
}
for (let i = 0; i < root2.length; i++) {
root2[i] = 2;
}

// total number of time running hash for 250_000 validators
const iterations = 2250026;

for (const {hasher, name} of [
{hasher: asShaHasher, name: "as-sha256"},
{hasher: nobleHasher, name: "noble"},
]) {
itBench(`hash 2 Uint8Array ${iterations} times - ${name}`, () => {
for (let j = 0; j < iterations; j++) hasher.digest64(root1, root2);
});

const obj1 = uint8ArrayToHashObject(root1);
const obj2 = uint8ArrayToHashObject(root2);
itBench(`hashTwoObjects ${iterations} times - ${name}`, () => {
for (let j = 0; j < iterations; j++) hasher.digest64HashObjects(obj1, obj2);
});
}
});
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { expect } from "chai";
import {uint8ArrayToHashObject, hash, hashTwoObjects, hashObjectToUint8Array} from "../src/hash";
import {uint8ArrayToHashObject, hasher, hashObjectToUint8Array} from "../../src/hasher";

describe("hash", function () {
it("hash and hashTwoObjects should be the same", () => {
describe("hasher", function () {
it("hasher methods should be the same", () => {
const root1 = Buffer.alloc(32, 1);
const root2 = Buffer.alloc(32, 2);
const root = hash(root1, root2);
const root = hasher.digest64(root1, root2);

const obj1 = uint8ArrayToHashObject(root1);
const obj2 = uint8ArrayToHashObject(root2);
const obj = hashTwoObjects(obj1, obj2);
const obj = hasher.digest64HashObjects(obj1, obj2);
const newRoot = hashObjectToUint8Array(obj);
expect(newRoot).to.be.deep.equal(root, "hash and hash2 is not equal");
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe("proof equivalence", () => {
}
});
it("should compute the same root from different proof types - multiple leaves", function () {
this.timeout(2000);
this.timeout(10_000);
const depth = 6;
const maxIndex = 2 ** depth;
const node = createTree(depth);
Expand Down
4 changes: 3 additions & 1 deletion packages/ssz/.mocharc.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
colors: true
require: ts-node/register
require:
- ts-node/register
- ../../setHasher.mjs
# benchmark
maxMs: 30_000
threshold: 3
2 changes: 1 addition & 1 deletion packages/ssz/src/branchNodeStruct.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {HashObject} from "@chainsafe/as-sha256";
import {HashObject} from "@chainsafe/as-sha256/hashObject";
import {hashObjectToUint8Array, Node} from "@chainsafe/persistent-merkle-tree";

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/ssz/src/util/merkleize.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {digest2Bytes32} from "@chainsafe/as-sha256";
import {hasher} from "@chainsafe/persistent-merkle-tree/hasher";
import {zeroHash} from "./zeros";

export function hash64(bytes32A: Uint8Array, bytes32B: Uint8Array): Uint8Array {
return digest2Bytes32(bytes32A, bytes32B);
return hasher.digest64(bytes32A, bytes32B);
}

export function merkleize(chunks: Uint8Array[], padFor: number): Uint8Array {
Expand Down
4 changes: 2 additions & 2 deletions packages/ssz/src/util/zeros.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {digest2Bytes32} from "@chainsafe/as-sha256";
import {hasher} from "@chainsafe/persistent-merkle-tree/hasher";

// create array of "zero hashes", successively hashed zero chunks
const zeroHashes = [new Uint8Array(32)];

export function zeroHash(depth: number): Uint8Array {
if (depth >= zeroHashes.length) {
for (let i = zeroHashes.length; i <= depth; i++) {
zeroHashes[i] = digest2Bytes32(zeroHashes[i - 1], zeroHashes[i - 1]);
zeroHashes[i] = hasher.digest64(zeroHashes[i - 1], zeroHashes[i - 1]);
}
}
return zeroHashes[depth];
Expand Down
4 changes: 2 additions & 2 deletions packages/ssz/test/perf/eth2/hashTreeRoot.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {itBench} from "@dapplion/benchmark";
import {hashTwoObjects, uint8ArrayToHashObject} from "@chainsafe/persistent-merkle-tree";
import {hasher, uint8ArrayToHashObject} from "@chainsafe/persistent-merkle-tree";
import * as sszPhase0 from "../../lodestarTypes/phase0/sszTypes";
import * as sszAltair from "../../lodestarTypes/altair/sszTypes";
import {
Expand Down Expand Up @@ -130,7 +130,7 @@ describe("HashTreeRoot individual components", () => {
});

itBench(`hashTwoObjects x${count}`, () => {
for (let i = 0; i < count; i++) hashTwoObjects(ho, ho);
for (let i = 0; i < count; i++) hasher.digest64HashObjects(ho, ho);
});
}

Expand Down
5 changes: 5 additions & 0 deletions setHasher.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Set the hasher to as-sha256
// Used to run benchmarks with with visibility into as-sha256 performance, useful for Lodestar
import {setHasher} from "@chainsafe/persistent-merkle-tree/hasher";
import {hasher} from "@chainsafe/persistent-merkle-tree/hasher/as-sha256";
setHasher(hasher);
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1669,6 +1669,7 @@ __metadata:
resolution: "@chainsafe/persistent-merkle-tree@workspace:packages/persistent-merkle-tree"
dependencies:
"@chainsafe/as-sha256": ^0.3.1
"@noble/hashes": ^1.3.0
languageName: unknown
linkType: soft

Expand Down Expand Up @@ -1920,6 +1921,13 @@ __metadata:
languageName: node
linkType: hard

"@noble/hashes@npm:^1.3.0":
version: 1.3.0
resolution: "@noble/hashes@npm:1.3.0"
checksum: 06d27f9e7dfbe379dbfb02073358aa2c25a6363acc3a2b09e074f0f47f630da1d5a81c731696faa9407594371b61a27c496076fdecc2f60fb1c6a24247a5dbef
languageName: node
linkType: hard

"@nodelib/fs.scandir@npm:2.1.5":
version: 2.1.5
resolution: "@nodelib/fs.scandir@npm:2.1.5"
Expand Down

1 comment on commit 4b44614

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for some benchmarks.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold.

Benchmark suite Current: 4b44614 Previous: dbae75a Ratio
250k validators 10.903 s/op 3.0091 s/op 3.62
Full benchmark results
Benchmark suite Current: 4b44614 Previous: dbae75a Ratio
digestTwoHashObjects 50023 times 69.933 ms/op 57.908 ms/op 1.21
digest64 50023 times 71.173 ms/op 60.642 ms/op 1.17
digest 50023 times 71.470 ms/op 60.606 ms/op 1.18
input length 32 1.5990 us/op 1.5280 us/op 1.05
input length 64 1.8230 us/op 1.5890 us/op 1.15
input length 128 3.1980 us/op 2.8480 us/op 1.12
input length 256 4.9550 us/op 4.1620 us/op 1.19
input length 512 7.9800 us/op 6.7530 us/op 1.18
input length 1024 15.423 us/op 13.478 us/op 1.14
digest 1000000 times 1.1677 s/op 1.0406 s/op 1.12
hashObjectToByteArray 50023 times 2.4026 ms/op 2.3770 ms/op 1.01
byteArrayToHashObject 50023 times 2.8969 ms/op 3.0661 ms/op 0.94
getGindicesAtDepth 6.0970 us/op 6.6290 us/op 0.92
iterateAtDepth 12.503 us/op 13.377 us/op 0.93
getGindexBits 620.00 ns/op 604.00 ns/op 1.03
gindexIterator 1.4250 us/op 1.3960 us/op 1.02
hash 2 Uint8Array 2250026 times - as-sha256 3.2843 s/op
hashTwoObjects 2250026 times - as-sha256 3.3155 s/op
hash 2 Uint8Array 2250026 times - noble 8.4476 s/op
hashTwoObjects 2250026 times - noble 10.323 s/op
getNodeH() x7812.5 avg hindex 23.968 us/op 20.853 us/op 1.15
getNodeH() x7812.5 index 0 6.6940 us/op 8.1650 us/op 0.82
getNodeH() x7812.5 index 7 6.5350 us/op 8.1220 us/op 0.80
getNodeH() x7812.5 index 7 with key array 6.5870 us/op 8.1900 us/op 0.80
new LeafNode() x7812.5 335.54 us/op 145.59 us/op 2.30
multiproof - depth 15, 1 requested leaves 15.565 us/op 10.774 us/op 1.44
tree offset multiproof - depth 15, 1 requested leaves 33.666 us/op 25.138 us/op 1.34
compact multiproof - depth 15, 1 requested leaves 8.6930 us/op 4.0590 us/op 2.14
multiproof - depth 15, 2 requested leaves 21.204 us/op 16.570 us/op 1.28
tree offset multiproof - depth 15, 2 requested leaves 36.943 us/op 30.683 us/op 1.20
compact multiproof - depth 15, 2 requested leaves 5.4030 us/op 4.0690 us/op 1.33
multiproof - depth 15, 3 requested leaves 29.476 us/op 23.887 us/op 1.23
tree offset multiproof - depth 15, 3 requested leaves 47.417 us/op 40.350 us/op 1.18
compact multiproof - depth 15, 3 requested leaves 9.1590 us/op 6.2660 us/op 1.46
multiproof - depth 15, 4 requested leaves 38.867 us/op 40.660 us/op 0.96
tree offset multiproof - depth 15, 4 requested leaves 58.327 us/op 54.906 us/op 1.06
compact multiproof - depth 15, 4 requested leaves 9.6460 us/op 8.4230 us/op 1.15
packedRootsBytesToLeafNodes bytes 4000 offset 0 3.7880 us/op 3.8120 us/op 0.99
packedRootsBytesToLeafNodes bytes 4000 offset 1 3.5980 us/op 3.8500 us/op 0.93
packedRootsBytesToLeafNodes bytes 4000 offset 2 3.6440 us/op 3.6950 us/op 0.99
packedRootsBytesToLeafNodes bytes 4000 offset 3 3.5440 us/op 3.6790 us/op 0.96
subtreeFillToContents depth 40 count 250000 87.426 ms/op 92.567 ms/op 0.94
setRoot - gindexBitstring 15.594 ms/op 15.222 ms/op 1.02
setRoot - gindex 16.747 ms/op 15.731 ms/op 1.06
getRoot - gindexBitstring 3.5733 ms/op 3.0653 ms/op 1.17
getRoot - gindex 4.6795 ms/op 3.9964 ms/op 1.17
getHashObject then setHashObject 18.220 ms/op 17.667 ms/op 1.03
setNodeWithFn 17.046 ms/op 15.572 ms/op 1.09
getNodeAtDepth depth 0 x100000 1.6888 ms/op 2.1908 ms/op 0.77
setNodeAtDepth depth 0 x100000 4.3003 ms/op 4.4174 ms/op 0.97
getNodesAtDepth depth 0 x100000 1.4874 ms/op 1.9455 ms/op 0.76
setNodesAtDepth depth 0 x100000 2.0892 ms/op 2.4256 ms/op 0.86
getNodeAtDepth depth 1 x100000 1.8049 ms/op 2.3653 ms/op 0.76
setNodeAtDepth depth 1 x100000 9.8646 ms/op 10.292 ms/op 0.96
getNodesAtDepth depth 1 x100000 1.7004 ms/op 2.0056 ms/op 0.85
setNodesAtDepth depth 1 x100000 7.1351 ms/op 8.2749 ms/op 0.86
getNodeAtDepth depth 2 x100000 2.3369 ms/op 2.7978 ms/op 0.84
setNodeAtDepth depth 2 x100000 16.499 ms/op 16.181 ms/op 1.02
getNodesAtDepth depth 2 x100000 29.533 ms/op 27.725 ms/op 1.07
setNodesAtDepth depth 2 x100000 21.585 ms/op 21.773 ms/op 0.99
tree.getNodesAtDepth - gindexes 7.7830 ms/op 9.4025 ms/op 0.83
tree.getNodesAtDepth - push all nodes 2.7079 ms/op 2.8365 ms/op 0.95
tree.getNodesAtDepth - navigation 177.70 us/op 169.30 us/op 1.05
tree.setNodesAtDepth - indexes 643.49 us/op 585.71 us/op 1.10
set at depth 8 889.00 ns/op 732.00 ns/op 1.21
set at depth 16 1.1460 us/op 989.00 ns/op 1.16
set at depth 32 1.8670 us/op 1.6260 us/op 1.15
iterateNodesAtDepth 8 256 22.576 us/op 22.509 us/op 1.00
getNodesAtDepth 8 256 5.3340 us/op 6.0540 us/op 0.88
iterateNodesAtDepth 16 65536 6.7779 ms/op 6.8060 ms/op 1.00
getNodesAtDepth 16 65536 2.4422 ms/op 2.6025 ms/op 0.94
iterateNodesAtDepth 32 250000 23.904 ms/op 25.211 ms/op 0.95
getNodesAtDepth 32 250000 6.3663 ms/op 7.2143 ms/op 0.88
iterateNodesAtDepth 40 250000 24.866 ms/op 25.167 ms/op 0.99
getNodesAtDepth 40 250000 6.4346 ms/op 7.1750 ms/op 0.90
250k validators 10.903 s/op 3.0091 s/op 3.62
bitlist bytes to struct (120,90) 1.0800 us/op 1.3200 us/op 0.82
bitlist bytes to tree (120,90) 3.5590 us/op 5.4550 us/op 0.65
bitlist bytes to struct (2048,2048) 1.6160 us/op 2.2790 us/op 0.71
bitlist bytes to tree (2048,2048) 6.0870 us/op 8.9530 us/op 0.68
ByteListType - deserialize 15.557 ms/op 18.686 ms/op 0.83
BasicListType - deserialize 12.151 ms/op 29.759 ms/op 0.41
ByteListType - serialize 15.684 ms/op 19.034 ms/op 0.82
BasicListType - serialize 17.371 ms/op 22.526 ms/op 0.77
BasicListType - tree_convertToStruct 32.720 ms/op 47.525 ms/op 0.69
List[uint8, 68719476736] len 300000 ViewDU.getAll() + iterate 6.1717 ms/op 5.9649 ms/op 1.03
List[uint8, 68719476736] len 300000 ViewDU.get(i) 6.0676 ms/op 6.3167 ms/op 0.96
Array.push len 300000 empty Array - number 7.5280 ms/op 8.6480 ms/op 0.87
Array.set len 300000 from new Array - number 2.2701 ms/op 2.7925 ms/op 0.81
Array.set len 300000 - number 8.2105 ms/op 8.6045 ms/op 0.95
Uint8Array.set len 300000 270.87 us/op 273.31 us/op 0.99
Uint32Array.set len 300000 382.36 us/op 430.77 us/op 0.89
Container({a: uint8, b: uint8}) getViewDU x300000 41.393 ms/op 41.985 ms/op 0.99
ContainerNodeStruct({a: uint8, b: uint8}) getViewDU x300000 13.708 ms/op 13.765 ms/op 1.00
List(Container) len 300000 ViewDU.getAllReadonly() + iterate 573.05 ms/op 401.23 ms/op 1.43
List(Container) len 300000 ViewDU.getAllReadonlyValues() + iterate 466.43 ms/op 499.20 ms/op 0.93
List(Container) len 300000 ViewDU.get(i) 10.151 ms/op 11.972 ms/op 0.85
List(Container) len 300000 ViewDU.getReadonly(i) 9.8093 ms/op 11.411 ms/op 0.86
List(ContainerNodeStruct) len 300000 ViewDU.getAllReadonly() + iterate 60.662 ms/op 60.758 ms/op 1.00
List(ContainerNodeStruct) len 300000 ViewDU.getAllReadonlyValues() + iterate 8.2013 ms/op 9.2190 ms/op 0.89
List(ContainerNodeStruct) len 300000 ViewDU.get(i) 8.2293 ms/op 10.233 ms/op 0.80
List(ContainerNodeStruct) len 300000 ViewDU.getReadonly(i) 8.0730 ms/op 10.316 ms/op 0.78
Array.push len 300000 empty Array - object 8.2148 ms/op 8.5220 ms/op 0.96
Array.set len 300000 from new Array - object 2.6622 ms/op 2.8492 ms/op 0.93
Array.set len 300000 - object 7.8095 ms/op 8.7091 ms/op 0.90
cachePermanentRootStruct no cache 13.421 us/op 12.767 us/op 1.05
cachePermanentRootStruct with cache 300.00 ns/op 297.00 ns/op 1.01
epochParticipation len 250000 rws 7813 3.5317 ms/op 3.3212 ms/op 1.06
deserialize Attestation - tree 5.4550 us/op 4.4350 us/op 1.23
deserialize Attestation - struct 3.1070 us/op 2.9130 us/op 1.07
deserialize SignedAggregateAndProof - tree 7.3620 us/op 5.7160 us/op 1.29
deserialize SignedAggregateAndProof - struct 5.1550 us/op 4.9550 us/op 1.04
deserialize SyncCommitteeMessage - tree 1.6700 us/op 1.5060 us/op 1.11
deserialize SyncCommitteeMessage - struct 1.8060 us/op 1.7940 us/op 1.01
deserialize SignedContributionAndProof - tree 3.2640 us/op 2.9000 us/op 1.13
deserialize SignedContributionAndProof - struct 4.1260 us/op 4.1330 us/op 1.00
deserialize SignedBeaconBlock - tree 420.57 us/op 325.51 us/op 1.29
deserialize SignedBeaconBlock - struct 219.90 us/op 208.22 us/op 1.06
BeaconState vc 300000 - deserialize tree 1.0357 s/op 1.0681 s/op 0.97
BeaconState vc 300000 - serialize tree 293.32 ms/op 315.85 ms/op 0.93
BeaconState.historicalRoots vc 300000 - deserialize tree 1.1150 us/op 1.1130 us/op 1.00
BeaconState.historicalRoots vc 300000 - serialize tree 1.3120 us/op 1.3020 us/op 1.01
BeaconState.validators vc 300000 - deserialize tree 1.0136 s/op 1.0370 s/op 0.98
BeaconState.validators vc 300000 - serialize tree 232.73 ms/op 265.56 ms/op 0.88
BeaconState.balances vc 300000 - deserialize tree 38.922 ms/op 39.766 ms/op 0.98
BeaconState.balances vc 300000 - serialize tree 5.4593 ms/op 6.6301 ms/op 0.82
BeaconState.previousEpochParticipation vc 300000 - deserialize tree 914.32 us/op 854.13 us/op 1.07
BeaconState.previousEpochParticipation vc 300000 - serialize tree 370.17 us/op 473.26 us/op 0.78
BeaconState.currentEpochParticipation vc 300000 - deserialize tree 956.53 us/op 825.05 us/op 1.16
BeaconState.currentEpochParticipation vc 300000 - serialize tree 374.90 us/op 470.69 us/op 0.80
BeaconState.inactivityScores vc 300000 - deserialize tree 40.434 ms/op 42.619 ms/op 0.95
BeaconState.inactivityScores vc 300000 - serialize tree 4.9872 ms/op 7.1394 ms/op 0.70
hashTreeRoot Attestation - struct 52.484 us/op 45.817 us/op 1.15
hashTreeRoot Attestation - tree 29.694 us/op 25.088 us/op 1.18
hashTreeRoot SignedAggregateAndProof - struct 72.017 us/op 61.010 us/op 1.18
hashTreeRoot SignedAggregateAndProof - tree 44.724 us/op 38.097 us/op 1.17
hashTreeRoot SyncCommitteeMessage - struct 16.596 us/op 15.127 us/op 1.10
hashTreeRoot SyncCommitteeMessage - tree 11.272 us/op 8.2870 us/op 1.36
hashTreeRoot SignedContributionAndProof - struct 45.912 us/op 43.996 us/op 1.04
hashTreeRoot SignedContributionAndProof - tree 29.890 us/op 30.016 us/op 1.00
hashTreeRoot SignedBeaconBlock - struct 4.2117 ms/op 3.6727 ms/op 1.15
hashTreeRoot SignedBeaconBlock - tree 2.5416 ms/op 2.2069 ms/op 1.15
hashTreeRoot Validator - struct 19.510 us/op 18.962 us/op 1.03
hashTreeRoot Validator - tree 16.937 us/op 15.724 us/op 1.08
BeaconState vc 300000 - hashTreeRoot tree 5.2660 s/op 5.0689 s/op 1.04
BeaconState.historicalRoots vc 300000 - hashTreeRoot tree 2.1580 us/op 1.9410 us/op 1.11
BeaconState.validators vc 300000 - hashTreeRoot tree 5.0837 s/op 4.6978 s/op 1.08
BeaconState.balances vc 300000 - hashTreeRoot tree 129.68 ms/op 124.64 ms/op 1.04
BeaconState.previousEpochParticipation vc 300000 - hashTreeRoot tree 13.175 ms/op 11.949 ms/op 1.10
BeaconState.currentEpochParticipation vc 300000 - hashTreeRoot tree 13.183 ms/op 11.949 ms/op 1.10
BeaconState.inactivityScores vc 300000 - hashTreeRoot tree 127.72 ms/op 110.62 ms/op 1.15
hash64 x18 28.269 us/op 25.028 us/op 1.13
hashTwoObjects x18 26.070 us/op 24.031 us/op 1.08
hash64 x1740 2.7332 ms/op 2.3228 ms/op 1.18
hashTwoObjects x1740 2.5575 ms/op 2.2708 ms/op 1.13
hash64 x2700000 4.3227 s/op 3.6109 s/op 1.20
hashTwoObjects x2700000 3.8582 s/op 3.5226 s/op 1.10
get_exitEpoch - ContainerType 480.00 ns/op 519.00 ns/op 0.92
get_exitEpoch - ContainerNodeStructType 394.00 ns/op 419.00 ns/op 0.94
set_exitEpoch - ContainerType 333.00 ns/op 372.00 ns/op 0.90
set_exitEpoch - ContainerNodeStructType 303.00 ns/op 313.00 ns/op 0.97
get_pubkey - ContainerType 1.5410 us/op 1.6230 us/op 0.95
get_pubkey - ContainerNodeStructType 297.00 ns/op 314.00 ns/op 0.95
hashTreeRoot - ContainerType 508.00 ns/op 491.00 ns/op 1.03
hashTreeRoot - ContainerNodeStructType 586.00 ns/op 541.00 ns/op 1.08
createProof - ContainerType 6.4860 us/op 6.6160 us/op 0.98
createProof - ContainerNodeStructType 37.571 us/op 35.031 us/op 1.07
serialize - ContainerType 2.9010 us/op 2.9560 us/op 0.98
serialize - ContainerNodeStructType 2.2590 us/op 2.3770 us/op 0.95
set_exitEpoch_and_hashTreeRoot - ContainerType 6.0590 us/op 5.7620 us/op 1.05
set_exitEpoch_and_hashTreeRoot - ContainerNodeStructType 17.011 us/op 16.008 us/op 1.06
Array - for of 6.6730 us/op 12.908 us/op 0.52
Array - for(;;) 6.5120 us/op 10.408 us/op 0.63
basicListValue.readonlyValuesArray() 4.8873 ms/op 5.4730 ms/op 0.89
basicListValue.readonlyValuesArray() + loop all 5.1665 ms/op 5.4217 ms/op 0.95
compositeListValue.readonlyValuesArray() 39.627 ms/op 39.937 ms/op 0.99
compositeListValue.readonlyValuesArray() + loop all 40.186 ms/op 34.043 ms/op 1.18
Number64UintType - get balances list 7.0314 ms/op 6.5380 ms/op 1.08
Number64UintType - set balances list 16.642 ms/op 15.554 ms/op 1.07
Number64UintType - get and increase 10 then set 62.392 ms/op 67.332 ms/op 0.93
Number64UintType - increase 10 using applyDelta 25.709 ms/op 25.473 ms/op 1.01
Number64UintType - increase 10 using applyDeltaInBatch 25.393 ms/op 25.797 ms/op 0.98
tree_newTreeFromUint64Deltas 26.069 ms/op 27.101 ms/op 0.96
unsafeUint8ArrayToTree 54.960 ms/op 49.635 ms/op 1.11
bitLength(50) 325.00 ns/op 312.00 ns/op 1.04
bitLengthStr(50) 394.00 ns/op 369.00 ns/op 1.07
bitLength(8000) 313.00 ns/op 314.00 ns/op 1.00
bitLengthStr(8000) 527.00 ns/op 503.00 ns/op 1.05
bitLength(250000) 317.00 ns/op 311.00 ns/op 1.02
bitLengthStr(250000) 630.00 ns/op 601.00 ns/op 1.05
floor - Math.floor (53) 0.59840 ns/op 0.67040 ns/op 0.89
floor - << 0 (53) 0.59584 ns/op 0.66980 ns/op 0.89
floor - Math.floor (512) 0.60160 ns/op 0.67014 ns/op 0.90
floor - << 0 (512) 0.59315 ns/op 0.67022 ns/op 0.89
fnIf(0) 1.8907 ns/op 2.6782 ns/op 0.71
fnSwitch(0) 2.9023 ns/op 5.0208 ns/op 0.58
fnObj(0) 0.60201 ns/op 0.66984 ns/op 0.90
fnArr(0) 0.58530 ns/op 0.67033 ns/op 0.87
fnIf(4) 2.7319 ns/op 4.3513 ns/op 0.63
fnSwitch(4) 2.8293 ns/op 5.0232 ns/op 0.56
fnObj(4) 0.58678 ns/op 0.66991 ns/op 0.88
fnArr(4) 0.59020 ns/op 0.67025 ns/op 0.88
fnIf(9) 3.7956 ns/op 6.6961 ns/op 0.57
fnSwitch(9) 2.8750 ns/op 5.0474 ns/op 0.57
fnObj(9) 0.58837 ns/op 0.67028 ns/op 0.88
fnArr(9) 0.59365 ns/op 0.67003 ns/op 0.89
Container {a,b,vec} - as struct x100000 59.293 us/op 67.415 us/op 0.88
Container {a,b,vec} - as tree x100000 573.98 us/op 837.15 us/op 0.69
Container {a,vec,b} - as struct x100000 91.352 us/op 100.89 us/op 0.91
Container {a,vec,b} - as tree x100000 646.76 us/op 904.28 us/op 0.72
get 2 props x1000000 - rawObject 339.72 us/op 335.26 us/op 1.01
get 2 props x1000000 - proxy 108.31 ms/op 133.43 ms/op 0.81
get 2 props x1000000 - customObj 336.58 us/op 335.29 us/op 1.00
Simple object binary -> struct 1.1670 us/op 967.00 ns/op 1.21
Simple object binary -> tree_backed 3.2290 us/op 2.7710 us/op 1.17
Simple object struct -> tree_backed 4.2320 us/op 3.7210 us/op 1.14
Simple object tree_backed -> struct 3.4310 us/op 3.0490 us/op 1.13
Simple object struct -> binary 1.7340 us/op 1.5450 us/op 1.12
Simple object tree_backed -> binary 2.9450 us/op 2.6670 us/op 1.10
aggregationBits binary -> struct 1.0870 us/op 899.00 ns/op 1.21
aggregationBits binary -> tree_backed 4.0380 us/op 3.8450 us/op 1.05
aggregationBits struct -> tree_backed 4.7830 us/op 4.6460 us/op 1.03
aggregationBits tree_backed -> struct 1.8040 us/op 1.8700 us/op 0.96
aggregationBits struct -> binary 1.2340 us/op 1.3430 us/op 0.92
aggregationBits tree_backed -> binary 1.5450 us/op 1.6430 us/op 0.94
List(uint8) 100000 binary -> struct 1.6518 ms/op 1.9585 ms/op 0.84
List(uint8) 100000 binary -> tree_backed 216.07 us/op 180.40 us/op 1.20
List(uint8) 100000 struct -> tree_backed 1.9918 ms/op 2.1614 ms/op 0.92
List(uint8) 100000 tree_backed -> struct 1.2284 ms/op 1.5327 ms/op 0.80
List(uint8) 100000 struct -> binary 1.7259 ms/op 1.9625 ms/op 0.88
List(uint8) 100000 tree_backed -> binary 126.04 us/op 143.15 us/op 0.88
List(uint64Number) 100000 binary -> struct 1.7620 ms/op 1.6757 ms/op 1.05
List(uint64Number) 100000 binary -> tree_backed 5.8711 ms/op 5.4463 ms/op 1.08
List(uint64Number) 100000 struct -> tree_backed 8.6116 ms/op 7.8345 ms/op 1.10
List(uint64Number) 100000 tree_backed -> struct 2.6378 ms/op 3.2261 ms/op 0.82
List(uint64Number) 100000 struct -> binary 2.1678 ms/op 2.3359 ms/op 0.93
List(uint64Number) 100000 tree_backed -> binary 1.1456 ms/op 1.6558 ms/op 0.69
List(Uint64Bigint) 100000 binary -> struct 5.0695 ms/op 5.3682 ms/op 0.94
List(Uint64Bigint) 100000 binary -> tree_backed 5.7363 ms/op 6.5940 ms/op 0.87
List(Uint64Bigint) 100000 struct -> tree_backed 9.3144 ms/op 9.1130 ms/op 1.02
List(Uint64Bigint) 100000 tree_backed -> struct 5.9485 ms/op 7.7943 ms/op 0.76
List(Uint64Bigint) 100000 struct -> binary 2.9031 ms/op 2.9126 ms/op 1.00
List(Uint64Bigint) 100000 tree_backed -> binary 1.1814 ms/op 1.4354 ms/op 0.82
Vector(Root) 100000 binary -> struct 56.037 ms/op 50.842 ms/op 1.10
Vector(Root) 100000 binary -> tree_backed 55.085 ms/op 52.858 ms/op 1.04
Vector(Root) 100000 struct -> tree_backed 65.781 ms/op 68.960 ms/op 0.95
Vector(Root) 100000 tree_backed -> struct 77.973 ms/op 79.664 ms/op 0.98
Vector(Root) 100000 struct -> binary 3.3147 ms/op 3.1679 ms/op 1.05
Vector(Root) 100000 tree_backed -> binary 14.349 ms/op 14.204 ms/op 1.01
List(Validator) 100000 binary -> struct 187.95 ms/op 202.13 ms/op 0.93
List(Validator) 100000 binary -> tree_backed 495.13 ms/op 517.99 ms/op 0.96
List(Validator) 100000 struct -> tree_backed 560.71 ms/op 553.03 ms/op 1.01
List(Validator) 100000 tree_backed -> struct 314.66 ms/op 322.98 ms/op 0.97
List(Validator) 100000 struct -> binary 49.334 ms/op 46.170 ms/op 1.07
List(Validator) 100000 tree_backed -> binary 142.66 ms/op 135.92 ms/op 1.05
List(Validator-NS) 100000 binary -> struct 181.03 ms/op 203.21 ms/op 0.89
List(Validator-NS) 100000 binary -> tree_backed 278.90 ms/op 282.53 ms/op 0.99
List(Validator-NS) 100000 struct -> tree_backed 333.80 ms/op 343.61 ms/op 0.97
List(Validator-NS) 100000 tree_backed -> struct 282.38 ms/op 283.61 ms/op 1.00
List(Validator-NS) 100000 struct -> binary 47.914 ms/op 46.756 ms/op 1.02
List(Validator-NS) 100000 tree_backed -> binary 62.660 ms/op 55.200 ms/op 1.14
get epochStatuses - MutableVector 134.88 us/op 121.80 us/op 1.11
get epochStatuses - ViewDU 254.98 us/op 281.36 us/op 0.91
set epochStatuses - ListTreeView 1.9199 ms/op 2.3047 ms/op 0.83
set epochStatuses - ListTreeView - set() 583.18 us/op 697.10 us/op 0.84
set epochStatuses - ListTreeView - commit() 603.24 us/op 684.86 us/op 0.88
bitstring 765.30 ns/op 768.48 ns/op 1.00
bit mask 15.135 ns/op 12.804 ns/op 1.18
struct - increase slot to 1000000 2.7919 ms/op 2.1861 ms/op 1.28
UintNumberType - increase slot to 1000000 44.252 ms/op 51.591 ms/op 0.86
UintBigintType - increase slot to 1000000 634.92 ms/op 617.89 ms/op 1.03
UintBigint8 x 100000 tree_deserialize 6.5451 ms/op 6.2157 ms/op 1.05
UintBigint8 x 100000 tree_serialize 1.9569 ms/op 2.2040 ms/op 0.89
UintBigint16 x 100000 tree_deserialize 5.8352 ms/op 5.7350 ms/op 1.02
UintBigint16 x 100000 tree_serialize 1.9563 ms/op 2.1539 ms/op 0.91
UintBigint32 x 100000 tree_deserialize 7.1316 ms/op 7.5000 ms/op 0.95
UintBigint32 x 100000 tree_serialize 1.7435 ms/op 1.9421 ms/op 0.90
UintBigint64 x 100000 tree_deserialize 8.4491 ms/op 8.0087 ms/op 1.05
UintBigint64 x 100000 tree_serialize 1.8098 ms/op 2.5548 ms/op 0.71
UintBigint8 x 100000 value_deserialize 626.38 us/op 870.87 us/op 0.72
UintBigint8 x 100000 value_serialize 1.0102 ms/op 1.3027 ms/op 0.78
UintBigint16 x 100000 value_deserialize 607.93 us/op 933.71 us/op 0.65
UintBigint16 x 100000 value_serialize 995.19 us/op 1.4075 ms/op 0.71
UintBigint32 x 100000 value_deserialize 617.42 us/op 852.20 us/op 0.72
UintBigint32 x 100000 value_serialize 1.0229 ms/op 1.4149 ms/op 0.72
UintBigint64 x 100000 value_deserialize 670.71 us/op 905.17 us/op 0.74
UintBigint64 x 100000 value_serialize 1.2359 ms/op 1.5883 ms/op 0.78
UintBigint8 x 100000 deserialize 6.7273 ms/op 6.8015 ms/op 0.99
UintBigint8 x 100000 serialize 2.2312 ms/op 2.5287 ms/op 0.88
UintBigint16 x 100000 deserialize 6.5111 ms/op 7.1703 ms/op 0.91
UintBigint16 x 100000 serialize 2.2493 ms/op 2.5192 ms/op 0.89
UintBigint32 x 100000 deserialize 8.5282 ms/op 8.1715 ms/op 1.04
UintBigint32 x 100000 serialize 4.4222 ms/op 4.3966 ms/op 1.01
UintBigint64 x 100000 deserialize 5.3191 ms/op 5.4941 ms/op 0.97
UintBigint64 x 100000 serialize 2.1783 ms/op 2.5368 ms/op 0.86
UintBigint128 x 100000 deserialize 8.1092 ms/op 8.3336 ms/op 0.97
UintBigint128 x 100000 serialize 29.001 ms/op 27.551 ms/op 1.05
UintBigint256 x 100000 deserialize 16.086 ms/op 15.755 ms/op 1.02
UintBigint256 x 100000 serialize 88.416 ms/op 83.136 ms/op 1.06
Slice from Uint8Array x25000 1.6285 ms/op 1.8364 ms/op 0.89
Slice from ArrayBuffer x25000 27.491 ms/op 30.036 ms/op 0.92
Slice from ArrayBuffer x25000 + new Uint8Array 28.967 ms/op 33.473 ms/op 0.87
Copy Uint8Array 100000 iterate 927.77 us/op 1.4873 ms/op 0.62
Copy Uint8Array 100000 slice 143.70 us/op 158.04 us/op 0.91
Copy Uint8Array 100000 Uint8Array.prototype.slice.call 136.94 us/op 149.68 us/op 0.91
Copy Buffer 100000 Uint8Array.prototype.slice.call 136.45 us/op 154.83 us/op 0.88
Copy Uint8Array 100000 slice + set 278.69 us/op 342.01 us/op 0.81
Copy Uint8Array 100000 subarray + set 143.42 us/op 148.83 us/op 0.96
Copy Uint8Array 100000 slice arrayBuffer 137.25 us/op 155.18 us/op 0.88
Uint64 deserialize 100000 - iterate Uint8Array 2.1922 ms/op 2.3467 ms/op 0.93
Uint64 deserialize 100000 - by Uint32A 1.9745 ms/op 2.2267 ms/op 0.89
Uint64 deserialize 100000 - by DataView.getUint32 x2 1.9635 ms/op 2.3098 ms/op 0.85
Uint64 deserialize 100000 - by DataView.getBigUint64 6.6633 ms/op 7.0624 ms/op 0.94
Uint64 deserialize 100000 - by byte 65.352 ms/op 69.229 ms/op 0.94

Please sign in to comment.