/
index.ts
118 lines (103 loc) Β· 4.79 KB
/
index.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params";
import {DomainType, ForkDigest, phase0, Root, Slot, ssz, Version} from "@lodestar/types";
import {toHexString} from "@chainsafe/ssz";
import {IChainForkConfig} from "../beaconConfig.js";
import {ForkDigestHex, ICachedGenesis} from "./types.js";
export {IForkDigestContext} from "./types.js";
export function createICachedGenesis(chainForkConfig: IChainForkConfig, genesisValidatorsRoot: Root): ICachedGenesis {
const domainCache = new Map<ForkName, Map<DomainType, Uint8Array>>();
const forkDigestByForkName = new Map<ForkName, ForkDigest>();
const forkDigestHexByForkName = new Map<ForkName, ForkDigestHex>();
/** Map of ForkDigest in hex format without prefix: `0011aabb` */
const forkNameByForkDigest = new Map<ForkDigestHex, ForkName>();
for (const fork of Object.values(chainForkConfig.forks)) {
const forkDigest = computeForkDigest(fork.version, genesisValidatorsRoot);
const forkDigestHex = toHexStringNoPrefix(forkDigest);
forkNameByForkDigest.set(forkDigestHex, fork.name);
forkDigestByForkName.set(fork.name, forkDigest);
forkDigestHexByForkName.set(fork.name, forkDigestHex);
}
return {
getDomain(stateSlot: Slot, domainType: DomainType, messageSlot?: Slot): Uint8Array {
// ```py
// def get_domain(state: BeaconState, domain_type: DomainType, epoch: Epoch=None) -> Domain:
// """
// Return the signature domain (fork version concatenated with domain type) of a message.
// """
// epoch = get_current_epoch(state) if epoch is None else epoch
// fork_version = state.fork.previous_version if epoch < state.fork.epoch else state.fork.current_version
// return compute_domain(domain_type, fork_version, state.genesis_validators_root)
// ```
const epoch = Math.floor((messageSlot ?? stateSlot) / SLOTS_PER_EPOCH);
// Get pre-computed fork schedule, which _should_ match the one in the state
const stateForkInfo = chainForkConfig.getForkInfo(stateSlot);
// Only allow to select either current or previous fork respective of the fork schedule at stateSlot
const forkName = epoch < stateForkInfo.epoch ? stateForkInfo.prevForkName : stateForkInfo.name;
const forkInfo = chainForkConfig.forks[forkName];
let domainByType = domainCache.get(forkInfo.name);
if (!domainByType) {
domainByType = new Map<DomainType, Uint8Array>();
domainCache.set(forkInfo.name, domainByType);
}
let domain = domainByType.get(domainType);
if (!domain) {
domain = computeDomain(domainType, forkInfo.version, genesisValidatorsRoot);
domainByType.set(domainType, domain);
}
return domain;
},
forkDigest2ForkName(forkDigest: ForkDigest | ForkDigestHex): ForkName {
const forkDigestHex = toHexStringNoPrefix(forkDigest);
const forkName = forkNameByForkDigest.get(forkDigestHex);
if (!forkName) {
throw Error(`Unknwon forkDigest ${forkDigestHex}`);
}
return forkName;
},
forkDigest2ForkNameOption(forkDigest: ForkDigest | ForkDigestHex): ForkName | null {
const forkDigestHex = toHexStringNoPrefix(forkDigest);
const forkName = forkNameByForkDigest.get(forkDigestHex);
if (!forkName) {
return null;
}
return forkName;
},
forkName2ForkDigest(forkName: ForkName): ForkDigest {
const forkDigest = forkDigestByForkName.get(forkName);
if (!forkDigest) {
throw Error(`No precomputed forkDigest for ${forkName}`);
}
return forkDigest;
},
forkName2ForkDigestHex(forkName: ForkName): ForkDigestHex {
const forkDigestHex = forkDigestHexByForkName.get(forkName);
if (!forkDigestHex) {
throw Error(`No precomputed forkDigest for ${forkName}`);
}
return toHexStringNoPrefix(forkDigestHex);
},
};
}
function computeDomain(domainType: DomainType, forkVersion: Version, genesisValidatorRoot: Root): Uint8Array {
const forkDataRoot = computeForkDataRoot(forkVersion, genesisValidatorRoot);
const domain = new Uint8Array(32);
domain.set(domainType, 0);
domain.set(forkDataRoot.slice(0, 28), 4);
return domain;
}
function computeForkDataRoot(currentVersion: Version, genesisValidatorsRoot: Root): Uint8Array {
const forkData: phase0.ForkData = {
currentVersion,
genesisValidatorsRoot,
};
return ssz.phase0.ForkData.hashTreeRoot(forkData);
}
function toHexStringNoPrefix(hex: string | Uint8Array): string {
return strip0xPrefix(typeof hex === "string" ? hex : toHexString(hex));
}
function strip0xPrefix(hex: string): string {
return hex.startsWith("0x") ? hex.slice(2) : hex;
}
function computeForkDigest(currentVersion: Version, genesisValidatorsRoot: Root): ForkDigest {
return computeForkDataRoot(currentVersion, genesisValidatorsRoot).slice(0, 4);
}