|
4 | 4 |
|
5 | 5 | #include <consensus/validation.h> |
6 | 6 | #include <evo/cbtx.h> |
7 | | -#include <evo/simplifiedmns.h> |
8 | 7 | #include <evo/specialtx.h> |
9 | 8 | #include <llmq/blockprocessor.h> |
10 | | -#include <llmq/chainlocks.h> |
11 | 9 | #include <llmq/commitment.h> |
12 | 10 | #include <llmq/options.h> |
13 | 11 | #include <llmq/quorums.h> |
@@ -45,93 +43,23 @@ bool CheckCbTx(const CCbTx& cbTx, const CBlockIndex* pindexPrev, TxValidationSta |
45 | 43 | return true; |
46 | 44 | } |
47 | 45 |
|
48 | | -// This can only be done after the block has been fully processed, as otherwise we won't have the finished MN list |
49 | 46 | bool CheckCbTxMerkleRoots(const CBlock& block, const CCbTx& cbTx, const CBlockIndex* pindex, |
50 | | - const llmq::CQuorumBlockProcessor& quorum_block_processor, CSimplifiedMNList&& sml, |
51 | | - BlockValidationState& state) |
| 47 | + const llmq::CQuorumBlockProcessor& quorum_block_processor, BlockValidationState& state) |
52 | 48 | { |
53 | | - if (pindex) { |
54 | | - static int64_t nTimeMerkleMNL = 0; |
55 | | - static int64_t nTimeMerkleQuorum = 0; |
56 | | - |
57 | | - int64_t nTime1 = GetTimeMicros(); |
| 49 | + if (pindex && cbTx.nVersion >= CCbTx::Version::MERKLE_ROOT_QUORUMS) { |
58 | 50 | uint256 calculatedMerkleRoot; |
59 | | - if (!CalcCbTxMerkleRootMNList(calculatedMerkleRoot, std::move(sml), state)) { |
| 51 | + if (!CalcCbTxMerkleRootQuorums(block, pindex->pprev, quorum_block_processor, calculatedMerkleRoot, state)) { |
60 | 52 | // pass the state returned by the function above |
61 | 53 | return false; |
62 | 54 | } |
63 | | - if (calculatedMerkleRoot != cbTx.merkleRootMNList) { |
64 | | - return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-mnmerkleroot"); |
65 | | - } |
66 | | - |
67 | | - int64_t nTime2 = GetTimeMicros(); |
68 | | - nTimeMerkleMNL += nTime2 - nTime1; |
69 | | - LogPrint(BCLog::BENCHMARK, " - CalcCbTxMerkleRootMNList: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), |
70 | | - nTimeMerkleMNL * 0.000001); |
71 | | - |
72 | | - if (cbTx.nVersion >= CCbTx::Version::MERKLE_ROOT_QUORUMS) { |
73 | | - if (!CalcCbTxMerkleRootQuorums(block, pindex->pprev, quorum_block_processor, calculatedMerkleRoot, state)) { |
74 | | - // pass the state returned by the function above |
75 | | - return false; |
76 | | - } |
77 | | - if (calculatedMerkleRoot != cbTx.merkleRootQuorums) { |
78 | | - return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-quorummerkleroot"); |
79 | | - } |
| 55 | + if (calculatedMerkleRoot != cbTx.merkleRootQuorums) { |
| 56 | + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-quorummerkleroot"); |
80 | 57 | } |
81 | | - |
82 | | - int64_t nTime3 = GetTimeMicros(); |
83 | | - nTimeMerkleQuorum += nTime3 - nTime2; |
84 | | - LogPrint(BCLog::BENCHMARK, " - CalcCbTxMerkleRootQuorums: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), |
85 | | - nTimeMerkleQuorum * 0.000001); |
86 | 58 | } |
87 | 59 |
|
88 | 60 | return true; |
89 | 61 | } |
90 | 62 |
|
91 | | -bool CalcCbTxMerkleRootMNList(uint256& merkleRootRet, CSimplifiedMNList&& sml, BlockValidationState& state) |
92 | | -{ |
93 | | - try { |
94 | | - static std::atomic<int64_t> nTimeMerkle = 0; |
95 | | - |
96 | | - int64_t nTime1 = GetTimeMicros(); |
97 | | - |
98 | | - static Mutex cached_mutex; |
99 | | - static CSimplifiedMNList smlCached GUARDED_BY(cached_mutex); |
100 | | - static uint256 merkleRootCached GUARDED_BY(cached_mutex); |
101 | | - static bool mutatedCached GUARDED_BY(cached_mutex) {false}; |
102 | | - |
103 | | - LOCK(cached_mutex); |
104 | | - if (sml == smlCached) { |
105 | | - merkleRootRet = merkleRootCached; |
106 | | - if (mutatedCached) { |
107 | | - return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "mutated-cached-calc-cb-mnmerkleroot"); |
108 | | - } |
109 | | - return true; |
110 | | - } |
111 | | - |
112 | | - bool mutated = false; |
113 | | - merkleRootRet = sml.CalcMerkleRoot(&mutated); |
114 | | - |
115 | | - int64_t nTime2 = GetTimeMicros(); |
116 | | - nTimeMerkle += nTime2 - nTime1; |
117 | | - LogPrint(BCLog::BENCHMARK, " - CalcMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), |
118 | | - nTimeMerkle * 0.000001); |
119 | | - |
120 | | - smlCached = std::move(sml); |
121 | | - merkleRootCached = merkleRootRet; |
122 | | - mutatedCached = mutated; |
123 | | - |
124 | | - if (mutated) { |
125 | | - return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "mutated-calc-cb-mnmerkleroot"); |
126 | | - } |
127 | | - |
128 | | - return true; |
129 | | - } catch (const std::exception& e) { |
130 | | - LogPrintf("%s -- failed: %s\n", __func__, e.what()); |
131 | | - return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "failed-calc-cb-mnmerkleroot"); |
132 | | - } |
133 | | -} |
134 | | - |
135 | 63 | using QcHashMap = std::map<Consensus::LLMQType, std::vector<uint256>>; |
136 | 64 | using QcIndexedHashMap = std::map<Consensus::LLMQType, std::map<int16_t, uint256>>; |
137 | 65 |
|
@@ -288,129 +216,6 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre |
288 | 216 | return true; |
289 | 217 | } |
290 | 218 |
|
291 | | -bool CheckCbTxBestChainlock(const CCbTx& cbTx, const CBlockIndex* pindex, |
292 | | - const llmq::CChainLocksHandler& chainlock_handler, BlockValidationState& state) |
293 | | -{ |
294 | | - if (cbTx.nVersion < CCbTx::Version::CLSIG_AND_BALANCE) { |
295 | | - return true; |
296 | | - } |
297 | | - |
298 | | - static Mutex cached_mutex; |
299 | | - static const CBlockIndex* cached_pindex GUARDED_BY(cached_mutex){nullptr}; |
300 | | - static std::optional<std::pair<CBLSSignature, uint32_t>> cached_chainlock GUARDED_BY(cached_mutex){std::nullopt}; |
301 | | - |
302 | | - auto best_clsig = chainlock_handler.GetBestChainLock(); |
303 | | - if (best_clsig.getHeight() == pindex->nHeight - 1 && cbTx.bestCLHeightDiff == 0 && cbTx.bestCLSignature == best_clsig.getSig()) { |
304 | | - // matches our best clsig which still hold values for the previous block |
305 | | - LOCK(cached_mutex); |
306 | | - cached_chainlock = std::make_pair(cbTx.bestCLSignature, cbTx.bestCLHeightDiff); |
307 | | - cached_pindex = pindex; |
308 | | - return true; |
309 | | - } |
310 | | - |
311 | | - std::optional<std::pair<CBLSSignature, uint32_t>> prevBlockCoinbaseChainlock{std::nullopt}; |
312 | | - if (LOCK(cached_mutex); cached_pindex == pindex->pprev) { |
313 | | - prevBlockCoinbaseChainlock = cached_chainlock; |
314 | | - } |
315 | | - if (!prevBlockCoinbaseChainlock.has_value()) { |
316 | | - prevBlockCoinbaseChainlock = GetNonNullCoinbaseChainlock(pindex->pprev); |
317 | | - } |
318 | | - // If std::optional prevBlockCoinbaseChainlock is empty, then up to the previous block, coinbase Chainlock is null. |
319 | | - if (prevBlockCoinbaseChainlock.has_value()) { |
320 | | - // Previous block Coinbase has a non-null Chainlock: current block's Chainlock must be non-null and at least as new as the previous one |
321 | | - if (!cbTx.bestCLSignature.IsValid()) { |
322 | | - // IsNull() doesn't exist for CBLSSignature: we assume that a non valid BLS sig is null |
323 | | - return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-null-clsig"); |
324 | | - } |
325 | | - if (cbTx.bestCLHeightDiff > prevBlockCoinbaseChainlock.value().second + 1) { |
326 | | - return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-older-clsig"); |
327 | | - } |
328 | | - } |
329 | | - |
330 | | - // IsNull() doesn't exist for CBLSSignature: we assume that a valid BLS sig is non-null |
331 | | - if (cbTx.bestCLSignature.IsValid()) { |
332 | | - int curBlockCoinbaseCLHeight = pindex->nHeight - static_cast<int>(cbTx.bestCLHeightDiff) - 1; |
333 | | - if (best_clsig.getHeight() == curBlockCoinbaseCLHeight && best_clsig.getSig() == cbTx.bestCLSignature) { |
334 | | - // matches our best (but outdated) clsig, no need to verify it again |
335 | | - LOCK(cached_mutex); |
336 | | - cached_chainlock = std::make_pair(cbTx.bestCLSignature, cbTx.bestCLHeightDiff); |
337 | | - cached_pindex = pindex; |
338 | | - return true; |
339 | | - } |
340 | | - uint256 curBlockCoinbaseCLBlockHash = pindex->GetAncestor(curBlockCoinbaseCLHeight)->GetBlockHash(); |
341 | | - if (chainlock_handler.VerifyChainLock(llmq::CChainLockSig(curBlockCoinbaseCLHeight, curBlockCoinbaseCLBlockHash, cbTx.bestCLSignature)) != llmq::VerifyRecSigStatus::Valid) { |
342 | | - return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-invalid-clsig"); |
343 | | - } |
344 | | - LOCK(cached_mutex); |
345 | | - cached_chainlock = std::make_pair(cbTx.bestCLSignature, cbTx.bestCLHeightDiff); |
346 | | - cached_pindex = pindex; |
347 | | - } else if (cbTx.bestCLHeightDiff != 0) { |
348 | | - // Null bestCLSignature is allowed only with bestCLHeightDiff = 0 |
349 | | - return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-cldiff"); |
350 | | - } |
351 | | - |
352 | | - return true; |
353 | | -} |
354 | | - |
355 | | -bool CalcCbTxBestChainlock(const llmq::CChainLocksHandler& chainlock_handler, const CBlockIndex* pindexPrev, |
356 | | - uint32_t& bestCLHeightDiff, CBLSSignature& bestCLSignature) |
357 | | -{ |
358 | | - auto best_clsig = chainlock_handler.GetBestChainLock(); |
359 | | - if (best_clsig.getHeight() < Params().GetConsensus().DeploymentHeight(Consensus::DEPLOYMENT_V19)) { |
360 | | - // We don't want legacy BLS ChainLocks in CbTx (can happen on regtest/devenets) |
361 | | - best_clsig = llmq::CChainLockSig{}; |
362 | | - } |
363 | | - if (best_clsig.getHeight() == pindexPrev->nHeight) { |
364 | | - // Our best CL is the newest one possible |
365 | | - bestCLHeightDiff = 0; |
366 | | - bestCLSignature = best_clsig.getSig(); |
367 | | - return true; |
368 | | - } |
369 | | - |
370 | | - auto prevBlockCoinbaseChainlock = GetNonNullCoinbaseChainlock(pindexPrev); |
371 | | - if (prevBlockCoinbaseChainlock.has_value()) { |
372 | | - // Previous block Coinbase contains a non-null CL: We must insert the same sig or a better (newest) one |
373 | | - if (best_clsig.IsNull()) { |
374 | | - // We don't know any CL, therefore inserting the CL of the previous block |
375 | | - bestCLHeightDiff = prevBlockCoinbaseChainlock->second + 1; |
376 | | - bestCLSignature = prevBlockCoinbaseChainlock->first; |
377 | | - return true; |
378 | | - } |
379 | | - |
380 | | - // We check if our best CL is newer than the one from previous block Coinbase |
381 | | - int curCLHeight = best_clsig.getHeight(); |
382 | | - int prevCLHeight = pindexPrev->nHeight - static_cast<int>(prevBlockCoinbaseChainlock->second) - 1; |
383 | | - if (curCLHeight < prevCLHeight) { |
384 | | - // Our best CL isn't newer: inserting CL from previous block |
385 | | - bestCLHeightDiff = prevBlockCoinbaseChainlock->second + 1; |
386 | | - bestCLSignature = prevBlockCoinbaseChainlock->first; |
387 | | - } |
388 | | - else { |
389 | | - // Our best CL is newer |
390 | | - bestCLHeightDiff = pindexPrev->nHeight - best_clsig.getHeight(); |
391 | | - bestCLSignature = best_clsig.getSig(); |
392 | | - } |
393 | | - |
394 | | - return true; |
395 | | - } |
396 | | - else { |
397 | | - // Previous block Coinbase has no CL. We can either insert null or any valid CL |
398 | | - if (best_clsig.IsNull()) { |
399 | | - // We don't know any CL, therefore inserting a null CL |
400 | | - bestCLHeightDiff = 0; |
401 | | - bestCLSignature.Reset(); |
402 | | - return false; |
403 | | - } |
404 | | - |
405 | | - // Inserting our best CL |
406 | | - bestCLHeightDiff = pindexPrev->nHeight - best_clsig.getHeight(); |
407 | | - bestCLSignature = chainlock_handler.GetBestChainLock().getSig(); |
408 | | - |
409 | | - return true; |
410 | | - } |
411 | | -} |
412 | | - |
413 | | - |
414 | 219 | std::string CCbTx::ToString() const |
415 | 220 | { |
416 | 221 | return strprintf("CCbTx(nVersion=%d, nHeight=%d, merkleRootMNList=%s, merkleRootQuorums=%s, bestCLHeightDiff=%d, bestCLSig=%s, creditPoolBalance=%d.%08d)", |
|
0 commit comments