@chainsafe/lodestar 1.35.0-dev.feed916580 → 1.35.0-rc.1
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 +2 -2
- 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.map +1 -0
- 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/initPeerIdAndEnr.d.ts.map +1 -0
- 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.map +1 -0
- package/lib/cmds/bootnode/index.d.ts.map +1 -0
- package/lib/cmds/bootnode/options.d.ts.map +1 -0
- package/lib/cmds/dev/files.d.ts.map +1 -0
- package/lib/cmds/dev/handler.d.ts.map +1 -0
- 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/handler.d.ts.map +1 -0
- package/lib/cmds/validator/handler.js +1 -1
- 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/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/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/server.d.ts.map +1 -0
- 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/config/beaconNodeOptions.d.ts.map +1 -0
- 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/migrations/index.d.ts.map +1 -0
- 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/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.map +1 -0
- 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.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/writeGitData.d.ts.map +1 -0
- package/lib/util/index.d.ts.map +1 -0
- 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/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/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 +19 -18
- 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,62 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import {GlobalArgs} from "../../options/index.js";
|
|
3
|
+
import {GlobalPaths, getGlobalPaths} from "../../paths/global.js";
|
|
4
|
+
|
|
5
|
+
export type BeaconPathsPartial = Partial<{
|
|
6
|
+
beaconDir: string;
|
|
7
|
+
peerStoreDir: string;
|
|
8
|
+
dbDir: string;
|
|
9
|
+
persistInvalidSszObjectsDir: string;
|
|
10
|
+
persistOrphanedBlocksDir?: string;
|
|
11
|
+
}>;
|
|
12
|
+
|
|
13
|
+
export type BeaconPaths = {
|
|
14
|
+
beaconDir: string;
|
|
15
|
+
peerStoreDir: string;
|
|
16
|
+
dbDir: string;
|
|
17
|
+
persistInvalidSszObjectsDir: string;
|
|
18
|
+
persistOrphanedBlocksDir: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Defines the path structure of the files relevant to the beacon node
|
|
23
|
+
*
|
|
24
|
+
* ```bash
|
|
25
|
+
* $dataDir
|
|
26
|
+
* └── $beaconDir
|
|
27
|
+
* ├── beacon.config.json
|
|
28
|
+
* ├── peer-id.json
|
|
29
|
+
* ├── enr
|
|
30
|
+
* ├── chain-db
|
|
31
|
+
* └── beacon.log
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function getBeaconPaths(
|
|
35
|
+
// Using Pick<GlobalArgs, "dataDir"> make changes in GlobalArgs throw a type error here
|
|
36
|
+
args: BeaconPathsPartial & Pick<GlobalArgs, "dataDir">,
|
|
37
|
+
network: string
|
|
38
|
+
): GlobalPaths & Required<BeaconPathsPartial> {
|
|
39
|
+
// Compute global paths first
|
|
40
|
+
const globalPaths = getGlobalPaths(args, network);
|
|
41
|
+
|
|
42
|
+
const dataDir = globalPaths.dataDir;
|
|
43
|
+
const beaconDir = dataDir;
|
|
44
|
+
const dbDir = args.dbDir ?? path.join(beaconDir, "chain-db");
|
|
45
|
+
const persistInvalidSszObjectsDir = args.persistInvalidSszObjectsDir ?? path.join(beaconDir, "invalidSszObjects");
|
|
46
|
+
const peerStoreDir = args.peerStoreDir ?? path.join(beaconDir, "peerstore");
|
|
47
|
+
const persistOrphanedBlocksDir = args.persistOrphanedBlocksDir ?? path.join(beaconDir, "orphaned_blocks");
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
...globalPaths,
|
|
51
|
+
beaconDir,
|
|
52
|
+
dbDir,
|
|
53
|
+
persistInvalidSszObjectsDir,
|
|
54
|
+
peerStoreDir,
|
|
55
|
+
persistOrphanedBlocksDir,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Constructs representations of the path structure to show in command's description
|
|
61
|
+
*/
|
|
62
|
+
export const defaultBeaconPaths = getBeaconPaths({dataDir: "$dataDir"}, "$network");
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import {PrivateKey} from "@libp2p/interface";
|
|
3
|
+
import {Multiaddr, multiaddr} from "@multiformats/multiaddr";
|
|
4
|
+
import {Discv5, Discv5EventEmitter} from "@chainsafe/discv5";
|
|
5
|
+
import {ENR, ENRData, SignableENR} from "@chainsafe/enr";
|
|
6
|
+
import {
|
|
7
|
+
HttpMetricsServer,
|
|
8
|
+
IBeaconNodeOptions,
|
|
9
|
+
RegistryMetricCreator,
|
|
10
|
+
getHttpMetricsServer,
|
|
11
|
+
} from "@lodestar/beacon-node";
|
|
12
|
+
import {ErrorAborted, Logger} from "@lodestar/utils";
|
|
13
|
+
import {getBeaconConfigFromArgs} from "../../config/index.js";
|
|
14
|
+
import {getNetworkBootnodes, isKnownNetworkName, readBootnodes} from "../../networks/index.js";
|
|
15
|
+
import {parseArgs as parseMetricsArgs} from "../../options/beaconNodeOptions/metrics.js";
|
|
16
|
+
import {parseArgs as parseNetworkArgs} from "../../options/beaconNodeOptions/network.js";
|
|
17
|
+
import {GlobalArgs} from "../../options/index.js";
|
|
18
|
+
import {mkdir, onGracefulShutdown, writeFile600Perm} from "../../util/index.js";
|
|
19
|
+
import {getVersionData} from "../../util/version.js";
|
|
20
|
+
import {initLogger} from "../beacon/handler.js";
|
|
21
|
+
import {initPrivateKeyAndEnr} from "../beacon/initPeerIdAndEnr.js";
|
|
22
|
+
import {BeaconArgs} from "../beacon/options.js";
|
|
23
|
+
import {getBeaconPaths} from "../beacon/paths.js";
|
|
24
|
+
import {BootnodeArgs} from "./options.js";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Runs a bootnode.
|
|
28
|
+
*/
|
|
29
|
+
export async function bootnodeHandler(args: BootnodeArgs & GlobalArgs): Promise<void> {
|
|
30
|
+
const {discv5Args, metricsArgs, bootnodeDir, network, version, commit, privateKey, enr, logger} =
|
|
31
|
+
await bootnodeHandlerInit(args);
|
|
32
|
+
|
|
33
|
+
const abortController = new AbortController();
|
|
34
|
+
const bindAddrs = discv5Args.bindAddrs;
|
|
35
|
+
|
|
36
|
+
logger.info("Lodestar Bootnode", {network, version, commit});
|
|
37
|
+
logger.info("Bind address", bindAddrs);
|
|
38
|
+
logger.info("Advertised address", {
|
|
39
|
+
ip4: enr.getLocationMultiaddr("udp4")?.toString(),
|
|
40
|
+
ip6: enr.getLocationMultiaddr("udp6")?.toString(),
|
|
41
|
+
});
|
|
42
|
+
logger.info("Identity", {peerId: enr.peerId.toString(), nodeId: enr.nodeId});
|
|
43
|
+
logger.info("ENR", {enr: enr.encodeTxt()});
|
|
44
|
+
|
|
45
|
+
// bootnode setup
|
|
46
|
+
try {
|
|
47
|
+
let metricsRegistry: RegistryMetricCreator | undefined;
|
|
48
|
+
let metricsServer: HttpMetricsServer | undefined;
|
|
49
|
+
if (metricsArgs.enabled) {
|
|
50
|
+
metricsRegistry = new RegistryMetricCreator();
|
|
51
|
+
metricsRegistry.static({
|
|
52
|
+
name: "bootnode_version",
|
|
53
|
+
help: "Bootnode version",
|
|
54
|
+
value: {version, commit, network},
|
|
55
|
+
});
|
|
56
|
+
metricsServer = await getHttpMetricsServer(metricsArgs, {register: metricsRegistry, logger});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const discv5 = Discv5.create({
|
|
60
|
+
enr,
|
|
61
|
+
privateKey,
|
|
62
|
+
bindAddrs: {
|
|
63
|
+
ip4: (bindAddrs.ip4 ? multiaddr(bindAddrs.ip4) : undefined) as Multiaddr,
|
|
64
|
+
ip6: bindAddrs.ip6 ? multiaddr(bindAddrs.ip6) : undefined,
|
|
65
|
+
},
|
|
66
|
+
config: {enrUpdate: !enr.ip && !enr.ip6},
|
|
67
|
+
metricsRegistry,
|
|
68
|
+
}) as Discv5 & Discv5EventEmitter;
|
|
69
|
+
|
|
70
|
+
// If there are any bootnodes, add them to the routing table
|
|
71
|
+
for (const bootEnrStr of Array.from(new Set(discv5Args.bootEnrs).values())) {
|
|
72
|
+
const bootEnr = ENR.decodeTxt(bootEnrStr);
|
|
73
|
+
logger.info("Adding bootnode", {
|
|
74
|
+
ip4: bootEnr.getLocationMultiaddr("udp4")?.toString(),
|
|
75
|
+
ip6: bootEnr.getLocationMultiaddr("udp6")?.toString(),
|
|
76
|
+
peerId: bootEnr.peerId.toString(),
|
|
77
|
+
nodeId: enr.nodeId,
|
|
78
|
+
});
|
|
79
|
+
discv5.addEnr(bootEnr);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// start the server
|
|
83
|
+
await discv5.start();
|
|
84
|
+
|
|
85
|
+
// if there are peers in the local routing table, establish a session by running a query
|
|
86
|
+
if (discv5.kadValues().length) {
|
|
87
|
+
void discv5.findRandomNode();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
discv5.on("multiaddrUpdated", (addr: ENRData) => {
|
|
91
|
+
logger.info("Advertised socket address updated", {addr: addr.toString()});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// respond with metrics every 10 seconds
|
|
95
|
+
const printInterval = setInterval(() => {
|
|
96
|
+
let ip4Only = 0;
|
|
97
|
+
let ip6Only = 0;
|
|
98
|
+
let ip4ip6 = 0;
|
|
99
|
+
let unreachable = 0;
|
|
100
|
+
for (const kadEnr of discv5.kadValues()) {
|
|
101
|
+
const hasIp4 = kadEnr.getLocationMultiaddr("udp4");
|
|
102
|
+
const hasIp6 = kadEnr.getLocationMultiaddr("udp6");
|
|
103
|
+
if (hasIp4 && hasIp6) {
|
|
104
|
+
ip4ip6++;
|
|
105
|
+
} else if (hasIp4) {
|
|
106
|
+
ip4Only++;
|
|
107
|
+
} else if (hasIp6) {
|
|
108
|
+
ip6Only++;
|
|
109
|
+
} else {
|
|
110
|
+
unreachable++;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
logger.info("Server metrics", {
|
|
114
|
+
connectedPeers: discv5.connectedPeerCount,
|
|
115
|
+
activeSessions: discv5.sessionService.sessionsSize(),
|
|
116
|
+
ip4Nodes: ip4Only,
|
|
117
|
+
ip6Nodes: ip6Only,
|
|
118
|
+
ip4AndIp6Nodes: ip4ip6,
|
|
119
|
+
unreachableNodes: unreachable,
|
|
120
|
+
});
|
|
121
|
+
}, 10_000);
|
|
122
|
+
|
|
123
|
+
// Intercept SIGINT signal, to perform final ops before exiting
|
|
124
|
+
onGracefulShutdown(async () => {
|
|
125
|
+
if (args.persistNetworkIdentity) {
|
|
126
|
+
try {
|
|
127
|
+
const enrPath = path.join(bootnodeDir, "enr");
|
|
128
|
+
writeFile600Perm(enrPath, enr.encodeTxt());
|
|
129
|
+
} catch (e) {
|
|
130
|
+
logger.warn("Unable to persist enr", {}, e as Error);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
abortController.abort();
|
|
134
|
+
}, logger.info.bind(logger));
|
|
135
|
+
|
|
136
|
+
abortController.signal.addEventListener(
|
|
137
|
+
"abort",
|
|
138
|
+
async () => {
|
|
139
|
+
try {
|
|
140
|
+
discv5.removeAllListeners();
|
|
141
|
+
clearInterval(printInterval);
|
|
142
|
+
|
|
143
|
+
await metricsServer?.close();
|
|
144
|
+
await discv5.stop();
|
|
145
|
+
logger.debug("Bootnode closed");
|
|
146
|
+
} catch (e) {
|
|
147
|
+
logger.error("Error closing bootnode", {}, e as Error);
|
|
148
|
+
// Must explicitly exit process due to potential active handles
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
{once: true}
|
|
153
|
+
);
|
|
154
|
+
} catch (e) {
|
|
155
|
+
if (e instanceof ErrorAborted) {
|
|
156
|
+
logger.info(e.message); // Let the user know the abort was received but don't print as error
|
|
157
|
+
} else {
|
|
158
|
+
throw e;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export type BootNodeInitOptions = {
|
|
164
|
+
discv5Args: Exclude<IBeaconNodeOptions["network"]["discv5"], null>;
|
|
165
|
+
metricsArgs: IBeaconNodeOptions["metrics"];
|
|
166
|
+
bootnodeDir: string;
|
|
167
|
+
network: string;
|
|
168
|
+
version: string;
|
|
169
|
+
commit: string;
|
|
170
|
+
privateKey: PrivateKey;
|
|
171
|
+
enr: SignableENR;
|
|
172
|
+
logger: Logger;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
/** Separate function to simplify unit testing of options merging */
|
|
176
|
+
export async function bootnodeHandlerInit(args: BootnodeArgs & GlobalArgs): Promise<BootNodeInitOptions> {
|
|
177
|
+
const {config, network} = getBeaconConfigFromArgs(args);
|
|
178
|
+
const {version, commit} = getVersionData();
|
|
179
|
+
const beaconPaths = getBeaconPaths(args, network);
|
|
180
|
+
// Use a separate directory to store bootnode enr + peer-id
|
|
181
|
+
const bootnodeDir = path.join(beaconPaths.dataDir, "bootnode");
|
|
182
|
+
const {discv5: discv5Args} = parseNetworkArgs(args);
|
|
183
|
+
const metricsArgs = parseMetricsArgs(args);
|
|
184
|
+
if (!discv5Args) {
|
|
185
|
+
// Unreachable because bootnode requires discv5 to be enabled - duh
|
|
186
|
+
throw new Error("unreachable - bootnode requires discv5 to be enabled");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// initialize directories
|
|
190
|
+
mkdir(beaconPaths.dataDir);
|
|
191
|
+
mkdir(bootnodeDir);
|
|
192
|
+
|
|
193
|
+
// Fetch extra bootnodes
|
|
194
|
+
discv5Args.bootEnrs = (discv5Args.bootEnrs ?? []).concat(
|
|
195
|
+
args.bootnodesFile ? readBootnodes(args.bootnodesFile) : [],
|
|
196
|
+
isKnownNetworkName(network) ? await getNetworkBootnodes(network) : []
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const logger = initLogger(args, beaconPaths.dataDir, config, "bootnode.log");
|
|
200
|
+
const {privateKey, enr} = await initPrivateKeyAndEnr(args as unknown as BeaconArgs, bootnodeDir, logger, true);
|
|
201
|
+
|
|
202
|
+
return {discv5Args, metricsArgs, bootnodeDir, network, version, commit, privateKey, enr, logger};
|
|
203
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {CliCommand, CliCommandOptions} from "@lodestar/utils";
|
|
2
|
+
import {GlobalArgs} from "../../options/index.js";
|
|
3
|
+
import {bootnodeHandler} from "./handler.js";
|
|
4
|
+
import {BootnodeArgs, bootnodeOptions} from "./options.js";
|
|
5
|
+
|
|
6
|
+
export const bootnode: CliCommand<BootnodeArgs, GlobalArgs> = {
|
|
7
|
+
command: "bootnode",
|
|
8
|
+
describe:
|
|
9
|
+
"Run a discv5 bootnode. This will NOT perform any beacon node functions, rather, it will run a discv5 service that allows nodes on the network to discover one another.",
|
|
10
|
+
docsFolder: "run/bootnode",
|
|
11
|
+
options: bootnodeOptions as CliCommandOptions<BootnodeArgs>,
|
|
12
|
+
handler: bootnodeHandler,
|
|
13
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {CliCommandOptions, CliOptionDefinition} from "@lodestar/utils";
|
|
2
|
+
import {MetricsArgs, options as metricsOptions} from "../../options/beaconNodeOptions/metrics.js";
|
|
3
|
+
import {defaultListenAddress, defaultListenAddress6, defaultP2pPort} from "../../options/beaconNodeOptions/network.js";
|
|
4
|
+
import {LogArgs, logOptions} from "../../options/logOptions.js";
|
|
5
|
+
|
|
6
|
+
type BootnodeExtraArgs = {
|
|
7
|
+
listenAddress?: string;
|
|
8
|
+
port?: number;
|
|
9
|
+
listenAddress6?: string;
|
|
10
|
+
port6?: number;
|
|
11
|
+
bootnodes?: string[];
|
|
12
|
+
bootnodesFile?: string;
|
|
13
|
+
persistNetworkIdentity?: boolean;
|
|
14
|
+
"enr.ip"?: string;
|
|
15
|
+
"enr.ip6"?: string;
|
|
16
|
+
"enr.udp"?: number;
|
|
17
|
+
"enr.udp6"?: number;
|
|
18
|
+
nat?: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const bootnodeExtraOptions: CliCommandOptions<BootnodeExtraArgs> = {
|
|
22
|
+
listenAddress: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "The IPv4 address to listen for discv5 connections",
|
|
25
|
+
defaultDescription: defaultListenAddress,
|
|
26
|
+
group: "network",
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
port: {
|
|
30
|
+
alias: "discoveryPort",
|
|
31
|
+
description: "The UDP port to listen on",
|
|
32
|
+
type: "number",
|
|
33
|
+
defaultDescription: String(defaultP2pPort),
|
|
34
|
+
group: "network",
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
listenAddress6: {
|
|
38
|
+
type: "string",
|
|
39
|
+
description: "The IPv6 address to listen for discv5 connections",
|
|
40
|
+
defaultDescription: defaultListenAddress6,
|
|
41
|
+
group: "network",
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
port6: {
|
|
45
|
+
alias: "discoveryPort6",
|
|
46
|
+
description: "The UDP port to listen on",
|
|
47
|
+
type: "number",
|
|
48
|
+
defaultDescription: String(defaultP2pPort),
|
|
49
|
+
group: "network",
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
bootnodes: {
|
|
53
|
+
type: "array",
|
|
54
|
+
description: "Additional bootnodes for discv5 discovery",
|
|
55
|
+
defaultDescription: JSON.stringify([]),
|
|
56
|
+
// Each bootnode entry could be comma separated, just deserialize it into a single array
|
|
57
|
+
// as comma separated entries are generally most friendly in ansible kind of setups, i.e.
|
|
58
|
+
// [ "en1", "en2,en3" ] => [ 'en1', 'en2', 'en3' ]
|
|
59
|
+
coerce: (args: string[]) => args.flatMap((item) => item.split(",")),
|
|
60
|
+
group: "network",
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
bootnodesFile: {
|
|
64
|
+
description: "Additional bootnodes for discv5 discovery file path",
|
|
65
|
+
type: "string",
|
|
66
|
+
group: "network",
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
persistNetworkIdentity: {
|
|
70
|
+
description: "Whether to reuse the same peer-id across restarts",
|
|
71
|
+
default: true,
|
|
72
|
+
type: "boolean",
|
|
73
|
+
group: "network",
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
"enr.ip": {
|
|
77
|
+
description: "Override ENR IP entry",
|
|
78
|
+
type: "string",
|
|
79
|
+
group: "enr",
|
|
80
|
+
},
|
|
81
|
+
"enr.udp": {
|
|
82
|
+
description: "Override ENR UDP entry",
|
|
83
|
+
type: "number",
|
|
84
|
+
group: "enr",
|
|
85
|
+
},
|
|
86
|
+
"enr.ip6": {
|
|
87
|
+
description: "Override ENR IPv6 entry",
|
|
88
|
+
type: "string",
|
|
89
|
+
group: "enr",
|
|
90
|
+
},
|
|
91
|
+
"enr.udp6": {
|
|
92
|
+
description: "Override ENR (IPv6-specific) UDP entry",
|
|
93
|
+
type: "number",
|
|
94
|
+
group: "enr",
|
|
95
|
+
},
|
|
96
|
+
nat: {
|
|
97
|
+
type: "boolean",
|
|
98
|
+
description: "Allow ENR configuration of non-local addresses",
|
|
99
|
+
group: "enr",
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export type BootnodeArgs = BootnodeExtraArgs & LogArgs & MetricsArgs;
|
|
104
|
+
|
|
105
|
+
export const bootnodeOptions: {[k: string]: CliOptionDefinition} = {
|
|
106
|
+
...bootnodeExtraOptions,
|
|
107
|
+
...logOptions,
|
|
108
|
+
...metricsOptions,
|
|
109
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import {Keystore} from "@chainsafe/bls-keystore";
|
|
4
|
+
import {nodeUtils} from "@lodestar/beacon-node";
|
|
5
|
+
import {ChainForkConfig, chainConfigToJson} from "@lodestar/config";
|
|
6
|
+
import {interopSecretKey} from "@lodestar/state-transition";
|
|
7
|
+
import {dumpYaml} from "@lodestar/utils";
|
|
8
|
+
import {PersistedKeysBackend} from "../validator/keymanager/persistedKeys.js";
|
|
9
|
+
|
|
10
|
+
export async function writeTestnetFiles(
|
|
11
|
+
config: ChainForkConfig,
|
|
12
|
+
targetDir: string,
|
|
13
|
+
genesisValidators: number
|
|
14
|
+
): Promise<void> {
|
|
15
|
+
const genesisTime = Math.floor(Date.now() / 1000);
|
|
16
|
+
const eth1BlockHash = Buffer.alloc(32, 0);
|
|
17
|
+
|
|
18
|
+
const {state} = nodeUtils.initDevState(config, genesisValidators, {genesisTime, eth1BlockHash});
|
|
19
|
+
|
|
20
|
+
// Write testnet data
|
|
21
|
+
fs.mkdirSync(targetDir, {recursive: true});
|
|
22
|
+
fs.writeFileSync(path.join(targetDir, "genesis.ssz"), state.serialize());
|
|
23
|
+
fs.writeFileSync(path.join(targetDir, "config.yaml"), dumpYaml(chainConfigToJson(config)));
|
|
24
|
+
fs.writeFileSync(path.join(targetDir, "deploy_block.txt"), "0");
|
|
25
|
+
|
|
26
|
+
const persistedKeystoresBackend = new PersistedKeysBackend({
|
|
27
|
+
keystoresDir: path.join(targetDir, "keystores"),
|
|
28
|
+
secretsDir: path.join(targetDir, "secrets"),
|
|
29
|
+
remoteKeysDir: path.join(targetDir, "remote_keys"),
|
|
30
|
+
proposerDir: path.join(targetDir, "proposer"),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const password = "test_password";
|
|
34
|
+
|
|
35
|
+
// Write keystores
|
|
36
|
+
for (let i = 0; i < genesisValidators; i++) {
|
|
37
|
+
console.log(`Generating keystore ${i}`);
|
|
38
|
+
|
|
39
|
+
const sk = interopSecretKey(i);
|
|
40
|
+
|
|
41
|
+
const keystore = await Keystore.create(password, sk.toBytes(), sk.toPublicKey().toBytes(), "");
|
|
42
|
+
|
|
43
|
+
persistedKeystoresBackend.writeKeystore({
|
|
44
|
+
keystoreStr: keystore.stringify(),
|
|
45
|
+
password,
|
|
46
|
+
// Not used immediately
|
|
47
|
+
lockBeforeWrite: false,
|
|
48
|
+
// Return duplicate status if already found
|
|
49
|
+
persistIfDuplicate: false,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import {rimraf} from "rimraf";
|
|
3
|
+
import {nodeUtils} from "@lodestar/beacon-node";
|
|
4
|
+
import {fromHex, toHex} from "@lodestar/utils";
|
|
5
|
+
import {getBeaconConfigFromArgs} from "../../config/beaconParams.js";
|
|
6
|
+
import {GlobalArgs} from "../../options/index.js";
|
|
7
|
+
import {mkdir, onGracefulShutdown} from "../../util/index.js";
|
|
8
|
+
import {beaconHandler} from "../beacon/handler.js";
|
|
9
|
+
import {getBeaconPaths} from "../beacon/paths.js";
|
|
10
|
+
import {validatorHandler} from "../validator/handler.js";
|
|
11
|
+
import {getValidatorPaths} from "../validator/paths.js";
|
|
12
|
+
import {writeTestnetFiles} from "./files.js";
|
|
13
|
+
import {IDevArgs} from "./options.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Run a beacon node with validator
|
|
17
|
+
*/
|
|
18
|
+
export async function devHandler(args: IDevArgs & GlobalArgs): Promise<void> {
|
|
19
|
+
const {config} = getBeaconConfigFromArgs(args);
|
|
20
|
+
|
|
21
|
+
if (args.dumpTestnetFiles) {
|
|
22
|
+
await writeTestnetFiles(config, args.dumpTestnetFiles, args.genesisValidators);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// TODO: Is this necessary?
|
|
27
|
+
const network = "dev";
|
|
28
|
+
if (args.network && args.network !== network) {
|
|
29
|
+
throw Error(`Must not run dev command with network '${args.network}', only 'dev' network`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Note: defaults to network "dev", to all paths are custom and don't conflict with networks.
|
|
33
|
+
// Flag --reset cleans up the custom dirs on dev stop
|
|
34
|
+
const beaconDbDir = getBeaconPaths(args, network).dbDir;
|
|
35
|
+
const validatorsDbDir = getValidatorPaths(args, network).validatorsDbDir;
|
|
36
|
+
|
|
37
|
+
// Remove slashing protection db. Otherwise the validators won't be able to propose nor attest
|
|
38
|
+
// until the clock reach a higher slot than the previous run of the dev command
|
|
39
|
+
if (args.genesisTime === undefined) {
|
|
40
|
+
await rimraf(beaconDbDir);
|
|
41
|
+
await rimraf(validatorsDbDir);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
mkdir(beaconDbDir);
|
|
45
|
+
mkdir(validatorsDbDir);
|
|
46
|
+
|
|
47
|
+
if (args.reset) {
|
|
48
|
+
onGracefulShutdown(async () => {
|
|
49
|
+
await rimraf(beaconDbDir);
|
|
50
|
+
await rimraf(validatorsDbDir);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// To be able to recycle beacon handler pass the genesis state via file
|
|
55
|
+
if (args.genesisStateFile) {
|
|
56
|
+
// Already set, skip
|
|
57
|
+
} else {
|
|
58
|
+
// Generate and write state to disk
|
|
59
|
+
const validatorCount = args.genesisValidators ?? 8;
|
|
60
|
+
const genesisTime = args.genesisTime ?? Math.floor(Date.now() / 1000) + 5;
|
|
61
|
+
const eth1BlockHash = fromHex(args.genesisEth1Hash ?? toHex(Buffer.alloc(32, 0x0b)));
|
|
62
|
+
|
|
63
|
+
const {state} = nodeUtils.initDevState(config, validatorCount, {genesisTime, eth1BlockHash});
|
|
64
|
+
|
|
65
|
+
args.genesisStateFile = "genesis.ssz";
|
|
66
|
+
fs.writeFileSync(args.genesisStateFile, state.serialize());
|
|
67
|
+
|
|
68
|
+
// Set logger format to Eph with provided genesisTime
|
|
69
|
+
if (args.logFormatGenesisTime === undefined) args.logFormatGenesisTime = genesisTime;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Note: recycle entire beacon handler
|
|
73
|
+
await beaconHandler(args);
|
|
74
|
+
|
|
75
|
+
if (args.startValidators) {
|
|
76
|
+
// TODO: Map dev option to validator's option
|
|
77
|
+
args.interopIndexes = args.startValidators;
|
|
78
|
+
|
|
79
|
+
// Note: recycle entire validator handler:
|
|
80
|
+
// - keystore handling
|
|
81
|
+
// - metrics
|
|
82
|
+
// - monitoring
|
|
83
|
+
// - keymanager server
|
|
84
|
+
await validatorHandler(args);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {CliCommand, CliCommandOptions} from "@lodestar/utils";
|
|
2
|
+
import {GlobalArgs} from "../../options/index.js";
|
|
3
|
+
import {devHandler} from "./handler.js";
|
|
4
|
+
import {IDevArgs, devOptions} from "./options.js";
|
|
5
|
+
|
|
6
|
+
export const dev: CliCommand<IDevArgs, GlobalArgs> = {
|
|
7
|
+
command: "dev",
|
|
8
|
+
describe: "Quickly bootstrap a beacon node and multiple validators. Use for development and testing",
|
|
9
|
+
docsFolder: "contribution",
|
|
10
|
+
examples: [
|
|
11
|
+
{
|
|
12
|
+
command: "dev --genesisValidators 8 --reset",
|
|
13
|
+
description: "Start a single beacon node with 8 interop validators",
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
options: devOptions as CliCommandOptions<IDevArgs>,
|
|
17
|
+
handler: devHandler,
|
|
18
|
+
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import {CliCommandOptions, CliOptionDefinition} from "@lodestar/utils";
|
|
2
|
+
import {NetworkName} from "../../networks/index.js";
|
|
3
|
+
import {beaconNodeOptions, globalOptions} from "../../options/index.js";
|
|
4
|
+
import {BeaconArgs, beaconOptions} from "../beacon/options.js";
|
|
5
|
+
import {IValidatorCliArgs, validatorOptions} from "../validator/options.js";
|
|
6
|
+
|
|
7
|
+
type IDevOwnArgs = {
|
|
8
|
+
genesisEth1Hash?: string;
|
|
9
|
+
genesisValidators: number;
|
|
10
|
+
startValidators?: string;
|
|
11
|
+
genesisTime?: number;
|
|
12
|
+
reset?: boolean;
|
|
13
|
+
dumpTestnetFiles?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const devOwnOptions: CliCommandOptions<IDevOwnArgs> = {
|
|
17
|
+
genesisEth1Hash: {
|
|
18
|
+
description: "If present it will create genesis with this eth1 hash.",
|
|
19
|
+
type: "string",
|
|
20
|
+
group: "dev",
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
genesisValidators: {
|
|
24
|
+
alias: ["c"],
|
|
25
|
+
description: "If present it will create genesis with interop validators and start chain.",
|
|
26
|
+
default: 8,
|
|
27
|
+
type: "number",
|
|
28
|
+
group: "dev",
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
startValidators: {
|
|
32
|
+
description: "Start interop validators in inclusive range with notation '0..7'",
|
|
33
|
+
type: "string",
|
|
34
|
+
group: "dev",
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
genesisTime: {
|
|
38
|
+
description: "genesis_time to initialize interop genesis state",
|
|
39
|
+
defaultDescription: "now",
|
|
40
|
+
type: "number",
|
|
41
|
+
group: "dev",
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
reset: {
|
|
45
|
+
description: "To delete chain and validator directories",
|
|
46
|
+
alias: ["r"],
|
|
47
|
+
type: "boolean",
|
|
48
|
+
group: "dev",
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
dumpTestnetFiles: {
|
|
52
|
+
description: "Dump testnet files and exit",
|
|
53
|
+
type: "string",
|
|
54
|
+
group: "dev",
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Add custom defaults different than the ones in `beaconOptions`:
|
|
60
|
+
* - In dev command we don't wanna connect to other peers,
|
|
61
|
+
* - but we do wanna get out of syncing (min peers)
|
|
62
|
+
* - and have api enabled by default (as it's used by validator)
|
|
63
|
+
* Note: use beaconNodeOptions and globalOptions to make sure option key is correct
|
|
64
|
+
*/
|
|
65
|
+
const externalOptionsOverrides: Partial<Record<"network" | keyof typeof beaconNodeOptions, CliOptionDefinition>> = {
|
|
66
|
+
// Custom paths different than regular beacon, validator paths
|
|
67
|
+
// network="dev" will store all data in separate dir than other networks
|
|
68
|
+
network: {
|
|
69
|
+
...globalOptions.network,
|
|
70
|
+
default: "dev" as NetworkName,
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
"sync.isSingleNode": {
|
|
74
|
+
...beaconNodeOptions["sync.isSingleNode"],
|
|
75
|
+
defaultDescription: undefined,
|
|
76
|
+
default: true,
|
|
77
|
+
},
|
|
78
|
+
"network.allowPublishToZeroPeers": {
|
|
79
|
+
...beaconNodeOptions["network.allowPublishToZeroPeers"],
|
|
80
|
+
defaultDescription: undefined,
|
|
81
|
+
default: true,
|
|
82
|
+
},
|
|
83
|
+
eth1: {
|
|
84
|
+
...beaconNodeOptions.eth1,
|
|
85
|
+
defaultDescription: undefined,
|
|
86
|
+
default: false,
|
|
87
|
+
},
|
|
88
|
+
rest: {
|
|
89
|
+
...beaconNodeOptions.rest,
|
|
90
|
+
defaultDescription: undefined,
|
|
91
|
+
default: true,
|
|
92
|
+
},
|
|
93
|
+
"rest.stacktraces": {
|
|
94
|
+
...beaconNodeOptions["rest.stacktraces"],
|
|
95
|
+
default: true,
|
|
96
|
+
},
|
|
97
|
+
"rest.swaggerUI": {
|
|
98
|
+
...beaconNodeOptions["rest.swaggerUI"],
|
|
99
|
+
default: true,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const devOptions = {
|
|
104
|
+
...beaconOptions,
|
|
105
|
+
...validatorOptions,
|
|
106
|
+
...externalOptionsOverrides,
|
|
107
|
+
...devOwnOptions,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export type IDevArgs = BeaconArgs & IValidatorCliArgs & IDevOwnArgs;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {CliCommand} from "@lodestar/utils";
|
|
2
|
+
import {GlobalArgs} from "../options/index.js";
|
|
3
|
+
import {beacon} from "./beacon/index.js";
|
|
4
|
+
import {bootnode} from "./bootnode/index.js";
|
|
5
|
+
import {dev} from "./dev/index.js";
|
|
6
|
+
import {lightclient} from "./lightclient/index.js";
|
|
7
|
+
import {validator} from "./validator/index.js";
|
|
8
|
+
|
|
9
|
+
export const cmds: Required<CliCommand<GlobalArgs, Record<never, never>>>["subcommands"] = [
|
|
10
|
+
beacon,
|
|
11
|
+
validator,
|
|
12
|
+
lightclient,
|
|
13
|
+
dev,
|
|
14
|
+
bootnode,
|
|
15
|
+
];
|