@lodestar/beacon-node 1.39.0-dev.aceb5b7416 → 1.39.0-dev.b37f2bd1bd

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 (248) hide show
  1. package/lib/api/impl/beacon/blocks/utils.js +1 -1
  2. package/lib/api/impl/beacon/blocks/utils.js.map +1 -1
  3. package/lib/chain/chain.d.ts +4 -1
  4. package/lib/chain/chain.d.ts.map +1 -1
  5. package/lib/chain/chain.js +12 -2
  6. package/lib/chain/chain.js.map +1 -1
  7. package/lib/chain/genesis/genesis.d.ts +51 -0
  8. package/lib/chain/genesis/genesis.d.ts.map +1 -0
  9. package/lib/chain/genesis/genesis.js +123 -0
  10. package/lib/chain/genesis/genesis.js.map +1 -0
  11. package/lib/chain/genesis/interface.d.ts +13 -0
  12. package/lib/chain/genesis/interface.d.ts.map +1 -0
  13. package/lib/chain/genesis/interface.js +2 -0
  14. package/lib/chain/genesis/interface.js.map +1 -0
  15. package/lib/chain/initState.d.ts +14 -1
  16. package/lib/chain/initState.d.ts.map +1 -1
  17. package/lib/chain/initState.js +62 -1
  18. package/lib/chain/initState.js.map +1 -1
  19. package/lib/chain/interface.d.ts +2 -0
  20. package/lib/chain/interface.d.ts.map +1 -1
  21. package/lib/chain/interface.js.map +1 -1
  22. package/lib/chain/prepareNextSlot.d.ts +4 -0
  23. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  24. package/lib/chain/prepareNextSlot.js +21 -1
  25. package/lib/chain/prepareNextSlot.js.map +1 -1
  26. package/lib/chain/produceBlock/produceBlockBody.d.ts +1 -0
  27. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  28. package/lib/chain/produceBlock/produceBlockBody.js +9 -6
  29. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  30. package/lib/db/beacon.d.ts +7 -1
  31. package/lib/db/beacon.d.ts.map +1 -1
  32. package/lib/db/beacon.js +12 -1
  33. package/lib/db/beacon.js.map +1 -1
  34. package/lib/db/buckets.d.ts +6 -0
  35. package/lib/db/buckets.d.ts.map +1 -1
  36. package/lib/db/buckets.js +7 -6
  37. package/lib/db/buckets.js.map +1 -1
  38. package/lib/db/interface.d.ts +7 -1
  39. package/lib/db/interface.d.ts.map +1 -1
  40. package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
  41. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  42. package/lib/db/repositories/depositDataRoot.d.ts +22 -0
  43. package/lib/db/repositories/depositDataRoot.d.ts.map +1 -0
  44. package/lib/db/repositories/depositDataRoot.js +62 -0
  45. package/lib/db/repositories/depositDataRoot.js.map +1 -0
  46. package/lib/db/repositories/depositEvent.d.ts +13 -0
  47. package/lib/db/repositories/depositEvent.d.ts.map +1 -0
  48. package/lib/db/repositories/depositEvent.js +27 -0
  49. package/lib/db/repositories/depositEvent.js.map +1 -0
  50. package/lib/db/repositories/eth1Data.d.ts +13 -0
  51. package/lib/db/repositories/eth1Data.d.ts.map +1 -0
  52. package/lib/db/repositories/eth1Data.js +26 -0
  53. package/lib/db/repositories/eth1Data.js.map +1 -0
  54. package/lib/db/repositories/index.d.ts +3 -0
  55. package/lib/db/repositories/index.d.ts.map +1 -1
  56. package/lib/db/repositories/index.js +3 -0
  57. package/lib/db/repositories/index.js.map +1 -1
  58. package/lib/db/single/index.d.ts +3 -0
  59. package/lib/db/single/index.d.ts.map +1 -0
  60. package/lib/db/single/index.js +3 -0
  61. package/lib/db/single/index.js.map +1 -0
  62. package/lib/db/single/preGenesisState.d.ts +16 -0
  63. package/lib/db/single/preGenesisState.d.ts.map +1 -0
  64. package/lib/db/single/preGenesisState.js +29 -0
  65. package/lib/db/single/preGenesisState.js.map +1 -0
  66. package/lib/db/single/preGenesisStateLastProcessedBlock.d.ts +14 -0
  67. package/lib/db/single/preGenesisStateLastProcessedBlock.d.ts.map +1 -0
  68. package/lib/db/single/preGenesisStateLastProcessedBlock.js +27 -0
  69. package/lib/db/single/preGenesisStateLastProcessedBlock.js.map +1 -0
  70. package/lib/eth1/errors.d.ts +66 -0
  71. package/lib/eth1/errors.d.ts.map +1 -0
  72. package/lib/eth1/errors.js +27 -0
  73. package/lib/eth1/errors.js.map +1 -0
  74. package/lib/eth1/eth1DataCache.d.ts +19 -0
  75. package/lib/eth1/eth1DataCache.d.ts.map +1 -0
  76. package/lib/eth1/eth1DataCache.js +19 -0
  77. package/lib/eth1/eth1DataCache.js.map +1 -0
  78. package/lib/eth1/eth1DepositDataTracker.d.ts +80 -0
  79. package/lib/eth1/eth1DepositDataTracker.d.ts.map +1 -0
  80. package/lib/eth1/eth1DepositDataTracker.js +317 -0
  81. package/lib/eth1/eth1DepositDataTracker.js.map +1 -0
  82. package/lib/eth1/eth1DepositsCache.d.ts +42 -0
  83. package/lib/eth1/eth1DepositsCache.d.ts.map +1 -0
  84. package/lib/eth1/eth1DepositsCache.js +119 -0
  85. package/lib/eth1/eth1DepositsCache.js.map +1 -0
  86. package/lib/eth1/index.d.ts +31 -0
  87. package/lib/eth1/index.d.ts.map +1 -0
  88. package/lib/eth1/index.js +71 -0
  89. package/lib/eth1/index.js.map +1 -0
  90. package/lib/eth1/interface.d.ts +74 -0
  91. package/lib/eth1/interface.d.ts.map +1 -0
  92. package/lib/eth1/interface.js +8 -0
  93. package/lib/eth1/interface.js.map +1 -0
  94. package/lib/eth1/options.d.ts +22 -0
  95. package/lib/eth1/options.d.ts.map +1 -0
  96. package/lib/eth1/options.js +8 -0
  97. package/lib/eth1/options.js.map +1 -0
  98. package/lib/eth1/provider/eth1Provider.d.ts +39 -0
  99. package/lib/eth1/provider/eth1Provider.d.ts.map +1 -0
  100. package/lib/eth1/provider/eth1Provider.js +147 -0
  101. package/lib/eth1/provider/eth1Provider.js.map +1 -0
  102. package/lib/{execution/engine → eth1/provider}/jsonRpcHttpClient.d.ts +1 -1
  103. package/lib/eth1/provider/jsonRpcHttpClient.d.ts.map +1 -0
  104. package/lib/eth1/provider/jsonRpcHttpClient.js.map +1 -0
  105. package/lib/eth1/provider/jwt.d.ts.map +1 -0
  106. package/lib/eth1/provider/jwt.js.map +1 -0
  107. package/lib/eth1/provider/utils.d.ts +65 -0
  108. package/lib/eth1/provider/utils.d.ts.map +1 -0
  109. package/lib/eth1/provider/utils.js +120 -0
  110. package/lib/eth1/provider/utils.js.map +1 -0
  111. package/lib/eth1/stream.d.ts +15 -0
  112. package/lib/eth1/stream.d.ts.map +1 -0
  113. package/lib/eth1/stream.js +54 -0
  114. package/lib/eth1/stream.js.map +1 -0
  115. package/lib/eth1/utils/depositContract.d.ts +14 -0
  116. package/lib/eth1/utils/depositContract.d.ts.map +1 -0
  117. package/lib/eth1/utils/depositContract.js +33 -0
  118. package/lib/eth1/utils/depositContract.js.map +1 -0
  119. package/lib/eth1/utils/deposits.d.ts +8 -0
  120. package/lib/eth1/utils/deposits.d.ts.map +1 -0
  121. package/lib/eth1/utils/deposits.js +47 -0
  122. package/lib/eth1/utils/deposits.js.map +1 -0
  123. package/lib/eth1/utils/eth1Data.d.ts +22 -0
  124. package/lib/eth1/utils/eth1Data.d.ts.map +1 -0
  125. package/lib/eth1/utils/eth1Data.js +77 -0
  126. package/lib/eth1/utils/eth1Data.js.map +1 -0
  127. package/lib/eth1/utils/eth1DepositEvent.d.ts +7 -0
  128. package/lib/eth1/utils/eth1DepositEvent.d.ts.map +1 -0
  129. package/lib/eth1/utils/eth1DepositEvent.js +13 -0
  130. package/lib/eth1/utils/eth1DepositEvent.js.map +1 -0
  131. package/lib/eth1/utils/eth1Vote.d.ts +17 -0
  132. package/lib/eth1/utils/eth1Vote.d.ts.map +1 -0
  133. package/lib/eth1/utils/eth1Vote.js +111 -0
  134. package/lib/eth1/utils/eth1Vote.js.map +1 -0
  135. package/lib/eth1/utils/groupDepositEventsByBlock.d.ts +9 -0
  136. package/lib/eth1/utils/groupDepositEventsByBlock.d.ts.map +1 -0
  137. package/lib/eth1/utils/groupDepositEventsByBlock.js +17 -0
  138. package/lib/eth1/utils/groupDepositEventsByBlock.js.map +1 -0
  139. package/lib/eth1/utils/optimizeNextBlockDiffForGenesis.d.ts +10 -0
  140. package/lib/eth1/utils/optimizeNextBlockDiffForGenesis.d.ts.map +1 -0
  141. package/lib/eth1/utils/optimizeNextBlockDiffForGenesis.js +14 -0
  142. package/lib/eth1/utils/optimizeNextBlockDiffForGenesis.js.map +1 -0
  143. package/lib/execution/engine/http.d.ts +1 -1
  144. package/lib/execution/engine/http.d.ts.map +1 -1
  145. package/lib/execution/engine/http.js +3 -2
  146. package/lib/execution/engine/http.js.map +1 -1
  147. package/lib/execution/engine/index.d.ts.map +1 -1
  148. package/lib/execution/engine/index.js +1 -1
  149. package/lib/execution/engine/index.js.map +1 -1
  150. package/lib/execution/engine/interface.d.ts +1 -1
  151. package/lib/execution/engine/interface.d.ts.map +1 -1
  152. package/lib/execution/engine/interface.js.map +1 -1
  153. package/lib/execution/engine/mock.d.ts.map +1 -1
  154. package/lib/execution/engine/mock.js +1 -1
  155. package/lib/execution/engine/mock.js.map +1 -1
  156. package/lib/execution/engine/payloadIdCache.d.ts +1 -1
  157. package/lib/execution/engine/payloadIdCache.d.ts.map +1 -1
  158. package/lib/execution/engine/types.d.ts +1 -1
  159. package/lib/execution/engine/types.d.ts.map +1 -1
  160. package/lib/execution/engine/types.js +1 -1
  161. package/lib/execution/engine/types.js.map +1 -1
  162. package/lib/execution/engine/utils.d.ts +2 -64
  163. package/lib/execution/engine/utils.d.ts.map +1 -1
  164. package/lib/execution/engine/utils.js +2 -91
  165. package/lib/execution/engine/utils.js.map +1 -1
  166. package/lib/index.d.ts +2 -1
  167. package/lib/index.d.ts.map +1 -1
  168. package/lib/index.js +2 -1
  169. package/lib/index.js.map +1 -1
  170. package/lib/metrics/metrics/lodestar.d.ts +35 -0
  171. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  172. package/lib/metrics/metrics/lodestar.js +90 -0
  173. package/lib/metrics/metrics/lodestar.js.map +1 -1
  174. package/lib/node/nodejs.d.ts.map +1 -1
  175. package/lib/node/nodejs.js +9 -0
  176. package/lib/node/nodejs.js.map +1 -1
  177. package/lib/node/options.d.ts +2 -0
  178. package/lib/node/options.d.ts.map +1 -1
  179. package/lib/node/options.js +2 -0
  180. package/lib/node/options.js.map +1 -1
  181. package/lib/node/utils/interop/deposits.d.ts +1 -2
  182. package/lib/node/utils/interop/deposits.d.ts.map +1 -1
  183. package/lib/node/utils/interop/deposits.js.map +1 -1
  184. package/lib/node/utils/interop/state.d.ts +1 -1
  185. package/lib/node/utils/interop/state.d.ts.map +1 -1
  186. package/lib/node/utils/state.d.ts +7 -1
  187. package/lib/node/utils/state.d.ts.map +1 -1
  188. package/lib/node/utils/state.js +14 -1
  189. package/lib/node/utils/state.js.map +1 -1
  190. package/package.json +20 -14
  191. package/src/api/impl/beacon/blocks/utils.ts +1 -1
  192. package/src/chain/chain.ts +15 -1
  193. package/src/chain/genesis/genesis.ts +190 -0
  194. package/src/chain/genesis/interface.ts +14 -0
  195. package/src/chain/initState.ts +97 -1
  196. package/src/chain/interface.ts +2 -0
  197. package/src/chain/prepareNextSlot.ts +28 -1
  198. package/src/chain/produceBlock/produceBlockBody.ts +10 -6
  199. package/src/db/beacon.ts +15 -0
  200. package/src/db/buckets.ts +7 -6
  201. package/src/db/interface.ts +13 -0
  202. package/src/db/repositories/depositDataRoot.ts +80 -0
  203. package/src/db/repositories/depositEvent.ts +32 -0
  204. package/src/db/repositories/eth1Data.ts +33 -0
  205. package/src/db/repositories/index.ts +3 -0
  206. package/src/db/single/index.ts +2 -0
  207. package/src/db/single/preGenesisState.ts +37 -0
  208. package/src/db/single/preGenesisStateLastProcessedBlock.ts +34 -0
  209. package/src/eth1/errors.ts +40 -0
  210. package/src/eth1/eth1DataCache.ts +26 -0
  211. package/src/eth1/eth1DepositDataTracker.ts +410 -0
  212. package/src/eth1/eth1DepositsCache.ts +141 -0
  213. package/src/eth1/index.ts +94 -0
  214. package/src/eth1/interface.ts +87 -0
  215. package/src/eth1/options.ts +28 -0
  216. package/src/eth1/provider/eth1Provider.ts +229 -0
  217. package/src/{execution/engine → eth1/provider}/jsonRpcHttpClient.ts +1 -1
  218. package/src/eth1/provider/utils.ts +136 -0
  219. package/src/eth1/stream.ts +75 -0
  220. package/src/eth1/utils/depositContract.ts +37 -0
  221. package/src/eth1/utils/deposits.ts +70 -0
  222. package/src/eth1/utils/eth1Data.ts +100 -0
  223. package/src/eth1/utils/eth1DepositEvent.ts +12 -0
  224. package/src/eth1/utils/eth1Vote.ts +142 -0
  225. package/src/eth1/utils/groupDepositEventsByBlock.ts +19 -0
  226. package/src/eth1/utils/optimizeNextBlockDiffForGenesis.ts +18 -0
  227. package/src/execution/engine/http.ts +9 -8
  228. package/src/execution/engine/index.ts +1 -1
  229. package/src/execution/engine/interface.ts +1 -1
  230. package/src/execution/engine/mock.ts +2 -1
  231. package/src/execution/engine/payloadIdCache.ts +1 -1
  232. package/src/execution/engine/types.ts +9 -9
  233. package/src/execution/engine/utils.ts +5 -111
  234. package/src/index.ts +2 -1
  235. package/src/metrics/metrics/lodestar.ts +92 -0
  236. package/src/node/nodejs.ts +9 -0
  237. package/src/node/options.ts +3 -0
  238. package/src/node/utils/interop/deposits.ts +1 -3
  239. package/src/node/utils/interop/state.ts +1 -1
  240. package/src/node/utils/state.ts +18 -3
  241. package/lib/execution/engine/jsonRpcHttpClient.d.ts.map +0 -1
  242. package/lib/execution/engine/jsonRpcHttpClient.js.map +0 -1
  243. package/lib/execution/engine/jwt.d.ts.map +0 -1
  244. package/lib/execution/engine/jwt.js.map +0 -1
  245. /package/lib/{execution/engine → eth1/provider}/jsonRpcHttpClient.js +0 -0
  246. /package/lib/{execution/engine → eth1/provider}/jwt.d.ts +0 -0
  247. /package/lib/{execution/engine → eth1/provider}/jwt.js +0 -0
  248. /package/src/{execution/engine → eth1/provider}/jwt.ts +0 -0
