@chainsafe/lodestar 1.35.0-dev.b42a298a7c → 1.35.0-dev.be3c5220f4

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 (233) 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.map +1 -0
  8. package/lib/cmds/beacon/handler.d.ts +1 -1
  9. package/lib/cmds/beacon/handler.d.ts.map +1 -0
  10. package/lib/cmds/beacon/handler.js +1 -1
  11. package/lib/cmds/beacon/handler.js.map +1 -1
  12. package/lib/cmds/beacon/index.d.ts.map +1 -0
  13. package/lib/cmds/beacon/initBeaconState.d.ts.map +1 -0
  14. package/lib/cmds/beacon/initPeerIdAndEnr.d.ts.map +1 -0
  15. package/lib/cmds/beacon/options.d.ts.map +1 -0
  16. package/lib/cmds/beacon/paths.d.ts.map +1 -0
  17. package/lib/cmds/bootnode/handler.d.ts.map +1 -0
  18. package/lib/cmds/bootnode/index.d.ts.map +1 -0
  19. package/lib/cmds/bootnode/options.d.ts.map +1 -0
  20. package/lib/cmds/dev/files.d.ts.map +1 -0
  21. package/lib/cmds/dev/handler.d.ts.map +1 -0
  22. package/lib/cmds/dev/index.d.ts.map +1 -0
  23. package/lib/cmds/dev/options.d.ts.map +1 -0
  24. package/lib/cmds/index.d.ts.map +1 -0
  25. package/lib/cmds/lightclient/handler.d.ts.map +1 -0
  26. package/lib/cmds/lightclient/index.d.ts.map +1 -0
  27. package/lib/cmds/lightclient/options.d.ts.map +1 -0
  28. package/lib/cmds/validator/blsToExecutionChange.d.ts.map +1 -0
  29. package/lib/cmds/validator/handler.d.ts.map +1 -0
  30. package/lib/cmds/validator/handler.js +1 -1
  31. package/lib/cmds/validator/handler.js.map +1 -1
  32. package/lib/cmds/validator/import.d.ts.map +1 -0
  33. package/lib/cmds/validator/index.d.ts.map +1 -0
  34. package/lib/cmds/validator/keymanager/decryptKeystoreDefinitions.d.ts.map +1 -0
  35. package/lib/cmds/validator/keymanager/decryptKeystores/index.d.ts.map +1 -0
  36. package/lib/cmds/validator/keymanager/decryptKeystores/poolSize.d.ts.map +1 -0
  37. package/lib/cmds/validator/keymanager/decryptKeystores/threadPool.d.ts.map +1 -0
  38. package/lib/cmds/validator/keymanager/decryptKeystores/types.d.ts.map +1 -0
  39. package/lib/cmds/validator/keymanager/decryptKeystores/worker.d.ts.map +1 -0
  40. package/lib/cmds/validator/keymanager/impl.d.ts.map +1 -0
  41. package/lib/cmds/validator/keymanager/interface.d.ts.map +1 -0
  42. package/lib/cmds/validator/keymanager/keystoreCache.d.ts.map +1 -0
  43. package/lib/cmds/validator/keymanager/persistedKeys.d.ts.map +1 -0
  44. package/lib/cmds/validator/keymanager/server.d.ts.map +1 -0
  45. package/lib/cmds/validator/list.d.ts.map +1 -0
  46. package/lib/cmds/validator/options.d.ts.map +1 -0
  47. package/lib/cmds/validator/options.js +5 -3
  48. package/lib/cmds/validator/options.js.map +1 -1
  49. package/lib/cmds/validator/paths.d.ts.map +1 -0
  50. package/lib/cmds/validator/signers/importExternalKeystores.d.ts.map +1 -0
  51. package/lib/cmds/validator/signers/index.d.ts.map +1 -0
  52. package/lib/cmds/validator/signers/logSigners.d.ts.map +1 -0
  53. package/lib/cmds/validator/slashingProtection/export.d.ts.map +1 -0
  54. package/lib/cmds/validator/slashingProtection/import.d.ts.map +1 -0
  55. package/lib/cmds/validator/slashingProtection/index.d.ts.map +1 -0
  56. package/lib/cmds/validator/slashingProtection/options.d.ts.map +1 -0
  57. package/lib/cmds/validator/slashingProtection/utils.d.ts.map +1 -0
  58. package/lib/cmds/validator/slashingProtection/utils.js +1 -1
  59. package/lib/cmds/validator/slashingProtection/utils.js.map +1 -1
  60. package/lib/cmds/validator/voluntaryExit.d.ts.map +1 -0
  61. package/lib/config/beaconNodeOptions.d.ts.map +1 -0
  62. package/lib/config/beaconParams.d.ts.map +1 -0
  63. package/lib/config/index.d.ts.map +1 -0
  64. package/lib/config/peerId.d.ts.map +1 -0
  65. package/lib/config/types.d.ts.map +1 -0
  66. package/lib/index.d.ts.map +1 -0
  67. package/lib/migrations/index.d.ts.map +1 -0
  68. package/lib/networks/chiado.d.ts.map +1 -0
  69. package/lib/networks/dev.d.ts.map +1 -0
  70. package/lib/networks/ephemery.d.ts.map +1 -0
  71. package/lib/networks/gnosis.d.ts.map +1 -0
  72. package/lib/networks/holesky.d.ts.map +1 -0
  73. package/lib/networks/hoodi.d.ts.map +1 -0
  74. package/lib/networks/index.d.ts.map +1 -0
  75. package/lib/networks/mainnet.d.ts.map +1 -0
  76. package/lib/networks/sepolia.d.ts.map +1 -0
  77. package/lib/options/beaconNodeOptions/api.d.ts +6 -0
  78. package/lib/options/beaconNodeOptions/api.d.ts.map +1 -0
  79. package/lib/options/beaconNodeOptions/api.js +14 -6
  80. package/lib/options/beaconNodeOptions/api.js.map +1 -1
  81. package/lib/options/beaconNodeOptions/builder.d.ts.map +1 -0
  82. package/lib/options/beaconNodeOptions/chain.d.ts.map +1 -0
  83. package/lib/options/beaconNodeOptions/eth1.d.ts.map +1 -0
  84. package/lib/options/beaconNodeOptions/execution.d.ts.map +1 -0
  85. package/lib/options/beaconNodeOptions/index.d.ts.map +1 -0
  86. package/lib/options/beaconNodeOptions/metrics.d.ts.map +1 -0
  87. package/lib/options/beaconNodeOptions/monitoring.d.ts.map +1 -0
  88. package/lib/options/beaconNodeOptions/network.d.ts.map +1 -0
  89. package/lib/options/beaconNodeOptions/sync.d.ts.map +1 -0
  90. package/lib/options/globalOptions.d.ts.map +1 -0
  91. package/lib/options/index.d.ts.map +1 -0
  92. package/lib/options/logOptions.d.ts.map +1 -0
  93. package/lib/options/paramsOptions.d.ts.map +1 -0
  94. package/lib/paths/global.d.ts.map +1 -0
  95. package/lib/paths/rootDir.d.ts.map +1 -0
  96. package/lib/util/errors.d.ts.map +1 -0
  97. package/lib/util/ethers.d.ts.map +1 -0
  98. package/lib/util/feeRecipient.d.ts.map +1 -0
  99. package/lib/util/file.d.ts.map +1 -0
  100. package/lib/util/file.js.map +1 -1
  101. package/lib/util/format.d.ts.map +1 -0
  102. package/lib/util/fs.d.ts.map +1 -0
  103. package/lib/util/gitData/gitDataPath.d.ts.map +1 -0
  104. package/lib/util/gitData/index.d.ts.map +1 -0
  105. package/lib/util/gitData/writeGitData.d.ts.map +1 -0
  106. package/lib/util/hasher_bun.d.ts +3 -0
  107. package/lib/util/hasher_bun.d.ts.map +1 -0
  108. package/lib/util/hasher_bun.js +118 -0
  109. package/lib/util/hasher_bun.js.map +1 -0
  110. package/lib/util/hasher_nodejs.d.ts +3 -0
  111. package/lib/util/hasher_nodejs.d.ts.map +1 -0
  112. package/lib/util/hasher_nodejs.js +3 -0
  113. package/lib/util/hasher_nodejs.js.map +1 -0
  114. package/lib/util/index.d.ts.map +1 -0
  115. package/lib/util/jwt.d.ts.map +1 -0
  116. package/lib/util/lockfile.d.ts.map +1 -0
  117. package/lib/util/logger.d.ts.map +1 -0
  118. package/lib/util/logger.js +1 -1
  119. package/lib/util/logger.js.map +1 -1
  120. package/lib/util/object.d.ts.map +1 -0
  121. package/lib/util/passphrase.d.ts.map +1 -0
  122. package/lib/util/process.d.ts.map +1 -0
  123. package/lib/util/progress.d.ts.map +1 -0
  124. package/lib/util/proposerConfig.d.ts.map +1 -0
  125. package/lib/util/pruneOldFilesInDir.d.ts.map +1 -0
  126. package/lib/util/sleep.d.ts.map +1 -0
  127. package/lib/util/stripOffNewlines.d.ts.map +1 -0
  128. package/lib/util/types.d.ts.map +1 -0
  129. package/lib/util/version.d.ts.map +1 -0
  130. package/package.json +32 -19
  131. package/src/applyPreset.ts +92 -0
  132. package/src/cli.ts +56 -0
  133. package/src/cmds/beacon/handler.ts +267 -0
  134. package/src/cmds/beacon/index.ts +18 -0
  135. package/src/cmds/beacon/initBeaconState.ts +275 -0
  136. package/src/cmds/beacon/initPeerIdAndEnr.ts +199 -0
  137. package/src/cmds/beacon/options.ts +214 -0
  138. package/src/cmds/beacon/paths.ts +62 -0
  139. package/src/cmds/bootnode/handler.ts +203 -0
  140. package/src/cmds/bootnode/index.ts +13 -0
  141. package/src/cmds/bootnode/options.ts +109 -0
  142. package/src/cmds/dev/files.ts +52 -0
  143. package/src/cmds/dev/handler.ts +86 -0
  144. package/src/cmds/dev/index.ts +18 -0
  145. package/src/cmds/dev/options.ts +110 -0
  146. package/src/cmds/index.ts +15 -0
  147. package/src/cmds/lightclient/handler.ts +36 -0
  148. package/src/cmds/lightclient/index.ts +18 -0
  149. package/src/cmds/lightclient/options.ts +21 -0
  150. package/src/cmds/validator/blsToExecutionChange.ts +91 -0
  151. package/src/cmds/validator/handler.ts +300 -0
  152. package/src/cmds/validator/import.ts +111 -0
  153. package/src/cmds/validator/index.ts +28 -0
  154. package/src/cmds/validator/keymanager/decryptKeystoreDefinitions.ts +189 -0
  155. package/src/cmds/validator/keymanager/decryptKeystores/index.ts +1 -0
  156. package/src/cmds/validator/keymanager/decryptKeystores/poolSize.ts +16 -0
  157. package/src/cmds/validator/keymanager/decryptKeystores/threadPool.ts +75 -0
  158. package/src/cmds/validator/keymanager/decryptKeystores/types.ts +12 -0
  159. package/src/cmds/validator/keymanager/decryptKeystores/worker.ts +24 -0
  160. package/src/cmds/validator/keymanager/impl.ts +425 -0
  161. package/src/cmds/validator/keymanager/interface.ts +35 -0
  162. package/src/cmds/validator/keymanager/keystoreCache.ts +91 -0
  163. package/src/cmds/validator/keymanager/persistedKeys.ts +268 -0
  164. package/src/cmds/validator/keymanager/server.ts +86 -0
  165. package/src/cmds/validator/list.ts +35 -0
  166. package/src/cmds/validator/options.ts +463 -0
  167. package/src/cmds/validator/paths.ts +95 -0
  168. package/src/cmds/validator/signers/importExternalKeystores.ts +69 -0
  169. package/src/cmds/validator/signers/index.ts +176 -0
  170. package/src/cmds/validator/signers/logSigners.ts +81 -0
  171. package/src/cmds/validator/slashingProtection/export.ts +110 -0
  172. package/src/cmds/validator/slashingProtection/import.ts +70 -0
  173. package/src/cmds/validator/slashingProtection/index.ts +12 -0
  174. package/src/cmds/validator/slashingProtection/options.ts +15 -0
  175. package/src/cmds/validator/slashingProtection/utils.ts +56 -0
  176. package/src/cmds/validator/voluntaryExit.ts +232 -0
  177. package/src/config/beaconNodeOptions.ts +68 -0
  178. package/src/config/beaconParams.ts +87 -0
  179. package/src/config/index.ts +3 -0
  180. package/src/config/peerId.ts +50 -0
  181. package/src/config/types.ts +3 -0
  182. package/src/index.ts +28 -0
  183. package/src/migrations/index.ts +0 -0
  184. package/src/networks/chiado.ts +20 -0
  185. package/src/networks/dev.ts +27 -0
  186. package/src/networks/ephemery.ts +9 -0
  187. package/src/networks/gnosis.ts +18 -0
  188. package/src/networks/holesky.ts +17 -0
  189. package/src/networks/hoodi.ts +16 -0
  190. package/src/networks/index.ts +236 -0
  191. package/src/networks/mainnet.ts +34 -0
  192. package/src/networks/sepolia.ts +17 -0
  193. package/src/options/beaconNodeOptions/api.ts +120 -0
  194. package/src/options/beaconNodeOptions/builder.ts +63 -0
  195. package/src/options/beaconNodeOptions/chain.ts +326 -0
  196. package/src/options/beaconNodeOptions/eth1.ts +95 -0
  197. package/src/options/beaconNodeOptions/execution.ts +92 -0
  198. package/src/options/beaconNodeOptions/index.ts +50 -0
  199. package/src/options/beaconNodeOptions/metrics.ts +39 -0
  200. package/src/options/beaconNodeOptions/monitoring.ts +61 -0
  201. package/src/options/beaconNodeOptions/network.ts +401 -0
  202. package/src/options/beaconNodeOptions/sync.ts +65 -0
  203. package/src/options/globalOptions.ts +72 -0
  204. package/src/options/index.ts +3 -0
  205. package/src/options/logOptions.ts +70 -0
  206. package/src/options/paramsOptions.ts +72 -0
  207. package/src/paths/global.ts +24 -0
  208. package/src/paths/rootDir.ts +11 -0
  209. package/src/util/errors.ts +20 -0
  210. package/src/util/ethers.ts +44 -0
  211. package/src/util/feeRecipient.ts +6 -0
  212. package/src/util/file.ts +167 -0
  213. package/src/util/format.ts +76 -0
  214. package/src/util/fs.ts +59 -0
  215. package/src/util/gitData/gitDataPath.ts +48 -0
  216. package/src/util/gitData/index.ts +70 -0
  217. package/src/util/gitData/writeGitData.ts +10 -0
  218. package/src/util/hasher_bun.ts +133 -0
  219. package/src/util/hasher_nodejs.ts +3 -0
  220. package/src/util/index.ts +17 -0
  221. package/src/util/jwt.ts +10 -0
  222. package/src/util/lockfile.ts +45 -0
  223. package/src/util/logger.ts +105 -0
  224. package/src/util/object.ts +15 -0
  225. package/src/util/passphrase.ts +25 -0
  226. package/src/util/process.ts +25 -0
  227. package/src/util/progress.ts +58 -0
  228. package/src/util/proposerConfig.ts +136 -0
  229. package/src/util/pruneOldFilesInDir.ts +27 -0
  230. package/src/util/sleep.ts +3 -0
  231. package/src/util/stripOffNewlines.ts +6 -0
  232. package/src/util/types.ts +8 -0
  233. package/src/util/version.ts +74 -0
