Skip to content

Commit

Permalink
feat: implement isomorphic utils for nodejs and browser (#7060)
Browse files Browse the repository at this point in the history
* feat: implement isomorphic utils for nodes and browser

* fix: avoid async import

* chore: revise toHexString() comment as in PR review

Co-authored-by: Nico Flaig <nflaig@protonmail.com>

---------

Co-authored-by: Nico Flaig <nflaig@protonmail.com>
  • Loading branch information
twoeths and nflaig authored Aug 30, 2024
1 parent 21afb72 commit 19ac678
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 35 deletions.
33 changes: 3 additions & 30 deletions packages/utils/src/bytes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import {toBufferLE, toBigIntLE, toBufferBE, toBigIntBE} from "bigint-buffer";
type Endianness = "le" | "be";

const hexByByte: string[] = [];
/**
* @deprecated Use toHex() instead.
*/
export function toHexString(bytes: Uint8Array): string {
let hex = "0x";
for (const byte of bytes) {
Expand Down Expand Up @@ -45,33 +48,3 @@ export function bytesToBigInt(value: Uint8Array, endianness: Endianness = "le"):
}
throw new Error("endianness must be either 'le' or 'be'");
}

export function toHex(buffer: Uint8Array | Parameters<typeof Buffer.from>[0]): string {
if (Buffer.isBuffer(buffer)) {
return "0x" + buffer.toString("hex");
} else if (buffer instanceof Uint8Array) {
return "0x" + Buffer.from(buffer.buffer, buffer.byteOffset, buffer.length).toString("hex");
} else {
return "0x" + Buffer.from(buffer).toString("hex");
}
}

// Shared buffer to convert root to hex
const rootBuf = Buffer.alloc(32);

/**
* Convert a Uint8Array, length 32, to 0x-prefixed hex string
*/
export function toRootHex(root: Uint8Array): string {
if (root.length !== 32) {
throw Error(`Expect root to be 32 bytes, got ${root.length}`);
}

rootBuf.set(root);
return `0x${rootBuf.toString("hex")}`;
}

export function fromHex(hex: string): Uint8Array {
const b = Buffer.from(hex.replace("0x", ""), "hex");
return new Uint8Array(b.buffer, b.byteOffset, b.length);
}
66 changes: 66 additions & 0 deletions packages/utils/src/bytes/browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
export function toHex(bytes: Uint8Array): string {
const charCodes = new Array<number>(bytes.length * 2 + 2);
charCodes[0] = 48;
charCodes[1] = 120;

for (let i = 0; i < bytes.length; i++) {
const byte = bytes[i];
const first = (byte & 0xf0) >> 4;
const second = byte & 0x0f;

// "0".charCodeAt(0) = 48
// "a".charCodeAt(0) = 97 => delta = 87
charCodes[2 + 2 * i] = first < 10 ? first + 48 : first + 87;
charCodes[2 + 2 * i + 1] = second < 10 ? second + 48 : second + 87;
}
return String.fromCharCode(...charCodes);
}

const rootCharCodes = new Array<number>(32 * 2 + 2);
// "0".charCodeAt(0)
rootCharCodes[0] = 48;
// "x".charCodeAt(0)
rootCharCodes[1] = 120;

/**
* Convert a Uint8Array, length 32, to 0x-prefixed hex string
*/
export function toRootHex(root: Uint8Array): string {
if (root.length !== 32) {
throw Error(`Expect root to be 32 bytes, got ${root.length}`);
}

for (let i = 0; i < root.length; i++) {
const byte = root[i];
const first = (byte & 0xf0) >> 4;
const second = byte & 0x0f;

// "0".charCodeAt(0) = 48
// "a".charCodeAt(0) = 97 => delta = 87
rootCharCodes[2 + 2 * i] = first < 10 ? first + 48 : first + 87;
rootCharCodes[2 + 2 * i + 1] = second < 10 ? second + 48 : second + 87;
}
return String.fromCharCode(...rootCharCodes);
}

export function fromHex(hex: string): Uint8Array {
if (typeof hex !== "string") {
throw new Error(`hex argument type ${typeof hex} must be of type string`);
}

if (hex.startsWith("0x")) {
hex = hex.slice(2);
}

if (hex.length % 2 !== 0) {
throw new Error(`hex string length ${hex.length} must be multiple of 2`);
}

const byteLen = hex.length / 2;
const bytes = new Uint8Array(byteLen);
for (let i = 0; i < byteLen; i++) {
const byte = parseInt(hex.slice(i * 2, (i + 1) * 2), 16);
bytes[i] = byte;
}
return bytes;
}
14 changes: 14 additions & 0 deletions packages/utils/src/bytes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {toHex as browserToHex, toRootHex as browserToRootHex, fromHex as browserFromHex} from "./browser.js";
import {toHex as nodeToHex, toRootHex as nodeToRootHex, fromHex as nodeFromHex} from "./nodejs.js";

let toHex = browserToHex;
let toRootHex = browserToRootHex;
let fromHex = browserFromHex;

if (typeof Buffer !== "undefined") {
toHex = nodeToHex;
toRootHex = nodeToRootHex;
fromHex = nodeFromHex;
}

export {toHex, toRootHex, fromHex};
33 changes: 33 additions & 0 deletions packages/utils/src/bytes/nodejs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export function toHex(buffer: Uint8Array | Parameters<typeof Buffer.from>[0]): string {
if (Buffer.isBuffer(buffer)) {
return "0x" + buffer.toString("hex");
} else if (buffer instanceof Uint8Array) {
return "0x" + Buffer.from(buffer.buffer, buffer.byteOffset, buffer.length).toString("hex");
} else {
return "0x" + Buffer.from(buffer).toString("hex");
}
}

// Shared buffer to convert root to hex
let rootBuf: Buffer | undefined;

/**
* Convert a Uint8Array, length 32, to 0x-prefixed hex string
*/
export function toRootHex(root: Uint8Array): string {
if (root.length !== 32) {
throw Error(`Expect root to be 32 bytes, got ${root.length}`);
}

if (rootBuf === undefined) {
rootBuf = Buffer.alloc(32);
}

rootBuf.set(root);
return `0x${rootBuf.toString("hex")}`;
}

export function fromHex(hex: string): Uint8Array {
const b = Buffer.from(hex.replace("0x", ""), "hex");
return new Uint8Array(b.buffer, b.byteOffset, b.length);
}
1 change: 1 addition & 0 deletions packages/utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from "./yaml/index.js";
export * from "./assert.js";
export * from "./base64.js";
export * from "./bytes.js";
export * from "./bytes/index.js";
export * from "./command.js";
export * from "./err.js";
export * from "./errors.js";
Expand Down
38 changes: 35 additions & 3 deletions packages/utils/test/perf/bytes.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {itBench} from "@dapplion/benchmark";
import {toHex, toRootHex} from "../../src/bytes.js";
import {toHex, toRootHex} from "../../src/bytes/nodejs.js";
import {toHex as browserToHex, toRootHex as browserToRootHex} from "../../src/bytes/browser.js";
import {toHexString} from "../../src/bytes.js";

describe("bytes utils", function () {
const runsFactor = 1000;
const blockRoot = new Uint8Array(Array.from({length: 32}, (_, i) => i));

itBench({
id: "block root to RootHex using toHex",
id: "nodejs block root to RootHex using toHex",
fn: () => {
for (let i = 0; i < runsFactor; i++) {
toHex(blockRoot);
Expand All @@ -16,12 +18,42 @@ describe("bytes utils", function () {
});

itBench({
id: "block root to RootHex using toRootHex",
id: "nodejs block root to RootHex using toRootHex",
fn: () => {
for (let i = 0; i < runsFactor; i++) {
toRootHex(blockRoot);
}
},
runsFactor,
});

itBench({
id: "browser block root to RootHex using the deprecated toHexString",
fn: () => {
for (let i = 0; i < runsFactor; i++) {
toHexString(blockRoot);
}
},
runsFactor,
});

itBench({
id: "browser block root to RootHex using toHex",
fn: () => {
for (let i = 0; i < runsFactor; i++) {
browserToHex(blockRoot);
}
},
runsFactor,
});

itBench({
id: "browser block root to RootHex using toRootHex",
fn: () => {
for (let i = 0; i < runsFactor; i++) {
browserToRootHex(blockRoot);
}
},
runsFactor,
});
});
23 changes: 21 additions & 2 deletions packages/utils/test/unit/bytes.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {describe, it, expect} from "vitest";
import {intToBytes, bytesToInt, toHex, fromHex, toHexString} from "../../src/index.js";
import {intToBytes, bytesToInt, toHex, fromHex, toHexString, toRootHex} from "../../src/index.js";

describe("intToBytes", () => {
const zeroedArray = (length: number): number[] => Array.from({length}, () => 0);
Expand Down Expand Up @@ -48,7 +48,7 @@ describe("bytesToInt", () => {
});

describe("toHex", () => {
const testCases: {input: Buffer | Uint8Array | string; output: string}[] = [
const testCases: {input: Uint8Array; output: string}[] = [
{input: Buffer.from("Hello, World!", "utf-8"), output: "0x48656c6c6f2c20576f726c6421"},
{input: new Uint8Array([72, 101, 108, 108, 111]), output: "0x48656c6c6f"},
{input: Buffer.from([72, 101, 108, 108, 111]), output: "0x48656c6c6f"},
Expand All @@ -61,6 +61,25 @@ describe("toHex", () => {
}
});

describe("toRootHex", () => {
const testCases: {input: Uint8Array; output: string}[] = [
{
input: new Uint8Array(Array.from({length: 32}, (_, i) => i)),
output: "0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
},
{
input: new Uint8Array(Array.from({length: 32}, () => 0)),
output: "0x0000000000000000000000000000000000000000000000000000000000000000",
},
];

for (const {input, output} of testCases) {
it(`should convert root to hex string ${output}`, () => {
expect(toRootHex(input)).toBe(output);
});
}
});

describe("fromHex", () => {
const testCases: {input: string; output: Buffer | Uint8Array}[] = [
{
Expand Down

1 comment on commit 19ac678

@github-actions
Copy link
Contributor

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: 19ac678 Previous: 21afb72 Ratio
Object access 1 prop 0.33000 ns/op 0.10700 ns/op 3.08
Map access 1 prop 0.33100 ns/op 0.10000 ns/op 3.31
Full benchmark results
Benchmark suite Current: 19ac678 Previous: 21afb72 Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 2.8321 ms/op 1.7655 ms/op 1.60
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 67.494 us/op 38.773 us/op 1.74
BLS verify - blst 848.04 us/op 842.45 us/op 1.01
BLS verifyMultipleSignatures 3 - blst 1.3035 ms/op 1.2694 ms/op 1.03
BLS verifyMultipleSignatures 8 - blst 1.8701 ms/op 2.0701 ms/op 0.90
BLS verifyMultipleSignatures 32 - blst 5.3396 ms/op 4.3696 ms/op 1.22
BLS verifyMultipleSignatures 64 - blst 9.8476 ms/op 8.0967 ms/op 1.22
BLS verifyMultipleSignatures 128 - blst 17.476 ms/op 15.742 ms/op 1.11
BLS deserializing 10000 signatures 637.59 ms/op 619.29 ms/op 1.03
BLS deserializing 100000 signatures 6.3941 s/op 6.2046 s/op 1.03
BLS verifyMultipleSignatures - same message - 3 - blst 967.98 us/op 925.73 us/op 1.05
BLS verifyMultipleSignatures - same message - 8 - blst 1.0840 ms/op 1.0608 ms/op 1.02
BLS verifyMultipleSignatures - same message - 32 - blst 1.6580 ms/op 1.6455 ms/op 1.01
BLS verifyMultipleSignatures - same message - 64 - blst 2.4772 ms/op 2.5029 ms/op 0.99
BLS verifyMultipleSignatures - same message - 128 - blst 4.0416 ms/op 4.1014 ms/op 0.99
BLS aggregatePubkeys 32 - blst 18.894 us/op 17.538 us/op 1.08
BLS aggregatePubkeys 128 - blst 64.499 us/op 62.298 us/op 1.04
notSeenSlots=1 numMissedVotes=1 numBadVotes=10 61.472 ms/op 45.155 ms/op 1.36
notSeenSlots=1 numMissedVotes=0 numBadVotes=4 57.203 ms/op 45.053 ms/op 1.27
notSeenSlots=2 numMissedVotes=1 numBadVotes=10 31.743 ms/op 31.066 ms/op 1.02
getSlashingsAndExits - default max 86.169 us/op 64.008 us/op 1.35
getSlashingsAndExits - 2k 304.34 us/op 225.96 us/op 1.35
proposeBlockBody type=full, size=empty 5.0533 ms/op 5.3454 ms/op 0.95
isKnown best case - 1 super set check 511.00 ns/op 228.00 ns/op 2.24
isKnown normal case - 2 super set checks 500.00 ns/op 215.00 ns/op 2.33
isKnown worse case - 16 super set checks 507.00 ns/op 215.00 ns/op 2.36
InMemoryCheckpointStateCache - add get delete 3.1310 us/op 2.0790 us/op 1.51
updateUnfinalizedPubkeys - updating 10 pubkeys 448.06 us/op 564.31 us/op 0.79
updateUnfinalizedPubkeys - updating 100 pubkeys 2.2140 ms/op 2.1378 ms/op 1.04
updateUnfinalizedPubkeys - updating 1000 pubkeys 40.379 ms/op 38.645 ms/op 1.04
validate api signedAggregateAndProof - struct 1.6546 ms/op 1.8891 ms/op 0.88
validate gossip signedAggregateAndProof - struct 1.5846 ms/op 1.8800 ms/op 0.84
validate gossip attestation - vc 640000 986.09 us/op 946.53 us/op 1.04
batch validate gossip attestation - vc 640000 - chunk 32 136.31 us/op 118.72 us/op 1.15
batch validate gossip attestation - vc 640000 - chunk 64 124.58 us/op 103.07 us/op 1.21
batch validate gossip attestation - vc 640000 - chunk 128 105.41 us/op 94.226 us/op 1.12
batch validate gossip attestation - vc 640000 - chunk 256 99.958 us/op 92.051 us/op 1.09
pickEth1Vote - no votes 861.83 us/op 893.82 us/op 0.96
pickEth1Vote - max votes 4.3587 ms/op 5.0441 ms/op 0.86
pickEth1Vote - Eth1Data hashTreeRoot value x2048 10.193 ms/op 14.600 ms/op 0.70
pickEth1Vote - Eth1Data hashTreeRoot tree x2048 13.310 ms/op 19.473 ms/op 0.68
pickEth1Vote - Eth1Data fastSerialize value x2048 363.20 us/op 378.39 us/op 0.96
pickEth1Vote - Eth1Data fastSerialize tree x2048 2.0327 ms/op 3.7545 ms/op 0.54
bytes32 toHexString 592.00 ns/op 345.00 ns/op 1.72
bytes32 Buffer.toString(hex) 446.00 ns/op 189.00 ns/op 2.36
bytes32 Buffer.toString(hex) from Uint8Array 538.00 ns/op 278.00 ns/op 1.94
bytes32 Buffer.toString(hex) + 0x 453.00 ns/op 188.00 ns/op 2.41
Object access 1 prop 0.33000 ns/op 0.10700 ns/op 3.08
Map access 1 prop 0.33100 ns/op 0.10000 ns/op 3.31
Object get x1000 5.1880 ns/op 5.0390 ns/op 1.03
Map get x1000 6.1030 ns/op 5.6550 ns/op 1.08
Object set x1000 22.634 ns/op 22.387 ns/op 1.01
Map set x1000 19.357 ns/op 18.426 ns/op 1.05
Return object 10000 times 0.30150 ns/op 0.27690 ns/op 1.09
Throw Error 10000 times 2.6919 us/op 2.6987 us/op 1.00
toHex 109.48 ns/op 94.482 ns/op 1.16
Buffer.from 104.16 ns/op 87.664 ns/op 1.19
shared Buffer 69.938 ns/op 60.900 ns/op 1.15
fastMsgIdFn sha256 / 200 bytes 2.0060 us/op 1.5270 us/op 1.31
fastMsgIdFn h32 xxhash / 200 bytes 419.00 ns/op 165.00 ns/op 2.54
fastMsgIdFn h64 xxhash / 200 bytes 449.00 ns/op 187.00 ns/op 2.40
fastMsgIdFn sha256 / 1000 bytes 5.8630 us/op 5.1410 us/op 1.14
fastMsgIdFn h32 xxhash / 1000 bytes 538.00 ns/op 270.00 ns/op 1.99
fastMsgIdFn h64 xxhash / 1000 bytes 514.00 ns/op 248.00 ns/op 2.07
fastMsgIdFn sha256 / 10000 bytes 49.293 us/op 43.658 us/op 1.13
fastMsgIdFn h32 xxhash / 10000 bytes 1.8950 us/op 1.4750 us/op 1.28
fastMsgIdFn h64 xxhash / 10000 bytes 1.3280 us/op 957.00 ns/op 1.39
send data - 1000 256B messages 9.6281 ms/op 9.6742 ms/op 1.00
send data - 1000 512B messages 13.622 ms/op 13.129 ms/op 1.04
send data - 1000 1024B messages 20.433 ms/op 20.261 ms/op 1.01
send data - 1000 1200B messages 23.685 ms/op 22.173 ms/op 1.07
send data - 1000 2048B messages 30.508 ms/op 26.575 ms/op 1.15
send data - 1000 4096B messages 27.505 ms/op 24.949 ms/op 1.10
send data - 1000 16384B messages 72.192 ms/op 56.262 ms/op 1.28
send data - 1000 65536B messages 246.77 ms/op 164.53 ms/op 1.50
enrSubnets - fastDeserialize 64 bits 1.1560 us/op 814.00 ns/op 1.42
enrSubnets - ssz BitVector 64 bits 521.00 ns/op 268.00 ns/op 1.94
enrSubnets - fastDeserialize 4 bits 342.00 ns/op 116.00 ns/op 2.95
enrSubnets - ssz BitVector 4 bits 527.00 ns/op 270.00 ns/op 1.95
prioritizePeers score -10:0 att 32-0.1 sync 2-0 108.45 us/op 117.47 us/op 0.92
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 133.26 us/op 154.10 us/op 0.86
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 187.65 us/op 223.74 us/op 0.84
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 330.36 us/op 439.04 us/op 0.75
prioritizePeers score 0:0 att 64-1 sync 4-1 400.94 us/op 574.68 us/op 0.70
array of 16000 items push then shift 1.2120 us/op 1.2956 us/op 0.94
LinkedList of 16000 items push then shift 7.1240 ns/op 6.0880 ns/op 1.17
array of 16000 items push then pop 79.404 ns/op 78.637 ns/op 1.01
LinkedList of 16000 items push then pop 6.0520 ns/op 5.9500 ns/op 1.02
array of 24000 items push then shift 1.7675 us/op 1.9037 us/op 0.93
LinkedList of 24000 items push then shift 6.7080 ns/op 6.0160 ns/op 1.12
array of 24000 items push then pop 102.47 ns/op 105.13 ns/op 0.97
LinkedList of 24000 items push then pop 6.0500 ns/op 5.8560 ns/op 1.03
intersect bitArray bitLen 8 5.1640 ns/op 5.2330 ns/op 0.99
intersect array and set length 8 35.474 ns/op 37.804 ns/op 0.94
intersect bitArray bitLen 128 25.498 ns/op 26.340 ns/op 0.97
intersect array and set length 128 573.44 ns/op 576.58 ns/op 0.99
bitArray.getTrueBitIndexes() bitLen 128 1.3960 us/op 1.9600 us/op 0.71
bitArray.getTrueBitIndexes() bitLen 248 2.0690 us/op 3.2810 us/op 0.63
bitArray.getTrueBitIndexes() bitLen 512 3.7920 us/op 6.4010 us/op 0.59
Buffer.concat 32 items 1.0110 us/op 796.00 ns/op 1.27
Uint8Array.set 32 items 2.0080 us/op 1.7410 us/op 1.15
Buffer.copy 1.8130 us/op 2.0440 us/op 0.89
Uint8Array.set - with subarray 1.8720 us/op 2.2720 us/op 0.82
Uint8Array.set - without subarray 1.4190 us/op 1.4010 us/op 1.01
getUint32 - dataview 406.00 ns/op 169.00 ns/op 2.40
getUint32 - manual 332.00 ns/op 112.00 ns/op 2.96
Set add up to 64 items then delete first 1.7552 us/op 1.7566 us/op 1.00
OrderedSet add up to 64 items then delete first 2.7300 us/op 2.7040 us/op 1.01
Set add up to 64 items then delete last 2.0480 us/op 2.0801 us/op 0.98
OrderedSet add up to 64 items then delete last 3.1501 us/op 2.6716 us/op 1.18
Set add up to 64 items then delete middle 2.0454 us/op 1.8286 us/op 1.12
OrderedSet add up to 64 items then delete middle 4.5576 us/op 3.9290 us/op 1.16
Set add up to 128 items then delete first 3.9423 us/op 3.4960 us/op 1.13
OrderedSet add up to 128 items then delete first 5.8989 us/op 5.4790 us/op 1.08
Set add up to 128 items then delete last 3.9290 us/op 3.4010 us/op 1.16
OrderedSet add up to 128 items then delete last 6.1054 us/op 5.1321 us/op 1.19
Set add up to 128 items then delete middle 3.9268 us/op 3.4089 us/op 1.15
OrderedSet add up to 128 items then delete middle 11.927 us/op 10.483 us/op 1.14
Set add up to 256 items then delete first 7.2082 us/op 6.8948 us/op 1.05
OrderedSet add up to 256 items then delete first 11.164 us/op 11.019 us/op 1.01
Set add up to 256 items then delete last 7.2220 us/op 6.7490 us/op 1.07
OrderedSet add up to 256 items then delete last 11.530 us/op 10.398 us/op 1.11
Set add up to 256 items then delete middle 7.1636 us/op 6.7092 us/op 1.07
OrderedSet add up to 256 items then delete middle 32.853 us/op 30.617 us/op 1.07
transfer serialized Status (84 B) 1.5540 us/op 1.1440 us/op 1.36
copy serialized Status (84 B) 1.3360 us/op 993.00 ns/op 1.35
transfer serialized SignedVoluntaryExit (112 B) 1.6770 us/op 1.4790 us/op 1.13
copy serialized SignedVoluntaryExit (112 B) 1.4590 us/op 1.1190 us/op 1.30
transfer serialized ProposerSlashing (416 B) 2.5100 us/op 1.7200 us/op 1.46
copy serialized ProposerSlashing (416 B) 2.5390 us/op 1.9030 us/op 1.33
transfer serialized Attestation (485 B) 2.3670 us/op 1.5240 us/op 1.55
copy serialized Attestation (485 B) 2.4590 us/op 1.7810 us/op 1.38
transfer serialized AttesterSlashing (33232 B) 2.7370 us/op 2.5410 us/op 1.08
copy serialized AttesterSlashing (33232 B) 5.0920 us/op 4.2170 us/op 1.21
transfer serialized Small SignedBeaconBlock (128000 B) 2.7930 us/op 2.7390 us/op 1.02
copy serialized Small SignedBeaconBlock (128000 B) 14.499 us/op 12.335 us/op 1.18
transfer serialized Avg SignedBeaconBlock (200000 B) 2.5670 us/op 2.3550 us/op 1.09
copy serialized Avg SignedBeaconBlock (200000 B) 12.072 us/op 11.834 us/op 1.02
transfer serialized BlobsSidecar (524380 B) 2.5980 us/op 2.2380 us/op 1.16
copy serialized BlobsSidecar (524380 B) 102.70 us/op 68.986 us/op 1.49
transfer serialized Big SignedBeaconBlock (1000000 B) 3.3070 us/op 2.5990 us/op 1.27
copy serialized Big SignedBeaconBlock (1000000 B) 137.54 us/op 137.20 us/op 1.00
pass gossip attestations to forkchoice per slot 2.4148 ms/op 2.4335 ms/op 0.99
forkChoice updateHead vc 100000 bc 64 eq 0 406.49 us/op 493.01 us/op 0.82
forkChoice updateHead vc 600000 bc 64 eq 0 2.4888 ms/op 2.4397 ms/op 1.02
forkChoice updateHead vc 1000000 bc 64 eq 0 4.0793 ms/op 4.2162 ms/op 0.97
forkChoice updateHead vc 600000 bc 320 eq 0 2.3563 ms/op 2.5426 ms/op 0.93
forkChoice updateHead vc 600000 bc 1200 eq 0 2.3778 ms/op 3.1266 ms/op 0.76
forkChoice updateHead vc 600000 bc 7200 eq 0 2.8583 ms/op 2.8391 ms/op 1.01
forkChoice updateHead vc 600000 bc 64 eq 1000 9.1681 ms/op 8.8821 ms/op 1.03
forkChoice updateHead vc 600000 bc 64 eq 10000 9.0124 ms/op 9.5579 ms/op 0.94
forkChoice updateHead vc 600000 bc 64 eq 300000 10.988 ms/op 11.684 ms/op 0.94
computeDeltas 500000 validators 300 proto nodes 2.9131 ms/op 2.9960 ms/op 0.97
computeDeltas 500000 validators 1200 proto nodes 2.9822 ms/op 3.0738 ms/op 0.97
computeDeltas 500000 validators 7200 proto nodes 3.0487 ms/op 2.9491 ms/op 1.03
computeDeltas 750000 validators 300 proto nodes 4.6492 ms/op 4.4889 ms/op 1.04
computeDeltas 750000 validators 1200 proto nodes 4.5435 ms/op 4.3873 ms/op 1.04
computeDeltas 750000 validators 7200 proto nodes 4.6144 ms/op 4.3908 ms/op 1.05
computeDeltas 1400000 validators 300 proto nodes 8.7679 ms/op 8.0745 ms/op 1.09
computeDeltas 1400000 validators 1200 proto nodes 8.8281 ms/op 8.1693 ms/op 1.08
computeDeltas 1400000 validators 7200 proto nodes 8.7140 ms/op 8.0097 ms/op 1.09
computeDeltas 2100000 validators 300 proto nodes 13.373 ms/op 12.190 ms/op 1.10
computeDeltas 2100000 validators 1200 proto nodes 13.379 ms/op 12.008 ms/op 1.11
computeDeltas 2100000 validators 7200 proto nodes 13.010 ms/op 12.214 ms/op 1.07
altair processAttestation - 250000 vs - 7PWei normalcase 1.4445 ms/op 1.3669 ms/op 1.06
altair processAttestation - 250000 vs - 7PWei worstcase 2.1422 ms/op 2.0237 ms/op 1.06
altair processAttestation - setStatus - 1/6 committees join 79.887 us/op 58.187 us/op 1.37
altair processAttestation - setStatus - 1/3 committees join 144.41 us/op 111.60 us/op 1.29
altair processAttestation - setStatus - 1/2 committees join 211.25 us/op 166.59 us/op 1.27
altair processAttestation - setStatus - 2/3 committees join 277.98 us/op 216.88 us/op 1.28
altair processAttestation - setStatus - 4/5 committees join 389.94 us/op 344.31 us/op 1.13
altair processAttestation - setStatus - 100% committees join 468.08 us/op 416.78 us/op 1.12
altair processBlock - 250000 vs - 7PWei normalcase 3.7004 ms/op 4.0658 ms/op 0.91
altair processBlock - 250000 vs - 7PWei normalcase hashState 24.910 ms/op 25.434 ms/op 0.98
altair processBlock - 250000 vs - 7PWei worstcase 35.160 ms/op 37.526 ms/op 0.94
altair processBlock - 250000 vs - 7PWei worstcase hashState 67.930 ms/op 73.195 ms/op 0.93
phase0 processBlock - 250000 vs - 7PWei normalcase 1.8277 ms/op 1.9371 ms/op 0.94
phase0 processBlock - 250000 vs - 7PWei worstcase 21.938 ms/op 22.379 ms/op 0.98
altair processEth1Data - 250000 vs - 7PWei normalcase 243.91 us/op 229.75 us/op 1.06
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:15 6.7210 us/op 5.4440 us/op 1.23
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:219 38.024 us/op 33.978 us/op 1.12
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:42 12.144 us/op 8.7480 us/op 1.39
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:18 6.7360 us/op 6.0420 us/op 1.11
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1020 149.58 us/op 143.88 us/op 1.04
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11777 953.99 us/op 876.22 us/op 1.09
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 1.3125 ms/op 1.3389 ms/op 0.98
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 1.3012 ms/op 1.3691 ms/op 0.95
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 3.0356 ms/op 2.6302 ms/op 1.15
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 1.3580 ms/op 1.3973 ms/op 0.97
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 3.0768 ms/op 3.0644 ms/op 1.00
Tree 40 250000 create 183.32 ms/op 188.32 ms/op 0.97
Tree 40 250000 get(125000) 105.83 ns/op 112.94 ns/op 0.94
Tree 40 250000 set(125000) 584.64 ns/op 512.97 ns/op 1.14
Tree 40 250000 toArray() 12.865 ms/op 9.6627 ms/op 1.33
Tree 40 250000 iterate all - toArray() + loop 9.6578 ms/op 9.6478 ms/op 1.00
Tree 40 250000 iterate all - get(i) 43.002 ms/op 38.873 ms/op 1.11
Array 250000 create 2.4141 ms/op 2.2916 ms/op 1.05
Array 250000 clone - spread 1.2351 ms/op 1.1744 ms/op 1.05
Array 250000 get(125000) 0.62200 ns/op 0.37400 ns/op 1.66
Array 250000 set(125000) 0.61400 ns/op 0.38200 ns/op 1.61
Array 250000 iterate all - loop 75.278 us/op 76.145 us/op 0.99
phase0 afterProcessEpoch - 250000 vs - 7PWei 82.033 ms/op 75.940 ms/op 1.08
Array.fill - length 1000000 2.5026 ms/op 2.4840 ms/op 1.01
Array push - length 1000000 14.611 ms/op 13.893 ms/op 1.05
Array.get 0.25809 ns/op 0.23831 ns/op 1.08
Uint8Array.get 0.32784 ns/op 0.30729 ns/op 1.07
phase0 beforeProcessEpoch - 250000 vs - 7PWei 14.794 ms/op 14.863 ms/op 1.00
altair processEpoch - mainnet_e81889 276.46 ms/op 316.11 ms/op 0.87
mainnet_e81889 - altair beforeProcessEpoch 18.737 ms/op 15.908 ms/op 1.18
mainnet_e81889 - altair processJustificationAndFinalization 9.3150 us/op 10.022 us/op 0.93
mainnet_e81889 - altair processInactivityUpdates 4.7977 ms/op 4.0255 ms/op 1.19
mainnet_e81889 - altair processRewardsAndPenalties 54.563 ms/op 52.940 ms/op 1.03
mainnet_e81889 - altair processRegistryUpdates 1.9330 us/op 1.3490 us/op 1.43
mainnet_e81889 - altair processSlashings 760.00 ns/op 375.00 ns/op 2.03
mainnet_e81889 - altair processEth1DataReset 771.00 ns/op 319.00 ns/op 2.42
mainnet_e81889 - altair processEffectiveBalanceUpdates 1.7678 ms/op 1.4875 ms/op 1.19
mainnet_e81889 - altair processSlashingsReset 3.3310 us/op 1.0450 us/op 3.19
mainnet_e81889 - altair processRandaoMixesReset 4.1960 us/op 2.1130 us/op 1.99
mainnet_e81889 - altair processHistoricalRootsUpdate 575.00 ns/op 238.00 ns/op 2.42
mainnet_e81889 - altair processParticipationFlagUpdates 2.0970 us/op 900.00 ns/op 2.33
mainnet_e81889 - altair processSyncCommitteeUpdates 729.00 ns/op 211.00 ns/op 3.45
mainnet_e81889 - altair afterProcessEpoch 82.792 ms/op 79.320 ms/op 1.04
capella processEpoch - mainnet_e217614 1.2556 s/op 1.0768 s/op 1.17
mainnet_e217614 - capella beforeProcessEpoch 78.466 ms/op 74.585 ms/op 1.05
mainnet_e217614 - capella processJustificationAndFinalization 18.625 us/op 11.859 us/op 1.57
mainnet_e217614 - capella processInactivityUpdates 12.605 ms/op 14.360 ms/op 0.88
mainnet_e217614 - capella processRewardsAndPenalties 254.58 ms/op 251.28 ms/op 1.01
mainnet_e217614 - capella processRegistryUpdates 14.403 us/op 11.281 us/op 1.28
mainnet_e217614 - capella processSlashings 944.00 ns/op 396.00 ns/op 2.38
mainnet_e217614 - capella processEth1DataReset 879.00 ns/op 321.00 ns/op 2.74
mainnet_e217614 - capella processEffectiveBalanceUpdates 14.825 ms/op 12.405 ms/op 1.20
mainnet_e217614 - capella processSlashingsReset 3.4900 us/op 1.9560 us/op 1.78
mainnet_e217614 - capella processRandaoMixesReset 8.5700 us/op 5.8810 us/op 1.46
mainnet_e217614 - capella processHistoricalRootsUpdate 786.00 ns/op 313.00 ns/op 2.51
mainnet_e217614 - capella processParticipationFlagUpdates 2.0430 us/op 1.0040 us/op 2.03
mainnet_e217614 - capella afterProcessEpoch 208.76 ms/op 200.04 ms/op 1.04
phase0 processEpoch - mainnet_e58758 325.79 ms/op 388.84 ms/op 0.84
mainnet_e58758 - phase0 beforeProcessEpoch 91.970 ms/op 77.377 ms/op 1.19
mainnet_e58758 - phase0 processJustificationAndFinalization 22.940 us/op 13.432 us/op 1.71
mainnet_e58758 - phase0 processRewardsAndPenalties 33.206 ms/op 29.953 ms/op 1.11
mainnet_e58758 - phase0 processRegistryUpdates 8.2160 us/op 6.6010 us/op 1.24
mainnet_e58758 - phase0 processSlashings 982.00 ns/op 424.00 ns/op 2.32
mainnet_e58758 - phase0 processEth1DataReset 749.00 ns/op 247.00 ns/op 3.03
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 904.00 us/op 1.3599 ms/op 0.66
mainnet_e58758 - phase0 processSlashingsReset 5.0950 us/op 1.7700 us/op 2.88
mainnet_e58758 - phase0 processRandaoMixesReset 6.9090 us/op 2.1380 us/op 3.23
mainnet_e58758 - phase0 processHistoricalRootsUpdate 1.0630 us/op 254.00 ns/op 4.19
mainnet_e58758 - phase0 processParticipationRecordUpdates 6.3480 us/op 2.5140 us/op 2.53
mainnet_e58758 - phase0 afterProcessEpoch 75.695 ms/op 62.627 ms/op 1.21
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.0299 ms/op 1.0438 ms/op 0.99
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 1.8412 ms/op 1.5435 ms/op 1.19
altair processInactivityUpdates - 250000 normalcase 16.875 ms/op 19.725 ms/op 0.86
altair processInactivityUpdates - 250000 worstcase 17.897 ms/op 18.338 ms/op 0.98
phase0 processRegistryUpdates - 250000 normalcase 6.2260 us/op 2.8220 us/op 2.21
phase0 processRegistryUpdates - 250000 badcase_full_deposits 204.89 us/op 185.20 us/op 1.11
phase0 processRegistryUpdates - 250000 worstcase 0.5 124.66 ms/op 114.78 ms/op 1.09
altair processRewardsAndPenalties - 250000 normalcase 41.047 ms/op 44.824 ms/op 0.92
altair processRewardsAndPenalties - 250000 worstcase 40.325 ms/op 39.060 ms/op 1.03
phase0 getAttestationDeltas - 250000 normalcase 7.8367 ms/op 5.5106 ms/op 1.42
phase0 getAttestationDeltas - 250000 worstcase 8.3045 ms/op 6.4599 ms/op 1.29
phase0 processSlashings - 250000 worstcase 96.218 us/op 85.758 us/op 1.12
altair processSyncCommitteeUpdates - 250000 112.40 ms/op 105.88 ms/op 1.06
BeaconState.hashTreeRoot - No change 485.00 ns/op 211.00 ns/op 2.30
BeaconState.hashTreeRoot - 1 full validator 102.89 us/op 127.19 us/op 0.81
BeaconState.hashTreeRoot - 32 full validator 1.2056 ms/op 1.5365 ms/op 0.78
BeaconState.hashTreeRoot - 512 full validator 12.707 ms/op 15.801 ms/op 0.80
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 163.61 us/op 153.17 us/op 1.07
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.9054 ms/op 1.8542 ms/op 1.03
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 22.771 ms/op 27.309 ms/op 0.83
BeaconState.hashTreeRoot - 1 balances 101.71 us/op 123.78 us/op 0.82
BeaconState.hashTreeRoot - 32 balances 1.0436 ms/op 1.3085 ms/op 0.80
BeaconState.hashTreeRoot - 512 balances 9.1315 ms/op 11.505 ms/op 0.79
BeaconState.hashTreeRoot - 250000 balances 154.59 ms/op 158.85 ms/op 0.97
aggregationBits - 2048 els - zipIndexesInBitList 21.989 us/op 18.532 us/op 1.19
byteArrayEquals 32 49.146 ns/op 46.923 ns/op 1.05
Buffer.compare 32 15.658 ns/op 15.335 ns/op 1.02
byteArrayEquals 1024 1.2916 us/op 1.2542 us/op 1.03
Buffer.compare 1024 23.384 ns/op 23.068 ns/op 1.01
byteArrayEquals 16384 20.478 us/op 19.890 us/op 1.03
Buffer.compare 16384 206.85 ns/op 194.65 ns/op 1.06
byteArrayEquals 123687377 153.71 ms/op 150.25 ms/op 1.02
Buffer.compare 123687377 6.2576 ms/op 3.6677 ms/op 1.71
byteArrayEquals 32 - diff last byte 47.822 ns/op 46.804 ns/op 1.02
Buffer.compare 32 - diff last byte 15.783 ns/op 15.936 ns/op 0.99
byteArrayEquals 1024 - diff last byte 1.2695 us/op 1.2493 us/op 1.02
Buffer.compare 1024 - diff last byte 23.918 ns/op 24.006 ns/op 1.00
byteArrayEquals 16384 - diff last byte 20.394 us/op 19.862 us/op 1.03
Buffer.compare 16384 - diff last byte 181.71 ns/op 176.51 ns/op 1.03
byteArrayEquals 123687377 - diff last byte 153.32 ms/op 140.90 ms/op 1.09
Buffer.compare 123687377 - diff last byte 5.0693 ms/op 5.3437 ms/op 0.95
byteArrayEquals 32 - random bytes 5.0750 ns/op 4.3790 ns/op 1.16
Buffer.compare 32 - random bytes 15.975 ns/op 14.270 ns/op 1.12
byteArrayEquals 1024 - random bytes 5.0320 ns/op 4.3420 ns/op 1.16
Buffer.compare 1024 - random bytes 15.847 ns/op 14.467 ns/op 1.10
byteArrayEquals 16384 - random bytes 5.0220 ns/op 4.3280 ns/op 1.16
Buffer.compare 16384 - random bytes 15.735 ns/op 13.957 ns/op 1.13
byteArrayEquals 123687377 - random bytes 7.9400 ns/op 5.2200 ns/op 1.52
Buffer.compare 123687377 - random bytes 18.810 ns/op 14.870 ns/op 1.26
regular array get 100000 times 31.163 us/op 28.041 us/op 1.11
wrappedArray get 100000 times 31.342 us/op 28.069 us/op 1.12
arrayWithProxy get 100000 times 10.485 ms/op 9.0282 ms/op 1.16
ssz.Root.equals 44.735 ns/op 40.615 ns/op 1.10
byteArrayEquals 42.979 ns/op 39.826 ns/op 1.08
Buffer.compare 9.1590 ns/op 8.1280 ns/op 1.13
shuffle list - 16384 els 5.5541 ms/op 4.9683 ms/op 1.12
shuffle list - 250000 els 82.730 ms/op 73.424 ms/op 1.13
processSlot - 1 slots 12.760 us/op 12.192 us/op 1.05
processSlot - 32 slots 3.5015 ms/op 3.6279 ms/op 0.97
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 37.301 ms/op 43.537 ms/op 0.86
getCommitteeAssignments - req 1 vs - 250000 vc 1.8823 ms/op 1.8008 ms/op 1.05
getCommitteeAssignments - req 100 vs - 250000 vc 3.6017 ms/op 3.5057 ms/op 1.03
getCommitteeAssignments - req 1000 vs - 250000 vc 3.9432 ms/op 3.7704 ms/op 1.05
findModifiedValidators - 10000 modified validators 267.56 ms/op 224.17 ms/op 1.19
findModifiedValidators - 1000 modified validators 182.76 ms/op 137.47 ms/op 1.33
findModifiedValidators - 100 modified validators 201.29 ms/op 134.39 ms/op 1.50
findModifiedValidators - 10 modified validators 172.95 ms/op 126.17 ms/op 1.37
findModifiedValidators - 1 modified validators 190.95 ms/op 120.35 ms/op 1.59
findModifiedValidators - no difference 187.88 ms/op 136.94 ms/op 1.37
compare ViewDUs 3.2009 s/op 2.9474 s/op 1.09
compare each validator Uint8Array 1.4094 s/op 1.7321 s/op 0.81
compare ViewDU to Uint8Array 1.1720 s/op 734.24 ms/op 1.60
migrate state 1000000 validators, 24 modified, 0 new 713.04 ms/op 601.34 ms/op 1.19
migrate state 1000000 validators, 1700 modified, 1000 new 932.08 ms/op 856.82 ms/op 1.09
migrate state 1000000 validators, 3400 modified, 2000 new 1.0690 s/op 1.0524 s/op 1.02
migrate state 1500000 validators, 24 modified, 0 new 628.50 ms/op 602.63 ms/op 1.04
migrate state 1500000 validators, 1700 modified, 1000 new 832.72 ms/op 860.33 ms/op 0.97
migrate state 1500000 validators, 3400 modified, 2000 new 938.73 ms/op 1.0565 s/op 0.89
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 6.4400 ns/op 3.5300 ns/op 1.82
state getBlockRootAtSlot - 250000 vs - 7PWei 774.91 ns/op 850.73 ns/op 0.91
computeProposers - vc 250000 6.9285 ms/op 6.4893 ms/op 1.07
computeEpochShuffling - vc 250000 79.670 ms/op 79.458 ms/op 1.00
getNextSyncCommittee - vc 250000 105.94 ms/op 106.70 ms/op 0.99
computeSigningRoot for AttestationData 20.197 us/op 20.726 us/op 0.97
hash AttestationData serialized data then Buffer.toString(base64) 1.1852 us/op 1.1666 us/op 1.02
toHexString serialized data 759.79 ns/op 796.82 ns/op 0.95
Buffer.toString(base64) 145.27 ns/op 141.75 ns/op 1.02
nodejs block root to RootHex using toHex 109.66 ns/op
nodejs block root to RootHex using toRootHex 71.774 ns/op
browser block root to RootHex using the deprecated toHexString 204.17 ns/op
browser block root to RootHex using toHex 161.10 ns/op
browser block root to RootHex using toRootHex 148.93 ns/op

Please sign in to comment.