@@ -0,0 +1,100 @@
1
+ import {Root, phase0} from "@lodestar/types";
2
+ import {DepositTree} from "../../db/repositories/depositDataRoot.js";
3
+ import {binarySearchLte} from "../../util/binarySearch.js";
4
+ import {Eth1Error, Eth1ErrorCode} from "../errors.js";
5
+ import {Eth1Block} from "../interface.js";
6
+
7
+ type BlockNumber = number;
8
+
9
+ /**
10
+ * Appends partial eth1 data (depositRoot, depositCount) in a sequence of blocks
11
+ * eth1 data deposit is inferred from sparse eth1 data obtained from the deposit logs
12
+ */
13
+ export async function getEth1DataForBlocks(
14
+ blocks: Eth1Block[],
15
+ depositDescendingStream: AsyncIterable<phase0.DepositEvent>,
16
+ depositRootTree: DepositTree,
17
+ lastProcessedDepositBlockNumber: BlockNumber | null
18
+ ): Promise<(phase0.Eth1Data & Eth1Block)[]> {
19
+ // Exclude blocks for which there is no valid eth1 data deposit
20
+ if (lastProcessedDepositBlockNumber !== null) {
21
+ blocks = blocks.filter((block) => block.blockNumber <= lastProcessedDepositBlockNumber);
22
+ }
23
+
24
+ // A valid block can be constructed using previous `state.eth1Data`, don't throw
25
+ if (blocks.length === 0) {
26
+ return [];
27
+ }
28
+
29
+ // Collect the latest deposit of each blockNumber in a block number range
30
+ const fromBlock = blocks[0].blockNumber;
31
+ const toBlock = blocks.at(-1)?.blockNumber as number;
32
+ const depositsByBlockNumber = await getDepositsByBlockNumber(fromBlock, toBlock, depositDescendingStream);
33
+ if (depositsByBlockNumber.length === 0) {
34
+ throw new Eth1Error({code: Eth1ErrorCode.NO_DEPOSITS_FOR_BLOCK_RANGE, fromBlock, toBlock});
35
+ }
36
+
37
+ // Precompute a map of depositCount => depositRoot (from depositRootTree)
38
+ const depositCounts = depositsByBlockNumber.map((event) => event.index + 1);
39
+ const depositRootByDepositCount = getDepositRootByDepositCount(depositCounts, depositRootTree);
40
+
41
+ const eth1Datas: (phase0.Eth1Data & Eth1Block)[] = [];
42
+ for (const block of blocks) {
43
+ const deposit = binarySearchLte(depositsByBlockNumber, block.blockNumber, (event) => event.blockNumber);
44
+ const depositCount = deposit.index + 1;
45
+ const depositRoot = depositRootByDepositCount.get(depositCount);
46
+ if (depositRoot === undefined) {
47
+ throw new Eth1Error({code: Eth1ErrorCode.NO_DEPOSIT_ROOT, depositCount});
48
+ }
49
+ eth1Datas.push({...block, depositCount, depositRoot});
50
+ }
51
+ return eth1Datas;
52
+ }
53
+
54
+ /**
55
+ * Collect depositCount by blockNumber from a stream matching a block number range
56
+ * For a given blockNumber it's depositCount is equal to the index + 1 of the
57
+ * closest deposit event whose deposit.blockNumber <= blockNumber
58
+ * @returns array ascending by blockNumber
59
+ */
60
+ export async function getDepositsByBlockNumber(
61
+ fromBlock: BlockNumber,
62
+ toBlock: BlockNumber,
63
+ depositEventDescendingStream: AsyncIterable<phase0.DepositEvent>
64
+ ): Promise<phase0.DepositEvent[]> {
65
+ const depositCountMap = new Map<BlockNumber, phase0.DepositEvent>();
66
+ // Take blocks until the block under the range lower bound (included)
67
+ for await (const deposit of depositEventDescendingStream) {
68
+ if (deposit.blockNumber <= toBlock && !depositCountMap.has(deposit.blockNumber)) {
69
+ depositCountMap.set(deposit.blockNumber, deposit);
70
+ }
71
+ if (deposit.blockNumber < fromBlock) {
72
+ break;
73
+ }
74
+ }
75
+
76
+ return Array.from(depositCountMap.values()).sort((a, b) => a.blockNumber - b.blockNumber);
77
+ }
78
+
79
+ /**
80
+ * Precompute a map of depositCount => depositRoot from a depositRootTree filled beforehand
81
+ */
82
+ export function getDepositRootByDepositCount(depositCounts: number[], depositRootTree: DepositTree): Map<number, Root> {
83
+ // Unique + sort numerically in descending order
84
+ depositCounts = [...new Set(depositCounts)].sort((a, b) => b - a);
85
+
86
+ if (depositCounts.length > 0) {
87
+ const maxIndex = depositCounts[0] - 1;
88
+ const treeLength = depositRootTree.length - 1;
89
+ if (maxIndex > treeLength) {
90
+ throw new Eth1Error({code: Eth1ErrorCode.NOT_ENOUGH_DEPOSIT_ROOTS, index: maxIndex, treeLength});
91
+ }
92
+ }
93
+
94
+ const depositRootByDepositCount = new Map<number, Root>();
95
+ for (const depositCount of depositCounts) {
96
+ depositRootTree = depositRootTree.sliceTo(depositCount - 1);
97
+ depositRootByDepositCount.set(depositCount, depositRootTree.hashTreeRoot());
98
+ }
99
+ return depositRootByDepositCount;
100
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Assert that an array of deposits are consecutive and ascending
3
+ */
4
+ export function assertConsecutiveDeposits(depositEvents: {index: number}[]): void {
5
+ for (let i = 0; i < depositEvents.length - 1; i++) {
6
+ const indexLeft = depositEvents[i].index;
7
+ const indexRight = depositEvents[i + 1].index;
8
+ if (indexLeft !== indexRight - 1) {
9
+ throw Error(`Non consecutive deposits. deposit[${i}] = ${indexLeft}, deposit[${i + 1}] ${indexRight}`);
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,142 @@
1
+ import {ChainForkConfig} from "@lodestar/config";
2
+ import {EPOCHS_PER_ETH1_VOTING_PERIOD, SLOTS_PER_EPOCH, isForkPostElectra} from "@lodestar/params";
3
+ import {BeaconStateAllForks, BeaconStateElectra, computeTimeAtSlot} from "@lodestar/state-transition";
4
+ import {RootHex, phase0} from "@lodestar/types";
5
+ import {toRootHex} from "@lodestar/utils";
6
+
7
+ export type Eth1DataGetter = ({
8
+ timestampRange,
9
+ }: {
10
+ timestampRange: {gte: number; lte: number};
11
+ }) => Promise<phase0.Eth1Data[]>;
12
+
13
+ export async function getEth1VotesToConsider(
14
+ config: ChainForkConfig,
15
+ state: BeaconStateAllForks,
16
+ eth1DataGetter: Eth1DataGetter
17
+ ): Promise<phase0.Eth1Data[]> {
18
+ const fork = config.getForkName(state.slot);
19
+ if (isForkPostElectra(fork)) {
20
+ const {eth1DepositIndex, depositRequestsStartIndex} = state as BeaconStateElectra;
21
+ if (eth1DepositIndex === Number(depositRequestsStartIndex)) {
22
+ return state.eth1DataVotes.getAllReadonly();
23
+ }
24
+ }
25
+
26
+ const periodStart = votingPeriodStartTime(config, state);
27
+ const {SECONDS_PER_ETH1_BLOCK, ETH1_FOLLOW_DISTANCE} = config;
28
+
29
+ // Modified version of the spec function to fetch the required range directly from the DB
30
+ return (
31
+ await eth1DataGetter({
32
+ timestampRange: {
33
+ // Spec v0.12.2
34
+ // is_candidate_block =
35
+ // block.timestamp + SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE <= period_start &&
36
+ // block.timestamp + SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE * 2 >= period_start
37
+ lte: periodStart - SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE,
38
+ gte: periodStart - SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE * 2,
39
+ },
40
+ })
41
+ ).filter((eth1Data) => eth1Data.depositCount >= state.eth1Data.depositCount);
42
+ }
43
+
44
+ export function pickEth1Vote(state: BeaconStateAllForks, votesToConsider: phase0.Eth1Data[]): phase0.Eth1Data {
45
+ const votesToConsiderKeys = new Set<string>();
46
+ for (const eth1Data of votesToConsider) {
47
+ votesToConsiderKeys.add(getEth1DataKey(eth1Data));
48
+ }
49
+
50
+ const eth1DataHashToEth1Data = new Map<RootHex, phase0.Eth1Data>();
51
+ const eth1DataVoteCountByRoot = new Map<RootHex, number>();
52
+ const eth1DataVotesOrder: RootHex[] = [];
53
+
54
+ // BeaconStateAllForks is always represented as a tree with a hashing cache.
55
+ // To check equality its cheaper to use hashTreeRoot as keys.
56
+ // However `votesToConsider` is an array of values since those are read from DB.
57
+ // TODO: Optimize cache of known votes, to prevent re-hashing stored values.
58
+ // Note: for low validator counts it's not very important, since this runs once per proposal
59
+ const eth1DataVotes = state.eth1DataVotes.getAllReadonly();
60
+ for (const eth1DataVote of eth1DataVotes) {
61
+ const rootHex = getEth1DataKey(eth1DataVote);
62
+
63
+ if (votesToConsiderKeys.has(rootHex)) {
64
+ const prevVoteCount = eth1DataVoteCountByRoot.get(rootHex);
65
+ eth1DataVoteCountByRoot.set(rootHex, 1 + (prevVoteCount ?? 0));
66
+
67
+ // Cache eth1DataVote to root Map only once per root
68
+ if (prevVoteCount === undefined) {
69
+ eth1DataHashToEth1Data.set(rootHex, eth1DataVote);
70
+ eth1DataVotesOrder.push(rootHex);
71
+ }
72
+ }
73
+ }
74
+
75
+ const eth1DataRootsMaxVotes = getKeysWithMaxValue(eth1DataVoteCountByRoot);
76
+
77
+ // No votes, vote for the last valid vote
78
+ if (eth1DataRootsMaxVotes.length === 0) {
79
+ return votesToConsider.at(-1) ?? state.eth1Data;
80
+ }
81
+
82
+ // If there's a single winning vote with a majority vote that one
83
+ if (eth1DataRootsMaxVotes.length === 1) {
84
+ return eth1DataHashToEth1Data.get(eth1DataRootsMaxVotes[0]) ?? state.eth1Data;
85
+ }
86
+
87
+ // If there are multiple winning votes, vote for the latest one
88
+ const latestMostVotedRoot =
89
+ eth1DataVotesOrder[Math.max(...eth1DataRootsMaxVotes.map((root) => eth1DataVotesOrder.indexOf(root)))];
90
+ return eth1DataHashToEth1Data.get(latestMostVotedRoot) ?? state.eth1Data;
91
+ }
92
+
93
+ /**
94
+ * Returns the array of keys with max value. May return 0, 1 or more keys
95
+ */
96
+ function getKeysWithMaxValue<T>(map: Map<T, number>): T[] {
97
+ const entries = Array.from(map.entries());
98
+ let keysMax: T[] = [];
99
+ let valueMax = -Infinity;
100
+
101
+ for (const [key, value] of entries) {
102
+ if (value > valueMax) {
103
+ keysMax = [key];
104
+ valueMax = value;
105
+ } else if (value === valueMax) {
106
+ keysMax.push(key);
107
+ }
108
+ }
109
+
110
+ return keysMax;
111
+ }
112
+
113
+ /**
114
+ * Key-ed by fastSerializeEth1Data(). votesToConsider is read from DB as struct and always has a length of 2048.
115
+ * `state.eth1DataVotes` has a length between 0 and ETH1_FOLLOW_DISTANCE with an equal probability of each value.
116
+ * So to get the average faster time to key both votesToConsider and state.eth1DataVotes it's better to use
117
+ * fastSerializeEth1Data(). However, a long term solution is to cache valid votes in memory and prevent having
118
+ * to recompute their key on every proposal.
119
+ *
120
+ * With `fastSerializeEth1Data()`: avg time 20 ms/op
121
+ * ✓ pickEth1Vote - no votes 233.0587 ops/s 4.290764 ms/op - 121 runs 1.02 s
122
+ * ✓ pickEth1Vote - max votes 29.21546 ops/s 34.22845 ms/op - 25 runs 1.38 s
123
+ *
124
+ * With `toHexString(ssz.phase0.Eth1Data.hashTreeRoot(eth1Data))`: avg time 23 ms/op
125
+ * ✓ pickEth1Vote - no votes 46.12341 ops/s 21.68096 ms/op - 133 runs 3.40 s
126
+ * ✓ pickEth1Vote - max votes 37.89912 ops/s 26.38583 ms/op - 29 runs 1.27 s
127
+ */
128
+ function getEth1DataKey(eth1Data: phase0.Eth1Data): string {
129
+ return fastSerializeEth1Data(eth1Data);
130
+ }
131
+
132
+ /**
133
+ * Serialize eth1Data types to a unique string ID. It is only used for comparison.
134
+ */
135
+ export function fastSerializeEth1Data(eth1Data: phase0.Eth1Data): string {
136
+ return toRootHex(eth1Data.blockHash) + eth1Data.depositCount.toString(16) + toRootHex(eth1Data.depositRoot);
137
+ }
138
+
139
+ export function votingPeriodStartTime(config: ChainForkConfig, state: BeaconStateAllForks): number {
140
+ const eth1VotingPeriodStartSlot = state.slot - (state.slot % (EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH));
141
+ return computeTimeAtSlot(config, eth1VotingPeriodStartSlot, state.genesisTime);
142
+ }
@@ -0,0 +1,19 @@
1
+ import {phase0} from "@lodestar/types";
2
+ import {BatchDepositEvents} from "../interface.js";
3
+
4
+ /**
5
+ * Return deposit events of blocks grouped/sorted by block number and deposit index
6
+ * Blocks without events are omitted
7
+ * @param depositEvents range deposit events
8
+ */
9
+ export function groupDepositEventsByBlock(depositEvents: phase0.DepositEvent[]): BatchDepositEvents[] {
10
+ depositEvents.sort((event1, event2) => event1.index - event2.index);
11
+ const depositsByBlockMap = new Map<number, phase0.DepositEvent[]>();
12
+ for (const deposit of depositEvents) {
13
+ depositsByBlockMap.set(deposit.blockNumber, [...(depositsByBlockMap.get(deposit.blockNumber) || []), deposit]);
14
+ }
15
+ return Array.from(depositsByBlockMap.entries()).map(([blockNumber, depositEvents]) => ({
16
+ blockNumber,
17
+ depositEvents,
18
+ }));
19
+ }
@@ -0,0 +1,18 @@
1
+ import {ChainConfig} from "@lodestar/config";
2
+
3
+ /**
4
+ * Utility for fetching genesis min genesis time block
5
+ * Returns an approximation of the next block diff to fetch to progressively
6
+ * get closer to the block that satisfies min genesis time condition
7
+ */
8
+ export function optimizeNextBlockDiffForGenesis(
9
+ lastFetchedBlock: {timestamp: number},
10
+ params: Pick<ChainConfig, "MIN_GENESIS_TIME" | "GENESIS_DELAY" | "SECONDS_PER_ETH1_BLOCK">
11
+ ): number {
12
+ const timeToGenesis = params.MIN_GENESIS_TIME - params.GENESIS_DELAY - lastFetchedBlock.timestamp;
13
+ const numBlocksToGenesis = Math.floor(timeToGenesis / params.SECONDS_PER_ETH1_BLOCK);
14
+ if (numBlocksToGenesis <= 2) {
15
+ return 1;
16
+ }
17
+ return Math.max(1, Math.floor(numBlocksToGenesis / 2));
18
+ }
@@ -4,6 +4,14 @@ import {BlobsBundle, ExecutionPayload, ExecutionRequests, Root, RootHex, Wei} fr
4
4
  import {BlobAndProof} from "@lodestar/types/deneb";
5
5
  import {BlobAndProofV2} from "@lodestar/types/fulu";
6
6
  import {strip0xPrefix} from "@lodestar/utils";
7
+ import {
8
+ ErrorJsonRpcResponse,
9
+ HttpRpcError,
10
+ IJsonRpcHttpClient,
11
+ JsonRpcHttpClientEvent,
12
+ ReqOpts,
13
+ } from "../../eth1/provider/jsonRpcHttpClient.js";
14
+ import {bytesToData, numToQuantity} from "../../eth1/provider/utils.js";
7
15
  import {Metrics} from "../../metrics/index.js";
8
16
  import {EPOCHS_PER_BATCH} from "../../sync/constants.js";
9
17
  import {getLodestarClientVersion} from "../../util/metadata.js";
@@ -19,13 +27,6 @@ import {
19
27
  PayloadId,
20
28
  VersionedHashes,
21
29
  } from "./interface.js";
22
- import {
23
- ErrorJsonRpcResponse,
24
- HttpRpcError,
25
- IJsonRpcHttpClient,
26
- JsonRpcHttpClientEvent,
27
- ReqOpts,
28
- } from "./jsonRpcHttpClient.js";
29
30
  import {PayloadIdCache} from "./payloadIdCache.js";
30
31
  import {
31
32
  BLOB_AND_PROOF_V2_RPC_BYTES,
@@ -44,7 +45,7 @@ import {
44
45
  serializePayloadAttributes,
45
46
  serializeVersionedHashes,
46
47
  } from "./types.js";
47
- import {bytesToData, getExecutionEngineState, numToQuantity} from "./utils.js";
48
+ import {getExecutionEngineState} from "./utils.js";
48
49
 
49
50
  export type ExecutionEngineModules = {
50
51
  signal: AbortSignal;
@@ -1,4 +1,5 @@
1
1
  import {fromHex, toPrintableUrl} from "@lodestar/utils";
2
+ import {JsonRpcHttpClient} from "../../eth1/provider/jsonRpcHttpClient.js";
2
3
  import {ExecutionEngineDisabled} from "./disabled.js";
3
4
  import {
4
5
  ExecutionEngineHttp,
@@ -7,7 +8,6 @@ import {
7
8
  defaultExecutionEngineHttpOpts,
8
9
  } from "./http.js";
9
10
  import {IExecutionEngine} from "./interface.js";
10
- import {JsonRpcHttpClient} from "./jsonRpcHttpClient.js";
11
11
  import {ExecutionEngineMockBackend, ExecutionEngineMockOpts} from "./mock.js";
12
12
  import {ExecutionEngineMockJsonRpcClient, JsonRpcBackend} from "./utils.js";
13
13
 
@@ -9,9 +9,9 @@ import {
9
9
  import {BlobsBundle, ExecutionPayload, ExecutionRequests, Root, RootHex, Wei, capella} from "@lodestar/types";
10
10
  import {BlobAndProof} from "@lodestar/types/deneb";
11
11
  import {BlobAndProofV2} from "@lodestar/types/fulu";
12
+ import {DATA} from "../../eth1/provider/utils.js";
12
13
  import {PayloadId, PayloadIdCache, WithdrawalV1} from "./payloadIdCache.js";
13
14
  import {ExecutionPayloadBody} from "./types.js";
14
- import {DATA} from "./utils.js";
15
15
 
16
16
  export {PayloadIdCache, type PayloadId, type WithdrawalV1};
17
17
 
@@ -11,6 +11,7 @@ import {
11
11
  import {ExecutionPayload, RootHex, bellatrix, deneb, ssz} from "@lodestar/types";
12
12
  import {fromHex, toRootHex} from "@lodestar/utils";
13
13
  import {ZERO_HASH_HEX} from "../../constants/index.js";
14
+ import {quantityToNum} from "../../eth1/provider/utils.js";
14
15
  import {INTEROP_BLOCK_HASH} from "../../node/utils/interop/state.js";
15
16
  import {kzgCommitmentToVersionedHash} from "../../util/blobs.js";
16
17
  import {kzg} from "../../util/kzg.js";
@@ -28,7 +29,7 @@ import {
28
29
  serializeExecutionPayload,
29
30
  serializeExecutionRequests,
30
31
  } from "./types.js";
31
- import {JsonRpcBackend, quantityToNum} from "./utils.js";
32
+ import {JsonRpcBackend} from "./utils.js";
32
33
 
33
34
  const INTEROP_GAS_LIMIT = 30e6;
34
35
  const PRUNE_PAYLOAD_ID_AFTER_MS = 5000;
@@ -1,7 +1,7 @@
1
1
  import {SLOTS_PER_EPOCH} from "@lodestar/params";
2
2
  import {pruneSetToMax} from "@lodestar/utils";
3
+ import {DATA, QUANTITY} from "../../eth1/provider/utils.js";
3
4
  import {PayloadAttributesRpc} from "./types.js";
4
- import {DATA, QUANTITY} from "./utils.js";
5
5
 
6
6
  // Idealy this only need to be set to the max head reorgs number
7
7
  const MAX_PAYLOAD_IDS = SLOTS_PER_EPOCH;
@@ -23,14 +23,6 @@ import {
23
23
  } from "@lodestar/types";
24
24
  import {BlobAndProof} from "@lodestar/types/deneb";
25
25
  import {BlobAndProofV2} from "@lodestar/types/fulu";
26
- import {
27
- ExecutionPayloadStatus,
28
- ExecutionRequestType,
29
- PayloadAttributes,
30
- VersionedHashes,
31
- isExecutionRequestType,
32
- } from "./interface.js";
33
- import {WithdrawalV1} from "./payloadIdCache.js";
34
26
  import {
35
27
  DATA,
36
28
  QUANTITY,
@@ -40,7 +32,15 @@ import {
40
32
  numToQuantity,
41
33
  quantityToBigint,
42
34
  quantityToNum,
43
- } from "./utils.js";
35
+ } from "../../eth1/provider/utils.js";
36
+ import {
37
+ ExecutionPayloadStatus,
38
+ ExecutionRequestType,
39
+ PayloadAttributes,
40
+ VersionedHashes,
41
+ isExecutionRequestType,
42
+ } from "./interface.js";
43
+ import {WithdrawalV1} from "./payloadIdCache.js";
44
44
 
45
45
  export type EngineApiRpcParamTypes = {
46
46
  /**
@@ -1,120 +1,14 @@
1
- import {bigIntToBytes, bytesToBigInt, fromHex, fromHexInto, isErrorAborted, isFetchError, toHex} from "@lodestar/utils";
2
- import {isQueueErrorAborted} from "../../util/queue/errors.js";
3
- import {ExecutionEngineState, ExecutionPayloadStatus} from "./interface.js";
1
+ import {isErrorAborted, isFetchError} from "@lodestar/utils";
2
+ import {IJson, RpcPayload} from "../../eth1/interface.js";
4
3
  import {
5
4
  ErrorJsonRpcResponse,
6
5
  HttpRpcError,
7
6
  IJsonRpcHttpClient,
8
7
  JsonRpcHttpClientEvent,
9
8
  JsonRpcHttpClientEventEmitter,
10
- } from "./jsonRpcHttpClient.js";
11
-
12
- /** QUANTITY as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API */
13
- export type QUANTITY = string;
14
- /** DATA as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API */
15
- export type DATA = string;
16
-
17
- export const rootHexRegex = /^0x[a-fA-F0-9]{64}$/;
18
-
19
- export type IJson = string | number | boolean | undefined | IJson[] | {[key: string]: IJson};
20
-
21
- export interface RpcPayload<P = IJson[]> {
22
- method: string;
23
- params: P;
24
- }
25
-
26
- /**
27
- * QUANTITY as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API
28
- *
29
- * When encoding QUANTITIES (integers, numbers): encode as hex, prefix with “0x”, the most compact representation (slight exception: zero should be represented as “0x0”). Examples:
30
- * - 0x41 (65 in decimal)
31
- * - 0x400 (1024 in decimal)
32
- * - WRONG: 0x (should always have at least one digit - zero is “0x0”)
33
- * - WRONG: 0x0400 (no leading zeroes allowed)
34
- * - WRONG: ff (must be prefixed 0x)
35
- */
36
- export function numToQuantity(num: number | bigint): QUANTITY {
37
- return "0x" + num.toString(16);
38
- }
39
-
40
- /**
41
- * QUANTITY as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API
42
- */
43
- export function quantityToNum(hex: QUANTITY, id = ""): number {
44
- const num = parseInt(hex, 16);
45
- if (Number.isNaN(num) || num < 0) throw Error(`Invalid hex decimal ${id} '${hex}'`);
46
- return num;
47
- }
48
-
49
- /**
50
- * QUANTITY as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API.
51
- * Typesafe fn to convert hex string to bigint. The BigInt constructor param is any
52
- */
53
- export function quantityToBigint(hex: QUANTITY, id = ""): bigint {
54
- try {
55
- return BigInt(hex);
56
- } catch (e) {
57
- throw Error(`Invalid hex bigint ${id} '${hex}': ${(e as Error).message}`);
58
- }
59
- }
60
-
61
- /**
62
- * QUANTITY as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API.
63
- */
64
- export function quantityToBytes(hex: QUANTITY): Uint8Array {
65
- const bn = quantityToBigint(hex);
66
- return bigIntToBytes(bn, 32, "le");
67
- }
68
-
69
- /**
70
- * QUANTITY as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API.
71
- * Compress a 32 ByteVector into a QUANTITY
72
- */
73
- export function bytesToQuantity(bytes: Uint8Array): QUANTITY {
74
- const bn = bytesToBigInt(bytes, "le");
75
- return numToQuantity(bn);
76
- }
77
-
78
- /**
79
- * DATA as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API
80
- *
81
- * When encoding UNFORMATTED DATA (byte arrays, account addresses, hashes, bytecode arrays): encode as hex, prefix with
82
- * “0x”, two hex digits per byte. Examples:
83
- *
84
- * - 0x41 (size 1, “A”)
85
- * - 0x004200 (size 3, “\0B\0”)
86
- * - 0x (size 0, “”)
87
- * - WRONG: 0xf0f0f (must be even number of digits)
88
- * - WRONG: 004200 (must be prefixed 0x)
89
- */
90
- export function bytesToData(bytes: Uint8Array): DATA {
91
- return toHex(bytes);
92
- }
93
-
94
- /**
95
- * DATA as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API
96
- */
97
- export function dataToBytes(hex: DATA, fixedLength: number | null): Uint8Array {
98
- try {
99
- const bytes = fromHex(hex);
100
- if (fixedLength != null && bytes.length !== fixedLength) {
101
- throw Error(`Wrong data length ${bytes.length} expected ${fixedLength}`);
102
- }
103
- return bytes;
104
- } catch (e) {
105
- (e as Error).message = `Invalid hex string: ${(e as Error).message}`;
106
- throw e;
107
- }
108
- }
109
-
110
- /**
111
- * Convert DATA into a preallocated buffer
112
- * fromHexInto will throw if buffer's length is not the same as the decoded hex length
113
- */
114
- export function dataIntoBytes(hex: DATA, buffer: Uint8Array): Uint8Array {
115
- fromHexInto(hex, buffer);
116
- return buffer;
117
- }
9
+ } from "../../eth1/provider/jsonRpcHttpClient.js";
10
+ import {isQueueErrorAborted} from "../../util/queue/errors.js";
11
+ import {ExecutionEngineState, ExecutionPayloadStatus} from "./interface.js";
118
12
 
119
13
  export type JsonRpcBackend = {
120
14
  // biome-ignore lint/suspicious/noExplicitAny: We need to use `any` type here
package/src/index.ts CHANGED
@@ -2,10 +2,11 @@
2
2
 
3
3
  export type {RestApiServerMetrics, RestApiServerModules, RestApiServerOpts} from "./api/rest/base.js";
4
4
  export {RestApiServer} from "./api/rest/base.js";
5
- export {checkAndPersistAnchorState, initStateFromDb} from "./chain/index.js";
5
+ export {checkAndPersistAnchorState, initStateFromDb, initStateFromEth1} from "./chain/index.js";
6
6
  export {DbCPStateDatastore} from "./chain/stateCache/datastore/db.js";
7
7
  export {FileCPStateDatastore} from "./chain/stateCache/datastore/file.js";
8
8
  export {BeaconDb, type IBeaconDb} from "./db/index.js";
9
+ export {Eth1Provider, type IEth1Provider} from "./eth1/index.js";
9
10
  // Export metrics utilities to de-duplicate validator metrics
10
11
  export {
11
12
  type HttpMetricsServer,
@@ -1619,6 +1619,98 @@ export function createLodestarMetrics(
1619
1619
  }),
1620
1620
  },
1621
1621
 
1622
+ eth1: {
1623
+ depositTrackerIsCaughtup: register.gauge({
1624
+ name: "lodestar_eth1_deposit_tracker_is_caughtup",
1625
+ help: "Eth1 deposit is caught up 0=false 1=true",
1626
+ }),
1627
+ depositTrackerUpdateErrors: register.gauge({
1628
+ name: "lodestar_eth1_deposit_tracker_update_errors_total",
1629
+ help: "Eth1 deposit update loop errors total",
1630
+ }),
1631
+ remoteHighestBlock: register.gauge({
1632
+ name: "lodestar_eth1_remote_highest_block",
1633
+ help: "Eth1 current highest block number",
1634
+ }),
1635
+ depositEventsFetched: register.gauge({
1636
+ name: "lodestar_eth1_deposit_events_fetched_total",
1637
+ help: "Eth1 deposit events fetched total",
1638
+ }),
1639
+ lastProcessedDepositBlockNumber: register.gauge({
1640
+ name: "lodestar_eth1_last_processed_deposit_block_number",
1641
+ help: "Eth1 deposit tracker lastProcessedDepositBlockNumber",
1642
+ }),
1643
+ blocksFetched: register.gauge({
1644
+ name: "lodestar_eth1_blocks_fetched_total",
1645
+ help: "Eth1 blocks fetched total",
1646
+ }),
1647
+ lastFetchedBlockBlockNumber: register.gauge({
1648
+ name: "lodestar_eth1_last_fetched_block_block_number",
1649
+ help: "Eth1 deposit tracker last fetched block's block number",
1650
+ }),
1651
+ lastFetchedBlockTimestamp: register.gauge({
1652
+ name: "lodestar_eth1_last_fetched_block_timestamp",
1653
+ help: "Eth1 deposit tracker last fetched block's timestamp",
1654
+ }),
1655
+ eth1FollowDistanceSecondsConfig: register.gauge({
1656
+ name: "lodestar_eth1_follow_distance_seconds_config",
1657
+ help: "Constant with value = SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE",
1658
+ }),
1659
+ eth1FollowDistanceDynamic: register.gauge({
1660
+ name: "lodestar_eth1_follow_distance_dynamic",
1661
+ help: "Eth1 dynamic follow distance changed by the deposit tracker if blocks are slow",
1662
+ }),
1663
+ eth1GetBlocksBatchSizeDynamic: register.gauge({
1664
+ name: "lodestar_eth1_blocks_batch_size_dynamic",
1665
+ help: "Dynamic batch size to fetch blocks",
1666
+ }),
1667
+ eth1GetLogsBatchSizeDynamic: register.gauge({
1668
+ name: "lodestar_eth1_logs_batch_size_dynamic",
1669
+ help: "Dynamic batch size to fetch deposit logs",
1670
+ }),
1671
+ },
1672
+
1673
+ eth1HttpClient: {
1674
+ requestTime: register.histogram<{routeId: string}>({
1675
+ name: "lodestar_eth1_http_client_request_time_seconds",
1676
+ help: "eth1 JsonHttpClient - histogram or roundtrip request times",
1677
+ labelNames: ["routeId"],
1678
+ // Provide max resolution on problematic values around 1 second
1679
+ buckets: [0.1, 0.5, 1, 2, 5, 15],
1680
+ }),
1681
+ streamTime: register.histogram<{routeId: string}>({
1682
+ name: "lodestar_eth1_http_client_stream_time_seconds",
1683
+ help: "eth1 JsonHttpClient - streaming time by routeId",
1684
+ labelNames: ["routeId"],
1685
+ // Provide max resolution on problematic values around 1 second
1686
+ buckets: [0.1, 0.5, 1, 2, 5, 15],
1687
+ }),
1688
+ requestErrors: register.gauge<{routeId: string}>({
1689
+ name: "lodestar_eth1_http_client_request_errors_total",
1690
+ help: "eth1 JsonHttpClient - total count of request errors",
1691
+ labelNames: ["routeId"],
1692
+ }),
1693
+ retryCount: register.gauge<{routeId: string}>({
1694
+ name: "lodestar_eth1_http_client_request_retries_total",
1695
+ help: "eth1 JsonHttpClient - total count of request retries",
1696
+ labelNames: ["routeId"],
1697
+ }),
1698
+ requestUsedFallbackUrl: register.gauge<{routeId: string}>({
1699
+ name: "lodestar_eth1_http_client_request_used_fallback_url_total",
1700
+ help: "eth1 JsonHttpClient - total count of requests on fallback url(s)",
1701
+ labelNames: ["routeId"],
1702
+ }),
1703
+ activeRequests: register.gauge<{routeId: string}>({
1704
+ name: "lodestar_eth1_http_client_active_requests",
1705
+ help: "eth1 JsonHttpClient - current count of active requests",
1706
+ labelNames: ["routeId"],
1707
+ }),
1708
+ configUrlsCount: register.gauge({
1709
+ name: "lodestar_eth1_http_client_config_urls_count",
1710
+ help: "eth1 JsonHttpClient - static config urls count",
1711
+ }),
1712
+ },
1713
+
1622
1714
  executionEnginerHttpClient: {
1623
1715
  requestTime: register.histogram<{routeId: string}>({
1624
1716
  name: "lodestar_execution_engine_http_client_request_time_seconds",