@chainsafe/lodestar 1.35.0-dev.8cacf063da → 1.35.0-dev.91dadf81de
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.git-data.json +1 -1
- package/bin/lodestar.js +3 -0
- package/bin/lodestar.ts +3 -0
- package/lib/applyPreset.d.ts.map +1 -0
- package/lib/cli.d.ts +3 -3
- package/lib/cli.d.ts.map +1 -0
- package/lib/cli.js +1 -1
- package/lib/cli.js.map +1 -1
- package/lib/cmds/beacon/handler.d.ts +1 -1
- package/lib/cmds/beacon/handler.d.ts.map +1 -0
- package/lib/cmds/beacon/handler.js +1 -1
- package/lib/cmds/beacon/handler.js.map +1 -1
- package/lib/cmds/beacon/index.d.ts.map +1 -0
- package/lib/cmds/beacon/initBeaconState.d.ts.map +1 -0
- package/lib/cmds/beacon/initBeaconState.js.map +1 -1
- package/lib/cmds/beacon/initPeerIdAndEnr.d.ts +2 -2
- package/lib/cmds/beacon/initPeerIdAndEnr.d.ts.map +1 -0
- package/lib/cmds/beacon/initPeerIdAndEnr.js +1 -1
- package/lib/cmds/beacon/initPeerIdAndEnr.js.map +1 -1
- package/lib/cmds/beacon/options.d.ts.map +1 -0
- package/lib/cmds/beacon/paths.d.ts.map +1 -0
- package/lib/cmds/bootnode/handler.d.ts +13 -8
- package/lib/cmds/bootnode/handler.d.ts.map +1 -0
- package/lib/cmds/bootnode/handler.js +2 -2
- package/lib/cmds/bootnode/handler.js.map +1 -1
- package/lib/cmds/bootnode/index.d.ts.map +1 -0
- package/lib/cmds/bootnode/options.d.ts.map +1 -0
- package/lib/cmds/bootnode/options.js +2 -1
- package/lib/cmds/bootnode/options.js.map +1 -1
- package/lib/cmds/dev/files.d.ts.map +1 -0
- package/lib/cmds/dev/handler.d.ts.map +1 -0
- package/lib/cmds/dev/handler.js +1 -1
- package/lib/cmds/dev/handler.js.map +1 -1
- package/lib/cmds/dev/index.d.ts.map +1 -0
- package/lib/cmds/dev/options.d.ts.map +1 -0
- package/lib/cmds/index.d.ts.map +1 -0
- package/lib/cmds/lightclient/handler.d.ts.map +1 -0
- package/lib/cmds/lightclient/index.d.ts.map +1 -0
- package/lib/cmds/lightclient/options.d.ts.map +1 -0
- package/lib/cmds/validator/blsToExecutionChange.d.ts.map +1 -0
- package/lib/cmds/validator/blsToExecutionChange.js.map +1 -1
- package/lib/cmds/validator/handler.d.ts.map +1 -0
- package/lib/cmds/validator/handler.js +3 -5
- package/lib/cmds/validator/handler.js.map +1 -1
- package/lib/cmds/validator/import.d.ts.map +1 -0
- package/lib/cmds/validator/index.d.ts.map +1 -0
- package/lib/cmds/validator/keymanager/decryptKeystoreDefinitions.d.ts.map +1 -0
- package/lib/cmds/validator/keymanager/decryptKeystores/index.d.ts.map +1 -0
- package/lib/cmds/validator/keymanager/decryptKeystores/poolSize.d.ts.map +1 -0
- package/lib/cmds/validator/keymanager/decryptKeystores/threadPool.d.ts.map +1 -0
- package/lib/cmds/validator/keymanager/decryptKeystores/threadPool.js +4 -1
- package/lib/cmds/validator/keymanager/decryptKeystores/threadPool.js.map +1 -1
- package/lib/cmds/validator/keymanager/decryptKeystores/types.d.ts.map +1 -0
- package/lib/cmds/validator/keymanager/decryptKeystores/worker.d.ts.map +1 -0
- package/lib/cmds/validator/keymanager/impl.d.ts.map +1 -0
- package/lib/cmds/validator/keymanager/impl.js +4 -0
- package/lib/cmds/validator/keymanager/impl.js.map +1 -1
- package/lib/cmds/validator/keymanager/interface.d.ts.map +1 -0
- package/lib/cmds/validator/keymanager/keystoreCache.d.ts.map +1 -0
- package/lib/cmds/validator/keymanager/persistedKeys.d.ts.map +1 -0
- package/lib/cmds/validator/keymanager/persistedKeys.js +1 -0
- package/lib/cmds/validator/keymanager/persistedKeys.js.map +1 -1
- package/lib/cmds/validator/keymanager/server.d.ts.map +1 -0
- package/lib/cmds/validator/keymanager/server.js +2 -0
- package/lib/cmds/validator/keymanager/server.js.map +1 -1
- package/lib/cmds/validator/list.d.ts.map +1 -0
- package/lib/cmds/validator/options.d.ts.map +1 -0
- package/lib/cmds/validator/paths.d.ts.map +1 -0
- package/lib/cmds/validator/signers/importExternalKeystores.d.ts.map +1 -0
- package/lib/cmds/validator/signers/index.d.ts.map +1 -0
- package/lib/cmds/validator/signers/logSigners.d.ts.map +1 -0
- package/lib/cmds/validator/slashingProtection/export.d.ts.map +1 -0
- package/lib/cmds/validator/slashingProtection/import.d.ts.map +1 -0
- package/lib/cmds/validator/slashingProtection/index.d.ts.map +1 -0
- package/lib/cmds/validator/slashingProtection/options.d.ts.map +1 -0
- package/lib/cmds/validator/slashingProtection/utils.d.ts.map +1 -0
- package/lib/cmds/validator/slashingProtection/utils.js +1 -1
- package/lib/cmds/validator/slashingProtection/utils.js.map +1 -1
- package/lib/cmds/validator/voluntaryExit.d.ts.map +1 -0
- package/lib/cmds/validator/voluntaryExit.js +1 -1
- package/lib/cmds/validator/voluntaryExit.js.map +1 -1
- package/lib/config/beaconNodeOptions.d.ts.map +1 -0
- package/lib/config/beaconNodeOptions.js +2 -1
- package/lib/config/beaconNodeOptions.js.map +1 -1
- package/lib/config/beaconParams.d.ts.map +1 -0
- package/lib/config/index.d.ts.map +1 -0
- package/lib/config/peerId.d.ts.map +1 -0
- package/lib/config/types.d.ts.map +1 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js.map +1 -1
- package/lib/migrations/index.d.ts +1 -0
- package/lib/migrations/index.d.ts.map +1 -0
- package/lib/migrations/index.js +1 -1
- package/lib/networks/chiado.d.ts.map +1 -0
- package/lib/networks/dev.d.ts.map +1 -0
- package/lib/networks/ephemery.d.ts.map +1 -0
- package/lib/networks/gnosis.d.ts.map +1 -0
- package/lib/networks/holesky.d.ts.map +1 -0
- package/lib/networks/hoodi.d.ts.map +1 -0
- package/lib/networks/index.d.ts.map +1 -0
- package/lib/networks/index.js +1 -2
- package/lib/networks/index.js.map +1 -1
- package/lib/networks/mainnet.d.ts.map +1 -0
- package/lib/networks/sepolia.d.ts.map +1 -0
- package/lib/options/beaconNodeOptions/api.d.ts.map +1 -0
- package/lib/options/beaconNodeOptions/builder.d.ts.map +1 -0
- package/lib/options/beaconNodeOptions/chain.d.ts.map +1 -0
- package/lib/options/beaconNodeOptions/eth1.d.ts.map +1 -0
- package/lib/options/beaconNodeOptions/execution.d.ts.map +1 -0
- package/lib/options/beaconNodeOptions/index.d.ts.map +1 -0
- package/lib/options/beaconNodeOptions/metrics.d.ts.map +1 -0
- package/lib/options/beaconNodeOptions/monitoring.d.ts.map +1 -0
- package/lib/options/beaconNodeOptions/network.d.ts +1 -0
- package/lib/options/beaconNodeOptions/network.d.ts.map +1 -0
- package/lib/options/beaconNodeOptions/network.js +6 -3
- package/lib/options/beaconNodeOptions/network.js.map +1 -1
- package/lib/options/beaconNodeOptions/sync.d.ts.map +1 -0
- package/lib/options/globalOptions.d.ts.map +1 -0
- package/lib/options/index.d.ts.map +1 -0
- package/lib/options/logOptions.d.ts.map +1 -0
- package/lib/options/paramsOptions.d.ts.map +1 -0
- package/lib/paths/global.d.ts.map +1 -0
- package/lib/paths/rootDir.d.ts.map +1 -0
- package/lib/util/errors.d.ts.map +1 -0
- package/lib/util/ethers.d.ts.map +1 -0
- package/lib/util/feeRecipient.d.ts.map +1 -0
- package/lib/util/file.d.ts.map +1 -0
- package/lib/util/file.js +1 -1
- package/lib/util/file.js.map +1 -1
- package/lib/util/format.d.ts.map +1 -0
- package/lib/util/fs.d.ts.map +1 -0
- package/lib/util/gitData/gitDataPath.d.ts.map +1 -0
- package/lib/util/gitData/index.d.ts.map +1 -0
- package/lib/util/gitData/index.js.map +1 -1
- package/lib/util/gitData/writeGitData.d.ts.map +1 -0
- package/lib/util/index.d.ts +3 -3
- package/lib/util/index.d.ts.map +1 -0
- package/lib/util/index.js +3 -3
- package/lib/util/index.js.map +1 -1
- package/lib/util/jwt.d.ts.map +1 -0
- package/lib/util/lockfile.d.ts.map +1 -0
- package/lib/util/logger.d.ts.map +1 -0
- package/lib/util/object.d.ts.map +1 -0
- package/lib/util/object.js.map +1 -1
- package/lib/util/passphrase.d.ts.map +1 -0
- package/lib/util/process.d.ts.map +1 -0
- package/lib/util/progress.d.ts.map +1 -0
- package/lib/util/proposerConfig.d.ts.map +1 -0
- package/lib/util/proposerConfig.js.map +1 -1
- package/lib/util/pruneOldFilesInDir.d.ts.map +1 -0
- package/lib/util/sleep.d.ts.map +1 -0
- package/lib/util/stripOffNewlines.d.ts.map +1 -0
- package/lib/util/types.d.ts.map +1 -0
- package/lib/util/version.d.ts.map +1 -0
- package/package.json +20 -19
- package/src/applyPreset.ts +91 -0
- package/src/cli.ts +56 -0
- package/src/cmds/beacon/handler.ts +267 -0
- package/src/cmds/beacon/index.ts +18 -0
- package/src/cmds/beacon/initBeaconState.ts +275 -0
- package/src/cmds/beacon/initPeerIdAndEnr.ts +199 -0
- package/src/cmds/beacon/options.ts +214 -0
- package/src/cmds/beacon/paths.ts +62 -0
- package/src/cmds/bootnode/handler.ts +203 -0
- package/src/cmds/bootnode/index.ts +13 -0
- package/src/cmds/bootnode/options.ts +109 -0
- package/src/cmds/dev/files.ts +52 -0
- package/src/cmds/dev/handler.ts +86 -0
- package/src/cmds/dev/index.ts +18 -0
- package/src/cmds/dev/options.ts +110 -0
- package/src/cmds/index.ts +15 -0
- package/src/cmds/lightclient/handler.ts +36 -0
- package/src/cmds/lightclient/index.ts +18 -0
- package/src/cmds/lightclient/options.ts +21 -0
- package/src/cmds/validator/blsToExecutionChange.ts +91 -0
- package/src/cmds/validator/handler.ts +300 -0
- package/src/cmds/validator/import.ts +111 -0
- package/src/cmds/validator/index.ts +28 -0
- package/src/cmds/validator/keymanager/decryptKeystoreDefinitions.ts +189 -0
- package/src/cmds/validator/keymanager/decryptKeystores/index.ts +1 -0
- package/src/cmds/validator/keymanager/decryptKeystores/poolSize.ts +16 -0
- package/src/cmds/validator/keymanager/decryptKeystores/threadPool.ts +75 -0
- package/src/cmds/validator/keymanager/decryptKeystores/types.ts +12 -0
- package/src/cmds/validator/keymanager/decryptKeystores/worker.ts +24 -0
- package/src/cmds/validator/keymanager/impl.ts +425 -0
- package/src/cmds/validator/keymanager/interface.ts +35 -0
- package/src/cmds/validator/keymanager/keystoreCache.ts +91 -0
- package/src/cmds/validator/keymanager/persistedKeys.ts +268 -0
- package/src/cmds/validator/keymanager/server.ts +86 -0
- package/src/cmds/validator/list.ts +35 -0
- package/src/cmds/validator/options.ts +461 -0
- package/src/cmds/validator/paths.ts +95 -0
- package/src/cmds/validator/signers/importExternalKeystores.ts +69 -0
- package/src/cmds/validator/signers/index.ts +176 -0
- package/src/cmds/validator/signers/logSigners.ts +81 -0
- package/src/cmds/validator/slashingProtection/export.ts +110 -0
- package/src/cmds/validator/slashingProtection/import.ts +70 -0
- package/src/cmds/validator/slashingProtection/index.ts +12 -0
- package/src/cmds/validator/slashingProtection/options.ts +15 -0
- package/src/cmds/validator/slashingProtection/utils.ts +56 -0
- package/src/cmds/validator/voluntaryExit.ts +232 -0
- package/src/config/beaconNodeOptions.ts +68 -0
- package/src/config/beaconParams.ts +87 -0
- package/src/config/index.ts +3 -0
- package/src/config/peerId.ts +50 -0
- package/src/config/types.ts +3 -0
- package/src/index.ts +28 -0
- package/src/migrations/index.ts +0 -0
- package/src/networks/chiado.ts +20 -0
- package/src/networks/dev.ts +27 -0
- package/src/networks/ephemery.ts +9 -0
- package/src/networks/gnosis.ts +18 -0
- package/src/networks/holesky.ts +17 -0
- package/src/networks/hoodi.ts +16 -0
- package/src/networks/index.ts +236 -0
- package/src/networks/mainnet.ts +34 -0
- package/src/networks/sepolia.ts +17 -0
- package/src/options/beaconNodeOptions/api.ts +110 -0
- package/src/options/beaconNodeOptions/builder.ts +63 -0
- package/src/options/beaconNodeOptions/chain.ts +326 -0
- package/src/options/beaconNodeOptions/eth1.ts +95 -0
- package/src/options/beaconNodeOptions/execution.ts +92 -0
- package/src/options/beaconNodeOptions/index.ts +50 -0
- package/src/options/beaconNodeOptions/metrics.ts +39 -0
- package/src/options/beaconNodeOptions/monitoring.ts +61 -0
- package/src/options/beaconNodeOptions/network.ts +401 -0
- package/src/options/beaconNodeOptions/sync.ts +65 -0
- package/src/options/globalOptions.ts +72 -0
- package/src/options/index.ts +3 -0
- package/src/options/logOptions.ts +70 -0
- package/src/options/paramsOptions.ts +72 -0
- package/src/paths/global.ts +24 -0
- package/src/paths/rootDir.ts +11 -0
- package/src/util/errors.ts +20 -0
- package/src/util/ethers.ts +44 -0
- package/src/util/feeRecipient.ts +6 -0
- package/src/util/file.ts +167 -0
- package/src/util/format.ts +76 -0
- package/src/util/fs.ts +59 -0
- package/src/util/gitData/gitDataPath.ts +48 -0
- package/src/util/gitData/index.ts +70 -0
- package/src/util/gitData/writeGitData.ts +10 -0
- package/src/util/index.ts +17 -0
- package/src/util/jwt.ts +10 -0
- package/src/util/lockfile.ts +45 -0
- package/src/util/logger.ts +105 -0
- package/src/util/object.ts +15 -0
- package/src/util/passphrase.ts +25 -0
- package/src/util/process.ts +25 -0
- package/src/util/progress.ts +58 -0
- package/src/util/proposerConfig.ts +136 -0
- package/src/util/pruneOldFilesInDir.ts +27 -0
- package/src/util/sleep.ts +3 -0
- package/src/util/stripOffNewlines.ts +6 -0
- package/src/util/types.ts +8 -0
- package/src/util/version.ts +74 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import {getHeapStatistics} from "node:v8";
|
|
3
|
+
import {SignableENR} from "@chainsafe/enr";
|
|
4
|
+
import {hasher} from "@chainsafe/persistent-merkle-tree";
|
|
5
|
+
import {BeaconDb, BeaconNode} from "@lodestar/beacon-node";
|
|
6
|
+
import {ChainForkConfig, createBeaconConfig} from "@lodestar/config";
|
|
7
|
+
import {LevelDbController} from "@lodestar/db/controller/level";
|
|
8
|
+
import {LoggerNode, getNodeLogger} from "@lodestar/logger/node";
|
|
9
|
+
import {ACTIVE_PRESET, PresetName} from "@lodestar/params";
|
|
10
|
+
import {ErrorAborted, bytesToInt} from "@lodestar/utils";
|
|
11
|
+
import {ProcessShutdownCallback} from "@lodestar/validator";
|
|
12
|
+
import {BeaconNodeOptions, getBeaconConfigFromArgs} from "../../config/index.js";
|
|
13
|
+
import {getNetworkBootnodes, getNetworkData, isKnownNetworkName, readBootnodes} from "../../networks/index.js";
|
|
14
|
+
import {GlobalArgs, parseBeaconNodeArgs} from "../../options/index.js";
|
|
15
|
+
import {LogArgs} from "../../options/logOptions.js";
|
|
16
|
+
import {
|
|
17
|
+
cleanOldLogFiles,
|
|
18
|
+
mkdir,
|
|
19
|
+
onGracefulShutdown,
|
|
20
|
+
parseLoggerArgs,
|
|
21
|
+
pruneOldFilesInDir,
|
|
22
|
+
writeFile600Perm,
|
|
23
|
+
} from "../../util/index.js";
|
|
24
|
+
import {getVersionData} from "../../util/version.js";
|
|
25
|
+
import {initBeaconState} from "./initBeaconState.js";
|
|
26
|
+
import {initPrivateKeyAndEnr} from "./initPeerIdAndEnr.js";
|
|
27
|
+
import {BeaconArgs} from "./options.js";
|
|
28
|
+
import {getBeaconPaths} from "./paths.js";
|
|
29
|
+
|
|
30
|
+
const DEFAULT_RETENTION_SSZ_OBJECTS_HOURS = 15 * 24;
|
|
31
|
+
const HOURS_TO_MS = 3600 * 1000;
|
|
32
|
+
const EIGHT_GB = 8 * 1024 * 1024 * 1024;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Runs a beacon node.
|
|
36
|
+
*/
|
|
37
|
+
export async function beaconHandler(args: BeaconArgs & GlobalArgs): Promise<void> {
|
|
38
|
+
const {config, options, beaconPaths, network, version, commit, privateKey, logger} = await beaconHandlerInit(args);
|
|
39
|
+
|
|
40
|
+
if (hasher.name !== "hashtree") {
|
|
41
|
+
logger.warn(`hashtree is not supported, using hasher ${hasher.name}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const heapSizeLimit = getHeapStatistics().heap_size_limit;
|
|
45
|
+
if (heapSizeLimit < EIGHT_GB) {
|
|
46
|
+
logger.warn(
|
|
47
|
+
`Node.js heap size limit is too low, consider increasing it to at least ${EIGHT_GB}. See https://chainsafe.github.io/lodestar/faqs/#running-a-beacon-node for more details.`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// initialize directories
|
|
52
|
+
mkdir(beaconPaths.dataDir);
|
|
53
|
+
mkdir(beaconPaths.beaconDir);
|
|
54
|
+
mkdir(beaconPaths.dbDir);
|
|
55
|
+
|
|
56
|
+
const abortController = new AbortController();
|
|
57
|
+
|
|
58
|
+
logger.info("Lodestar", {network, version, commit});
|
|
59
|
+
// Callback for beacon to request forced exit, for e.g. in case of irrecoverable
|
|
60
|
+
// forkchoice errors
|
|
61
|
+
const processShutdownCallback: ProcessShutdownCallback = (err) => {
|
|
62
|
+
logger.error("Process shutdown requested", {}, err);
|
|
63
|
+
process.kill(process.pid, "SIGINT");
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
if (ACTIVE_PRESET === PresetName.minimal) logger.info("ACTIVE_PRESET == minimal preset");
|
|
67
|
+
|
|
68
|
+
const db = new BeaconDb(config, await LevelDbController.create(options.db, {metrics: null, logger}));
|
|
69
|
+
logger.info("Connected to LevelDB database", {path: options.db.name});
|
|
70
|
+
|
|
71
|
+
// BeaconNode setup
|
|
72
|
+
try {
|
|
73
|
+
const {anchorState, wsCheckpoint} = await initBeaconState(
|
|
74
|
+
options,
|
|
75
|
+
args,
|
|
76
|
+
config,
|
|
77
|
+
db,
|
|
78
|
+
logger,
|
|
79
|
+
abortController.signal
|
|
80
|
+
);
|
|
81
|
+
const beaconConfig = createBeaconConfig(config, anchorState.genesisValidatorsRoot);
|
|
82
|
+
const node = await BeaconNode.init({
|
|
83
|
+
opts: options,
|
|
84
|
+
config: beaconConfig,
|
|
85
|
+
db,
|
|
86
|
+
logger,
|
|
87
|
+
processShutdownCallback,
|
|
88
|
+
privateKey,
|
|
89
|
+
dataDir: beaconPaths.dataDir,
|
|
90
|
+
peerStoreDir: beaconPaths.peerStoreDir,
|
|
91
|
+
anchorState,
|
|
92
|
+
wsCheckpoint,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// dev debug option to have access to the BN instance
|
|
96
|
+
if (args.attachToGlobalThis) {
|
|
97
|
+
(globalThis as unknown as {bn: BeaconNode}).bn = node;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Prune invalid SSZ objects every interval
|
|
101
|
+
const {persistInvalidSszObjectsDir, persistInvalidSszObjects} = options.chain;
|
|
102
|
+
const pruneInvalidSSZObjectsInterval =
|
|
103
|
+
persistInvalidSszObjectsDir && persistInvalidSszObjects
|
|
104
|
+
? setInterval(() => {
|
|
105
|
+
try {
|
|
106
|
+
const deletedFileCount = pruneOldFilesInDir(
|
|
107
|
+
persistInvalidSszObjectsDir,
|
|
108
|
+
(args.persistInvalidSszObjectsRetentionHours ?? DEFAULT_RETENTION_SSZ_OBJECTS_HOURS) * HOURS_TO_MS
|
|
109
|
+
);
|
|
110
|
+
logger.info("Pruned invalid SSZ objects", {deletedFileCount});
|
|
111
|
+
} catch (e) {
|
|
112
|
+
logger.warn("Error pruning invalid SSZ objects", {persistInvalidSszObjectsDir}, e as Error);
|
|
113
|
+
}
|
|
114
|
+
// Run every ~1 hour
|
|
115
|
+
}, HOURS_TO_MS)
|
|
116
|
+
: null;
|
|
117
|
+
|
|
118
|
+
// Intercept SIGINT signal, to perform final ops before exiting
|
|
119
|
+
onGracefulShutdown(async () => {
|
|
120
|
+
if (args.persistNetworkIdentity) {
|
|
121
|
+
try {
|
|
122
|
+
const networkIdentity = await node.network.getNetworkIdentity();
|
|
123
|
+
const enrPath = path.join(beaconPaths.beaconDir, "enr");
|
|
124
|
+
writeFile600Perm(enrPath, networkIdentity.enr);
|
|
125
|
+
} catch (e) {
|
|
126
|
+
logger.warn("Unable to persist enr", {}, e as Error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
abortController.abort();
|
|
130
|
+
|
|
131
|
+
if (pruneInvalidSSZObjectsInterval !== null) {
|
|
132
|
+
clearInterval(pruneInvalidSSZObjectsInterval);
|
|
133
|
+
}
|
|
134
|
+
}, logger.info.bind(logger));
|
|
135
|
+
|
|
136
|
+
abortController.signal.addEventListener(
|
|
137
|
+
"abort",
|
|
138
|
+
async () => {
|
|
139
|
+
try {
|
|
140
|
+
await node.close();
|
|
141
|
+
logger.debug("Beacon node closed");
|
|
142
|
+
// Explicitly exit until active handles issue is resolved
|
|
143
|
+
// See https://github.com/ChainSafe/lodestar/issues/5642
|
|
144
|
+
process.exit(0);
|
|
145
|
+
} catch (e) {
|
|
146
|
+
logger.error("Error closing beacon node", {}, e as Error);
|
|
147
|
+
// Make sure db is always closed gracefully
|
|
148
|
+
await db.close();
|
|
149
|
+
// Must explicitly exit process due to potential active handles
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
{once: true}
|
|
154
|
+
);
|
|
155
|
+
} catch (e) {
|
|
156
|
+
await db.close();
|
|
157
|
+
|
|
158
|
+
if (e instanceof ErrorAborted) {
|
|
159
|
+
logger.info(e.message); // Let the user know the abort was received but don't print as error
|
|
160
|
+
} else {
|
|
161
|
+
throw e;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Separate function to simplify unit testing of options merging */
|
|
167
|
+
export async function beaconHandlerInit(args: BeaconArgs & GlobalArgs) {
|
|
168
|
+
const {config, network} = getBeaconConfigFromArgs(args);
|
|
169
|
+
|
|
170
|
+
const beaconNodeOptions = new BeaconNodeOptions(parseBeaconNodeArgs(args));
|
|
171
|
+
|
|
172
|
+
const {version, commit} = getVersionData();
|
|
173
|
+
const beaconPaths = getBeaconPaths(args, network);
|
|
174
|
+
// TODO: Rename db.name to db.path or db.location
|
|
175
|
+
beaconNodeOptions.set({db: {name: beaconPaths.dbDir}});
|
|
176
|
+
beaconNodeOptions.set({
|
|
177
|
+
chain: {
|
|
178
|
+
validatorMonitorLogs: args.validatorMonitorLogs,
|
|
179
|
+
persistInvalidSszObjectsDir: beaconPaths.persistInvalidSszObjectsDir,
|
|
180
|
+
persistOrphanedBlocksDir: beaconPaths.persistOrphanedBlocksDir,
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
// Add metrics metadata to show versioning + network info in Prometheus + Grafana
|
|
184
|
+
beaconNodeOptions.set({metrics: {metadata: {version, commit, network}}});
|
|
185
|
+
// Add detailed version string for API node/version endpoint
|
|
186
|
+
beaconNodeOptions.set({api: {commit, version}});
|
|
187
|
+
|
|
188
|
+
if (args.supernode) {
|
|
189
|
+
beaconNodeOptions.set({chain: {supernode: true}, network: {supernode: true}});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Set known depositContractDeployBlock
|
|
193
|
+
if (isKnownNetworkName(network)) {
|
|
194
|
+
const {depositContractDeployBlock} = getNetworkData(network);
|
|
195
|
+
beaconNodeOptions.set({eth1: {depositContractDeployBlock}});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const logger = initLogger(args, beaconPaths.dataDir, config);
|
|
199
|
+
const {privateKey, enr} = await initPrivateKeyAndEnr(args, beaconPaths.beaconDir, logger);
|
|
200
|
+
|
|
201
|
+
if (args.discv5 !== false) {
|
|
202
|
+
// Inject ENR to beacon options
|
|
203
|
+
beaconNodeOptions.set({network: {discv5: {enr: enr.encodeTxt(), config: {enrUpdate: !enr.ip && !enr.ip6}}}});
|
|
204
|
+
|
|
205
|
+
// Combine bootnodes from different sources
|
|
206
|
+
const bootnodes = (beaconNodeOptions.get().network?.discv5?.bootEnrs ?? []).concat(
|
|
207
|
+
args.bootnodesFile ? readBootnodes(args.bootnodesFile) : [],
|
|
208
|
+
isKnownNetworkName(network) ? await getNetworkBootnodes(network) : []
|
|
209
|
+
);
|
|
210
|
+
// Deduplicate and set combined bootnodes
|
|
211
|
+
beaconNodeOptions.set({network: {discv5: {bootEnrs: [...new Set(bootnodes)]}}});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
beaconNodeOptions.set({chain: {initialCustodyGroupCount: getInitialCustodyGroupCount(args, config, enr)}});
|
|
215
|
+
|
|
216
|
+
if (args.disableLightClientServer) {
|
|
217
|
+
beaconNodeOptions.set({chain: {disableLightClientServer: true}});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (args.private) {
|
|
221
|
+
beaconNodeOptions.set({network: {private: true}, api: {private: true}});
|
|
222
|
+
} else {
|
|
223
|
+
const versionStr = `Lodestar/${version}`;
|
|
224
|
+
const simpleVersionStr = version.split("/")[0];
|
|
225
|
+
// Add simple version string for libp2p agent version
|
|
226
|
+
beaconNodeOptions.set({network: {version: simpleVersionStr}});
|
|
227
|
+
// Add User-Agent header to all builder requests
|
|
228
|
+
beaconNodeOptions.set({executionBuilder: {userAgent: versionStr}});
|
|
229
|
+
// Set jwt version with version string
|
|
230
|
+
beaconNodeOptions.set({executionEngine: {jwtVersion: versionStr}, eth1: {jwtVersion: versionStr}});
|
|
231
|
+
// Set commit and version for ClientVersion
|
|
232
|
+
beaconNodeOptions.set({executionEngine: {commit, version}});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Render final options
|
|
236
|
+
const options = beaconNodeOptions.getWithDefaults();
|
|
237
|
+
|
|
238
|
+
return {config, options, beaconPaths, network, version, commit, privateKey, logger};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function initLogger(
|
|
242
|
+
args: LogArgs & Pick<GlobalArgs, "dataDir">,
|
|
243
|
+
dataDir: string,
|
|
244
|
+
config: ChainForkConfig,
|
|
245
|
+
fileName = "beacon.log"
|
|
246
|
+
): LoggerNode {
|
|
247
|
+
const defaultLogFilepath = path.join(dataDir, fileName);
|
|
248
|
+
const logger = getNodeLogger(parseLoggerArgs(args, {defaultLogFilepath}, config));
|
|
249
|
+
try {
|
|
250
|
+
cleanOldLogFiles(args, {defaultLogFilepath});
|
|
251
|
+
} catch (e) {
|
|
252
|
+
logger.debug("Not able to delete log files", {}, e as Error);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return logger;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function getInitialCustodyGroupCount(args: BeaconArgs & GlobalArgs, config: ChainForkConfig, enr: SignableENR): number {
|
|
259
|
+
if (args.supernode) {
|
|
260
|
+
return config.NUMBER_OF_CUSTODY_GROUPS;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const enrCgcBytes = enr.kvs.get("cgc");
|
|
264
|
+
const enrCgc = enrCgcBytes != null ? bytesToInt(enrCgcBytes, "be") : 0;
|
|
265
|
+
|
|
266
|
+
return Math.max(enrCgc, config.CUSTODY_REQUIREMENT);
|
|
267
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {CliCommand, CliCommandOptions} from "@lodestar/utils";
|
|
2
|
+
import {GlobalArgs} from "../../options/index.js";
|
|
3
|
+
import {beaconHandler} from "./handler.js";
|
|
4
|
+
import {BeaconArgs, beaconOptions} from "./options.js";
|
|
5
|
+
|
|
6
|
+
export const beacon: CliCommand<BeaconArgs, GlobalArgs> = {
|
|
7
|
+
command: "beacon",
|
|
8
|
+
describe: "Run a beacon chain node",
|
|
9
|
+
docsFolder: "run/beacon-management",
|
|
10
|
+
examples: [
|
|
11
|
+
{
|
|
12
|
+
command: "beacon --network hoodi",
|
|
13
|
+
description: "Run a beacon chain node and connect to the hoodi testnet",
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
options: beaconOptions as CliCommandOptions<BeaconArgs>,
|
|
17
|
+
handler: beaconHandler,
|
|
18
|
+
};
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IBeaconDb,
|
|
3
|
+
IBeaconNodeOptions,
|
|
4
|
+
checkAndPersistAnchorState,
|
|
5
|
+
getStateTypeFromBytes,
|
|
6
|
+
initStateFromEth1,
|
|
7
|
+
} from "@lodestar/beacon-node";
|
|
8
|
+
import {BeaconConfig, ChainForkConfig, createBeaconConfig} from "@lodestar/config";
|
|
9
|
+
import {
|
|
10
|
+
BeaconStateAllForks,
|
|
11
|
+
ensureWithinWeakSubjectivityPeriod,
|
|
12
|
+
isWithinWeakSubjectivityPeriod,
|
|
13
|
+
loadState,
|
|
14
|
+
loadStateAndValidators,
|
|
15
|
+
} from "@lodestar/state-transition";
|
|
16
|
+
import {ssz} from "@lodestar/types";
|
|
17
|
+
import {Checkpoint} from "@lodestar/types/phase0";
|
|
18
|
+
import {Logger, formatBytes, toRootHex} from "@lodestar/utils";
|
|
19
|
+
import {
|
|
20
|
+
fetchWeakSubjectivityState,
|
|
21
|
+
getCheckpointFromArg,
|
|
22
|
+
getCheckpointFromState,
|
|
23
|
+
getGenesisFileUrl,
|
|
24
|
+
getGenesisStateRoot,
|
|
25
|
+
} from "../../networks/index.js";
|
|
26
|
+
import {GlobalArgs, defaultNetwork} from "../../options/globalOptions.js";
|
|
27
|
+
import {downloadOrLoadFile, wrapFnError} from "../../util/index.js";
|
|
28
|
+
import {BeaconArgs} from "./options.js";
|
|
29
|
+
|
|
30
|
+
type StateWithBytes = {state: BeaconStateAllForks; stateBytes: Uint8Array};
|
|
31
|
+
|
|
32
|
+
async function initAndVerifyWeakSubjectivityState(
|
|
33
|
+
config: BeaconConfig,
|
|
34
|
+
db: IBeaconDb,
|
|
35
|
+
logger: Logger,
|
|
36
|
+
dbStateBytes: StateWithBytes,
|
|
37
|
+
wsStateBytes: StateWithBytes,
|
|
38
|
+
wsCheckpoint: Checkpoint,
|
|
39
|
+
opts: {ignoreWeakSubjectivityCheck?: boolean} = {}
|
|
40
|
+
): Promise<{anchorState: BeaconStateAllForks; wsCheckpoint: Checkpoint}> {
|
|
41
|
+
const dbState = dbStateBytes.state;
|
|
42
|
+
const wsState = wsStateBytes.state;
|
|
43
|
+
// Check if the store's state and wsState are compatible
|
|
44
|
+
if (
|
|
45
|
+
dbState.genesisTime !== wsState.genesisTime ||
|
|
46
|
+
!ssz.Root.equals(dbState.genesisValidatorsRoot, wsState.genesisValidatorsRoot)
|
|
47
|
+
) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
"Db state and checkpoint state are not compatible, either clear the db or verify your checkpoint source"
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Pick the state which is ahead as an anchor to initialize the beacon chain
|
|
54
|
+
let anchorState = wsStateBytes;
|
|
55
|
+
let anchorCheckpoint = wsCheckpoint;
|
|
56
|
+
let isCheckpointState = true;
|
|
57
|
+
if (dbState.slot > wsState.slot) {
|
|
58
|
+
anchorState = dbStateBytes;
|
|
59
|
+
anchorCheckpoint = getCheckpointFromState(dbState);
|
|
60
|
+
isCheckpointState = false;
|
|
61
|
+
logger.verbose(
|
|
62
|
+
"Db state is ahead of the provided checkpoint state, using the db state to initialize the beacon chain"
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Throw error unless user explicitly asked not to, in testnets can happen that wss period is too small
|
|
67
|
+
// that even some epochs of non finalization can cause finalized checkpoint to be out of valid range
|
|
68
|
+
const wssCheck = wrapFnError(() => ensureWithinWeakSubjectivityPeriod(config, anchorState.state, anchorCheckpoint));
|
|
69
|
+
const isWithinWeakSubjectivityPeriod = wssCheck.err === null;
|
|
70
|
+
if (!isWithinWeakSubjectivityPeriod && !opts.ignoreWeakSubjectivityCheck) {
|
|
71
|
+
throw wssCheck.err;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
await checkAndPersistAnchorState(config, db, logger, anchorState.state, anchorState.stateBytes, {
|
|
75
|
+
isWithinWeakSubjectivityPeriod,
|
|
76
|
+
isCheckpointState,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Return the latest anchorState but still return original wsCheckpoint to validate in backfill
|
|
80
|
+
return {anchorState: anchorState.state, wsCheckpoint};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Initialize a beacon state, picking the strategy based on the `IBeaconArgs`
|
|
85
|
+
*
|
|
86
|
+
* State is initialized in one of three ways:
|
|
87
|
+
* 1. restore from weak subjectivity state (possibly downloaded from a remote beacon node)
|
|
88
|
+
* 2. restore from db
|
|
89
|
+
* 3. restore from genesis state (possibly downloaded via URL)
|
|
90
|
+
* 4. create genesis state from eth1
|
|
91
|
+
*/
|
|
92
|
+
export async function initBeaconState(
|
|
93
|
+
options: IBeaconNodeOptions,
|
|
94
|
+
args: BeaconArgs & GlobalArgs,
|
|
95
|
+
chainForkConfig: ChainForkConfig,
|
|
96
|
+
db: IBeaconDb,
|
|
97
|
+
logger: Logger,
|
|
98
|
+
signal: AbortSignal
|
|
99
|
+
): Promise<{anchorState: BeaconStateAllForks; wsCheckpoint?: Checkpoint}> {
|
|
100
|
+
if (args.forceCheckpointSync && !(args.checkpointState || args.checkpointSyncUrl)) {
|
|
101
|
+
throw new Error("Forced checkpoint sync without specifying a checkpointState or checkpointSyncUrl");
|
|
102
|
+
}
|
|
103
|
+
// fetch the latest state stored in the db which will be used in all cases, if it exists, either
|
|
104
|
+
// i) used directly as the anchor state
|
|
105
|
+
// ii) used to load and verify a weak subjectivity state,
|
|
106
|
+
const lastDbSlot = await db.stateArchive.lastKey();
|
|
107
|
+
let stateBytes = lastDbSlot !== null ? await db.stateArchive.getBinary(lastDbSlot) : null;
|
|
108
|
+
// Convert to `Uint8Array` to avoid unexpected behavior such as `Buffer.prototype.slice` not copying memory
|
|
109
|
+
stateBytes = stateBytes ? new Uint8Array(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength) : null;
|
|
110
|
+
let lastDbState: BeaconStateAllForks | null = null;
|
|
111
|
+
let lastDbValidatorsBytes: Uint8Array | null = null;
|
|
112
|
+
let lastDbStateWithBytes: StateWithBytes | null = null;
|
|
113
|
+
if (stateBytes) {
|
|
114
|
+
logger.verbose("Found the last archived state", {slot: lastDbSlot, size: formatBytes(stateBytes.length)});
|
|
115
|
+
const {state, validatorsBytes} = loadStateAndValidators(chainForkConfig, stateBytes);
|
|
116
|
+
lastDbState = state;
|
|
117
|
+
lastDbValidatorsBytes = validatorsBytes;
|
|
118
|
+
lastDbStateWithBytes = {state, stateBytes: stateBytes};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (lastDbState) {
|
|
122
|
+
const config = createBeaconConfig(chainForkConfig, lastDbState.genesisValidatorsRoot);
|
|
123
|
+
const wssCheck = isWithinWeakSubjectivityPeriod(config, lastDbState, getCheckpointFromState(lastDbState));
|
|
124
|
+
|
|
125
|
+
// Explicitly force syncing from checkpoint state
|
|
126
|
+
if (args.forceCheckpointSync) {
|
|
127
|
+
// Forcing to sync from checkpoint is only recommended if node is taking too long to sync from last db state.
|
|
128
|
+
// It is important to remind the user to remove this flag again unless it is absolutely necessary.
|
|
129
|
+
if (wssCheck) {
|
|
130
|
+
logger.warn(
|
|
131
|
+
`Forced syncing from checkpoint even though db state at slot ${lastDbState.slot} is within weak subjectivity period`
|
|
132
|
+
);
|
|
133
|
+
logger.warn("Please consider removing --forceCheckpointSync flag unless absolutely necessary");
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
// All cases when we want to directly use lastDbState as the anchor state:
|
|
137
|
+
// - if no checkpoint sync args provided, or
|
|
138
|
+
// - the lastDbState is within weak subjectivity period:
|
|
139
|
+
if ((!args.checkpointState && !args.checkpointSyncUrl) || wssCheck) {
|
|
140
|
+
if (stateBytes === null) {
|
|
141
|
+
// this never happens
|
|
142
|
+
throw Error(`There is no stateBytes for the lastDbState at slot ${lastDbState.slot}`);
|
|
143
|
+
}
|
|
144
|
+
await checkAndPersistAnchorState(config, db, logger, lastDbState, stateBytes, {
|
|
145
|
+
isWithinWeakSubjectivityPeriod: wssCheck,
|
|
146
|
+
isCheckpointState: false,
|
|
147
|
+
});
|
|
148
|
+
return {anchorState: lastDbState};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// See if we can sync state using checkpoint sync args or else start from genesis
|
|
154
|
+
if (args.checkpointState) {
|
|
155
|
+
return readWSState(
|
|
156
|
+
lastDbStateWithBytes,
|
|
157
|
+
lastDbValidatorsBytes,
|
|
158
|
+
{
|
|
159
|
+
checkpointState: args.checkpointState,
|
|
160
|
+
wssCheckpoint: args.wssCheckpoint,
|
|
161
|
+
ignoreWeakSubjectivityCheck: args.ignoreWeakSubjectivityCheck,
|
|
162
|
+
},
|
|
163
|
+
chainForkConfig,
|
|
164
|
+
db,
|
|
165
|
+
logger
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (args.checkpointSyncUrl) {
|
|
170
|
+
return fetchWSStateFromBeaconApi(
|
|
171
|
+
lastDbStateWithBytes,
|
|
172
|
+
lastDbValidatorsBytes,
|
|
173
|
+
{
|
|
174
|
+
checkpointSyncUrl: args.checkpointSyncUrl,
|
|
175
|
+
wssCheckpoint: args.wssCheckpoint,
|
|
176
|
+
ignoreWeakSubjectivityCheck: args.ignoreWeakSubjectivityCheck,
|
|
177
|
+
},
|
|
178
|
+
chainForkConfig,
|
|
179
|
+
db,
|
|
180
|
+
logger
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const genesisStateFile = args.genesisStateFile || getGenesisFileUrl(args.network || defaultNetwork);
|
|
185
|
+
if (genesisStateFile && !args.forceGenesis) {
|
|
186
|
+
let stateBytes = await downloadOrLoadFile(genesisStateFile);
|
|
187
|
+
// Convert to `Uint8Array` to avoid unexpected behavior such as `Buffer.prototype.slice` not copying memory
|
|
188
|
+
stateBytes = new Uint8Array(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength);
|
|
189
|
+
const anchorState = getStateTypeFromBytes(chainForkConfig, stateBytes).deserializeToViewDU(stateBytes);
|
|
190
|
+
// Validate genesis state root
|
|
191
|
+
const stateRoot = toRootHex(anchorState.hashTreeRoot());
|
|
192
|
+
const expectedRoot = getGenesisStateRoot(args.network);
|
|
193
|
+
if (expectedRoot !== null && stateRoot !== expectedRoot) {
|
|
194
|
+
throw Error(`Genesis state root mismatch expected=${expectedRoot} received=${stateRoot}`);
|
|
195
|
+
}
|
|
196
|
+
const config = createBeaconConfig(chainForkConfig, anchorState.genesisValidatorsRoot);
|
|
197
|
+
const wssCheck = isWithinWeakSubjectivityPeriod(config, anchorState, getCheckpointFromState(anchorState));
|
|
198
|
+
await checkAndPersistAnchorState(config, db, logger, anchorState, stateBytes, {
|
|
199
|
+
isWithinWeakSubjectivityPeriod: wssCheck,
|
|
200
|
+
isCheckpointState: true,
|
|
201
|
+
});
|
|
202
|
+
return {anchorState};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Only place we will not bother checking isWithinWeakSubjectivityPeriod as forceGenesis passed by user
|
|
206
|
+
const anchorState = await initStateFromEth1({config: chainForkConfig, db, logger, opts: options.eth1, signal});
|
|
207
|
+
return {anchorState};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async function readWSState(
|
|
211
|
+
lastDbStateBytes: StateWithBytes | null,
|
|
212
|
+
lastDbValidatorsBytes: Uint8Array | null,
|
|
213
|
+
wssOpts: {checkpointState: string; wssCheckpoint?: string; ignoreWeakSubjectivityCheck?: boolean},
|
|
214
|
+
chainForkConfig: ChainForkConfig,
|
|
215
|
+
db: IBeaconDb,
|
|
216
|
+
logger: Logger
|
|
217
|
+
): Promise<{anchorState: BeaconStateAllForks; wsCheckpoint?: Checkpoint}> {
|
|
218
|
+
// weak subjectivity sync from a provided state file:
|
|
219
|
+
// if a weak subjectivity checkpoint has been provided, it is used for additional verification
|
|
220
|
+
// otherwise, the state itself is used for verification (not bad, because the trusted state has been explicitly provided)
|
|
221
|
+
const {checkpointState, wssCheckpoint, ignoreWeakSubjectivityCheck} = wssOpts;
|
|
222
|
+
const lastDbState = lastDbStateBytes?.state ?? null;
|
|
223
|
+
|
|
224
|
+
const stateBytes = await downloadOrLoadFile(checkpointState);
|
|
225
|
+
let wsState: BeaconStateAllForks;
|
|
226
|
+
if (lastDbState && lastDbValidatorsBytes) {
|
|
227
|
+
// use lastDbState to load wsState if possible to share the same state tree
|
|
228
|
+
wsState = loadState(chainForkConfig, lastDbState, stateBytes, lastDbValidatorsBytes).state;
|
|
229
|
+
} else {
|
|
230
|
+
wsState = getStateTypeFromBytes(chainForkConfig, stateBytes).deserializeToViewDU(stateBytes);
|
|
231
|
+
}
|
|
232
|
+
const config = createBeaconConfig(chainForkConfig, wsState.genesisValidatorsRoot);
|
|
233
|
+
const wsStateBytes = {state: wsState, stateBytes};
|
|
234
|
+
const store = lastDbStateBytes ?? wsStateBytes;
|
|
235
|
+
const checkpoint = wssCheckpoint ? getCheckpointFromArg(wssCheckpoint) : getCheckpointFromState(wsState);
|
|
236
|
+
return initAndVerifyWeakSubjectivityState(config, db, logger, store, wsStateBytes, checkpoint, {
|
|
237
|
+
ignoreWeakSubjectivityCheck,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function fetchWSStateFromBeaconApi(
|
|
242
|
+
lastDbStateBytes: StateWithBytes | null,
|
|
243
|
+
lastDbValidatorsBytes: Uint8Array | null,
|
|
244
|
+
wssOpts: {checkpointSyncUrl: string; wssCheckpoint?: string; ignoreWeakSubjectivityCheck?: boolean},
|
|
245
|
+
chainForkConfig: ChainForkConfig,
|
|
246
|
+
db: IBeaconDb,
|
|
247
|
+
logger: Logger
|
|
248
|
+
): Promise<{anchorState: BeaconStateAllForks; wsCheckpoint?: Checkpoint}> {
|
|
249
|
+
// weak subjectivity sync from a state that needs to be fetched:
|
|
250
|
+
// if a weak subjectivity checkpoint has been provided, it is used to inform which state to download and used for additional verification
|
|
251
|
+
// otherwise, the 'finalized' state is downloaded and the state itself is used for verification (all trust delegated to the remote beacon node)
|
|
252
|
+
try {
|
|
253
|
+
// Validate the weakSubjectivityServerUrl and only log the origin to mask the
|
|
254
|
+
// username password credentials
|
|
255
|
+
const checkpointSyncUrl = new URL(wssOpts.checkpointSyncUrl);
|
|
256
|
+
logger.info("Fetching checkpoint state", {
|
|
257
|
+
checkpointSyncUrl: checkpointSyncUrl.origin,
|
|
258
|
+
});
|
|
259
|
+
} catch (e) {
|
|
260
|
+
logger.error("Invalid", {checkpointSyncUrl: wssOpts.checkpointSyncUrl}, e as Error);
|
|
261
|
+
throw e;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const {wsState, wsStateBytes, wsCheckpoint} = await fetchWeakSubjectivityState(chainForkConfig, logger, wssOpts, {
|
|
265
|
+
lastDbState: lastDbStateBytes?.state ?? null,
|
|
266
|
+
lastDbValidatorsBytes,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const config = createBeaconConfig(chainForkConfig, wsState.genesisValidatorsRoot);
|
|
270
|
+
const wsStateWithBytes = {state: wsState, stateBytes: wsStateBytes};
|
|
271
|
+
const store = lastDbStateBytes ?? wsStateWithBytes;
|
|
272
|
+
return initAndVerifyWeakSubjectivityState(config, db, logger, store, wsStateWithBytes, wsCheckpoint, {
|
|
273
|
+
ignoreWeakSubjectivityCheck: wssOpts.ignoreWeakSubjectivityCheck,
|
|
274
|
+
});
|
|
275
|
+
}
|