@@ -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
+ ];
@@ -0,0 +1,36 @@
1
+ import path from "node:path";
2
+ import {getClient} from "@lodestar/api";
3
+ import {Lightclient} from "@lodestar/light-client";
4
+ import {LightClientRestTransport} from "@lodestar/light-client/transport";
5
+ import {getNodeLogger} from "@lodestar/logger/node";
6
+ import {fromHex} from "@lodestar/utils";
7
+ import {getBeaconConfigFromArgs} from "../../config/beaconParams.js";
8
+ import {GlobalArgs} from "../../options/index.js";
9
+ import {getGlobalPaths} from "../../paths/global.js";
10
+ import {parseLoggerArgs} from "../../util/logger.js";
11
+ import {ILightClientArgs} from "./options.js";
12
+
13
+ export async function lightclientHandler(args: ILightClientArgs & GlobalArgs): Promise<void> {
14
+ const {config, network} = getBeaconConfigFromArgs(args);
15
+ const globalPaths = getGlobalPaths(args, network);
16
+
17
+ const logger = getNodeLogger(
18
+ parseLoggerArgs(args, {defaultLogFilepath: path.join(globalPaths.dataDir, "lightclient.log")}, config)
19
+ );
20
+
21
+ const api = getClient({baseUrl: args.beaconApiUrl}, {config});
22
+ const {genesisTime, genesisValidatorsRoot} = (await api.beacon.getGenesis()).value();
23
+
24
+ const client = await Lightclient.initializeFromCheckpointRoot({
25
+ config,
26
+ logger,
27
+ genesisData: {
28
+ genesisTime,
29
+ genesisValidatorsRoot,
30
+ },
31
+ checkpointRoot: fromHex(args.checkpointRoot),
32
+ transport: new LightClientRestTransport(api),
33
+ });
34
+
35
+ void client.start();
36
+ }
@@ -0,0 +1,18 @@
1
+ import {CliCommand} from "@lodestar/utils";
2
+ import {GlobalArgs} from "../../options/index.js";
3
+ import {lightclientHandler} from "./handler.js";
4
+ import {ILightClientArgs, lightclientOptions} from "./options.js";
5
+
6
+ export const lightclient: CliCommand<ILightClientArgs, GlobalArgs> = {
7
+ command: "lightclient",
8
+ describe: "Run lightclient",
9
+ docsFolder: "libraries/lightclient-prover",
10
+ examples: [
11
+ {
12
+ command: "lightclient --network hoodi",
13
+ description: "Run lightclient with hoodi network",
14
+ },
15
+ ],
16
+ options: lightclientOptions,
17
+ handler: lightclientHandler,
18
+ };
@@ -0,0 +1,21 @@
1
+ import {CliCommandOptions} from "@lodestar/utils";
2
+ import {LogArgs, logOptions} from "../../options/logOptions.js";
3
+
4
+ export type ILightClientArgs = LogArgs & {
5
+ beaconApiUrl: string;
6
+ checkpointRoot: string;
7
+ };
8
+
9
+ export const lightclientOptions: CliCommandOptions<ILightClientArgs> = {
10
+ ...logOptions,
11
+ beaconApiUrl: {
12
+ description: "Url to a beacon node that support lightclient API",
13
+ type: "string",
14
+ demandOption: true,
15
+ },
16
+ checkpointRoot: {
17
+ description: "Checkpoint root hex string to sync the lightclient from, start with 0x",
18
+ type: "string",
19
+ demandOption: true,
20
+ },
21
+ };
@@ -0,0 +1,91 @@
1
+ import {SecretKey} from "@chainsafe/blst";
2
+ import {getClient} from "@lodestar/api";
3
+ import {createBeaconConfig} from "@lodestar/config";
4
+ import {DOMAIN_BLS_TO_EXECUTION_CHANGE, ForkName} from "@lodestar/params";
5
+ import {computeSigningRoot} from "@lodestar/state-transition";
6
+ import {capella, ssz} from "@lodestar/types";
7
+ import {CliCommand, fromHex} from "@lodestar/utils";
8
+ import {getBeaconConfigFromArgs} from "../../config/index.js";
9
+ import {GlobalArgs} from "../../options/index.js";
10
+ import {IValidatorCliArgs} from "./options.js";
11
+
12
+ type BlsToExecutionChangeArgs = {
13
+ publicKey: string;
14
+ fromBlsPrivkey: string;
15
+ toExecutionAddress: string;
16
+ };
17
+
18
+ export const blsToExecutionChange: CliCommand<BlsToExecutionChangeArgs, IValidatorCliArgs & GlobalArgs> = {
19
+ command: "bls-to-execution-change",
20
+
21
+ describe:
22
+ "Performs BLS To Execution Change for a given validator (as identified via `publicKey`. \
23
+ If no `publicKey` is provided, a prompt will ask the user which validator they would \
24
+ like to choose for BLS To Execution Change.",
25
+
26
+ examples: [
27
+ {
28
+ command: "validator bls-to-execution-change --publicKey 0xF00 --fromBlsPrivkey ... --toExecutionAddress ...",
29
+ description: "Perform BLS To Execution Change for the validator who has a public key 0xF00",
30
+ },
31
+ ],
32
+
33
+ options: {
34
+ publicKey: {
35
+ description: "Validator public key for which to set withdrawal address hence enabling withdrawals",
36
+ type: "string",
37
+ demandOption: true,
38
+ },
39
+ fromBlsPrivkey: {
40
+ description: "Bls withdrawals private key to sign the message",
41
+ type: "string",
42
+ demandOption: true,
43
+ },
44
+ toExecutionAddress: {
45
+ description: "Address to which the validator's balances will be set to be withdrawn.",
46
+ type: "string",
47
+ demandOption: true,
48
+ },
49
+ },
50
+
51
+ handler: async (args) => {
52
+ const {publicKey} = args;
53
+ // Fetch genesisValidatorsRoot always from beacon node as anyway beacon node is needed for
54
+ // submitting the signed message
55
+ const {config: chainForkConfig} = getBeaconConfigFromArgs(args);
56
+ const client = getClient({urls: args.beaconNodes}, {config: chainForkConfig});
57
+ const {genesisValidatorsRoot} = (await client.beacon.getGenesis()).value();
58
+ const config = createBeaconConfig(chainForkConfig, genesisValidatorsRoot);
59
+
60
+ const validators = (await client.beacon.postStateValidators({stateId: "head", validatorIds: [publicKey]})).value();
61
+ const validator = validators[0];
62
+ if (validator === undefined) {
63
+ throw new Error(`Validator pubkey ${publicKey} not found in state`);
64
+ }
65
+
66
+ const blsPrivkey = SecretKey.fromBytes(fromHex(args.fromBlsPrivkey));
67
+ const fromBlsPubkey = blsPrivkey.toPublicKey().toBytes();
68
+
69
+ const blsToExecutionChange: capella.BLSToExecutionChange = {
70
+ validatorIndex: validator.index,
71
+ fromBlsPubkey,
72
+ toExecutionAddress: fromHex(args.toExecutionAddress),
73
+ };
74
+
75
+ const signatureFork = ForkName.phase0;
76
+ const domain = config.getDomainAtFork(signatureFork, DOMAIN_BLS_TO_EXECUTION_CHANGE);
77
+ const signingRoot = computeSigningRoot(ssz.capella.BLSToExecutionChange, blsToExecutionChange, domain);
78
+ const signedBLSToExecutionChange = {
79
+ message: blsToExecutionChange,
80
+ signature: blsPrivkey.sign(signingRoot).toBytes(),
81
+ };
82
+
83
+ (
84
+ await client.beacon.submitPoolBLSToExecutionChange({
85
+ blsToExecutionChanges: [signedBLSToExecutionChange],
86
+ })
87
+ ).assertOk();
88
+
89
+ console.log(`Submitted bls to execution change for ${publicKey}`);
90
+ },
91
+ };