Skip to content

Commit 4e7b5ac

Browse files
Merge dashpay#6730: refactor: break multiple circular dependencies over evo/deterministicmns and evo/cbtx
86c3dad fmt: re-order included for specialtxman.h (Konstantin Akimov) 8f40f40 refactor: remove un-needed header validationinterface.h from evo/{dmnstate,deterministicmns} (Konstantin Akimov) 51a83e7 fix: clang formatting and adjusting logs for BuildNewListFromBlock (Konstantin Akimov) 8e8d6eb refactor: remove dependency of evo/deterministicmns on llmq/utils and llmq/commitment (Konstantin Akimov) a20e1a0 refactor: drop unused arguments from CDeterministicMNManager::ProcessBlock (Konstantin Akimov) c873e55 refactor: move CL code validation to break circular dependencies over CbTx (Konstantin Akimov) 1011f6b refactor: drop dependency of CbTx on CSimplifiedMNList (Konstantin Akimov) 48a0357 refactor: only code move for CalcCbTxMerkleRootMNList from cbtx.h to simplifiedmns.h (Konstantin Akimov) Pull request description: ## Issue being fixed or feature implemented Addressed some exception for circular dependencies. ## What was done? See each commit. Most changes here are just moving functions between files, `git diff --color-moved=zebra` may help to review it. Though, `GetAllQuorumMembers()` is now called by `BuildNewListFromBlock()` compared to current behavior in develop branch. ## How Has This Been Tested? Removed these exception from linter: ``` - "core_io -> evo/cbtx -> evo/simplifiedmns -> core_io", - "evo/cbtx -> evo/simplifiedmns -> evo/cbtx", - "evo/deterministicmns -> llmq/commitment -> evo/deterministicmns", - "evo/deterministicmns -> llmq/commitment -> validation -> evo/deterministicmns", - "evo/deterministicmns -> llmq/commitment -> validation -> txmempool -> evo/deterministicmns", - "evo/deterministicmns -> llmq/utils -> evo/deterministicmns", - "evo/deterministicmns -> llmq/utils -> llmq/snapshot -> evo/simplifiedmns -> evo/deterministicmns", - "evo/deterministicmns -> llmq/utils -> net -> evo/deterministicmns", - "evo/deterministicmns -> validationinterface -> evo/deterministicmns", - "evo/deterministicmns -> validationinterface -> governance/vote -> evo/deterministicmns", + "core_io -> evo/assetlocktx -> llmq/signing -> net_processing -> evo/simplifiedmns -> core_io", ``` New one appeared in the list because it is a longer circular dependency that always has been here but has been hidden by shorter loop: `core_io -> evo/cbtx -> evo/simplifiedmns -> core_io`. ## Breaking Changes N/A ## Checklist: - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone ACKs for top commit: kwvg: utACK 86c3dad UdjinM6: re-utACK 86c3dad Tree-SHA512: 990ad21ca7e0fdf7207990bc4d8bad9453a3cdd6e5988941533f5c7e5cc4e6a70a412b92c3c9eba80b76732d25eaefe62c8491a0df6e621cf592de7098f9f50e
2 parents 5e7fae7 + 86c3dad commit 4e7b5ac

File tree

13 files changed

+571
-588
lines changed

13 files changed

+571
-588
lines changed

src/evo/cbtx.cpp

Lines changed: 5 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44

55
#include <consensus/validation.h>
66
#include <evo/cbtx.h>
7-
#include <evo/simplifiedmns.h>
87
#include <evo/specialtx.h>
98
#include <llmq/blockprocessor.h>
10-
#include <llmq/chainlocks.h>
119
#include <llmq/commitment.h>
1210
#include <llmq/options.h>
1311
#include <llmq/quorums.h>
@@ -45,93 +43,23 @@ bool CheckCbTx(const CCbTx& cbTx, const CBlockIndex* pindexPrev, TxValidationSta
4543
return true;
4644
}
4745

48-
// This can only be done after the block has been fully processed, as otherwise we won't have the finished MN list
4946
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)
5248
{
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) {
5850
uint256 calculatedMerkleRoot;
59-
if (!CalcCbTxMerkleRootMNList(calculatedMerkleRoot, std::move(sml), state)) {
51+
if (!CalcCbTxMerkleRootQuorums(block, pindex->pprev, quorum_block_processor, calculatedMerkleRoot, state)) {
6052
// pass the state returned by the function above
6153
return false;
6254
}
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");
8057
}
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);
8658
}
8759

8860
return true;
8961
}
9062

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-
13563
using QcHashMap = std::map<Consensus::LLMQType, std::vector<uint256>>;
13664
using QcIndexedHashMap = std::map<Consensus::LLMQType, std::map<int16_t, uint256>>;
13765

@@ -288,129 +216,6 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
288216
return true;
289217
}
290218

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-
414219
std::string CCbTx::ToString() const
415220
{
416221
return strprintf("CCbTx(nVersion=%d, nHeight=%d, merkleRootMNList=%s, merkleRootQuorums=%s, bestCLHeightDiff=%d, bestCLSig=%s, creditPoolBalance=%d.%08d)",

src/evo/cbtx.h

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@ class BlockValidationState;
1515
class CBlock;
1616
class CBlockIndex;
1717
class TxValidationState;
18-
class CSimplifiedMNList;
19-
2018
namespace llmq {
21-
class CChainLocksHandler;
2219
class CQuorumBlockProcessor;
2320
}// namespace llmq
2421

@@ -66,19 +63,13 @@ template<> struct is_serializable_enum<CCbTx::Version> : std::true_type {};
6663

6764
bool CheckCbTx(const CCbTx& cbTx, const CBlockIndex* pindexPrev, TxValidationState& state);
6865

66+
// This can only be done after the block has been fully processed, as otherwise we won't have the finished MN list
6967
bool CheckCbTxMerkleRoots(const CBlock& block, const CCbTx& cbTx, const CBlockIndex* pindex,
70-
const llmq::CQuorumBlockProcessor& quorum_block_processor, CSimplifiedMNList&& sml,
71-
BlockValidationState& state);
72-
bool CalcCbTxMerkleRootMNList(uint256& merkleRootRet, CSimplifiedMNList&& sml, BlockValidationState& state);
68+
const llmq::CQuorumBlockProcessor& quorum_block_processor, BlockValidationState& state);
7369
bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev,
7470
const llmq::CQuorumBlockProcessor& quorum_block_processor, uint256& merkleRootRet,
7571
BlockValidationState& state);
7672

77-
bool CheckCbTxBestChainlock(const CCbTx& cbTx, const CBlockIndex* pindexPrev,
78-
const llmq::CChainLocksHandler& chainlock_handler, BlockValidationState& state);
79-
bool CalcCbTxBestChainlock(const llmq::CChainLocksHandler& chainlock_handler, const CBlockIndex* pindexPrev,
80-
uint32_t& bestCLHeightDiff, CBLSSignature& bestCLSignature);
81-
8273
std::optional<std::pair<CBLSSignature, uint32_t>> GetNonNullCoinbaseChainlock(const CBlockIndex* pindex);
8374

8475
#endif // BITCOIN_EVO_CBTX_H

0 commit comments

Comments
 (0)