diff --git a/src/Makefile.am b/src/Makefile.am index 55c8f03ae4750..1f1cddf3f856a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -150,6 +150,9 @@ BITCOIN_CORE_H = \ cachemultimap.h \ blockfilter.h \ chain.h \ + chainlock/chainlock.h \ + chainlock/clsig.h \ + chainlock/signing.h \ chainparams.h \ chainparamsbase.h \ chainparamsseeds.h \ @@ -239,8 +242,6 @@ BITCOIN_CORE_H = \ key_io.h \ limitedmap.h \ llmq/blockprocessor.h \ - llmq/chainlocks.h \ - llmq/clsig.h \ llmq/commitment.h \ llmq/context.h \ llmq/debug.h \ @@ -455,6 +456,9 @@ libbitcoin_node_a_SOURCES = \ blockencodings.cpp \ blockfilter.cpp \ chain.cpp \ + chainlock/chainlock.cpp \ + chainlock/clsig.cpp \ + chainlock/signing.cpp \ coinjoin/coinjoin.cpp \ coinjoin/context.cpp \ coinjoin/server.cpp \ @@ -498,8 +502,6 @@ libbitcoin_node_a_SOURCES = \ instantsend/lock.cpp \ instantsend/signing.cpp \ llmq/blockprocessor.cpp \ - llmq/chainlocks.cpp \ - llmq/clsig.cpp \ llmq/commitment.cpp \ llmq/context.cpp \ llmq/debug.cpp \ diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp index 33fc11065d894..9ed1fffb2f780 100644 --- a/src/bench/rpc_blockchain.cpp +++ b/src/bench/rpc_blockchain.cpp @@ -5,9 +5,9 @@ #include #include +#include #include #include -#include #include #include #include diff --git a/src/llmq/chainlocks.cpp b/src/chainlock/chainlock.cpp similarity index 58% rename from src/llmq/chainlocks.cpp rename to src/chainlock/chainlock.cpp index 155e1117260a5..ea1d179dbd312 100644 --- a/src/llmq/chainlocks.cpp +++ b/src/chainlock/chainlock.cpp @@ -2,19 +2,13 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include -#include +#include #include #include #include -#include -#include -#include #include #include -#include -#include #include #include #include @@ -22,37 +16,47 @@ #include #include -using node::ReadBlockFromDisk; +#include +#include +#include +#include +#include // Forward declaration to break dependency over node/transaction.h -namespace node -{ +namespace node { CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock); } // namespace node + using node::GetTransaction; -static bool ChainLocksSigningEnabled(const CSporkManager& sporkman) +namespace llmq { +namespace { +static constexpr int64_t CLEANUP_INTERVAL{1000 * 30}; +static constexpr int64_t CLEANUP_SEEN_TIMEOUT{24 * 60 * 60 * 1000}; +//! How long to wait for islocks until we consider a block with non-islocked TXs to be safe to sign +static constexpr int64_t WAIT_FOR_ISLOCK_TIMEOUT{10 * 60}; +} // anonymous namespace + +bool AreChainLocksEnabled(const CSporkManager& sporkman) { - return sporkman.GetSporkValue(SPORK_19_CHAINLOCKS_ENABLED) == 0; + return sporkman.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED); } -namespace llmq -{ CChainLocksHandler::CChainLocksHandler(CChainState& chainstate, CQuorumManager& _qman, CSigningManager& _sigman, CSigSharesManager& _shareman, CSporkManager& sporkman, CTxMemPool& _mempool, const CMasternodeSync& mn_sync, bool is_masternode) : - m_chainstate(chainstate), - qman(_qman), - sigman(_sigman), - shareman(_shareman), - spork_manager(sporkman), - mempool(_mempool), - m_mn_sync(mn_sync), - m_is_masternode{is_masternode}, - scheduler(std::make_unique()), - scheduler_thread( - std::make_unique(std::thread(util::TraceThread, "cl-schdlr", [&] { scheduler->serviceQueue(); }))) + m_chainstate{chainstate}, + qman{_qman}, + spork_manager{sporkman}, + mempool{_mempool}, + m_mn_sync{mn_sync}, + scheduler{std::make_unique()}, + scheduler_thread{ + std::make_unique(std::thread(util::TraceThread, "cl-schdlr", [&] { scheduler->serviceQueue(); }))}, + m_signer{is_masternode + ? std::make_unique(chainstate, *this, _sigman, _shareman, sporkman, mn_sync) + : nullptr} { } @@ -64,19 +68,26 @@ CChainLocksHandler::~CChainLocksHandler() void CChainLocksHandler::Start(const llmq::CInstantSendManager& isman) { - sigman.RegisterRecoveredSigsListener(this); + if (m_signer) { + m_signer->Start(); + } scheduler->scheduleEvery([&]() { CheckActiveState(); EnforceBestChainLock(); + Cleanup(); // regularly retry signing the current chaintip as it might have failed before due to missing islocks - TrySignChainTip(isman); + if (m_signer) { + m_signer->TrySignChainTip(isman); + } }, std::chrono::seconds{5}); } void CChainLocksHandler::Stop() { scheduler->stop(); - sigman.UnregisterRecoveredSigsListener(this); + if (m_signer) { + m_signer->Stop(); + } } bool CChainLocksHandler::AlreadyHave(const CInv& inv) const @@ -85,7 +96,7 @@ bool CChainLocksHandler::AlreadyHave(const CInv& inv) const return seenChainLocks.count(inv.hash) != 0; } -bool CChainLocksHandler::GetChainLockByHash(const uint256& hash, llmq::CChainLockSig& ret) const +bool CChainLocksHandler::GetChainLockByHash(const uint256& hash, chainlock::ChainLockSig& ret) const { LOCK(cs); @@ -98,13 +109,22 @@ bool CChainLocksHandler::GetChainLockByHash(const uint256& hash, llmq::CChainLoc return true; } -CChainLockSig CChainLocksHandler::GetBestChainLock() const +chainlock::ChainLockSig CChainLocksHandler::GetBestChainLock() const { LOCK(cs); return bestChainLock; } -MessageProcessingResult CChainLocksHandler::ProcessNewChainLock(const NodeId from, const llmq::CChainLockSig& clsig, +void CChainLocksHandler::UpdateTxFirstSeenMap(const std::unordered_set& tx, const int64_t& time) +{ + AssertLockNotHeld(cs); + LOCK(cs); + for (const auto& txid : tx) { + txFirstSeenTime.emplace(txid, time); + } +} + +MessageProcessingResult CChainLocksHandler::ProcessNewChainLock(const NodeId from, const chainlock::ChainLockSig& clsig, const uint256& hash) { CheckActiveState(); @@ -203,7 +223,10 @@ void CChainLocksHandler::UpdatedBlockTip(const llmq::CInstantSendManager& isman) scheduler->scheduleFromNow([&]() { CheckActiveState(); EnforceBestChainLock(); - TrySignChainTip(isman); + Cleanup(); + if (m_signer) { + m_signer->TrySignChainTip(isman); + } tryLockChainTipScheduled = false; }, std::chrono::seconds{0}); } @@ -220,127 +243,11 @@ void CChainLocksHandler::CheckActiveState() // to disable spork19) LOCK(cs); bestChainLockHash = uint256(); - bestChainLock = bestChainLockWithKnownBlock = CChainLockSig(); + bestChainLock = bestChainLockWithKnownBlock = chainlock::ChainLockSig(); bestChainLockBlockIndex = lastNotifyChainLockBlockIndex = nullptr; } } -void CChainLocksHandler::TrySignChainTip(const llmq::CInstantSendManager& isman) -{ - Cleanup(); - - if (!m_is_masternode) { - return; - } - - if (!m_mn_sync.IsBlockchainSynced()) { - return; - } - - if (!isEnabled) { - return; - } - - if (!ChainLocksSigningEnabled(spork_manager)) { - return; - } - - const CBlockIndex* pindex = WITH_LOCK(::cs_main, return m_chainstate.m_chain.Tip()); - - if (pindex->pprev == nullptr) { - return; - } - - // DIP8 defines a process called "Signing attempts" which should run before the CLSIG is finalized - // To simplify the initial implementation, we skip this process and directly try to create a CLSIG - // This will fail when multiple blocks compete, but we accept this for the initial implementation. - // Later, we'll add the multiple attempts process. - - { - LOCK(cs); - - if (pindex->nHeight == lastSignedHeight) { - // already signed this one - return; - } - - if (bestChainLock.getHeight() >= pindex->nHeight) { - // already got the same CLSIG or a better one - return; - } - - if (InternalHasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) { - // don't sign if another conflicting CLSIG is already present. EnforceBestChainLock will later enforce - // the correct chain. - return; - } - } - - LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- trying to sign %s, height=%d\n", __func__, pindex->GetBlockHash().ToString(), pindex->nHeight); - - // When the new IX system is activated, we only try to ChainLock blocks which include safe transactions. A TX is - // considered safe when it is islocked or at least known since 10 minutes (from mempool or block). These checks are - // performed for the tip (which we try to sign) and the previous 5 blocks. If a ChainLocked block is found on the - // way down, we consider all TXs to be safe. - if (isman.IsInstantSendEnabled() && isman.RejectConflictingBlocks()) { - const auto* pindexWalk = pindex; - while (pindexWalk != nullptr) { - if (pindex->nHeight - pindexWalk->nHeight > 5) { - // no need to check further down, 6 confs is safe to assume that TXs below this height won't be - // islocked anymore if they aren't already - LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- tip and previous 5 blocks all safe\n", __func__); - break; - } - if (HasChainLock(pindexWalk->nHeight, pindexWalk->GetBlockHash())) { - // we don't care about islocks for TXs that are ChainLocked already - LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- chainlock at height %d\n", __func__, pindexWalk->nHeight); - break; - } - - auto txids = GetBlockTxs(pindexWalk->GetBlockHash()); - if (!txids) { - pindexWalk = pindexWalk->pprev; - continue; - } - - for (const auto& txid : *txids) { - int64_t txAge = 0; - { - LOCK(cs); - auto it = txFirstSeenTime.find(txid); - if (it != txFirstSeenTime.end()) { - txAge = GetTime().count() - it->second; - } - } - - if (txAge < WAIT_FOR_ISLOCK_TIMEOUT && !isman.IsLocked(txid)) { - LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- not signing block %s due to TX %s not being islocked and not old enough. age=%d\n", __func__, - pindexWalk->GetBlockHash().ToString(), txid.ToString(), txAge); - return; - } - } - - pindexWalk = pindexWalk->pprev; - } - } - - uint256 requestId = ::SerializeHash(std::make_pair(CLSIG_REQUESTID_PREFIX, pindex->nHeight)); - uint256 msgHash = pindex->GetBlockHash(); - - { - LOCK(cs); - if (bestChainLock.getHeight() >= pindex->nHeight) { - // might have happened while we didn't hold cs - return; - } - lastSignedHeight = pindex->nHeight; - lastSignedRequestId = requestId; - lastSignedMsgHash = msgHash; - } - - sigman.AsyncSignIfMember(Params().GetConsensus().llmqTypeChainLocks, shareman, requestId, msgHash); -} - void CChainLocksHandler::TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime) { if (tx->IsCoinBase() || tx->vin.empty()) { @@ -358,85 +265,34 @@ void CChainLocksHandler::BlockConnected(const std::shared_ptr& pbl } // We listen for BlockConnected so that we can collect all TX ids of all included TXs of newly received blocks - // We need this information later when we try to sign a new tip, so that we can determine if all included TXs are - // safe. - - LOCK(cs); - - auto it = blockTxs.find(pindex->GetBlockHash()); - if (it == blockTxs.end()) { - // we must create this entry even if there are no lockable transactions in the block, so that TrySignChainTip - // later knows about this block - it = blockTxs.emplace(pindex->GetBlockHash(), std::make_shared>()).first; - } - auto& txids = *it->second; - int64_t curTime = GetTime().count(); - - for (const auto& tx : pblock->vtx) { - if (tx->IsCoinBase() || tx->vin.empty()) { - continue; + { + LOCK(cs); + for (const auto& tx : pblock->vtx) { + if (!tx->IsCoinBase() && !tx->vin.empty()) { + txFirstSeenTime.emplace(tx->GetHash(), curTime); + } } - - txids.emplace(tx->GetHash()); - txFirstSeenTime.emplace(tx->GetHash(), curTime); } + // We need this information later when we try to sign a new tip, so that we can determine if all included TXs are safe. + if (m_signer) { + m_signer->UpdateBlockHashTxidMap(pindex->GetBlockHash(), pblock->vtx); + } } void CChainLocksHandler::BlockDisconnected(const std::shared_ptr& pblock, gsl::not_null pindexDisconnected) { - LOCK(cs); - blockTxs.erase(pindexDisconnected->GetBlockHash()); + if (m_signer) { + m_signer->EraseFromBlockHashTxidMap(pindexDisconnected->GetBlockHash()); + } } -CChainLocksHandler::BlockTxs::mapped_type CChainLocksHandler::GetBlockTxs(const uint256& blockHash) +int32_t CChainLocksHandler::GetBestChainLockHeight() const { AssertLockNotHeld(cs); - AssertLockNotHeld(cs_main); - - CChainLocksHandler::BlockTxs::mapped_type ret; - - { - LOCK(cs); - auto it = blockTxs.find(blockHash); - if (it != blockTxs.end()) { - ret = it->second; - } - } - if (!ret) { - // This should only happen when freshly started. - // If running for some time, SyncTransaction should have been called before which fills blockTxs. - LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- blockTxs for %s not found. Trying ReadBlockFromDisk\n", __func__, - blockHash.ToString()); - - uint32_t blockTime; - { - LOCK(::cs_main); - const auto* pindex = m_chainstate.m_blockman.LookupBlockIndex(blockHash); - CBlock block; - if (!ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { - return nullptr; - } - - ret = std::make_shared>(); - for (const auto& tx : block.vtx) { - if (tx->IsCoinBase() || tx->vin.empty()) { - continue; - } - ret->emplace(tx->GetHash()); - } - - blockTime = block.nTime; - } - - LOCK(cs); - blockTxs.emplace(blockHash, ret); - for (const auto& txid : *ret) { - txFirstSeenTime.emplace(txid, blockTime); - } - } - return ret; + LOCK(cs); + return bestChainLock.getHeight(); } bool CChainLocksHandler::IsTxSafeForMining(const uint256& txid) const @@ -460,17 +316,17 @@ void CChainLocksHandler::EnforceBestChainLock() AssertLockNotHeld(cs); AssertLockNotHeld(cs_main); - std::shared_ptr clsig; + std::shared_ptr clsig; const CBlockIndex* pindex; const CBlockIndex* currentBestChainLockBlockIndex; { LOCK(cs); - if (!isEnabled) { + if (!IsEnabled()) { return; } - clsig = std::make_shared(bestChainLockWithKnownBlock); + clsig = std::make_shared(bestChainLockWithKnownBlock); pindex = currentBestChainLockBlockIndex = this->bestChainLockBlockIndex; if (currentBestChainLockBlockIndex == nullptr) { @@ -510,51 +366,20 @@ void CChainLocksHandler::EnforceBestChainLock() ::g_stats_client->gauge("chainlocks.blockHeight", clsig->getHeight(), 1.0f); } -MessageProcessingResult CChainLocksHandler::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig) -{ - if (!isEnabled) { - return {}; - } - - CChainLockSig clsig; - { - LOCK(cs); - - if (recoveredSig.getId() != lastSignedRequestId || recoveredSig.getMsgHash() != lastSignedMsgHash) { - // this is not what we signed, so lets not create a CLSIG for it - return {}; - } - if (bestChainLock.getHeight() >= lastSignedHeight) { - // already got the same or a better CLSIG through the CLSIG message - return {}; - } - - - clsig = CChainLockSig(lastSignedHeight, lastSignedMsgHash, recoveredSig.sig.Get()); - } - return ProcessNewChainLock(-1, clsig, ::SerializeHash(clsig)); -} - -bool CChainLocksHandler::HasChainLock(int nHeight, const uint256& blockHash) const -{ - LOCK(cs); - return InternalHasChainLock(nHeight, blockHash); -} - - -VerifyRecSigStatus CChainLocksHandler::VerifyChainLock(const CChainLockSig& clsig) const +VerifyRecSigStatus CChainLocksHandler::VerifyChainLock(const chainlock::ChainLockSig& clsig) const { const auto llmqType = Params().GetConsensus().llmqTypeChainLocks; - const uint256 nRequestId = ::SerializeHash(std::make_pair(llmq::CLSIG_REQUESTID_PREFIX, clsig.getHeight())); + const uint256 nRequestId = ::SerializeHash(std::make_pair(chainlock::CLSIG_REQUESTID_PREFIX, clsig.getHeight())); return llmq::VerifyRecoveredSig(llmqType, m_chainstate.m_chain, qman, clsig.getHeight(), nRequestId, clsig.getBlockHash(), clsig.getSig()); } -bool CChainLocksHandler::InternalHasChainLock(int nHeight, const uint256& blockHash) const +bool CChainLocksHandler::HasChainLock(int nHeight, const uint256& blockHash) const { - AssertLockHeld(cs); + AssertLockNotHeld(cs); + LOCK(cs); - if (!isEnabled) { + if (!IsEnabled()) { return false; } @@ -576,15 +401,10 @@ bool CChainLocksHandler::InternalHasChainLock(int nHeight, const uint256& blockH bool CChainLocksHandler::HasConflictingChainLock(int nHeight, const uint256& blockHash) const { + AssertLockNotHeld(cs); LOCK(cs); - return InternalHasConflictingChainLock(nHeight, blockHash); -} -bool CChainLocksHandler::InternalHasConflictingChainLock(int nHeight, const uint256& blockHash) const -{ - AssertLockHeld(cs); - - if (!isEnabled) { + if (!IsEnabled()) { return false; } @@ -626,23 +446,19 @@ void CChainLocksHandler::Cleanup() } } } - // need mempool.cs due to GetTransaction calls - LOCK2(::cs_main, mempool.cs); - LOCK(cs); - for (auto it = blockTxs.begin(); it != blockTxs.end(); ) { - const auto* pindex = m_chainstate.m_blockman.LookupBlockIndex(it->first); - if (InternalHasChainLock(pindex->nHeight, pindex->GetBlockHash())) { - for (const auto& txid : *it->second) { + if (m_signer) { + const auto cleanup_txes{m_signer->Cleanup()}; + LOCK(cs); + for (const auto& tx : cleanup_txes) { + for (const auto& txid : *tx) { txFirstSeenTime.erase(txid); } - it = blockTxs.erase(it); - } else if (InternalHasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) { - it = blockTxs.erase(it); - } else { - ++it; } } + + LOCK(::cs_main); + LOCK2(mempool.cs, cs); // need mempool.cs due to GetTransaction calls for (auto it = txFirstSeenTime.begin(); it != txFirstSeenTime.end(); ) { uint256 hashBlock; if (auto tx = GetTransaction(nullptr, &mempool, it->first, Params().GetConsensus(), hashBlock); !tx) { @@ -661,10 +477,4 @@ void CChainLocksHandler::Cleanup() } } } - -bool AreChainLocksEnabled(const CSporkManager& sporkman) -{ - return sporkman.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED); -} - } // namespace llmq diff --git a/src/llmq/chainlocks.h b/src/chainlock/chainlock.h similarity index 55% rename from src/llmq/chainlocks.h rename to src/chainlock/chainlock.h index c91fa946bc01e..69ba8130ae75b 100644 --- a/src/llmq/chainlocks.h +++ b/src/chainlock/chainlock.h @@ -2,19 +2,18 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_LLMQ_CHAINLOCKS_H -#define BITCOIN_LLMQ_CHAINLOCKS_H +#ifndef BITCOIN_CHAINLOCK_CHAINLOCK_H +#define BITCOIN_CHAINLOCK_CHAINLOCK_H -#include +#include -#include // For ReadLE64 -#include -#include // For NodeId -#include #include +#include #include #include +#include + #include #include @@ -29,55 +28,39 @@ class CScheduler; class CSporkManager; class CTxMemPool; -namespace llmq -{ +using NodeId = int64_t; + +namespace llmq { class CInstantSendManager; +class CQuorumManager; class CSigningManager; class CSigSharesManager; enum class VerifyRecSigStatus; -class CChainLocksHandler : public CRecoveredSigsListener +class CChainLocksHandler final : public chainlock::ChainLockSignerParent { - static constexpr int64_t CLEANUP_INTERVAL = 1000 * 30; - static constexpr int64_t CLEANUP_SEEN_TIMEOUT = 24 * 60 * 60 * 1000; - - // how long to wait for islocks until we consider a block with non-islocked TXs to be safe to sign - static constexpr int64_t WAIT_FOR_ISLOCK_TIMEOUT = 10 * 60; - private: CChainState& m_chainstate; CQuorumManager& qman; - CSigningManager& sigman; - CSigSharesManager& shareman; CSporkManager& spork_manager; CTxMemPool& mempool; const CMasternodeSync& m_mn_sync; - - const bool m_is_masternode; std::unique_ptr scheduler; std::unique_ptr scheduler_thread; + + std::unique_ptr m_signer{nullptr}; + mutable Mutex cs; std::atomic tryLockChainTipScheduled{false}; std::atomic isEnabled{false}; uint256 bestChainLockHash GUARDED_BY(cs); - CChainLockSig bestChainLock GUARDED_BY(cs); + chainlock::ChainLockSig bestChainLock GUARDED_BY(cs); - CChainLockSig bestChainLockWithKnownBlock GUARDED_BY(cs); + chainlock::ChainLockSig bestChainLockWithKnownBlock GUARDED_BY(cs); const CBlockIndex* bestChainLockBlockIndex GUARDED_BY(cs) {nullptr}; const CBlockIndex* lastNotifyChainLockBlockIndex GUARDED_BY(cs) {nullptr}; - int32_t lastSignedHeight GUARDED_BY(cs) {-1}; - uint256 lastSignedRequestId GUARDED_BY(cs); - uint256 lastSignedMsgHash GUARDED_BY(cs); - - // We keep track of txids from recently received blocks so that we can check if all TXs got islocked - struct BlockHasher - { - size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); } - }; - using BlockTxs = std::unordered_map>, BlockHasher>; - BlockTxs blockTxs GUARDED_BY(cs); std::unordered_map txFirstSeenTime GUARDED_BY(cs); std::map seenChainLocks GUARDED_BY(cs); @@ -94,11 +77,14 @@ class CChainLocksHandler : public CRecoveredSigsListener void Stop(); bool AlreadyHave(const CInv& inv) const EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool GetChainLockByHash(const uint256& hash, CChainLockSig& ret) const EXCLUSIVE_LOCKS_REQUIRED(!cs); - CChainLockSig GetBestChainLock() const EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool GetChainLockByHash(const uint256& hash, chainlock::ChainLockSig& ret) const EXCLUSIVE_LOCKS_REQUIRED(!cs); + chainlock::ChainLockSig GetBestChainLock() const EXCLUSIVE_LOCKS_REQUIRED(!cs); + void UpdateTxFirstSeenMap(const std::unordered_set& tx, const int64_t& time) override + EXCLUSIVE_LOCKS_REQUIRED(!cs); - [[nodiscard]] MessageProcessingResult ProcessNewChainLock(NodeId from, const CChainLockSig& clsig, - const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(!cs); + [[nodiscard]] MessageProcessingResult ProcessNewChainLock(NodeId from, const chainlock::ChainLockSig& clsig, + const uint256& hash) override + EXCLUSIVE_LOCKS_REQUIRED(!cs); void AcceptedBlockHeader(gsl::not_null pindexNew) EXCLUSIVE_LOCKS_REQUIRED(!cs); void UpdatedBlockTip(const llmq::CInstantSendManager& isman); @@ -106,28 +92,25 @@ class CChainLocksHandler : public CRecoveredSigsListener void BlockConnected(const std::shared_ptr& pblock, gsl::not_null pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs); void BlockDisconnected(const std::shared_ptr& pblock, gsl::not_null pindexDisconnected) EXCLUSIVE_LOCKS_REQUIRED(!cs); void CheckActiveState() EXCLUSIVE_LOCKS_REQUIRED(!cs); - void TrySignChainTip(const llmq::CInstantSendManager& isman) EXCLUSIVE_LOCKS_REQUIRED(!cs); void EnforceBestChainLock() EXCLUSIVE_LOCKS_REQUIRED(!cs); - [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) override - EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool HasChainLock(int nHeight, const uint256& blockHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool HasConflictingChainLock(int nHeight, const uint256& blockHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); - VerifyRecSigStatus VerifyChainLock(const CChainLockSig& clsig) const; + bool HasChainLock(int nHeight, const uint256& blockHash) const override + EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool HasConflictingChainLock(int nHeight, const uint256& blockHash) const override + EXCLUSIVE_LOCKS_REQUIRED(!cs); + VerifyRecSigStatus VerifyChainLock(const chainlock::ChainLockSig& clsig) const; - bool IsTxSafeForMining(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(!cs); + [[nodiscard]] int32_t GetBestChainLockHeight() const override + EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool IsTxSafeForMining(const uint256& txid) const override + EXCLUSIVE_LOCKS_REQUIRED(!cs); + [[nodiscard]] bool IsEnabled() const override { return isEnabled; } private: - // these require locks to be held already - bool InternalHasChainLock(int nHeight, const uint256& blockHash) const EXCLUSIVE_LOCKS_REQUIRED(cs); - bool InternalHasConflictingChainLock(int nHeight, const uint256& blockHash) const EXCLUSIVE_LOCKS_REQUIRED(cs); - - BlockTxs::mapped_type GetBlockTxs(const uint256& blockHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); - void Cleanup() EXCLUSIVE_LOCKS_REQUIRED(!cs); }; bool AreChainLocksEnabled(const CSporkManager& sporkman); } // namespace llmq -#endif // BITCOIN_LLMQ_CHAINLOCKS_H +#endif // BITCOIN_CHAINLOCK_CHAINLOCK_H diff --git a/src/chainlock/clsig.cpp b/src/chainlock/clsig.cpp new file mode 100644 index 0000000000000..163c8bad52715 --- /dev/null +++ b/src/chainlock/clsig.cpp @@ -0,0 +1,26 @@ +// Copyright (c) 2021-2022 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +namespace chainlock { +const std::string CLSIG_REQUESTID_PREFIX = "clsig"; + +ChainLockSig::ChainLockSig() = default; +ChainLockSig::~ChainLockSig() = default; + +ChainLockSig::ChainLockSig(int32_t nHeight, const uint256& blockHash, const CBLSSignature& sig) : + nHeight{nHeight}, + blockHash{blockHash}, + sig{sig} +{ +} + +std::string ChainLockSig::ToString() const +{ + return strprintf("ChainLockSig(nHeight=%d, blockHash=%s)", nHeight, blockHash.ToString()); +} +} // namespace chainlock diff --git a/src/chainlock/clsig.h b/src/chainlock/clsig.h new file mode 100644 index 0000000000000..9efd399c27899 --- /dev/null +++ b/src/chainlock/clsig.h @@ -0,0 +1,43 @@ +// Copyright (c) 2019-2022 The Dash Core developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CHAINLOCK_CLSIG_H +#define BITCOIN_CHAINLOCK_CLSIG_H + +#include +#include + +#include + +#include + +namespace chainlock { +extern const std::string CLSIG_REQUESTID_PREFIX; + +struct ChainLockSig { +private: + int32_t nHeight{-1}; + uint256 blockHash; + CBLSSignature sig; + +public: + ChainLockSig(); + ~ChainLockSig(); + + ChainLockSig(int32_t nHeight, const uint256& blockHash, const CBLSSignature& sig); + + [[nodiscard]] int32_t getHeight() const { return nHeight; } + [[nodiscard]] const uint256& getBlockHash() const { return blockHash; } + [[nodiscard]] const CBLSSignature& getSig() const { return sig; } + [[nodiscard]] bool IsNull() const { return nHeight == -1 && blockHash == uint256(); } + [[nodiscard]] std::string ToString() const; + + SERIALIZE_METHODS(ChainLockSig, obj) + { + READWRITE(obj.nHeight, obj.blockHash, obj.sig); + } +}; +} // namespace chainlock + +#endif // BITCOIN_CHAINLOCK_CLSIG_H diff --git a/src/chainlock/signing.cpp b/src/chainlock/signing.cpp new file mode 100644 index 0000000000000..0ef9aa550dfb2 --- /dev/null +++ b/src/chainlock/signing.cpp @@ -0,0 +1,259 @@ +// Copyright (c) 2019-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +#include +#include +#include +#include + +using node::ReadBlockFromDisk; + +namespace chainlock { +ChainLockSigner::ChainLockSigner(CChainState& chainstate, ChainLockSignerParent& clhandler, llmq::CSigningManager& sigman, + llmq::CSigSharesManager& shareman, CSporkManager& sporkman, + const CMasternodeSync& mn_sync) : + m_chainstate{chainstate}, + m_clhandler{clhandler}, + m_sigman{sigman}, + m_shareman{shareman}, + m_sporkman{sporkman}, + m_mn_sync{mn_sync} +{ +} + +ChainLockSigner::~ChainLockSigner() = default; + +void ChainLockSigner::Start() +{ + m_sigman.RegisterRecoveredSigsListener(this); +} + +void ChainLockSigner::Stop() +{ + m_sigman.UnregisterRecoveredSigsListener(this); +} + +void ChainLockSigner::TrySignChainTip(const llmq::CInstantSendManager& isman) +{ + if (!m_mn_sync.IsBlockchainSynced()) { + return; + } + + if (!m_clhandler.IsEnabled()) { + return; + } + + if (m_sporkman.GetSporkValue(SPORK_19_CHAINLOCKS_ENABLED) != 0) { + // ChainLocks signing not enabled + return; + } + + const CBlockIndex* pindex = WITH_LOCK(::cs_main, return m_chainstate.m_chain.Tip()); + + if (pindex->pprev == nullptr) { + return; + } + + // DIP8 defines a process called "Signing attempts" which should run before the CLSIG is finalized + // To simplify the initial implementation, we skip this process and directly try to create a CLSIG + // This will fail when multiple blocks compete, but we accept this for the initial implementation. + // Later, we'll add the multiple attempts process. + + { + LOCK(cs_signer); + + if (pindex->nHeight == lastSignedHeight) { + // already signed this one + return; + } + } + + if (m_clhandler.GetBestChainLockHeight() >= pindex->nHeight) { + // already got the same CLSIG or a better one + return; + } + + if (m_clhandler.HasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) { + // don't sign if another conflicting CLSIG is already present. EnforceBestChainLock will later enforce + // the correct chain. + return; + } + + LogPrint(BCLog::CHAINLOCKS, "%s -- trying to sign %s, height=%d\n", __func__, pindex->GetBlockHash().ToString(), pindex->nHeight); + + // When the new IX system is activated, we only try to ChainLock blocks which include safe transactions. A TX is + // considered safe when it is islocked or at least known since 10 minutes (from mempool or block). These checks are + // performed for the tip (which we try to sign) and the previous 5 blocks. If a ChainLocked block is found on the + // way down, we consider all TXs to be safe. + if (isman.IsInstantSendEnabled() && isman.RejectConflictingBlocks()) { + const auto* pindexWalk = pindex; + while (pindexWalk != nullptr) { + if (pindex->nHeight - pindexWalk->nHeight > 5) { + // no need to check further down, 6 confs is safe to assume that TXs below this height won't be + // islocked anymore if they aren't already + LogPrint(BCLog::CHAINLOCKS, "%s -- tip and previous 5 blocks all safe\n", __func__); + break; + } + if (m_clhandler.HasChainLock(pindexWalk->nHeight, pindexWalk->GetBlockHash())) { + // we don't care about islocks for TXs that are ChainLocked already + LogPrint(BCLog::CHAINLOCKS, "%s -- chainlock at height %d\n", __func__, pindexWalk->nHeight); + break; + } + + auto txids = GetBlockTxs(pindexWalk->GetBlockHash()); + if (!txids) { + pindexWalk = pindexWalk->pprev; + continue; + } + + for (const auto& txid : *txids) { + if (!m_clhandler.IsTxSafeForMining(txid) && !isman.IsLocked(txid)) { + LogPrint(BCLog::CHAINLOCKS, "%s -- not signing block %s due to TX %s not being islocked and not old enough.\n", __func__, + pindexWalk->GetBlockHash().ToString(), txid.ToString()); + return; + } + } + + pindexWalk = pindexWalk->pprev; + } + } + + uint256 requestId = ::SerializeHash(std::make_pair(CLSIG_REQUESTID_PREFIX, pindex->nHeight)); + uint256 msgHash = pindex->GetBlockHash(); + + if (m_clhandler.GetBestChainLockHeight() >= pindex->nHeight) { + // might have happened while we didn't hold cs + return; + } + { + LOCK(cs_signer); + lastSignedHeight = pindex->nHeight; + lastSignedRequestId = requestId; + lastSignedMsgHash = msgHash; + } + + m_sigman.AsyncSignIfMember(Params().GetConsensus().llmqTypeChainLocks, m_shareman, requestId, msgHash); +} + +void ChainLockSigner::EraseFromBlockHashTxidMap(const uint256& hash) +{ + AssertLockNotHeld(cs_signer); + LOCK(cs_signer); + blockTxs.erase(hash); +} + +void ChainLockSigner::UpdateBlockHashTxidMap(const uint256& hash, const std::vector& vtx) +{ + AssertLockNotHeld(cs_signer); + LOCK(cs_signer); + auto it = blockTxs.find(hash); + if (it == blockTxs.end()) { + // We must create this entry even if there are no lockable transactions in the block, so that TrySignChainTip + // later knows about this block + it = blockTxs.emplace(hash, std::make_shared>()).first; + } + auto& txids = *it->second; + for (const auto& tx : vtx) { + if (!tx->IsCoinBase() && !tx->vin.empty()) { + txids.emplace(tx->GetHash()); + } + } +} + +ChainLockSigner::BlockTxs::mapped_type ChainLockSigner::GetBlockTxs(const uint256& blockHash) +{ + AssertLockNotHeld(cs_signer); + AssertLockNotHeld(::cs_main); + + ChainLockSigner::BlockTxs::mapped_type ret; + + { + LOCK(cs_signer); + auto it = blockTxs.find(blockHash); + if (it != blockTxs.end()) { + ret = it->second; + } + } + if (!ret) { + // This should only happen when freshly started. + // If running for some time, SyncTransaction should have been called before which fills blockTxs. + LogPrint(BCLog::CHAINLOCKS, "%s -- blockTxs for %s not found. Trying ReadBlockFromDisk\n", __func__, + blockHash.ToString()); + + uint32_t blockTime; + { + LOCK(::cs_main); + const auto* pindex = m_chainstate.m_blockman.LookupBlockIndex(blockHash); + CBlock block; + if (!ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { + return nullptr; + } + + ret = std::make_shared>(); + for (const auto& tx : block.vtx) { + if (tx->IsCoinBase() || tx->vin.empty()) { + continue; + } + ret->emplace(tx->GetHash()); + } + + blockTime = block.nTime; + } + { + LOCK(cs_signer); + blockTxs.emplace(blockHash, ret); + } + m_clhandler.UpdateTxFirstSeenMap(*ret, blockTime); + } + return ret; +} + +MessageProcessingResult ChainLockSigner::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig) +{ + if (!m_clhandler.IsEnabled()) { + return {}; + } + + ChainLockSig clsig; + { + LOCK(cs_signer); + + if (recoveredSig.getId() != lastSignedRequestId || recoveredSig.getMsgHash() != lastSignedMsgHash) { + // this is not what we signed, so lets not create a CLSIG for it + return {}; + } + if (m_clhandler.GetBestChainLockHeight() >= lastSignedHeight) { + // already got the same or a better CLSIG through the CLSIG message + return {}; + } + + clsig = ChainLockSig(lastSignedHeight, lastSignedMsgHash, recoveredSig.sig.Get()); + } + return m_clhandler.ProcessNewChainLock(-1, clsig, ::SerializeHash(clsig)); +} + +std::vector>> ChainLockSigner::Cleanup() +{ + AssertLockNotHeld(cs_signer); + std::vector>> removed; + LOCK2(::cs_main, cs_signer); + for (auto it = blockTxs.begin(); it != blockTxs.end(); ) { + const auto* pindex = m_chainstate.m_blockman.LookupBlockIndex(it->first); + if (m_clhandler.HasChainLock(pindex->nHeight, pindex->GetBlockHash())) { + removed.push_back(it->second); + it = blockTxs.erase(it); + } else if (m_clhandler.HasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) { + it = blockTxs.erase(it); + } else { + ++it; + } + } + return removed; +} +} // namespace chainlock diff --git a/src/chainlock/signing.h b/src/chainlock/signing.h new file mode 100644 index 0000000000000..a07df18265cd8 --- /dev/null +++ b/src/chainlock/signing.h @@ -0,0 +1,89 @@ +// Copyright (c) 2019-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CHAINLOCK_SIGNING_H +#define BITCOIN_CHAINLOCK_SIGNING_H + +#include +#include + +class CMasternodeSync; +class CSporkManager; +struct MessageProcessingResult; +namespace llmq { +class CChainLocksHandler; +class CInstantSendManager; +class CRecoveredSig; +class CSigningManager; +class CSigSharesManager; +} // namespace llmq + +namespace chainlock { +class ChainLockSignerParent +{ +public: + virtual ~ChainLockSignerParent() = default; + + virtual int32_t GetBestChainLockHeight() const = 0; + virtual bool HasChainLock(int nHeight, const uint256& blockHash) const = 0; + virtual bool HasConflictingChainLock(int nHeight, const uint256& blockHash) const = 0; + virtual bool IsEnabled() const = 0; + virtual bool IsTxSafeForMining(const uint256& txid) const = 0; + virtual MessageProcessingResult ProcessNewChainLock(NodeId from, const ChainLockSig& clsig, const uint256& hash) = 0; + virtual void UpdateTxFirstSeenMap(const std::unordered_set& tx, const int64_t& time) = 0; +}; + +class ChainLockSigner final : public llmq::CRecoveredSigsListener +{ +private: + CChainState& m_chainstate; + ChainLockSignerParent& m_clhandler; + llmq::CSigningManager& m_sigman; + llmq::CSigSharesManager& m_shareman; + CSporkManager& m_sporkman; + const CMasternodeSync& m_mn_sync; + +private: + // We keep track of txids from recently received blocks so that we can check if all TXs got islocked + struct BlockHasher { + size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); } + }; + using BlockTxs = std::unordered_map>, BlockHasher>; + +private: + mutable Mutex cs_signer; + + BlockTxs blockTxs GUARDED_BY(cs_signer); + int32_t lastSignedHeight GUARDED_BY(cs_signer){-1}; + uint256 lastSignedRequestId GUARDED_BY(cs_signer); + uint256 lastSignedMsgHash GUARDED_BY(cs_signer); + +public: + explicit ChainLockSigner(CChainState& chainstate, ChainLockSignerParent& clhandler, llmq::CSigningManager& sigman, + llmq::CSigSharesManager& shareman, CSporkManager& sporkman, const CMasternodeSync& mn_sync); + ~ChainLockSigner(); + + void Start(); + void Stop(); + + void EraseFromBlockHashTxidMap(const uint256& hash) + EXCLUSIVE_LOCKS_REQUIRED(!cs_signer); + void UpdateBlockHashTxidMap(const uint256& hash, const std::vector& vtx) + EXCLUSIVE_LOCKS_REQUIRED(!cs_signer); + + void TrySignChainTip(const llmq::CInstantSendManager& isman) + EXCLUSIVE_LOCKS_REQUIRED(!cs_signer); + [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig) override + EXCLUSIVE_LOCKS_REQUIRED(!cs_signer); + + [[nodiscard]] std::vector>> Cleanup() + EXCLUSIVE_LOCKS_REQUIRED(!cs_signer); + +private: + [[nodiscard]] BlockTxs::mapped_type GetBlockTxs(const uint256& blockHash) + EXCLUSIVE_LOCKS_REQUIRED(!cs_signer); +}; +} // namespace chainlock + +#endif // BITCOIN_CHAINLOCK_SIGNING_H diff --git a/src/coinjoin/coinjoin.cpp b/src/coinjoin/coinjoin.cpp index 641a1e7c02d31..07ddb2018090f 100644 --- a/src/coinjoin/coinjoin.cpp +++ b/src/coinjoin/coinjoin.cpp @@ -4,20 +4,21 @@ #include -#include #include #include -#include -#include -#include -#include #include #include #include #include #include - #include + +#include +#include +#include +#include +#include + #include constexpr static CAmount DEFAULT_MAX_RAW_TX_FEE{COIN / 10}; diff --git a/src/dsnotificationinterface.cpp b/src/dsnotificationinterface.cpp index 184689904ca47..1b6d80b687375 100644 --- a/src/dsnotificationinterface.cpp +++ b/src/dsnotificationinterface.cpp @@ -12,10 +12,10 @@ #include #include +#include #include #include #include -#include #include #include #include @@ -143,7 +143,8 @@ void CDSNotificationInterface::NotifyMasternodeListChanged(bool undo, const CDet } } -void CDSNotificationInterface::NotifyChainLock(const CBlockIndex* pindex, const std::shared_ptr& clsig) +void CDSNotificationInterface::NotifyChainLock(const CBlockIndex* pindex, + const std::shared_ptr& clsig) { assert(m_cj_ctx && m_llmq_ctx); diff --git a/src/dsnotificationinterface.h b/src/dsnotificationinterface.h index 92ee04aac1d36..6ca8634e2cc1c 100644 --- a/src/dsnotificationinterface.h +++ b/src/dsnotificationinterface.h @@ -46,7 +46,7 @@ class CDSNotificationInterface : public CValidationInterface void BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindex) override; void BlockDisconnected(const std::shared_ptr& pblock, const CBlockIndex* pindexDisconnected) override; void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff) override; - void NotifyChainLock(const CBlockIndex* pindex, const std::shared_ptr& clsig) override; + void NotifyChainLock(const CBlockIndex* pindex, const std::shared_ptr& clsig) override; private: CConnman& m_connman; diff --git a/src/evo/chainhelper.cpp b/src/evo/chainhelper.cpp index bda004ab14b30..d4661d71b7246 100644 --- a/src/evo/chainhelper.cpp +++ b/src/evo/chainhelper.cpp @@ -5,10 +5,11 @@ #include #include + +#include #include #include #include -#include #include CChainstateHelper::CChainstateHelper(CCreditPoolManager& cpoolman, CDeterministicMNManager& dmnman, diff --git a/src/evo/specialtxman.cpp b/src/evo/specialtxman.cpp index f0141922f4609..80fc0cabbb97c 100644 --- a/src/evo/specialtxman.cpp +++ b/src/evo/specialtxman.cpp @@ -8,6 +8,13 @@ #include #include #include +#include +#include +#include +#include + +#include +#include #include #include #include @@ -15,14 +22,9 @@ #include #include #include -#include -#include #include #include #include -#include -#include -#include static bool CheckCbTxBestChainlock(const CCbTx& cbTx, const CBlockIndex* pindex, const llmq::CChainLocksHandler& chainlock_handler, BlockValidationState& state) @@ -76,7 +78,7 @@ static bool CheckCbTxBestChainlock(const CCbTx& cbTx, const CBlockIndex* pindex, } uint256 curBlockCoinbaseCLBlockHash = pindex->GetAncestor(curBlockCoinbaseCLHeight)->GetBlockHash(); if (chainlock_handler.VerifyChainLock( - llmq::CChainLockSig(curBlockCoinbaseCLHeight, curBlockCoinbaseCLBlockHash, cbTx.bestCLSignature)) != + chainlock::ChainLockSig(curBlockCoinbaseCLHeight, curBlockCoinbaseCLBlockHash, cbTx.bestCLSignature)) != llmq::VerifyRecSigStatus::Valid) { return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-invalid-clsig"); } diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 4a228bc18537c..ea182b3dfb604 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -8,18 +8,18 @@ #include #include #include -#include #include #include #include #include +#include #include -#include #include #include #include #include +#include #include diff --git a/src/instantsend/signing.cpp b/src/instantsend/signing.cpp index 7fb3c7d8ecffe..46ea06702de64 100644 --- a/src/instantsend/signing.cpp +++ b/src/instantsend/signing.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 5dc214fa54a72..19ebf9d6f3bf2 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -31,12 +31,12 @@ enum class MemPoolRemovalReason; struct bilingual_str; struct CBlockLocator; struct FeeCalculation; +namespace chainlock { +struct ChainLockSig; +} // namespace chainlock namespace instantsend { struct InstantSendLock; } // namespace instantsend -namespace llmq { -class CChainLockSig; -} // namespace llmq namespace node { struct NodeContext; } // namespace node @@ -267,7 +267,7 @@ class Chain virtual void blockDisconnected(const CBlock& block, int height) {} virtual void updatedBlockTip() {} virtual void chainStateFlushed(const CBlockLocator& locator) {} - virtual void notifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr& clsig) {} + virtual void notifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr& clsig) {} virtual void notifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) {} }; diff --git a/src/llmq/clsig.cpp b/src/llmq/clsig.cpp deleted file mode 100644 index 686b2d15bfcfa..0000000000000 --- a/src/llmq/clsig.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2021-2022 The Dash Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include - -namespace llmq { - const std::string CLSIG_REQUESTID_PREFIX = "clsig"; - - std::string CChainLockSig::ToString() const { - return strprintf("CChainLockSig(nHeight=%d, blockHash=%s)", nHeight, blockHash.ToString()); - } - int32_t CChainLockSig::getHeight() const { - return nHeight; - } - const uint256& CChainLockSig::getBlockHash() const { - return blockHash; - } - const CBLSSignature& CChainLockSig::getSig() const { - return sig; - } - bool CChainLockSig::IsNull() const - { - return nHeight == -1 && blockHash == uint256(); - } -} diff --git a/src/llmq/clsig.h b/src/llmq/clsig.h deleted file mode 100644 index f8e0ea9629ac2..0000000000000 --- a/src/llmq/clsig.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2019-2022 The Dash Core developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_LLMQ_CLSIG_H -#define BITCOIN_LLMQ_CLSIG_H - -#include -#include -#include - -namespace llmq -{ - -extern const std::string CLSIG_REQUESTID_PREFIX; - -class CChainLockSig -{ -private: - int32_t nHeight{-1}; - uint256 blockHash; - CBLSSignature sig; - -public: - CChainLockSig(int32_t nHeight, const uint256& blockHash, const CBLSSignature& sig) : - nHeight(nHeight), - blockHash(blockHash), - sig(sig) - {} - CChainLockSig() = default; - - - [[nodiscard]] int32_t getHeight() const; - [[nodiscard]] const uint256& getBlockHash() const; - [[nodiscard]] const CBLSSignature& getSig() const; - [[nodiscard]] bool IsNull() const; - [[nodiscard]] std::string ToString() const; - - SERIALIZE_METHODS(CChainLockSig, obj) - { - READWRITE(obj.nHeight, obj.blockHash, obj.sig); - } -}; -} // namespace llmq - -#endif // BITCOIN_LLMQ_CLSIG_H diff --git a/src/llmq/context.cpp b/src/llmq/context.cpp index 87ed6f4709fe9..e2a60f21420b3 100644 --- a/src/llmq/context.cpp +++ b/src/llmq/context.cpp @@ -5,9 +5,9 @@ #include #include +#include #include #include -#include #include #include #include diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 1d634907c5bc9..eb57d9ee1b5ab 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -59,13 +59,13 @@ #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -2858,7 +2858,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic } if (!push && (inv.type == MSG_CLSIG)) { - llmq::CChainLockSig o; + chainlock::ChainLockSig o; if (m_llmq_ctx->clhandler->GetChainLockByHash(inv.hash, o)) { m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::CLSIG, o)); push = true; @@ -5282,7 +5282,7 @@ void PeerManagerImpl::ProcessMessage( if (msg_type == NetMsgType::CLSIG) { if (llmq::AreChainLocksEnabled(m_sporkman)) { - llmq::CChainLockSig clsig; + chainlock::ChainLockSig clsig; vRecv >> clsig; const uint256& hash = ::SerializeHash(clsig); WITH_LOCK(::cs_main, EraseObjectRequest(pfrom.GetId(), CInv{MSG_CLSIG, hash})); diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 493c8606c86c6..3f08db154699c 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -21,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -653,7 +653,7 @@ class NotificationsProxy : public CValidationInterface m_notifications->updatedBlockTip(); } void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->chainStateFlushed(locator); } - void NotifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr& clsig) override + void NotifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr& clsig) override { m_notifications->notifyChainLock(pindexChainLock, clsig); } diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 7409093904b06..8b2626570da11 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -35,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -127,7 +127,7 @@ static bool CalcCbTxBestChainlock(const llmq::CChainLocksHandler& chainlock_hand auto best_clsig = chainlock_handler.GetBestChainLock(); if (best_clsig.getHeight() < Params().GetConsensus().DeploymentHeight(Consensus::DEPLOYMENT_V19)) { // We don't want legacy BLS ChainLocks in CbTx (can happen on regtest/devenets) - best_clsig = llmq::CChainLockSig{}; + best_clsig = chainlock::ChainLockSig{}; } if (best_clsig.getHeight() == pindexPrev->nHeight) { // Our best CL is the newest one possible diff --git a/src/rest.cpp b/src/rest.cpp index 790b55af47acc..9771a2f62327f 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -6,13 +6,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include #include diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index ae6ca2b23ea84..b9fb546903a49 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -49,13 +48,14 @@ #include #include +#include #include #include #include #include #include #include -#include +#include #include @@ -268,7 +268,7 @@ static RPCHelpMan getbestchainlock() const NodeContext& node = EnsureAnyNodeContext(request.context); const LLMQContext& llmq_ctx = EnsureLLMQContext(node); - const llmq::CChainLockSig clsig = llmq_ctx.clhandler->GetBestChainLock(); + const chainlock::ChainLockSig clsig = llmq_ctx.clhandler->GetBestChainLock(); if (clsig.IsNull()) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to find any ChainLock"); } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index ec3723e1d9bd1..d3d28d516c005 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -5,6 +5,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include @@ -17,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index f0854b3371745..c25cb717dfb2a 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -13,11 +13,9 @@ #include #include -#include +#include #include - #include -#include #include #include #include @@ -28,6 +26,7 @@ #include #include #include +#include #include #include @@ -1021,7 +1020,8 @@ static RPCHelpMan verifychainlock() } const LLMQContext& llmq_ctx = EnsureLLMQContext(node); - return llmq_ctx.clhandler->VerifyChainLock(llmq::CChainLockSig(nBlockHeight, nBlockHash, sig)) == llmq::VerifyRecSigStatus::Valid; + return llmq_ctx.clhandler->VerifyChainLock(chainlock::ChainLockSig(nBlockHeight, nBlockHash, sig)) == + llmq::VerifyRecSigStatus::Valid; }, }; } @@ -1132,7 +1132,7 @@ static RPCHelpMan submitchainlock() } - const auto clsig{llmq::CChainLockSig(nBlockHeight, nBlockHash, sig)}; + const auto clsig{chainlock::ChainLockSig(nBlockHeight, nBlockHash, sig)}; const llmq::VerifyRecSigStatus ret{llmq_ctx.clhandler->VerifyChainLock(clsig)}; if (ret == llmq::VerifyRecSigStatus::NoQuorum) { LOCK(cs_main); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 27aa042a927f2..12b4ef5709147 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -48,11 +48,11 @@ #include #include +#include #include #include #include #include -#include #include #include diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index 5b458ba0a5414..73f255cbf841b 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -24,7 +24,6 @@ #include #include -#include #include #include #include diff --git a/src/test/llmq_chainlock_tests.cpp b/src/test/llmq_chainlock_tests.cpp index 0f364b1e40469..69857f193b8b7 100644 --- a/src/test/llmq_chainlock_tests.cpp +++ b/src/test/llmq_chainlock_tests.cpp @@ -5,12 +5,14 @@ #include #include -#include #include #include +#include + #include +using chainlock::ChainLockSig; using namespace llmq; using namespace llmq::testutils; @@ -19,7 +21,7 @@ BOOST_FIXTURE_TEST_SUITE(llmq_chainlock_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(chainlock_construction_test) { // Test default constructor - CChainLockSig clsig1; + ChainLockSig clsig1; BOOST_CHECK(clsig1.IsNull()); BOOST_CHECK_EQUAL(clsig1.getHeight(), -1); BOOST_CHECK(clsig1.getBlockHash().IsNull()); @@ -30,7 +32,7 @@ BOOST_AUTO_TEST_CASE(chainlock_construction_test) uint256 blockHash = GetTestBlockHash(1); CBLSSignature sig = CreateRandomBLSSignature(); - CChainLockSig clsig2(height, blockHash, sig); + ChainLockSig clsig2(height, blockHash, sig); BOOST_CHECK(!clsig2.IsNull()); BOOST_CHECK_EQUAL(clsig2.getHeight(), height); BOOST_CHECK(clsig2.getBlockHash() == blockHash); @@ -39,13 +41,13 @@ BOOST_AUTO_TEST_CASE(chainlock_construction_test) BOOST_AUTO_TEST_CASE(chainlock_null_test) { - CChainLockSig clsig; + ChainLockSig clsig; // Default constructed should be null BOOST_CHECK(clsig.IsNull()); // With height set but null hash, should not be null - clsig = CChainLockSig(100, uint256(), CBLSSignature()); + clsig = ChainLockSig(100, uint256(), CBLSSignature()); BOOST_CHECK(!clsig.IsNull()); // With valid data should not be null @@ -56,13 +58,13 @@ BOOST_AUTO_TEST_CASE(chainlock_null_test) BOOST_AUTO_TEST_CASE(chainlock_serialization_test) { // Test with valid chainlock - CChainLockSig clsig = CreateChainLock(67890, GetTestBlockHash(42)); + ChainLockSig clsig = CreateChainLock(67890, GetTestBlockHash(42)); // Test serialization preserves all fields CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << clsig; - CChainLockSig deserialized; + ChainLockSig deserialized; ss >> deserialized; BOOST_CHECK_EQUAL(clsig.getHeight(), deserialized.getHeight()); @@ -74,14 +76,14 @@ BOOST_AUTO_TEST_CASE(chainlock_serialization_test) BOOST_AUTO_TEST_CASE(chainlock_tostring_test) { // Test null chainlock - CChainLockSig nullClsig; + ChainLockSig nullClsig; std::string nullStr = nullClsig.ToString(); BOOST_CHECK(!nullStr.empty()); // Test valid chainlock int32_t height = 123456; uint256 blockHash = GetTestBlockHash(789); - CChainLockSig clsig = CreateChainLock(height, blockHash); + ChainLockSig clsig = CreateChainLock(height, blockHash); std::string str = clsig.ToString(); BOOST_CHECK(!str.empty()); @@ -94,23 +96,23 @@ BOOST_AUTO_TEST_CASE(chainlock_tostring_test) BOOST_AUTO_TEST_CASE(chainlock_edge_cases_test) { // Test with edge case heights - CChainLockSig clsig1 = CreateChainLock(0, GetTestBlockHash(1)); + ChainLockSig clsig1 = CreateChainLock(0, GetTestBlockHash(1)); BOOST_CHECK_EQUAL(clsig1.getHeight(), 0); BOOST_CHECK(!clsig1.IsNull()); - CChainLockSig clsig2 = CreateChainLock(std::numeric_limits::max(), GetTestBlockHash(2)); + ChainLockSig clsig2 = CreateChainLock(std::numeric_limits::max(), GetTestBlockHash(2)); BOOST_CHECK_EQUAL(clsig2.getHeight(), std::numeric_limits::max()); // Test serialization with extreme values CDataStream ss1(SER_NETWORK, PROTOCOL_VERSION); ss1 << clsig1; - CChainLockSig clsig1_deserialized; + ChainLockSig clsig1_deserialized; ss1 >> clsig1_deserialized; BOOST_CHECK_EQUAL(clsig1.getHeight(), clsig1_deserialized.getHeight()); CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); ss2 << clsig2; - CChainLockSig clsig2_deserialized; + ChainLockSig clsig2_deserialized; ss2 >> clsig2_deserialized; BOOST_CHECK_EQUAL(clsig2.getHeight(), clsig2_deserialized.getHeight()); } @@ -122,8 +124,8 @@ BOOST_AUTO_TEST_CASE(chainlock_comparison_test) uint256 blockHash = GetTestBlockHash(10); CBLSSignature sig = CreateRandomBLSSignature(); - CChainLockSig clsig1(height, blockHash, sig); - CChainLockSig clsig2(height, blockHash, sig); + ChainLockSig clsig1(height, blockHash, sig); + ChainLockSig clsig2(height, blockHash, sig); // Verify getters return same values BOOST_CHECK_EQUAL(clsig1.getHeight(), clsig2.getHeight()); @@ -131,17 +133,17 @@ BOOST_AUTO_TEST_CASE(chainlock_comparison_test) BOOST_CHECK(clsig1.getSig() == clsig2.getSig()); // Different chainlocks - CChainLockSig clsig3(height + 1, blockHash, sig); + ChainLockSig clsig3(height + 1, blockHash, sig); BOOST_CHECK(clsig1.getHeight() != clsig3.getHeight()); - CChainLockSig clsig4(height, GetTestBlockHash(11), sig); + ChainLockSig clsig4(height, GetTestBlockHash(11), sig); BOOST_CHECK(clsig1.getBlockHash() != clsig4.getBlockHash()); } BOOST_AUTO_TEST_CASE(chainlock_malformed_data_test) { // Test deserialization of truncated data - CChainLockSig clsig = CreateChainLock(1000, GetTestBlockHash(5)); + ChainLockSig clsig = CreateChainLock(1000, GetTestBlockHash(5)); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << clsig; @@ -152,7 +154,7 @@ BOOST_AUTO_TEST_CASE(chainlock_malformed_data_test) CDataStream truncated(std::vector(data.begin(), data.begin() + truncateAt), SER_NETWORK, PROTOCOL_VERSION); - CChainLockSig deserialized; + ChainLockSig deserialized; try { truncated >> deserialized; // If no exception, verify it's either complete or default diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index bcd497bb320b9..e7f6bb7a5fc1f 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -7,16 +7,10 @@ #include #include #include -#include -#include -#include -#include -#include #include #include #include #include