-
-
Notifications
You must be signed in to change notification settings - Fork 438
Expand file tree
/
Copy pathsigningRoot.test.ts
More file actions
92 lines (85 loc) · 3.1 KB
/
signingRoot.test.ts
File metadata and controls
92 lines (85 loc) · 3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import {digest} from "@chainsafe/as-sha256";
import {bench, describe, setBenchOpts} from "@chainsafe/benchmark";
import {fromHexString, toHexString} from "@chainsafe/ssz";
import {phase0, ssz} from "@lodestar/types";
import {computeSigningRoot} from "../../../src/util/signingRoot.js";
/**
* As of Apr 2023, when we apply new gossip queues we process all gossip attestations and computeSiningRoot may take up to 6% of cpu.
* The below benchmark results show that if we use Buffer.toString(base64) against serialized attestation data, it is still way cheaper
* than computeSigningRoot.
* Based on that we can cache attestation data as string in order to avoid recomputing signing root when validating gossip attestations.
* computeSigningRoot
✔ computeSigningRoot for AttestationData 94788.17 ops/s 10.54984 us/op - 901 runs 10.0 s
✔ hash AttestationData serialized data then Buffer.toString(base64 509425.9 ops/s 1.962994 us/op - 4856 runs 10.0 s
✔ toHexString serialized data 727592.3 ops/s 1.374396 us/op - 6916 runs 10.0 s
✔ Buffer.toString(base64) 2570800 ops/s 388.9840 ns/op - 24628 runs 10.1 s
*/
describe("computeSigningRoot", () => {
setBenchOpts({
minMs: 10_000,
});
const type = ssz.phase0.AttestationData;
const seedObject: phase0.AttestationData = {
slot: 6118259,
index: 46,
beaconBlockRoot: fromHexString("0x94cef26d543b20568a4bbb77ae2ba203826912065348613a437a9106142aff85"),
source: {
epoch: 191194,
root: fromHexString("0x1a955a91af4ee915c1f267f0026668c58237c1a23bd6c106ef05459741a9171c"),
},
target: {
epoch: 191195,
root: fromHexString("0x48db1209cd969a1a74eb19d1c5e24021d3a4ac45b8b1b2c1b0e8b0c1b0e8b0c1"),
},
};
const bytes = type.serialize(seedObject);
const domain = new Uint8Array(32);
bench({
id: "computeSigningRoot for AttestationData",
fn: () => {
for (let i = 0; i < 1000; i++) {
computeSigningRoot(type, clone(seedObject), domain);
}
},
runsFactor: 1000,
});
bench({
id: "hash AttestationData serialized data then Buffer.toString(base64)",
fn: () => {
for (let i = 0; i < 1000; i++) {
clone(seedObject);
Buffer.from(digest(bytes)).toString("base64");
}
},
runsFactor: 1000,
});
bench({
id: "toHexString serialized data",
fn: () => {
for (let i = 0; i < 1000; i++) {
clone(seedObject);
toHexString(bytes);
}
},
runsFactor: 1000,
});
bench({
id: "Buffer.toString(base64)",
fn: () => {
for (let i = 0; i < 1000; i++) {
clone(seedObject);
Buffer.from(bytes).toString("base64");
}
},
runsFactor: 1000,
});
});
function clone(sszObject: phase0.AttestationData): phase0.AttestationData {
return {
slot: sszObject.slot,
index: sszObject.index,
beaconBlockRoot: sszObject.beaconBlockRoot,
source: sszObject.source,
target: sszObject.target,
};
}