@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.
- package/README.md +1 -1
- package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/index.js +4 -5
- package/lib/api/impl/beacon/state/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +5 -3
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/validator/index.js +1 -1
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +1 -21
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +1 -6
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +10 -131
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.d.ts +2 -2
- package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.js +2 -2
- package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +4 -14
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +3 -3
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +3 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/options.d.ts +0 -4
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js +0 -2
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/prepareNextSlot.js +1 -1
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +2 -21
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +24 -87
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/rewards/attestationsRewards.d.ts +3 -3
- package/lib/chain/rewards/attestationsRewards.d.ts.map +1 -1
- package/lib/chain/rewards/attestationsRewards.js +4 -4
- package/lib/chain/rewards/attestationsRewards.js.map +1 -1
- package/lib/chain/rewards/syncCommitteeRewards.d.ts +2 -2
- package/lib/chain/rewards/syncCommitteeRewards.d.ts.map +1 -1
- package/lib/chain/rewards/syncCommitteeRewards.js +1 -2
- package/lib/chain/rewards/syncCommitteeRewards.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +2 -2
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/blobSidecar.d.ts.map +1 -1
- package/lib/chain/validation/blobSidecar.js +2 -2
- package/lib/chain/validation/blobSidecar.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +3 -3
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.js +2 -2
- package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +1 -1
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/chain/validation/signatureSets/contributionAndProof.d.ts +2 -2
- package/lib/chain/validation/signatureSets/contributionAndProof.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/contributionAndProof.js +2 -3
- package/lib/chain/validation/signatureSets/contributionAndProof.js.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommittee.d.ts +2 -2
- package/lib/chain/validation/signatureSets/syncCommittee.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommittee.js +2 -2
- package/lib/chain/validation/signatureSets/syncCommittee.js.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts +2 -2
- package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js +3 -3
- package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js.map +1 -1
- package/lib/chain/validation/syncCommittee.js +1 -1
- package/lib/chain/validation/syncCommittee.js.map +1 -1
- package/lib/chain/validation/syncCommitteeContributionAndProof.d.ts.map +1 -1
- package/lib/chain/validation/syncCommitteeContributionAndProof.js +4 -3
- package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
- package/lib/chain/validation/voluntaryExit.js +1 -1
- package/lib/chain/validation/voluntaryExit.js.map +1 -1
- package/lib/eth1/index.d.ts +2 -17
- package/lib/eth1/index.d.ts.map +1 -1
- package/lib/eth1/index.js +0 -50
- package/lib/eth1/index.js.map +1 -1
- package/lib/eth1/interface.d.ts +1 -39
- package/lib/eth1/interface.d.ts.map +1 -1
- package/lib/execution/engine/http.d.ts +4 -12
- package/lib/execution/engine/http.d.ts.map +1 -1
- package/lib/execution/engine/http.js +4 -12
- package/lib/execution/engine/http.js.map +1 -1
- package/lib/execution/engine/mock.d.ts +2 -6
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +3 -14
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +0 -14
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +0 -44
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/encoding.d.ts.map +1 -1
- package/lib/network/gossip/encoding.js +17 -7
- package/lib/network/gossip/encoding.js.map +1 -1
- package/lib/node/notifier.d.ts.map +1 -1
- package/lib/node/notifier.js +6 -22
- package/lib/node/notifier.js.map +1 -1
- package/lib/sync/backfill/backfill.d.ts.map +1 -1
- package/lib/sync/backfill/backfill.js +4 -2
- package/lib/sync/backfill/backfill.js.map +1 -1
- package/lib/sync/backfill/verify.d.ts +2 -2
- package/lib/sync/backfill/verify.d.ts.map +1 -1
- package/lib/sync/backfill/verify.js +3 -3
- package/lib/sync/backfill/verify.js.map +1 -1
- package/package.json +15 -16
- package/src/api/impl/beacon/state/index.ts +4 -5
- package/src/api/impl/beacon/state/utils.ts +5 -3
- package/src/api/impl/validator/index.ts +1 -1
- package/src/chain/blocks/verifyBlock.ts +2 -24
- package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +11 -170
- package/src/chain/blocks/verifyBlocksSignatures.ts +3 -2
- package/src/chain/chain.ts +4 -15
- package/src/chain/forkChoice/index.ts +2 -3
- package/src/chain/opPools/aggregatedAttestationPool.ts +5 -1
- package/src/chain/options.ts +0 -6
- package/src/chain/prepareNextSlot.ts +1 -1
- package/src/chain/produceBlock/produceBlockBody.ts +25 -120
- package/src/chain/rewards/attestationsRewards.ts +6 -5
- package/src/chain/rewards/syncCommitteeRewards.ts +2 -2
- package/src/chain/validation/attesterSlashing.ts +2 -2
- package/src/chain/validation/blobSidecar.ts +10 -2
- package/src/chain/validation/block.ts +2 -3
- package/src/chain/validation/dataColumnSidecar.ts +6 -1
- package/src/chain/validation/proposerSlashing.ts +1 -1
- package/src/chain/validation/signatureSets/contributionAndProof.ts +3 -2
- package/src/chain/validation/signatureSets/syncCommittee.ts +3 -1
- package/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts +4 -2
- package/src/chain/validation/syncCommittee.ts +1 -1
- package/src/chain/validation/syncCommitteeContributionAndProof.ts +4 -5
- package/src/chain/validation/voluntaryExit.ts +1 -1
- package/src/eth1/index.ts +2 -65
- package/src/eth1/interface.ts +1 -45
- package/src/execution/engine/http.ts +4 -12
- package/src/execution/engine/mock.ts +3 -15
- package/src/metrics/metrics/lodestar.ts +0 -52
- package/src/network/gossip/encoding.ts +19 -7
- package/src/node/notifier.ts +7 -29
- package/src/sync/backfill/backfill.ts +9 -2
- package/src/sync/backfill/verify.ts +8 -2
- package/lib/eth1/eth1MergeBlockTracker.d.ts +0 -65
- package/lib/eth1/eth1MergeBlockTracker.d.ts.map +0 -1
- package/lib/eth1/eth1MergeBlockTracker.js +0 -262
- package/lib/eth1/eth1MergeBlockTracker.js.map +0 -1
- 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":"AAEA,OAAO,EAAS,aAAa,EAAE,SAAS,EAAC,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAC,aAAa,EAAC,MAAM,uBAAuB,CAAC;AAEpD,OAAO,EAAC,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAC,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAEnF,MAAM,CAAN,IAAY,UAIX;AAJD,WAAY,UAAU;IACpB,iCAAmB,CAAA;IACnB,qCAAuB,CAAA;IACvB,6BAAe,CAAA;AACjB,CAAC,EAJW,UAAU,KAAV,UAAU,QAIrB;AAOD,kEAAkE;AAClE,MAAM,aAAa,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;AAEjD;;;GAGG;AACH,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC,MAAM,mBAAmB,GAAG,MAAM,CAAC,gBAAgB,CAAC;AASpD,oCAAoC;AAEpC;;;;;GAKG;AACH,MAAM,OAAO,qBAAqB;IAeb;IAdF,MAAM,CAAc;IACpB,MAAM,CAAS;IACf,OAAO,CAAiB;IAExB,iBAAiB,GAAG,IAAI,GAAG,EAA0B,CAAC;IACtD,SAAS,GAAqB,EAAE,CAAC;IAE1C,MAAM,CAAS;IACf,eAAe,GAAkC,IAAI,CAAC;IACtD,kCAAkC,GAAyC,IAAI,CAAC;IACvE,YAAY,CAAS;IAEtC,YACE,EAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAA+B,EAC9C,YAA2B;QAA3B,iBAAY,GAAZ,YAAY,CAAe;QAE5C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QAEvB,IAAI,CAAC,MAAM,GAAG,EAAC,IAAI,EAAE,UAAU,CAAC,OAAO,EAAC,CAAC;QAEzC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;QAEnE,IAAI,CAAC,YAAY,GAAG,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC;QAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,yBAAyB,GAAG,IAAI,CAAC,YAAY,CAAC;QAE5E,gCAAgC;QAChC,IAAI,OAAO,EAAE,CAAC;YACZ,0EAA0E;YAC1E,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,SAAmB,CAAC,CAAC,CAAC;YAC3D,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,YAAsB,CAAC,CAAC,CAAC;YAExE,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,GAAG,EAAE;gBAC3C,qDAAqD;gBACrD,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;gBAElE,IAAI,IAAI,CAAC,eAAe,KAAK,IAAI,EAAE,CAAC;oBAClC,wBAAwB;oBACxB,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;oBACpE,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;oBACrG,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;gBAC5E,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB;QACvB,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACzB,KAAK,UAAU,CAAC,OAAO;gBACrB,+DAA+D;gBAC/D,OAAO,IAAI,CAAC,2BAA2B,EAAE,CAAC;YAE5C,KAAK,UAAU,CAAC,SAAS;gBACvB,iDAAiD;gBACjD,OAAO,IAAI,CAAC;YAEd,KAAK,UAAU,CAAC,KAAK;gBACnB,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;QAClC,CAAC;IACH,CAAC;IAED,aAAa;QACX,IAAI,IAAI,CAAC,eAAe,KAAK,IAAI,EAAE,CAAC;YAClC,OAAO,IAAI,CAAC,eAAe,CAAC;QAC9B,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,yBAAyB,GAAG,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC;QAE5F,IAAI,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACvB,OAAO;gBACL,MAAM,EAAE,KAAK;gBACb,QAAQ,EAAE,IAAI,CAAC,YAAY;gBAC3B,YAAY,EAAE,MAAM,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,CAAW,CAAC;gBAC5D,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,yBAAyB;gBAC1C,EAAE,EAAE,IAAI,CAAC,eAAe,CAAC,eAAe;gBACxC,SAAS,EAAE,IAAI,CAAC,eAAe,CAAC,SAAS;aAC1C,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM,EAAE,IAAI;SACb,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,YAAoB;QACpC,oBAAoB;QACpB,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC7D,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,kBAAkB;QAClB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QACtE,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;YACnC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACvB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,sBAAsB;QACpB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC,OAAO,EAAE,CAAC;YAC5C,OAAO;QACT,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,EAAC,IAAI,EAAE,UAAU,CAAC,SAAS,EAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAwC,EAAE;YACzD,yBAAyB,EAAE,IAAI,CAAC,MAAM,CAAC,yBAAyB;SACjE,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;YAChC,8DAA8D;YAC9D,mFAAmF;YACnF,IAAI,CAAC,2BAA2B,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC7C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,EAAE,EAAE,CAAU,CAAC,CAAC;gBAC7D,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,wBAAwB,CAAC,GAAG,EAAE,CAAC;YACpD,CAAC,CAAC,CAAC;QACL,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC;QAE9C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAEO,KAAK;QACX,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACxC,CAAC;IAEO,KAAK,CAAC,2BAA2B;QACvC,IAAI,CAAC,IAAI,CAAC,kCAAkC,EAAE,CAAC;YAC7C,IAAI,CAAC,kCAAkC,GAAG,IAAI,CAAC,mCAAmC,EAAE;iBACjF,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE;gBACnB,8DAA8D;gBAC9D,sBAAsB;gBACtB,+BAA+B;gBAC/B,IAAI,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC,KAAK,EAAE,CAAC;oBACxD,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC,SAAS,EAAE,CAAC;wBAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;oBACf,CAAC;oBAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,EAAE;wBAC5C,IAAI,EAAE,UAAU,CAAC,SAAS;wBAC1B,MAAM,EAAE,UAAU,CAAC,MAAM;wBACzB,eAAe,EAAE,UAAU,CAAC,eAAe;qBAC5C,CAAC,CAAC;oBAEH,IAAI,CAAC,MAAM,GAAG,EAAC,IAAI,EAAE,UAAU,CAAC,KAAK,EAAE,UAAU,EAAC,CAAC;oBACnD,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAC1C;wBACE,iBAAiB,EAAE,UAAU,CAAC,SAAS;wBACvC,8CAA8C;wBAC9C,mBAAmB,EAAE,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;wBACnD,eAAe,EAAE,UAAU,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;qBACzD,EACD,CAAC,CACF,CAAC;gBACJ,CAAC;gBAED,OAAO,UAAU,CAAC;YACpB,CAAC,CAAC;iBACD,OAAO,CAAC,GAAG,EAAE;gBACZ,IAAI,CAAC,kCAAkC,GAAG,IAAI,CAAC;YACjD,CAAC,CAAC,CAAC;QACP,CAAC;aAAM,CAAC;YACN,gHAAgH;YAChH,uGAAuG;YACvG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,kCAAkC,CAAC,GAAG,EAAE,CAAC;QAC9D,CAAC;QAED,OAAO,IAAI,CAAC,kCAAkC,CAAC;IACjD,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,mCAAmC;QAC/C,6BAA6B;QAC7B,+EAA+E;QAC/E,MAAM,iBAAiB,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;QACrE,IAAI,iBAAiB,KAAK,aAAa,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;YACxD,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,KAAK,CAAC;YACf,CAAC;YACD,gGAAgG;YAChG,OAAO,IAAI,CAAC;QACd,CAAC;QAED,4BAA4B;QAC5B,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC1E,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,KAAK,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;QACvC,IAAI,CAAC,eAAe,GAAG,EAAC,GAAG,KAAK,EAAE,SAAS,EAAE,aAAa,CAAC,cAAc,CAAC,SAAS,CAAC,EAAC,CAAC;QACtF,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAEvB,6EAA6E;QAC7E,kDAAkD;QAClD,+DAA+D;QAC/D,8GAA8G;QAC9G,4GAA4G;QAC5G,+GAA+G;QAC/G,gFAAgF;QAEhF,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,yBAAyB,EAAE,CAAC;gBAClE,sBAAsB;gBACtB,OAAO,IAAI,CAAC;YACd,CAAC;YAED,sEAAsE;YACtE,kEAAkE;YAElE,yFAAyF;YACzF,IAAI,KAAK,CAAC,UAAU,KAAK,aAAa,EAAE,CAAC;gBACvC,OAAO,KAAK,CAAC;YACf,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACxD,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,KAAK,CAAC,uCAAuC,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;YACzE,CAAC;YAED,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,uBAAuB,CAAC,GAAG,EAAE,CAAC;YAEjD,2DAA2D;YAC3D,IAAI,MAAM,CAAC,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,yBAAyB,EAAE,CAAC;gBACnE,mFAAmF;gBACnF,OAAO,KAAK,CAAC;YACf,CAAC;YACD,KAAK,GAAG,MAAM,CAAC;QACjB,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,KAAoB;QACrC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACnD,aAAa,CAAC,IAAI,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,CAAC;IAC9D,CAAC;CACF;AAED,MAAM,UAAU,UAAU,CAAC,KAAyB;IAClD,mCAAmC;IACnC,OAAO;QACL,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC;QACnC,SAAS,EAAE,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC;QACpC,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC;QAC3C,eAAe,EAAE,gBAAgB,CAAC,KAAK,CAAC,eAAe,CAAC;KACzD,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,eAAe,GAAG,GAAG,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAE1D,mDAAmD;IACnD,IAAI,eAAe,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAClC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC;IAED,gDAAgD;IAChD,MAAM,qBAAqB,GAAG,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;IAClE,OAAO,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,qBAAqB,CAAC,CAAC;AACrD,CAAC"}
|
|
@@ -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
|
-
}
|