From 562ad2b067871ea1de50c85c3ae2904701ce75e0 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sat, 6 Sep 2025 12:19:03 +0000 Subject: [PATCH 1/9] wallet: drop collateral outpoints filtering from balance calculation The wallet should not concern itself with masternode mode state. Client side mixing is not available for masternodes and masternodes are no longer allowed to have the collateral in their own local wallet, drop it. --- src/wallet/coinjoin.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/wallet/coinjoin.cpp b/src/wallet/coinjoin.cpp index bf7c39ed6f20..5731e0ab6691 100644 --- a/src/wallet/coinjoin.cpp +++ b/src/wallet/coinjoin.cpp @@ -13,7 +13,6 @@ #include #include -#include namespace wallet { void CWallet::InitCJSaltFromDb() @@ -181,7 +180,6 @@ std::vector CWallet::SelectCoinsGroupedByAddresses(bool fSkipD if (fAnonymizable) { // ignore collaterals if (CoinJoin::IsCollateralAmount(wtx.tx->vout[i].nValue)) continue; - if (fMasternodeMode && dmn_types::IsCollateralAmount(wtx.tx->vout[i].nValue)) continue; // ignore outputs that are 10 times smaller then the smallest denomination // otherwise they will just lead to higher fee / lower priority if (wtx.tx->vout[i].nValue <= nSmallestDenom / 10) continue; From be84075e346b0b4df70bbdf69cec0943ea9165b6 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 24 Aug 2025 16:18:34 +0000 Subject: [PATCH 2/9] refactor: drop `fMasternodeMode` global We don't initialize mn_activeman in TestingSetup so we don't need to set `connOptions.m_active_masternode` --- src/governance/governance.cpp | 2 +- src/init.cpp | 11 ++++------- src/masternode/sync.cpp | 4 ++-- src/net.cpp | 4 ++-- src/net.h | 6 ++++++ src/util/system.cpp | 1 - src/util/system.h | 1 - 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 16a32e033367..d56c87952e99 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -1360,7 +1360,7 @@ int CGovernanceManager::RequestGovernanceObjectVotes(const std::vector& // Don't try to sync any data from outbound non-relay "masternode" connections. // Inbound connection this early is most likely a "masternode" connection // initiated from another node, so skip it too. - if (!pnode->CanRelay() || (fMasternodeMode && pnode->IsInboundConn())) continue; + if (!pnode->CanRelay() || (connman.IsActiveMasternode() && pnode->IsInboundConn())) continue; // stop early to prevent setAskFor overflow { LOCK(::cs_main); diff --git a/src/init.cpp b/src/init.cpp index 6a96d6dd4a9c..3b7683f40d4a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1692,19 +1692,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } } - fMasternodeMode = false; std::string strMasterNodeBLSPrivKey = args.GetArg("-masternodeblsprivkey", ""); if (!strMasterNodeBLSPrivKey.empty()) { CBLSSecretKey keyOperator(ParseHex(strMasterNodeBLSPrivKey)); if (!keyOperator.IsValid()) { return InitError(_("Invalid masternodeblsprivkey. Please see documentation.")); } - fMasternodeMode = true; - { - // Create and register mn_activeman, will init later in ThreadImport - node.mn_activeman = std::make_unique(keyOperator, *node.connman, node.dmnman); - RegisterValidationInterface(node.mn_activeman.get()); - } + // Create and register mn_activeman, will init later in ThreadImport + node.mn_activeman = std::make_unique(keyOperator, *node.connman, node.dmnman); + RegisterValidationInterface(node.mn_activeman.get()); } // Check port numbers @@ -2428,6 +2424,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) connOptions.nMaxOutboundLimit = *opt_max_upload; connOptions.m_peer_connect_timeout = peer_connect_timeout; connOptions.socketEventsMode = ::g_socket_events_mode; + connOptions.m_active_masternode = node.mn_activeman != nullptr; // Port to bind to if `-bind=addr` is provided without a `:port` suffix. const uint16_t default_bind_port = diff --git a/src/masternode/sync.cpp b/src/masternode/sync.cpp index fca0f0cde5cf..b9bebb07cb64 100644 --- a/src/masternode/sync.cpp +++ b/src/masternode/sync.cpp @@ -124,7 +124,7 @@ void CMasternodeSync::ProcessTick(const PeerManager& peerman, const CGovernanceM // reset the sync process if the last call to this function was more than 60 minutes ago (client was in sleep mode) static int64_t nTimeLastProcess = GetTime(); - if (!Params().IsMockableChain() && GetTime() - nTimeLastProcess > 60 * 60 && !fMasternodeMode) { + if (!Params().IsMockableChain() && GetTime() - nTimeLastProcess > 60 * 60 && !connman.IsActiveMasternode()) { LogPrintf("CMasternodeSync::ProcessTick -- WARNING: no actions for too long, restarting sync...\n"); Reset(true); nTimeLastProcess = GetTime(); @@ -157,7 +157,7 @@ void CMasternodeSync::ProcessTick(const PeerManager& peerman, const CGovernanceM // Don't try to sync any data from outbound non-relay "masternode" connections. // Inbound connection this early is most likely a "masternode" connection // initiated from another node, so skip it too. - if (!pnode->CanRelay() || (fMasternodeMode && pnode->IsInboundConn())) continue; + if (!pnode->CanRelay() || (connman.IsActiveMasternode() && pnode->IsInboundConn())) continue; { if ((pnode->HasPermission(NetPermissionFlags::NoBan) || pnode->IsManualConn()) && !m_netfulfilledman.HasFulfilledRequest(pnode->addr, strAllow)) { diff --git a/src/net.cpp b/src/net.cpp index fb56676f3d2e..a5ac046186f2 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1801,7 +1801,7 @@ bool CConnman::AttemptToEvictConnection() if (node->fDisconnect) continue; - if (fMasternodeMode) { + if (m_active_masternode) { // This handles eviction protected nodes. Nodes are always protected for a short time after the connection // was accepted. This short time is meant for the VERSION/VERACK exchange and the possible MNAUTH that might // follow when the incoming connection is from another masternode. When a message other than MNAUTH @@ -1971,7 +1971,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr&& sock, } // don't accept incoming connections until blockchain is synced - if (fMasternodeMode && !mn_sync.IsBlockchainSynced()) { + if (m_active_masternode && !mn_sync.IsBlockchainSynced()) { LogPrint(BCLog::NET_NETCONN, "AcceptConnection -- blockchain is not synced yet, skipping inbound connection attempt\n"); return; } diff --git a/src/net.h b/src/net.h index 957aff1b4fd3..5568fac1ab82 100644 --- a/src/net.h +++ b/src/net.h @@ -1194,6 +1194,7 @@ friend class CNode; std::vector m_added_nodes; SocketEventsMode socketEventsMode = SocketEventsMode::Select; bool m_i2p_accept_incoming; + bool m_active_masternode = false; }; void Init(const Options& connOptions) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_total_bytes_sent_mutex) @@ -1231,6 +1232,7 @@ friend class CNode; } socketEventsMode = connOptions.socketEventsMode; m_onion_binds = connOptions.onion_binds; + m_active_masternode = connOptions.m_active_masternode; } CConnman(uint64_t seed0, uint64_t seed1, AddrMan& addrman, const NetGroupManager& netgroupman, @@ -1255,6 +1257,7 @@ friend class CNode; void SetNetworkActive(bool active, CMasternodeSync* const mn_sync); bool GetMasternodeThreadActive() const { return m_masternode_thread_active; }; void SetMasternodeThreadActive(bool active) { m_masternode_thread_active = active; }; + bool IsActiveMasternode() const { return m_active_masternode; } SocketEventsMode GetSocketEventsMode() const { return socketEventsMode; } enum class MasternodeConn { @@ -1840,6 +1843,9 @@ friend class CNode; */ std::unique_ptr m_i2p_sam_session; + /** Flag for activating masternode mode */ + bool m_active_masternode{false}; + SocketEventsMode socketEventsMode; std::unique_ptr m_edge_trig_events{nullptr}; std::unique_ptr m_wakeup_pipe{nullptr}; diff --git a/src/util/system.cpp b/src/util/system.cpp index caf7972e6fe2..d294d202a8c9 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -80,7 +80,6 @@ const int64_t nStartupTime = GetTime(); //Dash only features -bool fMasternodeMode = false; const std::string gCoinJoinName = "CoinJoin"; /** diff --git a/src/util/system.h b/src/util/system.h index 12e14892a3db..b8c8309bdde7 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -36,7 +36,6 @@ //Dash only features -extern bool fMasternodeMode; extern int nWalletBackups; extern const std::string gCoinJoinName; From 314f070324165f12389a3cd1558d3ec53a4b3407 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 9 Sep 2025 14:09:15 +0000 Subject: [PATCH 3/9] refactor: move InstantSend signer to new `ActiveContext` ActiveContext is going to host all entities are part of masternode mode (i.e. used by a node if it is an active masternode) and is required to separate interactive (i.e. networking-driven) portions of consensus from portions that can be done non-interactively/offline. --- src/Makefile.am | 2 ++ src/init.cpp | 10 ++++++++- src/instantsend/instantsend.cpp | 10 +++------ src/instantsend/instantsend.h | 16 ++++++++----- src/llmq/context.cpp | 4 ++-- src/masternode/active/context.cpp | 24 ++++++++++++++++++++ src/masternode/active/context.h | 37 +++++++++++++++++++++++++++++++ src/node/context.cpp | 1 + src/node/context.h | 7 ++++-- test/util/data/non-backported.txt | 2 ++ 10 files changed, 96 insertions(+), 17 deletions(-) create mode 100644 src/masternode/active/context.cpp create mode 100644 src/masternode/active/context.h diff --git a/src/Makefile.am b/src/Makefile.am index 009f91437a96..c54c11874327 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -262,6 +262,7 @@ BITCOIN_CORE_H = \ logging.h \ logging/timer.h \ mapport.h \ + masternode/active/context.h \ masternode/node.h \ masternode/meta.h \ masternode/payments.h \ @@ -520,6 +521,7 @@ libbitcoin_node_a_SOURCES = \ llmq/snapshot.cpp \ llmq/utils.cpp \ mapport.cpp \ + masternode/active/context.cpp \ masternode/node.cpp \ masternode/meta.cpp \ masternode/payments.cpp \ diff --git a/src/init.cpp b/src/init.cpp index 3b7683f40d4a..1703daa276f3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -321,6 +322,7 @@ void PrepareShutdown(NodeContext& node) // After all scheduled tasks have been flushed, destroy pointers // and reset all to nullptr. + node.active_ctx.reset(); node.mn_sync.reset(); node.sporkman.reset(); node.govman.reset(); @@ -2159,7 +2161,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.mn_activeman.get(), *node.mn_sync, *node.llmq_ctx->isman, node.peerman, !ignores_incoming_txs); - // ********************************************************* Step 7d: Setup other Dash services + // ********************************************************* Step 7d: Setup masternode mode + assert(!node.active_ctx); + if (node.mn_activeman) { + node.active_ctx = std::make_unique(chainman.ActiveChainstate(), *node.llmq_ctx, *node.sporkman, *node.mempool, *node.mn_sync); + } + + // ********************************************************* Step 7e: Setup other Dash services bool fLoadCacheFiles = !(fReindex || fReindexChainState) && (chainman.ActiveChain().Tip() != nullptr); diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 2435ae3690d8..c4a2c498f027 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -50,9 +50,8 @@ std::unordered_set GetIdsFromLockable(const std::ve } // anonymous namespace CInstantSendManager::CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CQuorumManager& _qman, - CSigningManager& _sigman, CSigSharesManager& _shareman, - CSporkManager& sporkman, CTxMemPool& _mempool, const CMasternodeSync& mn_sync, - bool is_masternode, bool unitTests, bool fWipe) : + CSigningManager& _sigman, CSporkManager& sporkman, CTxMemPool& _mempool, + const CMasternodeSync& mn_sync, bool unitTests, bool fWipe) : db{unitTests, fWipe}, clhandler{_clhandler}, m_chainstate{chainstate}, @@ -60,10 +59,7 @@ CInstantSendManager::CInstantSendManager(CChainLocksHandler& _clhandler, CChainS sigman{_sigman}, spork_manager{sporkman}, mempool{_mempool}, - m_mn_sync{mn_sync}, - m_signer{is_masternode ? std::make_unique(chainstate, _clhandler, *this, _sigman, - _shareman, _qman, sporkman, _mempool, mn_sync) - : nullptr} + m_mn_sync{mn_sync} { workInterrupt.reset(); } diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index 6a045952eee2..cefcbee04677 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -39,7 +39,6 @@ namespace llmq { class CChainLocksHandler; class CQuorumManager; class CSigningManager; -class CSigSharesManager; class CInstantSendManager final : public instantsend::InstantSendSignerParent { @@ -54,7 +53,7 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent CTxMemPool& mempool; const CMasternodeSync& m_mn_sync; - std::unique_ptr m_signer{nullptr}; + instantsend::InstantSendSigner* m_signer{nullptr}; std::thread workThread; CThreadInterrupt workInterrupt; @@ -85,11 +84,18 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent public: explicit CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CQuorumManager& _qman, - CSigningManager& _sigman, CSigSharesManager& _shareman, CSporkManager& sporkman, - CTxMemPool& _mempool, const CMasternodeSync& mn_sync, bool is_masternode, - bool unitTests, bool fWipe); + CSigningManager& _sigman, CSporkManager& sporkman, CTxMemPool& _mempool, + const CMasternodeSync& mn_sync, bool unitTests, bool fWipe); ~CInstantSendManager(); + void ConnectSigner(gsl::not_null signer) + { + // Prohibit double initialization + assert(m_signer == nullptr); + m_signer = signer; + } + void DisconnectSigner() { m_signer = nullptr; } + void Start(PeerManager& peerman); void Stop(); void InterruptWorkerThread() { workInterrupt(); }; diff --git a/src/llmq/context.cpp b/src/llmq/context.cpp index e2a60f21420b..1df96010e9e3 100644 --- a/src/llmq/context.cpp +++ b/src/llmq/context.cpp @@ -37,8 +37,8 @@ LLMQContext::LLMQContext(ChainstateManager& chainman, CDeterministicMNManager& d shareman{std::make_unique(*sigman, mn_activeman, *qman, sporkman)}, clhandler{std::make_unique(chainman.ActiveChainstate(), *qman, *sigman, *shareman, sporkman, mempool, mn_sync, is_masternode)}, - isman{std::make_unique(*clhandler, chainman.ActiveChainstate(), *qman, *sigman, *shareman, - sporkman, mempool, mn_sync, is_masternode, unit_tests, wipe)}, + isman{std::make_unique(*clhandler, chainman.ActiveChainstate(), *qman, *sigman, sporkman, + mempool, mn_sync, unit_tests, wipe)}, ehfSignalsHandler{std::make_unique(chainman, mnhfman, *sigman, *shareman, *qman)} { // Have to start it early to let VerifyDB check ChainLock signatures in coinbase diff --git a/src/masternode/active/context.cpp b/src/masternode/active/context.cpp new file mode 100644 index 000000000000..b558595cf31a --- /dev/null +++ b/src/masternode/active/context.cpp @@ -0,0 +1,24 @@ +// 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 + +ActiveContext::ActiveContext(CChainState& chainstate, LLMQContext& llmq_ctx, CSporkManager& sporkman, + CTxMemPool& mempool, const CMasternodeSync& mn_sync) : + m_llmq_ctx{llmq_ctx}, + is_signer{std::make_unique(chainstate, *llmq_ctx.clhandler, *llmq_ctx.isman, + *llmq_ctx.sigman, *llmq_ctx.shareman, *llmq_ctx.qman, + sporkman, mempool, mn_sync)} +{ + m_llmq_ctx.isman->ConnectSigner(is_signer.get()); +} + +ActiveContext::~ActiveContext() +{ + m_llmq_ctx.isman->DisconnectSigner(); +} diff --git a/src/masternode/active/context.h b/src/masternode/active/context.h new file mode 100644 index 000000000000..0fdae9da0047 --- /dev/null +++ b/src/masternode/active/context.h @@ -0,0 +1,37 @@ +// 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_MASTERNODE_ACTIVE_CONTEXT_H +#define BITCOIN_MASTERNODE_ACTIVE_CONTEXT_H + +#include + +class CChainState; +class CMasternodeSync; +class CSporkManager; +class CTxMemPool; +struct LLMQContext; +namespace instantsend { +class InstantSendSigner; +} // namespace instantsend + +struct ActiveContext { +private: + LLMQContext& m_llmq_ctx; + + /* + * Entities that are registered with LLMQContext members are not accessible + * and are managed with (Dis)connectSigner() in the (c/d)tor instead + */ + const std::unique_ptr is_signer; + +public: + ActiveContext() = delete; + ActiveContext(const ActiveContext&) = delete; + ActiveContext(CChainState& chainstate, LLMQContext& llmq_ctx, CSporkManager& sporkman, CTxMemPool& mempool, + const CMasternodeSync& mn_sync); + ~ActiveContext(); +}; + +#endif // BITCOIN_MASTERNODE_ACTIVE_CONTEXT_H diff --git a/src/node/context.cpp b/src/node/context.cpp index 87ead0700582..22296e423a92 100644 --- a/src/node/context.cpp +++ b/src/node/context.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/src/node/context.h b/src/node/context.h index 3ce539df983a..fc04830e72d6 100644 --- a/src/node/context.h +++ b/src/node/context.h @@ -31,6 +31,7 @@ class CTxMemPool; class CMNHFManager; class NetGroupManager; class PeerManager; +struct ActiveContext; struct CJContext; struct LLMQContext; @@ -76,19 +77,21 @@ struct NodeContext { std::unique_ptr coinjoin_loader{nullptr}; std::unique_ptr scheduler; std::function rpc_interruption_point = [] {}; - //! Dash + //! Dash managers std::unique_ptr mn_activeman; std::unique_ptr cpoolman; std::unique_ptr evodb; std::unique_ptr chain_helper; std::unique_ptr dmnman; std::unique_ptr govman; - std::unique_ptr cj_ctx; std::unique_ptr mn_metaman; std::unique_ptr mn_sync; std::unique_ptr mnhf_manager; std::unique_ptr netfulfilledman; std::unique_ptr sporkman; + //! Dash contexts + std::unique_ptr active_ctx; + std::unique_ptr cj_ctx; std::unique_ptr llmq_ctx; //! Declare default constructor and destructor that are not inline, so code diff --git a/test/util/data/non-backported.txt b/test/util/data/non-backported.txt index adff5ebb6869..eaa118ca8fca 100644 --- a/test/util/data/non-backported.txt +++ b/test/util/data/non-backported.txt @@ -22,6 +22,8 @@ src/llmq/*.cpp src/llmq/*.h src/masternode/*.cpp src/masternode/*.h +src/masternode/active/*.cpp +src/masternode/active/*.h src/messagesigner.* src/netfulfilledman.* src/qt/governancelist.* From fcabb3d3296bb99cd7b5d31eed4c042da8f2b1eb Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 25 Aug 2025 07:50:20 +0000 Subject: [PATCH 4/9] refactor: move ChainLock signer to `ActiveContext` --- src/chainlock/chainlock.cpp | 8 ++------ src/chainlock/chainlock.h | 14 ++++++++++---- src/llmq/context.cpp | 4 ++-- src/masternode/active/context.cpp | 6 ++++++ src/masternode/active/context.h | 4 ++++ 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/chainlock/chainlock.cpp b/src/chainlock/chainlock.cpp index 15e235dea093..8026e2e88765 100644 --- a/src/chainlock/chainlock.cpp +++ b/src/chainlock/chainlock.cpp @@ -44,8 +44,7 @@ bool AreChainLocksEnabled(const CSporkManager& sporkman) } CChainLocksHandler::CChainLocksHandler(CChainState& chainstate, CQuorumManager& _qman, CSigningManager& _sigman, - CSigSharesManager& _shareman, CSporkManager& sporkman, CTxMemPool& _mempool, - const CMasternodeSync& mn_sync, bool is_masternode) : + CSporkManager& sporkman, CTxMemPool& _mempool, const CMasternodeSync& mn_sync) : m_chainstate{chainstate}, qman{_qman}, spork_manager{sporkman}, @@ -53,10 +52,7 @@ CChainLocksHandler::CChainLocksHandler(CChainState& chainstate, CQuorumManager& m_mn_sync{mn_sync}, scheduler{std::make_unique()}, scheduler_thread{ - std::make_unique(std::thread(util::TraceThread, "cl-schdlr", [&] { scheduler->serviceQueue(); }))}, - m_signer{is_masternode - ? std::make_unique(chainstate, *this, _sigman, _shareman, sporkman, mn_sync) - : nullptr} + std::make_unique(std::thread(util::TraceThread, "cl-schdlr", [&] { scheduler->serviceQueue(); }))} { } diff --git a/src/chainlock/chainlock.h b/src/chainlock/chainlock.h index e7060537df4c..297f0ef3168b 100644 --- a/src/chainlock/chainlock.h +++ b/src/chainlock/chainlock.h @@ -33,7 +33,6 @@ namespace llmq { class CInstantSendManager; class CQuorumManager; class CSigningManager; -class CSigSharesManager; enum class VerifyRecSigStatus; class CChainLocksHandler final : public chainlock::ChainLockSignerParent @@ -47,7 +46,7 @@ class CChainLocksHandler final : public chainlock::ChainLockSignerParent std::unique_ptr scheduler; std::unique_ptr scheduler_thread; - std::unique_ptr m_signer{nullptr}; + chainlock::ChainLockSigner* m_signer{nullptr}; mutable Mutex cs; std::atomic tryLockChainTipScheduled{false}; @@ -68,10 +67,17 @@ class CChainLocksHandler final : public chainlock::ChainLockSignerParent public: explicit CChainLocksHandler(CChainState& chainstate, CQuorumManager& _qman, CSigningManager& _sigman, - CSigSharesManager& _shareman, CSporkManager& sporkman, CTxMemPool& _mempool, - const CMasternodeSync& mn_sync, bool is_masternode); + CSporkManager& sporkman, CTxMemPool& _mempool, const CMasternodeSync& mn_sync); ~CChainLocksHandler(); + void ConnectSigner(gsl::not_null signer) + { + // Prohibit double initialization + assert(m_signer == nullptr); + m_signer = signer; + } + void DisconnectSigner() { m_signer = nullptr; } + void Start(const llmq::CInstantSendManager& isman); void Stop(); diff --git a/src/llmq/context.cpp b/src/llmq/context.cpp index 1df96010e9e3..7a30a08d5b63 100644 --- a/src/llmq/context.cpp +++ b/src/llmq/context.cpp @@ -35,8 +35,8 @@ LLMQContext::LLMQContext(ChainstateManager& chainman, CDeterministicMNManager& d unit_tests, wipe)}, sigman{std::make_unique(mn_activeman, chainman.ActiveChainstate(), *qman, unit_tests, wipe)}, shareman{std::make_unique(*sigman, mn_activeman, *qman, sporkman)}, - clhandler{std::make_unique(chainman.ActiveChainstate(), *qman, *sigman, *shareman, - sporkman, mempool, mn_sync, is_masternode)}, + clhandler{std::make_unique(chainman.ActiveChainstate(), *qman, *sigman, sporkman, mempool, + mn_sync)}, isman{std::make_unique(*clhandler, chainman.ActiveChainstate(), *qman, *sigman, sporkman, mempool, mn_sync, unit_tests, wipe)}, ehfSignalsHandler{std::make_unique(chainman, mnhfman, *sigman, *shareman, *qman)} diff --git a/src/masternode/active/context.cpp b/src/masternode/active/context.cpp index b558595cf31a..3d84883e4eff 100644 --- a/src/masternode/active/context.cpp +++ b/src/masternode/active/context.cpp @@ -4,6 +4,8 @@ #include +#include +#include #include #include #include @@ -11,14 +13,18 @@ ActiveContext::ActiveContext(CChainState& chainstate, LLMQContext& llmq_ctx, CSporkManager& sporkman, CTxMemPool& mempool, const CMasternodeSync& mn_sync) : m_llmq_ctx{llmq_ctx}, + cl_signer{std::make_unique(chainstate, *llmq_ctx.clhandler, *llmq_ctx.sigman, + *llmq_ctx.shareman, sporkman, mn_sync)}, is_signer{std::make_unique(chainstate, *llmq_ctx.clhandler, *llmq_ctx.isman, *llmq_ctx.sigman, *llmq_ctx.shareman, *llmq_ctx.qman, sporkman, mempool, mn_sync)} { + m_llmq_ctx.clhandler->ConnectSigner(cl_signer.get()); m_llmq_ctx.isman->ConnectSigner(is_signer.get()); } ActiveContext::~ActiveContext() { + m_llmq_ctx.clhandler->DisconnectSigner(); m_llmq_ctx.isman->DisconnectSigner(); } diff --git a/src/masternode/active/context.h b/src/masternode/active/context.h index 0fdae9da0047..e8eb751843d3 100644 --- a/src/masternode/active/context.h +++ b/src/masternode/active/context.h @@ -12,6 +12,9 @@ class CMasternodeSync; class CSporkManager; class CTxMemPool; struct LLMQContext; +namespace chainlock { +class ChainLockSigner; +} // namespace chainlock namespace instantsend { class InstantSendSigner; } // namespace instantsend @@ -24,6 +27,7 @@ struct ActiveContext { * Entities that are registered with LLMQContext members are not accessible * and are managed with (Dis)connectSigner() in the (c/d)tor instead */ + const std::unique_ptr cl_signer; const std::unique_ptr is_signer; public: From afec9ae4680667056375663f447ae76e5ad59042 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 9 Sep 2025 14:04:43 +0000 Subject: [PATCH 5/9] refactor: move CoinJoin server to `ActiveContext` --- src/coinjoin/context.cpp | 13 +++++-------- src/coinjoin/context.h | 14 ++++---------- src/init.cpp | 12 +++++++----- src/masternode/active/context.cpp | 20 +++++++++++++------- src/masternode/active/context.h | 23 ++++++++++++++++++++--- src/net_processing.cpp | 18 +++++++++++++----- src/net_processing.h | 2 ++ src/rpc/coinjoin.cpp | 3 ++- src/test/denialofservice_tests.cpp | 22 ++++++++++++---------- src/test/net_peer_connection_tests.cpp | 6 ++++-- src/test/util/setup_common.cpp | 9 +++++---- 11 files changed, 87 insertions(+), 55 deletions(-) diff --git a/src/coinjoin/context.cpp b/src/coinjoin/context.cpp index ced47cdf2374..52884e802b0e 100644 --- a/src/coinjoin/context.cpp +++ b/src/coinjoin/context.cpp @@ -7,13 +7,11 @@ #ifdef ENABLE_WALLET #include #endif // ENABLE_WALLET -#include +#include -CJContext::CJContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, - CMasternodeMetaMan& mn_metaman, CTxMemPool& mempool, - const CActiveMasternodeManager* const mn_activeman, const CMasternodeSync& mn_sync, - const llmq::CInstantSendManager& isman, std::unique_ptr& peerman, bool relay_txes) : - dstxman{std::make_unique()}, +CJContext::CJContext(ChainstateManager& chainman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, + CTxMemPool& mempool, const CActiveMasternodeManager* const mn_activeman, + const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, bool relay_txes) : #ifdef ENABLE_WALLET walletman{std::make_unique(chainman, dmnman, mn_metaman, mempool, mn_sync, isman, queueman, /*is_masternode=*/mn_activeman != nullptr)}, @@ -21,8 +19,7 @@ CJContext::CJContext(ChainstateManager& chainman, CConnman& connman, CDeterminis /*is_masternode=*/mn_activeman != nullptr) : nullptr}, #endif // ENABLE_WALLET - server{std::make_unique(chainman, connman, dmnman, *dstxman, mn_metaman, mempool, mn_activeman, - mn_sync, isman, peerman)} + dstxman{std::make_unique()} {} CJContext::~CJContext() {} diff --git a/src/coinjoin/context.h b/src/coinjoin/context.h index bc31718cff59..eb924f345772 100644 --- a/src/coinjoin/context.h +++ b/src/coinjoin/context.h @@ -12,16 +12,12 @@ #include class CActiveMasternodeManager; -class CBlockPolicyEstimator; -class CCoinJoinServer; -class CConnman; class CDeterministicMNManager; class CDSTXManager; class ChainstateManager; class CMasternodeMetaMan; class CMasternodeSync; class CTxMemPool; -class PeerManager; namespace llmq { class CInstantSendManager; }; @@ -34,19 +30,17 @@ class CoinJoinWalletManager; struct CJContext { CJContext() = delete; CJContext(const CJContext&) = delete; - CJContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, - CMasternodeMetaMan& mn_metaman, CTxMemPool& mempool, const CActiveMasternodeManager* const mn_activeman, - const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, - std::unique_ptr& peerman, bool relay_txes); + CJContext(ChainstateManager& chainman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, + CTxMemPool& mempool, const CActiveMasternodeManager* const mn_activeman, const CMasternodeSync& mn_sync, + const llmq::CInstantSendManager& isman, bool relay_txes); ~CJContext(); - const std::unique_ptr dstxman; #ifdef ENABLE_WALLET // The main object for accessing mixing const std::unique_ptr walletman; const std::unique_ptr queueman; #endif // ENABLE_WALLET - const std::unique_ptr server; + const std::unique_ptr dstxman; }; #endif // BITCOIN_COINJOIN_CONTEXT_H diff --git a/src/init.cpp b/src/init.cpp index 1703daa276f3..ca14d1d67fa5 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2147,7 +2147,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(), chainman, *node.mempool, *node.mn_metaman, *node.mn_sync, *node.govman, *node.sporkman, node.mn_activeman.get(), node.dmnman, - node.cj_ctx, node.llmq_ctx, ignores_incoming_txs); + node.active_ctx, node.cj_ctx, node.llmq_ctx, ignores_incoming_txs); RegisterValidationInterface(node.peerman.get()); g_ds_notification_interface = std::make_unique( @@ -2157,14 +2157,16 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 7c: Setup CoinJoin - node.cj_ctx = std::make_unique(chainman, *node.connman, *node.dmnman, *node.mn_metaman, *node.mempool, - node.mn_activeman.get(), *node.mn_sync, *node.llmq_ctx->isman, node.peerman, + node.cj_ctx = std::make_unique(chainman, *node.dmnman, *node.mn_metaman, *node.mempool, + node.mn_activeman.get(), *node.mn_sync, *node.llmq_ctx->isman, !ignores_incoming_txs); // ********************************************************* Step 7d: Setup masternode mode assert(!node.active_ctx); if (node.mn_activeman) { - node.active_ctx = std::make_unique(chainman.ActiveChainstate(), *node.llmq_ctx, *node.sporkman, *node.mempool, *node.mn_sync); + node.active_ctx = std::make_unique(chainman, *node.connman, *node.dmnman, *node.cj_ctx->dstxman, *node.mn_metaman, + *node.llmq_ctx, *node.sporkman, *node.mempool, *node.mn_activeman, *node.mn_sync, + node.peerman); } // ********************************************************* Step 7e: Setup other Dash services @@ -2276,7 +2278,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } if (node.mn_activeman) { - node.scheduler->scheduleEvery(std::bind(&CCoinJoinServer::DoMaintenance, std::ref(*node.cj_ctx->server)), std::chrono::seconds{1}); + node.scheduler->scheduleEvery(std::bind(&CCoinJoinServer::DoMaintenance, std::ref(*node.active_ctx->cj_server)), std::chrono::seconds{1}); node.scheduler->scheduleEvery(std::bind(&llmq::CDKGSessionManager::CleanupOldContributions, std::ref(*node.llmq_ctx->qdkgsman)), std::chrono::hours{1}); #ifdef ENABLE_WALLET } else if (!ignores_incoming_txs) { diff --git a/src/masternode/active/context.cpp b/src/masternode/active/context.cpp index 3d84883e4eff..60ce43f41278 100644 --- a/src/masternode/active/context.cpp +++ b/src/masternode/active/context.cpp @@ -6,18 +6,24 @@ #include #include +#include #include #include #include +#include -ActiveContext::ActiveContext(CChainState& chainstate, LLMQContext& llmq_ctx, CSporkManager& sporkman, - CTxMemPool& mempool, const CMasternodeSync& mn_sync) : +ActiveContext::ActiveContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, + CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, LLMQContext& llmq_ctx, + CSporkManager& sporkman, CTxMemPool& mempool, const CActiveMasternodeManager& mn_activeman, + const CMasternodeSync& mn_sync, std::unique_ptr& peerman) : m_llmq_ctx{llmq_ctx}, - cl_signer{std::make_unique(chainstate, *llmq_ctx.clhandler, *llmq_ctx.sigman, - *llmq_ctx.shareman, sporkman, mn_sync)}, - is_signer{std::make_unique(chainstate, *llmq_ctx.clhandler, *llmq_ctx.isman, - *llmq_ctx.sigman, *llmq_ctx.shareman, *llmq_ctx.qman, - sporkman, mempool, mn_sync)} + cl_signer{std::make_unique(chainman.ActiveChainstate(), *llmq_ctx.clhandler, + *llmq_ctx.sigman, *llmq_ctx.shareman, sporkman, mn_sync)}, + is_signer{std::make_unique(chainman.ActiveChainstate(), *llmq_ctx.clhandler, + *llmq_ctx.isman, *llmq_ctx.sigman, *llmq_ctx.shareman, + *llmq_ctx.qman, sporkman, mempool, mn_sync)}, + cj_server{std::make_unique(chainman, connman, dmnman, dstxman, mn_metaman, mempool, &mn_activeman, + mn_sync, *llmq_ctx.isman, peerman)} { m_llmq_ctx.clhandler->ConnectSigner(cl_signer.get()); m_llmq_ctx.isman->ConnectSigner(is_signer.get()); diff --git a/src/masternode/active/context.h b/src/masternode/active/context.h index e8eb751843d3..46e13feabb3c 100644 --- a/src/masternode/active/context.h +++ b/src/masternode/active/context.h @@ -7,10 +7,17 @@ #include -class CChainState; +class CActiveMasternodeManager; +class ChainstateManager; +class CCoinJoinServer; +class CConnman; +class CDeterministicMNManager; +class CDSTXManager; +class CMasternodeMetaMan; class CMasternodeSync; class CSporkManager; class CTxMemPool; +class PeerManager; struct LLMQContext; namespace chainlock { class ChainLockSigner; @@ -21,6 +28,7 @@ class InstantSendSigner; struct ActiveContext { private: + // TODO: Switch to references to members when migration is finished LLMQContext& m_llmq_ctx; /* @@ -33,9 +41,18 @@ struct ActiveContext { public: ActiveContext() = delete; ActiveContext(const ActiveContext&) = delete; - ActiveContext(CChainState& chainstate, LLMQContext& llmq_ctx, CSporkManager& sporkman, CTxMemPool& mempool, - const CMasternodeSync& mn_sync); + ActiveContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, + CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, LLMQContext& llmq_ctx, CSporkManager& sporkman, + CTxMemPool& mempool, const CActiveMasternodeManager& mn_activeman, const CMasternodeSync& mn_sync, + std::unique_ptr& peerman); ~ActiveContext(); + + /* + * Entities that are only utilized when masternode mode is enabled + * and are accessible in their own right + * TODO: Move CActiveMasternodeManager here when dependents have been migrated + */ + const std::unique_ptr cj_server; }; #endif // BITCOIN_MASTERNODE_ACTIVE_CONTEXT_H diff --git a/src/net_processing.cpp b/src/net_processing.cpp index fb6f2238470c..33f3b1dd4278 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -51,6 +51,7 @@ #include #include +#include #include #include #ifdef ENABLE_WALLET @@ -595,6 +596,7 @@ class PeerManagerImpl final : public PeerManager CGovernanceManager& govman, CSporkManager& sporkman, const CActiveMasternodeManager* const mn_activeman, const std::unique_ptr& dmnman, + const std::unique_ptr& active_ctx, const std::unique_ptr& cj_ctx, const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs); @@ -776,6 +778,7 @@ class PeerManagerImpl final : public PeerManager CTxMemPool& m_mempool; std::unique_ptr m_txreconciliation; const std::unique_ptr& m_dmnman; + const std::unique_ptr& m_active_ctx; const std::unique_ptr& m_cj_ctx; const std::unique_ptr& m_llmq_ctx; CMasternodeMetaMan& m_mn_metaman; @@ -1948,10 +1951,11 @@ std::unique_ptr PeerManager::make(const CChainParams& chainparams, CGovernanceManager& govman, CSporkManager& sporkman, const CActiveMasternodeManager* const mn_activeman, const std::unique_ptr& dmnman, + const std::unique_ptr& active_ctx, const std::unique_ptr& cj_ctx, const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs) { - return std::make_unique(chainparams, connman, addrman, banman, chainman, pool, mn_metaman, mn_sync, govman, sporkman, mn_activeman, dmnman, cj_ctx, llmq_ctx, ignore_incoming_txs); + return std::make_unique(chainparams, connman, addrman, banman, chainman, pool, mn_metaman, mn_sync, govman, sporkman, mn_activeman, dmnman, active_ctx, cj_ctx, llmq_ctx, ignore_incoming_txs); } PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman, BanMan* banman, @@ -1960,6 +1964,7 @@ PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& conn CGovernanceManager& govman, CSporkManager& sporkman, const CActiveMasternodeManager* const mn_activeman, const std::unique_ptr& dmnman, + const std::unique_ptr& active_ctx, const std::unique_ptr& cj_ctx, const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs) @@ -1970,6 +1975,7 @@ PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& conn m_chainman(chainman), m_mempool(pool), m_dmnman(dmnman), + m_active_ctx(active_ctx), m_cj_ctx(cj_ctx), m_llmq_ctx(llmq_ctx), m_mn_metaman(mn_metaman), @@ -2260,9 +2266,9 @@ bool PeerManagerImpl::AlreadyHave(const CInv& inv) return m_llmq_ctx->isman->AlreadyHave(inv); case MSG_DSQ: #ifdef ENABLE_WALLET - return m_cj_ctx->server->HasQueue(inv.hash) || m_cj_ctx->queueman->HasQueue(inv.hash); + return m_cj_ctx->queueman->HasQueue(inv.hash) || (m_active_ctx && m_active_ctx->cj_server->HasQueue(inv.hash)); #else - return m_cj_ctx->server->HasQueue(inv.hash); + return m_active_ctx && m_active_ctx->cj_server->HasQueue(inv.hash); #endif } @@ -2867,7 +2873,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic } } if (!push && inv.type == MSG_DSQ) { - auto opt_dsq = m_cj_ctx->server->GetQueueFromHash(inv.hash); + auto opt_dsq = m_active_ctx ? m_active_ctx->cj_server->GetQueueFromHash(inv.hash) : std::nullopt; #ifdef ENABLE_WALLET if (!opt_dsq.has_value()) { opt_dsq = m_cj_ctx->queueman->GetQueueFromHash(inv.hash); @@ -5249,7 +5255,9 @@ void PeerManagerImpl::ProcessMessage( clientman->ProcessMessage(pfrom, m_chainman.ActiveChainstate(), m_connman, m_mempool, msg_type, vRecv); }); #endif // ENABLE_WALLET - PostProcessMessage(m_cj_ctx->server->ProcessMessage(pfrom, msg_type, vRecv), pfrom.GetId()); + if (m_active_ctx) { + PostProcessMessage(m_active_ctx->cj_server->ProcessMessage(pfrom, msg_type, vRecv), pfrom.GetId()); + } PostProcessMessage(m_sporkman.ProcessMessage(pfrom, m_connman, msg_type, vRecv), pfrom.GetId()); m_mn_sync.ProcessMessage(pfrom, msg_type, vRecv); PostProcessMessage(m_govman.ProcessMessage(pfrom, m_connman, *this, msg_type, vRecv), pfrom.GetId()); diff --git a/src/net_processing.h b/src/net_processing.h index 99356f8aa2a9..8e0b9e8f8692 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -25,6 +25,7 @@ class CGovernanceManager; class CInv; class CSporkManager; class CTransaction; +struct ActiveContext; struct CJContext; struct LLMQContext; @@ -60,6 +61,7 @@ class PeerManager : public CValidationInterface, public NetEventsInterface CGovernanceManager& govman, CSporkManager& sporkman, const CActiveMasternodeManager* const mn_activeman, const std::unique_ptr& dmnman, + const std::unique_ptr& active_ctx, const std::unique_ptr& cj_ctx, const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs); virtual ~PeerManager() { } diff --git a/src/rpc/coinjoin.cpp b/src/rpc/coinjoin.cpp index 539972428e7d..c7d29f65204c 100644 --- a/src/rpc/coinjoin.cpp +++ b/src/rpc/coinjoin.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -466,7 +467,7 @@ static RPCHelpMan getcoinjoininfo() const NodeContext& node = EnsureAnyNodeContext(request.context); if (node.mn_activeman) { - node.cj_ctx->server->GetJsonInfo(obj); + node.active_ctx->cj_server->GetJsonInfo(obj); return obj; } diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index 8761dc406eeb..06c92a1434c5 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -20,6 +20,8 @@ #include #include +#include + #include #include @@ -146,10 +148,10 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management) NodeId id{0}; const CChainParams& chainparams = Params(); auto connman = std::make_unique(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman); - auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr, + auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, /*banman=*/nullptr, *m_node.chainman, *m_node.mempool, *m_node.mn_metaman, *m_node.mn_sync, - *m_node.govman, *m_node.sporkman, /* mn_activeman = */ nullptr, m_node.dmnman, - m_node.cj_ctx, m_node.llmq_ctx, /* ignore_incoming_txs = */ false); + *m_node.govman, *m_node.sporkman, /*mn_activeman=*/ nullptr, m_node.dmnman, + /*active_ctx=*/nullptr, m_node.cj_ctx, m_node.llmq_ctx, /*ignore_incoming_txs=*/false); constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS; CConnman::Options options; @@ -250,10 +252,10 @@ BOOST_AUTO_TEST_CASE(block_relay_only_eviction) NodeId id{0}; const CChainParams& chainparams = Params(); auto connman = std::make_unique(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman); - auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr, + auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, /*banman=*/nullptr, *m_node.chainman, *m_node.mempool, *m_node.mn_metaman, *m_node.mn_sync, - *m_node.govman, *m_node.sporkman, /* mn_activeman = */ nullptr, m_node.dmnman, - m_node.cj_ctx, m_node.llmq_ctx, /* ignore_incoming_txs = */ false); + *m_node.govman, *m_node.sporkman, /*mn_activeman=*/ nullptr, m_node.dmnman, + /*active_ctx=*/nullptr, m_node.cj_ctx, m_node.llmq_ctx, /*ignore_incoming_txs=*/false); constexpr int max_outbound_block_relay{MAX_BLOCK_RELAY_ONLY_CONNECTIONS}; constexpr int64_t MINIMUM_CONNECT_TIME{30}; @@ -319,8 +321,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) auto connman = std::make_unique(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman); auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, *m_node.mn_metaman, *m_node.mn_sync, - *m_node.govman, *m_node.sporkman, /* mn_activeman = */ nullptr, m_node.dmnman, - m_node.cj_ctx, m_node.llmq_ctx, /* ignore_incoming_txs = */ false); + *m_node.govman, *m_node.sporkman, /*mn_activeman=*/nullptr, m_node.dmnman, + /*active_ctx=*/nullptr, m_node.cj_ctx, m_node.llmq_ctx, /*ignore_incoming_txs=*/false); CNetAddr tor_netaddr; BOOST_REQUIRE( @@ -424,8 +426,8 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) auto connman = std::make_unique(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman); auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, *m_node.mn_metaman, *m_node.mn_sync, - *m_node.govman, *m_node.sporkman, /* mn_activeman = */ nullptr, m_node.dmnman, - m_node.cj_ctx, m_node.llmq_ctx, /* ignore_incoming_txs = */ false); + *m_node.govman, *m_node.sporkman, /*mn_activeman=*/nullptr, m_node.dmnman, + /*active_ctx=*/nullptr, m_node.cj_ctx, m_node.llmq_ctx, /*ignore_incoming_txs=*/false); banman->ClearBanned(); int64_t nStartTime = GetTime(); diff --git a/src/test/net_peer_connection_tests.cpp b/src/test/net_peer_connection_tests.cpp index 1273babb6d34..ac8e307f463c 100644 --- a/src/test/net_peer_connection_tests.cpp +++ b/src/test/net_peer_connection_tests.cpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -85,8 +87,8 @@ BOOST_AUTO_TEST_CASE(test_addnode_getaddednodeinfo_and_connection_detection) auto connman = std::make_unique(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman); auto peerman = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.mn_metaman, *m_node.mn_sync, - *m_node.govman, *m_node.sporkman, /* mn_activeman = */ nullptr, m_node.dmnman, - m_node.cj_ctx, m_node.llmq_ctx, /* ignore_incoming_txs = */ false); + *m_node.govman, *m_node.sporkman, /*mn_activeman=*/nullptr, m_node.dmnman, + /*active_ctx=*/nullptr, m_node.cj_ctx, m_node.llmq_ctx, /*ignore_incoming_txs=*/false); NodeId id{0}; std::vector nodes; diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 6c8d35946412..5ff670fab0c9 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -333,8 +334,8 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman, m_node.banman.get(), *m_node.chainman, *m_node.mempool, *m_node.mn_metaman, *m_node.mn_sync, - *m_node.govman, *m_node.sporkman, /* mn_activeman = */ nullptr, m_node.dmnman, - m_node.cj_ctx, m_node.llmq_ctx, /* ignore_incoming_txs = */ false); + *m_node.govman, *m_node.sporkman, /*mn_activeman=*/nullptr, m_node.dmnman, + /*active_ctx=*/nullptr, m_node.cj_ctx, m_node.llmq_ctx, /*ignore_incoming_txs=*/false); { CConnman::Options options; options.m_msgproc = m_node.peerman.get(); @@ -342,8 +343,8 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vectorInit(options); } - m_node.cj_ctx = std::make_unique(*m_node.chainman, *m_node.connman, *m_node.dmnman, *m_node.mn_metaman, *m_node.mempool, - /*mn_activeman=*/nullptr, *m_node.mn_sync, *m_node.llmq_ctx->isman, m_node.peerman, + m_node.cj_ctx = std::make_unique(*m_node.chainman, *m_node.dmnman, *m_node.mn_metaman, *m_node.mempool, + /*mn_activeman=*/nullptr, *m_node.mn_sync, *m_node.llmq_ctx->isman, /*relay_txes=*/true); #ifdef ENABLE_WALLET From d52795c231a6da2e72dbfab9b2f67c5ad2892b10 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 25 Aug 2025 09:13:17 +0000 Subject: [PATCH 6/9] refactor: clean up `CCoinJoinServer`, remove redundant checks Now that CCoinJoinServer is conditionally initialized, we can remove checks that assumed its unconditional existence. --- src/coinjoin/server.cpp | 62 +++++++++---------------------- src/coinjoin/server.h | 10 ++--- src/init.cpp | 4 +- src/masternode/active/context.cpp | 8 ++-- src/masternode/active/context.h | 7 ++-- 5 files changed, 32 insertions(+), 59 deletions(-) diff --git a/src/coinjoin/server.cpp b/src/coinjoin/server.cpp index ad068dc59db1..23c8f5e09a86 100644 --- a/src/coinjoin/server.cpp +++ b/src/coinjoin/server.cpp @@ -25,7 +25,6 @@ MessageProcessingResult CCoinJoinServer::ProcessMessage(CNode& peer, std::string_view msg_type, CDataStream& vRecv) { - if (!m_mn_activeman) return {}; if (!m_mn_sync.IsBlockchainSynced()) return {}; if (msg_type == NetMsgType::DSACCEPT) { @@ -42,7 +41,6 @@ MessageProcessingResult CCoinJoinServer::ProcessMessage(CNode& peer, std::string void CCoinJoinServer::ProcessDSACCEPT(CNode& peer, CDataStream& vRecv) { - assert(m_mn_activeman); assert(m_mn_metaman.IsValid()); if (IsSessionReady()) { @@ -58,7 +56,7 @@ void CCoinJoinServer::ProcessDSACCEPT(CNode& peer, CDataStream& vRecv) LogPrint(BCLog::COINJOIN, "DSACCEPT -- nDenom %d (%s) txCollateral %s", dsa.nDenom, CoinJoin::DenominationToString(dsa.nDenom), dsa.txCollateral.ToString()); /* Continued */ auto mnList = m_dmnman.GetListAtChainTip(); - auto dmn = mnList.GetValidMNByCollateral(m_mn_activeman->GetOutPoint()); + auto dmn = mnList.GetValidMNByCollateral(m_mn_activeman.GetOutPoint()); if (!dmn) { PushStatus(peer, STATUS_REJECTED, ERR_MN_LIST); return; @@ -69,7 +67,7 @@ void CCoinJoinServer::ProcessDSACCEPT(CNode& peer, CDataStream& vRecv) TRY_LOCK(cs_vecqueue, lockRecv); if (!lockRecv) return; - auto mnOutpoint = m_mn_activeman->GetOutPoint(); + auto mnOutpoint = m_mn_activeman.GetOutPoint(); if (ranges::any_of(vecCoinJoinQueue, [&mnOutpoint](const auto& q){return q.masternodeOutpoint == mnOutpoint;})) { @@ -183,7 +181,7 @@ MessageProcessingResult CCoinJoinServer::ProcessDSQUEUE(NodeId from, CDataStream TRY_LOCK(cs_vecqueue, lockRecv); if (!lockRecv) return ret; vecCoinJoinQueue.push_back(dsq); - m_peerman->RelayDSQ(dsq); + m_peerman.RelayDSQ(dsq); } return ret; } @@ -254,8 +252,6 @@ void CCoinJoinServer::SetNull() // void CCoinJoinServer::CheckPool() { - if (!m_mn_activeman) return; - if (int entries = GetEntriesCount(); entries != 0) LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CheckPool -- entries count %lu\n", entries); // If we have an entry for each collateral, then create final tx @@ -317,7 +313,6 @@ void CCoinJoinServer::CreateFinalTransaction() void CCoinJoinServer::CommitFinalTransaction() { AssertLockNotHeld(cs_coinjoin); - if (!m_mn_activeman) return; // check and relay final tx only on masternode CTransactionRef finalTransaction = WITH_LOCK(cs_coinjoin, return MakeTransactionRef(finalMutableTransaction)); uint256 hashTx = finalTransaction->GetHash(); @@ -341,18 +336,16 @@ void CCoinJoinServer::CommitFinalTransaction() // create and sign masternode dstx transaction if (!m_dstxman.GetDSTX(hashTx)) { - CCoinJoinBroadcastTx dstxNew(finalTransaction, - m_mn_activeman->GetOutPoint(), - m_mn_activeman->GetProTxHash(), - GetAdjustedTime()); - dstxNew.Sign(*m_mn_activeman); + CCoinJoinBroadcastTx dstxNew(finalTransaction, m_mn_activeman.GetOutPoint(), m_mn_activeman.GetProTxHash(), + GetAdjustedTime()); + dstxNew.Sign(m_mn_activeman); m_dstxman.AddDSTX(dstxNew); } LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CommitFinalTransaction -- TRANSMITTING DSTX\n"); CInv inv(MSG_DSTX, hashTx); - Assert(m_peerman)->RelayInv(inv); + m_peerman.RelayInv(inv); // Tell the clients it was successful RelayCompletedTransaction(MSG_SUCCESS); @@ -380,7 +373,6 @@ void CCoinJoinServer::CommitFinalTransaction() void CCoinJoinServer::ChargeFees() const { AssertLockNotHeld(cs_coinjoin); - if (!m_mn_activeman) return; //we don't need to charge collateral for every offence. if (GetRand(/*nMax=*/100) > 33) return; @@ -448,8 +440,6 @@ void CCoinJoinServer::ChargeFees() const */ void CCoinJoinServer::ChargeRandomFees() const { - if (!m_mn_activeman) return; - for (const auto& txCollateral : vecSessionCollaterals) { if (GetRand(/*nMax=*/100) > 10) return; LogPrint(BCLog::COINJOIN, "CCoinJoinServer::ChargeRandomFees -- charging random fees, txCollateral=%s", txCollateral->ToString()); /* Continued */ @@ -463,15 +453,13 @@ void CCoinJoinServer::ConsumeCollateral(const CTransactionRef& txref) const if (!ATMPIfSaneFee(m_chainman, txref)) { LogPrint(BCLog::COINJOIN, "%s -- ATMPIfSaneFee failed\n", __func__); } else { - Assert(m_peerman)->RelayTransaction(txref->GetHash()); + m_peerman.RelayTransaction(txref->GetHash()); LogPrint(BCLog::COINJOIN, "%s -- Collateral was consumed\n", __func__); } } bool CCoinJoinServer::HasTimedOut() const { - if (!m_mn_activeman) return false; - if (nState == POOL_STATE_IDLE) return false; int nTimeout = (nState == POOL_STATE_SIGNING) ? COINJOIN_SIGNING_TIMEOUT : COINJOIN_QUEUE_TIMEOUT; @@ -484,8 +472,6 @@ bool CCoinJoinServer::HasTimedOut() const // void CCoinJoinServer::CheckTimeout() { - if (!m_mn_activeman) return; - CheckQueue(); // Too early to do anything @@ -504,19 +490,15 @@ void CCoinJoinServer::CheckTimeout() */ void CCoinJoinServer::CheckForCompleteQueue() { - if (!m_mn_activeman) return; - if (nState == POOL_STATE_QUEUE && IsSessionReady()) { SetState(POOL_STATE_ACCEPTING_ENTRIES); - CCoinJoinQueue dsq(nSessionDenom, - m_mn_activeman->GetOutPoint(), - m_mn_activeman->GetProTxHash(), - GetAdjustedTime(), true); + CCoinJoinQueue dsq(nSessionDenom, m_mn_activeman.GetOutPoint(), m_mn_activeman.GetProTxHash(), + GetAdjustedTime(), true); LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CheckForCompleteQueue -- queue is ready, signing and relaying (%s) " /* Continued */ "with %d participants\n", dsq.ToString(), vecSessionCollaterals.size()); - dsq.Sign(*m_mn_activeman); - m_peerman->RelayDSQ(dsq); + dsq.Sign(m_mn_activeman); + m_peerman.RelayDSQ(dsq); WITH_LOCK(cs_vecqueue, vecCoinJoinQueue.push_back(dsq)); } } @@ -572,7 +554,6 @@ bool CCoinJoinServer::IsInputScriptSigValid(const CTxIn& txin) const bool CCoinJoinServer::AddEntry(const CCoinJoinEntry& entry, PoolMessage& nMessageIDRet) { AssertLockNotHeld(cs_coinjoin); - if (!m_mn_activeman) return false; if (size_t(GetEntriesCount()) >= vecSessionCollaterals.size()) { LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- ERROR: entries is full!\n", __func__); @@ -682,8 +663,6 @@ bool CCoinJoinServer::IsSignaturesComplete() const bool CCoinJoinServer::IsAcceptableDSA(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet) const { - if (!m_mn_activeman) return false; - // is denom even something legit? if (!CoinJoin::IsValidDenomination(dsa.nDenom)) { LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- denom not valid!\n", __func__); @@ -703,7 +682,7 @@ bool CCoinJoinServer::IsAcceptableDSA(const CCoinJoinAccept& dsa, PoolMessage& n bool CCoinJoinServer::CreateNewSession(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet) { - if (!m_mn_activeman || nSessionID != 0) return false; + if (nSessionID != 0) return false; // new session can only be started in idle mode if (nState != POOL_STATE_IDLE) { @@ -725,13 +704,11 @@ bool CCoinJoinServer::CreateNewSession(const CCoinJoinAccept& dsa, PoolMessage& if (!fUnitTest) { //broadcast that I'm accepting entries, only if it's the first entry through - CCoinJoinQueue dsq(nSessionDenom, - m_mn_activeman->GetOutPoint(), - m_mn_activeman->GetProTxHash(), - GetAdjustedTime(), false); + CCoinJoinQueue dsq(nSessionDenom, m_mn_activeman.GetOutPoint(), m_mn_activeman.GetProTxHash(), + GetAdjustedTime(), false); LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CreateNewSession -- signing and relaying new queue: %s\n", dsq.ToString()); - dsq.Sign(*m_mn_activeman); - m_peerman->RelayDSQ(dsq); + dsq.Sign(m_mn_activeman); + m_peerman.RelayDSQ(dsq); LOCK(cs_vecqueue); vecCoinJoinQueue.push_back(dsq); } @@ -745,7 +722,7 @@ bool CCoinJoinServer::CreateNewSession(const CCoinJoinAccept& dsa, PoolMessage& bool CCoinJoinServer::AddUserToExistingSession(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet) { - if (!m_mn_activeman || nSessionID == 0 || IsSessionReady()) return false; + if (nSessionID == 0 || IsSessionReady()) return false; if (!IsAcceptableDSA(dsa, nMessageIDRet)) { return false; @@ -881,8 +858,6 @@ void CCoinJoinServer::RelayCompletedTransaction(PoolMessage nMessageID) void CCoinJoinServer::SetState(PoolState nStateNew) { - if (!m_mn_activeman) return; - if (nStateNew == POOL_STATE_ERROR) { LogPrint(BCLog::COINJOIN, "CCoinJoinServer::SetState -- Can't set state to ERROR as a Masternode. \n"); return; @@ -895,7 +870,6 @@ void CCoinJoinServer::SetState(PoolState nStateNew) void CCoinJoinServer::DoMaintenance() { - if (!m_mn_activeman) return; // only run on masternodes if (!m_mn_sync.IsBlockchainSynced()) return; if (ShutdownRequested()) return; diff --git a/src/coinjoin/server.h b/src/coinjoin/server.h index eee182fb9230..31099a6ac384 100644 --- a/src/coinjoin/server.h +++ b/src/coinjoin/server.h @@ -35,10 +35,10 @@ class CCoinJoinServer : public CCoinJoinBaseSession, public CCoinJoinBaseManager CDSTXManager& m_dstxman; CMasternodeMetaMan& m_mn_metaman; CTxMemPool& mempool; - const CActiveMasternodeManager* const m_mn_activeman; + PeerManager& m_peerman; + const CActiveMasternodeManager& m_mn_activeman; const CMasternodeSync& m_mn_sync; const llmq::CInstantSendManager& m_isman; - std::unique_ptr& m_peerman; // Mixing uses collateral transactions to trust parties entering the pool // to behave honestly. If they don't it takes their money. @@ -95,18 +95,18 @@ class CCoinJoinServer : public CCoinJoinBaseSession, public CCoinJoinBaseManager public: explicit CCoinJoinServer(ChainstateManager& chainman, CConnman& _connman, CDeterministicMNManager& dmnman, CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, CTxMemPool& mempool, - const CActiveMasternodeManager* const mn_activeman, const CMasternodeSync& mn_sync, - const llmq::CInstantSendManager& isman, std::unique_ptr& peerman) : + PeerManager& peerman, const CActiveMasternodeManager& mn_activeman, + const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman) : m_chainman(chainman), connman(_connman), m_dmnman(dmnman), m_dstxman(dstxman), m_mn_metaman(mn_metaman), mempool(mempool), + m_peerman(peerman), m_mn_activeman(mn_activeman), m_mn_sync(mn_sync), m_isman{isman}, - m_peerman(peerman), vecSessionCollaterals(), fUnitTest(false) {} diff --git a/src/init.cpp b/src/init.cpp index ca14d1d67fa5..8e26e247e81a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2165,8 +2165,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) assert(!node.active_ctx); if (node.mn_activeman) { node.active_ctx = std::make_unique(chainman, *node.connman, *node.dmnman, *node.cj_ctx->dstxman, *node.mn_metaman, - *node.llmq_ctx, *node.sporkman, *node.mempool, *node.mn_activeman, *node.mn_sync, - node.peerman); + *node.llmq_ctx, *node.sporkman, *node.mempool, *node.peerman, *node.mn_activeman, + *node.mn_sync); } // ********************************************************* Step 7e: Setup other Dash services diff --git a/src/masternode/active/context.cpp b/src/masternode/active/context.cpp index 60ce43f41278..97332bbb9f1b 100644 --- a/src/masternode/active/context.cpp +++ b/src/masternode/active/context.cpp @@ -14,16 +14,16 @@ ActiveContext::ActiveContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, LLMQContext& llmq_ctx, - CSporkManager& sporkman, CTxMemPool& mempool, const CActiveMasternodeManager& mn_activeman, - const CMasternodeSync& mn_sync, std::unique_ptr& peerman) : + CSporkManager& sporkman, CTxMemPool& mempool, PeerManager& peerman, + const CActiveMasternodeManager& mn_activeman, const CMasternodeSync& mn_sync) : m_llmq_ctx{llmq_ctx}, cl_signer{std::make_unique(chainman.ActiveChainstate(), *llmq_ctx.clhandler, *llmq_ctx.sigman, *llmq_ctx.shareman, sporkman, mn_sync)}, is_signer{std::make_unique(chainman.ActiveChainstate(), *llmq_ctx.clhandler, *llmq_ctx.isman, *llmq_ctx.sigman, *llmq_ctx.shareman, *llmq_ctx.qman, sporkman, mempool, mn_sync)}, - cj_server{std::make_unique(chainman, connman, dmnman, dstxman, mn_metaman, mempool, &mn_activeman, - mn_sync, *llmq_ctx.isman, peerman)} + cj_server{std::make_unique(chainman, connman, dmnman, dstxman, mn_metaman, mempool, peerman, + mn_activeman, mn_sync, *llmq_ctx.isman)} { m_llmq_ctx.clhandler->ConnectSigner(cl_signer.get()); m_llmq_ctx.isman->ConnectSigner(is_signer.get()); diff --git a/src/masternode/active/context.h b/src/masternode/active/context.h index 46e13feabb3c..8651b09e763a 100644 --- a/src/masternode/active/context.h +++ b/src/masternode/active/context.h @@ -41,10 +41,9 @@ struct ActiveContext { public: ActiveContext() = delete; ActiveContext(const ActiveContext&) = delete; - ActiveContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, - CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, LLMQContext& llmq_ctx, CSporkManager& sporkman, - CTxMemPool& mempool, const CActiveMasternodeManager& mn_activeman, const CMasternodeSync& mn_sync, - std::unique_ptr& peerman); + ActiveContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, CDSTXManager& dstxman, + CMasternodeMetaMan& mn_metaman, LLMQContext& llmq_ctx, CSporkManager& sporkman, CTxMemPool& mempool, + PeerManager& peerman, const CActiveMasternodeManager& mn_activeman, const CMasternodeSync& mn_sync); ~ActiveContext(); /* From 83707a0c1058943fa3f1e0f017686c69e6dc7fc2 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 9 Sep 2025 14:08:21 +0000 Subject: [PATCH 7/9] refactor: create notification interface for masternode mode --- src/Makefile.am | 2 ++ src/init.cpp | 15 ++++++---- .../active/notificationinterface.cpp | 23 ++++++++++++++ src/masternode/active/notificationinterface.h | 30 +++++++++++++++++++ src/masternode/node.h | 4 +-- 5 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 src/masternode/active/notificationinterface.cpp create mode 100644 src/masternode/active/notificationinterface.h diff --git a/src/Makefile.am b/src/Makefile.am index c54c11874327..f2246d57c0c0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -263,6 +263,7 @@ BITCOIN_CORE_H = \ logging/timer.h \ mapport.h \ masternode/active/context.h \ + masternode/active/notificationinterface.h \ masternode/node.h \ masternode/meta.h \ masternode/payments.h \ @@ -522,6 +523,7 @@ libbitcoin_node_a_SOURCES = \ llmq/utils.cpp \ mapport.cpp \ masternode/active/context.cpp \ + masternode/active/notificationinterface.cpp \ masternode/node.cpp \ masternode/meta.cpp \ masternode/payments.cpp \ diff --git a/src/init.cpp b/src/init.cpp index 8e26e247e81a..15f82a05a5f3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -92,6 +92,7 @@ #include #include #include +#include #include #include #include @@ -320,6 +321,11 @@ void PrepareShutdown(NodeContext& node) // CValidationInterface callbacks, flush them... GetMainSignals().FlushBackgroundCallbacks(); + if (g_active_notification_interface) { + UnregisterValidationInterface(g_active_notification_interface.get()); + g_active_notification_interface.reset(); + } + // After all scheduled tasks have been flushed, destroy pointers // and reset all to nullptr. node.active_ctx.reset(); @@ -376,10 +382,7 @@ void PrepareShutdown(NodeContext& node) g_ds_notification_interface.reset(); } - if (node.mn_activeman) { - UnregisterValidationInterface(node.mn_activeman.get()); - node.mn_activeman.reset(); - } + node.mn_activeman.reset(); node.chain_clients.clear(); @@ -1702,7 +1705,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } // Create and register mn_activeman, will init later in ThreadImport node.mn_activeman = std::make_unique(keyOperator, *node.connman, node.dmnman); - RegisterValidationInterface(node.mn_activeman.get()); } // Check port numbers @@ -2163,10 +2165,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 7d: Setup masternode mode assert(!node.active_ctx); + assert(!g_active_notification_interface); if (node.mn_activeman) { node.active_ctx = std::make_unique(chainman, *node.connman, *node.dmnman, *node.cj_ctx->dstxman, *node.mn_metaman, *node.llmq_ctx, *node.sporkman, *node.mempool, *node.peerman, *node.mn_activeman, *node.mn_sync); + g_active_notification_interface = std::make_unique(*node.mn_activeman); + RegisterValidationInterface(g_active_notification_interface.get()); } // ********************************************************* Step 7e: Setup other Dash services diff --git a/src/masternode/active/notificationinterface.cpp b/src/masternode/active/notificationinterface.cpp new file mode 100644 index 000000000000..a785a0bc48bf --- /dev/null +++ b/src/masternode/active/notificationinterface.cpp @@ -0,0 +1,23 @@ +// 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 + +ActiveNotificationInterface::ActiveNotificationInterface(CActiveMasternodeManager& mn_activeman) : + m_mn_activeman{mn_activeman} +{ +} + +void ActiveNotificationInterface::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, + bool fInitialDownload) +{ + if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones + return; + + m_mn_activeman.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); +} + +std::unique_ptr g_active_notification_interface; diff --git a/src/masternode/active/notificationinterface.h b/src/masternode/active/notificationinterface.h new file mode 100644 index 000000000000..f358f9441a4c --- /dev/null +++ b/src/masternode/active/notificationinterface.h @@ -0,0 +1,30 @@ +// 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_MASTERNODE_ACTIVE_NOTIFICATIONINTERFACE_H +#define BITCOIN_MASTERNODE_ACTIVE_NOTIFICATIONINTERFACE_H + +#include + +class CActiveMasternodeManager; + +class ActiveNotificationInterface final : public CValidationInterface +{ +public: + ActiveNotificationInterface() = delete; + ActiveNotificationInterface(const ActiveNotificationInterface&) = delete; + explicit ActiveNotificationInterface(CActiveMasternodeManager& mn_activeman); + virtual ~ActiveNotificationInterface() = default; + +protected: + // CValidationInterface + void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override; + +private: + CActiveMasternodeManager& m_mn_activeman; +}; + +extern std::unique_ptr g_active_notification_interface; + +#endif // BITCOIN_MASTERNODE_ACTIVE_NOTIFICATIONINTERFACE_H diff --git a/src/masternode/node.h b/src/masternode/node.h index f1a54ed2cc70..931233c42f72 100644 --- a/src/masternode/node.h +++ b/src/masternode/node.h @@ -27,7 +27,7 @@ struct CActiveMasternodeInfo { blsKeyOperator(blsKeyOperator), blsPubKeyOperator(blsPubKeyOperator) {}; }; -class CActiveMasternodeManager final : public CValidationInterface +class CActiveMasternodeManager { public: enum class MasternodeState { @@ -52,7 +52,7 @@ class CActiveMasternodeManager final : public CValidationInterface public: explicit CActiveMasternodeManager(const CBLSSecretKey& sk, CConnman& connman, const std::unique_ptr& dmnman); - void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override + void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) EXCLUSIVE_LOCKS_REQUIRED(!cs); void Init(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs) { LOCK(cs); InitInternal(pindex); }; From ecb924ccb4b88d999efcbef361fbf048f5f0da22 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 9 Sep 2025 14:05:33 +0000 Subject: [PATCH 8/9] refactor: move EHF signals handler to `ActiveContext` --- src/dsnotificationinterface.cpp | 1 - src/init.cpp | 4 ++-- src/llmq/context.cpp | 4 +--- src/llmq/context.h | 2 -- src/llmq/ehf_signals.cpp | 6 +----- src/llmq/ehf_signals.h | 2 +- src/masternode/active/context.cpp | 9 ++++++--- src/masternode/active/context.h | 12 +++++++++--- src/masternode/active/notificationinterface.cpp | 6 +++++- src/masternode/active/notificationinterface.h | 4 +++- 10 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/dsnotificationinterface.cpp b/src/dsnotificationinterface.cpp index 1b6d80b68737..95066be54658 100644 --- a/src/dsnotificationinterface.cpp +++ b/src/dsnotificationinterface.cpp @@ -92,7 +92,6 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con m_llmq_ctx->qman->UpdatedBlockTip(pindexNew, m_connman, fInitialDownload); m_llmq_ctx->qdkgsman->UpdatedBlockTip(pindexNew, fInitialDownload); - m_llmq_ctx->ehfSignalsHandler->UpdatedBlockTip(pindexNew, /* is_masternode = */ m_mn_activeman != nullptr); if (m_govman.IsValid()) { m_govman.UpdatedBlockTip(pindexNew, m_connman, m_peerman, m_mn_activeman); diff --git a/src/init.cpp b/src/init.cpp index 15f82a05a5f3..8b870c4c24a4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2167,10 +2167,10 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) assert(!node.active_ctx); assert(!g_active_notification_interface); if (node.mn_activeman) { - node.active_ctx = std::make_unique(chainman, *node.connman, *node.dmnman, *node.cj_ctx->dstxman, *node.mn_metaman, + node.active_ctx = std::make_unique(chainman, *node.connman, *node.dmnman, *node.cj_ctx->dstxman, *node.mn_metaman, *node.mnhf_manager, *node.llmq_ctx, *node.sporkman, *node.mempool, *node.peerman, *node.mn_activeman, *node.mn_sync); - g_active_notification_interface = std::make_unique(*node.mn_activeman); + g_active_notification_interface = std::make_unique(*node.active_ctx, *node.mn_activeman); RegisterValidationInterface(g_active_notification_interface.get()); } diff --git a/src/llmq/context.cpp b/src/llmq/context.cpp index 7a30a08d5b63..75e98f40bbfb 100644 --- a/src/llmq/context.cpp +++ b/src/llmq/context.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -38,8 +37,7 @@ LLMQContext::LLMQContext(ChainstateManager& chainman, CDeterministicMNManager& d clhandler{std::make_unique(chainman.ActiveChainstate(), *qman, *sigman, sporkman, mempool, mn_sync)}, isman{std::make_unique(*clhandler, chainman.ActiveChainstate(), *qman, *sigman, sporkman, - mempool, mn_sync, unit_tests, wipe)}, - ehfSignalsHandler{std::make_unique(chainman, mnhfman, *sigman, *shareman, *qman)} + mempool, mn_sync, unit_tests, wipe)} { // Have to start it early to let VerifyDB check ChainLock signatures in coinbase bls_worker->Start(); diff --git a/src/llmq/context.h b/src/llmq/context.h index b6586bb01186..d27b2a7a8137 100644 --- a/src/llmq/context.h +++ b/src/llmq/context.h @@ -24,7 +24,6 @@ namespace llmq { class CChainLocksHandler; class CDKGDebugManager; class CDKGSessionManager; -class CEHFSignalsHandler; class CInstantSendManager; class CQuorumBlockProcessor; class CQuorumManager; @@ -70,7 +69,6 @@ struct LLMQContext { const std::unique_ptr shareman; const std::unique_ptr clhandler; const std::unique_ptr isman; - const std::unique_ptr ehfSignalsHandler; }; #endif // BITCOIN_LLMQ_CONTEXT_H diff --git a/src/llmq/ehf_signals.cpp b/src/llmq/ehf_signals.cpp index 91eb293ace9c..7ed66e2c05c5 100644 --- a/src/llmq/ehf_signals.cpp +++ b/src/llmq/ehf_signals.cpp @@ -34,14 +34,10 @@ CEHFSignalsHandler::~CEHFSignalsHandler() sigman.UnregisterRecoveredSigsListener(this); } -void CEHFSignalsHandler::UpdatedBlockTip(const CBlockIndex* const pindexNew, bool is_masternode) +void CEHFSignalsHandler::UpdatedBlockTip(const CBlockIndex* const pindexNew) { if (!DeploymentActiveAfter(pindexNew, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) return; - if (!is_masternode) { - return; - } - const auto ehfSignals = mnhfman.GetSignalsStage(pindexNew); for (const auto& deployment : Params().GetConsensus().vDeployments) { // Skip deployments that do not use dip0023 diff --git a/src/llmq/ehf_signals.h b/src/llmq/ehf_signals.h index b8598fa4a2d0..33722d7a3dea 100644 --- a/src/llmq/ehf_signals.h +++ b/src/llmq/ehf_signals.h @@ -43,7 +43,7 @@ class CEHFSignalsHandler : public CRecoveredSigsListener /** * Since Tip is updated it could be a time to generate EHF Signal */ - void UpdatedBlockTip(const CBlockIndex* const pindexNew, bool is_masternode) EXCLUSIVE_LOCKS_REQUIRED(!cs); + void UpdatedBlockTip(const CBlockIndex* const pindexNew) EXCLUSIVE_LOCKS_REQUIRED(!cs); [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) override EXCLUSIVE_LOCKS_REQUIRED(!cs); diff --git a/src/masternode/active/context.cpp b/src/masternode/active/context.cpp index 97332bbb9f1b..3fdfa75bad39 100644 --- a/src/masternode/active/context.cpp +++ b/src/masternode/active/context.cpp @@ -10,11 +10,12 @@ #include #include #include +#include #include ActiveContext::ActiveContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, - CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, LLMQContext& llmq_ctx, - CSporkManager& sporkman, CTxMemPool& mempool, PeerManager& peerman, + CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, CMNHFManager& mnhfman, + LLMQContext& llmq_ctx, CSporkManager& sporkman, CTxMemPool& mempool, PeerManager& peerman, const CActiveMasternodeManager& mn_activeman, const CMasternodeSync& mn_sync) : m_llmq_ctx{llmq_ctx}, cl_signer{std::make_unique(chainman.ActiveChainstate(), *llmq_ctx.clhandler, @@ -23,7 +24,9 @@ ActiveContext::ActiveContext(ChainstateManager& chainman, CConnman& connman, CDe *llmq_ctx.isman, *llmq_ctx.sigman, *llmq_ctx.shareman, *llmq_ctx.qman, sporkman, mempool, mn_sync)}, cj_server{std::make_unique(chainman, connman, dmnman, dstxman, mn_metaman, mempool, peerman, - mn_activeman, mn_sync, *llmq_ctx.isman)} + mn_activeman, mn_sync, *llmq_ctx.isman)}, + ehf_sighandler{std::make_unique(chainman, mnhfman, *llmq_ctx.sigman, *llmq_ctx.shareman, + *llmq_ctx.qman)} { m_llmq_ctx.clhandler->ConnectSigner(cl_signer.get()); m_llmq_ctx.isman->ConnectSigner(is_signer.get()); diff --git a/src/masternode/active/context.h b/src/masternode/active/context.h index 8651b09e763a..7dd04a507b47 100644 --- a/src/masternode/active/context.h +++ b/src/masternode/active/context.h @@ -15,6 +15,7 @@ class CDeterministicMNManager; class CDSTXManager; class CMasternodeMetaMan; class CMasternodeSync; +class CMNHFManager; class CSporkManager; class CTxMemPool; class PeerManager; @@ -25,6 +26,9 @@ class ChainLockSigner; namespace instantsend { class InstantSendSigner; } // namespace instantsend +namespace llmq { +class CEHFSignalsHandler; +} // namespace llmq struct ActiveContext { private: @@ -41,9 +45,10 @@ struct ActiveContext { public: ActiveContext() = delete; ActiveContext(const ActiveContext&) = delete; - ActiveContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, CDSTXManager& dstxman, - CMasternodeMetaMan& mn_metaman, LLMQContext& llmq_ctx, CSporkManager& sporkman, CTxMemPool& mempool, - PeerManager& peerman, const CActiveMasternodeManager& mn_activeman, const CMasternodeSync& mn_sync); + ActiveContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, + CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, CMNHFManager& mnhfman, LLMQContext& llmq_ctx, + CSporkManager& sporkman, CTxMemPool& mempool, PeerManager& peerman, + const CActiveMasternodeManager& mn_activeman, const CMasternodeSync& mn_sync); ~ActiveContext(); /* @@ -52,6 +57,7 @@ struct ActiveContext { * TODO: Move CActiveMasternodeManager here when dependents have been migrated */ const std::unique_ptr cj_server; + const std::unique_ptr ehf_sighandler; }; #endif // BITCOIN_MASTERNODE_ACTIVE_CONTEXT_H diff --git a/src/masternode/active/notificationinterface.cpp b/src/masternode/active/notificationinterface.cpp index a785a0bc48bf..215458a9e9dd 100644 --- a/src/masternode/active/notificationinterface.cpp +++ b/src/masternode/active/notificationinterface.cpp @@ -4,9 +4,12 @@ #include +#include +#include #include -ActiveNotificationInterface::ActiveNotificationInterface(CActiveMasternodeManager& mn_activeman) : +ActiveNotificationInterface::ActiveNotificationInterface(ActiveContext& active_ctx, CActiveMasternodeManager& mn_activeman) : + m_active_ctx{active_ctx}, m_mn_activeman{mn_activeman} { } @@ -18,6 +21,7 @@ void ActiveNotificationInterface::UpdatedBlockTip(const CBlockIndex* pindexNew, return; m_mn_activeman.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); + m_active_ctx.ehf_sighandler->UpdatedBlockTip(pindexNew); } std::unique_ptr g_active_notification_interface; diff --git a/src/masternode/active/notificationinterface.h b/src/masternode/active/notificationinterface.h index f358f9441a4c..ecb3f9fa962c 100644 --- a/src/masternode/active/notificationinterface.h +++ b/src/masternode/active/notificationinterface.h @@ -8,13 +8,14 @@ #include class CActiveMasternodeManager; +struct ActiveContext; class ActiveNotificationInterface final : public CValidationInterface { public: ActiveNotificationInterface() = delete; ActiveNotificationInterface(const ActiveNotificationInterface&) = delete; - explicit ActiveNotificationInterface(CActiveMasternodeManager& mn_activeman); + explicit ActiveNotificationInterface(ActiveContext& active_ctx, CActiveMasternodeManager& mn_activeman); virtual ~ActiveNotificationInterface() = default; protected: @@ -22,6 +23,7 @@ class ActiveNotificationInterface final : public CValidationInterface void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override; private: + ActiveContext& m_active_ctx; CActiveMasternodeManager& m_mn_activeman; }; From f4ac71c9873c860f9a71b77bfbaee2a6c6e867cd Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 9 Sep 2025 14:24:04 +0000 Subject: [PATCH 9/9] lint: update circular dependencies allowlist, minor cleanup --- src/llmq/ehf_signals.cpp | 3 --- src/llmq/ehf_signals.h | 6 +----- test/lint/lint-circular-dependencies.py | 15 +++++++++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/llmq/ehf_signals.cpp b/src/llmq/ehf_signals.cpp index 7ed66e2c05c5..b4689e2d4a3e 100644 --- a/src/llmq/ehf_signals.cpp +++ b/src/llmq/ehf_signals.cpp @@ -15,8 +15,6 @@ #include namespace llmq { - - CEHFSignalsHandler::CEHFSignalsHandler(ChainstateManager& chainman, CMNHFManager& mnhfman, CSigningManager& sigman, CSigSharesManager& shareman, const CQuorumManager& qman) : m_chainman(chainman), @@ -28,7 +26,6 @@ CEHFSignalsHandler::CEHFSignalsHandler(ChainstateManager& chainman, CMNHFManager sigman.RegisterRecoveredSigsListener(this); } - CEHFSignalsHandler::~CEHFSignalsHandler() { sigman.UnregisterRecoveredSigsListener(this); diff --git a/src/llmq/ehf_signals.h b/src/llmq/ehf_signals.h index 33722d7a3dea..33283f6dbca8 100644 --- a/src/llmq/ehf_signals.h +++ b/src/llmq/ehf_signals.h @@ -13,8 +13,7 @@ class CBlockIndex; class ChainstateManager; class CMNHFManager; -namespace llmq -{ +namespace llmq { class CQuorumManager; class CSigSharesManager; class CSigningManager; @@ -39,7 +38,6 @@ class CEHFSignalsHandler : public CRecoveredSigsListener ~CEHFSignalsHandler(); - /** * Since Tip is updated it could be a time to generate EHF Signal */ @@ -50,9 +48,7 @@ class CEHFSignalsHandler : public CRecoveredSigsListener private: void trySignEHFSignal(int bit, const CBlockIndex* const pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs); - }; - } // namespace llmq #endif // BITCOIN_LLMQ_EHF_SIGNALS_H diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py index e1573c17d6d0..4934b002e1a9 100755 --- a/test/lint/lint-circular-dependencies.py +++ b/test/lint/lint-circular-dependencies.py @@ -26,35 +26,42 @@ "chainlock/chainlock -> instantsend/instantsend -> 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 -> validation -> chainlock/chainlock", "chainlock/chainlock -> validation -> evo/chainhelper -> chainlock/chainlock", + "chainlock/signing -> instantsend/instantsend -> net_processing -> masternode/active/context -> chainlock/signing", "coinjoin/client -> net_processing -> coinjoin/client", "coinjoin/client -> net_processing -> coinjoin/context -> coinjoin/client", - "coinjoin/context -> coinjoin/server -> net_processing -> coinjoin/context", + "coinjoin/coinjoin -> instantsend/instantsend -> net_processing -> coinjoin/context -> coinjoin/coinjoin", "coinjoin/server -> net_processing -> coinjoin/server", - "common/bloom -> evo/assetlocktx -> llmq/quorums -> net -> common/bloom", + "coinjoin/server -> net_processing -> masternode/active/context -> coinjoin/server", "common/bloom -> evo/assetlocktx -> llmq/commitment -> evo/deterministicmns -> evo/simplifiedmns -> merkleblock -> common/bloom", - "evo/assetlocktx -> llmq/commitment -> validation -> txmempool -> evo/assetlocktx", + "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", + "evo/assetlocktx -> llmq/commitment -> validation -> txmempool -> evo/assetlocktx", "evo/chainhelper -> evo/specialtxman -> validation -> evo/chainhelper", "evo/deterministicmns -> index/txindex -> validation -> evo/deterministicmns", "evo/deterministicmns -> index/txindex -> validation -> txmempool -> evo/deterministicmns", "evo/netinfo -> evo/providertx -> evo/netinfo", "evo/smldiff -> llmq/blockprocessor -> llmq/utils -> llmq/snapshot -> evo/smldiff", - "core_io -> evo/mnhftx -> llmq/signing -> net_processing -> evo/smldiff -> core_io", "evo/specialtxman -> validation -> evo/specialtxman", "governance/governance -> governance/object -> governance/governance", "governance/governance -> masternode/sync -> 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 -> txmempool -> instantsend/instantsend", + "instantsend/signing -> llmq/signing -> 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/signing_shares -> net_processing -> llmq/signing_shares",