@chainsafe/lodestar 1.35.0-dev.c88a6ed255 → 1.35.0-dev.c9deb9b59f

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,275 @@
1
+ import {
2
+ IBeaconDb,
3
+ IBeaconNodeOptions,
4
+ checkAndPersistAnchorState,
5
+ getStateTypeFromBytes,
6
+ initStateFromEth1,
7
+ } from "@lodestar/beacon-node";
8
+ import {BeaconConfig, ChainForkConfig, createBeaconConfig} from "@lodestar/config";
9
+ import {
10
+ BeaconStateAllForks,
11
+ ensureWithinWeakSubjectivityPeriod,
12
+ isWithinWeakSubjectivityPeriod,
13
+ loadState,
14
+ loadStateAndValidators,
15
+ } from "@lodestar/state-transition";
16
+ import {ssz} from "@lodestar/types";
17
+ import {Checkpoint} from "@lodestar/types/phase0";
18
+ import {Logger, formatBytes, toRootHex} from "@lodestar/utils";
19
+ import {
20
+ fetchWeakSubjectivityState,
21
+ getCheckpointFromArg,
22
+ getCheckpointFromState,
23
+ getGenesisFileUrl,
24
+ getGenesisStateRoot,
25
+ } from "../../networks/index.js";
26
+ import {GlobalArgs, defaultNetwork} from "../../options/globalOptions.js";
27
+ import {downloadOrLoadFile, wrapFnError} from "../../util/index.js";
28
+ import {BeaconArgs} from "./options.js";
29
+
30
+ type StateWithBytes = {state: BeaconStateAllForks; stateBytes: Uint8Array};
31
+
32
+ async function initAndVerifyWeakSubjectivityState(
33
+ config: BeaconConfig,
34
+ db: IBeaconDb,
35
+ logger: Logger,
36
+ dbStateBytes: StateWithBytes,
37
+ wsStateBytes: StateWithBytes,
38
+ wsCheckpoint: Checkpoint,
39
+ opts: {ignoreWeakSubjectivityCheck?: boolean} = {}
40
+ ): Promise<{anchorState: BeaconStateAllForks; wsCheckpoint: Checkpoint}> {
41
+ const dbState = dbStateBytes.state;
42
+ const wsState = wsStateBytes.state;
43
+ // Check if the store's state and wsState are compatible
44
+ if (
45
+ dbState.genesisTime !== wsState.genesisTime ||
46
+ !ssz.Root.equals(dbState.genesisValidatorsRoot, wsState.genesisValidatorsRoot)
47
+ ) {
48
+ throw new Error(
49
+ "Db state and checkpoint state are not compatible, either clear the db or verify your checkpoint source"
50
+ );
51
+ }
52
+
53
+ // Pick the state which is ahead as an anchor to initialize the beacon chain
54
+ let anchorState = wsStateBytes;
55
+ let anchorCheckpoint = wsCheckpoint;
56
+ let isCheckpointState = true;
57
+ if (dbState.slot > wsState.slot) {
58
+ anchorState = dbStateBytes;
59
+ anchorCheckpoint = getCheckpointFromState(dbState);
60
+ isCheckpointState = false;
61
+ logger.verbose(
62
+ "Db state is ahead of the provided checkpoint state, using the db state to initialize the beacon chain"
63
+ );
64
+ }
65
+
66
+ // Throw error unless user explicitly asked not to, in testnets can happen that wss period is too small
67
+ // that even some epochs of non finalization can cause finalized checkpoint to be out of valid range
68
+ const wssCheck = wrapFnError(() => ensureWithinWeakSubjectivityPeriod(config, anchorState.state, anchorCheckpoint));
69
+ const isWithinWeakSubjectivityPeriod = wssCheck.err === null;
70
+ if (!isWithinWeakSubjectivityPeriod && !opts.ignoreWeakSubjectivityCheck) {
71
+ throw wssCheck.err;
72
+ }
73
+
74
+ await checkAndPersistAnchorState(config, db, logger, anchorState.state, anchorState.stateBytes, {
75
+ isWithinWeakSubjectivityPeriod,
76
+ isCheckpointState,
77
+ });
78
+
79
+ // Return the latest anchorState but still return original wsCheckpoint to validate in backfill
80
+ return {anchorState: anchorState.state, wsCheckpoint};
81
+ }
82
+
83
+ /**
84
+ * Initialize a beacon state, picking the strategy based on the `IBeaconArgs`
85
+ *
86
+ * State is initialized in one of three ways:
87
+ * 1. restore from weak subjectivity state (possibly downloaded from a remote beacon node)
88
+ * 2. restore from db
89
+ * 3. restore from genesis state (possibly downloaded via URL)
90
+ * 4. create genesis state from eth1
91
+ */
92
+ export async function initBeaconState(
93
+ options: IBeaconNodeOptions,
94
+ args: BeaconArgs & GlobalArgs,
95
+ chainForkConfig: ChainForkConfig,
96
+ db: IBeaconDb,
97
+ logger: Logger,
98
+ signal: AbortSignal
99
+ ): Promise<{anchorState: BeaconStateAllForks; wsCheckpoint?: Checkpoint}> {
100
+ if (args.forceCheckpointSync && !(args.checkpointState || args.checkpointSyncUrl)) {
101
+ throw new Error("Forced checkpoint sync without specifying a checkpointState or checkpointSyncUrl");
102
+ }
103
+ // fetch the latest state stored in the db which will be used in all cases, if it exists, either
104
+ // i) used directly as the anchor state
105
+ // ii) used to load and verify a weak subjectivity state,
106
+ const lastDbSlot = await db.stateArchive.lastKey();
107
+ let stateBytes = lastDbSlot !== null ? await db.stateArchive.getBinary(lastDbSlot) : null;
108
+ // Convert to `Uint8Array` to avoid unexpected behavior such as `Buffer.prototype.slice` not copying memory
109
+ stateBytes = stateBytes ? new Uint8Array(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength) : null;
110
+ let lastDbState: BeaconStateAllForks | null = null;
111
+ let lastDbValidatorsBytes: Uint8Array | null = null;
112
+ let lastDbStateWithBytes: StateWithBytes | null = null;
113
+ if (stateBytes) {
114
+ logger.verbose("Found the last archived state", {slot: lastDbSlot, size: formatBytes(stateBytes.length)});
115
+ const {state, validatorsBytes} = loadStateAndValidators(chainForkConfig, stateBytes);
116
+ lastDbState = state;
117
+ lastDbValidatorsBytes = validatorsBytes;
118
+ lastDbStateWithBytes = {state, stateBytes: stateBytes};
119
+ }
120
+
121
+ if (lastDbState) {
122
+ const config = createBeaconConfig(chainForkConfig, lastDbState.genesisValidatorsRoot);
123
+ const wssCheck = isWithinWeakSubjectivityPeriod(config, lastDbState, getCheckpointFromState(lastDbState));
124
+
125
+ // Explicitly force syncing from checkpoint state
126
+ if (args.forceCheckpointSync) {
127
+ // Forcing to sync from checkpoint is only recommended if node is taking too long to sync from last db state.
128
+ // It is important to remind the user to remove this flag again unless it is absolutely necessary.
129
+ if (wssCheck) {
130
+ logger.warn(
131
+ `Forced syncing from checkpoint even though db state at slot ${lastDbState.slot} is within weak subjectivity period`
132
+ );
133
+ logger.warn("Please consider removing --forceCheckpointSync flag unless absolutely necessary");
134
+ }
135
+ } else {
136
+ // All cases when we want to directly use lastDbState as the anchor state:
137
+ // - if no checkpoint sync args provided, or
138
+ // - the lastDbState is within weak subjectivity period:
139
+ if ((!args.checkpointState && !args.checkpointSyncUrl) || wssCheck) {
140
+ if (stateBytes === null) {
141
+ // this never happens
142
+ throw Error(`There is no stateBytes for the lastDbState at slot ${lastDbState.slot}`);
143
+ }
144
+ await checkAndPersistAnchorState(config, db, logger, lastDbState, stateBytes, {
145
+ isWithinWeakSubjectivityPeriod: wssCheck,
146
+ isCheckpointState: false,
147
+ });
148
+ return {anchorState: lastDbState};
149
+ }
150
+ }
151
+ }
152
+
153
+ // See if we can sync state using checkpoint sync args or else start from genesis
154
+ if (args.checkpointState) {
155
+ return readWSState(
156
+ lastDbStateWithBytes,
157
+ lastDbValidatorsBytes,
158
+ {
159
+ checkpointState: args.checkpointState,
160
+ wssCheckpoint: args.wssCheckpoint,
161
+ ignoreWeakSubjectivityCheck: args.ignoreWeakSubjectivityCheck,
162
+ },
163
+ chainForkConfig,
164
+ db,
165
+ logger
166
+ );
167
+ }
168
+
169
+ if (args.checkpointSyncUrl) {
170
+ return fetchWSStateFromBeaconApi(
171
+ lastDbStateWithBytes,
172
+ lastDbValidatorsBytes,
173
+ {
174
+ checkpointSyncUrl: args.checkpointSyncUrl,
175
+ wssCheckpoint: args.wssCheckpoint,
176
+ ignoreWeakSubjectivityCheck: args.ignoreWeakSubjectivityCheck,
177
+ },
178
+ chainForkConfig,
179
+ db,
180
+ logger
181
+ );
182
+ }
183
+
184
+ const genesisStateFile = args.genesisStateFile || getGenesisFileUrl(args.network || defaultNetwork);
185
+ if (genesisStateFile && !args.forceGenesis) {
186
+ let stateBytes = await downloadOrLoadFile(genesisStateFile);
187
+ // Convert to `Uint8Array` to avoid unexpected behavior such as `Buffer.prototype.slice` not copying memory
188
+ stateBytes = new Uint8Array(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength);
189
+ const anchorState = getStateTypeFromBytes(chainForkConfig, stateBytes).deserializeToViewDU(stateBytes);
190
+ // Validate genesis state root
191
+ const stateRoot = toRootHex(anchorState.hashTreeRoot());
192
+ const expectedRoot = getGenesisStateRoot(args.network);
193
+ if (expectedRoot !== null && stateRoot !== expectedRoot) {
194
+ throw Error(`Genesis state root mismatch expected=${expectedRoot} received=${stateRoot}`);
195
+ }
196
+ const config = createBeaconConfig(chainForkConfig, anchorState.genesisValidatorsRoot);
197
+ const wssCheck = isWithinWeakSubjectivityPeriod(config, anchorState, getCheckpointFromState(anchorState));
198
+ await checkAndPersistAnchorState(config, db, logger, anchorState, stateBytes, {
199
+ isWithinWeakSubjectivityPeriod: wssCheck,
200
+ isCheckpointState: true,
201
+ });
202
+ return {anchorState};
203
+ }
204
+
205
+ // Only place we will not bother checking isWithinWeakSubjectivityPeriod as forceGenesis passed by user
206
+ const anchorState = await initStateFromEth1({config: chainForkConfig, db, logger, opts: options.eth1, signal});
207
+ return {anchorState};
208
+ }
209
+
210
+ async function readWSState(
211
+ lastDbStateBytes: StateWithBytes | null,
212
+ lastDbValidatorsBytes: Uint8Array | null,
213
+ wssOpts: {checkpointState: string; wssCheckpoint?: string; ignoreWeakSubjectivityCheck?: boolean},
214
+ chainForkConfig: ChainForkConfig,
215
+ db: IBeaconDb,
216
+ logger: Logger
217
+ ): Promise<{anchorState: BeaconStateAllForks; wsCheckpoint?: Checkpoint}> {
218
+ // weak subjectivity sync from a provided state file:
219
+ // if a weak subjectivity checkpoint has been provided, it is used for additional verification
220
+ // otherwise, the state itself is used for verification (not bad, because the trusted state has been explicitly provided)
221
+ const {checkpointState, wssCheckpoint, ignoreWeakSubjectivityCheck} = wssOpts;
222
+ const lastDbState = lastDbStateBytes?.state ?? null;
223
+
224
+ const stateBytes = await downloadOrLoadFile(checkpointState);
225
+ let wsState: BeaconStateAllForks;
226
+ if (lastDbState && lastDbValidatorsBytes) {
227
+ // use lastDbState to load wsState if possible to share the same state tree
228
+ wsState = loadState(chainForkConfig, lastDbState, stateBytes, lastDbValidatorsBytes).state;
229
+ } else {
230
+ wsState = getStateTypeFromBytes(chainForkConfig, stateBytes).deserializeToViewDU(stateBytes);
231
+ }
232
+ const config = createBeaconConfig(chainForkConfig, wsState.genesisValidatorsRoot);
233
+ const wsStateBytes = {state: wsState, stateBytes};
234
+ const store = lastDbStateBytes ?? wsStateBytes;
235
+ const checkpoint = wssCheckpoint ? getCheckpointFromArg(wssCheckpoint) : getCheckpointFromState(wsState);
236
+ return initAndVerifyWeakSubjectivityState(config, db, logger, store, wsStateBytes, checkpoint, {
237
+ ignoreWeakSubjectivityCheck,
238
+ });
239
+ }
240
+
241
+ async function fetchWSStateFromBeaconApi(
242
+ lastDbStateBytes: StateWithBytes | null,
243
+ lastDbValidatorsBytes: Uint8Array | null,
244
+ wssOpts: {checkpointSyncUrl: string; wssCheckpoint?: string; ignoreWeakSubjectivityCheck?: boolean},
245
+ chainForkConfig: ChainForkConfig,
246
+ db: IBeaconDb,
247
+ logger: Logger
248
+ ): Promise<{anchorState: BeaconStateAllForks; wsCheckpoint?: Checkpoint}> {
249
+ // weak subjectivity sync from a state that needs to be fetched:
250
+ // if a weak subjectivity checkpoint has been provided, it is used to inform which state to download and used for additional verification
251
+ // otherwise, the 'finalized' state is downloaded and the state itself is used for verification (all trust delegated to the remote beacon node)
252
+ try {
253
+ // Validate the weakSubjectivityServerUrl and only log the origin to mask the
254
+ // username password credentials
255
+ const checkpointSyncUrl = new URL(wssOpts.checkpointSyncUrl);
256
+ logger.info("Fetching checkpoint state", {
257
+ checkpointSyncUrl: checkpointSyncUrl.origin,
258
+ });
259
+ } catch (e) {
260
+ logger.error("Invalid", {checkpointSyncUrl: wssOpts.checkpointSyncUrl}, e as Error);
261
+ throw e;
262
+ }
263
+
264
+ const {wsState, wsStateBytes, wsCheckpoint} = await fetchWeakSubjectivityState(chainForkConfig, logger, wssOpts, {
265
+ lastDbState: lastDbStateBytes?.state ?? null,
266
+ lastDbValidatorsBytes,
267
+ });
268
+
269
+ const config = createBeaconConfig(chainForkConfig, wsState.genesisValidatorsRoot);
270
+ const wsStateWithBytes = {state: wsState, stateBytes: wsStateBytes};
271
+ const store = lastDbStateBytes ?? wsStateWithBytes;
272
+ return initAndVerifyWeakSubjectivityState(config, db, logger, store, wsStateWithBytes, wsCheckpoint, {
273
+ ignoreWeakSubjectivityCheck: wssOpts.ignoreWeakSubjectivityCheck,
274
+ });
275
+ }
@@ -0,0 +1,199 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import {generateKeyPair} from "@libp2p/crypto/keys";
5
+ import type {PrivateKey} from "@libp2p/interface";
6
+ import {peerIdFromPrivateKey} from "@libp2p/peer-id";
7
+ import {Multiaddr} from "@multiformats/multiaddr";
8
+ import {SignableENR} from "@chainsafe/enr";
9
+ import {Logger} from "@lodestar/utils";
10
+ import {exportToJSON, readPrivateKey} from "../../config/index.js";
11
+ import {parseListenArgs} from "../../options/beaconNodeOptions/network.js";
12
+ import {writeFile600Perm} from "../../util/file.js";
13
+ import {BeaconArgs} from "./options.js";
14
+
15
+ /**
16
+ * Check if multiaddr belongs to the local network interfaces.
17
+ */
18
+ export function isLocalMultiAddr(multiaddr: Multiaddr | undefined): boolean {
19
+ if (!multiaddr) return false;
20
+
21
+ const protoNames = multiaddr.protoNames();
22
+ if (protoNames.length !== 2 && protoNames[1] !== "udp") {
23
+ throw new Error("Invalid udp multiaddr");
24
+ }
25
+
26
+ const interfaces = os.networkInterfaces();
27
+ const tuples = multiaddr.tuples();
28
+ const family = tuples[0][0];
29
+ const isIPv4: boolean = family === 4;
30
+ const ip = tuples[0][1];
31
+
32
+ if (!ip) {
33
+ return false;
34
+ }
35
+
36
+ const ipStr = isIPv4
37
+ ? Array.from(ip).join(".")
38
+ : Array.from(Uint16Array.from(ip))
39
+ .map((n) => n.toString(16))
40
+ .join(":");
41
+
42
+ for (const networkInterfaces of Object.values(interfaces)) {
43
+ for (const networkInterface of networkInterfaces || []) {
44
+ // since node version 18, the netowrkinterface family returns 4 | 6 instead of ipv4 | ipv6,
45
+ // even though the documentation says otherwise.
46
+ // This might be a bug that would be corrected in future version, in the meantime
47
+ // the check using endsWith ensures things work in node version 18 and earlier
48
+ if (String(networkInterface.family).endsWith(String(family)) && networkInterface.address === ipStr) {
49
+ return true;
50
+ }
51
+ }
52
+ }
53
+
54
+ return false;
55
+ }
56
+
57
+ /**
58
+ * Only update the enr if the value has changed
59
+ */
60
+ function maybeUpdateEnr<T extends "ip" | "tcp" | "udp" | "ip6" | "tcp6" | "udp6">(
61
+ enr: SignableENR,
62
+ key: T,
63
+ value: SignableENR[T] | undefined
64
+ ): void {
65
+ if (enr[key] !== value) {
66
+ enr[key] = value;
67
+ }
68
+ }
69
+
70
+ export function overwriteEnrWithCliArgs(
71
+ enr: SignableENR,
72
+ args: BeaconArgs,
73
+ logger: Logger,
74
+ opts?: {newEnr?: boolean; bootnode?: boolean}
75
+ ): void {
76
+ const preSeq = enr.seq;
77
+ const {port, discoveryPort, port6, discoveryPort6} = parseListenArgs(args);
78
+ maybeUpdateEnr(enr, "ip", args["enr.ip"] ?? enr.ip);
79
+ maybeUpdateEnr(enr, "ip6", args["enr.ip6"] ?? enr.ip6);
80
+ maybeUpdateEnr(enr, "udp", args["enr.udp"] ?? discoveryPort ?? enr.udp);
81
+ maybeUpdateEnr(enr, "udp6", args["enr.udp6"] ?? discoveryPort6 ?? enr.udp6);
82
+ if (!opts?.bootnode) {
83
+ maybeUpdateEnr(enr, "tcp", args["enr.tcp"] ?? port ?? enr.tcp);
84
+ maybeUpdateEnr(enr, "tcp6", args["enr.tcp6"] ?? port6 ?? enr.tcp6);
85
+ }
86
+
87
+ function testMultiaddrForLocal(mu: Multiaddr, ip4: boolean): void {
88
+ const isLocal = isLocalMultiAddr(mu);
89
+ if (args.nat) {
90
+ if (isLocal) {
91
+ logger.warn("--nat flag is set with no purpose");
92
+ }
93
+ } else {
94
+ if (!isLocal) {
95
+ logger.warn(
96
+ `Configured ENR ${ip4 ? "IPv4" : "IPv6"} address is not local, clearing ENR ${ip4 ? "ip" : "ip6"} and ${
97
+ ip4 ? "udp" : "udp6"
98
+ }. Set the --nat flag to prevent this`
99
+ );
100
+ if (ip4) {
101
+ enr.delete("ip");
102
+ enr.delete("udp");
103
+ } else {
104
+ enr.delete("ip6");
105
+ enr.delete("udp6");
106
+ }
107
+ }
108
+ }
109
+ }
110
+ const udpMultiaddr4 = enr.getLocationMultiaddr("udp4");
111
+ if (udpMultiaddr4) {
112
+ testMultiaddrForLocal(udpMultiaddr4, true);
113
+ }
114
+ const udpMultiaddr6 = enr.getLocationMultiaddr("udp6");
115
+ if (udpMultiaddr6) {
116
+ testMultiaddrForLocal(udpMultiaddr6, false);
117
+ }
118
+
119
+ if (enr.seq !== preSeq) {
120
+ // If the enr is newly created, its sequence number can be set to 1
121
+ // It's especially clean for fully configured bootnodes whose enrs never change
122
+ // Otherwise, we can increment the sequence number as little as possible
123
+ if (opts?.newEnr) {
124
+ enr.seq = BigInt(1);
125
+ } else {
126
+ enr.seq = preSeq + BigInt(1);
127
+ }
128
+ // invalidate cached signature
129
+ // biome-ignore lint/complexity/useLiteralKeys: `_signature` is a private attribute
130
+ delete enr["_signature"];
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Create new PeerId and ENR by default, unless persistNetworkIdentity is provided
136
+ */
137
+ export async function initPrivateKeyAndEnr(
138
+ args: BeaconArgs,
139
+ beaconDir: string,
140
+ logger: Logger,
141
+ bootnode?: boolean
142
+ ): Promise<{privateKey: PrivateKey; enr: SignableENR}> {
143
+ const {persistNetworkIdentity} = args;
144
+
145
+ const newPrivateKeyAndENR = async (): Promise<{privateKey: PrivateKey; enr: SignableENR}> => {
146
+ const privateKey = await generateKeyPair("secp256k1");
147
+ const enr = SignableENR.createFromPrivateKey(privateKey);
148
+ return {privateKey, enr};
149
+ };
150
+
151
+ const readPersistedPrivateKeyAndENR = async (
152
+ peerIdFile: string,
153
+ enrFile: string
154
+ ): Promise<{privateKey: PrivateKey; enr: SignableENR; newEnr: boolean}> => {
155
+ let privateKey: PrivateKey;
156
+ let enr: SignableENR;
157
+
158
+ // attempt to read stored private key
159
+ try {
160
+ privateKey = readPrivateKey(peerIdFile);
161
+ } catch (e) {
162
+ if ((e as {code: string}).code === "ENOENT") {
163
+ logger.debug("peerIdFile not found, creating a new peer id", {peerIdFile});
164
+ } else {
165
+ logger.warn("Unable to read peerIdFile, creating a new peer id", {peerIdFile}, e as Error);
166
+ }
167
+ return {...(await newPrivateKeyAndENR()), newEnr: true};
168
+ }
169
+ // attempt to read stored enr
170
+ try {
171
+ enr = SignableENR.decodeTxt(fs.readFileSync(enrFile, "utf-8"), privateKey.raw);
172
+ } catch (_e) {
173
+ logger.warn("Unable to decode stored local ENR, creating a new ENR");
174
+ enr = SignableENR.createFromPrivateKey(privateKey);
175
+ return {privateKey, enr, newEnr: true};
176
+ }
177
+ // check stored peer id against stored enr
178
+ if (!peerIdFromPrivateKey(privateKey).equals(enr.peerId)) {
179
+ logger.warn("Stored local ENR doesn't match peerIdFile, creating a new ENR");
180
+ enr = SignableENR.createFromPrivateKey(privateKey);
181
+ return {privateKey, enr, newEnr: true};
182
+ }
183
+ return {privateKey, enr, newEnr: false};
184
+ };
185
+
186
+ if (persistNetworkIdentity) {
187
+ const enrFile = path.join(beaconDir, "enr");
188
+ const peerIdFile = path.join(beaconDir, "peer-id.json");
189
+ const {privateKey, enr, newEnr} = await readPersistedPrivateKeyAndENR(peerIdFile, enrFile);
190
+ overwriteEnrWithCliArgs(enr, args, logger, {newEnr, bootnode});
191
+ // Re-persist peer-id and enr
192
+ writeFile600Perm(peerIdFile, exportToJSON(privateKey));
193
+ writeFile600Perm(enrFile, enr.encodeTxt());
194
+ return {privateKey, enr};
195
+ }
196
+ const {privateKey, enr} = await newPrivateKeyAndENR();
197
+ overwriteEnrWithCliArgs(enr, args, logger, {newEnr: true, bootnode});
198
+ return {privateKey, enr};
199
+ }
@@ -0,0 +1,214 @@
1
+ import {CliCommandOptions, CliOptionDefinition} from "@lodestar/utils";
2
+ import {BeaconNodeArgs, beaconNodeOptions, paramsOptions} from "../../options/index.js";
3
+ import {LogArgs, logOptions} from "../../options/logOptions.js";
4
+ import {BeaconPaths, defaultBeaconPaths} from "./paths.js";
5
+
6
+ type BeaconExtraArgs = {
7
+ forceGenesis?: boolean;
8
+ genesisStateFile?: string;
9
+ configFile?: string;
10
+ bootnodesFile?: string;
11
+ checkpointSyncUrl?: string;
12
+ checkpointState?: string;
13
+ wssCheckpoint?: string;
14
+ forceCheckpointSync?: boolean;
15
+ ignoreWeakSubjectivityCheck?: boolean;
16
+ beaconDir?: string;
17
+ dbDir?: string;
18
+ persistInvalidSszObjectsDir?: string;
19
+ persistInvalidSszObjectsRetentionHours?: number;
20
+ persistOrphanedBlocksDir?: string;
21
+ peerStoreDir?: string;
22
+ persistNetworkIdentity?: boolean;
23
+ private?: boolean;
24
+ validatorMonitorLogs?: boolean;
25
+ attachToGlobalThis?: boolean;
26
+ disableLightClientServer?: boolean;
27
+ };
28
+
29
+ export const beaconExtraOptions: CliCommandOptions<BeaconExtraArgs> = {
30
+ forceGenesis: {
31
+ description: "Force beacon to create genesis without file",
32
+ type: "boolean",
33
+ hidden: true,
34
+ },
35
+
36
+ genesisStateFile: {
37
+ description: "Path or URL to download a genesis state file in ssz-encoded format",
38
+ type: "string",
39
+ },
40
+
41
+ configFile: {
42
+ hidden: true,
43
+ description: "[DEPRECATED] Beacon node configuration file path",
44
+ type: "string",
45
+ },
46
+
47
+ bootnodesFile: {
48
+ hidden: true,
49
+ description: "Bootnodes file path",
50
+ type: "string",
51
+ },
52
+
53
+ checkpointSyncUrl: {
54
+ description:
55
+ "Server url hosting Beacon Node APIs to fetch weak subjectivity state. Fetch latest finalized by default, else set --wssCheckpoint",
56
+ type: "string",
57
+ group: "weak subjectivity",
58
+ },
59
+
60
+ checkpointState: {
61
+ description: "Set a checkpoint state to start syncing from",
62
+ type: "string",
63
+ group: "weak subjectivity",
64
+ },
65
+
66
+ wssCheckpoint: {
67
+ description:
68
+ "Start beacon node off a state at the provided weak subjectivity checkpoint, to be supplied in <blockRoot>:<epoch> format. For example, 0x1234:100 will sync and start off from the weak subjectivity state at checkpoint of epoch 100 with block root 0x1234.",
69
+ type: "string",
70
+ group: "weak subjectivity",
71
+ },
72
+
73
+ forceCheckpointSync: {
74
+ description:
75
+ "Force syncing from checkpoint state even if db state is within weak subjectivity period. This helps to avoid long sync times after node has been offline for a while.",
76
+ type: "boolean",
77
+ group: "weak subjectivity",
78
+ },
79
+
80
+ ignoreWeakSubjectivityCheck: {
81
+ description:
82
+ "Ignore the checkpoint sync state failing the weak subjectivity check. This is relevant in testnets where the weak subjectivity period is too small for even few epochs of non finalization causing last finalized to be out of range. This flag is not recommended for mainnet use.",
83
+ type: "boolean",
84
+ group: "weak subjectivity",
85
+ },
86
+
87
+ beaconDir: {
88
+ description: "Beacon root directory",
89
+ defaultDescription: defaultBeaconPaths.beaconDir,
90
+ hidden: true,
91
+ type: "string",
92
+ },
93
+
94
+ dbDir: {
95
+ description: "Beacon DB directory",
96
+ defaultDescription: defaultBeaconPaths.dbDir,
97
+ hidden: true,
98
+ type: "string",
99
+ },
100
+
101
+ persistInvalidSszObjectsDir: {
102
+ description: "Enable and specify a directory to persist invalid ssz objects",
103
+ defaultDescription: defaultBeaconPaths.persistInvalidSszObjectsDir,
104
+ hidden: true,
105
+ type: "string",
106
+ },
107
+
108
+ persistInvalidSszObjectsRetentionHours: {
109
+ description: "Number of hours to keep invalid SSZ objects on local disk",
110
+ hidden: true,
111
+ type: "number",
112
+ },
113
+
114
+ persistOrphanedBlocksDir: {
115
+ description: "Enable and specify a directory to persist orphaned blocks",
116
+ defaultDescription: defaultBeaconPaths.persistOrphanedBlocksDir,
117
+ hidden: true,
118
+ type: "string",
119
+ },
120
+
121
+ peerStoreDir: {
122
+ hidden: true,
123
+ description: "Peer store directory",
124
+ defaultDescription: defaultBeaconPaths.peerStoreDir,
125
+ type: "string",
126
+ },
127
+
128
+ persistNetworkIdentity: {
129
+ description:
130
+ "Whether to reuse the same peer-id across restarts. Validator custody requires custody group count to persist relative to a given ENR. Setting to false will reset ENR and validator custody requirements on restarts.",
131
+ default: true,
132
+ type: "boolean",
133
+ },
134
+
135
+ private: {
136
+ description:
137
+ "Do not send implementation details over p2p identify protocol and in builder, execution engine and eth1 requests",
138
+ type: "boolean",
139
+ },
140
+
141
+ validatorMonitorLogs: {
142
+ description: "Log validator monitor events as info.",
143
+ type: "boolean",
144
+ },
145
+
146
+ attachToGlobalThis: {
147
+ hidden: true,
148
+ description: "Attach the beacon node to `globalThis`. Useful to inspect a running beacon node.",
149
+ type: "boolean",
150
+ },
151
+
152
+ disableLightClientServer: {
153
+ description: "Disable light client server.",
154
+ type: "boolean",
155
+ },
156
+ };
157
+
158
+ type ENRArgs = {
159
+ "enr.ip"?: string;
160
+ "enr.tcp"?: number;
161
+ "enr.ip6"?: string;
162
+ "enr.udp"?: number;
163
+ "enr.tcp6"?: number;
164
+ "enr.udp6"?: number;
165
+ nat?: boolean;
166
+ };
167
+
168
+ const enrOptions: CliCommandOptions<ENRArgs> = {
169
+ "enr.ip": {
170
+ description: "Override ENR IP entry",
171
+ type: "string",
172
+ group: "enr",
173
+ },
174
+ "enr.tcp": {
175
+ description: "Override ENR TCP entry",
176
+ type: "number",
177
+ group: "enr",
178
+ },
179
+ "enr.udp": {
180
+ description: "Override ENR UDP entry",
181
+ type: "number",
182
+ group: "enr",
183
+ },
184
+ "enr.ip6": {
185
+ description: "Override ENR IPv6 entry",
186
+ type: "string",
187
+ group: "enr",
188
+ },
189
+ "enr.tcp6": {
190
+ description: "Override ENR (IPv6-specific) TCP entry",
191
+ type: "number",
192
+ group: "enr",
193
+ },
194
+ "enr.udp6": {
195
+ description: "Override ENR (IPv6-specific) UDP entry",
196
+ type: "number",
197
+ group: "enr",
198
+ },
199
+ nat: {
200
+ type: "boolean",
201
+ description: "Allow configuration of non-local addresses",
202
+ group: "enr",
203
+ },
204
+ };
205
+
206
+ export type BeaconArgs = BeaconExtraArgs & LogArgs & BeaconPaths & BeaconNodeArgs & ENRArgs;
207
+
208
+ export const beaconOptions: {[k: string]: CliOptionDefinition} = {
209
+ ...beaconExtraOptions,
210
+ ...logOptions,
211
+ ...beaconNodeOptions,
212
+ ...paramsOptions,
213
+ ...enrOptions,
214
+ };