-
-
Notifications
You must be signed in to change notification settings - Fork 266
/
utils.ts
98 lines (83 loc) 路 3.18 KB
/
utils.ts
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
93
94
95
96
97
98
import bls from "@chainsafe/bls";
import type {PublicKey} from "@chainsafe/bls/types";
import {BitArray} from "@chainsafe/ssz";
import {Api, ApiError} from "@lodestar/api";
import {altair, Bytes32, Root, ssz} from "@lodestar/types";
import {BeaconBlockHeader} from "@lodestar/types/phase0";
import {GenesisData} from "../index.js";
import {SyncCommitteeFast} from "../types.js";
export function sumBits(bits: BitArray): number {
return bits.getTrueBitIndexes().length;
}
export function isZeroHash(root: Root): boolean {
for (let i = 0; i < root.length; i++) {
if (root[i] !== 0) {
return false;
}
}
return true;
}
export function assertZeroHashes(rootArray: Root[], expectedLength: number, errorMessage: string): void {
if (rootArray.length !== expectedLength) {
throw Error(`Wrong length ${errorMessage}`);
}
for (const root of rootArray) {
if (!isZeroHash(root)) {
throw Error(`Not zeroed ${errorMessage}`);
}
}
}
/**
* Util to guarantee that all bits have a corresponding pubkey
*/
export function getParticipantPubkeys<T>(pubkeys: T[], bits: BitArray): T[] {
// BitArray.intersectValues() checks the length is correct
return bits.intersectValues(pubkeys);
}
export function toBlockHeader(block: altair.BeaconBlock): BeaconBlockHeader {
return {
slot: block.slot,
proposerIndex: block.proposerIndex,
parentRoot: block.parentRoot,
stateRoot: block.stateRoot,
bodyRoot: ssz.altair.BeaconBlockBody.hashTreeRoot(block.body),
};
}
function deserializePubkeys(pubkeys: altair.LightClientUpdate["nextSyncCommittee"]["pubkeys"]): PublicKey[] {
return pubkeys.map((pk) => bls.PublicKey.fromBytes(pk));
}
function serializePubkeys(pubkeys: PublicKey[]): altair.LightClientUpdate["nextSyncCommittee"]["pubkeys"] {
return pubkeys.map((pk) => pk.toBytes());
}
export function deserializeSyncCommittee(syncCommittee: altair.SyncCommittee): SyncCommitteeFast {
return {
pubkeys: deserializePubkeys(syncCommittee.pubkeys),
aggregatePubkey: bls.PublicKey.fromBytes(syncCommittee.aggregatePubkey),
};
}
export function serializeSyncCommittee(syncCommittee: SyncCommitteeFast): altair.SyncCommittee {
return {
pubkeys: serializePubkeys(syncCommittee.pubkeys),
aggregatePubkey: syncCommittee.aggregatePubkey.toBytes(),
};
}
export function isEmptyHeader(header: BeaconBlockHeader): boolean {
const emptyValue = ssz.phase0.BeaconBlockHeader.defaultValue();
return ssz.phase0.BeaconBlockHeader.equals(emptyValue, header);
}
// Thanks https://github.com/iliakan/detect-node/blob/master/index.esm.js
export const isNode =
Object.prototype.toString.call(typeof process !== "undefined" ? process : 0) === "[object process]";
export async function getGenesisData(api: Pick<Api, "beacon">): Promise<GenesisData> {
const res = await api.beacon.getGenesis();
ApiError.assert(res);
return {
genesisTime: res.response.data.genesisTime,
genesisValidatorsRoot: res.response.data.genesisValidatorsRoot,
};
}
export async function getFinalizedSyncCheckpoint(api: Pick<Api, "beacon">): Promise<Bytes32> {
const res = await api.beacon.getStateFinalityCheckpoints("head");
ApiError.assert(res);
return res.response.data.finalized.root;
}