@chainsafe/lodestar 1.35.0-dev.8644a83c62 → 1.35.0-dev.8961b06c11

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.
Files changed (271) hide show
  1. package/.git-data.json +1 -1
  2. package/bin/lodestar.js +3 -0
  3. package/bin/lodestar.ts +3 -0
  4. package/lib/applyPreset.d.ts.map +1 -0
  5. package/lib/applyPreset.js +1 -1
  6. package/lib/applyPreset.js.map +1 -1
  7. package/lib/cli.d.ts +3 -3
  8. package/lib/cli.d.ts.map +1 -0
  9. package/lib/cli.js +1 -1
  10. package/lib/cli.js.map +1 -1
  11. package/lib/cmds/beacon/handler.d.ts +1 -1
  12. package/lib/cmds/beacon/handler.d.ts.map +1 -0
  13. package/lib/cmds/beacon/handler.js +1 -1
  14. package/lib/cmds/beacon/handler.js.map +1 -1
  15. package/lib/cmds/beacon/index.d.ts.map +1 -0
  16. package/lib/cmds/beacon/initBeaconState.d.ts.map +1 -0
  17. package/lib/cmds/beacon/initBeaconState.js.map +1 -1
  18. package/lib/cmds/beacon/initPeerIdAndEnr.d.ts +2 -2
  19. package/lib/cmds/beacon/initPeerIdAndEnr.d.ts.map +1 -0
  20. package/lib/cmds/beacon/initPeerIdAndEnr.js +1 -1
  21. package/lib/cmds/beacon/initPeerIdAndEnr.js.map +1 -1
  22. package/lib/cmds/beacon/options.d.ts.map +1 -0
  23. package/lib/cmds/beacon/paths.d.ts.map +1 -0
  24. package/lib/cmds/bootnode/handler.d.ts +13 -8
  25. package/lib/cmds/bootnode/handler.d.ts.map +1 -0
  26. package/lib/cmds/bootnode/handler.js +2 -2
  27. package/lib/cmds/bootnode/handler.js.map +1 -1
  28. package/lib/cmds/bootnode/index.d.ts.map +1 -0
  29. package/lib/cmds/bootnode/options.d.ts.map +1 -0
  30. package/lib/cmds/bootnode/options.js +2 -1
  31. package/lib/cmds/bootnode/options.js.map +1 -1
  32. package/lib/cmds/dev/files.d.ts.map +1 -0
  33. package/lib/cmds/dev/handler.d.ts.map +1 -0
  34. package/lib/cmds/dev/handler.js +1 -1
  35. package/lib/cmds/dev/handler.js.map +1 -1
  36. package/lib/cmds/dev/index.d.ts.map +1 -0
  37. package/lib/cmds/dev/options.d.ts.map +1 -0
  38. package/lib/cmds/index.d.ts.map +1 -0
  39. package/lib/cmds/lightclient/handler.d.ts.map +1 -0
  40. package/lib/cmds/lightclient/index.d.ts.map +1 -0
  41. package/lib/cmds/lightclient/options.d.ts.map +1 -0
  42. package/lib/cmds/validator/blsToExecutionChange.d.ts.map +1 -0
  43. package/lib/cmds/validator/blsToExecutionChange.js.map +1 -1
  44. package/lib/cmds/validator/handler.d.ts.map +1 -0
  45. package/lib/cmds/validator/handler.js +3 -5
  46. package/lib/cmds/validator/handler.js.map +1 -1
  47. package/lib/cmds/validator/import.d.ts.map +1 -0
  48. package/lib/cmds/validator/index.d.ts.map +1 -0
  49. package/lib/cmds/validator/keymanager/decryptKeystoreDefinitions.d.ts.map +1 -0
  50. package/lib/cmds/validator/keymanager/decryptKeystores/index.d.ts.map +1 -0
  51. package/lib/cmds/validator/keymanager/decryptKeystores/poolSize.d.ts.map +1 -0
  52. package/lib/cmds/validator/keymanager/decryptKeystores/threadPool.d.ts.map +1 -0
  53. package/lib/cmds/validator/keymanager/decryptKeystores/threadPool.js +4 -1
  54. package/lib/cmds/validator/keymanager/decryptKeystores/threadPool.js.map +1 -1
  55. package/lib/cmds/validator/keymanager/decryptKeystores/types.d.ts.map +1 -0
  56. package/lib/cmds/validator/keymanager/decryptKeystores/worker.d.ts.map +1 -0
  57. package/lib/cmds/validator/keymanager/impl.d.ts.map +1 -0
  58. package/lib/cmds/validator/keymanager/impl.js +4 -0
  59. package/lib/cmds/validator/keymanager/impl.js.map +1 -1
  60. package/lib/cmds/validator/keymanager/interface.d.ts.map +1 -0
  61. package/lib/cmds/validator/keymanager/keystoreCache.d.ts.map +1 -0
  62. package/lib/cmds/validator/keymanager/persistedKeys.d.ts.map +1 -0
  63. package/lib/cmds/validator/keymanager/persistedKeys.js +1 -0
  64. package/lib/cmds/validator/keymanager/persistedKeys.js.map +1 -1
  65. package/lib/cmds/validator/keymanager/server.d.ts.map +1 -0
  66. package/lib/cmds/validator/keymanager/server.js +2 -0
  67. package/lib/cmds/validator/keymanager/server.js.map +1 -1
  68. package/lib/cmds/validator/list.d.ts.map +1 -0
  69. package/lib/cmds/validator/options.d.ts.map +1 -0
  70. package/lib/cmds/validator/options.js +2 -2
  71. package/lib/cmds/validator/paths.d.ts.map +1 -0
  72. package/lib/cmds/validator/signers/importExternalKeystores.d.ts.map +1 -0
  73. package/lib/cmds/validator/signers/index.d.ts.map +1 -0
  74. package/lib/cmds/validator/signers/logSigners.d.ts.map +1 -0
  75. package/lib/cmds/validator/slashingProtection/export.d.ts.map +1 -0
  76. package/lib/cmds/validator/slashingProtection/import.d.ts.map +1 -0
  77. package/lib/cmds/validator/slashingProtection/index.d.ts.map +1 -0
  78. package/lib/cmds/validator/slashingProtection/options.d.ts.map +1 -0
  79. package/lib/cmds/validator/slashingProtection/utils.d.ts.map +1 -0
  80. package/lib/cmds/validator/slashingProtection/utils.js +1 -1
  81. package/lib/cmds/validator/slashingProtection/utils.js.map +1 -1
  82. package/lib/cmds/validator/voluntaryExit.d.ts.map +1 -0
  83. package/lib/cmds/validator/voluntaryExit.js +1 -1
  84. package/lib/cmds/validator/voluntaryExit.js.map +1 -1
  85. package/lib/config/beaconNodeOptions.d.ts.map +1 -0
  86. package/lib/config/beaconNodeOptions.js +2 -1
  87. package/lib/config/beaconNodeOptions.js.map +1 -1
  88. package/lib/config/beaconParams.d.ts.map +1 -0
  89. package/lib/config/index.d.ts.map +1 -0
  90. package/lib/config/peerId.d.ts.map +1 -0
  91. package/lib/config/types.d.ts.map +1 -0
  92. package/lib/index.d.ts.map +1 -0
  93. package/lib/index.js.map +1 -1
  94. package/lib/migrations/index.d.ts +1 -0
  95. package/lib/migrations/index.d.ts.map +1 -0
  96. package/lib/migrations/index.js +1 -1
  97. package/lib/networks/chiado.d.ts.map +1 -0
  98. package/lib/networks/dev.d.ts.map +1 -0
  99. package/lib/networks/ephemery.d.ts.map +1 -0
  100. package/lib/networks/gnosis.d.ts.map +1 -0
  101. package/lib/networks/holesky.d.ts.map +1 -0
  102. package/lib/networks/hoodi.d.ts.map +1 -0
  103. package/lib/networks/index.d.ts.map +1 -0
  104. package/lib/networks/index.js +1 -2
  105. package/lib/networks/index.js.map +1 -1
  106. package/lib/networks/mainnet.d.ts.map +1 -0
  107. package/lib/networks/sepolia.d.ts.map +1 -0
  108. package/lib/options/beaconNodeOptions/api.d.ts.map +1 -0
  109. package/lib/options/beaconNodeOptions/builder.d.ts.map +1 -0
  110. package/lib/options/beaconNodeOptions/chain.d.ts.map +1 -0
  111. package/lib/options/beaconNodeOptions/eth1.d.ts.map +1 -0
  112. package/lib/options/beaconNodeOptions/execution.d.ts.map +1 -0
  113. package/lib/options/beaconNodeOptions/index.d.ts.map +1 -0
  114. package/lib/options/beaconNodeOptions/metrics.d.ts.map +1 -0
  115. package/lib/options/beaconNodeOptions/monitoring.d.ts.map +1 -0
  116. package/lib/options/beaconNodeOptions/network.d.ts +1 -0
  117. package/lib/options/beaconNodeOptions/network.d.ts.map +1 -0
  118. package/lib/options/beaconNodeOptions/network.js +6 -3
  119. package/lib/options/beaconNodeOptions/network.js.map +1 -1
  120. package/lib/options/beaconNodeOptions/sync.d.ts.map +1 -0
  121. package/lib/options/globalOptions.d.ts.map +1 -0
  122. package/lib/options/index.d.ts.map +1 -0
  123. package/lib/options/logOptions.d.ts.map +1 -0
  124. package/lib/options/paramsOptions.d.ts.map +1 -0
  125. package/lib/paths/global.d.ts.map +1 -0
  126. package/lib/paths/rootDir.d.ts.map +1 -0
  127. package/lib/util/errors.d.ts.map +1 -0
  128. package/lib/util/ethers.d.ts.map +1 -0
  129. package/lib/util/feeRecipient.d.ts.map +1 -0
  130. package/lib/util/file.d.ts.map +1 -0
  131. package/lib/util/file.js +1 -1
  132. package/lib/util/file.js.map +1 -1
  133. package/lib/util/format.d.ts.map +1 -0
  134. package/lib/util/fs.d.ts.map +1 -0
  135. package/lib/util/gitData/gitDataPath.d.ts.map +1 -0
  136. package/lib/util/gitData/index.d.ts.map +1 -0
  137. package/lib/util/gitData/index.js.map +1 -1
  138. package/lib/util/gitData/writeGitData.d.ts.map +1 -0
  139. package/lib/util/hasher_bun.d.ts +3 -0
  140. package/lib/util/hasher_bun.d.ts.map +1 -0
  141. package/lib/util/hasher_bun.js +118 -0
  142. package/lib/util/hasher_bun.js.map +1 -0
  143. package/lib/util/hasher_nodejs.d.ts +3 -0
  144. package/lib/util/hasher_nodejs.d.ts.map +1 -0
  145. package/lib/util/hasher_nodejs.js +3 -0
  146. package/lib/util/hasher_nodejs.js.map +1 -0
  147. package/lib/util/index.d.ts +3 -3
  148. package/lib/util/index.d.ts.map +1 -0
  149. package/lib/util/index.js +3 -3
  150. package/lib/util/index.js.map +1 -1
  151. package/lib/util/jwt.d.ts.map +1 -0
  152. package/lib/util/lockfile.d.ts.map +1 -0
  153. package/lib/util/logger.d.ts.map +1 -0
  154. package/lib/util/logger.js +1 -1
  155. package/lib/util/logger.js.map +1 -1
  156. package/lib/util/object.d.ts.map +1 -0
  157. package/lib/util/object.js.map +1 -1
  158. package/lib/util/passphrase.d.ts.map +1 -0
  159. package/lib/util/process.d.ts.map +1 -0
  160. package/lib/util/progress.d.ts.map +1 -0
  161. package/lib/util/proposerConfig.d.ts.map +1 -0
  162. package/lib/util/proposerConfig.js.map +1 -1
  163. package/lib/util/pruneOldFilesInDir.d.ts.map +1 -0
  164. package/lib/util/sleep.d.ts.map +1 -0
  165. package/lib/util/stripOffNewlines.d.ts.map +1 -0
  166. package/lib/util/types.d.ts.map +1 -0
  167. package/lib/util/version.d.ts.map +1 -0
  168. package/package.json +33 -20
  169. package/src/applyPreset.ts +92 -0
  170. package/src/cli.ts +56 -0
  171. package/src/cmds/beacon/handler.ts +267 -0
  172. package/src/cmds/beacon/index.ts +18 -0
  173. package/src/cmds/beacon/initBeaconState.ts +275 -0
  174. package/src/cmds/beacon/initPeerIdAndEnr.ts +199 -0
  175. package/src/cmds/beacon/options.ts +214 -0
  176. package/src/cmds/beacon/paths.ts +62 -0
  177. package/src/cmds/bootnode/handler.ts +203 -0
  178. package/src/cmds/bootnode/index.ts +13 -0
  179. package/src/cmds/bootnode/options.ts +109 -0
  180. package/src/cmds/dev/files.ts +52 -0
  181. package/src/cmds/dev/handler.ts +86 -0
  182. package/src/cmds/dev/index.ts +18 -0
  183. package/src/cmds/dev/options.ts +110 -0
  184. package/src/cmds/index.ts +15 -0
  185. package/src/cmds/lightclient/handler.ts +36 -0
  186. package/src/cmds/lightclient/index.ts +18 -0
  187. package/src/cmds/lightclient/options.ts +21 -0
  188. package/src/cmds/validator/blsToExecutionChange.ts +91 -0
  189. package/src/cmds/validator/handler.ts +300 -0
  190. package/src/cmds/validator/import.ts +111 -0
  191. package/src/cmds/validator/index.ts +28 -0
  192. package/src/cmds/validator/keymanager/decryptKeystoreDefinitions.ts +189 -0
  193. package/src/cmds/validator/keymanager/decryptKeystores/index.ts +1 -0
  194. package/src/cmds/validator/keymanager/decryptKeystores/poolSize.ts +16 -0
  195. package/src/cmds/validator/keymanager/decryptKeystores/threadPool.ts +75 -0
  196. package/src/cmds/validator/keymanager/decryptKeystores/types.ts +12 -0
  197. package/src/cmds/validator/keymanager/decryptKeystores/worker.ts +24 -0
  198. package/src/cmds/validator/keymanager/impl.ts +425 -0
  199. package/src/cmds/validator/keymanager/interface.ts +35 -0
  200. package/src/cmds/validator/keymanager/keystoreCache.ts +91 -0
  201. package/src/cmds/validator/keymanager/persistedKeys.ts +268 -0
  202. package/src/cmds/validator/keymanager/server.ts +86 -0
  203. package/src/cmds/validator/list.ts +35 -0
  204. package/src/cmds/validator/options.ts +461 -0
  205. package/src/cmds/validator/paths.ts +95 -0
  206. package/src/cmds/validator/signers/importExternalKeystores.ts +69 -0
  207. package/src/cmds/validator/signers/index.ts +176 -0
  208. package/src/cmds/validator/signers/logSigners.ts +81 -0
  209. package/src/cmds/validator/slashingProtection/export.ts +110 -0
  210. package/src/cmds/validator/slashingProtection/import.ts +70 -0
  211. package/src/cmds/validator/slashingProtection/index.ts +12 -0
  212. package/src/cmds/validator/slashingProtection/options.ts +15 -0
  213. package/src/cmds/validator/slashingProtection/utils.ts +56 -0
  214. package/src/cmds/validator/voluntaryExit.ts +232 -0
  215. package/src/config/beaconNodeOptions.ts +68 -0
  216. package/src/config/beaconParams.ts +87 -0
  217. package/src/config/index.ts +3 -0
  218. package/src/config/peerId.ts +50 -0
  219. package/src/config/types.ts +3 -0
  220. package/src/index.ts +28 -0
  221. package/src/migrations/index.ts +0 -0
  222. package/src/networks/chiado.ts +20 -0
  223. package/src/networks/dev.ts +27 -0
  224. package/src/networks/ephemery.ts +9 -0
  225. package/src/networks/gnosis.ts +18 -0
  226. package/src/networks/holesky.ts +17 -0
  227. package/src/networks/hoodi.ts +16 -0
  228. package/src/networks/index.ts +236 -0
  229. package/src/networks/mainnet.ts +34 -0
  230. package/src/networks/sepolia.ts +17 -0
  231. package/src/options/beaconNodeOptions/api.ts +110 -0
  232. package/src/options/beaconNodeOptions/builder.ts +63 -0
  233. package/src/options/beaconNodeOptions/chain.ts +326 -0
  234. package/src/options/beaconNodeOptions/eth1.ts +95 -0
  235. package/src/options/beaconNodeOptions/execution.ts +92 -0
  236. package/src/options/beaconNodeOptions/index.ts +50 -0
  237. package/src/options/beaconNodeOptions/metrics.ts +39 -0
  238. package/src/options/beaconNodeOptions/monitoring.ts +61 -0
  239. package/src/options/beaconNodeOptions/network.ts +401 -0
  240. package/src/options/beaconNodeOptions/sync.ts +65 -0
  241. package/src/options/globalOptions.ts +72 -0
  242. package/src/options/index.ts +3 -0
  243. package/src/options/logOptions.ts +70 -0
  244. package/src/options/paramsOptions.ts +72 -0
  245. package/src/paths/global.ts +24 -0
  246. package/src/paths/rootDir.ts +11 -0
  247. package/src/util/errors.ts +20 -0
  248. package/src/util/ethers.ts +44 -0
  249. package/src/util/feeRecipient.ts +6 -0
  250. package/src/util/file.ts +167 -0
  251. package/src/util/format.ts +76 -0
  252. package/src/util/fs.ts +59 -0
  253. package/src/util/gitData/gitDataPath.ts +48 -0
  254. package/src/util/gitData/index.ts +70 -0
  255. package/src/util/gitData/writeGitData.ts +10 -0
  256. package/src/util/hasher_bun.ts +133 -0
  257. package/src/util/hasher_nodejs.ts +3 -0
  258. package/src/util/index.ts +17 -0
  259. package/src/util/jwt.ts +10 -0
  260. package/src/util/lockfile.ts +45 -0
  261. package/src/util/logger.ts +105 -0
  262. package/src/util/object.ts +15 -0
  263. package/src/util/passphrase.ts +25 -0
  264. package/src/util/process.ts +25 -0
  265. package/src/util/progress.ts +58 -0
  266. package/src/util/proposerConfig.ts +136 -0
  267. package/src/util/pruneOldFilesInDir.ts +27 -0
  268. package/src/util/sleep.ts +3 -0
  269. package/src/util/stripOffNewlines.ts +6 -0
  270. package/src/util/types.ts +8 -0
  271. 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
+ ];