-
-
Notifications
You must be signed in to change notification settings - Fork 314
/
Copy pathtestFileCache.ts
116 lines (100 loc) · 3.99 KB
/
testFileCache.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
import fs from "node:fs";
import path from "node:path";
import got from "got";
import {getClient} from "@chainsafe/lodestar-api";
import {NetworkName, networksChainConfig} from "@chainsafe/lodestar-config/networks";
import {createIChainForkConfig, IChainForkConfig} from "@chainsafe/lodestar-config";
import {CachedBeaconStateAllForks, computeEpochAtSlot} from "../../src";
import {getInfuraBeaconUrl} from "./infura";
import {testCachePath} from "../cache";
import {createCachedBeaconStateTest} from "../utils/state";
import {allForks} from "@chainsafe/lodestar-types";
/**
* Full link example:
* ```
* https://github.com/dapplion/ethereum-consensus-test-data/releases/download/v0.1.0/block_mainnet_3766821.ssz
* ``` */
const TEST_FILES_BASE_URL = "https://github.com/dapplion/ethereum-consensus-test-data/releases/download/v0.1.0";
/**
* Create a network config from known network params
*/
export function getNetworkConfig(network: NetworkName): IChainForkConfig {
const configNetwork = networksChainConfig[network];
return createIChainForkConfig(configNetwork);
}
/**
* Download a state from Infura. Caches states in local fs by network and slot to only download once.
*/
export async function getNetworkCachedState(
network: NetworkName,
slot: number,
timeout?: number
): Promise<CachedBeaconStateAllForks> {
const config = getNetworkConfig(network);
const fileId = `state_${network}_${slot}.ssz`;
const filepath = path.join(testCachePath, fileId);
if (fs.existsSync(filepath)) {
const stateSsz = fs.readFileSync(filepath);
return createCachedBeaconStateTest(config.getForkTypes(slot).BeaconState.deserializeToViewDU(stateSsz), config);
} else {
const stateSsz = await tryEach([
() => downloadTestFile(fileId),
() => {
const client = getClient({baseUrl: getInfuraBeaconUrl(network), timeoutMs: timeout ?? 300_000}, {config});
return computeEpochAtSlot(slot) < config.ALTAIR_FORK_EPOCH
? client.debug.getState(String(slot), "ssz")
: client.debug.getStateV2(String(slot), "ssz");
},
]);
fs.writeFileSync(filepath, stateSsz);
return createCachedBeaconStateTest(config.getForkTypes(slot).BeaconState.deserializeToViewDU(stateSsz), config);
}
}
/**
* Download a state from Infura. Caches states in local fs by network and slot to only download once.
*/
export async function getNetworkCachedBlock(
network: NetworkName,
slot: number,
timeout?: number
): Promise<allForks.SignedBeaconBlock> {
const config = getNetworkConfig(network);
const fileId = `block_${network}_${slot}.ssz`;
const filepath = path.join(testCachePath, fileId);
if (fs.existsSync(filepath)) {
const blockSsz = fs.readFileSync(filepath);
return config.getForkTypes(slot).SignedBeaconBlock.deserialize(blockSsz);
} else {
const blockSsz = await tryEach([
() => downloadTestFile(fileId),
async () => {
const client = getClient({baseUrl: getInfuraBeaconUrl(network), timeoutMs: timeout ?? 300_000}, {config});
const res =
computeEpochAtSlot(slot) < config.ALTAIR_FORK_EPOCH
? await client.beacon.getBlock(String(slot))
: await client.beacon.getBlockV2(String(slot));
return config.getForkTypes(slot).SignedBeaconBlock.serialize(res.data);
},
]);
fs.writeFileSync(filepath, blockSsz);
return config.getForkTypes(slot).SignedBeaconBlock.deserialize(blockSsz);
}
}
async function downloadTestFile(fileId: string): Promise<Buffer> {
const fileUrl = `${TEST_FILES_BASE_URL}/${fileId}`;
// eslint-disable-next-line no-console
console.log(`Downloading file ${fileUrl}`);
const res = await got(fileUrl, {responseType: "buffer"});
return res.body;
}
async function tryEach<T>(promises: (() => Promise<T>)[]): Promise<T> {
const errors: Error[] = [];
for (let i = 0; i < promises.length; i++) {
try {
return promises[i]();
} catch (e) {
errors.push(e as Error);
}
}
throw Error(errors.map((e, i) => `Error[${i}] ${e.message}`).join("\n"));
}