@lodestar/beacon-node 1.38.0-dev.bc1fed4d3d → 1.38.0-dev.ebc352f211

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 (150) hide show
  1. package/README.md +1 -1
  2. package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
  3. package/lib/api/impl/beacon/state/index.js +4 -5
  4. package/lib/api/impl/beacon/state/index.js.map +1 -1
  5. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  6. package/lib/api/impl/beacon/state/utils.js +5 -3
  7. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  8. package/lib/api/impl/validator/index.js +1 -1
  9. package/lib/api/impl/validator/index.js.map +1 -1
  10. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  11. package/lib/chain/blocks/verifyBlock.js +1 -21
  12. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  13. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +1 -6
  14. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  15. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +10 -131
  16. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  17. package/lib/chain/blocks/verifyBlocksSignatures.d.ts +2 -2
  18. package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
  19. package/lib/chain/blocks/verifyBlocksSignatures.js +2 -2
  20. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  21. package/lib/chain/chain.d.ts.map +1 -1
  22. package/lib/chain/chain.js +4 -14
  23. package/lib/chain/chain.js.map +1 -1
  24. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  25. package/lib/chain/forkChoice/index.js +3 -3
  26. package/lib/chain/forkChoice/index.js.map +1 -1
  27. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  28. package/lib/chain/opPools/aggregatedAttestationPool.js +3 -1
  29. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  30. package/lib/chain/options.d.ts +0 -4
  31. package/lib/chain/options.d.ts.map +1 -1
  32. package/lib/chain/options.js +0 -2
  33. package/lib/chain/options.js.map +1 -1
  34. package/lib/chain/prepareNextSlot.js +1 -1
  35. package/lib/chain/prepareNextSlot.js.map +1 -1
  36. package/lib/chain/produceBlock/produceBlockBody.d.ts +2 -21
  37. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  38. package/lib/chain/produceBlock/produceBlockBody.js +24 -87
  39. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  40. package/lib/chain/rewards/attestationsRewards.d.ts +3 -3
  41. package/lib/chain/rewards/attestationsRewards.d.ts.map +1 -1
  42. package/lib/chain/rewards/attestationsRewards.js +4 -4
  43. package/lib/chain/rewards/attestationsRewards.js.map +1 -1
  44. package/lib/chain/rewards/syncCommitteeRewards.d.ts +2 -2
  45. package/lib/chain/rewards/syncCommitteeRewards.d.ts.map +1 -1
  46. package/lib/chain/rewards/syncCommitteeRewards.js +1 -2
  47. package/lib/chain/rewards/syncCommitteeRewards.js.map +1 -1
  48. package/lib/chain/validation/attesterSlashing.js +2 -2
  49. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  50. package/lib/chain/validation/blobSidecar.d.ts.map +1 -1
  51. package/lib/chain/validation/blobSidecar.js +2 -2
  52. package/lib/chain/validation/blobSidecar.js.map +1 -1
  53. package/lib/chain/validation/block.d.ts.map +1 -1
  54. package/lib/chain/validation/block.js +3 -3
  55. package/lib/chain/validation/block.js.map +1 -1
  56. package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
  57. package/lib/chain/validation/dataColumnSidecar.js +2 -2
  58. package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
  59. package/lib/chain/validation/proposerSlashing.js +1 -1
  60. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  61. package/lib/chain/validation/signatureSets/contributionAndProof.d.ts +2 -2
  62. package/lib/chain/validation/signatureSets/contributionAndProof.d.ts.map +1 -1
  63. package/lib/chain/validation/signatureSets/contributionAndProof.js +2 -3
  64. package/lib/chain/validation/signatureSets/contributionAndProof.js.map +1 -1
  65. package/lib/chain/validation/signatureSets/syncCommittee.d.ts +2 -2
  66. package/lib/chain/validation/signatureSets/syncCommittee.d.ts.map +1 -1
  67. package/lib/chain/validation/signatureSets/syncCommittee.js +2 -2
  68. package/lib/chain/validation/signatureSets/syncCommittee.js.map +1 -1
  69. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts +2 -2
  70. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts.map +1 -1
  71. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js +3 -3
  72. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js.map +1 -1
  73. package/lib/chain/validation/syncCommittee.js +1 -1
  74. package/lib/chain/validation/syncCommittee.js.map +1 -1
  75. package/lib/chain/validation/syncCommitteeContributionAndProof.d.ts.map +1 -1
  76. package/lib/chain/validation/syncCommitteeContributionAndProof.js +4 -3
  77. package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
  78. package/lib/chain/validation/voluntaryExit.js +1 -1
  79. package/lib/chain/validation/voluntaryExit.js.map +1 -1
  80. package/lib/eth1/index.d.ts +2 -17
  81. package/lib/eth1/index.d.ts.map +1 -1
  82. package/lib/eth1/index.js +0 -50
  83. package/lib/eth1/index.js.map +1 -1
  84. package/lib/eth1/interface.d.ts +1 -39
  85. package/lib/eth1/interface.d.ts.map +1 -1
  86. package/lib/execution/engine/http.d.ts +4 -12
  87. package/lib/execution/engine/http.d.ts.map +1 -1
  88. package/lib/execution/engine/http.js +4 -12
  89. package/lib/execution/engine/http.js.map +1 -1
  90. package/lib/execution/engine/mock.d.ts +2 -6
  91. package/lib/execution/engine/mock.d.ts.map +1 -1
  92. package/lib/execution/engine/mock.js +3 -14
  93. package/lib/execution/engine/mock.js.map +1 -1
  94. package/lib/metrics/metrics/lodestar.d.ts +0 -14
  95. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  96. package/lib/metrics/metrics/lodestar.js +0 -44
  97. package/lib/metrics/metrics/lodestar.js.map +1 -1
  98. package/lib/network/gossip/encoding.d.ts.map +1 -1
  99. package/lib/network/gossip/encoding.js +17 -7
  100. package/lib/network/gossip/encoding.js.map +1 -1
  101. package/lib/node/notifier.d.ts.map +1 -1
  102. package/lib/node/notifier.js +6 -22
  103. package/lib/node/notifier.js.map +1 -1
  104. package/lib/sync/backfill/backfill.d.ts.map +1 -1
  105. package/lib/sync/backfill/backfill.js +4 -2
  106. package/lib/sync/backfill/backfill.js.map +1 -1
  107. package/lib/sync/backfill/verify.d.ts +2 -2
  108. package/lib/sync/backfill/verify.d.ts.map +1 -1
  109. package/lib/sync/backfill/verify.js +3 -3
  110. package/lib/sync/backfill/verify.js.map +1 -1
  111. package/package.json +15 -16
  112. package/src/api/impl/beacon/state/index.ts +4 -5
  113. package/src/api/impl/beacon/state/utils.ts +5 -3
  114. package/src/api/impl/validator/index.ts +1 -1
  115. package/src/chain/blocks/verifyBlock.ts +2 -24
  116. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +11 -170
  117. package/src/chain/blocks/verifyBlocksSignatures.ts +3 -2
  118. package/src/chain/chain.ts +4 -15
  119. package/src/chain/forkChoice/index.ts +2 -3
  120. package/src/chain/opPools/aggregatedAttestationPool.ts +5 -1
  121. package/src/chain/options.ts +0 -6
  122. package/src/chain/prepareNextSlot.ts +1 -1
  123. package/src/chain/produceBlock/produceBlockBody.ts +25 -120
  124. package/src/chain/rewards/attestationsRewards.ts +6 -5
  125. package/src/chain/rewards/syncCommitteeRewards.ts +2 -2
  126. package/src/chain/validation/attesterSlashing.ts +2 -2
  127. package/src/chain/validation/blobSidecar.ts +10 -2
  128. package/src/chain/validation/block.ts +2 -3
  129. package/src/chain/validation/dataColumnSidecar.ts +6 -1
  130. package/src/chain/validation/proposerSlashing.ts +1 -1
  131. package/src/chain/validation/signatureSets/contributionAndProof.ts +3 -2
  132. package/src/chain/validation/signatureSets/syncCommittee.ts +3 -1
  133. package/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts +4 -2
  134. package/src/chain/validation/syncCommittee.ts +1 -1
  135. package/src/chain/validation/syncCommitteeContributionAndProof.ts +4 -5
  136. package/src/chain/validation/voluntaryExit.ts +1 -1
  137. package/src/eth1/index.ts +2 -65
  138. package/src/eth1/interface.ts +1 -45
  139. package/src/execution/engine/http.ts +4 -12
  140. package/src/execution/engine/mock.ts +3 -15
  141. package/src/metrics/metrics/lodestar.ts +0 -52
  142. package/src/network/gossip/encoding.ts +19 -7
  143. package/src/node/notifier.ts +7 -29
  144. package/src/sync/backfill/backfill.ts +9 -2
  145. package/src/sync/backfill/verify.ts +8 -2
  146. package/lib/eth1/eth1MergeBlockTracker.d.ts +0 -65
  147. package/lib/eth1/eth1MergeBlockTracker.d.ts.map +0 -1
  148. package/lib/eth1/eth1MergeBlockTracker.js +0 -262
  149. package/lib/eth1/eth1MergeBlockTracker.js.map +0 -1
  150. package/src/eth1/eth1MergeBlockTracker.ts +0 -328
