Skip to content

Commit

Permalink
refactor: update snappy frame decompress (#7333)
Browse files Browse the repository at this point in the history
* refactor: update snappy frame decompress

* chore: fix lint errors

* chore: separate code paths for ChunkTypes
  • Loading branch information
wemeetagain authored Jan 8, 2025
1 parent 877b1ae commit 18a0d68
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,38 @@
import crc32c from "@chainsafe/fast-crc32c";

export enum ChunkType {
IDENTIFIER = 0xff,
COMPRESSED = 0x00,
UNCOMPRESSED = 0x01,
PADDING = 0xfe,
SKIPPABLE = 0x80,
}

export const IDENTIFIER = Buffer.from([0x73, 0x4e, 0x61, 0x50, 0x70, 0x59]);
export const IDENTIFIER_FRAME = Buffer.from([0xff, 0x06, 0x00, 0x00, 0x73, 0x4e, 0x61, 0x50, 0x70, 0x59]);

/**
* As per the snappy framing format for streams, the size of any uncompressed chunk can be
* no longer than 65536 bytes.
*
* From: https://github.com/google/snappy/blob/main/framing_format.txt#L90:L92
*/
export const UNCOMPRESSED_CHUNK_SIZE = 65536;

export function crc(value: Uint8Array): Buffer {
// this function doesn't actually need a buffer
// see https://github.com/napi-rs/node-rs/blob/main/packages/crc32/index.d.ts
const x = crc32c.calculate(value as Buffer);
const result = Buffer.allocUnsafe?.(4) ?? Buffer.alloc(4);

// As defined in section 3 of https://github.com/google/snappy/blob/master/framing_format.txt
// And other implementations for reference:
// Go: https://github.com/golang/snappy/blob/2e65f85255dbc3072edf28d6b5b8efc472979f5a/snappy.go#L97
// Python: https://github.com/andrix/python-snappy/blob/602e9c10d743f71bef0bac5e4c4dffa17340d7b3/snappy/snappy.py#L70
// Mask the right hand to (32 - 17) = 15 bits -> 0x7fff, to keep correct 32 bit values.
// Shift the left hand with >>> for correct 32 bit intermediate result.
// Then final >>> 0 for 32 bits output
result.writeUInt32LE((((x >>> 15) | ((x & 0x7fff) << 17)) + 0xa282ead8) >>> 0, 0);

return result;
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,8 @@
import crc32c from "@chainsafe/fast-crc32c";
import snappy from "snappy";
import {ChunkType, IDENTIFIER_FRAME} from "./common.js";
import {ChunkType, IDENTIFIER_FRAME, UNCOMPRESSED_CHUNK_SIZE, crc} from "./common.js";

// The logic in this file is largely copied (in simplified form) from https://github.com/ChainSafe/node-snappy-stream/

/**
* As per the snappy framing format for streams, the size of any uncompressed chunk can be
* no longer than 65536 bytes.
*
* From: https://github.com/google/snappy/blob/main/framing_format.txt#L90:L92
*/
const UNCOMPRESSED_CHUNK_SIZE = 65536;

function checksum(value: Buffer): Buffer {
const x = crc32c.calculate(value);
const result = Buffer.allocUnsafe?.(4) ?? Buffer.alloc(4);

// As defined in section 3 of https://github.com/google/snappy/blob/master/framing_format.txt
// And other implementations for reference:
// Go: https://github.com/golang/snappy/blob/2e65f85255dbc3072edf28d6b5b8efc472979f5a/snappy.go#L97
// Python: https://github.com/andrix/python-snappy/blob/602e9c10d743f71bef0bac5e4c4dffa17340d7b3/snappy/snappy.py#L70
// Mask the right hand to (32 - 17) = 15 bits -> 0x7fff, to keep correct 32 bit values.
// Shift the left hand with >>> for correct 32 bit intermediate result.
// Then final >>> 0 for 32 bits output
result.writeUInt32LE((((x >>> 15) | ((x & 0x7fff) << 17)) + 0xa282ead8) >>> 0, 0);

return result;
}

export async function* encodeSnappy(bytes: Buffer): AsyncGenerator<Buffer> {
yield IDENTIFIER_FRAME;

Expand All @@ -36,17 +11,13 @@ export async function* encodeSnappy(bytes: Buffer): AsyncGenerator<Buffer> {
const compressed = snappy.compressSync(chunk);
if (compressed.length < chunk.length) {
const size = compressed.length + 4;
yield Buffer.concat([
Buffer.from([ChunkType.COMPRESSED, size, size >> 8, size >> 16]),
checksum(chunk),
compressed,
]);
yield Buffer.concat([Buffer.from([ChunkType.COMPRESSED, size, size >> 8, size >> 16]), crc(chunk), compressed]);
} else {
const size = chunk.length + 4;
yield Buffer.concat([
//
Buffer.from([ChunkType.UNCOMPRESSED, size, size >> 8, size >> 16]),
checksum(chunk),
crc(chunk),
chunk,
]);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {uncompress} from "snappyjs";
import {Uint8ArrayList} from "uint8arraylist";
import {ChunkType, IDENTIFIER} from "./common.js";
import {ChunkType, IDENTIFIER, UNCOMPRESSED_CHUNK_SIZE, crc} from "./common.js";

export class SnappyFramesUncompress {
private buffer = new Uint8ArrayList();
Expand All @@ -21,32 +21,55 @@ export class SnappyFramesUncompress {
if (this.buffer.length < 4) break;

const type = getChunkType(this.buffer.get(0));

if (!this.state.foundIdentifier && type !== ChunkType.IDENTIFIER) {
throw "malformed input: must begin with an identifier";
}

const frameSize = getFrameSize(this.buffer, 1);

if (this.buffer.length - 4 < frameSize) {
break;
}

const data = this.buffer.subarray(4, 4 + frameSize);
const frame = this.buffer.subarray(4, 4 + frameSize);
this.buffer.consume(4 + frameSize);

if (!this.state.foundIdentifier && type !== ChunkType.IDENTIFIER) {
throw "malformed input: must begin with an identifier";
}
switch (type) {
case ChunkType.IDENTIFIER: {
if (!Buffer.prototype.equals.call(frame, IDENTIFIER)) {
throw "malformed input: bad identifier";
}
this.state.foundIdentifier = true;
continue;
}
case ChunkType.PADDING:
case ChunkType.SKIPPABLE:
continue;
case ChunkType.COMPRESSED: {
const checksum = frame.subarray(0, 4);
const data = frame.subarray(4);

if (type === ChunkType.IDENTIFIER) {
if (!Buffer.prototype.equals.call(data, IDENTIFIER)) {
throw "malformed input: bad identifier";
const uncompressed = uncompress(data, UNCOMPRESSED_CHUNK_SIZE);
if (crc(uncompressed).compare(checksum) !== 0) {
throw "malformed input: bad checksum";
}
result.append(uncompressed);
break;
}
this.state.foundIdentifier = true;
continue;
}
case ChunkType.UNCOMPRESSED: {
const checksum = frame.subarray(0, 4);
const uncompressed = frame.subarray(4);

if (type === ChunkType.COMPRESSED) {
result.append(uncompress(data.subarray(4)));
}
if (type === ChunkType.UNCOMPRESSED) {
result.append(data.subarray(4));
if (uncompressed.length > UNCOMPRESSED_CHUNK_SIZE) {
throw "malformed input: too large";
}
if (crc(uncompressed).compare(checksum) !== 0) {
throw "malformed input: bad checksum";
}
result.append(uncompressed);
break;
}
}
}
if (result.length === 0) {
Expand Down Expand Up @@ -82,6 +105,10 @@ function getChunkType(value: number): ChunkType {
case ChunkType.PADDING:
return ChunkType.PADDING;
default:
// https://github.com/google/snappy/blob/main/framing_format.txt#L129
if (value >= 0x80 && value <= 0xfd) {
return ChunkType.SKIPPABLE;
}
throw new Error("Unsupported snappy chunk type");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {pipe} from "it-pipe";
import {Uint8ArrayList} from "uint8arraylist";
import {describe, expect, it} from "vitest";
import {ChunkType, IDENTIFIER_FRAME, crc} from "../../../../../src/encodingStrategies/sszSnappy/snappyFrames/common.js";
import {encodeSnappy} from "../../../../../src/encodingStrategies/sszSnappy/snappyFrames/compress.js";
import {SnappyFramesUncompress} from "../../../../../src/encodingStrategies/sszSnappy/snappyFrames/uncompress.js";

Expand Down Expand Up @@ -56,4 +57,43 @@ describe("encodingStrategies / sszSnappy / snappy frames / uncompress", () => {

expect(decompress.uncompress(new Uint8ArrayList(Buffer.alloc(3, 1)))).toBe(null);
});

it("should detect invalid checksum", () => {
const chunks = new Uint8ArrayList();
chunks.append(IDENTIFIER_FRAME);

chunks.append(Uint8Array.from([ChunkType.UNCOMPRESSED, 0x80, 0x00, 0x00]));
// first 4 bytes are checksum
// 0xffffffff is clearly an invalid checksum
chunks.append(Uint8Array.from(Array.from({length: 0x80}, () => 0xff)));

const decompress = new SnappyFramesUncompress();
expect(() => decompress.uncompress(chunks)).toThrow(/checksum/);
});

it("should detect skippable frames", () => {
const chunks = new Uint8ArrayList();
chunks.append(IDENTIFIER_FRAME);

chunks.append(Uint8Array.from([ChunkType.SKIPPABLE, 0x80, 0x00, 0x00]));
chunks.append(Uint8Array.from(Array.from({length: 0x80}, () => 0xff)));

const decompress = new SnappyFramesUncompress();
expect(decompress.uncompress(chunks)).toBeNull();
});

it("should detect large data", () => {
const chunks = new Uint8ArrayList();
chunks.append(IDENTIFIER_FRAME);

// add a chunk of size 100000
chunks.append(Uint8Array.from([ChunkType.UNCOMPRESSED, 160, 134, 1]));
const data = Uint8Array.from(Array.from({length: 100000 - 4}, () => 0xff));
const checksum = crc(data);
chunks.append(checksum);
chunks.append(data);

const decompress = new SnappyFramesUncompress();
expect(() => decompress.uncompress(chunks)).toThrow(/large/);
});
});

1 comment on commit 18a0d68

@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: 18a0d68 Previous: 877b1ae Ratio
forkChoice updateHead vc 600000 bc 7200 eq 0 7.6865 ms/op 2.4826 ms/op 3.10
forkChoice updateHead vc 600000 bc 64 eq 300000 54.706 ms/op 10.482 ms/op 5.22
Full benchmark results
Benchmark suite Current: 18a0d68 Previous: 877b1ae Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 1.1040 ms/op 1.6453 ms/op 0.67
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 47.211 us/op 37.374 us/op 1.26
BLS verify - blst 792.70 us/op 884.87 us/op 0.90
BLS verifyMultipleSignatures 3 - blst 1.2621 ms/op 1.4889 ms/op 0.85
BLS verifyMultipleSignatures 8 - blst 1.8084 ms/op 2.2172 ms/op 0.82
BLS verifyMultipleSignatures 32 - blst 5.0180 ms/op 4.7840 ms/op 1.05
BLS verifyMultipleSignatures 64 - blst 9.4633 ms/op 8.8089 ms/op 1.07
BLS verifyMultipleSignatures 128 - blst 17.988 ms/op 16.018 ms/op 1.12
BLS deserializing 10000 signatures 734.03 ms/op 622.96 ms/op 1.18
BLS deserializing 100000 signatures 7.1874 s/op 6.4069 s/op 1.12
BLS verifyMultipleSignatures - same message - 3 - blst 910.52 us/op 875.60 us/op 1.04
BLS verifyMultipleSignatures - same message - 8 - blst 999.57 us/op 964.27 us/op 1.04
BLS verifyMultipleSignatures - same message - 32 - blst 1.7200 ms/op 1.5649 ms/op 1.10
BLS verifyMultipleSignatures - same message - 64 - blst 2.6512 ms/op 2.4746 ms/op 1.07
BLS verifyMultipleSignatures - same message - 128 - blst 4.4681 ms/op 4.1146 ms/op 1.09
BLS aggregatePubkeys 32 - blst 20.493 us/op 18.520 us/op 1.11
BLS aggregatePubkeys 128 - blst 73.004 us/op 64.352 us/op 1.13
notSeenSlots=1 numMissedVotes=1 numBadVotes=10 58.541 ms/op 55.971 ms/op 1.05
notSeenSlots=1 numMissedVotes=0 numBadVotes=4 50.429 ms/op 50.384 ms/op 1.00
notSeenSlots=2 numMissedVotes=1 numBadVotes=10 42.456 ms/op 33.275 ms/op 1.28
getSlashingsAndExits - default max 129.35 us/op 94.499 us/op 1.37
getSlashingsAndExits - 2k 392.83 us/op 504.67 us/op 0.78
proposeBlockBody type=full, size=empty 6.5200 ms/op 5.1100 ms/op 1.28
isKnown best case - 1 super set check 298.00 ns/op 475.00 ns/op 0.63
isKnown normal case - 2 super set checks 312.00 ns/op 457.00 ns/op 0.68
isKnown worse case - 16 super set checks 278.00 ns/op 451.00 ns/op 0.62
InMemoryCheckpointStateCache - add get delete 3.1020 us/op 2.5820 us/op 1.20
validate api signedAggregateAndProof - struct 1.4079 ms/op 1.5046 ms/op 0.94
validate gossip signedAggregateAndProof - struct 1.3852 ms/op 1.5203 ms/op 0.91
batch validate gossip attestation - vc 640000 - chunk 32 129.49 us/op 121.90 us/op 1.06
batch validate gossip attestation - vc 640000 - chunk 64 124.61 us/op 105.93 us/op 1.18
batch validate gossip attestation - vc 640000 - chunk 128 119.80 us/op 99.685 us/op 1.20
batch validate gossip attestation - vc 640000 - chunk 256 136.26 us/op 92.083 us/op 1.48
pickEth1Vote - no votes 1.6040 ms/op 848.67 us/op 1.89
pickEth1Vote - max votes 10.273 ms/op 4.4189 ms/op 2.32
pickEth1Vote - Eth1Data hashTreeRoot value x2048 21.005 ms/op 11.926 ms/op 1.76
pickEth1Vote - Eth1Data hashTreeRoot tree x2048 29.523 ms/op 16.450 ms/op 1.79
pickEth1Vote - Eth1Data fastSerialize value x2048 673.54 us/op 380.24 us/op 1.77
pickEth1Vote - Eth1Data fastSerialize tree x2048 4.0605 ms/op 2.6362 ms/op 1.54
bytes32 toHexString 773.00 ns/op 563.00 ns/op 1.37
bytes32 Buffer.toString(hex) 301.00 ns/op 400.00 ns/op 0.75
bytes32 Buffer.toString(hex) from Uint8Array 548.00 ns/op 513.00 ns/op 1.07
bytes32 Buffer.toString(hex) + 0x 305.00 ns/op 410.00 ns/op 0.74
Object access 1 prop 0.21900 ns/op 0.32600 ns/op 0.67
Map access 1 prop 0.15500 ns/op 0.33700 ns/op 0.46
Object get x1000 7.2020 ns/op 5.0990 ns/op 1.41
Map get x1000 8.5130 ns/op 5.7880 ns/op 1.47
Object set x1000 60.314 ns/op 22.471 ns/op 2.68
Map set x1000 40.622 ns/op 18.802 ns/op 2.16
Return object 10000 times 0.35520 ns/op 0.29850 ns/op 1.19
Throw Error 10000 times 3.9594 us/op 2.6413 us/op 1.50
toHex 197.22 ns/op 111.95 ns/op 1.76
Buffer.from 176.45 ns/op 105.76 ns/op 1.67
shared Buffer 108.70 ns/op 69.998 ns/op 1.55
fastMsgIdFn sha256 / 200 bytes 2.8720 us/op 1.9960 us/op 1.44
fastMsgIdFn h32 xxhash / 200 bytes 370.00 ns/op 405.00 ns/op 0.91
fastMsgIdFn h64 xxhash / 200 bytes 314.00 ns/op 431.00 ns/op 0.73
fastMsgIdFn sha256 / 1000 bytes 8.4200 us/op 5.8380 us/op 1.44
fastMsgIdFn h32 xxhash / 1000 bytes 512.00 ns/op 526.00 ns/op 0.97
fastMsgIdFn h64 xxhash / 1000 bytes 421.00 ns/op 507.00 ns/op 0.83
fastMsgIdFn sha256 / 10000 bytes 73.741 us/op 49.614 us/op 1.49
fastMsgIdFn h32 xxhash / 10000 bytes 2.1740 us/op 1.9540 us/op 1.11
fastMsgIdFn h64 xxhash / 10000 bytes 1.3840 us/op 1.3550 us/op 1.02
send data - 1000 256B messages 17.468 ms/op 10.511 ms/op 1.66
send data - 1000 512B messages 23.414 ms/op 12.721 ms/op 1.84
send data - 1000 1024B messages 32.408 ms/op 23.556 ms/op 1.38
send data - 1000 1200B messages 33.454 ms/op 23.965 ms/op 1.40
send data - 1000 2048B messages 40.143 ms/op 29.021 ms/op 1.38
send data - 1000 4096B messages 40.915 ms/op 26.581 ms/op 1.54
send data - 1000 16384B messages 87.057 ms/op 66.790 ms/op 1.30
send data - 1000 65536B messages 258.91 ms/op 243.13 ms/op 1.06
enrSubnets - fastDeserialize 64 bits 1.4450 us/op 1.1280 us/op 1.28
enrSubnets - ssz BitVector 64 bits 543.00 ns/op 505.00 ns/op 1.08
enrSubnets - fastDeserialize 4 bits 249.00 ns/op 321.00 ns/op 0.78
enrSubnets - ssz BitVector 4 bits 460.00 ns/op 510.00 ns/op 0.90
prioritizePeers score -10:0 att 32-0.1 sync 2-0 172.08 us/op 107.08 us/op 1.61
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 196.04 us/op 129.69 us/op 1.51
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 250.96 us/op 188.87 us/op 1.33
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 452.34 us/op 324.61 us/op 1.39
prioritizePeers score 0:0 att 64-1 sync 4-1 741.52 us/op 405.16 us/op 1.83
array of 16000 items push then shift 1.8877 us/op 1.2942 us/op 1.46
LinkedList of 16000 items push then shift 9.5570 ns/op 6.3070 ns/op 1.52
array of 16000 items push then pop 149.58 ns/op 73.406 ns/op 2.04
LinkedList of 16000 items push then pop 9.6270 ns/op 6.4240 ns/op 1.50
array of 24000 items push then shift 2.7987 us/op 1.8975 us/op 1.47
LinkedList of 24000 items push then shift 9.7710 ns/op 6.3390 ns/op 1.54
array of 24000 items push then pop 206.17 ns/op 105.65 ns/op 1.95
LinkedList of 24000 items push then pop 9.4400 ns/op 5.8720 ns/op 1.61
intersect bitArray bitLen 8 7.7050 ns/op 5.1700 ns/op 1.49
intersect array and set length 8 81.517 ns/op 34.600 ns/op 2.36
intersect bitArray bitLen 128 35.515 ns/op 24.610 ns/op 1.44
intersect array and set length 128 974.26 ns/op 563.61 ns/op 1.73
bitArray.getTrueBitIndexes() bitLen 128 2.2000 us/op 1.4340 us/op 1.53
bitArray.getTrueBitIndexes() bitLen 248 3.4210 us/op 2.2050 us/op 1.55
bitArray.getTrueBitIndexes() bitLen 512 6.9960 us/op 4.1590 us/op 1.68
Buffer.concat 32 items 1.0390 us/op 912.00 ns/op 1.14
Uint8Array.set 32 items 1.9080 us/op 1.5570 us/op 1.23
Buffer.copy 3.7130 us/op 2.5410 us/op 1.46
Uint8Array.set - with subarray 3.7970 us/op 2.4170 us/op 1.57
Uint8Array.set - without subarray 1.9480 us/op 1.4960 us/op 1.30
getUint32 - dataview 335.00 ns/op 417.00 ns/op 0.80
getUint32 - manual 290.00 ns/op 325.00 ns/op 0.89
Set add up to 64 items then delete first 3.1121 us/op 1.7562 us/op 1.77
OrderedSet add up to 64 items then delete first 4.5860 us/op 2.6320 us/op 1.74
Set add up to 64 items then delete last 3.5031 us/op 1.9984 us/op 1.75
OrderedSet add up to 64 items then delete last 5.1197 us/op 3.0026 us/op 1.71
Set add up to 64 items then delete middle 3.2713 us/op 2.0017 us/op 1.63
OrderedSet add up to 64 items then delete middle 6.9993 us/op 4.4049 us/op 1.59
Set add up to 128 items then delete first 7.6949 us/op 3.9532 us/op 1.95
OrderedSet add up to 128 items then delete first 11.991 us/op 6.1800 us/op 1.94
Set add up to 128 items then delete last 7.3426 us/op 3.8216 us/op 1.92
OrderedSet add up to 128 items then delete last 11.144 us/op 5.8010 us/op 1.92
Set add up to 128 items then delete middle 7.1830 us/op 3.8154 us/op 1.88
OrderedSet add up to 128 items then delete middle 18.298 us/op 11.760 us/op 1.56
Set add up to 256 items then delete first 14.755 us/op 7.6585 us/op 1.93
OrderedSet add up to 256 items then delete first 23.239 us/op 12.304 us/op 1.89
Set add up to 256 items then delete last 14.654 us/op 7.7070 us/op 1.90
OrderedSet add up to 256 items then delete last 22.452 us/op 11.446 us/op 1.96
Set add up to 256 items then delete middle 14.272 us/op 7.4599 us/op 1.91
OrderedSet add up to 256 items then delete middle 56.682 us/op 34.678 us/op 1.63
transfer serialized Status (84 B) 3.7240 us/op 2.1620 us/op 1.72
copy serialized Status (84 B) 1.8040 us/op 1.3610 us/op 1.33
transfer serialized SignedVoluntaryExit (112 B) 3.8880 us/op 2.3200 us/op 1.68
copy serialized SignedVoluntaryExit (112 B) 2.0090 us/op 1.3630 us/op 1.47
transfer serialized ProposerSlashing (416 B) 4.1870 us/op 2.4350 us/op 1.72
copy serialized ProposerSlashing (416 B) 2.7620 us/op 1.9510 us/op 1.42
transfer serialized Attestation (485 B) 4.4420 us/op 2.6240 us/op 1.69
copy serialized Attestation (485 B) 3.0550 us/op 2.1590 us/op 1.42
transfer serialized AttesterSlashing (33232 B) 4.1330 us/op 2.7370 us/op 1.51
copy serialized AttesterSlashing (33232 B) 11.656 us/op 5.2790 us/op 2.21
transfer serialized Small SignedBeaconBlock (128000 B) 5.5230 us/op 2.8740 us/op 1.92
copy serialized Small SignedBeaconBlock (128000 B) 39.357 us/op 8.7270 us/op 4.51
transfer serialized Avg SignedBeaconBlock (200000 B) 6.6050 us/op 3.3860 us/op 1.95
copy serialized Avg SignedBeaconBlock (200000 B) 49.477 us/op 13.001 us/op 3.81
transfer serialized BlobsSidecar (524380 B) 7.0350 us/op 3.5550 us/op 1.98
copy serialized BlobsSidecar (524380 B) 157.96 us/op 70.200 us/op 2.25
transfer serialized Big SignedBeaconBlock (1000000 B) 8.6260 us/op 4.4350 us/op 1.94
copy serialized Big SignedBeaconBlock (1000000 B) 256.58 us/op 131.50 us/op 1.95
pass gossip attestations to forkchoice per slot 3.4914 ms/op 2.3898 ms/op 1.46
forkChoice updateHead vc 100000 bc 64 eq 0 567.06 us/op 367.46 us/op 1.54
forkChoice updateHead vc 600000 bc 64 eq 0 6.2050 ms/op 2.4216 ms/op 2.56
forkChoice updateHead vc 1000000 bc 64 eq 0 9.0462 ms/op 3.6762 ms/op 2.46
forkChoice updateHead vc 600000 bc 320 eq 0 4.6535 ms/op 2.2771 ms/op 2.04
forkChoice updateHead vc 600000 bc 1200 eq 0 5.0855 ms/op 2.2366 ms/op 2.27
forkChoice updateHead vc 600000 bc 7200 eq 0 7.6865 ms/op 2.4826 ms/op 3.10
forkChoice updateHead vc 600000 bc 64 eq 1000 16.702 ms/op 8.6578 ms/op 1.93
forkChoice updateHead vc 600000 bc 64 eq 10000 12.679 ms/op 8.8859 ms/op 1.43
forkChoice updateHead vc 600000 bc 64 eq 300000 54.706 ms/op 10.482 ms/op 5.22
computeDeltas 500000 validators 300 proto nodes 5.6119 ms/op 3.1840 ms/op 1.76
computeDeltas 500000 validators 1200 proto nodes 5.2537 ms/op 3.2255 ms/op 1.63
computeDeltas 500000 validators 7200 proto nodes 8.6721 ms/op 3.2374 ms/op 2.68
computeDeltas 750000 validators 300 proto nodes 8.8509 ms/op 4.9075 ms/op 1.80
computeDeltas 750000 validators 1200 proto nodes 8.1025 ms/op 4.7390 ms/op 1.71
computeDeltas 750000 validators 7200 proto nodes 7.5593 ms/op 5.0202 ms/op 1.51
computeDeltas 1400000 validators 300 proto nodes 12.782 ms/op 9.2689 ms/op 1.38
computeDeltas 1400000 validators 1200 proto nodes 12.194 ms/op 9.2328 ms/op 1.32
computeDeltas 1400000 validators 7200 proto nodes 13.799 ms/op 9.5778 ms/op 1.44
computeDeltas 2100000 validators 300 proto nodes 21.314 ms/op 13.584 ms/op 1.57
computeDeltas 2100000 validators 1200 proto nodes 21.306 ms/op 13.951 ms/op 1.53
computeDeltas 2100000 validators 7200 proto nodes 19.749 ms/op 13.882 ms/op 1.42
altair processAttestation - 250000 vs - 7PWei normalcase 3.1429 ms/op 1.5196 ms/op 2.07
altair processAttestation - 250000 vs - 7PWei worstcase 4.2468 ms/op 2.2998 ms/op 1.85
altair processAttestation - setStatus - 1/6 committees join 195.07 us/op 93.135 us/op 2.09
altair processAttestation - setStatus - 1/3 committees join 331.87 us/op 189.07 us/op 1.76
altair processAttestation - setStatus - 1/2 committees join 388.20 us/op 276.78 us/op 1.40
altair processAttestation - setStatus - 2/3 committees join 499.21 us/op 363.14 us/op 1.37
altair processAttestation - setStatus - 4/5 committees join 729.22 us/op 496.76 us/op 1.47
altair processAttestation - setStatus - 100% committees join 890.47 us/op 590.43 us/op 1.51
altair processBlock - 250000 vs - 7PWei normalcase 6.8430 ms/op 3.6205 ms/op 1.89
altair processBlock - 250000 vs - 7PWei normalcase hashState 31.233 ms/op 22.011 ms/op 1.42
altair processBlock - 250000 vs - 7PWei worstcase 37.961 ms/op 35.954 ms/op 1.06
altair processBlock - 250000 vs - 7PWei worstcase hashState 78.791 ms/op 67.824 ms/op 1.16
phase0 processBlock - 250000 vs - 7PWei normalcase 2.2133 ms/op 1.5069 ms/op 1.47
phase0 processBlock - 250000 vs - 7PWei worstcase 24.012 ms/op 24.439 ms/op 0.98
altair processEth1Data - 250000 vs - 7PWei normalcase 425.65 us/op 262.31 us/op 1.62
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:15 6.7690 us/op 7.5380 us/op 0.90
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:219 54.588 us/op 54.240 us/op 1.01
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:42 11.667 us/op 10.959 us/op 1.06
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:18 7.6390 us/op 8.2760 us/op 0.92
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1020 185.34 us/op 133.35 us/op 1.39
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11777 1.2444 ms/op 1.4279 ms/op 0.87
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 1.9692 ms/op 1.3152 ms/op 1.50
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 1.6513 ms/op 1.9485 ms/op 0.85
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 4.2397 ms/op 3.1919 ms/op 1.33
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 1.8969 ms/op 1.3201 ms/op 1.44
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 4.7207 ms/op 2.9904 ms/op 1.58
Tree 40 250000 create 236.17 ms/op 196.05 ms/op 1.20
Tree 40 250000 get(125000) 174.61 ns/op 117.88 ns/op 1.48
Tree 40 250000 set(125000) 716.68 ns/op 501.07 ns/op 1.43
Tree 40 250000 toArray() 19.876 ms/op 9.8414 ms/op 2.02
Tree 40 250000 iterate all - toArray() + loop 21.781 ms/op 10.141 ms/op 2.15
Tree 40 250000 iterate all - get(i) 58.009 ms/op 42.776 ms/op 1.36
Array 250000 create 3.6614 ms/op 2.4076 ms/op 1.52
Array 250000 clone - spread 1.5433 ms/op 1.3092 ms/op 1.18
Array 250000 get(125000) 0.44300 ns/op 0.59800 ns/op 0.74
Array 250000 set(125000) 0.46500 ns/op 0.61100 ns/op 0.76
Array 250000 iterate all - loop 100.53 us/op 78.100 us/op 1.29
phase0 afterProcessEpoch - 250000 vs - 7PWei 54.594 ms/op 44.210 ms/op 1.23
Array.fill - length 1000000 3.8453 ms/op 2.5042 ms/op 1.54
Array push - length 1000000 18.948 ms/op 15.176 ms/op 1.25
Array.get 0.30015 ns/op 0.27435 ns/op 1.09
Uint8Array.get 0.46504 ns/op 0.35325 ns/op 1.32
phase0 beforeProcessEpoch - 250000 vs - 7PWei 19.130 ms/op 20.796 ms/op 0.92
altair processEpoch - mainnet_e81889 298.37 ms/op 258.04 ms/op 1.16
mainnet_e81889 - altair beforeProcessEpoch 19.098 ms/op 20.203 ms/op 0.95
mainnet_e81889 - altair processJustificationAndFinalization 15.133 us/op 15.575 us/op 0.97
mainnet_e81889 - altair processInactivityUpdates 5.5439 ms/op 5.2677 ms/op 1.05
mainnet_e81889 - altair processRewardsAndPenalties 45.273 ms/op 44.443 ms/op 1.02
mainnet_e81889 - altair processRegistryUpdates 2.5690 us/op 3.2240 us/op 0.80
mainnet_e81889 - altair processSlashings 477.00 ns/op 1.1650 us/op 0.41
mainnet_e81889 - altair processEth1DataReset 556.00 ns/op 1.3020 us/op 0.43
mainnet_e81889 - altair processEffectiveBalanceUpdates 1.4729 ms/op 1.0028 ms/op 1.47
mainnet_e81889 - altair processSlashingsReset 3.3310 us/op 6.1900 us/op 0.54
mainnet_e81889 - altair processRandaoMixesReset 6.3210 us/op 4.9560 us/op 1.28
mainnet_e81889 - altair processHistoricalRootsUpdate 680.00 ns/op 1.6380 us/op 0.42
mainnet_e81889 - altair processParticipationFlagUpdates 2.2480 us/op 3.0110 us/op 0.75
mainnet_e81889 - altair processSyncCommitteeUpdates 608.00 ns/op 1.3740 us/op 0.44
mainnet_e81889 - altair afterProcessEpoch 53.893 ms/op 44.129 ms/op 1.22
capella processEpoch - mainnet_e217614 1.0443 s/op 949.08 ms/op 1.10
mainnet_e217614 - capella beforeProcessEpoch 80.452 ms/op 70.393 ms/op 1.14
mainnet_e217614 - capella processJustificationAndFinalization 17.341 us/op 12.499 us/op 1.39
mainnet_e217614 - capella processInactivityUpdates 20.327 ms/op 11.879 ms/op 1.71
mainnet_e217614 - capella processRewardsAndPenalties 247.42 ms/op 232.40 ms/op 1.06
mainnet_e217614 - capella processRegistryUpdates 18.912 us/op 16.737 us/op 1.13
mainnet_e217614 - capella processSlashings 1.7500 us/op 1.2180 us/op 1.44
mainnet_e217614 - capella processEth1DataReset 819.00 ns/op 857.00 ns/op 0.96
mainnet_e217614 - capella processEffectiveBalanceUpdates 18.384 ms/op 7.9927 ms/op 2.30
mainnet_e217614 - capella processSlashingsReset 8.3470 us/op 3.3730 us/op 2.47
mainnet_e217614 - capella processRandaoMixesReset 6.6240 us/op 3.9210 us/op 1.69
mainnet_e217614 - capella processHistoricalRootsUpdate 883.00 ns/op 1.7750 us/op 0.50
mainnet_e217614 - capella processParticipationFlagUpdates 3.0620 us/op 2.0010 us/op 1.53
mainnet_e217614 - capella afterProcessEpoch 135.77 ms/op 105.28 ms/op 1.29
phase0 processEpoch - mainnet_e58758 356.94 ms/op 288.85 ms/op 1.24
mainnet_e58758 - phase0 beforeProcessEpoch 104.34 ms/op 82.312 ms/op 1.27
mainnet_e58758 - phase0 processJustificationAndFinalization 18.855 us/op 17.429 us/op 1.08
mainnet_e58758 - phase0 processRewardsAndPenalties 22.626 ms/op 32.304 ms/op 0.70
mainnet_e58758 - phase0 processRegistryUpdates 10.449 us/op 8.2800 us/op 1.26
mainnet_e58758 - phase0 processSlashings 559.00 ns/op 956.00 ns/op 0.58
mainnet_e58758 - phase0 processEth1DataReset 465.00 ns/op 900.00 ns/op 0.52
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 1.2448 ms/op 1.4130 ms/op 0.88
mainnet_e58758 - phase0 processSlashingsReset 4.9140 us/op 2.3950 us/op 2.05
mainnet_e58758 - phase0 processRandaoMixesReset 6.5380 us/op 4.7210 us/op 1.38
mainnet_e58758 - phase0 processHistoricalRootsUpdate 850.00 ns/op 983.00 ns/op 0.86
mainnet_e58758 - phase0 processParticipationRecordUpdates 4.0240 us/op 6.4140 us/op 0.63
mainnet_e58758 - phase0 afterProcessEpoch 45.942 ms/op 37.531 ms/op 1.22
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.4330 ms/op 1.0110 ms/op 1.42
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 2.2870 ms/op 1.4021 ms/op 1.63
altair processInactivityUpdates - 250000 normalcase 18.418 ms/op 15.277 ms/op 1.21
altair processInactivityUpdates - 250000 worstcase 18.220 ms/op 15.148 ms/op 1.20
phase0 processRegistryUpdates - 250000 normalcase 12.650 us/op 9.6040 us/op 1.32
phase0 processRegistryUpdates - 250000 badcase_full_deposits 324.54 us/op 319.99 us/op 1.01
phase0 processRegistryUpdates - 250000 worstcase 0.5 123.54 ms/op 108.25 ms/op 1.14
altair processRewardsAndPenalties - 250000 normalcase 40.173 ms/op 39.123 ms/op 1.03
altair processRewardsAndPenalties - 250000 worstcase 41.678 ms/op 44.266 ms/op 0.94
phase0 getAttestationDeltas - 250000 normalcase 9.7855 ms/op 6.7755 ms/op 1.44
phase0 getAttestationDeltas - 250000 worstcase 8.1581 ms/op 8.6641 ms/op 0.94
phase0 processSlashings - 250000 worstcase 88.620 us/op 90.439 us/op 0.98
altair processSyncCommitteeUpdates - 250000 136.98 ms/op 99.231 ms/op 1.38
BeaconState.hashTreeRoot - No change 270.00 ns/op 459.00 ns/op 0.59
BeaconState.hashTreeRoot - 1 full validator 123.48 us/op 104.60 us/op 1.18
BeaconState.hashTreeRoot - 32 full validator 1.1997 ms/op 1.1988 ms/op 1.00
BeaconState.hashTreeRoot - 512 full validator 10.103 ms/op 10.449 ms/op 0.97
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 119.19 us/op 150.19 us/op 0.79
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.5506 ms/op 1.6128 ms/op 0.96
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 19.699 ms/op 17.671 ms/op 1.11
BeaconState.hashTreeRoot - 1 balances 97.625 us/op 99.396 us/op 0.98
BeaconState.hashTreeRoot - 32 balances 874.22 us/op 914.31 us/op 0.96
BeaconState.hashTreeRoot - 512 balances 8.1950 ms/op 6.5728 ms/op 1.25
BeaconState.hashTreeRoot - 250000 balances 170.69 ms/op 197.86 ms/op 0.86
aggregationBits - 2048 els - zipIndexesInBitList 28.054 us/op 19.689 us/op 1.42
byteArrayEquals 32 59.763 ns/op 48.083 ns/op 1.24
Buffer.compare 32 19.830 ns/op 15.546 ns/op 1.28
byteArrayEquals 1024 1.7725 us/op 1.2805 us/op 1.38
Buffer.compare 1024 29.274 ns/op 24.372 ns/op 1.20
byteArrayEquals 16384 27.654 us/op 20.345 us/op 1.36
Buffer.compare 16384 219.61 ns/op 188.41 ns/op 1.17
byteArrayEquals 123687377 209.90 ms/op 153.61 ms/op 1.37
Buffer.compare 123687377 8.6221 ms/op 4.2155 ms/op 2.05
byteArrayEquals 32 - diff last byte 56.255 ns/op 47.725 ns/op 1.18
Buffer.compare 32 - diff last byte 18.716 ns/op 15.881 ns/op 1.18
byteArrayEquals 1024 - diff last byte 1.6735 us/op 1.2693 us/op 1.32
Buffer.compare 1024 - diff last byte 26.127 ns/op 23.731 ns/op 1.10
byteArrayEquals 16384 - diff last byte 26.551 us/op 20.588 us/op 1.29
Buffer.compare 16384 - diff last byte 208.07 ns/op 185.44 ns/op 1.12
byteArrayEquals 123687377 - diff last byte 199.66 ms/op 150.81 ms/op 1.32
Buffer.compare 123687377 - diff last byte 6.8407 ms/op 5.2600 ms/op 1.30
byteArrayEquals 32 - random bytes 5.2910 ns/op 4.6440 ns/op 1.14
Buffer.compare 32 - random bytes 17.575 ns/op 14.597 ns/op 1.20
byteArrayEquals 1024 - random bytes 5.2740 ns/op 4.6650 ns/op 1.13
Buffer.compare 1024 - random bytes 17.678 ns/op 15.006 ns/op 1.18
byteArrayEquals 16384 - random bytes 5.2980 ns/op 4.6490 ns/op 1.14
Buffer.compare 16384 - random bytes 17.565 ns/op 15.109 ns/op 1.16
byteArrayEquals 123687377 - random bytes 6.6900 ns/op 7.4500 ns/op 0.90
Buffer.compare 123687377 - random bytes 18.880 ns/op 17.420 ns/op 1.08
regular array get 100000 times 43.506 us/op 29.067 us/op 1.50
wrappedArray get 100000 times 35.321 us/op 28.942 us/op 1.22
arrayWithProxy get 100000 times 12.636 ms/op 8.3367 ms/op 1.52
ssz.Root.equals 47.002 ns/op 41.790 ns/op 1.12
byteArrayEquals 46.838 ns/op 40.988 ns/op 1.14
Buffer.compare 10.536 ns/op 8.4920 ns/op 1.24
processSlot - 1 slots 13.239 us/op 12.435 us/op 1.06
processSlot - 32 slots 2.9151 ms/op 2.4409 ms/op 1.19
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 35.472 ms/op 37.847 ms/op 0.94
getCommitteeAssignments - req 1 vs - 250000 vc 2.1735 ms/op 1.8154 ms/op 1.20
getCommitteeAssignments - req 100 vs - 250000 vc 4.2247 ms/op 3.5624 ms/op 1.19
getCommitteeAssignments - req 1000 vs - 250000 vc 4.5705 ms/op 3.6155 ms/op 1.26
findModifiedValidators - 10000 modified validators 261.29 ms/op 247.67 ms/op 1.05
findModifiedValidators - 1000 modified validators 245.11 ms/op 142.44 ms/op 1.72
findModifiedValidators - 100 modified validators 195.84 ms/op 140.21 ms/op 1.40
findModifiedValidators - 10 modified validators 189.36 ms/op 131.93 ms/op 1.44
findModifiedValidators - 1 modified validators 177.98 ms/op 128.39 ms/op 1.39
findModifiedValidators - no difference 185.25 ms/op 138.81 ms/op 1.33
compare ViewDUs 3.3121 s/op 3.2637 s/op 1.01
compare each validator Uint8Array 1.8383 s/op 867.96 ms/op 2.12
compare ViewDU to Uint8Array 1.4073 s/op 799.30 ms/op 1.76
migrate state 1000000 validators, 24 modified, 0 new 967.85 ms/op 697.59 ms/op 1.39
migrate state 1000000 validators, 1700 modified, 1000 new 1.1327 s/op 847.62 ms/op 1.34
migrate state 1000000 validators, 3400 modified, 2000 new 1.2316 s/op 1.4430 s/op 0.85
migrate state 1500000 validators, 24 modified, 0 new 752.72 ms/op 692.55 ms/op 1.09
migrate state 1500000 validators, 1700 modified, 1000 new 1.2026 s/op 897.13 ms/op 1.34
migrate state 1500000 validators, 3400 modified, 2000 new 1.3114 s/op 1.2193 s/op 1.08
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 5.5000 ns/op 6.6400 ns/op 0.83
state getBlockRootAtSlot - 250000 vs - 7PWei 995.44 ns/op 627.32 ns/op 1.59
computeProposers - vc 250000 8.2682 ms/op 6.5958 ms/op 1.25
computeEpochShuffling - vc 250000 47.975 ms/op 35.498 ms/op 1.35
getNextSyncCommittee - vc 250000 148.10 ms/op 110.52 ms/op 1.34
computeSigningRoot for AttestationData 25.963 us/op 20.445 us/op 1.27
hash AttestationData serialized data then Buffer.toString(base64) 1.8524 us/op 1.1969 us/op 1.55
toHexString serialized data 1.2352 us/op 764.36 ns/op 1.62
Buffer.toString(base64) 230.95 ns/op 154.24 ns/op 1.50
nodejs block root to RootHex using toHex 181.53 ns/op 122.37 ns/op 1.48
nodejs block root to RootHex using toRootHex 113.03 ns/op 76.575 ns/op 1.48
browser block root to RootHex using the deprecated toHexString 304.67 ns/op 208.47 ns/op 1.46
browser block root to RootHex using toHex 253.53 ns/op 164.33 ns/op 1.54
browser block root to RootHex using toRootHex 198.02 ns/op 148.50 ns/op 1.33

Please sign in to comment.