From 6e5147748c231dd64e7725baa65014eb465ed0fb Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 27 Oct 2025 03:34:02 +0700 Subject: [PATCH 01/58] feat: new abstract handler for net messages --- src/net_processing.cpp | 32 +++++++++++++++++++++++++++++++- src/net_processing.h | 23 ++++++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 4804d513e6614..f39175f067267 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -595,6 +595,11 @@ class PeerManagerImpl final : public PeerManager const std::unique_ptr& active_ctx, CJWalletManager* const cj_walletman, const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs); + ~PeerManagerImpl() { + // probably do some disassignment +// m_handlers.clear(); + } + /** Overridden from CValidationInterface. */ void BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindexConnected) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex); @@ -636,6 +641,11 @@ class PeerManagerImpl final : public PeerManager void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) override; bool IsBanned(NodeId pnode) override EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_peer_mutex); size_t GetRequestedObjectCount(NodeId nodeid) const override EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + void AddExtraHandler(std::unique_ptr&& handler) override; + + /** Implement PeerManagerInternal */ + void PeerMisbehaving(const NodeId pnode, const int howmuch, const std::string& message = "") override; + void PeerEraseObjectRequest(const NodeId nodeid, const CInv& inv) override; private: void _RelayTransaction(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_peer_mutex); @@ -1065,6 +1075,8 @@ class PeerManagerImpl final : public PeerManager std::vector> vExtraTxnForCompact GUARDED_BY(g_msgproc_mutex); /** Offset into vExtraTxnForCompact to insert the next tx */ size_t vExtraTxnForCompactIt GUARDED_BY(g_msgproc_mutex) = 0; + + std::vector> m_handlers; }; // Keeps track of the time (in microseconds) when transactions were requested last time @@ -1623,6 +1635,12 @@ size_t PeerManagerImpl::GetRequestedObjectCount(NodeId nodeid) const return state->m_object_download.m_object_process_time.size(); } +void PeerManagerImpl::AddExtraHandler(std::unique_ptr&& handler) +{ + assert(handler != nullptr); + m_handlers.emplace_back(std::move(handler)); +} + void PeerManagerImpl::UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) { LOCK(cs_main); @@ -5389,7 +5407,9 @@ void PeerManagerImpl::ProcessMessage( return; // CLSIG } - PostProcessMessage(m_llmq_ctx->isman->ProcessMessage(pfrom.GetId(), msg_type, vRecv), pfrom.GetId()); + for (const auto& handler : m_handlers) { + handler->ProcessMessage(pfrom, msg_type, vRecv); + } return; } @@ -6465,3 +6485,13 @@ bool PeerManagerImpl::SendMessages(CNode* pto) } // release cs_main return true; } + +void PeerManagerImpl::PeerMisbehaving(const NodeId pnode, const int howmuch, const std::string& message) +{ + Misbehaving(pnode, howmuch, message); +} + +void PeerManagerImpl::PeerEraseObjectRequest(const NodeId nodeid, const CInv& inv) +{ + EraseObjectRequest(nodeid, inv); +} diff --git a/src/net_processing.h b/src/net_processing.h index 8a4a4e7aba884..adc2fb2aa45b6 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -55,7 +55,26 @@ struct CNodeStateStats { ServiceFlags their_services; }; -class PeerManager : public CValidationInterface, public NetEventsInterface +class PeerManagerInternal +{ +public: + virtual void PeerMisbehaving(const NodeId pnode, const int howmuch, const std::string& message = "") = 0; + virtual void PeerEraseObjectRequest(const NodeId nodeid, const CInv& inv) = 0; +}; + +class NetHandler +{ +public: + NetHandler(PeerManagerInternal* peer_manager) : m_peer_manager{Assert(peer_manager)} {} + virtual ~NetHandler() {} + + virtual void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) = 0; +protected: + PeerManagerInternal* m_peer_manager; +}; + + +class PeerManager : public CValidationInterface, public NetEventsInterface, public PeerManagerInternal { public: static std::unique_ptr make(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman, @@ -133,6 +152,8 @@ class PeerManager : public CValidationInterface, public NetEventsInterface virtual bool IsBanned(NodeId pnode) = 0; virtual size_t GetRequestedObjectCount(NodeId nodeid) const = 0; + + virtual void AddExtraHandler(std::unique_ptr&& handler) = 0; }; #endif // BITCOIN_NET_PROCESSING_H From ef09f46d1cb3aac1d79711ea3b12992c7b03ee61 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 27 Oct 2025 12:29:18 +0700 Subject: [PATCH 02/58] refactor: use NetHandler for InstantSend --- src/Makefile.am | 2 ++ src/init.cpp | 3 ++ src/instantsend/instantsend.cpp | 51 +++++++++------------------------ src/instantsend/instantsend.h | 5 +++- src/test/util/setup_common.cpp | 2 ++ 5 files changed, 25 insertions(+), 38 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 7b5c4ca684028..2fd3add2a983d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -296,6 +296,7 @@ BITCOIN_CORE_H = \ net.h \ net_permissions.h \ net_processing.h \ + net_instantsend.h \ net_types.h \ netaddress.h \ netbase.h \ @@ -557,6 +558,7 @@ libbitcoin_node_a_SOURCES = \ netfulfilledman.cpp \ netgroup.cpp \ net_processing.cpp \ + net_instantsend.cpp \ node/blockstorage.cpp \ node/caches.cpp \ node/chainstate.cpp \ diff --git a/src/init.cpp b/src/init.cpp index 18d1cafe92c89..823853f5982da 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -2158,6 +2159,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.active_ctx, node.cj_walletman.get(), node.llmq_ctx, ignores_incoming_txs); RegisterValidationInterface(node.peerman.get()); + node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.llmq_ctx->isman)); + g_ds_notification_interface = std::make_unique( *node.connman, *node.dstxman, *node.mn_sync, *node.govman, chainman, node.dmnman, node.llmq_ctx ); diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 34537ffb64c84..04282f22cd98d 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -103,53 +103,31 @@ void CInstantSendManager::Stop() } } -bool ShouldReportISLockTiming() { +bool ShouldReportISLockTiming() +{ return g_stats_client->active() || LogAcceptDebug(BCLog::INSTANTSEND); } -MessageProcessingResult CInstantSendManager::ProcessMessage(NodeId from, std::string_view msg_type, CDataStream& vRecv) +int CInstantSendManager::GetCycleBlockHeight(const uint256& cycle_hash) const { - if (!IsInstantSendEnabled() || msg_type != NetMsgType::ISDLOCK) { - return {}; - } - - const auto islock = std::make_shared(); - vRecv >> *islock; - - auto hash = ::SerializeHash(*islock); - - MessageProcessingResult ret{}; - ret.m_to_erase = CInv{MSG_ISDLOCK, hash}; - - if (!islock->TriviallyValid()) { - ret.m_error = MisbehavingError{100}; - return ret; - } - - const auto blockIndex = WITH_LOCK(::cs_main, return m_chainstate.m_blockman.LookupBlockIndex(islock->cycleHash)); + const auto blockIndex = WITH_LOCK(::cs_main, return m_chainstate.m_blockman.LookupBlockIndex(cycle_hash)); if (blockIndex == nullptr) { - // Maybe we don't have the block yet or maybe some peer spams invalid values for cycleHash - ret.m_error = MisbehavingError{1}; - return ret; - } - - // Deterministic islocks MUST use rotation based llmq - auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; - const auto& llmq_params_opt = Params().GetLLMQ(llmqType); - assert(llmq_params_opt); - if (blockIndex->nHeight % llmq_params_opt->dkgInterval != 0) { - ret.m_error = MisbehavingError{100}; - return ret; + return -1; } + return blockIndex->nHeight; +} +bool CInstantSendManager::IsKnownInstantSend(const uint256& hash) const +{ if (WITH_LOCK(cs_pendingLocks, return pendingInstantSendLocks.count(hash) || pendingNoTxInstantSendLocks.count(hash)) || db.KnownInstantSendLock(hash)) { - return ret; + return true; } + return false; +} - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: received islock, peer=%d\n", __func__, - islock->txid.ToString(), hash.ToString(), from); - +void CInstantSendManager::EnqueueInstantSendLock(NodeId from, const uint256& hash, const std::shared_ptr& islock) +{ if (ShouldReportISLockTiming()) { auto time_diff = [&]() -> int64_t { LOCK(cs_timingsTxSeen); @@ -169,7 +147,6 @@ MessageProcessingResult CInstantSendManager::ProcessMessage(NodeId from, std::st LOCK(cs_pendingLocks); pendingInstantSendLocks.emplace(hash, std::make_pair(from, islock)); - return ret; } instantsend::PendingState CInstantSendManager::ProcessPendingInstantSendLocks() diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index e9b5c809c1978..fe0bc69026194 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -142,7 +142,10 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent bool IsWaitingForTx(const uint256& txHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); instantsend::InstantSendLockPtr GetConflictingLock(const CTransaction& tx) const override; - [[nodiscard]] MessageProcessingResult ProcessMessage(NodeId from, std::string_view msg_type, CDataStream& vRecv) + // It return negative number if + int GetCycleBlockHeight(const uint256& cycle_hash) const; + bool IsKnownInstantSend(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); + void EnqueueInstantSendLock(NodeId from, const uint256& hash, const std::shared_ptr& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); void TransactionAddedToMempool(const CTransactionRef& tx) diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 480296e80fc5e..a83224e8f6262 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -364,6 +365,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vectorAddExtraHandler(std::make_unique(m_node.peerman.get(), *m_node.llmq_ctx->isman)); { CConnman::Options options; options.m_msgproc = m_node.peerman.get(); From d500b50a063a0abff418b95ef362c094a0c05f12 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 27 Oct 2025 12:44:53 +0700 Subject: [PATCH 03/58] refactor: stop extra net handlers before Active Signer stopped --- src/init.cpp | 6 ++++-- src/net_processing.cpp | 6 ++++++ src/net_processing.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 823853f5982da..068a97a86ac5e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -270,6 +270,8 @@ void PrepareShutdown(NodeContext& node) StopREST(); StopRPC(); StopHTTPServer(); + node.peerman->RemoveHandlers(); + if (node.active_ctx) node.active_ctx->Stop(); if (node.llmq_ctx) node.llmq_ctx->Stop(); @@ -2159,8 +2161,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.active_ctx, node.cj_walletman.get(), node.llmq_ctx, ignores_incoming_txs); RegisterValidationInterface(node.peerman.get()); - node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.llmq_ctx->isman)); - g_ds_notification_interface = std::make_unique( *node.connman, *node.dstxman, *node.mn_sync, *node.govman, chainman, node.dmnman, node.llmq_ctx ); @@ -2176,6 +2176,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) g_active_notification_interface = std::make_unique(*node.active_ctx, *node.mn_activeman); RegisterValidationInterface(g_active_notification_interface.get()); } + node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.llmq_ctx->isman)); + // ********************************************************* Step 7d: Setup other Dash services diff --git a/src/net_processing.cpp b/src/net_processing.cpp index f39175f067267..630581824a676 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -642,6 +642,7 @@ class PeerManagerImpl final : public PeerManager bool IsBanned(NodeId pnode) override EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_peer_mutex); size_t GetRequestedObjectCount(NodeId nodeid) const override EXCLUSIVE_LOCKS_REQUIRED(::cs_main); void AddExtraHandler(std::unique_ptr&& handler) override; + void RemoveHandlers() override; /** Implement PeerManagerInternal */ void PeerMisbehaving(const NodeId pnode, const int howmuch, const std::string& message = "") override; @@ -1641,6 +1642,11 @@ void PeerManagerImpl::AddExtraHandler(std::unique_ptr&& handler) m_handlers.emplace_back(std::move(handler)); } +void PeerManagerImpl::RemoveHandlers() +{ + m_handlers.clear(); +} + void PeerManagerImpl::UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) { LOCK(cs_main); diff --git a/src/net_processing.h b/src/net_processing.h index adc2fb2aa45b6..e21e690290e69 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -154,6 +154,7 @@ class PeerManager : public CValidationInterface, public NetEventsInterface, publ virtual size_t GetRequestedObjectCount(NodeId nodeid) const = 0; virtual void AddExtraHandler(std::unique_ptr&& handler) = 0; + virtual void RemoveHandlers() = 0; }; #endif // BITCOIN_NET_PROCESSING_H From f285d0a4f126d8fb99320dfc402b763355f22dbe Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 28 Oct 2025 14:38:07 +0700 Subject: [PATCH 04/58] part I refactor to net-instantsend --- src/instantsend/instantsend.cpp | 121 +++++----------------------- src/instantsend/instantsend.h | 22 ++--- src/net_instantsend.cpp | 138 ++++++++++++++++++++++++++++++++ src/net_instantsend.h | 42 ++++++++++ 4 files changed, 207 insertions(+), 116 deletions(-) create mode 100644 src/net_instantsend.cpp create mode 100644 src/net_instantsend.h diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 04282f22cd98d..e333be28a2a23 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -6,10 +6,8 @@ #include #include -#include #include #include -#include #include #include @@ -68,41 +66,10 @@ CInstantSendManager::CInstantSendManager(CChainLocksHandler& _clhandler, CChainS mempool{_mempool}, m_mn_sync{mn_sync} { - workInterrupt.reset(); } CInstantSendManager::~CInstantSendManager() = default; -void CInstantSendManager::Start(PeerManager& peerman) -{ - // can't start new thread if we have one running already - if (workThread.joinable()) { - assert(false); - } - - workThread = std::thread(&util::TraceThread, "isman", [this, &peerman] { WorkThreadMain(peerman); }); - - if (auto signer = m_signer.load(std::memory_order_acquire); signer) { - signer->Start(); - } -} - -void CInstantSendManager::Stop() -{ - if (auto signer = m_signer.load(std::memory_order_acquire); signer) { - signer->Stop(); - } - - // make sure to call InterruptWorkerThread() first - if (!workInterrupt) { - assert(false); - } - - if (workThread.joinable()) { - workThread.join(); - } -} - bool ShouldReportISLockTiming() { return g_stats_client->active() || LogAcceptDebug(BCLog::INSTANTSEND); @@ -149,15 +116,16 @@ void CInstantSendManager::EnqueueInstantSendLock(NodeId from, const uint256& has pendingInstantSendLocks.emplace(hash, std::make_pair(from, islock)); } -instantsend::PendingState CInstantSendManager::ProcessPendingInstantSendLocks() +instantsend::PendingState CInstantSendManager::GetPendingLocks() { decltype(pendingInstantSendLocks) pend; instantsend::PendingState ret; + ret.m_pending_work = false; + if (!IsInstantSendEnabled()) { return ret; } - { LOCK(cs_pendingLocks); // only process a max 32 locks at a time to avoid duplicate verification of recovered signatures which have been @@ -182,36 +150,7 @@ instantsend::PendingState CInstantSendManager::ProcessPendingInstantSendLocks() } } - if (pend.empty()) { - ret.m_pending_work = false; - return ret; - } - - // TODO Investigate if leaving this is ok - auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; - const auto& llmq_params_opt = Params().GetLLMQ(llmqType); - assert(llmq_params_opt); - const auto& llmq_params = llmq_params_opt.value(); - auto dkgInterval = llmq_params.dkgInterval; - - // First check against the current active set and don't ban - auto badISLocks = ProcessPendingInstantSendLocks(llmq_params, /*signOffset=*/0, /*ban=*/false, pend, ret.m_peer_activity); - if (!badISLocks.empty()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- doing verification on old active set\n", __func__); - - // filter out valid IS locks from "pend" - for (auto it = pend.begin(); it != pend.end();) { - if (!badISLocks.count(it->first)) { - it = pend.erase(it); - } else { - ++it; - } - } - // Now check against the previous active set and perform banning if this fails - ProcessPendingInstantSendLocks(llmq_params, dkgInterval, /*ban=*/true, pend, ret.m_peer_activity); - } - - return ret; + return pend; } Uint256HashSet CInstantSendManager::ProcessPendingInstantSendLocks( @@ -578,6 +517,21 @@ void CInstantSendManager::RemoveNonLockedTx(const uint256& txid, bool retryChild __func__, txid.ToString(), retryChildren, retryChildrenCount); } +std::vector CInstantSendManager::PrepareTxToRetry() +{ + std::vector txns{}; + LOCK2(cs_nonLocked, cs_pendingRetry); + if (pendingRetryTxs.empty()) return more_work; + txns.reserve(pendingRetryTxs.size()); + for (const auto& txid : pendingRetryTxs) { + if (auto it = nonLockedTxs.find(txid); it != nonLockedTxs.end()) { + const auto& [_, tx_info] = *it; + if (tx_info.tx) { + txns.push_back(tx_info.tx); + } + } + } +} void CInstantSendManager::RemoveConflictedTx(const CTransaction& tx) { RemoveNonLockedTx(tx.GetHash(), false); @@ -900,43 +854,6 @@ size_t CInstantSendManager::GetInstantSendLockCount() const return db.GetInstantSendLockCount(); } -void CInstantSendManager::WorkThreadMain(PeerManager& peerman) -{ - while (!workInterrupt) { - bool fMoreWork = [&]() -> bool { - if (!IsInstantSendEnabled()) return false; - auto [more_work, peer_activity] = ProcessPendingInstantSendLocks(); - for (auto& [node_id, mpr] : peer_activity) { - peerman.PostProcessMessage(std::move(mpr), node_id); - } - auto signer = m_signer.load(std::memory_order_acquire); - if (!signer) return more_work; - // Construct set of non-locked transactions that are pending to retry - std::vector txns{}; - { - LOCK2(cs_nonLocked, cs_pendingRetry); - if (pendingRetryTxs.empty()) return more_work; - txns.reserve(pendingRetryTxs.size()); - for (const auto& txid : pendingRetryTxs) { - if (auto it = nonLockedTxs.find(txid); it != nonLockedTxs.end()) { - const auto& [_, tx_info] = *it; - if (tx_info.tx) { - txns.push_back(tx_info.tx); - } - } - } - } - // Retry processing them - signer->ProcessPendingRetryLockTxs(txns); - return more_work; - }(); - - if (!fMoreWork && !workInterrupt.sleep_for(std::chrono::milliseconds(100))) { - return; - } - } -} - bool CInstantSendManager::IsInstantSendEnabled() const { return !fReindex && !fImporting && spork_manager.IsSporkActive(SPORK_2_INSTANTSEND_ENABLED); diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index fe0bc69026194..096a565f55734 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -18,6 +17,7 @@ #include #include +#include #include #include @@ -27,7 +27,6 @@ class CDataStream; class CMasternodeSync; class CSporkManager; class CTxMemPool; -class PeerManager; namespace Consensus { struct LLMQParams; } // namespace Consensus @@ -61,9 +60,6 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent std::atomic m_signer{nullptr}; - std::thread workThread; - CThreadInterrupt workInterrupt; - mutable Mutex cs_pendingLocks; // Incoming and not verified yet Uint256HashMap> pendingInstantSendLocks GUARDED_BY(cs_pendingLocks); @@ -102,13 +98,11 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent } void DisconnectSigner() { m_signer.store(nullptr, std::memory_order_release); } - void Start(PeerManager& peerman); - void Stop(); - void InterruptWorkerThread() { workInterrupt(); }; + instantsend::InstantSendSigner* Signer() const { return m_signer.load(); } -private: instantsend::PendingState ProcessPendingInstantSendLocks() EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); +private: Uint256HashSet ProcessPendingInstantSendLocks(const Consensus::LLMQParams& llmq_params, int signOffset, bool ban, const Uint256HashMap>& pend, @@ -131,9 +125,6 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent void ResolveBlockConflicts(const uint256& islockHash, const instantsend::InstantSendLock& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); - void WorkThreadMain(PeerManager& peerman) - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); - void HandleFullyConfirmedBlock(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); @@ -142,12 +133,15 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent bool IsWaitingForTx(const uint256& txHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); instantsend::InstantSendLockPtr GetConflictingLock(const CTransaction& tx) const override; - // It return negative number if + /* Helpers for communications between CInstantSendManager & NetInstantSend */ + // GetCycleBlockHeight returns negative number if cycle_hash is now known int GetCycleBlockHeight(const uint256& cycle_hash) const; bool IsKnownInstantSend(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); void EnqueueInstantSendLock(NodeId from, const uint256& hash, const std::shared_ptr& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); - + std::vector PrepareTxToRetry() EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, cs_pendingRetry); + //---- + // void TransactionAddedToMempool(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry, !cs_timingsTxSeen); void TransactionRemovedFromMempool(const CTransactionRef& tx); diff --git a/src/net_instantsend.cpp b/src/net_instantsend.cpp new file mode 100644 index 0000000000000..de137a798931d --- /dev/null +++ b/src/net_instantsend.cpp @@ -0,0 +1,138 @@ +// Copyright (c) 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 + +void NetInstantSend::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) +{ + if (msg_type != NetMsgType::ISDLOCK) { + return; + } + + if (!m_is_manager.IsInstantSendEnabled()) return; + + // TODO: consider removing shared_ptr from this islock + const auto islock = std::make_shared(); + vRecv >> *islock; + + uint256 hash = ::SerializeHash(*islock); + + WITH_LOCK(::cs_main, m_peer_manager->PeerEraseObjectRequest(pfrom.GetId(), CInv{MSG_ISDLOCK, hash})); + + if (!islock->TriviallyValid()) { + m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100); + return; + } + + int block_height = m_is_manager.GetCycleBlockHeight(islock->cycleHash); + if (block_height < 0) { + // Maybe we don't have the block yet or maybe some peer spams invalid values for cycleHash + m_peer_manager->PeerMisbehaving(pfrom.GetId(), 1); + return; + } + + // Deterministic islocks MUST use rotation based llmq + auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); + assert(llmq_params_opt); + if (block_height % llmq_params_opt->dkgInterval != 0) { + m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100); + return; + } + + if (!m_is_manager.IsKnownInstantSend(hash)) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: received islock, peer=%d\n", __func__, + islock->txid.ToString(), hash.ToString(), pfrom.GetId()); + + m_is_manager.EnqueueInstantSendLock(pfrom.GetId(), hash, islock); + } +} + +void NetInstantSend::Start() +{ + // can't start new thread if we have one running already + if (workThread.joinable()) { + assert(false); + } + + workThread = std::thread(&util::TraceThread, "isman", [this] { WorkThreadMain(); }); + + // TODO: doubing that it works at all reliable even in previous implementation + if (auto signer = m_is_manager.Signer(); signer) { + signer->Start(); + } +} + +void NetInstantSend::Stop() +{ + if (auto signer = m_is_manager.Signer(); signer) { + signer->Stop(); + } + + // make sure to call InterruptWorkerThread() first + if (!workInterrupt) { + assert(false); + } + + if (workThread.joinable()) { + workThread.join(); + } +} + + +void NetInstantSend::ProcessPendingISLocks(const Uint256HashMap>& locks_to_process) +{ + // TODO Investigate if leaving this is ok + auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); + assert(llmq_params_opt); + const auto& llmq_params = llmq_params_opt.value(); + auto dkgInterval = llmq_params.dkgInterval; + + // First check against the current active set and don't ban + auto bad_is_locks = ProcessPendingInstantSendLocks(llmq_params, /*signOffset=*/0, /*ban=*/false, locks_to_process, ret.m_peer_activity); + if (!bad_is_locks.empty()) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- doing verification on old active set\n", __func__); + + // filter out valid IS locks from "locks_to_process" + for (auto it = locks_to_process.begin(); it != locks_to_process.end();) { + if (bad_is_locks.find(it->first) == bad_is_locks.end()) { + it = locks_to_process.erase(it); + } else { + ++it; + } + } + // Now check against the previous active set and perform banning if this fails + ProcessPendingInstantSendLocks(llmq_params, dkgInterval, /*ban=*/true, locks_to_process, ret.m_peer_activity); + } +} + +void NetInstantSend::WorkThreadMain() +{ + while (!workInterrupt) { + bool fMoreWork = [&]() -> bool { + if (!m_is_manager.IsInstantSendEnabled()) return false; + + auto [more_work, locks] = m_is_manager.GetPendingLocks(); + ProcessPendingISLocks(locks); + /* + for (auto& [node_id, mpr] : peer_activity) { + m_peer_manager.PostProcessMessage(std::move(mpr), node_id); + } + */ + auto signer = m_is_manager.Signer(); + if (!signer) return more_work; + + signer->ProcessPendingRetryLockTxs(m_is_manager.PrepareTxToRetry()); + return more_work; + }(); + + if (!fMoreWork && !workInterrupt.sleep_for(std::chrono::milliseconds(100))) { + return; + } + } +} + diff --git a/src/net_instantsend.h b/src/net_instantsend.h new file mode 100644 index 0000000000000..ff34c2003c749 --- /dev/null +++ b/src/net_instantsend.h @@ -0,0 +1,42 @@ +// Copyright (c) 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_NET_INSTANTSEND_H +#define BITCOIN_NET_INSTANTSEND_H + +#include + +#include +namespace llmq { +class CInstantSendManager; +} + +class NetInstantSend : public NetHandler +{ +public: + NetInstantSend(PeerManagerInternal* peer_manager, llmq::CInstantSendManager& is_manager) + : NetHandler(peer_manager), m_is_manager{is_manager} + { + workInterrupt.reset(); + } + + void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) override; + + void Start(); + void Stop(); + void InterruptWorkerThread() { workInterrupt(); }; + + void WorkThreadMain(); +private: + void ProcessPendingISLocks(const Uint256HashMap>& locks_to_process); + + llmq::CInstantSendManager& m_is_manager; + + std::thread workThread; + CThreadInterrupt workInterrupt; + +}; + +#endif // BITCOIN_NET_INSTANTSEND_H From e68b53f6096f569e029fde1fb87c594a0c66d54f Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 28 Oct 2025 19:49:13 +0700 Subject: [PATCH 05/58] part II refactoring --- src/init.cpp | 5 + src/instantsend/instantsend.cpp | 173 +++++--------------------------- src/instantsend/instantsend.h | 12 +-- src/llmq/context.cpp | 3 - src/net_instantsend.cpp | 127 ++++++++++++++++++++++- src/net_instantsend.h | 21 ++-- 6 files changed, 176 insertions(+), 165 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 068a97a86ac5e..18818f0024356 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -235,6 +235,9 @@ void Interrupt(NodeContext& node) if (node.active_ctx) { node.active_ctx->Interrupt(); } + if (node.peerman) { + node.peerman->InterruptHandlers(); + } if (node.llmq_ctx) { node.llmq_ctx->Interrupt(); } @@ -273,6 +276,7 @@ void PrepareShutdown(NodeContext& node) node.peerman->RemoveHandlers(); if (node.active_ctx) node.active_ctx->Stop(); + if (node.peerman) node.peerman->StopHandlers(); if (node.llmq_ctx) node.llmq_ctx->Stop(); for (const auto& client : node.chain_clients) { @@ -2273,6 +2277,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 10a: schedule Dash-specific tasks node.llmq_ctx->Start(*node.peerman); + node.peerman->StartHandlers(); if (node.active_ctx) node.active_ctx->Start(*node.connman, *node.peerman); node.scheduler->scheduleEvery(std::bind(&CNetFulfilledRequestManager::DoMaintenance, std::ref(*node.netfulfilledman)), std::chrono::minutes{1}); diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index e333be28a2a23..6c360c731b429 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -4,23 +4,17 @@ #include +#include #include #include -#include -#include -#include - -#include -#include #include -#include -#include -#include #include +#include #include #include - -#include +#include +#include +#include // Forward declaration to break dependency over node/transaction.h namespace node { @@ -118,151 +112,35 @@ void CInstantSendManager::EnqueueInstantSendLock(NodeId from, const uint256& has instantsend::PendingState CInstantSendManager::GetPendingLocks() { - decltype(pendingInstantSendLocks) pend; instantsend::PendingState ret; - ret.m_pending_work = false; - if (!IsInstantSendEnabled()) { return ret; } - { - LOCK(cs_pendingLocks); - // only process a max 32 locks at a time to avoid duplicate verification of recovered signatures which have been - // verified by CSigningManager in parallel - const size_t maxCount = 32; - // The keys of the removed values are temporaily stored here to avoid invalidating an iterator - std::vector removed; - removed.reserve(maxCount); - - for (const auto& [islockHash, nodeid_islptr_pair] : pendingInstantSendLocks) { - // Check if we've reached max count - if (pend.size() >= maxCount) { - ret.m_pending_work = true; - break; - } - pend.emplace(islockHash, std::move(nodeid_islptr_pair)); - removed.emplace_back(islockHash); - } - - for (const auto& islockHash : removed) { - pendingInstantSendLocks.erase(islockHash); - } - } - - return pend; -} - -Uint256HashSet CInstantSendManager::ProcessPendingInstantSendLocks( - const Consensus::LLMQParams& llmq_params, int signOffset, bool ban, - const Uint256HashMap>& pend, - std::vector>& peer_activity) -{ - CBLSBatchVerifier batchVerifier(false, true, 8); - Uint256HashMap recSigs; - - size_t verifyCount = 0; - size_t alreadyVerified = 0; - for (const auto& p : pend) { - const auto& hash = p.first; - auto nodeId = p.second.first; - const auto& islock = p.second.second; - if (batchVerifier.badSources.count(nodeId)) { - continue; - } - - if (!islock->sig.Get().IsValid()) { - batchVerifier.badSources.emplace(nodeId); - continue; - } - - auto id = islock->GetRequestId(); - - // no need to verify an ISLOCK if we already have verified the recovered sig that belongs to it - if (sigman.HasRecoveredSig(llmq_params.type, id, islock->txid)) { - alreadyVerified++; - continue; - } - - const auto blockIndex = WITH_LOCK(::cs_main, return m_chainstate.m_blockman.LookupBlockIndex(islock->cycleHash)); - if (blockIndex == nullptr) { - batchVerifier.badSources.emplace(nodeId); - continue; - } - - int nSignHeight{-1}; - const auto dkgInterval = llmq_params.dkgInterval; - if (blockIndex->nHeight + dkgInterval < m_chainstate.m_chain.Height()) { - nSignHeight = blockIndex->nHeight + dkgInterval - 1; - } - // For RegTest non-rotating quorum cycleHash has directly quorum hash - auto quorum = llmq_params.useRotation ? llmq::SelectQuorumForSigning(llmq_params, m_chainstate.m_chain, qman, - id, nSignHeight, signOffset) - : qman.GetQuorum(llmq_params.type, islock->cycleHash); - - if (!quorum) { - // should not happen, but if one fails to select, all others will also fail to select - return {}; - } - uint256 signHash = llmq::SignHash{llmq_params.type, quorum->qc->quorumHash, id, islock->txid}.Get(); - batchVerifier.PushMessage(nodeId, hash, signHash, islock->sig.Get(), quorum->qc->quorumPublicKey); - verifyCount++; - - // We can reconstruct the CRecoveredSig objects from the islock and pass it to the signing manager, which - // avoids unnecessary double-verification of the signature. We however only do this when verification here - // turns out to be good (which is checked further down) - if (!sigman.HasRecoveredSigForId(llmq_params.type, id)) { - recSigs.try_emplace(hash, - CRecoveredSig(llmq_params.type, quorum->qc->quorumHash, id, islock->txid, islock->sig)); - } - } - - cxxtimer::Timer verifyTimer(true); - batchVerifier.Verify(); - verifyTimer.stop(); - - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- verified locks. count=%d, alreadyVerified=%d, vt=%d, nodes=%d\n", __func__, - verifyCount, alreadyVerified, verifyTimer.count(), batchVerifier.GetUniqueSourceCount()); - - Uint256HashSet badISLocks; - - if (ban && !batchVerifier.badSources.empty()) { - LOCK(::cs_main); - for (const auto& nodeId : batchVerifier.badSources) { - // Let's not be too harsh, as the peer might simply be unlucky and might have sent us an old lock which - // does not validate anymore due to changed quorums - peer_activity.emplace_back(nodeId, MisbehavingError{20}); + LOCK(cs_pendingLocks); + // only process a max 32 locks at a time to avoid duplicate verification of recovered signatures which have been + // verified by CSigningManager in parallel + const size_t maxCount = 32; + // The keys of the removed values are temporaily stored here to avoid invalidating an iterator + std::vector removed; + removed.reserve(maxCount); + + for (const auto& [islockHash, nodeid_islptr_pair] : pendingInstantSendLocks) { + // Check if we've reached max count + if (ret.m_pending_is.size() >= maxCount) { + ret.m_pending_work = true; + break; } + ret.m_pending_is.emplace(islockHash, std::move(nodeid_islptr_pair)); + removed.emplace_back(islockHash); } - for (const auto& p : pend) { - const auto& hash = p.first; - auto nodeId = p.second.first; - const auto& islock = p.second.second; - - if (batchVerifier.badMessages.count(hash)) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: invalid sig in islock, peer=%d\n", - __func__, islock->txid.ToString(), hash.ToString(), nodeId); - badISLocks.emplace(hash); - continue; - } - peer_activity.emplace_back(nodeId, ProcessInstantSendLock(nodeId, hash, islock)); - - // See comment further on top. We pass a reconstructed recovered sig to the signing manager to avoid - // double-verification of the sig. - auto it = recSigs.find(hash); - if (it != recSigs.end()) { - auto recSig = std::make_shared(std::move(it->second)); - if (!sigman.HasRecoveredSigForId(llmq_params.type, recSig->getId())) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: passing reconstructed recSig to signing mgr, peer=%d\n", __func__, - islock->txid.ToString(), hash.ToString(), nodeId); - sigman.PushReconstructedRecoveredSig(recSig); - } - } + for (const auto& islockHash : removed) { + pendingInstantSendLocks.erase(islockHash); } - return badISLocks; + return ret; } MessageProcessingResult CInstantSendManager::ProcessInstantSendLock(NodeId from, const uint256& hash, @@ -520,8 +398,9 @@ void CInstantSendManager::RemoveNonLockedTx(const uint256& txid, bool retryChild std::vector CInstantSendManager::PrepareTxToRetry() { std::vector txns{}; + LOCK2(cs_nonLocked, cs_pendingRetry); - if (pendingRetryTxs.empty()) return more_work; + if (pendingRetryTxs.empty()) return txns; txns.reserve(pendingRetryTxs.size()); for (const auto& txid : pendingRetryTxs) { if (auto it = nonLockedTxs.find(txid); it != nonLockedTxs.end()) { @@ -531,7 +410,9 @@ std::vector CInstantSendManager::PrepareTxToRetry() } } } + return txns; } + void CInstantSendManager::RemoveConflictedTx(const CTransaction& tx) { RemoveNonLockedTx(tx.GetHash(), false); diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index 096a565f55734..6f15ac3cdf6d9 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -36,7 +36,7 @@ class InstantSendSigner; struct PendingState { bool m_pending_work{false}; - std::vector> m_peer_activity{}; + Uint256HashMap> m_pending_is; }; } // namespace instantsend @@ -100,14 +100,8 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent instantsend::InstantSendSigner* Signer() const { return m_signer.load(); } - instantsend::PendingState ProcessPendingInstantSendLocks() - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); private: - Uint256HashSet ProcessPendingInstantSendLocks(const Consensus::LLMQParams& llmq_params, int signOffset, bool ban, - const Uint256HashMap>& pend, - std::vector>& peer_activity) - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); MessageProcessingResult ProcessInstantSendLock(NodeId from, const uint256& hash, const instantsend::InstantSendLockPtr& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); @@ -140,6 +134,10 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent void EnqueueInstantSendLock(NodeId from, const uint256& hash, const std::shared_ptr& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); std::vector PrepareTxToRetry() EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, cs_pendingRetry); + instantsend::PendingState GetPendingLocks(); + CSigningManager& Sigman() { return sigman; } + CQuorumManager& Qman() { return qman; } + CChainState& Chainstate() { return m_chainstate; } //---- // void TransactionAddedToMempool(const CTransactionRef& tx) diff --git a/src/llmq/context.cpp b/src/llmq/context.cpp index 359d2a23924c6..499f2b1f16351 100644 --- a/src/llmq/context.cpp +++ b/src/llmq/context.cpp @@ -44,7 +44,6 @@ LLMQContext::~LLMQContext() { } void LLMQContext::Interrupt() { - isman->InterruptWorkerThread(); sigman->InterruptWorkerThread(); } @@ -53,12 +52,10 @@ void LLMQContext::Start(PeerManager& peerman) qman->Start(); sigman->StartWorkerThread(peerman); clhandler->Start(*isman); - isman->Start(peerman); } void LLMQContext::Stop() { - isman->Stop(); clhandler->Stop(); sigman->StopWorkerThread(); qman->Stop(); diff --git a/src/net_instantsend.cpp b/src/net_instantsend.cpp index de137a798931d..7d751f1899ee8 100644 --- a/src/net_instantsend.cpp +++ b/src/net_instantsend.cpp @@ -3,7 +3,15 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include + +#include +#include #include +#include +#include +#include +#include +#include #include void NetInstantSend::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) @@ -72,7 +80,7 @@ void NetInstantSend::Stop() signer->Stop(); } - // make sure to call InterruptWorkerThread() first + // make sure to call Interrupt() first if (!workInterrupt) { assert(false); } @@ -82,8 +90,121 @@ void NetInstantSend::Stop() } } +Uint256HashSet NetInstantSend::ProcessPendingInstantSendLocks( + const Consensus::LLMQParams& llmq_params, int signOffset, bool ban, + const Uint256HashMap>& pend) +{ + CBLSBatchVerifier batchVerifier(false, true, 8); + Uint256HashMap recSigs; + + size_t verifyCount = 0; + size_t alreadyVerified = 0; + for (const auto& p : pend) { + const auto& hash = p.first; + auto nodeId = p.second.first; + const auto& islock = p.second.second; + + if (batchVerifier.badSources.count(nodeId)) { + continue; + } + + if (!islock->sig.Get().IsValid()) { + batchVerifier.badSources.emplace(nodeId); + continue; + } + + auto id = islock->GetRequestId(); + + // no need to verify an ISLOCK if we already have verified the recovered sig that belongs to it + if (m_is_manager.Sigman().HasRecoveredSig(llmq_params.type, id, islock->txid)) { + alreadyVerified++; + continue; + } + + const auto blockIndex = WITH_LOCK(::cs_main, return m_is_manager.Chainstate().m_blockman.LookupBlockIndex(islock->cycleHash)); + if (blockIndex == nullptr) { + batchVerifier.badSources.emplace(nodeId); + continue; + } + + int nSignHeight{-1}; + const auto dkgInterval = llmq_params.dkgInterval; + if (blockIndex->nHeight + dkgInterval < m_is_manager.Chainstate().m_chain.Height()) { + nSignHeight = blockIndex->nHeight + dkgInterval - 1; + } + // For RegTest non-rotating quorum cycleHash has directly quorum hash + auto quorum = llmq_params.useRotation ? llmq::SelectQuorumForSigning(llmq_params, m_is_manager.Chainstate().m_chain, m_is_manager.Qman(), + id, nSignHeight, signOffset) + : m_is_manager.Qman().GetQuorum(llmq_params.type, islock->cycleHash); + + if (!quorum) { + // should not happen, but if one fails to select, all others will also fail to select + return {}; + } + uint256 signHash = llmq::SignHash{llmq_params.type, quorum->qc->quorumHash, id, islock->txid}.Get(); + batchVerifier.PushMessage(nodeId, hash, signHash, islock->sig.Get(), quorum->qc->quorumPublicKey); + verifyCount++; + + // We can reconstruct the CRecoveredSig objects from the islock and pass it to the signing manager, which + // avoids unnecessary double-verification of the signature. We however only do this when verification here + // turns out to be good (which is checked further down) + if (!m_is_manager.Sigman().HasRecoveredSigForId(llmq_params.type, id)) { + recSigs.try_emplace(hash, + llmq::CRecoveredSig(llmq_params.type, quorum->qc->quorumHash, id, islock->txid, islock->sig)); + } + } + + cxxtimer::Timer verifyTimer(true); + batchVerifier.Verify(); + verifyTimer.stop(); + + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- verified locks. count=%d, alreadyVerified=%d, vt=%d, nodes=%d\n", __func__, + verifyCount, alreadyVerified, verifyTimer.count(), batchVerifier.GetUniqueSourceCount()); + + Uint256HashSet badISLocks; + + if (ban && !batchVerifier.badSources.empty()) { + LOCK(::cs_main); + for (const auto& nodeId : batchVerifier.badSources) { + // Let's not be too harsh, as the peer might simply be unlucky and might have sent us an old lock which + // does not validate anymore due to changed quorums + m_peer_manager->PeerMisbehaving(nodeId, 20); + } + } + for (const auto& p : pend) { + const auto& hash = p.first; + auto nodeId = p.second.first; + const auto& islock = p.second.second; + + if (batchVerifier.badMessages.count(hash)) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: invalid sig in islock, peer=%d\n", + __func__, islock->txid.ToString(), hash.ToString(), nodeId); + badISLocks.emplace(hash); + continue; + } + + // TODO - remove it + std::vector> peer_activity; + peer_activity.emplace_back(nodeId, ProcessInstantSendLock(nodeId, hash, islock)); + + // See comment further on top. We pass a reconstructed recovered sig to the signing manager to avoid + // double-verification of the sig. + auto it = recSigs.find(hash); + if (it != recSigs.end()) { + auto recSig = std::make_shared(std::move(it->second)); + if (!m_is_manager.Sigman().HasRecoveredSigForId(llmq_params.type, recSig->getId())) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: passing reconstructed recSig to signing mgr, peer=%d\n", __func__, + islock->txid.ToString(), hash.ToString(), nodeId); + m_is_manager.Sigman().PushReconstructedRecoveredSig(recSig); + } + } + } + + return badISLocks; +} + -void NetInstantSend::ProcessPendingISLocks(const Uint256HashMap>& locks_to_process) +void NetInstantSend::ProcessPendingISLocks(Uint256HashMap>&& locks_to_process) { // TODO Investigate if leaving this is ok auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; @@ -117,7 +238,7 @@ void NetInstantSend::WorkThreadMain() if (!m_is_manager.IsInstantSendEnabled()) return false; auto [more_work, locks] = m_is_manager.GetPendingLocks(); - ProcessPendingISLocks(locks); + ProcessPendingISLocks(std::move(locks)); /* for (auto& [node_id, mpr] : peer_activity) { m_peer_manager.PostProcessMessage(std::move(mpr), node_id); diff --git a/src/net_instantsend.h b/src/net_instantsend.h index ff34c2003c749..1d85a86b9274d 100644 --- a/src/net_instantsend.h +++ b/src/net_instantsend.h @@ -9,11 +9,17 @@ #include #include + +namespace instantsend +{ +struct InstantSendLock; +using InstantSendLockPtr = std::shared_ptr; +} // namespace instantsend namespace llmq { class CInstantSendManager; -} +} // namespace llmq -class NetInstantSend : public NetHandler +class NetInstantSend final : public NetHandler { public: NetInstantSend(PeerManagerInternal* peer_manager, llmq::CInstantSendManager& is_manager) @@ -24,14 +30,17 @@ class NetInstantSend : public NetHandler void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) override; - void Start(); - void Stop(); - void InterruptWorkerThread() { workInterrupt(); }; + void Start() override; + void Stop() override; + void Interrupt() override { workInterrupt(); }; void WorkThreadMain(); private: - void ProcessPendingISLocks(const Uint256HashMap>& locks_to_process); + void ProcessPendingISLocks(Uint256HashMap>&& locks_to_process); + Uint256HashSet ProcessPendingInstantSendLocks(const Consensus::LLMQParams& llmq_params, int signOffset, bool ban, + const Uint256HashMap>& pend); + // EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); llmq::CInstantSendManager& m_is_manager; std::thread workThread; From e8f660c2d67230bcc892b6752f23a4aaa43b7efc Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 28 Oct 2025 19:49:59 +0700 Subject: [PATCH 06/58] net-processing - added start/stop/interrupt --- src/net_processing.cpp | 24 ++++++++++++++++++++++++ src/net_processing.h | 6 ++++++ src/node/chainstate.cpp | 2 ++ 3 files changed, 32 insertions(+) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 630581824a676..0c0b6185e688e 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -643,6 +643,9 @@ class PeerManagerImpl final : public PeerManager size_t GetRequestedObjectCount(NodeId nodeid) const override EXCLUSIVE_LOCKS_REQUIRED(::cs_main); void AddExtraHandler(std::unique_ptr&& handler) override; void RemoveHandlers() override; + void StartHandlers() override; + void StopHandlers() override; + void InterruptHandlers() override; /** Implement PeerManagerInternal */ void PeerMisbehaving(const NodeId pnode, const int howmuch, const std::string& message = "") override; @@ -1647,6 +1650,27 @@ void PeerManagerImpl::RemoveHandlers() m_handlers.clear(); } +void PeerManagerImpl::StartHandlers() +{ + for (auto& handler : m_handlers) { + handler->Start(); + } +} + +void PeerManagerImpl::StopHandlers() +{ + for (auto& handler : m_handlers) { + handler->Stop(); + } +} + +void PeerManagerImpl::InterruptHandlers() +{ + for (auto& handler : m_handlers) { + handler->Interrupt(); + } +} + void PeerManagerImpl::UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) { LOCK(cs_main); diff --git a/src/net_processing.h b/src/net_processing.h index e21e690290e69..86ba0c31a60d5 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -68,6 +68,9 @@ class NetHandler NetHandler(PeerManagerInternal* peer_manager) : m_peer_manager{Assert(peer_manager)} {} virtual ~NetHandler() {} + virtual void Start() {} + virtual void Stop() {} + virtual void Interrupt() {} virtual void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) = 0; protected: PeerManagerInternal* m_peer_manager; @@ -155,6 +158,9 @@ class PeerManager : public CValidationInterface, public NetEventsInterface, publ virtual void AddExtraHandler(std::unique_ptr&& handler) = 0; virtual void RemoveHandlers() = 0; + virtual void StartHandlers() = 0; + virtual void StopHandlers() = 0; + virtual void InterruptHandlers() = 0; }; #endif // BITCOIN_NET_PROCESSING_H diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index b5e5714252079..d4650cc189d8d 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -240,6 +240,7 @@ void DashChainstateSetup(ChainstateManager& chainman, cpoolman.reset(); cpoolman = std::make_unique(*evodb); + // TODO: reconnect handlers! if (llmq_ctx) { llmq_ctx->Interrupt(); llmq_ctx->Stop(); @@ -255,6 +256,7 @@ void DashChainstateSetup(ChainstateManager& chainman, chain_helper = std::make_unique(*cpoolman, *dmnman, *mnhf_manager, govman, *(llmq_ctx->isman), *(llmq_ctx->quorum_block_processor), *(llmq_ctx->qsnapman), chainman, consensus_params, mn_sync, sporkman, *(llmq_ctx->clhandler), *(llmq_ctx->qman)); + } void DashChainstateSetupClose(std::unique_ptr& chain_helper, From 8b720dbe7d676730f8558d9114980cd2ed57e041 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 28 Oct 2025 20:28:41 +0700 Subject: [PATCH 07/58] part III --- src/instantsend/instantsend.cpp | 19 ++++++------------- src/instantsend/instantsend.h | 20 +++++++++++--------- src/msg_result.h | 8 -------- src/net_instantsend.cpp | 17 ++++++++++++----- src/net_processing.cpp | 29 ++++++++++++++++------------- src/net_processing.h | 3 +++ 6 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 6c360c731b429..0039db03e95d5 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -143,7 +143,7 @@ instantsend::PendingState CInstantSendManager::GetPendingLocks() return ret; } -MessageProcessingResult CInstantSendManager::ProcessInstantSendLock(NodeId from, const uint256& hash, +std::variant CInstantSendManager::ProcessInstantSendLock(NodeId from, const uint256& hash, const instantsend::InstantSendLockPtr& islock) { LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: processing islock, peer=%d\n", @@ -153,12 +153,12 @@ MessageProcessingResult CInstantSendManager::ProcessInstantSendLock(NodeId from, signer->ClearLockFromQueue(islock); } if (db.KnownInstantSendLock(hash)) { - return {}; + return std::monostate{}; } if (const auto sameTxIsLock = db.GetInstantSendLockByTxid(islock->txid)) { // can happen, nothing to do - return {}; + return std::monostate{}; } for (const auto& in : islock->inputs) { const auto sameOutpointIsLock = db.GetInstantSendLockByInput(in); @@ -181,7 +181,7 @@ MessageProcessingResult CInstantSendManager::ProcessInstantSendLock(NodeId from, if (pindexMined != nullptr && clhandler.HasChainLock(pindexMined->nHeight, pindexMined->GetBlockHash())) { LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txlock=%s, islock=%s: dropping islock as it already got a ChainLock in block %s, peer=%d\n", __func__, islock->txid.ToString(), hash.ToString(), hashBlock.ToString(), from); - return {}; + return std::monostate{}; } } @@ -212,17 +212,10 @@ MessageProcessingResult CInstantSendManager::ProcessInstantSendLock(NodeId from, mempool.AddTransactionsUpdated(1); } - MessageProcessingResult ret{}; - CInv inv(MSG_ISDLOCK, hash); if (found_transaction) { - ret.m_inv_filter = std::make_pair(inv, tx); - } else { - // we don't have the TX yet, so we only filter based on txid. Later when that TX arrives, we will re-announce - // with the TX taken into account. - ret.m_inv_filter = std::make_pair(inv, islock->txid); - ret.m_request_tx = islock->txid; + return tx; } - return ret; + return islock->txid; } void CInstantSendManager::TransactionAddedToMempool(const CTransactionRef& tx) diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index 6f15ac3cdf6d9..1ccc88dc1ffd4 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -5,21 +5,22 @@ #ifndef BITCOIN_INSTANTSEND_INSTANTSEND_H #define BITCOIN_INSTANTSEND_INSTANTSEND_H +#include +#include +#include + #include #include #include #include #include - -#include -#include -#include #include #include -#include #include #include +#include +#include class CBlockIndex; class CChainState; @@ -102,10 +103,6 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent private: - MessageProcessingResult ProcessInstantSendLock(NodeId from, const uint256& hash, - const instantsend::InstantSendLockPtr& islock) - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); - void AddNonLockedTx(const CTransactionRef& tx, const CBlockIndex* pindexMined) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_timingsTxSeen); void RemoveNonLockedTx(const uint256& txid, bool retryChildren) @@ -138,6 +135,11 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent CSigningManager& Sigman() { return sigman; } CQuorumManager& Qman() { return qman; } CChainState& Chainstate() { return m_chainstate; } + std::variant ProcessInstantSendLock( + NodeId from, const uint256& hash, + const instantsend::InstantSendLockPtr& islock) + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); + //---- // void TransactionAddedToMempool(const CTransactionRef& tx) diff --git a/src/msg_result.h b/src/msg_result.h index 01b14288ee274..d24f461571ecf 100644 --- a/src/msg_result.h +++ b/src/msg_result.h @@ -7,14 +7,12 @@ #include -#include #include #include #include #include #include -#include #include struct MisbehavingError @@ -54,12 +52,6 @@ struct MessageProcessingResult //! @m_dsq will relay DSQs to connected peers std::vector m_dsq; - //! @m_inv_filter will relay this inventory if filter matches to connected peers if not nullopt - std::optional>> m_inv_filter; - - //! @m_request_tx will ask connected peers to relay transaction if not nullopt - std::optional m_request_tx; - //! @m_transactions will relay transactions to peers which is ready to accept it (some peers does not accept transactions) std::vector m_transactions; diff --git a/src/net_instantsend.cpp b/src/net_instantsend.cpp index 7d751f1899ee8..d104267e8d021 100644 --- a/src/net_instantsend.cpp +++ b/src/net_instantsend.cpp @@ -183,9 +183,16 @@ Uint256HashSet NetInstantSend::ProcessPendingInstantSendLocks( continue; } - // TODO - remove it - std::vector> peer_activity; - peer_activity.emplace_back(nodeId, ProcessInstantSendLock(nodeId, hash, islock)); + CInv inv(MSG_ISDLOCK, hash); + auto ret = m_is_manager.ProcessInstantSendLock(nodeId, hash, islock); + if (std::holds_alternative(ret)) { + m_peer_manager->PeerRelayInvFiltered(inv, std::get(ret)); + m_peer_manager->PeerAskPeersForTransaction(islock->txid); + } else if (std::holds_alternative(ret)) { + m_peer_manager->PeerRelayInvFiltered(inv, *std::get(ret)); + } else { + assert(std::holds_alternative(ret)); + } // See comment further on top. We pass a reconstructed recovered sig to the signing manager to avoid // double-verification of the sig. @@ -214,7 +221,7 @@ void NetInstantSend::ProcessPendingISLocks(Uint256HashMap(filter)) { - RelayInvFiltered(inv, *std::get(filter)); - } else if (std::holds_alternative(filter)) { - RelayInvFiltered(inv, std::get(filter)); - } else { - assert(false); - } - } - if (result.m_request_tx) { - AskPeersForTransaction(result.m_request_tx.value()); - } } MessageProcessingResult PeerManagerImpl::ProcessPlatformBanMessage(NodeId node, std::string_view msg_type, CDataStream& vRecv) @@ -6525,3 +6515,16 @@ void PeerManagerImpl::PeerEraseObjectRequest(const NodeId nodeid, const CInv& in { EraseObjectRequest(nodeid, inv); } +void PeerManagerImpl::PeerRelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) +{ + RelayInvFiltered(inv, relatedTx); +} +void PeerManagerImpl::PeerRelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) +{ + RelayInvFiltered(inv, relatedTxHash); +} + +void PeerManagerImpl::PeerAskPeersForTransaction(const uint256& txid) +{ + AskPeersForTransaction(txid); +} diff --git a/src/net_processing.h b/src/net_processing.h index 86ba0c31a60d5..6612e3fdc6301 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -60,6 +60,9 @@ class PeerManagerInternal public: virtual void PeerMisbehaving(const NodeId pnode, const int howmuch, const std::string& message = "") = 0; virtual void PeerEraseObjectRequest(const NodeId nodeid, const CInv& inv) = 0; + virtual void PeerRelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) = 0; + virtual void PeerRelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) = 0; + virtual void PeerAskPeersForTransaction(const uint256& txid) = 0; }; class NetHandler From 229eb14de15af5b8f3ba5a1e3c2cf31ac439b917 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 28 Oct 2025 21:15:02 +0700 Subject: [PATCH 08/58] lint - update list of circular dependencies --- test/lint/lint-circular-dependencies.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py index 00073f64865ec..bea7aa31cd58f 100755 --- a/test/lint/lint-circular-dependencies.py +++ b/test/lint/lint-circular-dependencies.py @@ -24,15 +24,15 @@ # Dash "banman -> common/bloom -> evo/assetlocktx -> llmq/quorums -> net -> banman", "chainlock/chainlock -> instantsend/instantsend -> chainlock/chainlock", + "chainlock/chainlock -> chainlock/signing -> llmq/signing -> net_processing -> chainlock/chainlock", + "chainlock/chainlock -> chainlock/signing -> llmq/signing -> net_processing -> masternode/active/context -> chainlock/chainlock", "chainlock/chainlock -> instantsend/instantsend -> instantsend/signing -> chainlock/chainlock", - "chainlock/chainlock -> instantsend/instantsend -> net_processing -> chainlock/chainlock", - "chainlock/chainlock -> instantsend/instantsend -> net_processing -> masternode/active/context -> chainlock/chainlock", "chainlock/chainlock -> llmq/quorums -> msg_result -> coinjoin/coinjoin -> chainlock/chainlock", "chainlock/chainlock -> validation -> chainlock/chainlock", "chainlock/chainlock -> validation -> evo/chainhelper -> chainlock/chainlock", - "chainlock/signing -> instantsend/instantsend -> net_processing -> masternode/active/context -> chainlock/signing", - "coinjoin/client -> coinjoin/coinjoin -> instantsend/instantsend -> net_processing -> coinjoin/walletman -> coinjoin/client", - "coinjoin/coinjoin -> instantsend/instantsend -> llmq/quorums -> msg_result -> coinjoin/coinjoin", + "chainlock/signing -> llmq/signing -> net_processing -> masternode/active/context -> chainlock/signing", + "coinjoin/coinjoin -> instantsend/instantsend -> spork -> msg_result -> coinjoin/coinjoin", + "coinjoin/client -> core_io -> evo/mnhftx -> llmq/signing -> net_processing -> coinjoin/walletman -> coinjoin/client", "coinjoin/server -> net_processing -> coinjoin/server", "coinjoin/server -> net_processing -> masternode/active/context -> coinjoin/server", "common/bloom -> evo/assetlocktx -> llmq/commitment -> evo/deterministicmns -> evo/simplifiedmns -> merkleblock -> common/bloom", @@ -54,9 +54,8 @@ "governance/governance -> masternode/sync -> governance/governance", "governance/governance -> net_processing -> masternode/active/context -> governance/governance", "governance/governance -> net_processing -> governance/governance", - "instantsend/instantsend -> net_processing -> instantsend/instantsend", - "instantsend/instantsend -> net_processing -> llmq/context -> instantsend/instantsend", - "instantsend/instantsend -> net_processing -> masternode/active/context -> instantsend/instantsend", + "instantsend/instantsend -> instantsend/signing -> llmq/signing -> net_processing -> instantsend/instantsend", + "instantsend/instantsend -> instantsend/signing -> llmq/signing -> net_processing -> masternode/active/context -> instantsend/instantsend", "instantsend/instantsend -> txmempool -> instantsend/instantsend", "instantsend/signing -> llmq/signing -> net_processing -> masternode/active/context -> instantsend/signing", "llmq/blockprocessor -> llmq/utils -> llmq/snapshot -> llmq/blockprocessor", From 51ec5ae89d3b1f7a4ca21120d1a0e5dd7ecfb60c Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 28 Oct 2025 22:07:56 +0700 Subject: [PATCH 09/58] fixup crash during RemoveHandlers --- src/net_processing.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/net_processing.h b/src/net_processing.h index 6612e3fdc6301..d2e074d8b0b06 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -69,7 +69,10 @@ class NetHandler { public: NetHandler(PeerManagerInternal* peer_manager) : m_peer_manager{Assert(peer_manager)} {} - virtual ~NetHandler() {} + virtual ~NetHandler() { + Interrupt(); + Stop(); + } virtual void Start() {} virtual void Stop() {} From 6b0fab637e05c41fd86bcf15d5b71efb86aa4e28 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 28 Oct 2025 22:32:52 +0700 Subject: [PATCH 10/58] refactor: drop Qman from CInstantSendManager --- src/init.cpp | 2 +- src/instantsend/instantsend.cpp | 3 +-- src/instantsend/instantsend.h | 5 +---- src/llmq/context.cpp | 2 +- src/net_instantsend.cpp | 4 ++-- src/net_instantsend.h | 7 ++++--- src/test/util/setup_common.cpp | 2 +- 7 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 18818f0024356..f693b5e0a9c06 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2180,7 +2180,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) g_active_notification_interface = std::make_unique(*node.active_ctx, *node.mn_activeman); RegisterValidationInterface(g_active_notification_interface.get()); } - node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.llmq_ctx->isman)); + node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.llmq_ctx->isman, *node.llmq_ctx->qman)); // ********************************************************* Step 7d: Setup other Dash services diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 0039db03e95d5..e4b167bdc351e 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -48,13 +48,12 @@ Uint256HashSet GetIdsFromLockable(const std::vector& vec) } } // anonymous namespace -CInstantSendManager::CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CQuorumManager& _qman, +CInstantSendManager::CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CSigningManager& _sigman, CSporkManager& sporkman, CTxMemPool& _mempool, const CMasternodeSync& mn_sync, bool unitTests, bool fWipe) : db{unitTests, fWipe}, clhandler{_clhandler}, m_chainstate{chainstate}, - qman{_qman}, sigman{_sigman}, spork_manager{sporkman}, mempool{_mempool}, diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index 1ccc88dc1ffd4..20cf9ba6208cb 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -43,7 +43,6 @@ struct PendingState { namespace llmq { class CChainLocksHandler; -class CQuorumManager; class CSigningManager; class CInstantSendManager final : public instantsend::InstantSendSignerParent @@ -53,7 +52,6 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent CChainLocksHandler& clhandler; CChainState& m_chainstate; - CQuorumManager& qman; CSigningManager& sigman; CSporkManager& spork_manager; CTxMemPool& mempool; @@ -86,7 +84,7 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent Uint256HashMap timingsTxSeen GUARDED_BY(cs_timingsTxSeen); public: - explicit CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CQuorumManager& _qman, + explicit CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CSigningManager& _sigman, CSporkManager& sporkman, CTxMemPool& _mempool, const CMasternodeSync& mn_sync, bool unitTests, bool fWipe); ~CInstantSendManager(); @@ -133,7 +131,6 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent std::vector PrepareTxToRetry() EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, cs_pendingRetry); instantsend::PendingState GetPendingLocks(); CSigningManager& Sigman() { return sigman; } - CQuorumManager& Qman() { return qman; } CChainState& Chainstate() { return m_chainstate; } std::variant ProcessInstantSendLock( NodeId from, const uint256& hash, diff --git a/src/llmq/context.cpp b/src/llmq/context.cpp index 499f2b1f16351..d84d5121fbf87 100644 --- a/src/llmq/context.cpp +++ b/src/llmq/context.cpp @@ -32,7 +32,7 @@ LLMQContext::LLMQContext(ChainstateManager& chainman, CDeterministicMNManager& d unit_tests, wipe)}, sigman{std::make_unique(chainman.ActiveChainstate(), *qman, unit_tests, wipe)}, clhandler{std::make_unique(chainman.ActiveChainstate(), *qman, sporkman, mempool, mn_sync)}, - isman{std::make_unique(*clhandler, chainman.ActiveChainstate(), *qman, *sigman, sporkman, + isman{std::make_unique(*clhandler, chainman.ActiveChainstate(), *sigman, sporkman, mempool, mn_sync, unit_tests, wipe)} { // Have to start it early to let VerifyDB check ChainLock signatures in coinbase diff --git a/src/net_instantsend.cpp b/src/net_instantsend.cpp index d104267e8d021..6096c4b886442 100644 --- a/src/net_instantsend.cpp +++ b/src/net_instantsend.cpp @@ -133,9 +133,9 @@ Uint256HashSet NetInstantSend::ProcessPendingInstantSendLocks( nSignHeight = blockIndex->nHeight + dkgInterval - 1; } // For RegTest non-rotating quorum cycleHash has directly quorum hash - auto quorum = llmq_params.useRotation ? llmq::SelectQuorumForSigning(llmq_params, m_is_manager.Chainstate().m_chain, m_is_manager.Qman(), + auto quorum = llmq_params.useRotation ? llmq::SelectQuorumForSigning(llmq_params, m_is_manager.Chainstate().m_chain, m_qman, id, nSignHeight, signOffset) - : m_is_manager.Qman().GetQuorum(llmq_params.type, islock->cycleHash); + : m_qman.GetQuorum(llmq_params.type, islock->cycleHash); if (!quorum) { // should not happen, but if one fails to select, all others will also fail to select diff --git a/src/net_instantsend.h b/src/net_instantsend.h index 1d85a86b9274d..414dcfdce4ace 100644 --- a/src/net_instantsend.h +++ b/src/net_instantsend.h @@ -17,17 +17,17 @@ using InstantSendLockPtr = std::shared_ptr; } // namespace instantsend namespace llmq { class CInstantSendManager; +class CQuorumManager; } // namespace llmq class NetInstantSend final : public NetHandler { public: - NetInstantSend(PeerManagerInternal* peer_manager, llmq::CInstantSendManager& is_manager) - : NetHandler(peer_manager), m_is_manager{is_manager} + NetInstantSend(PeerManagerInternal* peer_manager, llmq::CInstantSendManager& is_manager, llmq::CQuorumManager& qman) + : NetHandler(peer_manager), m_is_manager{is_manager}, m_qman(qman) { workInterrupt.reset(); } - void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) override; void Start() override; @@ -42,6 +42,7 @@ class NetInstantSend final : public NetHandler const Uint256HashMap>& pend); // EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); llmq::CInstantSendManager& m_is_manager; + llmq::CQuorumManager& m_qman; std::thread workThread; CThreadInterrupt workInterrupt; diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index a83224e8f6262..e226463da703d 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -365,7 +365,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vectorAddExtraHandler(std::make_unique(m_node.peerman.get(), *m_node.llmq_ctx->isman)); + m_node.peerman->AddExtraHandler(std::make_unique(m_node.peerman.get(), *m_node.llmq_ctx->isman, *m_node.llmq_ctx->qman)); { CConnman::Options options; options.m_msgproc = m_node.peerman.get(); From 6199e31162ddca331a7004e9b0ec06b0bfcea209 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 28 Oct 2025 22:33:30 +0700 Subject: [PATCH 11/58] fixup RemoveHandlers --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index f693b5e0a9c06..0fd71d3796da6 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -273,7 +273,7 @@ void PrepareShutdown(NodeContext& node) StopREST(); StopRPC(); StopHTTPServer(); - node.peerman->RemoveHandlers(); + if (node.peerman) node.peerman->RemoveHandlers(); if (node.active_ctx) node.active_ctx->Stop(); if (node.peerman) node.peerman->StopHandlers(); From 94c893af6fa2edee3484ab4bcf84e94529497a4a Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 28 Oct 2025 22:45:09 +0700 Subject: [PATCH 12/58] add TODO for mempool in instantsend --- src/instantsend/instantsend.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index e4b167bdc351e..b2ff9d0231c8a 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -168,6 +168,7 @@ std::variant CInstantSendManager::Proc } uint256 hashBlock{}; + // TODO: move GetTransaction to NetInstantsend ; keep it here const auto tx = GetTransaction(nullptr, &mempool, islock->txid, Params().GetConsensus(), hashBlock); const CBlockIndex* pindexMined{nullptr}; const bool found_transaction{tx != nullptr}; From 6c80da66bfeab2cbaae92128e6437da672dcac0c Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 28 Oct 2025 22:52:07 +0700 Subject: [PATCH 13/58] fix handlers!!! --- src/net_processing.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 788b8f5431ff0..d1284ef9bd11c 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1650,6 +1650,8 @@ void PeerManagerImpl::AddExtraHandler(std::unique_ptr&& handler) void PeerManagerImpl::RemoveHandlers() { + InterruptHandlers(); + StopHandlers(); m_handlers.clear(); } From af72e3b7109ed610da79527120914646518851a6 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Wed, 29 Oct 2025 01:42:07 +0700 Subject: [PATCH 14/58] refactor: use new NetHandler for llmq/signing module. Almost done! --- src/Makefile.am | 2 + src/init.cpp | 2 + src/llmq/context.cpp | 5 +- src/llmq/signing.cpp | 193 +++------------------------------ src/llmq/signing.h | 41 +++---- src/llmq/signing_shares.cpp | 22 +++- src/llmq/signing_shares.h | 1 + src/net_instantsend.h | 1 - src/net_processing.cpp | 1 - src/net_signing.cpp | 170 +++++++++++++++++++++++++++++ src/net_signing.h | 41 +++++++ src/test/util/setup_common.cpp | 2 + 12 files changed, 271 insertions(+), 210 deletions(-) create mode 100644 src/net_signing.cpp create mode 100644 src/net_signing.h diff --git a/src/Makefile.am b/src/Makefile.am index 2fd3add2a983d..a84c3b2efdf71 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -297,6 +297,7 @@ BITCOIN_CORE_H = \ net_permissions.h \ net_processing.h \ net_instantsend.h \ + net_signing.h \ net_types.h \ netaddress.h \ netbase.h \ @@ -559,6 +560,7 @@ libbitcoin_node_a_SOURCES = \ netgroup.cpp \ net_processing.cpp \ net_instantsend.cpp \ + net_signing.cpp \ node/blockstorage.cpp \ node/caches.cpp \ node/chainstate.cpp \ diff --git a/src/init.cpp b/src/init.cpp index 0fd71d3796da6..f6a196c5f152c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -2181,6 +2182,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) RegisterValidationInterface(g_active_notification_interface.get()); } node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.llmq_ctx->isman, *node.llmq_ctx->qman)); + node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.llmq_ctx->sigman)); // ********************************************************* Step 7d: Setup other Dash services diff --git a/src/llmq/context.cpp b/src/llmq/context.cpp index d84d5121fbf87..0ee243180f749 100644 --- a/src/llmq/context.cpp +++ b/src/llmq/context.cpp @@ -30,7 +30,7 @@ LLMQContext::LLMQContext(ChainstateManager& chainman, CDeterministicMNManager& d qman{std::make_unique(*bls_worker, chainman.ActiveChainstate(), dmnman, *qdkgsman, evo_db, *quorum_block_processor, *qsnapman, mn_activeman, mn_sync, sporkman, unit_tests, wipe)}, - sigman{std::make_unique(chainman.ActiveChainstate(), *qman, unit_tests, wipe)}, + sigman{std::make_unique(*qman, unit_tests, wipe)}, clhandler{std::make_unique(chainman.ActiveChainstate(), *qman, sporkman, mempool, mn_sync)}, isman{std::make_unique(*clhandler, chainman.ActiveChainstate(), *sigman, sporkman, mempool, mn_sync, unit_tests, wipe)} @@ -44,19 +44,16 @@ LLMQContext::~LLMQContext() { } void LLMQContext::Interrupt() { - sigman->InterruptWorkerThread(); } void LLMQContext::Start(PeerManager& peerman) { qman->Start(); - sigman->StartWorkerThread(peerman); clhandler->Start(*isman); } void LLMQContext::Stop() { clhandler->Stop(); - sigman->StopWorkerThread(); qman->Stop(); } diff --git a/src/llmq/signing.cpp b/src/llmq/signing.cpp index 8ed8640c60cbb..975369e3e270d 100644 --- a/src/llmq/signing.cpp +++ b/src/llmq/signing.cpp @@ -7,20 +7,16 @@ #include #include #include -#include -#include #include -#include #include #include #include -#include #include +#include #include #include #include -#include #include #include @@ -332,9 +328,8 @@ void CRecoveredSigsDb::CleanupOldVotes(int64_t maxAge) ////////////////// -CSigningManager::CSigningManager(const CChainState& chainstate, const CQuorumManager& _qman, bool fMemory, bool fWipe) : +CSigningManager::CSigningManager(const CQuorumManager& _qman, bool fMemory, bool fWipe) : db(fMemory, fWipe), - m_chainstate(chainstate), qman(_qman) { } @@ -366,55 +361,12 @@ bool CSigningManager::GetRecoveredSigForGetData(const uint256& hash, CRecoveredS return true; } -static bool PreVerifyRecoveredSig(const CQuorumManager& quorum_manager, const CRecoveredSig& recoveredSig, bool& retBan) +void CSigningManager::ProcessRecoveredSig(NodeId from, std::shared_ptr&& recoveredSig) { - retBan = false; - - auto llmqType = recoveredSig.getLlmqType(); - if (!Params().GetLLMQ(llmqType).has_value()) { - retBan = true; - return false; - } - - auto quorum = quorum_manager.GetQuorum(llmqType, recoveredSig.getQuorumHash()); - - if (!quorum) { - LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not found\n", __func__, - recoveredSig.getQuorumHash().ToString()); - return false; - } - if (!IsQuorumActive(llmqType, quorum_manager, quorum->qc->quorumHash)) { - return false; - } - - return true; -} - -MessageProcessingResult CSigningManager::ProcessMessage(NodeId from, std::string_view msg_type, CDataStream& vRecv) -{ - if (msg_type != NetMsgType::QSIGREC) { - return {}; - } - - auto recoveredSig = std::make_shared(); - vRecv >> *recoveredSig; - - MessageProcessingResult ret{}; - ret.m_to_erase = CInv{MSG_QUORUM_RECOVERED_SIG, recoveredSig->GetHash()}; - - bool ban = false; - if (!PreVerifyRecoveredSig(qman, *recoveredSig, ban)) { - if (ban) { - ret.m_error = MisbehavingError{100}; - return ret; - } - return ret; - } - // It's important to only skip seen *valid* sig shares here. See comment for CBatchedSigShare // We don't receive recovered sigs in batches, but we do batched verification per node on these if (db.HasRecoveredSigForHash(recoveredSig->GetHash())) { - return ret; + return; } LogPrint(BCLog::LLMQ, "CSigningManager::%s -- signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__, @@ -425,11 +377,10 @@ MessageProcessingResult CSigningManager::ProcessMessage(NodeId from, std::string // no need to perform full verification LogPrint(BCLog::LLMQ, "CSigningManager::%s -- already pending reconstructed sig, signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__, recoveredSig->buildSignHash().ToString(), recoveredSig->getId().ToString(), recoveredSig->getMsgHash().ToString(), from); - return ret; + return; } pendingRecoveredSigs[from].emplace_back(recoveredSig); - return ret; } void CSigningManager::CollectPendingRecoveredSigsToVerify( @@ -499,88 +450,20 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify( } } -void CSigningManager::ProcessPendingReconstructedRecoveredSigs(PeerManager& peerman) +Uint256HashMap> CSigningManager::FetchPendingReconstructed() { - decltype(pendingReconstructedRecoveredSigs) m; - WITH_LOCK(cs_pending, swap(m, pendingReconstructedRecoveredSigs)); - - for (const auto& p : m) { - ProcessRecoveredSig(p.second, peerman); - } -} - -bool CSigningManager::ProcessPendingRecoveredSigs(PeerManager& peerman) -{ - std::unordered_map>> recSigsByNode; - std::unordered_map, CQuorumCPtr, StaticSaltedHasher> quorums; - - ProcessPendingReconstructedRecoveredSigs(peerman); - - const size_t nMaxBatchSize{32}; - CollectPendingRecoveredSigsToVerify(nMaxBatchSize, recSigsByNode, quorums); - if (recSigsByNode.empty()) { - return false; - } - - // It's ok to perform insecure batched verification here as we verify against the quorum public keys, which are not - // craftable by individual entities, making the rogue public key attack impossible - CBLSBatchVerifier batchVerifier(false, false); - - size_t verifyCount = 0; - for (const auto& p : recSigsByNode) { - NodeId nodeId = p.first; - const auto& v = p.second; - - for (const auto& recSig : v) { - // we didn't verify the lazy signature until now - if (!recSig->sig.Get().IsValid()) { - batchVerifier.badSources.emplace(nodeId); - break; - } - - const auto& quorum = quorums.at(std::make_pair(recSig->getLlmqType(), recSig->getQuorumHash())); - batchVerifier.PushMessage(nodeId, recSig->GetHash(), recSig->buildSignHash().Get(), recSig->sig.Get(), - quorum->qc->quorumPublicKey); - verifyCount++; - } - } - - cxxtimer::Timer verifyTimer(true); - batchVerifier.Verify(); - verifyTimer.stop(); - - LogPrint(BCLog::LLMQ, "CSigningManager::%s -- verified recovered sig(s). count=%d, vt=%d, nodes=%d\n", __func__, verifyCount, verifyTimer.count(), recSigsByNode.size()); - - Uint256HashSet processed; - for (const auto& p : recSigsByNode) { - NodeId nodeId = p.first; - const auto& v = p.second; - - if (batchVerifier.badSources.count(nodeId)) { - LogPrint(BCLog::LLMQ, "CSigningManager::%s -- invalid recSig from other node, banning peer=%d\n", __func__, nodeId); - peerman.Misbehaving(nodeId, 100); - continue; - } - - for (const auto& recSig : v) { - if (!processed.emplace(recSig->GetHash()).second) { - continue; - } - - ProcessRecoveredSig(recSig, peerman); - } - } - - return recSigsByNode.size() >= nMaxBatchSize; + Uint256HashMap> tmp; + WITH_LOCK(cs_pending, swap(tmp, pendingReconstructedRecoveredSigs)); + return tmp; } // signature must be verified already -void CSigningManager::ProcessRecoveredSig(const std::shared_ptr& recoveredSig, PeerManager& peerman) +bool CSigningManager::ProcessRecoveredSig(const std::shared_ptr& recoveredSig) { auto llmqType = recoveredSig->getLlmqType(); if (db.HasRecoveredSigForHash(recoveredSig->GetHash())) { - return; + return false; } auto signHash = recoveredSig->buildSignHash(); @@ -602,7 +485,7 @@ void CSigningManager::ProcessRecoveredSig(const std::shared_ptrGetHash())); - auto listeners = WITH_LOCK(cs_listeners, return recoveredSigsListeners); - for (auto& l : listeners) { - peerman.PostProcessMessage(l->HandleNewRecoveredSig(*recoveredSig)); - } + return true; +} - GetMainSignals().NotifyRecoveredSig(recoveredSig, recoveredSig->GetHash().ToString()); +std::vector CSigningManager::GetListeners() const +{ + LOCK(cs_listeners); + return recoveredSigsListeners; } void CSigningManager::PushReconstructedRecoveredSig(const std::shared_ptr& recoveredSig) @@ -704,47 +588,6 @@ bool CSigningManager::GetVoteForId(Consensus::LLMQType llmqType, const uint256& return db.GetVoteForId(llmqType, id, msgHashRet); } -void CSigningManager::StartWorkerThread(PeerManager& peerman) -{ - // can't start new thread if we have one running already - if (workThread.joinable()) { - assert(false); - } - - workThread = std::thread(&util::TraceThread, "recsigs", [this, &peerman] { WorkThreadMain(peerman); }); -} - -void CSigningManager::StopWorkerThread() -{ - // make sure to call InterruptWorkerThread() first - if (!workInterrupt) { - assert(false); - } - - if (workThread.joinable()) { - workThread.join(); - } -} - -void CSigningManager::InterruptWorkerThread() -{ - workInterrupt(); -} - -void CSigningManager::WorkThreadMain(PeerManager& peerman) -{ - while (!workInterrupt) { - bool fMoreWork = ProcessPendingRecoveredSigs(peerman); - - Cleanup(); - - // TODO Wakeup when pending signing is needed? - if (!fMoreWork && !workInterrupt.sleep_for(std::chrono::milliseconds(100))) { - return; - } - } -} - SignHash CSigBase::buildSignHash() const { return SignHash(llmqType, quorumHash, id, msgHash); } diff --git a/src/llmq/signing.h b/src/llmq/signing.h index 4f60be0320ee6..ed59c3e2c2517 100644 --- a/src/llmq/signing.h +++ b/src/llmq/signing.h @@ -7,22 +7,17 @@ #include #include -#include #include -#include #include +#include #include #include #include #include -#include - -#include #include #include -#include #include class CChainState; @@ -30,7 +25,6 @@ class CDataStream; class CDBBatch; class CDBWrapper; class CInv; -class PeerManager; struct RPCResult; class UniValue; @@ -38,6 +32,7 @@ class UniValue; namespace llmq { class CQuorumManager; class CSigSharesManager; +class SignHash; // Keep recovered signatures for a week. This is a "-maxrecsigsage" option default. static constexpr int64_t DEFAULT_MAX_RECOVERED_SIGS_AGE{60 * 60 * 24 * 7}; @@ -55,7 +50,7 @@ class CSigBase CSigBase() = default; public: - [[nodiscard]] constexpr auto getLlmqType() const { + [[nodiscard]] constexpr Consensus::LLMQType getLlmqType() const { return llmqType; } @@ -164,7 +159,6 @@ class CSigningManager private: CRecoveredSigsDb db; - const CChainState& m_chainstate; const CQuorumManager& qman; mutable Mutex cs_pending; @@ -180,12 +174,12 @@ class CSigningManager std::vector recoveredSigsListeners GUARDED_BY(cs_listeners); public: - CSigningManager(const CChainState& chainstate, const CQuorumManager& _qman, bool fMemory, bool fWipe); + CSigningManager(const CQuorumManager& _qman, bool fMemory, bool fWipe); bool AlreadyHave(const CInv& inv) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pending); bool GetRecoveredSigForGetData(const uint256& hash, CRecoveredSig& ret) const; - [[nodiscard]] MessageProcessingResult ProcessMessage(NodeId from, std::string_view msg_type, CDataStream& vRecv) + void ProcessRecoveredSig(NodeId from, std::shared_ptr&& recovered_sig) EXCLUSIVE_LOCKS_REQUIRED(!cs_pending); // This is called when a recovered signature was was reconstructed from another P2P message and is known to be valid @@ -199,20 +193,21 @@ class CSigningManager // allows AlreadyHave to keep returning true. Cleanup will later remove the remains void TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id); -private: + // Used by NetSigning: + const CQuorumManager& Qman() { return qman; } + Uint256HashMap> FetchPendingReconstructed() EXCLUSIVE_LOCKS_REQUIRED(!cs_pending); void CollectPendingRecoveredSigsToVerify( size_t maxUniqueSessions, std::unordered_map>>& retSigShares, std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& retQuorums) EXCLUSIVE_LOCKS_REQUIRED(!cs_pending); - void ProcessPendingReconstructedRecoveredSigs(PeerManager& peerman) - EXCLUSIVE_LOCKS_REQUIRED(!cs_pending, !cs_listeners); - bool ProcessPendingRecoveredSigs(PeerManager& peerman) - EXCLUSIVE_LOCKS_REQUIRED(!cs_pending, !cs_listeners); // called from the worker thread of CSigSharesManager + std::vector GetListeners() const EXCLUSIVE_LOCKS_REQUIRED(!cs_listeners); + // Returns true if recovered sigs should be send to listeners + bool ProcessRecoveredSig(const std::shared_ptr& recoveredSig) + EXCLUSIVE_LOCKS_REQUIRED(!cs_pending); +private: // Used by CSigSharesManager CRecoveredSigsDb& GetDb() { return db; } - void ProcessRecoveredSig(const std::shared_ptr& recoveredSig, PeerManager& peerman) - EXCLUSIVE_LOCKS_REQUIRED(!cs_pending, !cs_listeners); // Needed for access to GetDb() and ProcessRecoveredSig() friend class CSigSharesManager; @@ -230,16 +225,8 @@ class CSigningManager bool GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet) const; -private: - std::thread workThread; - CThreadInterrupt workInterrupt; - void Cleanup(); // called from the worker thread of CSigSharesManager - void WorkThreadMain(PeerManager& peerman) EXCLUSIVE_LOCKS_REQUIRED(!cs_pending, !cs_listeners); - public: - void StartWorkerThread(PeerManager& peerman); - void StopWorkerThread(); - void InterruptWorkerThread(); + void Cleanup(); }; template diff --git a/src/llmq/signing_shares.cpp b/src/llmq/signing_shares.cpp index 4b070416b9bb6..0dc8d8c9f7cfd 100644 --- a/src/llmq/signing_shares.cpp +++ b/src/llmq/signing_shares.cpp @@ -804,7 +804,16 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& auto rs = std::make_shared(quorum->params.type, quorum->qc->quorumHash, id, msgHash, recoveredSig); - sigman.ProcessRecoveredSig(rs, m_peerman); + if (sigman.ProcessRecoveredSig(rs )) { + // TODO: remove duplicated code with NetSigning + auto listeners = sigman.GetListeners(); + for (auto& l : listeners) { + // TODO: simplify it to std::variant + m_peerman.PostProcessMessage(l->HandleNewRecoveredSig(*recoveredSig)); + } + + GetMainSignals().NotifyRecoveredSig(recoveredSig, recoveredSig->GetHash().ToString()); + } return; // end of single-quorum processing } @@ -850,7 +859,16 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& } } - sigman.ProcessRecoveredSig(rs, m_peerman); + if (sigman.ProcessRecoveredSig(rs)) { + // TODO: remove duplicated code with NetSigning + auto listeners = sigman.GetListeners(); + for (auto& l : listeners) { + // TODO: simplify it to std::variant + m_peerman.PostProcessMessage(l->HandleNewRecoveredSig(*recoveredSig)); + } + + GetMainSignals().NotifyRecoveredSig(recoveredSig, recoveredSig->GetHash().ToString()); + } } CDeterministicMNCPtr CSigSharesManager::SelectMemberForRecovery(const CQuorumCPtr& quorum, const uint256 &id, int attempt) diff --git a/src/llmq/signing_shares.h b/src/llmq/signing_shares.h index fb2f692306fa3..88fd89fdb133c 100644 --- a/src/llmq/signing_shares.h +++ b/src/llmq/signing_shares.h @@ -7,6 +7,7 @@ #include #include +#include #include #include diff --git a/src/net_instantsend.h b/src/net_instantsend.h index 414dcfdce4ace..e496aac86bea7 100644 --- a/src/net_instantsend.h +++ b/src/net_instantsend.h @@ -2,7 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. - #ifndef BITCOIN_NET_INSTANTSEND_H #define BITCOIN_NET_INSTANTSEND_H diff --git a/src/net_processing.cpp b/src/net_processing.cpp index d1284ef9bd11c..28d9e693a8b09 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -5415,7 +5415,6 @@ void PeerManagerImpl::ProcessMessage( PostProcessMessage(m_llmq_ctx->quorum_block_processor->ProcessMessage(pfrom, msg_type, vRecv), pfrom.GetId()); PostProcessMessage(m_llmq_ctx->qdkgsman->ProcessMessage(pfrom, is_masternode, msg_type, vRecv), pfrom.GetId()); PostProcessMessage(m_llmq_ctx->qman->ProcessMessage(pfrom, m_connman, msg_type, vRecv), pfrom.GetId()); - PostProcessMessage(m_llmq_ctx->sigman->ProcessMessage(pfrom.GetId(), msg_type, vRecv), pfrom.GetId()); PostProcessMessage(ProcessPlatformBanMessage(pfrom.GetId(), msg_type, vRecv), pfrom.GetId()); if (msg_type == NetMsgType::CLSIG) { diff --git a/src/net_signing.cpp b/src/net_signing.cpp new file mode 100644 index 0000000000000..4a4e120a5bd1d --- /dev/null +++ b/src/net_signing.cpp @@ -0,0 +1,170 @@ +// Copyright (c) 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 +#include + +#include + +static bool PreVerifyRecoveredSig(Consensus::LLMQType& llmqType, const llmq::CQuorumManager& quorum_manager, const llmq::CRecoveredSig& recoveredSig) +{ + auto quorum = quorum_manager.GetQuorum(llmqType, recoveredSig.getQuorumHash()); + + if (!quorum) { + LogPrint(BCLog::LLMQ, "NetSigning::%s -- quorum %s not found\n", __func__, + recoveredSig.getQuorumHash().ToString()); + return false; + } + if (!llmq::IsQuorumActive(llmqType, quorum_manager, quorum->qc->quorumHash)) { + return false; + } + + return true; +} + +void NetSigning::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) +{ + if (msg_type != NetMsgType::QSIGREC) return; + + auto recoveredSig = std::make_shared(); + vRecv >> *recoveredSig; + + m_peer_manager->PeerEraseObjectRequest(pfrom.GetId(), CInv{MSG_QUORUM_RECOVERED_SIG, recoveredSig->GetHash()}; + + auto llmqType = recoveredSig.getLlmqType(); + if (!Params().GetLLMQ(llmqType).has_value()) { + m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100); + } + if (!PreVerifyRecoveredSig(llmqType, m_sig_manager.Qman(), *recoveredSig, ban)) { + return; + } + + m_sig_manager.ProcessRecoveredSig(pfrom.GetId(), std::move(recoveredSig)); + +} + +void NetSigning::Start() +{ + // can't start new thread if we have one running already + if (workThread.joinable()) { + assert(false); + } + + workThread = std::thread(&util::TraceThread, "recsigs", [this] { WorkThreadMain(); }); +} + +void NetSigning::Stop() +{ + // make sure to call InterruptWorkerThread() first + if (!workInterrupt) { + assert(false); + } + + if (workThread.joinable()) { + workThread.join(); + } +} + +void NetSigning::ProcessRecoveredSig(const std::shared_ptr& recoveredSig) +{ + if (!m_sig_manager.ProcessRecoveredSig(recoveredSig)) return; + + auto listeners = m_sig_manager.GetListeners(); + for (auto& l : listeners) { + // TODO: simplify it to std::variant + m_peer_manager->PostProcessMessage(l->HandleNewRecoveredSig(*recoveredSig)); + } + + GetMainSignals().NotifyRecoveredSig(recoveredSig, recoveredSig->GetHash().ToString()); +} + +bool NetSigning::ProcessPendingRecoveredSigs() +{ + Uint256HashMap> pending{m_sig_manager.FetchPendingReconstructed()}; + + for (const auto& p : pending) { + ProcessRecoveredSig(p.second); + } + + std::unordered_map>> recSigsByNode; + std::unordered_map, llmq::CQuorumCPtr, StaticSaltedHasher> quorums; + + const size_t nMaxBatchSize{32}; + m_sig_manager.CollectPendingRecoveredSigsToVerify(nMaxBatchSize, recSigsByNode, quorums); + if (recSigsByNode.empty()) { + return false; + } + + // It's ok to perform insecure batched verification here as we verify against the quorum public keys, which are not + // craftable by individual entities, making the rogue public key attack impossible + CBLSBatchVerifier batchVerifier(false, false); + + size_t verifyCount = 0; + for (const auto& p : recSigsByNode) { + NodeId nodeId = p.first; + const auto& v = p.second; + + for (const auto& recSig : v) { + // we didn't verify the lazy signature until now + if (!recSig->sig.Get().IsValid()) { + batchVerifier.badSources.emplace(nodeId); + break; + } + + const auto& quorum = quorums.at(std::make_pair(recSig->getLlmqType(), recSig->getQuorumHash())); + batchVerifier.PushMessage(nodeId, recSig->GetHash(), recSig->buildSignHash().Get(), recSig->sig.Get(), + quorum->qc->quorumPublicKey); + verifyCount++; + } + } + + cxxtimer::Timer verifyTimer(true); + batchVerifier.Verify(); + verifyTimer.stop(); + + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- verified recovered sig(s). count=%d, vt=%d, nodes=%d\n", __func__, verifyCount, verifyTimer.count(), recSigsByNode.size()); + + Uint256HashSet processed; + for (const auto& p : recSigsByNode) { + NodeId nodeId = p.first; + const auto& v = p.second; + + if (batchVerifier.badSources.count(nodeId)) { + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- invalid recSig from other node, banning peer=%d\n", __func__, nodeId); + m_peer_manager->PeerMisbehaving(nodeId, 100); + continue; + } + + for (const auto& recSig : v) { + if (!processed.emplace(recSig->GetHash()).second) { + continue; + } + + ProcessRecoveredSig(recSig); + } + } + + return recSigsByNode.size() >= nMaxBatchSize; +} + +void NetSigning::WorkThreadMain() +{ + while (!workInterrupt) { + bool fMoreWork = ProcessPendingRecoveredSigs(); + + m_sig_manager.Cleanup(); + + // TODO Wakeup when pending signing is needed? + if (!fMoreWork && !workInterrupt.sleep_for(std::chrono::milliseconds(100))) { + return; + } + } +} diff --git a/src/net_signing.h b/src/net_signing.h new file mode 100644 index 0000000000000..b252e182b015f --- /dev/null +++ b/src/net_signing.h @@ -0,0 +1,41 @@ +// Copyright (c) 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_NET_SIGNING_H +#define BITCOIN_NET_SIGNING_H + +#include + +#include + +namespace llmq { +class CSigningManager; +} // namespace llmq +class NetSigning final : public NetHandler +{ +public: + NetSigning(PeerManagerInternal* peer_manager, llmq::CSigningManager& sig_manager) + : NetHandler(peer_manager), m_sig_manager(sig_manager) + { + workInterrupt.reset(); + } + void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) override; + + bool ProcessPendingRecoveredSigs(); + void ProcessRecoveredSig(const std::shared_ptr& recoveredSig); + + void Start() override; + void Stop() override; + void Interrupt() override { workInterrupt(); }; + + void WorkThreadMain(); +private: + llmq::CSigningManager& m_sig_manager; + + std::thread workThread; + CThreadInterrupt workInterrupt; +}; + +#endif // BITCOIN_NET_SIGNING_H diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index e226463da703d..297fecad0f17c 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -366,6 +367,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vectorAddExtraHandler(std::make_unique(m_node.peerman.get(), *m_node.llmq_ctx->isman, *m_node.llmq_ctx->qman)); + m_node.peerman->AddExtraHandler(std::make_unique(m_node.peerman.get(), *m_node.llmq_ctx->sigman)); { CConnman::Options options; options.m_msgproc = m_node.peerman.get(); From d326c7a2bfb4902d10814d9bed6bc7e2e6c159c5 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Wed, 29 Oct 2025 15:14:06 +0700 Subject: [PATCH 15/58] continue implementation for llmq/signing --- src/llmq/signing.cpp | 5 +---- src/llmq/signing_shares.cpp | 10 +++++----- src/net_processing.cpp | 6 ++++++ src/net_processing.h | 2 ++ src/net_signing.cpp | 13 ++++++++----- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/llmq/signing.cpp b/src/llmq/signing.cpp index 975369e3e270d..fe8c3e53e97b8 100644 --- a/src/llmq/signing.cpp +++ b/src/llmq/signing.cpp @@ -10,15 +10,12 @@ #include #include -#include -#include #include #include -#include #include -#include #include +#include #include namespace llmq diff --git a/src/llmq/signing_shares.cpp b/src/llmq/signing_shares.cpp index 0dc8d8c9f7cfd..7366e79e422e6 100644 --- a/src/llmq/signing_shares.cpp +++ b/src/llmq/signing_shares.cpp @@ -804,15 +804,15 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& auto rs = std::make_shared(quorum->params.type, quorum->qc->quorumHash, id, msgHash, recoveredSig); - if (sigman.ProcessRecoveredSig(rs )) { + if (sigman.ProcessRecoveredSig(rs)) { // TODO: remove duplicated code with NetSigning auto listeners = sigman.GetListeners(); for (auto& l : listeners) { // TODO: simplify it to std::variant - m_peerman.PostProcessMessage(l->HandleNewRecoveredSig(*recoveredSig)); + m_peerman.PostProcessMessage(l->HandleNewRecoveredSig(*rs)); } - GetMainSignals().NotifyRecoveredSig(recoveredSig, recoveredSig->GetHash().ToString()); + GetMainSignals().NotifyRecoveredSig(rs, rs->GetHash().ToString()); } return; // end of single-quorum processing } @@ -864,10 +864,10 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& auto listeners = sigman.GetListeners(); for (auto& l : listeners) { // TODO: simplify it to std::variant - m_peerman.PostProcessMessage(l->HandleNewRecoveredSig(*recoveredSig)); + m_peerman.PostProcessMessage(l->HandleNewRecoveredSig(*rs)); } - GetMainSignals().NotifyRecoveredSig(recoveredSig, recoveredSig->GetHash().ToString()); + GetMainSignals().NotifyRecoveredSig(rs, rs->GetHash().ToString()); } } diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 28d9e693a8b09..6b13d26dafd99 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -653,6 +653,7 @@ class PeerManagerImpl final : public PeerManager void PeerRelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) override; void PeerRelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) override; void PeerAskPeersForTransaction(const uint256& txid) override; + void PeerPostProcessMessage(MessageProcessingResult&& ret) override; private: void _RelayTransaction(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_peer_mutex); @@ -6529,3 +6530,8 @@ void PeerManagerImpl::PeerAskPeersForTransaction(const uint256& txid) { AskPeersForTransaction(txid); } + +void PeerManagerImpl::PeerPostProcessMessage(MessageProcessingResult&& ret) +{ + PostProcessMessage(std::move(ret), -1); +} diff --git a/src/net_processing.h b/src/net_processing.h index d2e074d8b0b06..6aa1d4d259770 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -63,6 +63,8 @@ class PeerManagerInternal virtual void PeerRelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) = 0; virtual void PeerRelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) = 0; virtual void PeerAskPeersForTransaction(const uint256& txid) = 0; + // TODO: remove it! + virtual void PeerPostProcessMessage(MessageProcessingResult&& ret) = 0; }; class NetHandler diff --git a/src/net_signing.cpp b/src/net_signing.cpp index 4a4e120a5bd1d..fa9bdfe653586 100644 --- a/src/net_signing.cpp +++ b/src/net_signing.cpp @@ -6,10 +6,13 @@ #include #include -#include #include #include +#include #include +#include +#include +#include #include #include @@ -37,13 +40,13 @@ void NetSigning::ProcessMessage(CNode& pfrom, const std::string& msg_type, CData auto recoveredSig = std::make_shared(); vRecv >> *recoveredSig; - m_peer_manager->PeerEraseObjectRequest(pfrom.GetId(), CInv{MSG_QUORUM_RECOVERED_SIG, recoveredSig->GetHash()}; + m_peer_manager->PeerEraseObjectRequest(pfrom.GetId(), CInv{MSG_QUORUM_RECOVERED_SIG, recoveredSig->GetHash()}); - auto llmqType = recoveredSig.getLlmqType(); + auto llmqType = recoveredSig->getLlmqType(); if (!Params().GetLLMQ(llmqType).has_value()) { m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100); } - if (!PreVerifyRecoveredSig(llmqType, m_sig_manager.Qman(), *recoveredSig, ban)) { + if (!PreVerifyRecoveredSig(llmqType, m_sig_manager.Qman(), *recoveredSig)) { return; } @@ -80,7 +83,7 @@ void NetSigning::ProcessRecoveredSig(const std::shared_ptr - m_peer_manager->PostProcessMessage(l->HandleNewRecoveredSig(*recoveredSig)); + m_peer_manager->PeerPostProcessMessage(l->HandleNewRecoveredSig(*recoveredSig)); } GetMainSignals().NotifyRecoveredSig(recoveredSig, recoveredSig->GetHash().ToString()); From 589a8fbf0db3ab7fdf2266ad892355ee2005ed5a Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Wed, 29 Oct 2025 15:24:35 +0700 Subject: [PATCH 16/58] lint - update circular after llmq/signing breakage --- test/lint/lint-circular-dependencies.py | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py index bea7aa31cd58f..452ae5bf95606 100755 --- a/test/lint/lint-circular-dependencies.py +++ b/test/lint/lint-circular-dependencies.py @@ -24,24 +24,22 @@ # Dash "banman -> common/bloom -> evo/assetlocktx -> llmq/quorums -> net -> banman", "chainlock/chainlock -> instantsend/instantsend -> chainlock/chainlock", - "chainlock/chainlock -> chainlock/signing -> llmq/signing -> net_processing -> chainlock/chainlock", - "chainlock/chainlock -> chainlock/signing -> llmq/signing -> net_processing -> masternode/active/context -> chainlock/chainlock", + "chainlock/chainlock -> chainlock/signing -> llmq/signing_shares -> net_processing -> chainlock/chainlock", + "chainlock/chainlock -> chainlock/signing -> llmq/signing_shares -> net_processing -> llmq/context -> chainlock/chainlock", + "chainlock/chainlock -> chainlock/signing -> llmq/signing_shares -> net_processing -> masternode/active/context -> chainlock/chainlock", "chainlock/chainlock -> instantsend/instantsend -> instantsend/signing -> chainlock/chainlock", "chainlock/chainlock -> llmq/quorums -> msg_result -> coinjoin/coinjoin -> chainlock/chainlock", "chainlock/chainlock -> validation -> chainlock/chainlock", "chainlock/chainlock -> validation -> evo/chainhelper -> chainlock/chainlock", - "chainlock/signing -> llmq/signing -> net_processing -> masternode/active/context -> chainlock/signing", + "chainlock/signing -> llmq/signing_shares -> net_processing -> masternode/active/context -> chainlock/signing", "coinjoin/coinjoin -> instantsend/instantsend -> spork -> msg_result -> coinjoin/coinjoin", - "coinjoin/client -> core_io -> evo/mnhftx -> llmq/signing -> net_processing -> coinjoin/walletman -> coinjoin/client", + "coinjoin/client -> coinjoin/coinjoin -> instantsend/instantsend -> instantsend/signing -> llmq/signing_shares -> net_processing -> coinjoin/walletman -> coinjoin/client", "coinjoin/server -> net_processing -> coinjoin/server", "coinjoin/server -> net_processing -> masternode/active/context -> coinjoin/server", "common/bloom -> evo/assetlocktx -> llmq/commitment -> evo/deterministicmns -> evo/simplifiedmns -> merkleblock -> common/bloom", "common/bloom -> evo/assetlocktx -> llmq/quorums -> net -> common/bloom", "consensus/tx_verify -> evo/assetlocktx -> llmq/commitment -> validation -> consensus/tx_verify", "consensus/tx_verify -> evo/assetlocktx -> llmq/commitment -> validation -> txmempool -> consensus/tx_verify", - "core_io -> evo/mnhftx -> llmq/signing -> net_processing -> evo/smldiff -> core_io", - "core_io -> evo/mnhftx -> llmq/signing -> net_processing -> masternode/active/context -> governance/signing -> governance/classes -> core_io", - "core_io -> evo/mnhftx -> llmq/signing -> net_processing -> masternode/active/context -> governance/signing -> governance/object -> core_io", "evo/assetlocktx -> llmq/commitment -> validation -> txmempool -> evo/assetlocktx", "evo/chainhelper -> evo/specialtxman -> validation -> evo/chainhelper", "evo/deterministicmns -> index/txindex -> validation -> evo/deterministicmns", @@ -54,19 +52,16 @@ "governance/governance -> masternode/sync -> governance/governance", "governance/governance -> net_processing -> masternode/active/context -> governance/governance", "governance/governance -> net_processing -> governance/governance", - "instantsend/instantsend -> instantsend/signing -> llmq/signing -> net_processing -> instantsend/instantsend", - "instantsend/instantsend -> instantsend/signing -> llmq/signing -> net_processing -> masternode/active/context -> instantsend/instantsend", + "instantsend/instantsend -> instantsend/signing -> llmq/signing_shares -> net_processing -> instantsend/instantsend", + "instantsend/instantsend -> instantsend/signing -> llmq/signing_shares -> net_processing -> llmq/context -> instantsend/instantsend", + "instantsend/instantsend -> instantsend/signing -> llmq/signing_shares -> net_processing -> masternode/active/context -> instantsend/instantsend", "instantsend/instantsend -> txmempool -> instantsend/instantsend", - "instantsend/signing -> llmq/signing -> net_processing -> masternode/active/context -> instantsend/signing", + "instantsend/signing -> llmq/signing_shares -> net_processing -> masternode/active/context -> instantsend/signing", "llmq/blockprocessor -> llmq/utils -> llmq/snapshot -> llmq/blockprocessor", "llmq/commitment -> llmq/utils -> llmq/snapshot -> llmq/commitment", - "llmq/context -> llmq/signing -> net_processing -> llmq/context", - "llmq/context -> llmq/signing -> net_processing -> masternode/active/context -> llmq/context", "llmq/dkgsession -> llmq/dkgsessionmgr -> llmq/dkgsessionhandler -> llmq/dkgsession", "llmq/dkgsessionhandler -> net_processing -> llmq/dkgsessionmgr -> llmq/dkgsessionhandler", - "llmq/ehf_signals -> llmq/signing -> net_processing -> masternode/active/context -> llmq/ehf_signals", - "llmq/signing -> llmq/signing_shares -> llmq/signing", - "llmq/signing -> net_processing -> llmq/signing", + "llmq/ehf_signals -> llmq/signing_shares -> net_processing -> masternode/active/context -> llmq/ehf_signals", "llmq/signing_shares -> net_processing -> llmq/signing_shares", "llmq/signing_shares -> net_processing -> masternode/active/context -> llmq/signing_shares", "masternode/payments -> validation -> masternode/payments", From e38ffdcea3b04c33f81fa6ddfe862edcbf13356e Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Wed, 29 Oct 2025 20:18:15 +0700 Subject: [PATCH 17/58] refactor: move CCoinJoinQueue from coinjoin.h to common.h to drop dependency of msg_result on the heavy header It's temporary refactoring; may be discarded later --- src/coinjoin/client.cpp | 2 +- src/coinjoin/coinjoin.cpp | 28 ------------ src/coinjoin/coinjoin.h | 52 ---------------------- src/coinjoin/common.cpp | 31 ++++++++++++++ src/coinjoin/common.h | 57 ++++++++++++++++++++++++- src/coinjoin/server.cpp | 2 +- src/msg_result.h | 5 +-- src/net_processing.cpp | 4 +- test/lint/lint-circular-dependencies.py | 4 +- 9 files changed, 95 insertions(+), 90 deletions(-) diff --git a/src/coinjoin/client.cpp b/src/coinjoin/client.cpp index 88d5ee4f81870..b64941a9a2e5c 100644 --- a/src/coinjoin/client.cpp +++ b/src/coinjoin/client.cpp @@ -135,7 +135,7 @@ MessageProcessingResult CCoinJoinClientQueueManager::ProcessMessage(NodeId from, WITH_LOCK(cs_vecqueue, vecCoinJoinQueue.push_back(dsq)); } } // cs_ProcessDSQueue - ret.m_dsq.push_back(dsq); + ret.m_dsq = dsq; return ret; } diff --git a/src/coinjoin/coinjoin.cpp b/src/coinjoin/coinjoin.cpp index d48239927f1aa..970eca0c37a49 100644 --- a/src/coinjoin/coinjoin.cpp +++ b/src/coinjoin/coinjoin.cpp @@ -38,34 +38,6 @@ bool CCoinJoinEntry::AddScriptSig(const CTxIn& txin) return false; } -uint256 CCoinJoinQueue::GetSignatureHash() const -{ - return SerializeHash(*this, SER_GETHASH, PROTOCOL_VERSION); -} -uint256 CCoinJoinQueue::GetHash() const { return SerializeHash(*this, SER_NETWORK, PROTOCOL_VERSION); } - -bool CCoinJoinQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const -{ - if (!CBLSSignature(Span{vchSig}, false).VerifyInsecure(blsPubKey, GetSignatureHash(), false)) { - LogPrint(BCLog::COINJOIN, "CCoinJoinQueue::CheckSignature -- VerifyInsecure() failed\n"); - return false; - } - - return true; -} - -bool CCoinJoinQueue::IsTimeOutOfBounds(int64_t current_time) const -{ - return current_time - nTime > COINJOIN_QUEUE_TIMEOUT || - nTime - current_time > COINJOIN_QUEUE_TIMEOUT; -} - -[[nodiscard]] std::string CCoinJoinQueue::ToString() const -{ - return strprintf("nDenom=%d, nTime=%lld, fReady=%s, fTried=%s, masternode=%s", - nDenom, nTime, fReady ? "true" : "false", fTried ? "true" : "false", masternodeOutpoint.ToStringShort()); -} - uint256 CCoinJoinBroadcastTx::GetSignatureHash() const { return SerializeHash(*this, SER_GETHASH, PROTOCOL_VERSION); diff --git a/src/coinjoin/coinjoin.h b/src/coinjoin/coinjoin.h index b0c13beebbdbd..58e44ee4d58df 100644 --- a/src/coinjoin/coinjoin.h +++ b/src/coinjoin/coinjoin.h @@ -39,7 +39,6 @@ extern RecursiveMutex cs_main; // timeouts static constexpr int COINJOIN_AUTO_TIMEOUT_MIN = 5; static constexpr int COINJOIN_AUTO_TIMEOUT_MAX = 15; -static constexpr int COINJOIN_QUEUE_TIMEOUT = 30; static constexpr int COINJOIN_SIGNING_TIMEOUT = 15; static constexpr size_t COINJOIN_ENTRY_MAX_SIZE = 9; @@ -171,57 +170,6 @@ class CCoinJoinEntry }; -/** - * A currently in progress mixing merge and denomination information - */ -class CCoinJoinQueue -{ -public: - int nDenom{0}; - COutPoint masternodeOutpoint; - uint256 m_protxHash; - int64_t nTime{0}; - bool fReady{false}; //ready for submit - std::vector vchSig; - // memory only - bool fTried{false}; - - CCoinJoinQueue() = default; - - CCoinJoinQueue(int nDenom, const COutPoint& outpoint, const uint256& proTxHash, int64_t nTime, bool fReady) : - nDenom(nDenom), - masternodeOutpoint(outpoint), - m_protxHash(proTxHash), - nTime(nTime), - fReady(fReady) - { - } - - SERIALIZE_METHODS(CCoinJoinQueue, obj) - { - READWRITE(obj.nDenom, obj.m_protxHash, obj.nTime, obj.fReady); - if (!(s.GetType() & SER_GETHASH)) { - READWRITE(obj.vchSig); - } - } - - [[nodiscard]] uint256 GetHash() const; - [[nodiscard]] uint256 GetSignatureHash() const; - - /// Check if we have a valid Masternode address - [[nodiscard]] bool CheckSignature(const CBLSPublicKey& blsPubKey) const; - - /// Check if a queue is too old or too far into the future - [[nodiscard]] bool IsTimeOutOfBounds(int64_t current_time = GetAdjustedTime()) const; - - [[nodiscard]] std::string ToString() const; - - friend bool operator==(const CCoinJoinQueue& a, const CCoinJoinQueue& b) - { - return a.nDenom == b.nDenom && a.masternodeOutpoint == b.masternodeOutpoint && a.nTime == b.nTime && a.fReady == b.fReady; - } -}; - /** Helper class to store mixing transaction (tx) information. */ class CCoinJoinBroadcastTx diff --git a/src/coinjoin/common.cpp b/src/coinjoin/common.cpp index 8f1d29893eb95..e60c7bfe55396 100644 --- a/src/coinjoin/common.cpp +++ b/src/coinjoin/common.cpp @@ -4,7 +4,9 @@ #include +#include #include +#include #include namespace CoinJoin @@ -24,3 +26,32 @@ std::string DenominationToString(int nDenom) } } // namespace CoinJoin + // +uint256 CCoinJoinQueue::GetSignatureHash() const +{ + return SerializeHash(*this, SER_GETHASH, PROTOCOL_VERSION); +} +uint256 CCoinJoinQueue::GetHash() const { return SerializeHash(*this, SER_NETWORK, PROTOCOL_VERSION); } + +bool CCoinJoinQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const +{ + if (!CBLSSignature(Span{vchSig}, false).VerifyInsecure(blsPubKey, GetSignatureHash(), false)) { + LogPrint(BCLog::COINJOIN, "CCoinJoinQueue::CheckSignature -- VerifyInsecure() failed\n"); + return false; + } + + return true; +} + +bool CCoinJoinQueue::IsTimeOutOfBounds(int64_t current_time) const +{ + return current_time - nTime > COINJOIN_QUEUE_TIMEOUT || + nTime - current_time > COINJOIN_QUEUE_TIMEOUT; +} + +[[nodiscard]] std::string CCoinJoinQueue::ToString() const +{ + return strprintf("nDenom=%d, nTime=%lld, fReady=%s, fTried=%s, masternode=%s", + nDenom, nTime, fReady ? "true" : "false", fTried ? "true" : "false", masternodeOutpoint.ToStringShort()); +} + diff --git a/src/coinjoin/common.h b/src/coinjoin/common.h index 7b7c939f1184c..6148ef4f9dca0 100644 --- a/src/coinjoin/common.h +++ b/src/coinjoin/common.h @@ -7,11 +7,14 @@ #include #include +#include #include #include #include +class CBLSPublicKey; + /** Holds a mixing input */ class CTxDSIn : public CTxIn @@ -129,7 +132,59 @@ constexpr int CalculateAmountPriority(CAmount nInputAmount) //nondenom return largest first return -1 * (nInputAmount / COIN); } - } // namespace CoinJoin +/** + * A currently in progress mixing merge and denomination information + */ +static constexpr int COINJOIN_QUEUE_TIMEOUT = 30; +class CCoinJoinQueue +// TODO: move it inside CoinJoin namespace +{ +public: + int nDenom{0}; + COutPoint masternodeOutpoint; + uint256 m_protxHash; + int64_t nTime{0}; + bool fReady{false}; //ready for submit + std::vector vchSig; + // memory only + bool fTried{false}; + + CCoinJoinQueue() = default; + + CCoinJoinQueue(int nDenom, const COutPoint& outpoint, const uint256& proTxHash, int64_t nTime, bool fReady) : + nDenom(nDenom), + masternodeOutpoint(outpoint), + m_protxHash(proTxHash), + nTime(nTime), + fReady(fReady) + { + } + + SERIALIZE_METHODS(CCoinJoinQueue, obj) + { + READWRITE(obj.nDenom, obj.m_protxHash, obj.nTime, obj.fReady); + if (!(s.GetType() & SER_GETHASH)) { + READWRITE(obj.vchSig); + } + } + + [[nodiscard]] uint256 GetHash() const; + [[nodiscard]] uint256 GetSignatureHash() const; + + /// Check if we have a valid Masternode address + [[nodiscard]] bool CheckSignature(const CBLSPublicKey& blsPubKey) const; + + /// Check if a queue is too old or too far into the future + [[nodiscard]] bool IsTimeOutOfBounds(int64_t current_time = GetAdjustedTime()) const; + + [[nodiscard]] std::string ToString() const; + + friend bool operator==(const CCoinJoinQueue& a, const CCoinJoinQueue& b) + { + return a.nDenom == b.nDenom && a.masternodeOutpoint == b.masternodeOutpoint && a.nTime == b.nTime && a.fReady == b.fReady; + } +}; + #endif // BITCOIN_COINJOIN_COMMON_H diff --git a/src/coinjoin/server.cpp b/src/coinjoin/server.cpp index 6f7169af74864..4210c4f99d6c4 100644 --- a/src/coinjoin/server.cpp +++ b/src/coinjoin/server.cpp @@ -188,7 +188,7 @@ MessageProcessingResult CCoinJoinServer::ProcessDSQUEUE(NodeId from, CDataStream TRY_LOCK(cs_vecqueue, lockRecv); if (!lockRecv) return ret; vecCoinJoinQueue.push_back(dsq); - ret.m_dsq.push_back(dsq); + ret.m_dsq = dsq; } return ret; } diff --git a/src/msg_result.h b/src/msg_result.h index d24f461571ecf..e96731fbad87d 100644 --- a/src/msg_result.h +++ b/src/msg_result.h @@ -5,8 +5,7 @@ #ifndef BITCOIN_MSG_RESULT_H #define BITCOIN_MSG_RESULT_H -#include - +#include #include #include @@ -50,7 +49,7 @@ struct MessageProcessingResult std::vector m_inventory; //! @m_dsq will relay DSQs to connected peers - std::vector m_dsq; + std::optional m_dsq; //! @m_transactions will relay transactions to peers which is ready to accept it (some peers does not accept transactions) std::vector m_transactions; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 6b13d26dafd99..297b2c5a23dc3 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3567,8 +3567,8 @@ void PeerManagerImpl::PostProcessMessage(MessageProcessingResult&& result, NodeI for (const auto& inv : result.m_inventory) { RelayInv(inv); } - for (const auto& dsq : result.m_dsq) { - RelayDSQ(dsq); + if (result.m_dsq.has_value()) { + RelayDSQ(result.m_dsq.value()); } } diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py index 452ae5bf95606..7970cb0de15e1 100755 --- a/test/lint/lint-circular-dependencies.py +++ b/test/lint/lint-circular-dependencies.py @@ -28,11 +28,11 @@ "chainlock/chainlock -> chainlock/signing -> llmq/signing_shares -> net_processing -> llmq/context -> chainlock/chainlock", "chainlock/chainlock -> chainlock/signing -> llmq/signing_shares -> net_processing -> masternode/active/context -> chainlock/chainlock", "chainlock/chainlock -> instantsend/instantsend -> instantsend/signing -> chainlock/chainlock", - "chainlock/chainlock -> llmq/quorums -> msg_result -> coinjoin/coinjoin -> chainlock/chainlock", + "chainlock/chainlock -> chainlock/signing -> llmq/signing_shares -> net_processing -> coinjoin/walletman -> coinjoin/client -> coinjoin/coinjoin -> chainlock/chainlock", "chainlock/chainlock -> validation -> chainlock/chainlock", "chainlock/chainlock -> validation -> evo/chainhelper -> chainlock/chainlock", "chainlock/signing -> llmq/signing_shares -> net_processing -> masternode/active/context -> chainlock/signing", - "coinjoin/coinjoin -> instantsend/instantsend -> spork -> msg_result -> coinjoin/coinjoin", + "coinjoin/common -> core_io -> evo/cbtx -> llmq/blockprocessor -> msg_result -> coinjoin/common", "coinjoin/client -> coinjoin/coinjoin -> instantsend/instantsend -> instantsend/signing -> llmq/signing_shares -> net_processing -> coinjoin/walletman -> coinjoin/client", "coinjoin/server -> net_processing -> coinjoin/server", "coinjoin/server -> net_processing -> masternode/active/context -> coinjoin/server", From ec8568eaca3ee5eaa51201d65ce3b4d8817a01dc Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 30 Oct 2025 00:19:03 +0700 Subject: [PATCH 18/58] Revert "refactor: move CCoinJoinQueue from coinjoin.h to common.h to drop dependency of msg_result on the heavy header" This reverts commit e38ffdcea3b04c33f81fa6ddfe862edcbf13356e. --- src/coinjoin/client.cpp | 2 +- src/coinjoin/coinjoin.cpp | 28 ++++++++++++ src/coinjoin/coinjoin.h | 52 ++++++++++++++++++++++ src/coinjoin/common.cpp | 31 -------------- src/coinjoin/common.h | 57 +------------------------ src/coinjoin/server.cpp | 2 +- src/msg_result.h | 5 ++- src/net_processing.cpp | 4 +- test/lint/lint-circular-dependencies.py | 4 +- 9 files changed, 90 insertions(+), 95 deletions(-) diff --git a/src/coinjoin/client.cpp b/src/coinjoin/client.cpp index b64941a9a2e5c..88d5ee4f81870 100644 --- a/src/coinjoin/client.cpp +++ b/src/coinjoin/client.cpp @@ -135,7 +135,7 @@ MessageProcessingResult CCoinJoinClientQueueManager::ProcessMessage(NodeId from, WITH_LOCK(cs_vecqueue, vecCoinJoinQueue.push_back(dsq)); } } // cs_ProcessDSQueue - ret.m_dsq = dsq; + ret.m_dsq.push_back(dsq); return ret; } diff --git a/src/coinjoin/coinjoin.cpp b/src/coinjoin/coinjoin.cpp index 970eca0c37a49..d48239927f1aa 100644 --- a/src/coinjoin/coinjoin.cpp +++ b/src/coinjoin/coinjoin.cpp @@ -38,6 +38,34 @@ bool CCoinJoinEntry::AddScriptSig(const CTxIn& txin) return false; } +uint256 CCoinJoinQueue::GetSignatureHash() const +{ + return SerializeHash(*this, SER_GETHASH, PROTOCOL_VERSION); +} +uint256 CCoinJoinQueue::GetHash() const { return SerializeHash(*this, SER_NETWORK, PROTOCOL_VERSION); } + +bool CCoinJoinQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const +{ + if (!CBLSSignature(Span{vchSig}, false).VerifyInsecure(blsPubKey, GetSignatureHash(), false)) { + LogPrint(BCLog::COINJOIN, "CCoinJoinQueue::CheckSignature -- VerifyInsecure() failed\n"); + return false; + } + + return true; +} + +bool CCoinJoinQueue::IsTimeOutOfBounds(int64_t current_time) const +{ + return current_time - nTime > COINJOIN_QUEUE_TIMEOUT || + nTime - current_time > COINJOIN_QUEUE_TIMEOUT; +} + +[[nodiscard]] std::string CCoinJoinQueue::ToString() const +{ + return strprintf("nDenom=%d, nTime=%lld, fReady=%s, fTried=%s, masternode=%s", + nDenom, nTime, fReady ? "true" : "false", fTried ? "true" : "false", masternodeOutpoint.ToStringShort()); +} + uint256 CCoinJoinBroadcastTx::GetSignatureHash() const { return SerializeHash(*this, SER_GETHASH, PROTOCOL_VERSION); diff --git a/src/coinjoin/coinjoin.h b/src/coinjoin/coinjoin.h index 58e44ee4d58df..b0c13beebbdbd 100644 --- a/src/coinjoin/coinjoin.h +++ b/src/coinjoin/coinjoin.h @@ -39,6 +39,7 @@ extern RecursiveMutex cs_main; // timeouts static constexpr int COINJOIN_AUTO_TIMEOUT_MIN = 5; static constexpr int COINJOIN_AUTO_TIMEOUT_MAX = 15; +static constexpr int COINJOIN_QUEUE_TIMEOUT = 30; static constexpr int COINJOIN_SIGNING_TIMEOUT = 15; static constexpr size_t COINJOIN_ENTRY_MAX_SIZE = 9; @@ -170,6 +171,57 @@ class CCoinJoinEntry }; +/** + * A currently in progress mixing merge and denomination information + */ +class CCoinJoinQueue +{ +public: + int nDenom{0}; + COutPoint masternodeOutpoint; + uint256 m_protxHash; + int64_t nTime{0}; + bool fReady{false}; //ready for submit + std::vector vchSig; + // memory only + bool fTried{false}; + + CCoinJoinQueue() = default; + + CCoinJoinQueue(int nDenom, const COutPoint& outpoint, const uint256& proTxHash, int64_t nTime, bool fReady) : + nDenom(nDenom), + masternodeOutpoint(outpoint), + m_protxHash(proTxHash), + nTime(nTime), + fReady(fReady) + { + } + + SERIALIZE_METHODS(CCoinJoinQueue, obj) + { + READWRITE(obj.nDenom, obj.m_protxHash, obj.nTime, obj.fReady); + if (!(s.GetType() & SER_GETHASH)) { + READWRITE(obj.vchSig); + } + } + + [[nodiscard]] uint256 GetHash() const; + [[nodiscard]] uint256 GetSignatureHash() const; + + /// Check if we have a valid Masternode address + [[nodiscard]] bool CheckSignature(const CBLSPublicKey& blsPubKey) const; + + /// Check if a queue is too old or too far into the future + [[nodiscard]] bool IsTimeOutOfBounds(int64_t current_time = GetAdjustedTime()) const; + + [[nodiscard]] std::string ToString() const; + + friend bool operator==(const CCoinJoinQueue& a, const CCoinJoinQueue& b) + { + return a.nDenom == b.nDenom && a.masternodeOutpoint == b.masternodeOutpoint && a.nTime == b.nTime && a.fReady == b.fReady; + } +}; + /** Helper class to store mixing transaction (tx) information. */ class CCoinJoinBroadcastTx diff --git a/src/coinjoin/common.cpp b/src/coinjoin/common.cpp index e60c7bfe55396..8f1d29893eb95 100644 --- a/src/coinjoin/common.cpp +++ b/src/coinjoin/common.cpp @@ -4,9 +4,7 @@ #include -#include #include -#include #include namespace CoinJoin @@ -26,32 +24,3 @@ std::string DenominationToString(int nDenom) } } // namespace CoinJoin - // -uint256 CCoinJoinQueue::GetSignatureHash() const -{ - return SerializeHash(*this, SER_GETHASH, PROTOCOL_VERSION); -} -uint256 CCoinJoinQueue::GetHash() const { return SerializeHash(*this, SER_NETWORK, PROTOCOL_VERSION); } - -bool CCoinJoinQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const -{ - if (!CBLSSignature(Span{vchSig}, false).VerifyInsecure(blsPubKey, GetSignatureHash(), false)) { - LogPrint(BCLog::COINJOIN, "CCoinJoinQueue::CheckSignature -- VerifyInsecure() failed\n"); - return false; - } - - return true; -} - -bool CCoinJoinQueue::IsTimeOutOfBounds(int64_t current_time) const -{ - return current_time - nTime > COINJOIN_QUEUE_TIMEOUT || - nTime - current_time > COINJOIN_QUEUE_TIMEOUT; -} - -[[nodiscard]] std::string CCoinJoinQueue::ToString() const -{ - return strprintf("nDenom=%d, nTime=%lld, fReady=%s, fTried=%s, masternode=%s", - nDenom, nTime, fReady ? "true" : "false", fTried ? "true" : "false", masternodeOutpoint.ToStringShort()); -} - diff --git a/src/coinjoin/common.h b/src/coinjoin/common.h index 6148ef4f9dca0..7b7c939f1184c 100644 --- a/src/coinjoin/common.h +++ b/src/coinjoin/common.h @@ -7,14 +7,11 @@ #include #include -#include #include #include #include -class CBLSPublicKey; - /** Holds a mixing input */ class CTxDSIn : public CTxIn @@ -132,59 +129,7 @@ constexpr int CalculateAmountPriority(CAmount nInputAmount) //nondenom return largest first return -1 * (nInputAmount / COIN); } -} // namespace CoinJoin - -/** - * A currently in progress mixing merge and denomination information - */ -static constexpr int COINJOIN_QUEUE_TIMEOUT = 30; -class CCoinJoinQueue -// TODO: move it inside CoinJoin namespace -{ -public: - int nDenom{0}; - COutPoint masternodeOutpoint; - uint256 m_protxHash; - int64_t nTime{0}; - bool fReady{false}; //ready for submit - std::vector vchSig; - // memory only - bool fTried{false}; - - CCoinJoinQueue() = default; - - CCoinJoinQueue(int nDenom, const COutPoint& outpoint, const uint256& proTxHash, int64_t nTime, bool fReady) : - nDenom(nDenom), - masternodeOutpoint(outpoint), - m_protxHash(proTxHash), - nTime(nTime), - fReady(fReady) - { - } - SERIALIZE_METHODS(CCoinJoinQueue, obj) - { - READWRITE(obj.nDenom, obj.m_protxHash, obj.nTime, obj.fReady); - if (!(s.GetType() & SER_GETHASH)) { - READWRITE(obj.vchSig); - } - } - - [[nodiscard]] uint256 GetHash() const; - [[nodiscard]] uint256 GetSignatureHash() const; - - /// Check if we have a valid Masternode address - [[nodiscard]] bool CheckSignature(const CBLSPublicKey& blsPubKey) const; - - /// Check if a queue is too old or too far into the future - [[nodiscard]] bool IsTimeOutOfBounds(int64_t current_time = GetAdjustedTime()) const; - - [[nodiscard]] std::string ToString() const; - - friend bool operator==(const CCoinJoinQueue& a, const CCoinJoinQueue& b) - { - return a.nDenom == b.nDenom && a.masternodeOutpoint == b.masternodeOutpoint && a.nTime == b.nTime && a.fReady == b.fReady; - } -}; +} // namespace CoinJoin #endif // BITCOIN_COINJOIN_COMMON_H diff --git a/src/coinjoin/server.cpp b/src/coinjoin/server.cpp index 4210c4f99d6c4..6f7169af74864 100644 --- a/src/coinjoin/server.cpp +++ b/src/coinjoin/server.cpp @@ -188,7 +188,7 @@ MessageProcessingResult CCoinJoinServer::ProcessDSQUEUE(NodeId from, CDataStream TRY_LOCK(cs_vecqueue, lockRecv); if (!lockRecv) return ret; vecCoinJoinQueue.push_back(dsq); - ret.m_dsq = dsq; + ret.m_dsq.push_back(dsq); } return ret; } diff --git a/src/msg_result.h b/src/msg_result.h index e96731fbad87d..d24f461571ecf 100644 --- a/src/msg_result.h +++ b/src/msg_result.h @@ -5,7 +5,8 @@ #ifndef BITCOIN_MSG_RESULT_H #define BITCOIN_MSG_RESULT_H -#include +#include + #include #include @@ -49,7 +50,7 @@ struct MessageProcessingResult std::vector m_inventory; //! @m_dsq will relay DSQs to connected peers - std::optional m_dsq; + std::vector m_dsq; //! @m_transactions will relay transactions to peers which is ready to accept it (some peers does not accept transactions) std::vector m_transactions; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 297b2c5a23dc3..6b13d26dafd99 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3567,8 +3567,8 @@ void PeerManagerImpl::PostProcessMessage(MessageProcessingResult&& result, NodeI for (const auto& inv : result.m_inventory) { RelayInv(inv); } - if (result.m_dsq.has_value()) { - RelayDSQ(result.m_dsq.value()); + for (const auto& dsq : result.m_dsq) { + RelayDSQ(dsq); } } diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py index 7970cb0de15e1..452ae5bf95606 100755 --- a/test/lint/lint-circular-dependencies.py +++ b/test/lint/lint-circular-dependencies.py @@ -28,11 +28,11 @@ "chainlock/chainlock -> chainlock/signing -> llmq/signing_shares -> net_processing -> llmq/context -> chainlock/chainlock", "chainlock/chainlock -> chainlock/signing -> llmq/signing_shares -> net_processing -> masternode/active/context -> chainlock/chainlock", "chainlock/chainlock -> instantsend/instantsend -> instantsend/signing -> chainlock/chainlock", - "chainlock/chainlock -> chainlock/signing -> llmq/signing_shares -> net_processing -> coinjoin/walletman -> coinjoin/client -> coinjoin/coinjoin -> chainlock/chainlock", + "chainlock/chainlock -> llmq/quorums -> msg_result -> coinjoin/coinjoin -> chainlock/chainlock", "chainlock/chainlock -> validation -> chainlock/chainlock", "chainlock/chainlock -> validation -> evo/chainhelper -> chainlock/chainlock", "chainlock/signing -> llmq/signing_shares -> net_processing -> masternode/active/context -> chainlock/signing", - "coinjoin/common -> core_io -> evo/cbtx -> llmq/blockprocessor -> msg_result -> coinjoin/common", + "coinjoin/coinjoin -> instantsend/instantsend -> spork -> msg_result -> coinjoin/coinjoin", "coinjoin/client -> coinjoin/coinjoin -> instantsend/instantsend -> instantsend/signing -> llmq/signing_shares -> net_processing -> coinjoin/walletman -> coinjoin/client", "coinjoin/server -> net_processing -> coinjoin/server", "coinjoin/server -> net_processing -> masternode/active/context -> coinjoin/server", From 3b94f808246fa149fbf4ca4cf30a76691641319e Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 30 Oct 2025 01:01:44 +0700 Subject: [PATCH 19/58] refactor: break governance dependency over net_processing using NetGovernance part I --- src/Makefile.am | 2 ++ src/governance/governance.cpp | 37 +++++++------------------------ src/governance/governance.h | 15 ++++++------- src/init.cpp | 8 +++---- src/net_governance.cpp | 41 +++++++++++++++++++++++++++++++++++ src/net_governance.h | 26 ++++++++++++++++++++++ src/net_processing.cpp | 15 +++++++++++++ src/net_processing.h | 3 +++ 8 files changed, 106 insertions(+), 41 deletions(-) create mode 100644 src/net_governance.cpp create mode 100644 src/net_governance.h diff --git a/src/Makefile.am b/src/Makefile.am index a84c3b2efdf71..123ad55a6e6c1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -296,6 +296,7 @@ BITCOIN_CORE_H = \ net.h \ net_permissions.h \ net_processing.h \ + net_governance.h \ net_instantsend.h \ net_signing.h \ net_types.h \ @@ -559,6 +560,7 @@ libbitcoin_node_a_SOURCES = \ netfulfilledman.cpp \ netgroup.cpp \ net_processing.cpp \ + net_governance.cpp \ net_instantsend.cpp \ net_signing.cpp \ node/blockstorage.cpp \ diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 9d193de7036cb..2fe07749541ed 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -91,35 +91,6 @@ CGovernanceManager::~CGovernanceManager() m_db->Store(*this); } -void CGovernanceManager::Schedule(CScheduler& scheduler, CConnman& connman, PeerManager& peerman) -{ - assert(IsValid()); - - scheduler.scheduleEvery( - [this, &connman]() -> void { - if (!m_mn_sync.IsSynced()) return; - - // CHECK OBJECTS WE'VE ASKED FOR, REMOVE OLD ENTRIES - CleanOrphanObjects(); - RequestOrphanObjects(connman); - - // CHECK AND REMOVE - REPROCESS GOVERNANCE OBJECTS - CheckAndRemove(); - }, - std::chrono::minutes{5}); - - scheduler.scheduleEvery( - [this, &peerman]() -> void { - LOCK(cs_relay); - for (const auto& inv : m_relay_invs) { - peerman.RelayInv(inv); - } - m_relay_invs.clear(); - }, - // Tests need tighter timings to avoid timeouts, use more relaxed pacing otherwise - Params().IsMockableChain() ? std::chrono::seconds{1} : std::chrono::seconds{5}); -} - bool CGovernanceManager::LoadCache(bool load_cache) { assert(m_db != nullptr); @@ -562,6 +533,14 @@ void CGovernanceManager::CheckAndRemove() ToString(), m_requested_hash_time.size()); } +std::vector CGovernanceManager::FetchRelayInventory() +{ + std::vector ret; + LOCK(cs_relay); + swap(ret, m_relay_invs); + return ret; +} + const CGovernanceObject* CGovernanceManager::FindConstGovernanceObject(const uint256& nHash) const { AssertLockHeld(cs); diff --git a/src/governance/governance.h b/src/governance/governance.h index 8035985fdad60..8521018f94ea7 100644 --- a/src/governance/governance.h +++ b/src/governance/governance.h @@ -278,8 +278,6 @@ class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent const std::unique_ptr& dmnman, CMasternodeSync& mn_sync); ~CGovernanceManager(); - void Schedule(CScheduler& scheduler, CConnman& connman, PeerManager& peerman); - bool LoadCache(bool load_cache); bool IsValid() const override { return is_valid; } @@ -312,8 +310,6 @@ class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent void AddGovernanceObject(CGovernanceObject& govobj, const CNode* pfrom = nullptr) override EXCLUSIVE_LOCKS_REQUIRED(!cs_relay); - void CheckAndRemove(); - UniValue ToJson() const; void UpdatedBlockTip(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_relay); @@ -393,6 +389,13 @@ class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent std::vector> GetApprovedProposals(const CDeterministicMNList& tip_mn_list) override EXCLUSIVE_LOCKS_REQUIRED(!cs); + // used by NetGovernance + void RequestOrphanObjects(CConnman& connman); + void CleanOrphanObjects(); + void CheckAndRemove(); + //! This method clears internal data structure and returns a copy + std::vector FetchRelayInventory() EXCLUSIVE_LOCKS_REQUIRED(!cs_relay); + CMasternodeSync& GetMNSync() { return m_mn_sync; } private: //! Internal functions that require locks to be held CGovernanceObject* FindGovernanceObjectInternal(const uint256& nHash) EXCLUSIVE_LOCKS_REQUIRED(cs); @@ -417,10 +420,6 @@ class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent void AddCachedTriggers(); - void RequestOrphanObjects(CConnman& connman); - - void CleanOrphanObjects(); - void RemoveInvalidVotes(); }; diff --git a/src/init.cpp b/src/init.cpp index f6a196c5f152c..c2198b4fd5e9e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -2183,7 +2184,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.llmq_ctx->isman, *node.llmq_ctx->qman)); node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.llmq_ctx->sigman)); - + node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.govman)); // ********************************************************* Step 7d: Setup other Dash services @@ -2287,9 +2288,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.scheduler->scheduleEvery(std::bind(&CMasternodeUtils::DoMaintenance, std::ref(*node.connman), std::ref(*node.dmnman), std::ref(*node.mn_sync), node.cj_walletman.get()), std::chrono::minutes{1}); node.scheduler->scheduleEvery(std::bind(&CDeterministicMNManager::DoMaintenance, std::ref(*node.dmnman)), std::chrono::seconds{10}); - if (node.govman->IsValid()) { - node.govman->Schedule(*node.scheduler, *node.connman, *node.peerman); - } + + node.peerman->ScheduleHandlers(*node.scheduler); if (node.mn_activeman) { node.scheduler->scheduleEvery(std::bind(&CCoinJoinServer::DoMaintenance, std::ref(*node.active_ctx->cj_server)), std::chrono::seconds{1}); diff --git a/src/net_governance.cpp b/src/net_governance.cpp new file mode 100644 index 0000000000000..31d353c243371 --- /dev/null +++ b/src/net_governance.cpp @@ -0,0 +1,41 @@ +// Copyright (c) 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 + +class CConnman; + +void NetGovernance::Schedule(CScheduler& scheduler, CConnman& connman) +{ + if (!m_gov_manager.IsValid()) return; + + scheduler.scheduleEvery( + [this, &connman]() -> void { + if (!m_gov_manager.GetMNSync().IsSynced()) return; + + // CHECK OBJECTS WE'VE ASKED FOR, REMOVE OLD ENTRIES + m_gov_manager.CleanOrphanObjects(); + m_gov_manager.RequestOrphanObjects(connman); + + // CHECK AND REMOVE - REPROCESS GOVERNANCE OBJECTS + m_gov_manager.CheckAndRemove(); + }, + std::chrono::minutes{5}); + + scheduler.scheduleEvery( + [this]() -> void { + auto relay_invs = m_gov_manager.FetchRelayInventory(); + for (const auto& inv : relay_invs) { + m_peer_manager->PeerRelayInv(inv); + } + }, + // Tests need tighter timings to avoid timeouts, use more relaxed pacing otherwise + Params().IsMockableChain() ? std::chrono::seconds{1} : std::chrono::seconds{5}); +} + + diff --git a/src/net_governance.h b/src/net_governance.h new file mode 100644 index 0000000000000..572f14d40ebb2 --- /dev/null +++ b/src/net_governance.h @@ -0,0 +1,26 @@ +// Copyright (c) 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_NET_GOVERNANCE_H +#define BITCOIN_NET_GOVERNANCE_H + +#include + +//#include + +class CGovernanceManager; + +class NetGovernance final : public NetHandler +{ +public: + NetGovernance(PeerManagerInternal* peer_manager, CGovernanceManager& gov_manager) + : NetHandler(peer_manager), m_gov_manager(gov_manager) + { + } + void Schedule(CScheduler& scheduler, CConnman& connman) override; +private: + CGovernanceManager& m_gov_manager; +}; + +#endif // BITCOIN_NET_GOVERNANCE_H diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 6b13d26dafd99..1d10b3a73e6e1 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -646,10 +646,12 @@ class PeerManagerImpl final : public PeerManager void StartHandlers() override; void StopHandlers() override; void InterruptHandlers() override; + void ScheduleHandlers(CScheduler& scheduler) override; /** Implement PeerManagerInternal */ void PeerMisbehaving(const NodeId pnode, const int howmuch, const std::string& message = "") override; void PeerEraseObjectRequest(const NodeId nodeid, const CInv& inv) override; + void PeerRelayInv(const CInv& inv) override; void PeerRelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) override; void PeerRelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) override; void PeerAskPeersForTransaction(const uint256& txid) override; @@ -1677,6 +1679,12 @@ void PeerManagerImpl::InterruptHandlers() } } +void PeerManagerImpl::ScheduleHandlers(CScheduler& scheduler) +{ + for (auto& handler : m_handlers) { + handler->Schedule(scheduler, m_connman); + } +} void PeerManagerImpl::UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) { LOCK(cs_main); @@ -6517,10 +6525,17 @@ void PeerManagerImpl::PeerEraseObjectRequest(const NodeId nodeid, const CInv& in { EraseObjectRequest(nodeid, inv); } + +void PeerManagerImpl::PeerRelayInv(const CInv& inv) +{ + RelayInv(inv); +} + void PeerManagerImpl::PeerRelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) { RelayInvFiltered(inv, relatedTx); } + void PeerManagerImpl::PeerRelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) { RelayInvFiltered(inv, relatedTxHash); diff --git a/src/net_processing.h b/src/net_processing.h index 6aa1d4d259770..eb54e42dd7255 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -60,6 +60,7 @@ class PeerManagerInternal public: virtual void PeerMisbehaving(const NodeId pnode, const int howmuch, const std::string& message = "") = 0; virtual void PeerEraseObjectRequest(const NodeId nodeid, const CInv& inv) = 0; + virtual void PeerRelayInv(const CInv& inv) = 0; virtual void PeerRelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) = 0; virtual void PeerRelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) = 0; virtual void PeerAskPeersForTransaction(const uint256& txid) = 0; @@ -79,6 +80,7 @@ class NetHandler virtual void Start() {} virtual void Stop() {} virtual void Interrupt() {} + virtual void Schedule(CScheduler& scheduler, CConnman& connman) {} virtual void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) = 0; protected: PeerManagerInternal* m_peer_manager; @@ -169,6 +171,7 @@ class PeerManager : public CValidationInterface, public NetEventsInterface, publ virtual void StartHandlers() = 0; virtual void StopHandlers() = 0; virtual void InterruptHandlers() = 0; + virtual void ScheduleHandlers(CScheduler& scheduler) = 0; }; #endif // BITCOIN_NET_PROCESSING_H From dcca78966439b417908a60a36d3a6a7ad88d23b8 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 30 Oct 2025 12:33:18 +0700 Subject: [PATCH 20/58] fix: removed duplicated checks if blockchain is synced --- src/governance/governance.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 2fe07749541ed..95fe5af767738 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -222,11 +222,6 @@ MessageProcessingResult CGovernanceManager::ProcessMessage(CNode& peer, CConnman MessageProcessingResult ret{}; ret.m_to_erase = CInv{MSG_GOVERNANCE_OBJECT, nHash}; - if (!m_mn_sync.IsBlockchainSynced()) { - LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- masternode list not synced\n"); - return ret; - } - std::string strHash = nHash.ToString(); LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- Received object: %s\n", strHash); @@ -289,12 +284,6 @@ MessageProcessingResult CGovernanceManager::ProcessMessage(CNode& peer, CConnman MessageProcessingResult ret{}; ret.m_to_erase = CInv{MSG_GOVERNANCE_OBJECT_VOTE, nHash}; - // Ignore such messages until masternode list is synced - if (!m_mn_sync.IsBlockchainSynced()) { - LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- masternode list not synced\n"); - return ret; - } - LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- Received vote: %s\n", vote.ToString(tip_mn_list)); std::string strHash = nHash.ToString(); From c6daa49fc587a0e0161e4b05d33de449a55cd62c Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 30 Oct 2025 12:34:12 +0700 Subject: [PATCH 21/58] Revert "fix: removed duplicated checks if blockchain is synced" This reverts commit dcca78966439b417908a60a36d3a6a7ad88d23b8. --- src/governance/governance.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 95fe5af767738..2fe07749541ed 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -222,6 +222,11 @@ MessageProcessingResult CGovernanceManager::ProcessMessage(CNode& peer, CConnman MessageProcessingResult ret{}; ret.m_to_erase = CInv{MSG_GOVERNANCE_OBJECT, nHash}; + if (!m_mn_sync.IsBlockchainSynced()) { + LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- masternode list not synced\n"); + return ret; + } + std::string strHash = nHash.ToString(); LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- Received object: %s\n", strHash); @@ -284,6 +289,12 @@ MessageProcessingResult CGovernanceManager::ProcessMessage(CNode& peer, CConnman MessageProcessingResult ret{}; ret.m_to_erase = CInv{MSG_GOVERNANCE_OBJECT_VOTE, nHash}; + // Ignore such messages until masternode list is synced + if (!m_mn_sync.IsBlockchainSynced()) { + LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- masternode list not synced\n"); + return ret; + } + LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- Received vote: %s\n", vote.ToString(tip_mn_list)); std::string strHash = nHash.ToString(); From cfa5a40d241ad3c4ed32dfcc27f8ec29159ea156 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 30 Oct 2025 13:05:41 +0700 Subject: [PATCH 22/58] scheduler - fixups --- src/governance/governance.h | 1 - src/net_governance.h | 2 -- src/net_processing.h | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/governance/governance.h b/src/governance/governance.h index 8521018f94ea7..9fe9ed5cb460c 100644 --- a/src/governance/governance.h +++ b/src/governance/governance.h @@ -32,7 +32,6 @@ template class CFlatDB; class CInv; class CNode; -class CScheduler; class PeerManager; class CDeterministicMNList; diff --git a/src/net_governance.h b/src/net_governance.h index 572f14d40ebb2..6df38fe7d72a1 100644 --- a/src/net_governance.h +++ b/src/net_governance.h @@ -7,8 +7,6 @@ #include -//#include - class CGovernanceManager; class NetGovernance final : public NetHandler diff --git a/src/net_processing.h b/src/net_processing.h index eb54e42dd7255..41a6e845f1401 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -81,7 +81,7 @@ class NetHandler virtual void Stop() {} virtual void Interrupt() {} virtual void Schedule(CScheduler& scheduler, CConnman& connman) {} - virtual void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) = 0; + virtual void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) {} protected: PeerManagerInternal* m_peer_manager; }; From 5363ca224b6a36745cda0d4b1c938e8f2aa12504 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 30 Oct 2025 13:10:24 +0700 Subject: [PATCH 23/58] perf: drop shared_ptr from GetCurrentVotes --- src/governance/governance.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 2fe07749541ed..3a4975b1e16ce 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -595,26 +595,26 @@ std::vector CGovernanceManager::GetCurrentVotes(const uint256& const CGovernanceObject& govobj = it->second; const auto tip_mn_list = Assert(m_dmnman)->GetListAtChainTip(); - std::map mapMasternodes; + std::set masternodes; if (mnCollateralOutpointFilter.IsNull()) { - tip_mn_list.ForEachMNShared(false, [&](const CDeterministicMNCPtr& dmn) { - mapMasternodes.emplace(dmn->collateralOutpoint, dmn); + tip_mn_list.ForEachMN(false, [&](const CDeterministicMN& mn) { + masternodes.emplace(mn.collateralOutpoint); }); } else { auto dmn = tip_mn_list.GetMNByCollateral(mnCollateralOutpointFilter); if (dmn) { - mapMasternodes.emplace(dmn->collateralOutpoint, dmn); + masternodes.insert(mnCollateralOutpointFilter); } } // Loop through each MN collateral outpoint and get the votes for the `nParentHash` governance object - for (const auto& mnpair : mapMasternodes) { + for (const auto& collateral : masternodes) { // get a vote_rec_t from the govobj vote_rec_t voteRecord; - if (!govobj.GetCurrentMNVotes(mnpair.first, voteRecord)) continue; + if (!govobj.GetCurrentMNVotes(collateral, voteRecord)) continue; for (const auto& [signal, vote_instance] : voteRecord.mapInstances) { - CGovernanceVote vote = CGovernanceVote(mnpair.first, nParentHash, (vote_signal_enum_t)signal, + CGovernanceVote vote = CGovernanceVote(collateral, nParentHash, (vote_signal_enum_t)signal, vote_instance.eOutcome); vote.SetTime(vote_instance.nCreationTime); vecResult.push_back(vote); From bbac29f795f271fba44375cbe6a476b8b86fb046 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 30 Oct 2025 13:12:56 +0700 Subject: [PATCH 24/58] refactor: drop unused includes from net.h and test/util/net.h to speed up compilation time --- src/net.h | 2 +- src/test/util/net.h | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/net.h b/src/net.h index 9e0fb5d8b5b85..55c77916c0488 100644 --- a/src/net.h +++ b/src/net.h @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/test/util/net.h b/src/test/util/net.h index ab1d958546c89..7f7d5b640bdd0 100644 --- a/src/test/util/net.h +++ b/src/test/util/net.h @@ -7,8 +7,6 @@ #include #include -#include -#include #include #include #include @@ -23,10 +21,10 @@ #include #include #include -#include #include class FastRandomContext; +class PeerManager; template class Span; From 08630bb6dcb95064ac3e6496b257c17ffceb2dea Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 30 Oct 2025 15:01:13 +0700 Subject: [PATCH 25/58] refactor: rename masternode/sync to node/sync. It does nothing to masternodes --- src/Makefile.am | 4 ++-- src/chainlock/chainlock.cpp | 2 +- src/chainlock/signing.cpp | 2 +- src/coinjoin/client.cpp | 2 +- src/coinjoin/coinjoin.cpp | 2 +- src/coinjoin/server.cpp | 2 +- src/dsnotificationinterface.cpp | 2 +- src/evo/mnauth.cpp | 2 +- src/governance/governance.cpp | 2 +- src/governance/object.cpp | 2 +- src/governance/signing.cpp | 2 +- src/governance/vote.cpp | 2 +- src/init.cpp | 2 +- src/instantsend/instantsend.cpp | 2 +- src/instantsend/signing.cpp | 2 +- src/llmq/quorums.cpp | 2 +- src/masternode/payments.cpp | 2 +- src/masternode/utils.cpp | 2 +- src/net.cpp | 2 +- src/net_governance.cpp | 2 +- src/net_processing.cpp | 2 +- src/node/context.cpp | 2 +- src/node/interfaces.cpp | 2 +- src/{masternode => node}/sync.cpp | 2 +- src/{masternode => node}/sync.h | 0 src/rpc/governance.cpp | 2 +- src/rpc/mining.cpp | 2 +- src/rpc/node.cpp | 2 +- src/test/util/setup_common.cpp | 2 +- src/wallet/interfaces.cpp | 2 +- 30 files changed, 30 insertions(+), 30 deletions(-) rename src/{masternode => node}/sync.cpp (99%) rename src/{masternode => node}/sync.h (100%) diff --git a/src/Makefile.am b/src/Makefile.am index 123ad55a6e6c1..056ae7cc0cad4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -287,7 +287,6 @@ BITCOIN_CORE_H = \ masternode/node.h \ masternode/meta.h \ masternode/payments.h \ - masternode/sync.h \ masternode/utils.h \ memusage.h \ merkleblock.h \ @@ -316,6 +315,7 @@ BITCOIN_CORE_H = \ node/miner.h \ node/minisketchwrapper.h \ node/psbt.h \ + sync/sync.h \ node/transaction.h \ node/txreconciliation.h \ node/interface_ui.h \ @@ -554,7 +554,6 @@ libbitcoin_node_a_SOURCES = \ masternode/node.cpp \ masternode/meta.cpp \ masternode/payments.cpp \ - masternode/sync.cpp \ masternode/utils.cpp \ net.cpp \ netfulfilledman.cpp \ @@ -575,6 +574,7 @@ libbitcoin_node_a_SOURCES = \ node/miner.cpp \ node/minisketchwrapper.cpp \ node/psbt.cpp \ + node/sync.cpp \ node/transaction.cpp \ node/txreconciliation.cpp \ node/interface_ui.cpp \ diff --git a/src/chainlock/chainlock.cpp b/src/chainlock/chainlock.cpp index bb4380170cf0a..d794f8f198062 100644 --- a/src/chainlock/chainlock.cpp +++ b/src/chainlock/chainlock.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/src/chainlock/signing.cpp b/src/chainlock/signing.cpp index 9b574d5cc6ee3..325946770df8f 100644 --- a/src/chainlock/signing.cpp +++ b/src/chainlock/signing.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include using node::ReadBlockFromDisk; diff --git a/src/coinjoin/client.cpp b/src/coinjoin/client.cpp index 88d5ee4f81870..85dffb22d0c2c 100644 --- a/src/coinjoin/client.cpp +++ b/src/coinjoin/client.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/coinjoin/coinjoin.cpp b/src/coinjoin/coinjoin.cpp index d48239927f1aa..6c8aec95ab6ca 100644 --- a/src/coinjoin/coinjoin.cpp +++ b/src/coinjoin/coinjoin.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include diff --git a/src/coinjoin/server.cpp b/src/coinjoin/server.cpp index 6f7169af74864..f28171c705271 100644 --- a/src/coinjoin/server.cpp +++ b/src/coinjoin/server.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/dsnotificationinterface.cpp b/src/dsnotificationinterface.cpp index 1a1faa9695636..71f8d51e72c12 100644 --- a/src/dsnotificationinterface.cpp +++ b/src/dsnotificationinterface.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include CDSNotificationInterface::CDSNotificationInterface(CConnman& connman, CDSTXManager& dstxman, diff --git a/src/evo/mnauth.cpp b/src/evo/mnauth.cpp index 376c96ecfaf40..fcc3f0de8e112 100644 --- a/src/evo/mnauth.cpp +++ b/src/evo/mnauth.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 3a4975b1e16ce..46aa6623dd914 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/governance/object.cpp b/src/governance/object.cpp index 8bea754eea50c..900c3ccf1b7aa 100644 --- a/src/governance/object.cpp +++ b/src/governance/object.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/governance/signing.cpp b/src/governance/signing.cpp index 13dd74d886372..52d6cd98894a7 100644 --- a/src/governance/signing.cpp +++ b/src/governance/signing.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/governance/vote.cpp b/src/governance/vote.cpp index 2a013465e38c6..41299162ce3f9 100644 --- a/src/governance/vote.cpp +++ b/src/governance/vote.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/init.cpp b/src/init.cpp index c2198b4fd5e9e..b11281e24db49 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -98,7 +98,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index b2ff9d0231c8a..5220c642ccb84 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/instantsend/signing.cpp b/src/instantsend/signing.cpp index 789c0135f9685..c522b42a07e43 100644 --- a/src/instantsend/signing.cpp +++ b/src/instantsend/signing.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include // Forward declaration to break dependency over node/transaction.h diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index c73395a010714..8dba511eedcfd 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/masternode/payments.cpp b/src/masternode/payments.cpp index 1c5b1d4be107a..7ca2fdbb40273 100644 --- a/src/masternode/payments.cpp +++ b/src/masternode/payments.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include