@@ -1,262 +0,0 @@
1
- import { pruneSetToMax, toRootHex } from "@lodestar/utils";
2
- import { ZERO_HASH_HEX } from "../constants/index.js";
3
- import { enumToIndexMap } from "../util/enum.js";
4
- import { dataToRootHex, quantityToBigint, quantityToNum } from "./provider/utils.js";
5
- export var StatusCode;
6
- (function (StatusCode) {
7
- StatusCode["STOPPED"] = "STOPPED";
8
- StatusCode["SEARCHING"] = "SEARCHING";
9
- StatusCode["FOUND"] = "FOUND";
10
- })(StatusCode || (StatusCode = {}));
11
- /** For metrics, index order = declaration order of StatusCode */
12
- const statusCodeIdx = enumToIndexMap(StatusCode);
13
- /**
14
- * Bounds `blocksByHashCache` cache, imposing a max distance between highest and lowest block numbers.
15
- * In case of extreme forking the cache might grow unbounded.
16
- */
17
- const MAX_CACHE_POW_BLOCKS = 1024;
18
- const MAX_TD_RENDER_VALUE = Number.MAX_SAFE_INTEGER;
19
- // get_pow_block_at_total_difficulty
20
- /**
21
- * Follows the eth1 chain to find a (or multiple?) merge blocks that cross the threshold of total terminal difficulty
22
- *
23
- * Finding the mergeBlock could be done in demand when proposing pre-merge blocks. However, that would slow block
24
- * production during the weeks between BELLATRIX_EPOCH and TTD.
25
- */
26
- export class Eth1MergeBlockTracker {
27
- eth1Provider;
28
- config;
29
- logger;
30
- metrics;
31
- blocksByHashCache = new Map();
32
- intervals = [];
33
- status;
34
- latestEth1Block = null;
35
- getTerminalPowBlockFromEth1Promise = null;
36
- safeTDFactor;
37
- constructor({ config, logger, signal, metrics }, eth1Provider) {
38
- this.eth1Provider = eth1Provider;
39
- this.config = config;
40
- this.logger = logger;
41
- this.metrics = metrics;
42
- this.status = { code: StatusCode.STOPPED };
43
- signal.addEventListener("abort", () => this.close(), { once: true });
44
- this.safeTDFactor = getSafeTDFactor(this.config.TERMINAL_TOTAL_DIFFICULTY);
45
- const scaledTTD = this.config.TERMINAL_TOTAL_DIFFICULTY / this.safeTDFactor;
46
- // Only run metrics if necessary
47
- if (metrics) {
48
- // TTD can't be dynamically changed during execution, register metric once
49
- metrics.eth1.eth1MergeTTD.set(Number(scaledTTD));
50
- metrics.eth1.eth1MergeTDFactor.set(Number(this.safeTDFactor));
51
- metrics.eth1.eth1MergeStatus.addCollect(() => {
52
- // Set merge ttd, merge status and merge block status
53
- metrics.eth1.eth1MergeStatus.set(statusCodeIdx[this.status.code]);
54
- if (this.latestEth1Block !== null) {
55
- // Set latestBlock stats
56
- metrics.eth1.eth1LatestBlockNumber.set(this.latestEth1Block.number);
57
- metrics.eth1.eth1LatestBlockTD.set(Number(this.latestEth1Block.totalDifficulty / this.safeTDFactor));
58
- metrics.eth1.eth1LatestBlockTimestamp.set(this.latestEth1Block.timestamp);
59
- }
60
- });
61
- }
62
- }
63
- /**
64
- * Returns the most recent POW block that satisfies the merge block condition
65
- */
66
- async getTerminalPowBlock() {
67
- switch (this.status.code) {
68
- case StatusCode.STOPPED:
69
- // If not module is not polling fetch the mergeBlock explicitly
70
- return this.getTerminalPowBlockFromEth1();
71
- case StatusCode.SEARCHING:
72
- // Assume that polling would have found the block
73
- return null;
74
- case StatusCode.FOUND:
75
- return this.status.mergeBlock;
76
- }
77
- }
78
- getTDProgress() {
79
- if (this.latestEth1Block === null) {
80
- return this.latestEth1Block;
81
- }
82
- const tdDiff = this.config.TERMINAL_TOTAL_DIFFICULTY - this.latestEth1Block.totalDifficulty;
83
- if (tdDiff > BigInt(0)) {
84
- return {
85
- ttdHit: false,
86
- tdFactor: this.safeTDFactor,
87
- tdDiffScaled: Number((tdDiff / this.safeTDFactor)),
88
- ttd: this.config.TERMINAL_TOTAL_DIFFICULTY,
89
- td: this.latestEth1Block.totalDifficulty,
90
- timestamp: this.latestEth1Block.timestamp,
91
- };
92
- }
93
- return {
94
- ttdHit: true,
95
- };
96
- }
97
- /**
98
- * Get a POW block by hash checking the local cache first
99
- */
100
- async getPowBlock(powBlockHash) {
101
- // Check cache first
102
- const cachedBlock = this.blocksByHashCache.get(powBlockHash);
103
- if (cachedBlock) {
104
- return cachedBlock;
105
- }
106
- // Fetch from node
107
- const blockRaw = await this.eth1Provider.getBlockByHash(powBlockHash);
108
- if (blockRaw) {
109
- const block = toPowBlock(blockRaw);
110
- this.cacheBlock(block);
111
- return block;
112
- }
113
- return null;
114
- }
115
- /**
116
- * Should only start polling for mergeBlock if:
117
- * - after BELLATRIX_FORK_EPOCH
118
- * - Beacon node synced
119
- * - head state not isMergeTransitionComplete
120
- */
121
- startPollingMergeBlock() {
122
- if (this.status.code !== StatusCode.STOPPED) {
123
- return;
124
- }
125
- this.status = { code: StatusCode.SEARCHING };
126
- this.logger.info("Starting search for terminal POW block", {
127
- TERMINAL_TOTAL_DIFFICULTY: this.config.TERMINAL_TOTAL_DIFFICULTY,
128
- });
129
- const interval = setInterval(() => {
130
- // Preemptively try to find merge block and cache it if found.
131
- // Future callers of getTerminalPowBlock() will re-use the cached found mergeBlock.
132
- this.getTerminalPowBlockFromEth1().catch((e) => {
133
- this.logger.error("Error on findMergeBlock", {}, e);
134
- this.metrics?.eth1.eth1PollMergeBlockErrors.inc();
135
- });
136
- }, this.config.SECONDS_PER_ETH1_BLOCK * 1000);
137
- this.intervals.push(interval);
138
- }
139
- close() {
140
- this.intervals.forEach(clearInterval);
141
- }
142
- async getTerminalPowBlockFromEth1() {
143
- if (!this.getTerminalPowBlockFromEth1Promise) {
144
- this.getTerminalPowBlockFromEth1Promise = this.internalGetTerminalPowBlockFromEth1()
145
- .then((mergeBlock) => {
146
- // Persist found merge block here to affect both caller paths:
147
- // - internal searcher
148
- // - external caller if STOPPED
149
- if (mergeBlock && this.status.code !== StatusCode.FOUND) {
150
- if (this.status.code === StatusCode.SEARCHING) {
151
- this.close();
152
- }
153
- this.logger.info("Terminal POW block found!", {
154
- hash: mergeBlock.blockHash,
155
- number: mergeBlock.number,
156
- totalDifficulty: mergeBlock.totalDifficulty,
157
- });
158
- this.status = { code: StatusCode.FOUND, mergeBlock };
159
- this.metrics?.eth1.eth1MergeBlockDetails.set({
160
- terminalBlockHash: mergeBlock.blockHash,
161
- // Convert all number/bigints to string labels
162
- terminalBlockNumber: mergeBlock.number.toString(10),
163
- terminalBlockTD: mergeBlock.totalDifficulty.toString(10),
164
- }, 1);
165
- }
166
- return mergeBlock;
167
- })
168
- .finally(() => {
169
- this.getTerminalPowBlockFromEth1Promise = null;
170
- });
171
- }
172
- else {
173
- // This should no happen, since getTerminalPowBlockFromEth1() should resolve faster than SECONDS_PER_ETH1_BLOCK.
174
- // else something is wrong: the el-cl comms are two slow, or the backsearch got stuck in a deep search.
175
- this.metrics?.eth1.getTerminalPowBlockPromiseCacheHit.inc();
176
- }
177
- return this.getTerminalPowBlockFromEth1Promise;
178
- }
179
- /**
180
- * **internal** + **unsafe** since it can create multiple backward searches that overload the eth1 client.
181
- * Must be called in a wrapper to ensure that there's only once concurrent call to this fn.
182
- */
183
- async internalGetTerminalPowBlockFromEth1() {
184
- // Search merge block by hash
185
- // Terminal block hash override takes precedence over terminal total difficulty
186
- const terminalBlockHash = toRootHex(this.config.TERMINAL_BLOCK_HASH);
187
- if (terminalBlockHash !== ZERO_HASH_HEX) {
188
- const block = await this.getPowBlock(terminalBlockHash);
189
- if (block) {
190
- return block;
191
- }
192
- // if a TERMINAL_BLOCK_HASH other than ZERO_HASH is configured and we can't find it, return NONE
193
- return null;
194
- }
195
- // Search merge block by TTD
196
- const latestBlockRaw = await this.eth1Provider.getBlockByNumber("latest");
197
- if (!latestBlockRaw) {
198
- throw Error("getBlockByNumber('latest') returned null");
199
- }
200
- let block = toPowBlock(latestBlockRaw);
201
- this.latestEth1Block = { ...block, timestamp: quantityToNum(latestBlockRaw.timestamp) };
202
- this.cacheBlock(block);
203
- // This code path to look backwards for the merge block is only necessary if:
204
- // - The network has not yet found the merge block
205
- // - There are descendants of the merge block in the eth1 chain
206
- // For the search below to require more than a few hops, multiple block proposers in a row must fail to detect
207
- // an existing merge block. Such situation is extremely unlikely, so this search is left un-optimized. Since
208
- // this class can start eagerly looking for the merge block when not necessary, startPollingMergeBlock() should
209
- // only be called when there is certainty that a mergeBlock search is necessary.
210
- while (true) {
211
- if (block.totalDifficulty < this.config.TERMINAL_TOTAL_DIFFICULTY) {
212
- // TTD not reached yet
213
- return null;
214
- }
215
- // else block.totalDifficulty >= this.config.TERMINAL_TOTAL_DIFFICULTY
216
- // Potential mergeBlock! Must find the first block that passes TTD
217
- // Allow genesis block to reach TTD https://github.com/ethereum/consensus-specs/pull/2719
218
- if (block.parentHash === ZERO_HASH_HEX) {
219
- return block;
220
- }
221
- const parent = await this.getPowBlock(block.parentHash);
222
- if (!parent) {
223
- throw Error(`Unknown parent of block with TD>TTD ${block.parentHash}`);
224
- }
225
- this.metrics?.eth1.eth1ParentBlocksFetched.inc();
226
- // block.td > TTD && parent.td < TTD => block is mergeBlock
227
- if (parent.totalDifficulty < this.config.TERMINAL_TOTAL_DIFFICULTY) {
228
- // Is terminal total difficulty block AND has verified block -> parent relationship
229
- return block;
230
- }
231
- block = parent;
232
- }
233
- }
234
- cacheBlock(block) {
235
- this.blocksByHashCache.set(block.blockHash, block);
236
- pruneSetToMax(this.blocksByHashCache, MAX_CACHE_POW_BLOCKS);
237
- }
238
- }
239
- export function toPowBlock(block) {
240
- // Validate untrusted data from API
241
- return {
242
- number: quantityToNum(block.number),
243
- blockHash: dataToRootHex(block.hash),
244
- parentHash: dataToRootHex(block.parentHash),
245
- totalDifficulty: quantityToBigint(block.totalDifficulty),
246
- };
247
- }
248
- /**
249
- * TTD values can be very large, for xDAI > 1e45. So scale down.
250
- * To be good, TTD should be rendered as a number < Number.MAX_TD_RENDER_VALUE ~= 9e15
251
- */
252
- export function getSafeTDFactor(ttd) {
253
- const safeIntegerMult = ttd / BigInt(MAX_TD_RENDER_VALUE);
254
- // TTD < MAX_TD_RENDER_VALUE, no need to scale down
255
- if (safeIntegerMult === BigInt(0)) {
256
- return BigInt(1);
257
- }
258
- // Return closest power of 10 to ensure TD < max
259
- const safeIntegerMultDigits = safeIntegerMult.toString(10).length;
260
- return BigInt(10) ** BigInt(safeIntegerMultDigits);
261
- }
262
- //# sourceMappingURL=eth1MergeBlockTracker.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"eth1MergeBlockTracker.js","sourceRoot":"","sources":["../../src/eth1/eth1MergeBlockTracker.ts"],"names":[],"mappings":"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"}
@@ -1,328 +0,0 @@
1
- import {ChainConfig} from "@lodestar/config";
2
- import {RootHex} from "@lodestar/types";
3
- import {Logger, pruneSetToMax, toRootHex} from "@lodestar/utils";
4
- import {ZERO_HASH_HEX} from "../constants/index.js";
5
- import {Metrics} from "../metrics/index.js";
6
- import {enumToIndexMap} from "../util/enum.js";
7
- import {EthJsonRpcBlockRaw, IEth1Provider, PowMergeBlock, PowMergeBlockTimestamp, TDProgress} from "./interface.js";
8
- import {dataToRootHex, quantityToBigint, quantityToNum} from "./provider/utils.js";
9
-
10
- export enum StatusCode {
11
- STOPPED = "STOPPED",
12
- SEARCHING = "SEARCHING",
13
- FOUND = "FOUND",
14
- }
15
-
16
- type Status =
17
- | {code: StatusCode.STOPPED}
18
- | {code: StatusCode.SEARCHING}
19
- | {code: StatusCode.FOUND; mergeBlock: PowMergeBlock};
20
-
21
- /** For metrics, index order = declaration order of StatusCode */
22
- const statusCodeIdx = enumToIndexMap(StatusCode);
23
-
24
- /**
25
- * Bounds `blocksByHashCache` cache, imposing a max distance between highest and lowest block numbers.
26
- * In case of extreme forking the cache might grow unbounded.
27
- */
28
- const MAX_CACHE_POW_BLOCKS = 1024;
29
-
30
- const MAX_TD_RENDER_VALUE = Number.MAX_SAFE_INTEGER;
31
-
32
- export type Eth1MergeBlockTrackerModules = {
33
- config: ChainConfig;
34
- logger: Logger;
35
- signal: AbortSignal;
36
- metrics: Metrics | null;
37
- };
38
-
39
- // get_pow_block_at_total_difficulty
40
-
41
- /**
42
- * Follows the eth1 chain to find a (or multiple?) merge blocks that cross the threshold of total terminal difficulty
43
- *
44
- * Finding the mergeBlock could be done in demand when proposing pre-merge blocks. However, that would slow block
45
- * production during the weeks between BELLATRIX_EPOCH and TTD.
46
- */
47
- export class Eth1MergeBlockTracker {
48
- private readonly config: ChainConfig;
49
- private readonly logger: Logger;
50
- private readonly metrics: Metrics | null;
51
-
52
- private readonly blocksByHashCache = new Map<RootHex, PowMergeBlock>();
53
- private readonly intervals: NodeJS.Timeout[] = [];
54
-
55
- private status: Status;
56
- private latestEth1Block: PowMergeBlockTimestamp | null = null;
57
- private getTerminalPowBlockFromEth1Promise: Promise<PowMergeBlock | null> | null = null;
58
- private readonly safeTDFactor: bigint;
59
-
60
- constructor(
61
- {config, logger, signal, metrics}: Eth1MergeBlockTrackerModules,
62
- private readonly eth1Provider: IEth1Provider
63
- ) {
64
- this.config = config;
65
- this.logger = logger;
66
- this.metrics = metrics;
67
-
68
- this.status = {code: StatusCode.STOPPED};
69
-
70
- signal.addEventListener("abort", () => this.close(), {once: true});
71
-
72
- this.safeTDFactor = getSafeTDFactor(this.config.TERMINAL_TOTAL_DIFFICULTY);
73
- const scaledTTD = this.config.TERMINAL_TOTAL_DIFFICULTY / this.safeTDFactor;
74
-
75
- // Only run metrics if necessary
76
- if (metrics) {
77
- // TTD can't be dynamically changed during execution, register metric once
78
- metrics.eth1.eth1MergeTTD.set(Number(scaledTTD as bigint));
79
- metrics.eth1.eth1MergeTDFactor.set(Number(this.safeTDFactor as bigint));
80
-
81
- metrics.eth1.eth1MergeStatus.addCollect(() => {
82
- // Set merge ttd, merge status and merge block status
83
- metrics.eth1.eth1MergeStatus.set(statusCodeIdx[this.status.code]);
84
-
85
- if (this.latestEth1Block !== null) {
86
- // Set latestBlock stats
87
- metrics.eth1.eth1LatestBlockNumber.set(this.latestEth1Block.number);
88
- metrics.eth1.eth1LatestBlockTD.set(Number(this.latestEth1Block.totalDifficulty / this.safeTDFactor));
89
- metrics.eth1.eth1LatestBlockTimestamp.set(this.latestEth1Block.timestamp);
90
- }
91
- });
92
- }
93
- }
94
-
95
- /**
96
- * Returns the most recent POW block that satisfies the merge block condition
97
- */
98
- async getTerminalPowBlock(): Promise<PowMergeBlock | null> {
99
- switch (this.status.code) {
100
- case StatusCode.STOPPED:
101
- // If not module is not polling fetch the mergeBlock explicitly
102
- return this.getTerminalPowBlockFromEth1();
103
-
104
- case StatusCode.SEARCHING:
105
- // Assume that polling would have found the block
106
- return null;
107
-
108
- case StatusCode.FOUND:
109
- return this.status.mergeBlock;
110
- }
111
- }
112
-
113
- getTDProgress(): TDProgress | null {
114
- if (this.latestEth1Block === null) {
115
- return this.latestEth1Block;
116
- }
117
-
118
- const tdDiff = this.config.TERMINAL_TOTAL_DIFFICULTY - this.latestEth1Block.totalDifficulty;
119
-
120
- if (tdDiff > BigInt(0)) {
121
- return {
122
- ttdHit: false,
123
- tdFactor: this.safeTDFactor,
124
- tdDiffScaled: Number((tdDiff / this.safeTDFactor) as bigint),
125
- ttd: this.config.TERMINAL_TOTAL_DIFFICULTY,
126
- td: this.latestEth1Block.totalDifficulty,
127
- timestamp: this.latestEth1Block.timestamp,
128
- };
129
- }
130
- return {
131
- ttdHit: true,
132
- };
133
- }
134
-
135
- /**
136
- * Get a POW block by hash checking the local cache first
137
- */
138
- async getPowBlock(powBlockHash: string): Promise<PowMergeBlock | null> {
139
- // Check cache first
140
- const cachedBlock = this.blocksByHashCache.get(powBlockHash);
141
- if (cachedBlock) {
142
- return cachedBlock;
143
- }
144
-
145
- // Fetch from node
146
- const blockRaw = await this.eth1Provider.getBlockByHash(powBlockHash);
147
- if (blockRaw) {
148
- const block = toPowBlock(blockRaw);
149
- this.cacheBlock(block);
150
- return block;
151
- }
152
-
153
- return null;
154
- }
155
-
156
- /**
157
- * Should only start polling for mergeBlock if:
158
- * - after BELLATRIX_FORK_EPOCH
159
- * - Beacon node synced
160
- * - head state not isMergeTransitionComplete
161
- */
162
- startPollingMergeBlock(): void {
163
- if (this.status.code !== StatusCode.STOPPED) {
164
- return;
165
- }
166
-
167
- this.status = {code: StatusCode.SEARCHING};
168
- this.logger.info("Starting search for terminal POW block", {
169
- TERMINAL_TOTAL_DIFFICULTY: this.config.TERMINAL_TOTAL_DIFFICULTY,
170
- });
171
-
172
- const interval = setInterval(() => {
173
- // Preemptively try to find merge block and cache it if found.
174
- // Future callers of getTerminalPowBlock() will re-use the cached found mergeBlock.
175
- this.getTerminalPowBlockFromEth1().catch((e) => {
176
- this.logger.error("Error on findMergeBlock", {}, e as Error);
177
- this.metrics?.eth1.eth1PollMergeBlockErrors.inc();
178
- });
179
- }, this.config.SECONDS_PER_ETH1_BLOCK * 1000);
180
-
181
- this.intervals.push(interval);
182
- }
183
-
184
- private close(): void {
185
- this.intervals.forEach(clearInterval);
186
- }
187
-
188
- private async getTerminalPowBlockFromEth1(): Promise<PowMergeBlock | null> {
189
- if (!this.getTerminalPowBlockFromEth1Promise) {
190
- this.getTerminalPowBlockFromEth1Promise = this.internalGetTerminalPowBlockFromEth1()
191
- .then((mergeBlock) => {
192
- // Persist found merge block here to affect both caller paths:
193
- // - internal searcher
194
- // - external caller if STOPPED
195
- if (mergeBlock && this.status.code !== StatusCode.FOUND) {
196
- if (this.status.code === StatusCode.SEARCHING) {
197
- this.close();
198
- }
199
-
200
- this.logger.info("Terminal POW block found!", {
201
- hash: mergeBlock.blockHash,
202
- number: mergeBlock.number,
203
- totalDifficulty: mergeBlock.totalDifficulty,
204
- });
205
-
206
- this.status = {code: StatusCode.FOUND, mergeBlock};
207
- this.metrics?.eth1.eth1MergeBlockDetails.set(
208
- {
209
- terminalBlockHash: mergeBlock.blockHash,
210
- // Convert all number/bigints to string labels
211
- terminalBlockNumber: mergeBlock.number.toString(10),
212
- terminalBlockTD: mergeBlock.totalDifficulty.toString(10),
213
- },
214
- 1
215
- );
216
- }
217
-
218
- return mergeBlock;
219
- })
220
- .finally(() => {
221
- this.getTerminalPowBlockFromEth1Promise = null;
222
- });
223
- } else {
224
- // This should no happen, since getTerminalPowBlockFromEth1() should resolve faster than SECONDS_PER_ETH1_BLOCK.
225
- // else something is wrong: the el-cl comms are two slow, or the backsearch got stuck in a deep search.
226
- this.metrics?.eth1.getTerminalPowBlockPromiseCacheHit.inc();
227
- }
228
-
229
- return this.getTerminalPowBlockFromEth1Promise;
230
- }
231
-
232
- /**
233
- * **internal** + **unsafe** since it can create multiple backward searches that overload the eth1 client.
234
- * Must be called in a wrapper to ensure that there's only once concurrent call to this fn.
235
- */
236
- private async internalGetTerminalPowBlockFromEth1(): Promise<PowMergeBlock | null> {
237
- // Search merge block by hash
238
- // Terminal block hash override takes precedence over terminal total difficulty
239
- const terminalBlockHash = toRootHex(this.config.TERMINAL_BLOCK_HASH);
240
- if (terminalBlockHash !== ZERO_HASH_HEX) {
241
- const block = await this.getPowBlock(terminalBlockHash);
242
- if (block) {
243
- return block;
244
- }
245
- // if a TERMINAL_BLOCK_HASH other than ZERO_HASH is configured and we can't find it, return NONE
246
- return null;
247
- }
248
-
249
- // Search merge block by TTD
250
- const latestBlockRaw = await this.eth1Provider.getBlockByNumber("latest");
251
- if (!latestBlockRaw) {
252
- throw Error("getBlockByNumber('latest') returned null");
253
- }
254
-
255
- let block = toPowBlock(latestBlockRaw);
256
- this.latestEth1Block = {...block, timestamp: quantityToNum(latestBlockRaw.timestamp)};
257
- this.cacheBlock(block);
258
-
259
- // This code path to look backwards for the merge block is only necessary if:
260
- // - The network has not yet found the merge block
261
- // - There are descendants of the merge block in the eth1 chain
262
- // For the search below to require more than a few hops, multiple block proposers in a row must fail to detect
263
- // an existing merge block. Such situation is extremely unlikely, so this search is left un-optimized. Since
264
- // this class can start eagerly looking for the merge block when not necessary, startPollingMergeBlock() should
265
- // only be called when there is certainty that a mergeBlock search is necessary.
266
-
267
- while (true) {
268
- if (block.totalDifficulty < this.config.TERMINAL_TOTAL_DIFFICULTY) {
269
- // TTD not reached yet
270
- return null;
271
- }
272
-
273
- // else block.totalDifficulty >= this.config.TERMINAL_TOTAL_DIFFICULTY
274
- // Potential mergeBlock! Must find the first block that passes TTD
275
-
276
- // Allow genesis block to reach TTD https://github.com/ethereum/consensus-specs/pull/2719
277
- if (block.parentHash === ZERO_HASH_HEX) {
278
- return block;
279
- }
280
-
281
- const parent = await this.getPowBlock(block.parentHash);
282
- if (!parent) {
283
- throw Error(`Unknown parent of block with TD>TTD ${block.parentHash}`);
284
- }
285
-
286
- this.metrics?.eth1.eth1ParentBlocksFetched.inc();
287
-
288
- // block.td > TTD && parent.td < TTD => block is mergeBlock
289
- if (parent.totalDifficulty < this.config.TERMINAL_TOTAL_DIFFICULTY) {
290
- // Is terminal total difficulty block AND has verified block -> parent relationship
291
- return block;
292
- }
293
- block = parent;
294
- }
295
- }
296
-
297
- private cacheBlock(block: PowMergeBlock): void {
298
- this.blocksByHashCache.set(block.blockHash, block);
299
- pruneSetToMax(this.blocksByHashCache, MAX_CACHE_POW_BLOCKS);
300
- }
301
- }
302
-
303
- export function toPowBlock(block: EthJsonRpcBlockRaw): PowMergeBlock {
304
- // Validate untrusted data from API
305
- return {
306
- number: quantityToNum(block.number),
307
- blockHash: dataToRootHex(block.hash),
308
- parentHash: dataToRootHex(block.parentHash),
309
- totalDifficulty: quantityToBigint(block.totalDifficulty),
310
- };
311
- }
312
-
313
- /**
314
- * TTD values can be very large, for xDAI > 1e45. So scale down.
315
- * To be good, TTD should be rendered as a number < Number.MAX_TD_RENDER_VALUE ~= 9e15
316
- */
317
- export function getSafeTDFactor(ttd: bigint): bigint {
318
- const safeIntegerMult = ttd / BigInt(MAX_TD_RENDER_VALUE);
319
-
320
- // TTD < MAX_TD_RENDER_VALUE, no need to scale down
321
- if (safeIntegerMult === BigInt(0)) {
322
- return BigInt(1);
323
- }
324
-
325
- // Return closest power of 10 to ensure TD < max
326
- const safeIntegerMultDigits = safeIntegerMult.toString(10).length;
327
- return BigInt(10) ** BigInt(safeIntegerMultDigits);
328
- }