-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat!: Insertion of best CL signature in CbTx #5262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1485fd4
531c7c5
5ceb71b
7e002b6
cce1184
9a5648c
2a50226
60994a1
3fffb2f
b2cbaab
3fb85ee
032cfb1
5d094a9
380e9e0
04d1986
3999739
29b0c30
c5ee6ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| #include <evo/cbtx.h> | ||
| #include <evo/deterministicmns.h> | ||
| #include <llmq/blockprocessor.h> | ||
| #include <llmq/chainlocks.h> | ||
| #include <llmq/commitment.h> | ||
| #include <llmq/utils.h> | ||
| #include <evo/simplifiedmns.h> | ||
|
|
@@ -14,6 +15,7 @@ | |
| #include <chain.h> | ||
| #include <chainparams.h> | ||
| #include <consensus/merkle.h> | ||
| #include <validation.h> | ||
|
|
||
| bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state) | ||
| { | ||
|
|
@@ -30,7 +32,7 @@ bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidati | |
| return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-payload"); | ||
| } | ||
|
|
||
| if (cbTx.nVersion == 0 || cbTx.nVersion > CCbTx::CURRENT_VERSION) { | ||
| if (cbTx.nVersion == 0 || cbTx.nVersion > CCbTx::CB_V20_VERSION) { | ||
| return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-version"); | ||
| } | ||
|
|
||
|
|
@@ -40,7 +42,12 @@ bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidati | |
|
|
||
| if (pindexPrev) { | ||
| bool fDIP0008Active = pindexPrev->nHeight >= Params().GetConsensus().DIP0008Height; | ||
| if (fDIP0008Active && cbTx.nVersion < 2) { | ||
| if (fDIP0008Active && cbTx.nVersion < CCbTx::CB_V19_VERSION) { | ||
| return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-version"); | ||
| } | ||
|
|
||
| bool isV20 = llmq::utils::IsV20Active(pindexPrev); | ||
| if ((isV20 && cbTx.nVersion < CCbTx::CB_V20_VERSION) || (!isV20 && cbTx.nVersion >= CCbTx::CB_V20_VERSION)) { | ||
| return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-version"); | ||
| } | ||
| } | ||
|
|
@@ -314,8 +321,158 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre | |
| return true; | ||
| } | ||
|
|
||
| bool CheckCbTxBestChainlock(const CBlock& block, const CBlockIndex* pindex, const llmq::CChainLocksHandler& chainlock_handler, BlockValidationState& state) | ||
| { | ||
| if (block.vtx[0]->nType != TRANSACTION_COINBASE) { | ||
| return true; | ||
| } | ||
|
ogabrielides marked this conversation as resolved.
|
||
|
|
||
| CCbTx cbTx; | ||
| if (!GetTxPayload(*block.vtx[0], cbTx)) { | ||
| return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-payload"); | ||
| } | ||
|
|
||
| if (cbTx.nVersion < CCbTx::CB_V20_VERSION) { | ||
| return true; | ||
| } | ||
|
|
||
| auto best_clsig = chainlock_handler.GetBestChainLock(); | ||
| if (best_clsig.getHeight() == pindex->nHeight - 1 && cbTx.bestCLHeightDiff == 0 && cbTx.bestCLSignature == best_clsig.getSig()) { | ||
| // matches our best clsig which still hold values for the previous block | ||
| return true; | ||
| } | ||
|
|
||
| auto prevBlockCoinbaseChainlock = GetNonNullCoinbaseChainlock(pindex); | ||
| // If std::optional prevBlockCoinbaseChainlock is empty, then up to the previous block, coinbase Chainlock is null. | ||
| if (prevBlockCoinbaseChainlock.has_value()) { | ||
| // 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 | ||
| if (!cbTx.bestCLSignature.IsValid()) { | ||
| // IsNull() doesn't exist for CBLSSignature: we assume that a non valid BLS sig is null | ||
| return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-null-clsig"); | ||
| } | ||
| int prevBlockCoinbaseCLHeight = pindex->nHeight - static_cast<int>(prevBlockCoinbaseChainlock.value().second) - 1; | ||
| int curBlockCoinbaseCLHeight = pindex->nHeight - static_cast<int>(cbTx.bestCLHeightDiff) - 1; | ||
| if (curBlockCoinbaseCLHeight < prevBlockCoinbaseCLHeight) { | ||
| return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-older-clsig"); | ||
| } | ||
| } | ||
|
|
||
| // IsNull() doesn't exist for CBLSSignature: we assume that a valid BLS sig is non-null | ||
| if (cbTx.bestCLSignature.IsValid()) { | ||
| int curBlockCoinbaseCLHeight = pindex->nHeight - static_cast<int>(cbTx.bestCLHeightDiff) - 1; | ||
| if (best_clsig.getHeight() == curBlockCoinbaseCLHeight && best_clsig.getSig() == cbTx.bestCLSignature) { | ||
| // matches our best (but outdated) clsig, no need to verify it again | ||
| return true; | ||
| } | ||
| uint256 curBlockCoinbaseCLBlockHash = pindex->GetAncestor(curBlockCoinbaseCLHeight)->GetBlockHash(); | ||
| if (!chainlock_handler.VerifyChainLock(llmq::CChainLockSig(curBlockCoinbaseCLHeight, curBlockCoinbaseCLBlockHash, cbTx.bestCLSignature))) { | ||
| return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-invalid-clsig"); | ||
| } | ||
| } else if (cbTx.bestCLHeightDiff != 0) { | ||
| // Null bestCLSignature is allowed only with bestCLHeightDiff = 0 | ||
| return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-cldiff"); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| bool CalcCbTxBestChainlock(const llmq::CChainLocksHandler& chainlock_handler, const CBlockIndex* pindexPrev, uint32_t& bestCLHeightDiff, CBLSSignature& bestCLSignature) | ||
| { | ||
| auto best_clsig = chainlock_handler.GetBestChainLock(); | ||
| if (best_clsig.getHeight() == pindexPrev->nHeight) { | ||
| // Our best CL is the newest one possible | ||
| bestCLHeightDiff = 0; | ||
| bestCLSignature = best_clsig.getSig(); | ||
| return true; | ||
| } | ||
|
|
||
| auto prevBlockCoinbaseChainlock = GetNonNullCoinbaseChainlock(pindexPrev); | ||
| if (prevBlockCoinbaseChainlock.has_value()) { | ||
| // Previous block Coinbase contains a non-null CL: We must insert the same sig or a better (newest) one | ||
| if (best_clsig.IsNull()) { | ||
| // We don't know any CL, therefore inserting the CL of the previous block | ||
| bestCLHeightDiff = prevBlockCoinbaseChainlock->second + 1; | ||
| bestCLSignature = prevBlockCoinbaseChainlock->first; | ||
| return true; | ||
| } | ||
|
|
||
| // We check if our best CL is newer than the one from previous block Coinbase | ||
| auto curCLHeight = best_clsig.getHeight(); | ||
| auto prevCLHeight = static_cast<uint32_t>(pindexPrev->nHeight) - prevBlockCoinbaseChainlock->second - 1; | ||
| if (curCLHeight < prevCLHeight) { | ||
| // Our best CL isn't newer: inserting CL from previous block | ||
| bestCLHeightDiff = prevBlockCoinbaseChainlock->second + 1; | ||
| bestCLSignature = prevBlockCoinbaseChainlock->first; | ||
| } | ||
| else { | ||
| // Our best CL is newer | ||
| bestCLHeightDiff = static_cast<uint32_t>(pindexPrev->nHeight) - best_clsig.getHeight(); | ||
| bestCLSignature = best_clsig.getSig(); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
| else { | ||
| // Previous block Coinbase has no CL. We can either insert null or any valid CL | ||
| if (best_clsig.IsNull()) { | ||
| // We don't know any CL, therefore inserting a null CL | ||
| bestCLHeightDiff = 0; | ||
| bestCLSignature.Reset(); | ||
| return false; | ||
| } | ||
|
|
||
| // Inserting our best CL | ||
| bestCLHeightDiff = static_cast<uint32_t>(pindexPrev->nHeight) - best_clsig.getHeight(); | ||
| bestCLSignature = chainlock_handler.GetBestChainLock().getSig(); | ||
|
|
||
| return true; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| std::string CCbTx::ToString() const | ||
| { | ||
| return strprintf("CCbTx(nVersion=%d, nHeight=%d, merkleRootMNList=%s, merkleRootQuorums=%s)", | ||
| nVersion, nHeight, merkleRootMNList.ToString(), merkleRootQuorums.ToString()); | ||
| return strprintf("CCbTx(nVersion=%d, nHeight=%d, merkleRootMNList=%s, merkleRootQuorums=%s, bestCLHeightDiff=%d, bestCLSig=%s)", | ||
| nVersion, nHeight, merkleRootMNList.ToString(), merkleRootQuorums.ToString(), bestCLHeightDiff, bestCLSignature.ToString()); | ||
| } | ||
|
|
||
| std::optional<CCbTx> GetCoinbaseTx(const CBlockIndex* pindex) | ||
| { | ||
| if (pindex == nullptr) { | ||
| return std::nullopt; | ||
| } | ||
|
|
||
| CBlock block; | ||
| if (!ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { | ||
| return std::nullopt; | ||
| } | ||
|
|
||
| CTransactionRef cbTx = block.vtx[0]; | ||
| CCbTx cbTxPayload; | ||
| if (!GetTxPayload(*cbTx, cbTxPayload)) { | ||
| return std::nullopt; | ||
| } | ||
|
|
||
| return cbTxPayload; | ||
| } | ||
|
|
||
| std::optional<std::pair<CBLSSignature, uint32_t>> GetNonNullCoinbaseChainlock(const CBlockIndex* pindex) | ||
| { | ||
| auto opt_cbtx = GetCoinbaseTx(pindex); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should probably store
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean to cache
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implemented in #5347 by the way |
||
|
|
||
| if (!opt_cbtx.has_value()) { | ||
| return std::nullopt; | ||
| } | ||
|
|
||
| CCbTx& cbtx = opt_cbtx.value(); | ||
|
|
||
| if (cbtx.nVersion < CCbTx::CB_V20_VERSION) { | ||
| return std::nullopt; | ||
| } | ||
|
|
||
| if (!cbtx.bestCLSignature.IsValid()) { | ||
| return std::nullopt; | ||
| } | ||
|
|
||
| return std::make_pair(cbtx.bestCLSignature, cbtx.bestCLHeightDiff); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.