From 9edd27bff028d99836293ef7934bf5b1984f7569 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:30:33 +0000 Subject: [PATCH 01/10] refactor: `llmq/instantsend.{cpp,h}` > `instantsend/instantsend.{cpp,h}` --- src/Makefile.am | 4 ++-- src/bench/rpc_blockchain.cpp | 2 +- src/coinjoin/coinjoin.cpp | 2 +- src/dsnotificationinterface.cpp | 3 +-- src/evo/chainhelper.cpp | 2 +- src/init.cpp | 2 +- src/{llmq => instantsend}/instantsend.cpp | 2 +- src/{llmq => instantsend}/instantsend.h | 6 +++--- src/llmq/chainlocks.cpp | 7 ++++--- src/llmq/context.cpp | 2 +- src/net_processing.cpp | 2 +- src/node/interfaces.cpp | 2 +- src/node/miner.cpp | 2 +- src/rest.cpp | 2 +- src/rpc/blockchain.cpp | 3 +-- src/rpc/mempool.cpp | 2 +- src/rpc/mining.cpp | 2 +- src/rpc/rawtransaction.cpp | 3 +-- src/test/evo_deterministicmns_tests.cpp | 2 +- src/test/evo_islock_tests.cpp | 2 +- src/test/fuzz/process_message.cpp | 2 +- src/test/miner_tests.cpp | 2 +- src/txmempool.cpp | 2 +- src/zmq/zmqpublishnotifier.cpp | 5 ++--- test/lint/lint-circular-dependencies.py | 11 ++++++----- test/util/data/non-backported.txt | 2 ++ 26 files changed, 39 insertions(+), 39 deletions(-) rename src/{llmq => instantsend}/instantsend.cpp (99%) rename src/{llmq => instantsend}/instantsend.h (99%) diff --git a/src/Makefile.am b/src/Makefile.am index 23ecb98e4786..a717f246c5e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -230,6 +230,7 @@ BITCOIN_CORE_H = \ interfaces/ipc.h \ interfaces/node.h \ interfaces/wallet.h \ + instantsend/instantsend.h \ key.h \ key_io.h \ limitedmap.h \ @@ -243,7 +244,6 @@ BITCOIN_CORE_H = \ llmq/dkgsessionhandler.h \ llmq/dkgsessionmgr.h \ llmq/ehf_signals.h \ - llmq/instantsend.h \ llmq/options.h \ llmq/params.h \ llmq/quorums.h \ @@ -488,6 +488,7 @@ libbitcoin_node_a_SOURCES = \ index/coinstatsindex.cpp \ index/txindex.cpp \ init.cpp \ + instantsend/instantsend.cpp \ llmq/blockprocessor.cpp \ llmq/chainlocks.cpp \ llmq/clsig.cpp \ @@ -498,7 +499,6 @@ libbitcoin_node_a_SOURCES = \ llmq/dkgsessionhandler.cpp \ llmq/dkgsessionmgr.cpp \ llmq/ehf_signals.cpp \ - llmq/instantsend.cpp \ llmq/options.cpp \ llmq/quorums.cpp \ llmq/signing.cpp \ diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp index 72e9f8bbbfb2..33fc11065d89 100644 --- a/src/bench/rpc_blockchain.cpp +++ b/src/bench/rpc_blockchain.cpp @@ -6,9 +6,9 @@ #include #include +#include #include #include -#include #include #include #include diff --git a/src/coinjoin/coinjoin.cpp b/src/coinjoin/coinjoin.cpp index fafdf4528755..698d53e71859 100644 --- a/src/coinjoin/coinjoin.cpp +++ b/src/coinjoin/coinjoin.cpp @@ -9,8 +9,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/dsnotificationinterface.cpp b/src/dsnotificationinterface.cpp index 7c8dfcfa771d..04c0a742b635 100644 --- a/src/dsnotificationinterface.cpp +++ b/src/dsnotificationinterface.cpp @@ -16,12 +16,11 @@ #include #include - +#include #include #include #include #include -#include #include CDSNotificationInterface::CDSNotificationInterface(CConnman& connman, diff --git a/src/evo/chainhelper.cpp b/src/evo/chainhelper.cpp index c58c942b535c..19c0e33d2bee 100644 --- a/src/evo/chainhelper.cpp +++ b/src/evo/chainhelper.cpp @@ -6,8 +6,8 @@ #include #include +#include #include -#include #include CChainstateHelper::CChainstateHelper(CCreditPoolManager& cpoolman, CDeterministicMNManager& dmnman, diff --git a/src/init.cpp b/src/init.cpp index 19f89b47c8db..5dab028704b1 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -87,11 +87,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include diff --git a/src/llmq/instantsend.cpp b/src/instantsend/instantsend.cpp similarity index 99% rename from src/llmq/instantsend.cpp rename to src/instantsend/instantsend.cpp index ff4ed81f2d1f..faea37c476ca 100644 --- a/src/llmq/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include +#include #include #include diff --git a/src/llmq/instantsend.h b/src/instantsend/instantsend.h similarity index 99% rename from src/llmq/instantsend.h rename to src/instantsend/instantsend.h index 6d2038087215..2c9399cc3860 100644 --- a/src/llmq/instantsend.h +++ b/src/instantsend/instantsend.h @@ -2,8 +2,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_LLMQ_INSTANTSEND_H -#define BITCOIN_LLMQ_INSTANTSEND_H +#ifndef BITCOIN_INSTANTSEND_INSTANTSEND_H +#define BITCOIN_INSTANTSEND_INSTANTSEND_H #include @@ -370,4 +370,4 @@ class CInstantSendManager : public CRecoveredSigsListener }; } // namespace llmq -#endif // BITCOIN_LLMQ_INSTANTSEND_H +#endif // BITCOIN_INSTANTSEND_INSTANTSEND_H diff --git a/src/llmq/chainlocks.cpp b/src/llmq/chainlocks.cpp index 7bef167fc638..43836b68378b 100644 --- a/src/llmq/chainlocks.cpp +++ b/src/llmq/chainlocks.cpp @@ -3,9 +3,6 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include -#include -#include -#include #include #include @@ -23,6 +20,10 @@ #include #include +#include +#include +#include + using node::ReadBlockFromDisk; // Forward declaration to break dependency over node/transaction.h diff --git a/src/llmq/context.cpp b/src/llmq/context.cpp index 303194291e6c..7b3d31a1fc77 100644 --- a/src/llmq/context.cpp +++ b/src/llmq/context.cpp @@ -7,13 +7,13 @@ #include #include +#include #include #include #include #include #include #include -#include #include #include #include diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 03a6d83a2117..4ea6b96ca494 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -62,13 +62,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include #include diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index df80facbf11f..b475c7fd5bee 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -20,9 +20,9 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 0d35e2cbd638..58c7693130e1 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -33,10 +33,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/src/rest.cpp b/src/rest.cpp index 39be8e6e3eb1..790b55af47ac 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -11,9 +11,9 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index c33dc4b42b38..dd08f585103b 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -54,9 +54,8 @@ #include #include #include - +#include #include -#include #include diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index c090221f0540..1e3d67c3ea70 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -16,8 +16,8 @@ #include #include +#include #include -#include using node::NodeContext; diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 30bbfa543f00..9367f5160c51 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -15,10 +15,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 3f6ec00219e2..e7079f24e1f4 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -50,10 +50,9 @@ #include #include - +#include #include #include -#include #include #include diff --git a/src/test/evo_deterministicmns_tests.cpp b/src/test/evo_deterministicmns_tests.cpp index d9c6f6df3bbd..01dbf27cf33c 100644 --- a/src/test/evo_deterministicmns_tests.cpp +++ b/src/test/evo_deterministicmns_tests.cpp @@ -23,8 +23,8 @@ #include #include #include +#include #include -#include #include diff --git a/src/test/evo_islock_tests.cpp b/src/test/evo_islock_tests.cpp index 6cfa8ff25e44..ca83dd631866 100644 --- a/src/test/evo_islock_tests.cpp +++ b/src/test/evo_islock_tests.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index 7830b2998218..9e9c1696192b 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -23,10 +23,10 @@ #include #include +#include #include #include #include -#include #include #include #include diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 8adf72e04514..6ef2a0189e0d 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -9,10 +9,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/src/txmempool.cpp b/src/txmempool.cpp index b5e270ca60ec..e90128f7df5a 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index c08c64f58e2b..7de85679e7ce 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -9,16 +9,15 @@ #include #include #include -#include #include #include - +#include #include -#include #include #include +#include #include #include diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py index 698d013bb068..c89eed880066 100755 --- a/test/lint/lint-circular-dependencies.py +++ b/test/lint/lint-circular-dependencies.py @@ -44,16 +44,17 @@ "governance/governance -> governance/object -> governance/governance", "governance/governance -> masternode/sync -> governance/governance", "governance/governance -> net_processing -> governance/governance", + "instantsend/instantsend -> llmq/chainlocks -> instantsend/instantsend", + "instantsend/instantsend -> net_processing -> instantsend/instantsend", + "instantsend/instantsend -> net_processing -> llmq/context -> instantsend/instantsend", + "instantsend/instantsend -> txmempool -> instantsend/instantsend", "llmq/blockprocessor -> llmq/utils -> llmq/snapshot -> llmq/blockprocessor", - "llmq/chainlocks -> llmq/instantsend -> llmq/chainlocks", - "llmq/chainlocks -> llmq/instantsend -> net_processing -> llmq/chainlocks", "llmq/chainlocks -> validation -> llmq/chainlocks", "llmq/commitment -> llmq/utils -> llmq/snapshot -> llmq/commitment", - "llmq/context -> llmq/instantsend -> net_processing -> llmq/context", + "llmq/chainlocks -> llmq/signing -> net_processing -> llmq/chainlocks", + "llmq/context -> llmq/signing -> net_processing -> llmq/context", "llmq/dkgsession -> llmq/dkgsessionmgr -> llmq/dkgsessionhandler -> llmq/dkgsession", "llmq/dkgsessionhandler -> net_processing -> llmq/dkgsessionmgr -> llmq/dkgsessionhandler", - "llmq/instantsend -> net_processing -> llmq/instantsend", - "llmq/instantsend -> txmempool -> llmq/instantsend", "llmq/signing -> llmq/signing_shares -> llmq/signing", "llmq/signing -> net_processing -> llmq/signing", "llmq/signing_shares -> net_processing -> llmq/signing_shares", diff --git a/test/util/data/non-backported.txt b/test/util/data/non-backported.txt index d7567f67035d..05fc3f1cd774 100644 --- a/test/util/data/non-backported.txt +++ b/test/util/data/non-backported.txt @@ -14,6 +14,8 @@ src/evo/*.cpp src/evo/*.h src/governance/*.cpp src/governance/*.h +src/instantsend/*.cpp +src/instantsend/*.h src/llmq/*.cpp src/llmq/*.h src/masternode/*.cpp From ac8dcddd594c62e0187b79a4748a192b6ef24d64 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:51:23 +0000 Subject: [PATCH 02/10] refactor: move `CInstantSendManager` constructor to source file --- src/instantsend/instantsend.cpp | 20 ++++++++++++++++++++ src/instantsend/instantsend.h | 17 ++--------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index faea37c476ca..3f702bd28301 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -440,6 +440,26 @@ std::vector CInstantSendDb::RemoveChainedInstantSendLocks(const uint256 //////////////// +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) : + db{unitTests, fWipe}, + clhandler{_clhandler}, + m_chainstate{chainstate}, + qman{_qman}, + sigman{_sigman}, + shareman{_shareman}, + spork_manager{sporkman}, + mempool{_mempool}, + m_mn_sync{mn_sync}, + m_is_masternode{is_masternode} +{ + workInterrupt.reset(); +} + +CInstantSendManager::~CInstantSendManager() = default; + void CInstantSendManager::Start(PeerManager& peerman) { // can't start new thread if we have one running already diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index 2c9399cc3860..d9e5099fc989 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -259,21 +259,8 @@ class CInstantSendManager : public CRecoveredSigsListener 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) : - db(unitTests, fWipe), - clhandler(_clhandler), - m_chainstate(chainstate), - qman(_qman), - sigman(_sigman), - shareman(_shareman), - spork_manager(sporkman), - mempool(_mempool), - m_mn_sync(mn_sync), - m_is_masternode{is_masternode} - { - workInterrupt.reset(); - } - ~CInstantSendManager() = default; + bool unitTests, bool fWipe); + ~CInstantSendManager(); void Start(PeerManager& peerman); void Stop(); From 5e704569f090fd2fc58d8b57edfb0f80ab1137d5 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Jul 2025 15:24:46 +0000 Subject: [PATCH 03/10] refactor: move `CInstantSendLock` definition to `instantsend/lock.{cpp,h}` Review with `git log -p -n1 --color-moved=dimmed_zebra`. --- src/Makefile.am | 2 ++ src/evo/chainhelper.cpp | 1 + src/instantsend/instantsend.cpp | 51 +++++++-------------------------- src/instantsend/instantsend.h | 28 +----------------- src/instantsend/lock.cpp | 44 ++++++++++++++++++++++++++++ src/instantsend/lock.h | 46 +++++++++++++++++++++++++++++ src/llmq/context.h | 2 +- src/net_processing.cpp | 1 + src/rpc/rawtransaction.cpp | 1 + src/test/evo_islock_tests.cpp | 12 ++++---- src/zmq/zmqpublishnotifier.cpp | 2 +- 11 files changed, 115 insertions(+), 75 deletions(-) create mode 100644 src/instantsend/lock.cpp create mode 100644 src/instantsend/lock.h diff --git a/src/Makefile.am b/src/Makefile.am index a717f246c5e7..89e0fa59bf44 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -231,6 +231,7 @@ BITCOIN_CORE_H = \ interfaces/node.h \ interfaces/wallet.h \ instantsend/instantsend.h \ + instantsend/lock.h \ key.h \ key_io.h \ limitedmap.h \ @@ -489,6 +490,7 @@ libbitcoin_node_a_SOURCES = \ index/txindex.cpp \ init.cpp \ instantsend/instantsend.cpp \ + instantsend/lock.cpp \ llmq/blockprocessor.cpp \ llmq/chainlocks.cpp \ llmq/clsig.cpp \ diff --git a/src/evo/chainhelper.cpp b/src/evo/chainhelper.cpp index 19c0e33d2bee..4014bb79335c 100644 --- a/src/evo/chainhelper.cpp +++ b/src/evo/chainhelper.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 3f702bd28301..b5a86fef6219 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -4,20 +4,12 @@ #include -#include -#include -#include -#include - -#include #include #include #include #include -#include #include #include -#include #include #include #include @@ -25,6 +17,15 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include + #include using node::fImporting; @@ -38,11 +39,8 @@ CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMe } // namespace node using node::GetTransaction; -namespace llmq -{ - +namespace llmq { static const std::string_view INPUTLOCK_REQUESTID_PREFIX = "inlock"; -static const std::string_view ISLOCK_REQUESTID_PREFIX = "islock"; static const std::string_view DB_ISLOCK_BY_HASH = "is_i"; static const std::string_view DB_HASH_BY_TXID = "is_tx"; @@ -53,14 +51,6 @@ static const std::string_view DB_ARCHIVED_BY_HASH = "is_a2"; static const std::string_view DB_VERSION = "is_v"; -uint256 CInstantSendLock::GetRequestId() const -{ - CHashWriter hw(SER_GETHASH, 0); - hw << ISLOCK_REQUESTID_PREFIX; - hw << inputs; - return hw.GetHash(); -} - //////////////// @@ -838,27 +828,6 @@ PeerMsgRet CInstantSendManager::ProcessMessageInstantSendLock(const CNode& pfrom return {}; } -/** - * Handles trivial ISLock verification - * @return returns false if verification failed, otherwise true - */ -bool CInstantSendLock::TriviallyValid() const -{ - if (txid.IsNull() || inputs.empty()) { - return false; - } - - // Check that each input is unique - std::set dups; - for (const auto& o : inputs) { - if (!dups.emplace(o).second) { - return false; - } - } - - return true; -} - bool CInstantSendManager::ProcessPendingInstantSendLocks(PeerManager& peerman) { decltype(pendingInstantSendLocks) pend; diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index d9e5099fc989..2dbc39c0757e 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -35,33 +36,6 @@ class CQuorumManager; class CSigningManager; class CSigSharesManager; -struct CInstantSendLock -{ - static constexpr uint8_t CURRENT_VERSION{1}; - - uint8_t nVersion{CURRENT_VERSION}; - std::vector inputs; - uint256 txid; - uint256 cycleHash; - CBLSLazySignature sig; - - CInstantSendLock() = default; - - SERIALIZE_METHODS(CInstantSendLock, obj) - { - READWRITE(obj.nVersion); - READWRITE(obj.inputs); - READWRITE(obj.txid); - READWRITE(obj.cycleHash); - READWRITE(obj.sig); - } - - uint256 GetRequestId() const; - bool TriviallyValid() const; -}; - -using CInstantSendLockPtr = std::shared_ptr; - class CInstantSendDb { private: diff --git a/src/instantsend/lock.cpp b/src/instantsend/lock.cpp new file mode 100644 index 000000000000..c94b8b8273a5 --- /dev/null +++ b/src/instantsend/lock.cpp @@ -0,0 +1,44 @@ +// Copyright (c) 2019-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +#include +#include + +static const std::string_view ISLOCK_REQUESTID_PREFIX = "islock"; + +namespace llmq { +uint256 CInstantSendLock::GetRequestId() const +{ + CHashWriter hw(SER_GETHASH, 0); + hw << ISLOCK_REQUESTID_PREFIX; + hw << inputs; + return hw.GetHash(); +} + +/** + * Handles trivial ISLock verification + * @return returns false if verification failed, otherwise true + */ +bool CInstantSendLock::TriviallyValid() const +{ + if (txid.IsNull() || inputs.empty()) { + return false; + } + + // Check that each input is unique + std::set dups; + for (const auto& o : inputs) { + if (!dups.emplace(o).second) { + return false; + } + } + + return true; +} +} // namespace llmq diff --git a/src/instantsend/lock.h b/src/instantsend/lock.h new file mode 100644 index 000000000000..fddd0bcde3de --- /dev/null +++ b/src/instantsend/lock.h @@ -0,0 +1,46 @@ +// Copyright (c) 2019-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_INSTANTSEND_LOCK_H +#define BITCOIN_INSTANTSEND_LOCK_H + +#include +#include +#include + +#include +#include +#include + +class COutPoint; + +namespace llmq { +struct CInstantSendLock { + static constexpr uint8_t CURRENT_VERSION{1}; + + uint8_t nVersion{CURRENT_VERSION}; + std::vector inputs; + uint256 txid; + uint256 cycleHash; + CBLSLazySignature sig; + + CInstantSendLock() = default; + + SERIALIZE_METHODS(CInstantSendLock, obj) + { + READWRITE(obj.nVersion); + READWRITE(obj.inputs); + READWRITE(obj.txid); + READWRITE(obj.cycleHash); + READWRITE(obj.sig); + } + + uint256 GetRequestId() const; + bool TriviallyValid() const; +}; + +using CInstantSendLockPtr = std::shared_ptr; +} // namespace llmq + +#endif // BITCOIN_INSTANTSEND_LOCK_H diff --git a/src/llmq/context.h b/src/llmq/context.h index 1f6dba27916e..b6586bb01186 100644 --- a/src/llmq/context.h +++ b/src/llmq/context.h @@ -69,7 +69,7 @@ struct LLMQContext { const std::unique_ptr sigman; const std::unique_ptr shareman; const std::unique_ptr clhandler; - const std::unique_ptr isman; // TODO: split CInstantSendManager and CInstantSendLock to 2 files + const std::unique_ptr isman; const std::unique_ptr ehfSignalsHandler; }; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 4ea6b96ca494..b1f8def7b296 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index e7079f24e1f4..6c403e6f459b 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -50,6 +50,7 @@ #include #include +#include #include #include #include diff --git a/src/test/evo_islock_tests.cpp b/src/test/evo_islock_tests.cpp index ca83dd631866..42d50c0ee31b 100644 --- a/src/test/evo_islock_tests.cpp +++ b/src/test/evo_islock_tests.cpp @@ -1,14 +1,16 @@ -#include +#include #include -#include +#include +#include #include #include -#include #include - -// For constructing dummy outpoints using uint256S. #include +#include + +#include + BOOST_AUTO_TEST_SUITE(evo_islock_tests) uint256 CalculateRequestId(const std::vector& inputs) diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index 7de85679e7ce..230c6db71a75 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include From 82dded4530d3043402e9ce48e4ddb3db50370765 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Jul 2025 15:09:16 +0000 Subject: [PATCH 04/10] refactor: move `CInstantSendDb` definition to `instantsend/db.{cpp,h}` Also, since CInstantSendDb is used only by CInstantSendManager, we can move it to the instantsend namespace easier. Review with `git log -p -n1 --color-moved=dimmed_zebra`. --- src/Makefile.am | 2 + src/instantsend/db.cpp | 395 ++++++++++++++++++++++++++++++++ src/instantsend/db.h | 161 +++++++++++++ src/instantsend/instantsend.cpp | 388 ------------------------------- src/instantsend/instantsend.h | 134 +---------- 5 files changed, 560 insertions(+), 520 deletions(-) create mode 100644 src/instantsend/db.cpp create mode 100644 src/instantsend/db.h diff --git a/src/Makefile.am b/src/Makefile.am index 89e0fa59bf44..e76b53f1c23e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -230,6 +230,7 @@ BITCOIN_CORE_H = \ interfaces/ipc.h \ interfaces/node.h \ interfaces/wallet.h \ + instantsend/db.h \ instantsend/instantsend.h \ instantsend/lock.h \ key.h \ @@ -489,6 +490,7 @@ libbitcoin_node_a_SOURCES = \ index/coinstatsindex.cpp \ index/txindex.cpp \ init.cpp \ + instantsend/db.cpp \ instantsend/instantsend.cpp \ instantsend/lock.cpp \ llmq/blockprocessor.cpp \ diff --git a/src/instantsend/db.cpp b/src/instantsend/db.cpp new file mode 100644 index 000000000000..ac06ee934b24 --- /dev/null +++ b/src/instantsend/db.cpp @@ -0,0 +1,395 @@ +// Copyright (c) 2019-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include + +static const std::string_view DB_ARCHIVED_BY_HASH = "is_a2"; +static const std::string_view DB_ARCHIVED_BY_HEIGHT_AND_HASH = "is_a1"; +static const std::string_view DB_HASH_BY_OUTPOINT = "is_in"; +static const std::string_view DB_HASH_BY_TXID = "is_tx"; +static const std::string_view DB_ISLOCK_BY_HASH = "is_i"; +static const std::string_view DB_MINED_BY_HEIGHT_AND_HASH = "is_m"; +static const std::string_view DB_VERSION = "is_v"; + +namespace instantsend { +namespace { +static std::tuple BuildInversedISLockKey(std::string_view k, int nHeight, const uint256& islockHash) +{ + return std::make_tuple(std::string{k}, htobe32_internal(std::numeric_limits::max() - nHeight), islockHash); +} +} // anonymous namespace + +CInstantSendDb::CInstantSendDb(bool unitTests, bool fWipe) : + db(std::make_unique(unitTests ? "" : (gArgs.GetDataDirNet() / "llmq/isdb"), 32 << 20, unitTests, fWipe)) +{ + Upgrade(unitTests); +} + +CInstantSendDb::~CInstantSendDb() = default; + +void CInstantSendDb::Upgrade(bool unitTests) +{ + LOCK(cs_db); + int v{0}; + if (!db->Read(DB_VERSION, v) || v < CInstantSendDb::CURRENT_VERSION) { + // Wipe db + db.reset(); + db = std::make_unique(unitTests ? "" : (gArgs.GetDataDirNet() / "llmq/isdb"), 32 << 20, unitTests, + /*fWipe=*/true); + CDBBatch batch(*db); + batch.Write(DB_VERSION, CInstantSendDb::CURRENT_VERSION); + // Sync DB changes to disk + db->WriteBatch(batch, /*fSync=*/true); + batch.Clear(); + } +} + +void CInstantSendDb::WriteNewInstantSendLock(const uint256& hash, const llmq::CInstantSendLock& islock) +{ + LOCK(cs_db); + CDBBatch batch(*db); + batch.Write(std::make_tuple(DB_ISLOCK_BY_HASH, hash), islock); + batch.Write(std::make_tuple(DB_HASH_BY_TXID, islock.txid), hash); + for (const auto& in : islock.inputs) { + batch.Write(std::make_tuple(DB_HASH_BY_OUTPOINT, in), hash); + } + db->WriteBatch(batch); + + islockCache.insert(hash, std::make_shared(islock)); + txidCache.insert(islock.txid, hash); + for (const auto& in : islock.inputs) { + outpointCache.insert(in, hash); + } +} + +void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, llmq::CInstantSendLockPtr islock, bool keep_cache) +{ + AssertLockHeld(cs_db); + if (!islock) { + islock = GetInstantSendLockByHashInternal(hash, false); + if (!islock) { + return; + } + } + + batch.Erase(std::make_tuple(DB_ISLOCK_BY_HASH, hash)); + batch.Erase(std::make_tuple(DB_HASH_BY_TXID, islock->txid)); + for (auto& in : islock->inputs) { + batch.Erase(std::make_tuple(DB_HASH_BY_OUTPOINT, in)); + } + + if (!keep_cache) { + islockCache.erase(hash); + txidCache.erase(islock->txid); + for (const auto& in : islock->inputs) { + outpointCache.erase(in); + } + } +} + +void CInstantSendDb::WriteInstantSendLockMined(const uint256& hash, int nHeight) +{ + LOCK(cs_db); + CDBBatch batch(*db); + WriteInstantSendLockMined(batch, hash, nHeight); + db->WriteBatch(batch); +} + +void CInstantSendDb::WriteInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight) +{ + AssertLockHeld(cs_db); + batch.Write(BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nHeight, hash), true); +} + +void CInstantSendDb::RemoveInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight) +{ + AssertLockHeld(cs_db); + batch.Erase(BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nHeight, hash)); +} + +void CInstantSendDb::WriteInstantSendLockArchived(CDBBatch& batch, const uint256& hash, int nHeight) +{ + AssertLockHeld(cs_db); + batch.Write(BuildInversedISLockKey(DB_ARCHIVED_BY_HEIGHT_AND_HASH, nHeight, hash), true); + batch.Write(std::make_tuple(DB_ARCHIVED_BY_HASH, hash), true); +} + +std::unordered_map CInstantSendDb::RemoveConfirmedInstantSendLocks(int nUntilHeight) +{ + LOCK(cs_db); + if (nUntilHeight <= best_confirmed_height) { + LogPrint(BCLog::ALL, "CInstantSendDb::%s -- Attempting to confirm height %d, however we've already confirmed height %d. This should never happen.\n", __func__, + nUntilHeight, best_confirmed_height); + return {}; + } + best_confirmed_height = nUntilHeight; + + auto it = std::unique_ptr(db->NewIterator()); + + auto firstKey = BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nUntilHeight, uint256()); + + it->Seek(firstKey); + + CDBBatch batch(*db); + std::unordered_map ret; + while (it->Valid()) { + decltype(firstKey) curKey; + if (!it->GetKey(curKey) || std::get<0>(curKey) != DB_MINED_BY_HEIGHT_AND_HASH) { + break; + } + uint32_t nHeight = std::numeric_limits::max() - be32toh_internal(std::get<1>(curKey)); + if (nHeight > uint32_t(nUntilHeight)) { + break; + } + + auto& islockHash = std::get<2>(curKey); + + if (auto islock = GetInstantSendLockByHashInternal(islockHash, false)) { + RemoveInstantSendLock(batch, islockHash, islock); + ret.try_emplace(islockHash, std::move(islock)); + } + + // archive the islock hash, so that we're still able to check if we've seen the islock in the past + WriteInstantSendLockArchived(batch, islockHash, nHeight); + + batch.Erase(curKey); + + it->Next(); + } + + db->WriteBatch(batch); + + return ret; +} + +void CInstantSendDb::RemoveArchivedInstantSendLocks(int nUntilHeight) +{ + LOCK(cs_db); + if (nUntilHeight <= 0) { + return; + } + + auto it = std::unique_ptr(db->NewIterator()); + + auto firstKey = BuildInversedISLockKey(DB_ARCHIVED_BY_HEIGHT_AND_HASH, nUntilHeight, uint256()); + + it->Seek(firstKey); + + CDBBatch batch(*db); + while (it->Valid()) { + decltype(firstKey) curKey; + if (!it->GetKey(curKey) || std::get<0>(curKey) != DB_ARCHIVED_BY_HEIGHT_AND_HASH) { + break; + } + uint32_t nHeight = std::numeric_limits::max() - be32toh_internal(std::get<1>(curKey)); + if (nHeight > uint32_t(nUntilHeight)) { + break; + } + + auto& islockHash = std::get<2>(curKey); + batch.Erase(std::make_tuple(DB_ARCHIVED_BY_HASH, islockHash)); + batch.Erase(curKey); + + it->Next(); + } + + db->WriteBatch(batch); +} + +void CInstantSendDb::WriteBlockInstantSendLocks(const gsl::not_null>& pblock, + gsl::not_null pindexConnected) +{ + LOCK(cs_db); + CDBBatch batch(*db); + for (const auto& tx : pblock->vtx) { + if (tx->IsCoinBase() || tx->vin.empty()) { + // coinbase and TXs with no inputs can't be locked + continue; + } + uint256 islockHash = GetInstantSendLockHashByTxidInternal(tx->GetHash()); + // update DB about when an IS lock was mined + if (!islockHash.IsNull()) { + WriteInstantSendLockMined(batch, islockHash, pindexConnected->nHeight); + } + } + db->WriteBatch(batch); +} + +void CInstantSendDb::RemoveBlockInstantSendLocks(const gsl::not_null>& pblock, gsl::not_null pindexDisconnected) +{ + LOCK(cs_db); + CDBBatch batch(*db); + for (const auto& tx : pblock->vtx) { + if (tx->IsCoinBase() || tx->vin.empty()) { + // coinbase and TXs with no inputs can't be locked + continue; + } + uint256 islockHash = GetInstantSendLockHashByTxidInternal(tx->GetHash()); + if (!islockHash.IsNull()) { + RemoveInstantSendLockMined(batch, islockHash, pindexDisconnected->nHeight); + } + } + db->WriteBatch(batch); +} + +bool CInstantSendDb::KnownInstantSendLock(const uint256& islockHash) const +{ + LOCK(cs_db); + return GetInstantSendLockByHashInternal(islockHash) != nullptr || db->Exists(std::make_tuple(DB_ARCHIVED_BY_HASH, islockHash)); +} + +size_t CInstantSendDb::GetInstantSendLockCount() const +{ + LOCK(cs_db); + auto it = std::unique_ptr(db->NewIterator()); + auto firstKey = std::make_tuple(std::string{DB_ISLOCK_BY_HASH}, uint256()); + + it->Seek(firstKey); + + size_t cnt = 0; + while (it->Valid()) { + decltype(firstKey) curKey; + if (!it->GetKey(curKey) || std::get<0>(curKey) != DB_ISLOCK_BY_HASH) { + break; + } + + cnt++; + + it->Next(); + } + + return cnt; +} + +llmq::CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByHashInternal(const uint256& hash, bool use_cache) const +{ + AssertLockHeld(cs_db); + if (hash.IsNull()) { + return nullptr; + } + + llmq::CInstantSendLockPtr ret; + if (use_cache && islockCache.get(hash, ret)) { + return ret; + } + + ret = std::make_shared(); + bool exists = db->Read(std::make_tuple(DB_ISLOCK_BY_HASH, hash), *ret); + if (!exists || (::SerializeHash(*ret) != hash)) { + ret = std::make_shared(); + exists = db->Read(std::make_tuple(DB_ISLOCK_BY_HASH, hash), *ret); + if (!exists || (::SerializeHash(*ret) != hash)) { + ret = nullptr; + } + } + islockCache.insert(hash, ret); + return ret; +} + +uint256 CInstantSendDb::GetInstantSendLockHashByTxidInternal(const uint256& txid) const +{ + AssertLockHeld(cs_db); + uint256 islockHash; + if (!txidCache.get(txid, islockHash)) { + if (!db->Read(std::make_tuple(DB_HASH_BY_TXID, txid), islockHash)) { + return {}; + } + txidCache.insert(txid, islockHash); + } + return islockHash; +} + +llmq::CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByTxid(const uint256& txid) const +{ + LOCK(cs_db); + return GetInstantSendLockByHashInternal(GetInstantSendLockHashByTxidInternal(txid)); +} + +llmq::CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByInput(const COutPoint& outpoint) const +{ + LOCK(cs_db); + uint256 islockHash; + if (!outpointCache.get(outpoint, islockHash)) { + if (!db->Read(std::make_tuple(DB_HASH_BY_OUTPOINT, outpoint), islockHash)) { + return nullptr; + } + outpointCache.insert(outpoint, islockHash); + } + return GetInstantSendLockByHashInternal(islockHash); +} + +std::vector CInstantSendDb::GetInstantSendLocksByParent(const uint256& parent) const +{ + AssertLockHeld(cs_db); + auto it = std::unique_ptr(db->NewIterator()); + auto firstKey = std::make_tuple(std::string{DB_HASH_BY_OUTPOINT}, COutPoint(parent, 0)); + it->Seek(firstKey); + + std::vector result; + + while (it->Valid()) { + decltype(firstKey) curKey; + if (!it->GetKey(curKey) || std::get<0>(curKey) != DB_HASH_BY_OUTPOINT) { + break; + } + const auto& outpoint = std::get<1>(curKey); + if (outpoint.hash != parent) { + break; + } + + uint256 islockHash; + if (!it->GetValue(islockHash)) { + break; + } + result.emplace_back(islockHash); + it->Next(); + } + + return result; +} + +std::vector CInstantSendDb::RemoveChainedInstantSendLocks(const uint256& islockHash, const uint256& txid, int nHeight) +{ + LOCK(cs_db); + std::vector result; + + std::vector stack; + std::unordered_set added; + stack.emplace_back(txid); + + CDBBatch batch(*db); + while (!stack.empty()) { + auto children = GetInstantSendLocksByParent(stack.back()); + stack.pop_back(); + + for (auto& childIslockHash : children) { + auto childIsLock = GetInstantSendLockByHashInternal(childIslockHash, false); + if (!childIsLock) { + continue; + } + + RemoveInstantSendLock(batch, childIslockHash, childIsLock, false); + WriteInstantSendLockArchived(batch, childIslockHash, nHeight); + result.emplace_back(childIslockHash); + + if (added.emplace(childIsLock->txid).second) { + stack.emplace_back(childIsLock->txid); + } + } + } + + RemoveInstantSendLock(batch, islockHash, nullptr, false); + WriteInstantSendLockArchived(batch, islockHash, nHeight); + result.emplace_back(islockHash); + + db->WriteBatch(batch); + + return result; +} +} // namespace instantsend diff --git a/src/instantsend/db.h b/src/instantsend/db.h new file mode 100644 index 000000000000..26f90a25c19a --- /dev/null +++ b/src/instantsend/db.h @@ -0,0 +1,161 @@ +// Copyright (c) 2019-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_INSTANTSEND_DB_H +#define BITCOIN_INSTANTSEND_DB_H + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +class CBlock; +class CBlockIndex; +class CDBBatch; +class CDBWrapper; +class COutPoint; + +namespace instantsend { +class CInstantSendDb +{ +private: + mutable Mutex cs_db; + + static constexpr int CURRENT_VERSION{1}; + + int best_confirmed_height GUARDED_BY(cs_db) {0}; + + std::unique_ptr db GUARDED_BY(cs_db) {nullptr}; + mutable unordered_lru_cache islockCache GUARDED_BY(cs_db); + mutable unordered_lru_cache txidCache GUARDED_BY(cs_db); + + mutable unordered_lru_cache outpointCache GUARDED_BY(cs_db); + void WriteInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_db); + + void RemoveInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_db); + + /** + * This method removes a InstantSend Lock from the database and is called when a tx with an IS lock is confirmed and Chainlocked + * @param batch Object used to batch many calls together + * @param hash The hash of the InstantSend Lock + * @param islock The InstantSend Lock object itself + * @param keep_cache Should we still keep corresponding entries in the cache or not + */ + void RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, llmq::CInstantSendLockPtr islock, bool keep_cache = true) EXCLUSIVE_LOCKS_REQUIRED(cs_db); + /** + * Marks an InstantSend Lock as archived. + * @param batch Object used to batch many calls together + * @param hash The hash of the InstantSend Lock + * @param nHeight The height that the transaction was included at + */ + void WriteInstantSendLockArchived(CDBBatch& batch, const uint256& hash, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_db); + /** + * Gets a vector of IS Lock hashes of the IS Locks which rely on or are children of the parent IS Lock + * @param parent The hash of the parent IS Lock + * @return Returns a vector of IS Lock hashes + */ + std::vector GetInstantSendLocksByParent(const uint256& parent) const EXCLUSIVE_LOCKS_REQUIRED(cs_db); + + /** + * See GetInstantSendLockByHash + */ + llmq::CInstantSendLockPtr GetInstantSendLockByHashInternal(const uint256& hash, bool use_cache = true) const EXCLUSIVE_LOCKS_REQUIRED(cs_db); + + /** + * See GetInstantSendLockHashByTxid + */ + uint256 GetInstantSendLockHashByTxidInternal(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_db); + + + void Upgrade(bool unitTests) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + +public: + explicit CInstantSendDb(bool unitTests, bool fWipe); + ~CInstantSendDb(); + + /** + * This method is called when an InstantSend Lock is processed and adds the lock to the database + * @param hash The hash of the InstantSend Lock + * @param islock The InstantSend Lock object itself + */ + void WriteNewInstantSendLock(const uint256& hash, const llmq::CInstantSendLock& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + /** + * This method updates a DB entry for an InstantSend Lock from being not included in a block to being included in a block + * @param hash The hash of the InstantSend Lock + * @param nHeight The height that the transaction was included at + */ + void WriteInstantSendLockMined(const uint256& hash, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + /** + * Archives and deletes all IS Locks which were mined into a block before nUntilHeight + * @param nUntilHeight Removes all IS Locks confirmed up until nUntilHeight + * @return returns an unordered_map of the hash of the IS Locks and a pointer object to the IS Locks for all IS Locks which were removed + */ + std::unordered_map RemoveConfirmedInstantSendLocks(int nUntilHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + /** + * Removes IS Locks from the archive if the tx was confirmed 100 blocks before nUntilHeight + * @param nUntilHeight the height from which to base the remove of archive IS Locks + */ + void RemoveArchivedInstantSendLocks(int nUntilHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + void WriteBlockInstantSendLocks(const gsl::not_null>& pblock, gsl::not_null pindexConnected) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + void RemoveBlockInstantSendLocks(const gsl::not_null>& pblock, gsl::not_null pindexDisconnected) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + bool KnownInstantSendLock(const uint256& islockHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + /** + * Gets the number of IS Locks which have not been confirmed by a block + * @return size_t value of the number of IS Locks not confirmed by a block + */ + size_t GetInstantSendLockCount() const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + /** + * Gets a pointer to the IS Lock based on the hash + * @param hash The hash of the IS Lock + * @param use_cache Should we try using the cache first or not + * @return A Pointer object to the IS Lock, returns nullptr if it doesn't exist + */ + llmq::CInstantSendLockPtr GetInstantSendLockByHash(const uint256& hash, bool use_cache = true) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db) + { + LOCK(cs_db); + return GetInstantSendLockByHashInternal(hash, use_cache); + }; + /** + * Gets an IS Lock hash based on the txid the IS Lock is for + * @param txid The txid which is being searched for + * @return Returns the hash the IS Lock of the specified txid, returns uint256() if it doesn't exist + */ + uint256 GetInstantSendLockHashByTxid(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db) + { + LOCK(cs_db); + return GetInstantSendLockHashByTxidInternal(txid); + }; + /** + * Gets an IS Lock pointer from the txid given + * @param txid The txid for which the IS Lock Pointer is being returned + * @return Returns the IS Lock Pointer associated with the txid, returns nullptr if it doesn't exist + */ + llmq::CInstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + /** + * Gets an IS Lock pointer from an input given + * @param outpoint Since all inputs are really just outpoints that are being spent + * @return IS Lock Pointer associated with that input. + */ + llmq::CInstantSendLockPtr GetInstantSendLockByInput(const COutPoint& outpoint) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + /** + * Called when a ChainLock invalidated a IS Lock, removes any chained/children IS Locks and the invalidated IS Lock + * @param islockHash IS Lock hash which has been invalidated + * @param txid Transaction id associated with the islockHash + * @param nHeight height of the block which received a chainlock and invalidated the IS Lock + * @return A vector of IS Lock hashes of all IS Locks removed + */ + std::vector RemoveChainedInstantSendLocks(const uint256& islockHash, const uint256& txid, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); +}; +} // namespace instantsend + +#endif // BITCOIN_INSTANTSEND_DB_H diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index b5a86fef6219..411edb928c51 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -42,394 +42,6 @@ using node::GetTransaction; namespace llmq { static const std::string_view INPUTLOCK_REQUESTID_PREFIX = "inlock"; -static const std::string_view DB_ISLOCK_BY_HASH = "is_i"; -static const std::string_view DB_HASH_BY_TXID = "is_tx"; -static const std::string_view DB_HASH_BY_OUTPOINT = "is_in"; -static const std::string_view DB_MINED_BY_HEIGHT_AND_HASH = "is_m"; -static const std::string_view DB_ARCHIVED_BY_HEIGHT_AND_HASH = "is_a1"; -static const std::string_view DB_ARCHIVED_BY_HASH = "is_a2"; - -static const std::string_view DB_VERSION = "is_v"; - -//////////////// - - -CInstantSendDb::CInstantSendDb(bool unitTests, bool fWipe) : - db(std::make_unique(unitTests ? "" : (gArgs.GetDataDirNet() / "llmq/isdb"), 32 << 20, unitTests, fWipe)) -{ - Upgrade(unitTests); -} - -CInstantSendDb::~CInstantSendDb() = default; - -void CInstantSendDb::Upgrade(bool unitTests) -{ - LOCK(cs_db); - int v{0}; - if (!db->Read(DB_VERSION, v) || v < CInstantSendDb::CURRENT_VERSION) { - // Wipe db - db.reset(); - db = std::make_unique(unitTests ? "" : (gArgs.GetDataDirNet() / "llmq/isdb"), 32 << 20, unitTests, - /*fWipe=*/true); - CDBBatch batch(*db); - batch.Write(DB_VERSION, CInstantSendDb::CURRENT_VERSION); - // Sync DB changes to disk - db->WriteBatch(batch, /*fSync=*/true); - batch.Clear(); - } -} - -void CInstantSendDb::WriteNewInstantSendLock(const uint256& hash, const CInstantSendLock& islock) -{ - LOCK(cs_db); - CDBBatch batch(*db); - batch.Write(std::make_tuple(DB_ISLOCK_BY_HASH, hash), islock); - batch.Write(std::make_tuple(DB_HASH_BY_TXID, islock.txid), hash); - for (const auto& in : islock.inputs) { - batch.Write(std::make_tuple(DB_HASH_BY_OUTPOINT, in), hash); - } - db->WriteBatch(batch); - - islockCache.insert(hash, std::make_shared(islock)); - txidCache.insert(islock.txid, hash); - for (const auto& in : islock.inputs) { - outpointCache.insert(in, hash); - } -} - -void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock, bool keep_cache) -{ - AssertLockHeld(cs_db); - if (!islock) { - islock = GetInstantSendLockByHashInternal(hash, false); - if (!islock) { - return; - } - } - - batch.Erase(std::make_tuple(DB_ISLOCK_BY_HASH, hash)); - batch.Erase(std::make_tuple(DB_HASH_BY_TXID, islock->txid)); - for (auto& in : islock->inputs) { - batch.Erase(std::make_tuple(DB_HASH_BY_OUTPOINT, in)); - } - - if (!keep_cache) { - islockCache.erase(hash); - txidCache.erase(islock->txid); - for (const auto& in : islock->inputs) { - outpointCache.erase(in); - } - } -} - -static std::tuple BuildInversedISLockKey(std::string_view k, int nHeight, const uint256& islockHash) -{ - return std::make_tuple(std::string{k}, htobe32_internal(std::numeric_limits::max() - nHeight), islockHash); -} - -void CInstantSendDb::WriteInstantSendLockMined(const uint256& hash, int nHeight) -{ - LOCK(cs_db); - CDBBatch batch(*db); - WriteInstantSendLockMined(batch, hash, nHeight); - db->WriteBatch(batch); -} - -void CInstantSendDb::WriteInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight) -{ - AssertLockHeld(cs_db); - batch.Write(BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nHeight, hash), true); -} - -void CInstantSendDb::RemoveInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight) -{ - AssertLockHeld(cs_db); - batch.Erase(BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nHeight, hash)); -} - -void CInstantSendDb::WriteInstantSendLockArchived(CDBBatch& batch, const uint256& hash, int nHeight) -{ - AssertLockHeld(cs_db); - batch.Write(BuildInversedISLockKey(DB_ARCHIVED_BY_HEIGHT_AND_HASH, nHeight, hash), true); - batch.Write(std::make_tuple(DB_ARCHIVED_BY_HASH, hash), true); -} - -std::unordered_map CInstantSendDb::RemoveConfirmedInstantSendLocks(int nUntilHeight) -{ - LOCK(cs_db); - if (nUntilHeight <= best_confirmed_height) { - LogPrint(BCLog::ALL, "CInstantSendDb::%s -- Attempting to confirm height %d, however we've already confirmed height %d. This should never happen.\n", __func__, - nUntilHeight, best_confirmed_height); - return {}; - } - best_confirmed_height = nUntilHeight; - - auto it = std::unique_ptr(db->NewIterator()); - - auto firstKey = BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nUntilHeight, uint256()); - - it->Seek(firstKey); - - CDBBatch batch(*db); - std::unordered_map ret; - while (it->Valid()) { - decltype(firstKey) curKey; - if (!it->GetKey(curKey) || std::get<0>(curKey) != DB_MINED_BY_HEIGHT_AND_HASH) { - break; - } - uint32_t nHeight = std::numeric_limits::max() - be32toh_internal(std::get<1>(curKey)); - if (nHeight > uint32_t(nUntilHeight)) { - break; - } - - auto& islockHash = std::get<2>(curKey); - - if (auto islock = GetInstantSendLockByHashInternal(islockHash, false)) { - RemoveInstantSendLock(batch, islockHash, islock); - ret.try_emplace(islockHash, std::move(islock)); - } - - // archive the islock hash, so that we're still able to check if we've seen the islock in the past - WriteInstantSendLockArchived(batch, islockHash, nHeight); - - batch.Erase(curKey); - - it->Next(); - } - - db->WriteBatch(batch); - - return ret; -} - -void CInstantSendDb::RemoveArchivedInstantSendLocks(int nUntilHeight) -{ - LOCK(cs_db); - if (nUntilHeight <= 0) { - return; - } - - auto it = std::unique_ptr(db->NewIterator()); - - auto firstKey = BuildInversedISLockKey(DB_ARCHIVED_BY_HEIGHT_AND_HASH, nUntilHeight, uint256()); - - it->Seek(firstKey); - - CDBBatch batch(*db); - while (it->Valid()) { - decltype(firstKey) curKey; - if (!it->GetKey(curKey) || std::get<0>(curKey) != DB_ARCHIVED_BY_HEIGHT_AND_HASH) { - break; - } - uint32_t nHeight = std::numeric_limits::max() - be32toh_internal(std::get<1>(curKey)); - if (nHeight > uint32_t(nUntilHeight)) { - break; - } - - auto& islockHash = std::get<2>(curKey); - batch.Erase(std::make_tuple(DB_ARCHIVED_BY_HASH, islockHash)); - batch.Erase(curKey); - - it->Next(); - } - - db->WriteBatch(batch); -} - -void CInstantSendDb::WriteBlockInstantSendLocks(const gsl::not_null>& pblock, - gsl::not_null pindexConnected) -{ - LOCK(cs_db); - CDBBatch batch(*db); - for (const auto& tx : pblock->vtx) { - if (tx->IsCoinBase() || tx->vin.empty()) { - // coinbase and TXs with no inputs can't be locked - continue; - } - uint256 islockHash = GetInstantSendLockHashByTxidInternal(tx->GetHash()); - // update DB about when an IS lock was mined - if (!islockHash.IsNull()) { - WriteInstantSendLockMined(batch, islockHash, pindexConnected->nHeight); - } - } - db->WriteBatch(batch); -} - -void CInstantSendDb::RemoveBlockInstantSendLocks(const gsl::not_null>& pblock, gsl::not_null pindexDisconnected) -{ - LOCK(cs_db); - CDBBatch batch(*db); - for (const auto& tx : pblock->vtx) { - if (tx->IsCoinBase() || tx->vin.empty()) { - // coinbase and TXs with no inputs can't be locked - continue; - } - uint256 islockHash = GetInstantSendLockHashByTxidInternal(tx->GetHash()); - if (!islockHash.IsNull()) { - RemoveInstantSendLockMined(batch, islockHash, pindexDisconnected->nHeight); - } - } - db->WriteBatch(batch); -} - -bool CInstantSendDb::KnownInstantSendLock(const uint256& islockHash) const -{ - LOCK(cs_db); - return GetInstantSendLockByHashInternal(islockHash) != nullptr || db->Exists(std::make_tuple(DB_ARCHIVED_BY_HASH, islockHash)); -} - -size_t CInstantSendDb::GetInstantSendLockCount() const -{ - LOCK(cs_db); - auto it = std::unique_ptr(db->NewIterator()); - auto firstKey = std::make_tuple(std::string{DB_ISLOCK_BY_HASH}, uint256()); - - it->Seek(firstKey); - - size_t cnt = 0; - while (it->Valid()) { - decltype(firstKey) curKey; - if (!it->GetKey(curKey) || std::get<0>(curKey) != DB_ISLOCK_BY_HASH) { - break; - } - - cnt++; - - it->Next(); - } - - return cnt; -} - -CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByHashInternal(const uint256& hash, bool use_cache) const -{ - AssertLockHeld(cs_db); - if (hash.IsNull()) { - return nullptr; - } - - CInstantSendLockPtr ret; - if (use_cache && islockCache.get(hash, ret)) { - return ret; - } - - ret = std::make_shared(); - bool exists = db->Read(std::make_tuple(DB_ISLOCK_BY_HASH, hash), *ret); - if (!exists || (::SerializeHash(*ret) != hash)) { - ret = std::make_shared(); - exists = db->Read(std::make_tuple(DB_ISLOCK_BY_HASH, hash), *ret); - if (!exists || (::SerializeHash(*ret) != hash)) { - ret = nullptr; - } - } - islockCache.insert(hash, ret); - return ret; -} - -uint256 CInstantSendDb::GetInstantSendLockHashByTxidInternal(const uint256& txid) const -{ - AssertLockHeld(cs_db); - uint256 islockHash; - if (!txidCache.get(txid, islockHash)) { - if (!db->Read(std::make_tuple(DB_HASH_BY_TXID, txid), islockHash)) { - return {}; - } - txidCache.insert(txid, islockHash); - } - return islockHash; -} - -CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByTxid(const uint256& txid) const -{ - LOCK(cs_db); - return GetInstantSendLockByHashInternal(GetInstantSendLockHashByTxidInternal(txid)); -} - -CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByInput(const COutPoint& outpoint) const -{ - LOCK(cs_db); - uint256 islockHash; - if (!outpointCache.get(outpoint, islockHash)) { - if (!db->Read(std::make_tuple(DB_HASH_BY_OUTPOINT, outpoint), islockHash)) { - return nullptr; - } - outpointCache.insert(outpoint, islockHash); - } - return GetInstantSendLockByHashInternal(islockHash); -} - -std::vector CInstantSendDb::GetInstantSendLocksByParent(const uint256& parent) const -{ - AssertLockHeld(cs_db); - auto it = std::unique_ptr(db->NewIterator()); - auto firstKey = std::make_tuple(std::string{DB_HASH_BY_OUTPOINT}, COutPoint(parent, 0)); - it->Seek(firstKey); - - std::vector result; - - while (it->Valid()) { - decltype(firstKey) curKey; - if (!it->GetKey(curKey) || std::get<0>(curKey) != DB_HASH_BY_OUTPOINT) { - break; - } - const auto& outpoint = std::get<1>(curKey); - if (outpoint.hash != parent) { - break; - } - - uint256 islockHash; - if (!it->GetValue(islockHash)) { - break; - } - result.emplace_back(islockHash); - it->Next(); - } - - return result; -} - -std::vector CInstantSendDb::RemoveChainedInstantSendLocks(const uint256& islockHash, const uint256& txid, int nHeight) -{ - LOCK(cs_db); - std::vector result; - - std::vector stack; - std::unordered_set added; - stack.emplace_back(txid); - - CDBBatch batch(*db); - while (!stack.empty()) { - auto children = GetInstantSendLocksByParent(stack.back()); - stack.pop_back(); - - for (auto& childIslockHash : children) { - auto childIsLock = GetInstantSendLockByHashInternal(childIslockHash, false); - if (!childIsLock) { - continue; - } - - RemoveInstantSendLock(batch, childIslockHash, childIsLock, false); - WriteInstantSendLockArchived(batch, childIslockHash, nHeight); - result.emplace_back(childIslockHash); - - if (added.emplace(childIsLock->txid).second) { - stack.emplace_back(childIsLock->txid); - } - } - } - - RemoveInstantSendLock(batch, islockHash, nullptr, false); - WriteInstantSendLockArchived(batch, islockHash, nHeight); - result.emplace_back(islockHash); - - db->WriteBatch(batch); - - return result; -} - -//////////////// - - CInstantSendManager::CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CQuorumManager& _qman, CSigningManager& _sigman, CSigSharesManager& _shareman, CSporkManager& sporkman, CTxMemPool& _mempool, const CMasternodeSync& mn_sync, diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index 2dbc39c0757e..ead397951983 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -36,141 +37,10 @@ class CQuorumManager; class CSigningManager; class CSigSharesManager; -class CInstantSendDb -{ -private: - mutable Mutex cs_db; - - static constexpr int CURRENT_VERSION{1}; - - int best_confirmed_height GUARDED_BY(cs_db) {0}; - - std::unique_ptr db GUARDED_BY(cs_db) {nullptr}; - mutable unordered_lru_cache islockCache GUARDED_BY(cs_db); - mutable unordered_lru_cache txidCache GUARDED_BY(cs_db); - - mutable unordered_lru_cache outpointCache GUARDED_BY(cs_db); - void WriteInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_db); - - void RemoveInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_db); - - /** - * This method removes a InstantSend Lock from the database and is called when a tx with an IS lock is confirmed and Chainlocked - * @param batch Object used to batch many calls together - * @param hash The hash of the InstantSend Lock - * @param islock The InstantSend Lock object itself - * @param keep_cache Should we still keep corresponding entries in the cache or not - */ - void RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock, bool keep_cache = true) EXCLUSIVE_LOCKS_REQUIRED(cs_db); - /** - * Marks an InstantSend Lock as archived. - * @param batch Object used to batch many calls together - * @param hash The hash of the InstantSend Lock - * @param nHeight The height that the transaction was included at - */ - void WriteInstantSendLockArchived(CDBBatch& batch, const uint256& hash, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_db); - /** - * Gets a vector of IS Lock hashes of the IS Locks which rely on or are children of the parent IS Lock - * @param parent The hash of the parent IS Lock - * @return Returns a vector of IS Lock hashes - */ - std::vector GetInstantSendLocksByParent(const uint256& parent) const EXCLUSIVE_LOCKS_REQUIRED(cs_db); - - /** - * See GetInstantSendLockByHash - */ - CInstantSendLockPtr GetInstantSendLockByHashInternal(const uint256& hash, bool use_cache = true) const EXCLUSIVE_LOCKS_REQUIRED(cs_db); - - /** - * See GetInstantSendLockHashByTxid - */ - uint256 GetInstantSendLockHashByTxidInternal(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_db); - - - void Upgrade(bool unitTests) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); - -public: - explicit CInstantSendDb(bool unitTests, bool fWipe); - ~CInstantSendDb(); - - /** - * This method is called when an InstantSend Lock is processed and adds the lock to the database - * @param hash The hash of the InstantSend Lock - * @param islock The InstantSend Lock object itself - */ - void WriteNewInstantSendLock(const uint256& hash, const CInstantSendLock& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); - /** - * This method updates a DB entry for an InstantSend Lock from being not included in a block to being included in a block - * @param hash The hash of the InstantSend Lock - * @param nHeight The height that the transaction was included at - */ - void WriteInstantSendLockMined(const uint256& hash, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); - /** - * Archives and deletes all IS Locks which were mined into a block before nUntilHeight - * @param nUntilHeight Removes all IS Locks confirmed up until nUntilHeight - * @return returns an unordered_map of the hash of the IS Locks and a pointer object to the IS Locks for all IS Locks which were removed - */ - std::unordered_map RemoveConfirmedInstantSendLocks(int nUntilHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); - /** - * Removes IS Locks from the archive if the tx was confirmed 100 blocks before nUntilHeight - * @param nUntilHeight the height from which to base the remove of archive IS Locks - */ - void RemoveArchivedInstantSendLocks(int nUntilHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); - void WriteBlockInstantSendLocks(const gsl::not_null>& pblock, gsl::not_null pindexConnected) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); - void RemoveBlockInstantSendLocks(const gsl::not_null>& pblock, gsl::not_null pindexDisconnected) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); - bool KnownInstantSendLock(const uint256& islockHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); - /** - * Gets the number of IS Locks which have not been confirmed by a block - * @return size_t value of the number of IS Locks not confirmed by a block - */ - size_t GetInstantSendLockCount() const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); - /** - * Gets a pointer to the IS Lock based on the hash - * @param hash The hash of the IS Lock - * @param use_cache Should we try using the cache first or not - * @return A Pointer object to the IS Lock, returns nullptr if it doesn't exist - */ - CInstantSendLockPtr GetInstantSendLockByHash(const uint256& hash, bool use_cache = true) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db) - { - LOCK(cs_db); - return GetInstantSendLockByHashInternal(hash, use_cache); - }; - /** - * Gets an IS Lock hash based on the txid the IS Lock is for - * @param txid The txid which is being searched for - * @return Returns the hash the IS Lock of the specified txid, returns uint256() if it doesn't exist - */ - uint256 GetInstantSendLockHashByTxid(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db) - { - LOCK(cs_db); - return GetInstantSendLockHashByTxidInternal(txid); - }; - /** - * Gets an IS Lock pointer from the txid given - * @param txid The txid for which the IS Lock Pointer is being returned - * @return Returns the IS Lock Pointer associated with the txid, returns nullptr if it doesn't exist - */ - CInstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); - /** - * Gets an IS Lock pointer from an input given - * @param outpoint Since all inputs are really just outpoints that are being spent - * @return IS Lock Pointer associated with that input. - */ - CInstantSendLockPtr GetInstantSendLockByInput(const COutPoint& outpoint) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); - /** - * Called when a ChainLock invalidated a IS Lock, removes any chained/children IS Locks and the invalidated IS Lock - * @param islockHash IS Lock hash which has been invalidated - * @param txid Transaction id associated with the islockHash - * @param nHeight height of the block which received a chainlock and invalidated the IS Lock - * @return A vector of IS Lock hashes of all IS Locks removed - */ - std::vector RemoveChainedInstantSendLocks(const uint256& islockHash, const uint256& txid, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); -}; - class CInstantSendManager : public CRecoveredSigsListener { private: - CInstantSendDb db; + instantsend::CInstantSendDb db; CChainLocksHandler& clhandler; CChainState& m_chainstate; From 544791d35cb9323a10ea0122784aeaf0a4539d65 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:49:01 +0000 Subject: [PATCH 05/10] refactor: move masternode mode logic to `instantsend/signer.{cpp,h}` Review with `git log -p -n1 --color-moved=dimmed_zebra`. --- src/Makefile.am | 1 + src/instantsend/instantsend.cpp | 348 ----------------------------- src/instantsend/signing.cpp | 378 ++++++++++++++++++++++++++++++++ 3 files changed, 379 insertions(+), 348 deletions(-) create mode 100644 src/instantsend/signing.cpp diff --git a/src/Makefile.am b/src/Makefile.am index e76b53f1c23e..51f789848001 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -493,6 +493,7 @@ libbitcoin_node_a_SOURCES = \ instantsend/db.cpp \ instantsend/instantsend.cpp \ instantsend/lock.cpp \ + instantsend/signing.cpp \ llmq/blockprocessor.cpp \ llmq/chainlocks.cpp \ llmq/clsig.cpp \ diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 411edb928c51..32e2cb007a94 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -88,288 +88,6 @@ void CInstantSendManager::Stop() } } -void CInstantSendManager::ProcessTx(const CTransaction& tx, bool fRetroactive, const Consensus::Params& params) -{ - if (!m_is_masternode || !IsInstantSendEnabled() || !m_mn_sync.IsBlockchainSynced()) { - return; - } - - if (params.llmqTypeDIP0024InstantSend == Consensus::LLMQType::LLMQ_NONE) { - return; - } - - if (!CheckCanLock(tx, true, params)) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: CheckCanLock returned false\n", __func__, - tx.GetHash().ToString()); - return; - } - - auto conflictingLock = GetConflictingLock(tx); - if (conflictingLock != nullptr) { - auto conflictingLockHash = ::SerializeHash(*conflictingLock); - LogPrintf("CInstantSendManager::%s -- txid=%s: conflicts with islock %s, txid=%s\n", __func__, - tx.GetHash().ToString(), conflictingLockHash.ToString(), conflictingLock->txid.ToString()); - return; - } - - // Only sign for inlocks or islocks if mempool IS signing is enabled. - // However, if we are processing a tx because it was included in a block we should - // sign even if mempool IS signing is disabled. This allows a ChainLock to happen on this - // block after we retroactively locked all transactions. - if (!IsInstantSendMempoolSigningEnabled() && !fRetroactive) return; - - if (!TrySignInputLocks(tx, fRetroactive, params.llmqTypeDIP0024InstantSend, params)) { - return; - } - - // We might have received all input locks before we got the corresponding TX. In this case, we have to sign the - // islock now instead of waiting for the input locks. - TrySignInstantSendLock(tx); -} - -bool CInstantSendManager::TrySignInputLocks(const CTransaction& tx, bool fRetroactive, Consensus::LLMQType llmqType, const Consensus::Params& params) -{ - std::vector ids; - ids.reserve(tx.vin.size()); - - size_t alreadyVotedCount = 0; - for (const auto& in : tx.vin) { - auto id = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in.prevout)); - ids.emplace_back(id); - - uint256 otherTxHash; - if (sigman.GetVoteForId(params.llmqTypeDIP0024InstantSend, id, otherTxHash)) { - if (otherTxHash != tx.GetHash()) { - LogPrintf("CInstantSendManager::%s -- txid=%s: input %s is conflicting with previous vote for tx %s\n", __func__, - tx.GetHash().ToString(), in.prevout.ToStringShort(), otherTxHash.ToString()); - return false; - } - alreadyVotedCount++; - } - - // don't even try the actual signing if any input is conflicting - if (sigman.IsConflicting(params.llmqTypeDIP0024InstantSend, id, tx.GetHash())) { - LogPrintf("CInstantSendManager::%s -- txid=%s: sigman.IsConflicting returned true. id=%s\n", __func__, - tx.GetHash().ToString(), id.ToString()); - return false; - } - } - if (!fRetroactive && alreadyVotedCount == ids.size()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: already voted on all inputs, bailing out\n", __func__, - tx.GetHash().ToString()); - return true; - } - - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: trying to vote on %d inputs\n", __func__, - tx.GetHash().ToString(), tx.vin.size()); - - for (const auto i : irange::range(tx.vin.size())) { - const auto& in = tx.vin[i]; - auto& id = ids[i]; - WITH_LOCK(cs_inputReqests, inputRequestIds.emplace(id)); - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: trying to vote on input %s with id %s. fRetroactive=%d\n", __func__, - tx.GetHash().ToString(), in.prevout.ToStringShort(), id.ToString(), fRetroactive); - if (sigman.AsyncSignIfMember(llmqType, shareman, id, tx.GetHash(), {}, fRetroactive)) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: voted on input %s with id %s\n", __func__, - tx.GetHash().ToString(), in.prevout.ToStringShort(), id.ToString()); - } - } - - return true; -} - -bool CInstantSendManager::CheckCanLock(const CTransaction& tx, bool printDebug, const Consensus::Params& params) const -{ - if (tx.vin.empty()) { - // can't lock TXs without inputs (e.g. quorum commitments) - return false; - } - - return ranges::all_of(tx.vin, - [&](const auto& in) { return CheckCanLock(in.prevout, printDebug, tx.GetHash(), params); }); -} - -bool CInstantSendManager::CheckCanLock(const COutPoint& outpoint, bool printDebug, const uint256& txHash, const Consensus::Params& params) const -{ - int nInstantSendConfirmationsRequired = params.nInstantSendConfirmationsRequired; - - if (IsLocked(outpoint.hash)) { - // if prevout was ix locked, allow locking of descendants (no matter if prevout is in mempool or already mined) - return true; - } - - auto mempoolTx = mempool.get(outpoint.hash); - if (mempoolTx) { - if (printDebug) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: parent mempool TX %s is not locked\n", __func__, - txHash.ToString(), outpoint.hash.ToString()); - } - return false; - } - - uint256 hashBlock{}; - const auto tx = GetTransaction(nullptr, &mempool, outpoint.hash, params, hashBlock); - // this relies on enabled txindex and won't work if we ever try to remove the requirement for txindex for masternodes - if (!tx) { - if (printDebug) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: failed to find parent TX %s\n", __func__, - txHash.ToString(), outpoint.hash.ToString()); - } - return false; - } - - const CBlockIndex* pindexMined; - int nTxAge; - { - LOCK(::cs_main); - pindexMined = m_chainstate.m_blockman.LookupBlockIndex(hashBlock); - nTxAge = m_chainstate.m_chain.Height() - pindexMined->nHeight + 1; - } - - if (nTxAge < nInstantSendConfirmationsRequired && !clhandler.HasChainLock(pindexMined->nHeight, pindexMined->GetBlockHash())) { - if (printDebug) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: outpoint %s too new and not ChainLocked. nTxAge=%d, nInstantSendConfirmationsRequired=%d\n", __func__, - txHash.ToString(), outpoint.ToStringShort(), nTxAge, nInstantSendConfirmationsRequired); - } - return false; - } - - return true; -} - -MessageProcessingResult CInstantSendManager::HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) -{ - if (!IsInstantSendEnabled()) { - return {}; - } - - if (Params().GetConsensus().llmqTypeDIP0024InstantSend == Consensus::LLMQType::LLMQ_NONE) { - return {}; - } - - uint256 txid; - if (LOCK(cs_inputReqests); inputRequestIds.count(recoveredSig.getId())) { - txid = recoveredSig.getMsgHash(); - } - if (!txid.IsNull()) { - HandleNewInputLockRecoveredSig(recoveredSig, txid); - } else if (/*isInstantSendLock=*/ WITH_LOCK(cs_creating, return creatingInstantSendLocks.count(recoveredSig.getId()))) { - HandleNewInstantSendLockRecoveredSig(recoveredSig); - } - return {}; -} - -void CInstantSendManager::HandleNewInputLockRecoveredSig(const CRecoveredSig& recoveredSig, const uint256& txid) -{ - if (g_txindex) { - g_txindex->BlockUntilSyncedToCurrentChain(); - } - - - uint256 hashBlock{}; - const auto tx = GetTransaction(nullptr, &mempool, txid, Params().GetConsensus(), hashBlock); - if (!tx) { - return; - } - - if (LogAcceptDebug(BCLog::INSTANTSEND)) { - for (const auto& in : tx->vin) { - auto id = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in.prevout)); - if (id == recoveredSig.getId()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: got recovered sig for input %s\n", __func__, - txid.ToString(), in.prevout.ToStringShort()); - break; - } - } - } - - TrySignInstantSendLock(*tx); -} - -void CInstantSendManager::TrySignInstantSendLock(const CTransaction& tx) -{ - const auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; - - for (const auto& in : tx.vin) { - auto id = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in.prevout)); - if (!sigman.HasRecoveredSig(llmqType, id, tx.GetHash())) { - return; - } - } - - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: got all recovered sigs, creating CInstantSendLock\n", __func__, - tx.GetHash().ToString()); - - CInstantSendLock islock; - islock.txid = tx.GetHash(); - for (const auto& in : tx.vin) { - islock.inputs.emplace_back(in.prevout); - } - - auto id = islock.GetRequestId(); - - if (sigman.HasRecoveredSigForId(llmqType, id)) { - return; - } - - const auto& llmq_params_opt = Params().GetLLMQ(llmqType); - assert(llmq_params_opt); - const auto quorum = SelectQuorumForSigning(llmq_params_opt.value(), m_chainstate.m_chain, qman, id); - - if (!quorum) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- failed to select quorum. islock id=%s, txid=%s\n", - __func__, id.ToString(), tx.GetHash().ToString()); - return; - } - - const int cycle_height = quorum->m_quorum_base_block_index->nHeight - - quorum->m_quorum_base_block_index->nHeight % llmq_params_opt->dkgInterval; - islock.cycleHash = quorum->m_quorum_base_block_index->GetAncestor(cycle_height)->GetBlockHash(); - - { - LOCK(cs_creating); - auto e = creatingInstantSendLocks.emplace(id, std::move(islock)); - if (!e.second) { - return; - } - txToCreatingInstantSendLocks.emplace(tx.GetHash(), &e.first->second); - } - - sigman.AsyncSignIfMember(llmqType, shareman, id, tx.GetHash(), quorum->m_quorum_base_block_index->GetBlockHash()); -} - -void CInstantSendManager::HandleNewInstantSendLockRecoveredSig(const llmq::CRecoveredSig& recoveredSig) -{ - CInstantSendLockPtr islock; - - { - LOCK(cs_creating); - auto it = creatingInstantSendLocks.find(recoveredSig.getId()); - if (it == creatingInstantSendLocks.end()) { - return; - } - - islock = std::make_shared(std::move(it->second)); - creatingInstantSendLocks.erase(it); - txToCreatingInstantSendLocks.erase(islock->txid); - } - - if (islock->txid != recoveredSig.getMsgHash()) { - LogPrintf("CInstantSendManager::%s -- txid=%s: islock conflicts with %s, dropping own version\n", __func__, - islock->txid.ToString(), recoveredSig.getMsgHash().ToString()); - return; - } - - islock->sig = recoveredSig.sig; - auto hash = ::SerializeHash(*islock); - - if (WITH_LOCK(cs_pendingLocks, return pendingInstantSendLocks.count(hash)) || db.KnownInstantSendLock(hash)) { - return; - } - LOCK(cs_pendingLocks); - pendingInstantSendLocks.emplace(hash, std::make_pair(-1, islock)); -} - PeerMsgRet CInstantSendManager::ProcessMessage(const CNode& pfrom, PeerManager& peerman, std::string_view msg_type, CDataStream& vRecv) { @@ -1080,67 +798,6 @@ void CInstantSendManager::RemoveConflictingLock(const uint256& islockHash, const } } -void CInstantSendManager::ProcessPendingRetryLockTxs() -{ - const auto retryTxs = WITH_LOCK(cs_pendingRetry, return pendingRetryTxs); - - if (retryTxs.empty()) { - return; - } - - if (!IsInstantSendEnabled()) { - return; - } - - int retryCount = 0; - for (const auto& txid : retryTxs) { - CTransactionRef tx; - { - { - LOCK(cs_nonLocked); - auto it = nonLockedTxs.find(txid); - if (it == nonLockedTxs.end()) { - continue; - } - tx = it->second.tx; - } - if (!tx) { - continue; - } - - if (LOCK(cs_creating); txToCreatingInstantSendLocks.count(tx->GetHash())) { - // we're already in the middle of locking this one - continue; - } - if (IsLocked(tx->GetHash())) { - continue; - } - if (GetConflictingLock(*tx) != nullptr) { - // should not really happen as we have already filtered these out - continue; - } - } - - // CheckCanLock is already called by ProcessTx, so we should avoid calling it twice. But we also shouldn't spam - // the logs when retrying TXs that are not ready yet. - if (LogAcceptDebug(BCLog::INSTANTSEND)) { - if (!CheckCanLock(*tx, false, Params().GetConsensus())) { - continue; - } - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: retrying to lock\n", __func__, - tx->GetHash().ToString()); - } - - ProcessTx(*tx, false, Params().GetConsensus()); - retryCount++; - } - - if (retryCount != 0) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- retried %d TXs. nonLockedTxs.size=%d\n", __func__, - retryCount, WITH_LOCK(cs_nonLocked, return nonLockedTxs.size())); - } -} - bool CInstantSendManager::AlreadyHave(const CInv& inv) const { if (!IsInstantSendEnabled()) { @@ -1254,11 +911,6 @@ bool CInstantSendManager::IsInstantSendEnabled() const return !fReindex && !fImporting && spork_manager.IsSporkActive(SPORK_2_INSTANTSEND_ENABLED); } -bool CInstantSendManager::IsInstantSendMempoolSigningEnabled() const -{ - return !fReindex && !fImporting && spork_manager.GetSporkValue(SPORK_2_INSTANTSEND_ENABLED) == 0; -} - bool CInstantSendManager::RejectConflictingBlocks() const { if (!m_mn_sync.IsBlockchainSynced()) { diff --git a/src/instantsend/signing.cpp b/src/instantsend/signing.cpp new file mode 100644 index 000000000000..ad6d0c0ad3b9 --- /dev/null +++ b/src/instantsend/signing.cpp @@ -0,0 +1,378 @@ +// Copyright (c) 2019-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// Forward declaration to break dependency over node/transaction.h +namespace node { +CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, + const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock); +} // namespace node + +using node::fImporting; +using node::fReindex; +using node::GetTransaction; + +namespace llmq { +static const std::string_view INPUTLOCK_REQUESTID_PREFIX = "inlock"; + +MessageProcessingResult CInstantSendManager::HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) +{ + if (!IsInstantSendEnabled()) { + return {}; + } + + if (Params().GetConsensus().llmqTypeDIP0024InstantSend == Consensus::LLMQType::LLMQ_NONE) { + return {}; + } + + uint256 txid; + if (LOCK(cs_inputReqests); inputRequestIds.count(recoveredSig.getId())) { + txid = recoveredSig.getMsgHash(); + } + if (!txid.IsNull()) { + HandleNewInputLockRecoveredSig(recoveredSig, txid); + } else if (/*isInstantSendLock=*/ WITH_LOCK(cs_creating, return creatingInstantSendLocks.count(recoveredSig.getId()))) { + HandleNewInstantSendLockRecoveredSig(recoveredSig); + } + return {}; +} + +bool CInstantSendManager::IsInstantSendMempoolSigningEnabled() const +{ + return !fReindex && !fImporting && spork_manager.GetSporkValue(SPORK_2_INSTANTSEND_ENABLED) == 0; +} + +void CInstantSendManager::HandleNewInputLockRecoveredSig(const CRecoveredSig& recoveredSig, const uint256& txid) +{ + if (g_txindex) { + g_txindex->BlockUntilSyncedToCurrentChain(); + } + + uint256 hashBlock{}; + const auto tx = GetTransaction(nullptr, &mempool, txid, Params().GetConsensus(), hashBlock); + if (!tx) { + return; + } + + if (LogAcceptDebug(BCLog::INSTANTSEND)) { + for (const auto& in : tx->vin) { + auto id = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in.prevout)); + if (id == recoveredSig.getId()) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: got recovered sig for input %s\n", __func__, + txid.ToString(), in.prevout.ToStringShort()); + break; + } + } + } + + TrySignInstantSendLock(*tx); +} + +void CInstantSendManager::ProcessPendingRetryLockTxs() +{ + const auto retryTxs = WITH_LOCK(cs_pendingRetry, return pendingRetryTxs); + + if (retryTxs.empty()) { + return; + } + + if (!IsInstantSendEnabled()) { + return; + } + + int retryCount = 0; + for (const auto& txid : retryTxs) { + CTransactionRef tx; + { + { + LOCK(cs_nonLocked); + auto it = nonLockedTxs.find(txid); + if (it == nonLockedTxs.end()) { + continue; + } + tx = it->second.tx; + } + if (!tx) { + continue; + } + + if (LOCK(cs_creating); txToCreatingInstantSendLocks.count(tx->GetHash())) { + // we're already in the middle of locking this one + continue; + } + if (IsLocked(tx->GetHash())) { + continue; + } + if (GetConflictingLock(*tx) != nullptr) { + // should not really happen as we have already filtered these out + continue; + } + } + + // CheckCanLock is already called by ProcessTx, so we should avoid calling it twice. But we also shouldn't spam + // the logs when retrying TXs that are not ready yet. + if (LogAcceptDebug(BCLog::INSTANTSEND)) { + if (!CheckCanLock(*tx, false, Params().GetConsensus())) { + continue; + } + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: retrying to lock\n", __func__, + tx->GetHash().ToString()); + } + + ProcessTx(*tx, false, Params().GetConsensus()); + retryCount++; + } + + if (retryCount != 0) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- retried %d TXs. nonLockedTxs.size=%d\n", __func__, + retryCount, WITH_LOCK(cs_nonLocked, return nonLockedTxs.size())); + } +} + +bool CInstantSendManager::CheckCanLock(const CTransaction& tx, bool printDebug, const Consensus::Params& params) const +{ + if (tx.vin.empty()) { + // can't lock TXs without inputs (e.g. quorum commitments) + return false; + } + + return ranges::all_of(tx.vin, + [&](const auto& in) { return CheckCanLock(in.prevout, printDebug, tx.GetHash(), params); }); +} + +bool CInstantSendManager::CheckCanLock(const COutPoint& outpoint, bool printDebug, const uint256& txHash, const Consensus::Params& params) const +{ + int nInstantSendConfirmationsRequired = params.nInstantSendConfirmationsRequired; + + if (IsLocked(outpoint.hash)) { + // if prevout was ix locked, allow locking of descendants (no matter if prevout is in mempool or already mined) + return true; + } + + auto mempoolTx = mempool.get(outpoint.hash); + if (mempoolTx) { + if (printDebug) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: parent mempool TX %s is not locked\n", __func__, + txHash.ToString(), outpoint.hash.ToString()); + } + return false; + } + + uint256 hashBlock{}; + const auto tx = GetTransaction(nullptr, &mempool, outpoint.hash, params, hashBlock); + // this relies on enabled txindex and won't work if we ever try to remove the requirement for txindex for masternodes + if (!tx) { + if (printDebug) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: failed to find parent TX %s\n", __func__, + txHash.ToString(), outpoint.hash.ToString()); + } + return false; + } + + const CBlockIndex* pindexMined; + int nTxAge; + { + LOCK(::cs_main); + pindexMined = m_chainstate.m_blockman.LookupBlockIndex(hashBlock); + nTxAge = m_chainstate.m_chain.Height() - pindexMined->nHeight + 1; + } + + if (nTxAge < nInstantSendConfirmationsRequired && !clhandler.HasChainLock(pindexMined->nHeight, pindexMined->GetBlockHash())) { + if (printDebug) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: outpoint %s too new and not ChainLocked. nTxAge=%d, nInstantSendConfirmationsRequired=%d\n", __func__, + txHash.ToString(), outpoint.ToStringShort(), nTxAge, nInstantSendConfirmationsRequired); + } + return false; + } + + return true; +} + +void CInstantSendManager::HandleNewInstantSendLockRecoveredSig(const llmq::CRecoveredSig& recoveredSig) +{ + CInstantSendLockPtr islock; + + { + LOCK(cs_creating); + auto it = creatingInstantSendLocks.find(recoveredSig.getId()); + if (it == creatingInstantSendLocks.end()) { + return; + } + + islock = std::make_shared(std::move(it->second)); + creatingInstantSendLocks.erase(it); + txToCreatingInstantSendLocks.erase(islock->txid); + } + + if (islock->txid != recoveredSig.getMsgHash()) { + LogPrintf("CInstantSendManager::%s -- txid=%s: islock conflicts with %s, dropping own version\n", __func__, + islock->txid.ToString(), recoveredSig.getMsgHash().ToString()); + return; + } + + islock->sig = recoveredSig.sig; + auto hash = ::SerializeHash(*islock); + + if (WITH_LOCK(cs_pendingLocks, return pendingInstantSendLocks.count(hash)) || db.KnownInstantSendLock(hash)) { + return; + } + LOCK(cs_pendingLocks); + pendingInstantSendLocks.emplace(hash, std::make_pair(-1, islock)); +} + +void CInstantSendManager::ProcessTx(const CTransaction& tx, bool fRetroactive, const Consensus::Params& params) +{ + if (!m_is_masternode || !IsInstantSendEnabled() || !m_mn_sync.IsBlockchainSynced()) { + return; + } + + if (params.llmqTypeDIP0024InstantSend == Consensus::LLMQType::LLMQ_NONE) { + return; + } + + if (!CheckCanLock(tx, true, params)) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: CheckCanLock returned false\n", __func__, + tx.GetHash().ToString()); + return; + } + + auto conflictingLock = GetConflictingLock(tx); + if (conflictingLock != nullptr) { + auto conflictingLockHash = ::SerializeHash(*conflictingLock); + LogPrintf("CInstantSendManager::%s -- txid=%s: conflicts with islock %s, txid=%s\n", __func__, + tx.GetHash().ToString(), conflictingLockHash.ToString(), conflictingLock->txid.ToString()); + return; + } + + // Only sign for inlocks or islocks if mempool IS signing is enabled. + // However, if we are processing a tx because it was included in a block we should + // sign even if mempool IS signing is disabled. This allows a ChainLock to happen on this + // block after we retroactively locked all transactions. + if (!IsInstantSendMempoolSigningEnabled() && !fRetroactive) return; + + if (!TrySignInputLocks(tx, fRetroactive, params.llmqTypeDIP0024InstantSend, params)) { + return; + } + + // We might have received all input locks before we got the corresponding TX. In this case, we have to sign the + // islock now instead of waiting for the input locks. + TrySignInstantSendLock(tx); +} + +bool CInstantSendManager::TrySignInputLocks(const CTransaction& tx, bool fRetroactive, Consensus::LLMQType llmqType, const Consensus::Params& params) +{ + std::vector ids; + ids.reserve(tx.vin.size()); + + size_t alreadyVotedCount = 0; + for (const auto& in : tx.vin) { + auto id = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in.prevout)); + ids.emplace_back(id); + + uint256 otherTxHash; + if (sigman.GetVoteForId(params.llmqTypeDIP0024InstantSend, id, otherTxHash)) { + if (otherTxHash != tx.GetHash()) { + LogPrintf("CInstantSendManager::%s -- txid=%s: input %s is conflicting with previous vote for tx %s\n", __func__, + tx.GetHash().ToString(), in.prevout.ToStringShort(), otherTxHash.ToString()); + return false; + } + alreadyVotedCount++; + } + + // don't even try the actual signing if any input is conflicting + if (sigman.IsConflicting(params.llmqTypeDIP0024InstantSend, id, tx.GetHash())) { + LogPrintf("CInstantSendManager::%s -- txid=%s: sigman.IsConflicting returned true. id=%s\n", __func__, + tx.GetHash().ToString(), id.ToString()); + return false; + } + } + if (!fRetroactive && alreadyVotedCount == ids.size()) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: already voted on all inputs, bailing out\n", __func__, + tx.GetHash().ToString()); + return true; + } + + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: trying to vote on %d inputs\n", __func__, + tx.GetHash().ToString(), tx.vin.size()); + + for (const auto i : irange::range(tx.vin.size())) { + const auto& in = tx.vin[i]; + auto& id = ids[i]; + WITH_LOCK(cs_inputReqests, inputRequestIds.emplace(id)); + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: trying to vote on input %s with id %s. fRetroactive=%d\n", __func__, + tx.GetHash().ToString(), in.prevout.ToStringShort(), id.ToString(), fRetroactive); + if (sigman.AsyncSignIfMember(llmqType, shareman, id, tx.GetHash(), {}, fRetroactive)) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: voted on input %s with id %s\n", __func__, + tx.GetHash().ToString(), in.prevout.ToStringShort(), id.ToString()); + } + } + + return true; +} + +void CInstantSendManager::TrySignInstantSendLock(const CTransaction& tx) +{ + const auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; + + for (const auto& in : tx.vin) { + auto id = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in.prevout)); + if (!sigman.HasRecoveredSig(llmqType, id, tx.GetHash())) { + return; + } + } + + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: got all recovered sigs, creating CInstantSendLock\n", __func__, + tx.GetHash().ToString()); + + CInstantSendLock islock; + islock.txid = tx.GetHash(); + for (const auto& in : tx.vin) { + islock.inputs.emplace_back(in.prevout); + } + + auto id = islock.GetRequestId(); + + if (sigman.HasRecoveredSigForId(llmqType, id)) { + return; + } + + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); + assert(llmq_params_opt); + const auto quorum = SelectQuorumForSigning(llmq_params_opt.value(), m_chainstate.m_chain, qman, id); + + if (!quorum) { + LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- failed to select quorum. islock id=%s, txid=%s\n", + __func__, id.ToString(), tx.GetHash().ToString()); + return; + } + + const int cycle_height = quorum->m_quorum_base_block_index->nHeight - + quorum->m_quorum_base_block_index->nHeight % llmq_params_opt->dkgInterval; + islock.cycleHash = quorum->m_quorum_base_block_index->GetAncestor(cycle_height)->GetBlockHash(); + + { + LOCK(cs_creating); + auto e = creatingInstantSendLocks.emplace(id, std::move(islock)); + if (!e.second) { + return; + } + txToCreatingInstantSendLocks.emplace(tx.GetHash(), &e.first->second); + } + + sigman.AsyncSignIfMember(llmqType, shareman, id, tx.GetHash(), quorum->m_quorum_base_block_index->GetBlockHash()); +} +} // namespace llmq From f22fb22cdfd060bcd9ea5c0d5808b6ea360ba848 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Jul 2025 18:15:45 +0000 Subject: [PATCH 06/10] refactor: separate masternode mode logic into dedicated manager class --- src/Makefile.am | 1 + src/instantsend/instantsend.cpp | 47 +++++--- src/instantsend/instantsend.h | 82 +++++--------- src/instantsend/signing.cpp | 139 ++++++++++++++---------- src/instantsend/signing.h | 98 +++++++++++++++++ test/lint/lint-circular-dependencies.py | 1 + 6 files changed, 235 insertions(+), 133 deletions(-) create mode 100644 src/instantsend/signing.h diff --git a/src/Makefile.am b/src/Makefile.am index 51f789848001..da020fc9a23b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -233,6 +233,7 @@ BITCOIN_CORE_H = \ instantsend/db.h \ instantsend/instantsend.h \ instantsend/lock.h \ + instantsend/signing.h \ key.h \ key_io.h \ limitedmap.h \ diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 32e2cb007a94..1c1a77c5a7fd 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -51,11 +52,12 @@ CInstantSendManager::CInstantSendManager(CChainLocksHandler& _clhandler, CChainS m_chainstate{chainstate}, qman{_qman}, sigman{_sigman}, - shareman{_shareman}, spork_manager{sporkman}, mempool{_mempool}, m_mn_sync{mn_sync}, - m_is_masternode{is_masternode} + m_signer{is_masternode ? std::make_unique(chainstate, _clhandler, *this, _sigman, + _shareman, _qman, sporkman, _mempool, mn_sync) + : nullptr} { workInterrupt.reset(); } @@ -71,12 +73,16 @@ void CInstantSendManager::Start(PeerManager& peerman) workThread = std::thread(&util::TraceThread, "isman", [this, &peerman] { WorkThreadMain(peerman); }); - sigman.RegisterRecoveredSigsListener(this); + if (m_signer) { + sigman.RegisterRecoveredSigsListener(m_signer.get()); + } } void CInstantSendManager::Stop() { - sigman.UnregisterRecoveredSigsListener(this); + if (m_signer) { + sigman.UnregisterRecoveredSigsListener(m_signer.get()); + } // make sure to call InterruptWorkerThread() first if (!workInterrupt) { @@ -337,10 +343,10 @@ void CInstantSendManager::ProcessInstantSendLock(NodeId from, PeerManager& peerm { LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: processing islock, peer=%d\n", __func__, islock->txid.ToString(), hash.ToString(), from); - { - LOCK(cs_creating); - creatingInstantSendLocks.erase(islock->GetRequestId()); - txToCreatingInstantSendLocks.erase(islock->txid); + if (m_signer) { + LOCK(m_signer->cs_creating); + m_signer->creatingInstantSendLocks.erase(islock->GetRequestId()); + m_signer->txToCreatingInstantSendLocks.erase(islock->txid); } if (db.KnownInstantSendLock(hash)) { return; @@ -411,7 +417,7 @@ void CInstantSendManager::ProcessInstantSendLock(NodeId from, PeerManager& peerm // bump mempool counter to make sure newly locked txes are picked up by getblocktemplate mempool.AddTransactionsUpdated(1); } else { - peerman.AskPeersForTransaction(islock->txid, m_is_masternode); + peerman.AskPeersForTransaction(islock->txid, /*is_masternode=*/m_signer != nullptr); } } @@ -440,7 +446,9 @@ void CInstantSendManager::TransactionAddedToMempool(PeerManager& peerman, const } if (islock == nullptr) { - ProcessTx(*tx, false, Params().GetConsensus()); + if (m_signer) { + m_signer->ProcessTx(*tx, false, Params().GetConsensus()); + } // TX is not locked, so make sure it is tracked AddNonLockedTx(tx, nullptr); } else { @@ -479,7 +487,9 @@ void CInstantSendManager::BlockConnected(const std::shared_ptr& pb } if (!IsLocked(tx->GetHash()) && !has_chainlock) { - ProcessTx(*tx, true, Params().GetConsensus()); + if (m_signer) { + m_signer->ProcessTx(*tx, true, Params().GetConsensus()); + } // TX is not locked, so make sure it is tracked AddNonLockedTx(tx, pindex); } else { @@ -582,19 +592,22 @@ void CInstantSendManager::RemoveNonLockedTx(const uint256& txid, bool retryChild void CInstantSendManager::RemoveConflictedTx(const CTransaction& tx) { RemoveNonLockedTx(tx.GetHash(), false); + if (!m_signer) return; - LOCK(cs_inputReqests); + LOCK(m_signer->cs_inputReqests); for (const auto& in : tx.vin) { auto inputRequestId = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in)); - inputRequestIds.erase(inputRequestId); + m_signer->inputRequestIds.erase(inputRequestId); } } void CInstantSendManager::TruncateRecoveredSigsForInputs(const llmq::CInstantSendLock& islock) { + if (!m_signer) return; + for (const auto& in : islock.inputs) { auto inputRequestId = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in)); - WITH_LOCK(cs_inputReqests, inputRequestIds.erase(inputRequestId)); + WITH_LOCK(m_signer->cs_inputReqests, m_signer->inputRequestIds.erase(inputRequestId)); sigman.TruncateRecoveredSig(Params().GetConsensus().llmqTypeDIP0024InstantSend, inputRequestId); } } @@ -693,7 +706,7 @@ void CInstantSendManager::RemoveMempoolConflictsForLock(PeerManager& peerman, co for (const auto& p : toDelete) { RemoveConflictedTx(*p.second); } - peerman.AskPeersForTransaction(islock.txid, m_is_masternode); + peerman.AskPeersForTransaction(islock.txid, /*is_masternode=*/m_signer != nullptr); } } @@ -898,7 +911,9 @@ void CInstantSendManager::WorkThreadMain(PeerManager& peerman) { while (!workInterrupt) { bool fMoreWork = ProcessPendingInstantSendLocks(peerman); - ProcessPendingRetryLockTxs(); + if (m_signer) { + m_signer->ProcessPendingRetryLockTxs(); + } if (!fMoreWork && !workInterrupt.sleep_for(std::chrono::milliseconds(100))) { return; diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index ead397951983..652f97bd0ce2 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -30,6 +30,10 @@ class CMasternodeSync; class CSporkManager; class PeerManager; +namespace instantsend { +class InstantSendSigner; +} // namespace instantsend + namespace llmq { class CChainLocksHandler; @@ -37,7 +41,7 @@ class CQuorumManager; class CSigningManager; class CSigSharesManager; -class CInstantSendManager : public CRecoveredSigsListener +class CInstantSendManager { private: instantsend::CInstantSendDb db; @@ -46,35 +50,15 @@ class CInstantSendManager : public CRecoveredSigsListener CChainState& m_chainstate; CQuorumManager& qman; CSigningManager& sigman; - CSigSharesManager& shareman; CSporkManager& spork_manager; CTxMemPool& mempool; const CMasternodeSync& m_mn_sync; - const bool m_is_masternode; + std::unique_ptr m_signer{nullptr}; std::thread workThread; CThreadInterrupt workInterrupt; - mutable Mutex cs_inputReqests; - - /** - * Request ids of inputs that we signed. Used to determine if a recovered signature belongs to an - * in-progress input lock. - */ - std::unordered_set inputRequestIds GUARDED_BY(cs_inputReqests); - - mutable Mutex cs_creating; - - /** - * These are the islocks that are currently in the middle of being created. Entries are created when we observed - * recovered signatures for all inputs of a TX. At the same time, we initiate signing of our sigshare for the islock. - * When the recovered sig for the islock later arrives, we can finish the islock and propagate it. - */ - std::unordered_map creatingInstantSendLocks GUARDED_BY(cs_creating); - // maps from txid to the in-progress islock - std::unordered_map txToCreatingInstantSendLocks GUARDED_BY(cs_creating); - mutable Mutex cs_pendingLocks; // Incoming and not verified yet std::unordered_map, StaticSaltedHasher> pendingInstantSendLocks GUARDED_BY(cs_pendingLocks); @@ -111,69 +95,52 @@ class CInstantSendManager : public CRecoveredSigsListener void InterruptWorkerThread() { workInterrupt(); }; private: - void ProcessTx(const CTransaction& tx, bool fRetroactive, const Consensus::Params& params) - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests); - bool CheckCanLock(const CTransaction& tx, bool printDebug, const Consensus::Params& params) const; - bool CheckCanLock(const COutPoint& outpoint, bool printDebug, const uint256& txHash, - const Consensus::Params& params) const; - - void HandleNewInputLockRecoveredSig(const CRecoveredSig& recoveredSig, const uint256& txid) - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating); - void HandleNewInstantSendLockRecoveredSig(const CRecoveredSig& recoveredSig) - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_pendingLocks); - - bool TrySignInputLocks(const CTransaction& tx, bool allowResigning, Consensus::LLMQType llmqType, - const Consensus::Params& params) EXCLUSIVE_LOCKS_REQUIRED(!cs_inputReqests); - void TrySignInstantSendLock(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(!cs_creating); - PeerMsgRet ProcessMessageInstantSendLock(const CNode& pfrom, PeerManager& peerman, const CInstantSendLockPtr& islock); bool ProcessPendingInstantSendLocks(PeerManager& peerman) - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests, !cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); std::unordered_set ProcessPendingInstantSendLocks( const Consensus::LLMQParams& llmq_params, PeerManager& peerman, int signOffset, const std::unordered_map, StaticSaltedHasher>& pend, bool ban) - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests, !cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); void ProcessInstantSendLock(NodeId from, PeerManager& peerman, const uint256& hash, const CInstantSendLockPtr& islock) - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests, !cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); void AddNonLockedTx(const CTransactionRef& tx, const CBlockIndex* pindexMined) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks); void RemoveNonLockedTx(const uint256& txid, bool retryChildren) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); void RemoveConflictedTx(const CTransaction& tx) - EXCLUSIVE_LOCKS_REQUIRED(!cs_inputReqests, !cs_nonLocked, !cs_pendingRetry); - void TruncateRecoveredSigsForInputs(const CInstantSendLock& islock) - EXCLUSIVE_LOCKS_REQUIRED(!cs_inputReqests); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); + void TruncateRecoveredSigsForInputs(const CInstantSendLock& islock); void RemoveMempoolConflictsForLock(PeerManager& peerman, const uint256& hash, const CInstantSendLock& islock) - EXCLUSIVE_LOCKS_REQUIRED(!cs_inputReqests, !cs_nonLocked, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); void ResolveBlockConflicts(const uint256& islockHash, const CInstantSendLock& islock) - EXCLUSIVE_LOCKS_REQUIRED(!cs_inputReqests, !cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); - void ProcessPendingRetryLockTxs() - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests, !cs_nonLocked, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); void WorkThreadMain(PeerManager& peerman) - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests, !cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); + NO_THREAD_SAFETY_ANALYSIS; + // Needed as compiler cannot differentiate between negative capability against member and against + // member accessed through reference. + // TODO: Remove this, it's terrible. + // EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); void HandleFullyConfirmedBlock(const CBlockIndex* pindex) - EXCLUSIVE_LOCKS_REQUIRED(!cs_inputReqests, !cs_nonLocked, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); public: bool IsLocked(const uint256& txHash) const; bool IsWaitingForTx(const uint256& txHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); CInstantSendLockPtr GetConflictingLock(const CTransaction& tx) const; - [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) override - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests, !cs_pendingLocks); - PeerMsgRet ProcessMessage(const CNode& pfrom, PeerManager& peerman, std::string_view msg_type, CDataStream& vRecv); void TransactionAddedToMempool(PeerManager& peerman, const CTransactionRef& tx) - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests, !cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); void TransactionRemovedFromMempool(const CTransactionRef& tx); void BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindex) - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests, !cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); void BlockDisconnected(const std::shared_ptr& pblock, const CBlockIndex* pindexDisconnected); bool AlreadyHave(const CInv& inv) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); @@ -182,9 +149,9 @@ class CInstantSendManager : public CRecoveredSigsListener CInstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const; void NotifyChainLock(const CBlockIndex* pindexChainLock) - EXCLUSIVE_LOCKS_REQUIRED(!cs_inputReqests, !cs_nonLocked, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); void UpdatedBlockTip(const CBlockIndex* pindexNew) - EXCLUSIVE_LOCKS_REQUIRED(!cs_inputReqests, !cs_nonLocked, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); void RemoveConflictingLock(const uint256& islockHash, const CInstantSendLock& islock); @@ -196,8 +163,9 @@ class CInstantSendManager : public CRecoveredSigsListener * transactions in mempool, but should sign txes included in a block. This * allows ChainLocks to continue even while this spork is disabled. */ - bool IsInstantSendMempoolSigningEnabled() const; bool RejectConflictingBlocks() const; + + friend class ::instantsend::InstantSendSigner; }; } // namespace llmq diff --git a/src/instantsend/signing.cpp b/src/instantsend/signing.cpp index ad6d0c0ad3b9..a2e4136b1c22 100644 --- a/src/instantsend/signing.cpp +++ b/src/instantsend/signing.cpp @@ -2,6 +2,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include + #include #include #include @@ -10,7 +12,6 @@ #include #include -#include #include #include #include @@ -26,12 +27,30 @@ using node::fImporting; using node::fReindex; using node::GetTransaction; -namespace llmq { +namespace instantsend { static const std::string_view INPUTLOCK_REQUESTID_PREFIX = "inlock"; -MessageProcessingResult CInstantSendManager::HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) +InstantSendSigner::InstantSendSigner(CChainState& chainstate, llmq::CChainLocksHandler& clhandler, + llmq::CInstantSendManager& isman, llmq::CSigningManager& sigman, + llmq::CSigSharesManager& shareman, llmq::CQuorumManager& qman, + CSporkManager& sporkman, CTxMemPool& mempool, const CMasternodeSync& mn_sync) : + m_chainstate{chainstate}, + m_clhandler{clhandler}, + m_isman{isman}, + m_sigman{sigman}, + m_shareman{shareman}, + m_qman{qman}, + m_sporkman{sporkman}, + m_mempool{mempool}, + m_mn_sync{mn_sync} +{ +} + +InstantSendSigner::~InstantSendSigner() = default; + +MessageProcessingResult InstantSendSigner::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig) { - if (!IsInstantSendEnabled()) { + if (!m_isman.IsInstantSendEnabled()) { return {}; } @@ -51,19 +70,19 @@ MessageProcessingResult CInstantSendManager::HandleNewRecoveredSig(const CRecove return {}; } -bool CInstantSendManager::IsInstantSendMempoolSigningEnabled() const +bool InstantSendSigner::IsInstantSendMempoolSigningEnabled() const { - return !fReindex && !fImporting && spork_manager.GetSporkValue(SPORK_2_INSTANTSEND_ENABLED) == 0; + return !fReindex && !fImporting && m_sporkman.GetSporkValue(SPORK_2_INSTANTSEND_ENABLED) == 0; } -void CInstantSendManager::HandleNewInputLockRecoveredSig(const CRecoveredSig& recoveredSig, const uint256& txid) +void InstantSendSigner::HandleNewInputLockRecoveredSig(const llmq::CRecoveredSig& recoveredSig, const uint256& txid) { if (g_txindex) { g_txindex->BlockUntilSyncedToCurrentChain(); } uint256 hashBlock{}; - const auto tx = GetTransaction(nullptr, &mempool, txid, Params().GetConsensus(), hashBlock); + const auto tx = GetTransaction(nullptr, &m_mempool, txid, Params().GetConsensus(), hashBlock); if (!tx) { return; } @@ -72,7 +91,7 @@ void CInstantSendManager::HandleNewInputLockRecoveredSig(const CRecoveredSig& re for (const auto& in : tx->vin) { auto id = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in.prevout)); if (id == recoveredSig.getId()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: got recovered sig for input %s\n", __func__, + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: got recovered sig for input %s\n", __func__, txid.ToString(), in.prevout.ToStringShort()); break; } @@ -82,15 +101,15 @@ void CInstantSendManager::HandleNewInputLockRecoveredSig(const CRecoveredSig& re TrySignInstantSendLock(*tx); } -void CInstantSendManager::ProcessPendingRetryLockTxs() +void InstantSendSigner::ProcessPendingRetryLockTxs() { - const auto retryTxs = WITH_LOCK(cs_pendingRetry, return pendingRetryTxs); + const auto retryTxs = WITH_LOCK(m_isman.cs_pendingRetry, return m_isman.pendingRetryTxs); if (retryTxs.empty()) { return; } - if (!IsInstantSendEnabled()) { + if (!m_isman.IsInstantSendEnabled()) { return; } @@ -99,9 +118,9 @@ void CInstantSendManager::ProcessPendingRetryLockTxs() CTransactionRef tx; { { - LOCK(cs_nonLocked); - auto it = nonLockedTxs.find(txid); - if (it == nonLockedTxs.end()) { + LOCK(m_isman.cs_nonLocked); + auto it = m_isman.nonLockedTxs.find(txid); + if (it == m_isman.nonLockedTxs.end()) { continue; } tx = it->second.tx; @@ -114,10 +133,10 @@ void CInstantSendManager::ProcessPendingRetryLockTxs() // we're already in the middle of locking this one continue; } - if (IsLocked(tx->GetHash())) { + if (m_isman.IsLocked(tx->GetHash())) { continue; } - if (GetConflictingLock(*tx) != nullptr) { + if (m_isman.GetConflictingLock(*tx) != nullptr) { // should not really happen as we have already filtered these out continue; } @@ -129,7 +148,7 @@ void CInstantSendManager::ProcessPendingRetryLockTxs() if (!CheckCanLock(*tx, false, Params().GetConsensus())) { continue; } - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: retrying to lock\n", __func__, + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: retrying to lock\n", __func__, tx->GetHash().ToString()); } @@ -138,12 +157,12 @@ void CInstantSendManager::ProcessPendingRetryLockTxs() } if (retryCount != 0) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- retried %d TXs. nonLockedTxs.size=%d\n", __func__, - retryCount, WITH_LOCK(cs_nonLocked, return nonLockedTxs.size())); + LogPrint(BCLog::INSTANTSEND, "%s -- retried %d TXs. nonLockedTxs.size=%d\n", __func__, + retryCount, WITH_LOCK(m_isman.cs_nonLocked, return m_isman.nonLockedTxs.size())); } } -bool CInstantSendManager::CheckCanLock(const CTransaction& tx, bool printDebug, const Consensus::Params& params) const +bool InstantSendSigner::CheckCanLock(const CTransaction& tx, bool printDebug, const Consensus::Params& params) const { if (tx.vin.empty()) { // can't lock TXs without inputs (e.g. quorum commitments) @@ -154,30 +173,30 @@ bool CInstantSendManager::CheckCanLock(const CTransaction& tx, bool printDebug, [&](const auto& in) { return CheckCanLock(in.prevout, printDebug, tx.GetHash(), params); }); } -bool CInstantSendManager::CheckCanLock(const COutPoint& outpoint, bool printDebug, const uint256& txHash, const Consensus::Params& params) const +bool InstantSendSigner::CheckCanLock(const COutPoint& outpoint, bool printDebug, const uint256& txHash, const Consensus::Params& params) const { int nInstantSendConfirmationsRequired = params.nInstantSendConfirmationsRequired; - if (IsLocked(outpoint.hash)) { + if (m_isman.IsLocked(outpoint.hash)) { // if prevout was ix locked, allow locking of descendants (no matter if prevout is in mempool or already mined) return true; } - auto mempoolTx = mempool.get(outpoint.hash); + auto mempoolTx = m_mempool.get(outpoint.hash); if (mempoolTx) { if (printDebug) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: parent mempool TX %s is not locked\n", __func__, + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: parent mempool TX %s is not locked\n", __func__, txHash.ToString(), outpoint.hash.ToString()); } return false; } uint256 hashBlock{}; - const auto tx = GetTransaction(nullptr, &mempool, outpoint.hash, params, hashBlock); + const auto tx = GetTransaction(nullptr, &m_mempool, outpoint.hash, params, hashBlock); // this relies on enabled txindex and won't work if we ever try to remove the requirement for txindex for masternodes if (!tx) { if (printDebug) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: failed to find parent TX %s\n", __func__, + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: failed to find parent TX %s\n", __func__, txHash.ToString(), outpoint.hash.ToString()); } return false; @@ -191,9 +210,9 @@ bool CInstantSendManager::CheckCanLock(const COutPoint& outpoint, bool printDebu nTxAge = m_chainstate.m_chain.Height() - pindexMined->nHeight + 1; } - if (nTxAge < nInstantSendConfirmationsRequired && !clhandler.HasChainLock(pindexMined->nHeight, pindexMined->GetBlockHash())) { + if (nTxAge < nInstantSendConfirmationsRequired && !m_clhandler.HasChainLock(pindexMined->nHeight, pindexMined->GetBlockHash())) { if (printDebug) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: outpoint %s too new and not ChainLocked. nTxAge=%d, nInstantSendConfirmationsRequired=%d\n", __func__, + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: outpoint %s too new and not ChainLocked. nTxAge=%d, nInstantSendConfirmationsRequired=%d\n", __func__, txHash.ToString(), outpoint.ToStringShort(), nTxAge, nInstantSendConfirmationsRequired); } return false; @@ -202,9 +221,9 @@ bool CInstantSendManager::CheckCanLock(const COutPoint& outpoint, bool printDebu return true; } -void CInstantSendManager::HandleNewInstantSendLockRecoveredSig(const llmq::CRecoveredSig& recoveredSig) +void InstantSendSigner::HandleNewInstantSendLockRecoveredSig(const llmq::CRecoveredSig& recoveredSig) { - CInstantSendLockPtr islock; + llmq::CInstantSendLockPtr islock; { LOCK(cs_creating); @@ -213,13 +232,13 @@ void CInstantSendManager::HandleNewInstantSendLockRecoveredSig(const llmq::CReco return; } - islock = std::make_shared(std::move(it->second)); + islock = std::make_shared(std::move(it->second)); creatingInstantSendLocks.erase(it); txToCreatingInstantSendLocks.erase(islock->txid); } if (islock->txid != recoveredSig.getMsgHash()) { - LogPrintf("CInstantSendManager::%s -- txid=%s: islock conflicts with %s, dropping own version\n", __func__, + LogPrintf("%s -- txid=%s: islock conflicts with %s, dropping own version\n", __func__, islock->txid.ToString(), recoveredSig.getMsgHash().ToString()); return; } @@ -227,16 +246,16 @@ void CInstantSendManager::HandleNewInstantSendLockRecoveredSig(const llmq::CReco islock->sig = recoveredSig.sig; auto hash = ::SerializeHash(*islock); - if (WITH_LOCK(cs_pendingLocks, return pendingInstantSendLocks.count(hash)) || db.KnownInstantSendLock(hash)) { + if (WITH_LOCK(m_isman.cs_pendingLocks, return m_isman.pendingInstantSendLocks.count(hash)) || m_isman.db.KnownInstantSendLock(hash)) { return; } - LOCK(cs_pendingLocks); - pendingInstantSendLocks.emplace(hash, std::make_pair(-1, islock)); + LOCK(m_isman.cs_pendingLocks); + m_isman.pendingInstantSendLocks.emplace(hash, std::make_pair(-1, islock)); } -void CInstantSendManager::ProcessTx(const CTransaction& tx, bool fRetroactive, const Consensus::Params& params) +void InstantSendSigner::ProcessTx(const CTransaction& tx, bool fRetroactive, const Consensus::Params& params) { - if (!m_is_masternode || !IsInstantSendEnabled() || !m_mn_sync.IsBlockchainSynced()) { + if (!m_isman.IsInstantSendEnabled() || !m_mn_sync.IsBlockchainSynced()) { return; } @@ -245,15 +264,15 @@ void CInstantSendManager::ProcessTx(const CTransaction& tx, bool fRetroactive, c } if (!CheckCanLock(tx, true, params)) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: CheckCanLock returned false\n", __func__, + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: CheckCanLock returned false\n", __func__, tx.GetHash().ToString()); return; } - auto conflictingLock = GetConflictingLock(tx); + auto conflictingLock = m_isman.GetConflictingLock(tx); if (conflictingLock != nullptr) { auto conflictingLockHash = ::SerializeHash(*conflictingLock); - LogPrintf("CInstantSendManager::%s -- txid=%s: conflicts with islock %s, txid=%s\n", __func__, + LogPrintf("%s -- txid=%s: conflicts with islock %s, txid=%s\n", __func__, tx.GetHash().ToString(), conflictingLockHash.ToString(), conflictingLock->txid.ToString()); return; } @@ -273,7 +292,7 @@ void CInstantSendManager::ProcessTx(const CTransaction& tx, bool fRetroactive, c TrySignInstantSendLock(tx); } -bool CInstantSendManager::TrySignInputLocks(const CTransaction& tx, bool fRetroactive, Consensus::LLMQType llmqType, const Consensus::Params& params) +bool InstantSendSigner::TrySignInputLocks(const CTransaction& tx, bool fRetroactive, Consensus::LLMQType llmqType, const Consensus::Params& params) { std::vector ids; ids.reserve(tx.vin.size()); @@ -284,9 +303,9 @@ bool CInstantSendManager::TrySignInputLocks(const CTransaction& tx, bool fRetroa ids.emplace_back(id); uint256 otherTxHash; - if (sigman.GetVoteForId(params.llmqTypeDIP0024InstantSend, id, otherTxHash)) { + if (m_sigman.GetVoteForId(params.llmqTypeDIP0024InstantSend, id, otherTxHash)) { if (otherTxHash != tx.GetHash()) { - LogPrintf("CInstantSendManager::%s -- txid=%s: input %s is conflicting with previous vote for tx %s\n", __func__, + LogPrintf("%s -- txid=%s: input %s is conflicting with previous vote for tx %s\n", __func__, tx.GetHash().ToString(), in.prevout.ToStringShort(), otherTxHash.ToString()); return false; } @@ -294,29 +313,29 @@ bool CInstantSendManager::TrySignInputLocks(const CTransaction& tx, bool fRetroa } // don't even try the actual signing if any input is conflicting - if (sigman.IsConflicting(params.llmqTypeDIP0024InstantSend, id, tx.GetHash())) { - LogPrintf("CInstantSendManager::%s -- txid=%s: sigman.IsConflicting returned true. id=%s\n", __func__, + if (m_sigman.IsConflicting(params.llmqTypeDIP0024InstantSend, id, tx.GetHash())) { + LogPrintf("%s -- txid=%s: m_sigman.IsConflicting returned true. id=%s\n", __func__, tx.GetHash().ToString(), id.ToString()); return false; } } if (!fRetroactive && alreadyVotedCount == ids.size()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: already voted on all inputs, bailing out\n", __func__, + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: already voted on all inputs, bailing out\n", __func__, tx.GetHash().ToString()); return true; } - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: trying to vote on %d inputs\n", __func__, + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: trying to vote on %d inputs\n", __func__, tx.GetHash().ToString(), tx.vin.size()); for (const auto i : irange::range(tx.vin.size())) { const auto& in = tx.vin[i]; auto& id = ids[i]; WITH_LOCK(cs_inputReqests, inputRequestIds.emplace(id)); - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: trying to vote on input %s with id %s. fRetroactive=%d\n", __func__, + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: trying to vote on input %s with id %s. fRetroactive=%d\n", __func__, tx.GetHash().ToString(), in.prevout.ToStringShort(), id.ToString(), fRetroactive); - if (sigman.AsyncSignIfMember(llmqType, shareman, id, tx.GetHash(), {}, fRetroactive)) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: voted on input %s with id %s\n", __func__, + if (m_sigman.AsyncSignIfMember(llmqType, m_shareman, id, tx.GetHash(), {}, fRetroactive)) { + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: voted on input %s with id %s\n", __func__, tx.GetHash().ToString(), in.prevout.ToStringShort(), id.ToString()); } } @@ -324,21 +343,21 @@ bool CInstantSendManager::TrySignInputLocks(const CTransaction& tx, bool fRetroa return true; } -void CInstantSendManager::TrySignInstantSendLock(const CTransaction& tx) +void InstantSendSigner::TrySignInstantSendLock(const CTransaction& tx) { const auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; for (const auto& in : tx.vin) { auto id = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in.prevout)); - if (!sigman.HasRecoveredSig(llmqType, id, tx.GetHash())) { + if (!m_sigman.HasRecoveredSig(llmqType, id, tx.GetHash())) { return; } } - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: got all recovered sigs, creating CInstantSendLock\n", __func__, + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: got all recovered sigs, creating CInstantSendLock\n", __func__, tx.GetHash().ToString()); - CInstantSendLock islock; + llmq::CInstantSendLock islock; islock.txid = tx.GetHash(); for (const auto& in : tx.vin) { islock.inputs.emplace_back(in.prevout); @@ -346,16 +365,16 @@ void CInstantSendManager::TrySignInstantSendLock(const CTransaction& tx) auto id = islock.GetRequestId(); - if (sigman.HasRecoveredSigForId(llmqType, id)) { + if (m_sigman.HasRecoveredSigForId(llmqType, id)) { return; } const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt); - const auto quorum = SelectQuorumForSigning(llmq_params_opt.value(), m_chainstate.m_chain, qman, id); + const auto quorum = llmq::SelectQuorumForSigning(llmq_params_opt.value(), m_chainstate.m_chain, m_qman, id); if (!quorum) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- failed to select quorum. islock id=%s, txid=%s\n", + LogPrint(BCLog::INSTANTSEND, "%s -- failed to select quorum. islock id=%s, txid=%s\n", __func__, id.ToString(), tx.GetHash().ToString()); return; } @@ -373,6 +392,6 @@ void CInstantSendManager::TrySignInstantSendLock(const CTransaction& tx) txToCreatingInstantSendLocks.emplace(tx.GetHash(), &e.first->second); } - sigman.AsyncSignIfMember(llmqType, shareman, id, tx.GetHash(), quorum->m_quorum_base_block_index->GetBlockHash()); + m_sigman.AsyncSignIfMember(llmqType, m_shareman, id, tx.GetHash(), quorum->m_quorum_base_block_index->GetBlockHash()); } -} // namespace llmq +} // namespace instantsend diff --git a/src/instantsend/signing.h b/src/instantsend/signing.h new file mode 100644 index 000000000000..e745e33ac6a5 --- /dev/null +++ b/src/instantsend/signing.h @@ -0,0 +1,98 @@ +// Copyright (c) 2019-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_INSTANTSEND_SIGNING_H +#define BITCOIN_INSTANTSEND_SIGNING_H + +#include +#include +#include + +class CMasternodeSync; +class CSporkManager; +class CTxMemPool; +struct MessageProcessingResult; + +namespace Consensus { +struct Params; +} // namespace Consensus +namespace llmq { +class CChainLocksHandler; +class CInstantSendManager; +class CSigningManager; +class CSigSharesManager; +class CQuorumManager; +} // namespace llmq + +namespace instantsend { +class InstantSendSigner : public llmq::CRecoveredSigsListener +{ +private: + CChainState& m_chainstate; + llmq::CChainLocksHandler& m_clhandler; + llmq::CInstantSendManager& m_isman; + llmq::CSigningManager& m_sigman; + llmq::CSigSharesManager& m_shareman; + llmq::CQuorumManager& m_qman; + CSporkManager& m_sporkman; + CTxMemPool& m_mempool; + const CMasternodeSync& m_mn_sync; + +private: + mutable Mutex cs_inputReqests; + mutable Mutex cs_creating; + + /** + * Request ids of inputs that we signed. Used to determine if a recovered signature belongs to an + * in-progress input lock. + */ + std::unordered_set inputRequestIds GUARDED_BY(cs_inputReqests); + + /** + * These are the islocks that are currently in the middle of being created. Entries are created when we observed + * recovered signatures for all inputs of a TX. At the same time, we initiate signing of our sigshare for the islock. + * When the recovered sig for the islock later arrives, we can finish the islock and propagate it. + */ + std::unordered_map creatingInstantSendLocks GUARDED_BY(cs_creating); + // maps from txid to the in-progress islock + std::unordered_map txToCreatingInstantSendLocks GUARDED_BY(cs_creating); + +public: + explicit InstantSendSigner(CChainState& chainstate, llmq::CChainLocksHandler& clhandler, + llmq::CInstantSendManager& isman, llmq::CSigningManager& sigman, + llmq::CSigSharesManager& shareman, llmq::CQuorumManager& qman, CSporkManager& sporkman, + CTxMemPool& mempool, const CMasternodeSync& mn_sync); + ~InstantSendSigner(); + + [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig) override + EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests, !m_isman.cs_pendingLocks); + +private: + bool CheckCanLock(const CTransaction& tx, bool printDebug, const Consensus::Params& params) const; + bool CheckCanLock(const COutPoint& outpoint, bool printDebug, const uint256& txHash, + const Consensus::Params& params) const; + + void HandleNewInputLockRecoveredSig(const llmq::CRecoveredSig& recoveredSig, const uint256& txid) + EXCLUSIVE_LOCKS_REQUIRED(!cs_creating); + void HandleNewInstantSendLockRecoveredSig(const llmq::CRecoveredSig& recoveredSig) + EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !m_isman.cs_pendingLocks); + + bool IsInstantSendMempoolSigningEnabled() const; + + void ProcessPendingRetryLockTxs() + EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests, !m_isman.cs_nonLocked, !m_isman.cs_pendingRetry); + void ProcessTx(const CTransaction& tx, bool fRetroactive, const Consensus::Params& params) + EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests); + + bool TrySignInputLocks(const CTransaction& tx, bool allowResigning, Consensus::LLMQType llmqType, + const Consensus::Params& params) + EXCLUSIVE_LOCKS_REQUIRED(!cs_inputReqests); + void TrySignInstantSendLock(const CTransaction& tx) + EXCLUSIVE_LOCKS_REQUIRED(!cs_creating); + + friend class ::llmq::CInstantSendManager; +}; +} // namespace instantsend + +#endif // BITCOIN_INSTANTSEND_SIGNING_H diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py index c89eed880066..e9c0efc438e5 100755 --- a/test/lint/lint-circular-dependencies.py +++ b/test/lint/lint-circular-dependencies.py @@ -44,6 +44,7 @@ "governance/governance -> governance/object -> governance/governance", "governance/governance -> masternode/sync -> governance/governance", "governance/governance -> net_processing -> governance/governance", + "instantsend/instantsend -> instantsend/signing -> instantsend/instantsend", "instantsend/instantsend -> llmq/chainlocks -> instantsend/instantsend", "instantsend/instantsend -> net_processing -> instantsend/instantsend", "instantsend/instantsend -> net_processing -> llmq/context -> instantsend/instantsend", From 8d78e7d8970d705bf024f7a841a3a03818591123 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Jul 2025 21:32:27 +0000 Subject: [PATCH 07/10] refactor: remove need for mutual access to private members --- src/instantsend/instantsend.cpp | 77 ++++++++++++++++++++++++--------- src/instantsend/instantsend.h | 10 ++--- src/instantsend/signing.cpp | 61 +++++++++++++------------- src/instantsend/signing.h | 38 +++++++++------- 4 files changed, 112 insertions(+), 74 deletions(-) diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 1c1a77c5a7fd..6364725340de 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -43,6 +43,21 @@ using node::GetTransaction; namespace llmq { static const std::string_view INPUTLOCK_REQUESTID_PREFIX = "inlock"; +namespace { +template + requires std::same_as || std::same_as +std::unordered_set GetIdsFromLockable(const std::vector& vec) +{ + std::unordered_set ret{}; + if (vec.empty()) return ret; + ret.reserve(vec.size()); + for (const auto& in : vec) { + ret.emplace(::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in))); + } + return ret; +} +} // anonymous namespace + CInstantSendManager::CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CQuorumManager& _qman, CSigningManager& _sigman, CSigSharesManager& _shareman, CSporkManager& sporkman, CTxMemPool& _mempool, const CMasternodeSync& mn_sync, @@ -74,14 +89,14 @@ void CInstantSendManager::Start(PeerManager& peerman) workThread = std::thread(&util::TraceThread, "isman", [this, &peerman] { WorkThreadMain(peerman); }); if (m_signer) { - sigman.RegisterRecoveredSigsListener(m_signer.get()); + m_signer->Start(); } } void CInstantSendManager::Stop() { if (m_signer) { - sigman.UnregisterRecoveredSigsListener(m_signer.get()); + m_signer->Stop(); } // make sure to call InterruptWorkerThread() first @@ -344,9 +359,7 @@ void CInstantSendManager::ProcessInstantSendLock(NodeId from, PeerManager& peerm LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: processing islock, peer=%d\n", __func__, islock->txid.ToString(), hash.ToString(), from); if (m_signer) { - LOCK(m_signer->cs_creating); - m_signer->creatingInstantSendLocks.erase(islock->GetRequestId()); - m_signer->txToCreatingInstantSendLocks.erase(islock->txid); + m_signer->ClearLockFromQueue(islock); } if (db.KnownInstantSendLock(hash)) { return; @@ -592,23 +605,28 @@ void CInstantSendManager::RemoveNonLockedTx(const uint256& txid, bool retryChild void CInstantSendManager::RemoveConflictedTx(const CTransaction& tx) { RemoveNonLockedTx(tx.GetHash(), false); - if (!m_signer) return; - - LOCK(m_signer->cs_inputReqests); - for (const auto& in : tx.vin) { - auto inputRequestId = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in)); - m_signer->inputRequestIds.erase(inputRequestId); + if (m_signer) { + m_signer->ClearInputsFromQueue(GetIdsFromLockable(tx.vin)); } } void CInstantSendManager::TruncateRecoveredSigsForInputs(const llmq::CInstantSendLock& islock) { - if (!m_signer) return; + auto ids = GetIdsFromLockable(islock.inputs); + if (m_signer) { + m_signer->ClearInputsFromQueue(ids); + } + for (const auto& id : ids) { + sigman.TruncateRecoveredSig(Params().GetConsensus().llmqTypeDIP0024InstantSend, id); + } +} - for (const auto& in : islock.inputs) { - auto inputRequestId = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in)); - WITH_LOCK(m_signer->cs_inputReqests, m_signer->inputRequestIds.erase(inputRequestId)); - sigman.TruncateRecoveredSig(Params().GetConsensus().llmqTypeDIP0024InstantSend, inputRequestId); +void CInstantSendManager::TryEmplacePendingLock(const uint256& hash, const NodeId id, const CInstantSendLockPtr& islock) +{ + if (db.KnownInstantSendLock(hash)) return; + LOCK(cs_pendingLocks); + if (!pendingInstantSendLocks.count(hash)) { + pendingInstantSendLocks.emplace(hash, std::make_pair(id, islock)); } } @@ -910,10 +928,29 @@ size_t CInstantSendManager::GetInstantSendLockCount() const void CInstantSendManager::WorkThreadMain(PeerManager& peerman) { while (!workInterrupt) { - bool fMoreWork = ProcessPendingInstantSendLocks(peerman); - if (m_signer) { - m_signer->ProcessPendingRetryLockTxs(); - } + bool fMoreWork = [&]() -> bool { + if (!IsInstantSendEnabled()) return false; + const bool more_work{ProcessPendingInstantSendLocks(peerman)}; + if (!m_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 + m_signer->ProcessPendingRetryLockTxs(txns); + return more_work; + }(); if (!fMoreWork && !workInterrupt.sleep_for(std::chrono::milliseconds(100))) { return; diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index 652f97bd0ce2..6c3f1c2600ea 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -120,11 +120,7 @@ class CInstantSendManager EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); void WorkThreadMain(PeerManager& peerman) - NO_THREAD_SAFETY_ANALYSIS; - // Needed as compiler cannot differentiate between negative capability against member and against - // member accessed through reference. - // TODO: Remove this, it's terrible. - // EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); void HandleFullyConfirmedBlock(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); @@ -154,6 +150,8 @@ class CInstantSendManager EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); void RemoveConflictingLock(const uint256& islockHash, const CInstantSendLock& islock); + void TryEmplacePendingLock(const uint256& hash, const NodeId id, const CInstantSendLockPtr& islock) + EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); size_t GetInstantSendLockCount() const; @@ -164,8 +162,6 @@ class CInstantSendManager * allows ChainLocks to continue even while this spork is disabled. */ bool RejectConflictingBlocks() const; - - friend class ::instantsend::InstantSendSigner; }; } // namespace llmq diff --git a/src/instantsend/signing.cpp b/src/instantsend/signing.cpp index a2e4136b1c22..1053182afa5c 100644 --- a/src/instantsend/signing.cpp +++ b/src/instantsend/signing.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include @@ -48,6 +48,31 @@ InstantSendSigner::InstantSendSigner(CChainState& chainstate, llmq::CChainLocksH InstantSendSigner::~InstantSendSigner() = default; +void InstantSendSigner::Start() +{ + m_sigman.RegisterRecoveredSigsListener(this); +} + +void InstantSendSigner::Stop() +{ + m_sigman.UnregisterRecoveredSigsListener(this); +} + +void InstantSendSigner::ClearInputsFromQueue(const std::unordered_set& ids) +{ + LOCK(cs_inputReqests); + for (const auto& id : ids) { + inputRequestIds.erase(id); + } +} + +void InstantSendSigner::ClearLockFromQueue(const llmq::CInstantSendLockPtr& islock) +{ + LOCK(cs_creating); + creatingInstantSendLocks.erase(islock->GetRequestId()); + txToCreatingInstantSendLocks.erase(islock->txid); +} + MessageProcessingResult InstantSendSigner::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig) { if (!m_isman.IsInstantSendEnabled()) { @@ -101,34 +126,15 @@ void InstantSendSigner::HandleNewInputLockRecoveredSig(const llmq::CRecoveredSig TrySignInstantSendLock(*tx); } -void InstantSendSigner::ProcessPendingRetryLockTxs() +void InstantSendSigner::ProcessPendingRetryLockTxs(const std::vector& retryTxs) { - const auto retryTxs = WITH_LOCK(m_isman.cs_pendingRetry, return m_isman.pendingRetryTxs); - - if (retryTxs.empty()) { - return; - } - if (!m_isman.IsInstantSendEnabled()) { return; } int retryCount = 0; - for (const auto& txid : retryTxs) { - CTransactionRef tx; + for (const auto& tx : retryTxs) { { - { - LOCK(m_isman.cs_nonLocked); - auto it = m_isman.nonLockedTxs.find(txid); - if (it == m_isman.nonLockedTxs.end()) { - continue; - } - tx = it->second.tx; - } - if (!tx) { - continue; - } - if (LOCK(cs_creating); txToCreatingInstantSendLocks.count(tx->GetHash())) { // we're already in the middle of locking this one continue; @@ -157,8 +163,7 @@ void InstantSendSigner::ProcessPendingRetryLockTxs() } if (retryCount != 0) { - LogPrint(BCLog::INSTANTSEND, "%s -- retried %d TXs. nonLockedTxs.size=%d\n", __func__, - retryCount, WITH_LOCK(m_isman.cs_nonLocked, return m_isman.nonLockedTxs.size())); + LogPrint(BCLog::INSTANTSEND, "%s -- retried %d TXs.\n", __func__, retryCount); } } @@ -244,13 +249,7 @@ void InstantSendSigner::HandleNewInstantSendLockRecoveredSig(const llmq::CRecove } islock->sig = recoveredSig.sig; - auto hash = ::SerializeHash(*islock); - - if (WITH_LOCK(m_isman.cs_pendingLocks, return m_isman.pendingInstantSendLocks.count(hash)) || m_isman.db.KnownInstantSendLock(hash)) { - return; - } - LOCK(m_isman.cs_pendingLocks); - m_isman.pendingInstantSendLocks.emplace(hash, std::make_pair(-1, islock)); + m_isman.TryEmplacePendingLock(/*hash=*/::SerializeHash(*islock), /*id=*/-1, islock); } void InstantSendSigner::ProcessTx(const CTransaction& tx, bool fRetroactive, const Consensus::Params& params) diff --git a/src/instantsend/signing.h b/src/instantsend/signing.h index e745e33ac6a5..a5523795ff30 100644 --- a/src/instantsend/signing.h +++ b/src/instantsend/signing.h @@ -5,7 +5,6 @@ #ifndef BITCOIN_INSTANTSEND_SIGNING_H #define BITCOIN_INSTANTSEND_SIGNING_H -#include #include #include @@ -65,33 +64,40 @@ class InstantSendSigner : public llmq::CRecoveredSigsListener CTxMemPool& mempool, const CMasternodeSync& mn_sync); ~InstantSendSigner(); + void Start(); + void Stop(); + + void ClearInputsFromQueue(const std::unordered_set& ids) + EXCLUSIVE_LOCKS_REQUIRED(!cs_inputReqests); + + void ClearLockFromQueue(const llmq::CInstantSendLockPtr& islock) + EXCLUSIVE_LOCKS_REQUIRED(!cs_creating); + [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig) override - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests, !m_isman.cs_pendingLocks); + EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests); + + void ProcessPendingRetryLockTxs(const std::vector& retryTxs) + EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests); + void ProcessTx(const CTransaction& tx, bool fRetroactive, const Consensus::Params& params) + EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests); private: - bool CheckCanLock(const CTransaction& tx, bool printDebug, const Consensus::Params& params) const; - bool CheckCanLock(const COutPoint& outpoint, bool printDebug, const uint256& txHash, - const Consensus::Params& params) const; + [[nodiscard]] bool CheckCanLock(const CTransaction& tx, bool printDebug, const Consensus::Params& params) const; + [[nodiscard]] bool CheckCanLock(const COutPoint& outpoint, bool printDebug, const uint256& txHash, + const Consensus::Params& params) const; void HandleNewInputLockRecoveredSig(const llmq::CRecoveredSig& recoveredSig, const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(!cs_creating); void HandleNewInstantSendLockRecoveredSig(const llmq::CRecoveredSig& recoveredSig) - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !m_isman.cs_pendingLocks); + EXCLUSIVE_LOCKS_REQUIRED(!cs_creating); - bool IsInstantSendMempoolSigningEnabled() const; + [[nodiscard]] bool IsInstantSendMempoolSigningEnabled() const; - void ProcessPendingRetryLockTxs() - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests, !m_isman.cs_nonLocked, !m_isman.cs_pendingRetry); - void ProcessTx(const CTransaction& tx, bool fRetroactive, const Consensus::Params& params) - EXCLUSIVE_LOCKS_REQUIRED(!cs_creating, !cs_inputReqests); - - bool TrySignInputLocks(const CTransaction& tx, bool allowResigning, Consensus::LLMQType llmqType, - const Consensus::Params& params) + [[nodiscard]] bool TrySignInputLocks(const CTransaction& tx, bool allowResigning, Consensus::LLMQType llmqType, + const Consensus::Params& params) EXCLUSIVE_LOCKS_REQUIRED(!cs_inputReqests); void TrySignInstantSendLock(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(!cs_creating); - - friend class ::llmq::CInstantSendManager; }; } // namespace instantsend From b4d1bd22d9e388290815d58c7663daa87321e180 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Jul 2025 15:24:03 +0000 Subject: [PATCH 08/10] refactor: `llmq::CInstantSendLock{,Ptr}` > `instantsend::InstantSendLock{,Ptr}` --- src/instantsend/db.cpp | 22 +++++++++++----------- src/instantsend/db.h | 16 ++++++++-------- src/instantsend/instantsend.cpp | 28 ++++++++++++++-------------- src/instantsend/instantsend.h | 26 +++++++++++++------------- src/instantsend/lock.cpp | 8 ++++---- src/instantsend/lock.h | 12 ++++++------ src/instantsend/signing.cpp | 10 +++++----- src/instantsend/signing.h | 6 +++--- src/interfaces/chain.h | 6 ++++-- src/net_processing.cpp | 2 +- src/node/interfaces.cpp | 2 +- src/rpc/rawtransaction.cpp | 2 +- src/test/evo_islock_tests.cpp | 6 +++--- src/validationinterface.cpp | 2 +- src/validationinterface.h | 21 ++++++++++----------- src/wallet/wallet.cpp | 2 +- src/wallet/wallet.h | 2 +- src/zmq/zmqabstractnotifier.cpp | 2 +- src/zmq/zmqabstractnotifier.h | 22 ++++++++++------------ src/zmq/zmqnotificationinterface.cpp | 2 +- src/zmq/zmqnotificationinterface.h | 2 +- src/zmq/zmqpublishnotifier.cpp | 6 +++--- src/zmq/zmqpublishnotifier.h | 6 +++--- 23 files changed, 106 insertions(+), 107 deletions(-) diff --git a/src/instantsend/db.cpp b/src/instantsend/db.cpp index ac06ee934b24..dbd3596ee757 100644 --- a/src/instantsend/db.cpp +++ b/src/instantsend/db.cpp @@ -50,7 +50,7 @@ void CInstantSendDb::Upgrade(bool unitTests) } } -void CInstantSendDb::WriteNewInstantSendLock(const uint256& hash, const llmq::CInstantSendLock& islock) +void CInstantSendDb::WriteNewInstantSendLock(const uint256& hash, const InstantSendLock& islock) { LOCK(cs_db); CDBBatch batch(*db); @@ -61,14 +61,14 @@ void CInstantSendDb::WriteNewInstantSendLock(const uint256& hash, const llmq::CI } db->WriteBatch(batch); - islockCache.insert(hash, std::make_shared(islock)); + islockCache.insert(hash, std::make_shared(islock)); txidCache.insert(islock.txid, hash); for (const auto& in : islock.inputs) { outpointCache.insert(in, hash); } } -void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, llmq::CInstantSendLockPtr islock, bool keep_cache) +void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, InstantSendLockPtr islock, bool keep_cache) { AssertLockHeld(cs_db); if (!islock) { @@ -120,7 +120,7 @@ void CInstantSendDb::WriteInstantSendLockArchived(CDBBatch& batch, const uint256 batch.Write(std::make_tuple(DB_ARCHIVED_BY_HASH, hash), true); } -std::unordered_map CInstantSendDb::RemoveConfirmedInstantSendLocks(int nUntilHeight) +std::unordered_map CInstantSendDb::RemoveConfirmedInstantSendLocks(int nUntilHeight) { LOCK(cs_db); if (nUntilHeight <= best_confirmed_height) { @@ -137,7 +137,7 @@ std::unordered_map CInst it->Seek(firstKey); CDBBatch batch(*db); - std::unordered_map ret; + std::unordered_map ret; while (it->Valid()) { decltype(firstKey) curKey; if (!it->GetKey(curKey) || std::get<0>(curKey) != DB_MINED_BY_HEIGHT_AND_HASH) { @@ -267,22 +267,22 @@ size_t CInstantSendDb::GetInstantSendLockCount() const return cnt; } -llmq::CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByHashInternal(const uint256& hash, bool use_cache) const +InstantSendLockPtr CInstantSendDb::GetInstantSendLockByHashInternal(const uint256& hash, bool use_cache) const { AssertLockHeld(cs_db); if (hash.IsNull()) { return nullptr; } - llmq::CInstantSendLockPtr ret; + InstantSendLockPtr ret; if (use_cache && islockCache.get(hash, ret)) { return ret; } - ret = std::make_shared(); + ret = std::make_shared(); bool exists = db->Read(std::make_tuple(DB_ISLOCK_BY_HASH, hash), *ret); if (!exists || (::SerializeHash(*ret) != hash)) { - ret = std::make_shared(); + ret = std::make_shared(); exists = db->Read(std::make_tuple(DB_ISLOCK_BY_HASH, hash), *ret); if (!exists || (::SerializeHash(*ret) != hash)) { ret = nullptr; @@ -305,13 +305,13 @@ uint256 CInstantSendDb::GetInstantSendLockHashByTxidInternal(const uint256& txid return islockHash; } -llmq::CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByTxid(const uint256& txid) const +InstantSendLockPtr CInstantSendDb::GetInstantSendLockByTxid(const uint256& txid) const { LOCK(cs_db); return GetInstantSendLockByHashInternal(GetInstantSendLockHashByTxidInternal(txid)); } -llmq::CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByInput(const COutPoint& outpoint) const +InstantSendLockPtr CInstantSendDb::GetInstantSendLockByInput(const COutPoint& outpoint) const { LOCK(cs_db); uint256 islockHash; diff --git a/src/instantsend/db.h b/src/instantsend/db.h index 26f90a25c19a..178171d7ea2d 100644 --- a/src/instantsend/db.h +++ b/src/instantsend/db.h @@ -36,7 +36,7 @@ class CInstantSendDb int best_confirmed_height GUARDED_BY(cs_db) {0}; std::unique_ptr db GUARDED_BY(cs_db) {nullptr}; - mutable unordered_lru_cache islockCache GUARDED_BY(cs_db); + mutable unordered_lru_cache islockCache GUARDED_BY(cs_db); mutable unordered_lru_cache txidCache GUARDED_BY(cs_db); mutable unordered_lru_cache outpointCache GUARDED_BY(cs_db); @@ -51,7 +51,7 @@ class CInstantSendDb * @param islock The InstantSend Lock object itself * @param keep_cache Should we still keep corresponding entries in the cache or not */ - void RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, llmq::CInstantSendLockPtr islock, bool keep_cache = true) EXCLUSIVE_LOCKS_REQUIRED(cs_db); + void RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, InstantSendLockPtr islock, bool keep_cache = true) EXCLUSIVE_LOCKS_REQUIRED(cs_db); /** * Marks an InstantSend Lock as archived. * @param batch Object used to batch many calls together @@ -69,7 +69,7 @@ class CInstantSendDb /** * See GetInstantSendLockByHash */ - llmq::CInstantSendLockPtr GetInstantSendLockByHashInternal(const uint256& hash, bool use_cache = true) const EXCLUSIVE_LOCKS_REQUIRED(cs_db); + InstantSendLockPtr GetInstantSendLockByHashInternal(const uint256& hash, bool use_cache = true) const EXCLUSIVE_LOCKS_REQUIRED(cs_db); /** * See GetInstantSendLockHashByTxid @@ -88,7 +88,7 @@ class CInstantSendDb * @param hash The hash of the InstantSend Lock * @param islock The InstantSend Lock object itself */ - void WriteNewInstantSendLock(const uint256& hash, const llmq::CInstantSendLock& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + void WriteNewInstantSendLock(const uint256& hash, const InstantSendLock& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); /** * This method updates a DB entry for an InstantSend Lock from being not included in a block to being included in a block * @param hash The hash of the InstantSend Lock @@ -100,7 +100,7 @@ class CInstantSendDb * @param nUntilHeight Removes all IS Locks confirmed up until nUntilHeight * @return returns an unordered_map of the hash of the IS Locks and a pointer object to the IS Locks for all IS Locks which were removed */ - std::unordered_map RemoveConfirmedInstantSendLocks(int nUntilHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + std::unordered_map RemoveConfirmedInstantSendLocks(int nUntilHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); /** * Removes IS Locks from the archive if the tx was confirmed 100 blocks before nUntilHeight * @param nUntilHeight the height from which to base the remove of archive IS Locks @@ -120,7 +120,7 @@ class CInstantSendDb * @param use_cache Should we try using the cache first or not * @return A Pointer object to the IS Lock, returns nullptr if it doesn't exist */ - llmq::CInstantSendLockPtr GetInstantSendLockByHash(const uint256& hash, bool use_cache = true) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db) + InstantSendLockPtr GetInstantSendLockByHash(const uint256& hash, bool use_cache = true) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db) { LOCK(cs_db); return GetInstantSendLockByHashInternal(hash, use_cache); @@ -140,13 +140,13 @@ class CInstantSendDb * @param txid The txid for which the IS Lock Pointer is being returned * @return Returns the IS Lock Pointer associated with the txid, returns nullptr if it doesn't exist */ - llmq::CInstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + InstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); /** * Gets an IS Lock pointer from an input given * @param outpoint Since all inputs are really just outpoints that are being spent * @return IS Lock Pointer associated with that input. */ - llmq::CInstantSendLockPtr GetInstantSendLockByInput(const COutPoint& outpoint) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + InstantSendLockPtr GetInstantSendLockByInput(const COutPoint& outpoint) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); /** * Called when a ChainLock invalidated a IS Lock, removes any chained/children IS Locks and the invalidated IS Lock * @param islockHash IS Lock hash which has been invalidated diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 6364725340de..52cf2f870cbf 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -113,7 +113,7 @@ PeerMsgRet CInstantSendManager::ProcessMessage(const CNode& pfrom, PeerManager& CDataStream& vRecv) { if (IsInstantSendEnabled() && msg_type == NetMsgType::ISDLOCK) { - const auto islock = std::make_shared(); + const auto islock = std::make_shared(); vRecv >> *islock; return ProcessMessageInstantSendLock(pfrom, peerman, islock); } @@ -125,7 +125,7 @@ bool ShouldReportISLockTiming() { } PeerMsgRet CInstantSendManager::ProcessMessageInstantSendLock(const CNode& pfrom, PeerManager& peerman, - const llmq::CInstantSendLockPtr& islock) + const instantsend::InstantSendLockPtr& islock) { auto hash = ::SerializeHash(*islock); @@ -245,7 +245,7 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks(PeerManager& peerman) std::unordered_set CInstantSendManager::ProcessPendingInstantSendLocks( const Consensus::LLMQParams& llmq_params, PeerManager& peerman, int signOffset, - const std::unordered_map, StaticSaltedHasher>& pend, bool ban) + const std::unordered_map, StaticSaltedHasher>& pend, bool ban) { CBLSBatchVerifier batchVerifier(false, true, 8); std::unordered_map recSigs; @@ -354,7 +354,7 @@ std::unordered_set CInstantSendManager::ProcessPend } void CInstantSendManager::ProcessInstantSendLock(NodeId from, PeerManager& peerman, const uint256& hash, - const CInstantSendLockPtr& islock) + const instantsend::InstantSendLockPtr& islock) { LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: processing islock, peer=%d\n", __func__, islock->txid.ToString(), hash.ToString(), from); @@ -440,7 +440,7 @@ void CInstantSendManager::TransactionAddedToMempool(PeerManager& peerman, const return; } - CInstantSendLockPtr islock{nullptr}; + instantsend::InstantSendLockPtr islock{nullptr}; { LOCK(cs_pendingLocks); auto it = pendingNoTxInstantSendLocks.begin(); @@ -475,7 +475,7 @@ void CInstantSendManager::TransactionRemovedFromMempool(const CTransactionRef& t return; } - CInstantSendLockPtr islock = db.GetInstantSendLockByTxid(tx->GetHash()); + instantsend::InstantSendLockPtr islock = db.GetInstantSendLockByTxid(tx->GetHash()); if (islock == nullptr) { return; @@ -610,7 +610,7 @@ void CInstantSendManager::RemoveConflictedTx(const CTransaction& tx) } } -void CInstantSendManager::TruncateRecoveredSigsForInputs(const llmq::CInstantSendLock& islock) +void CInstantSendManager::TruncateRecoveredSigsForInputs(const instantsend::InstantSendLock& islock) { auto ids = GetIdsFromLockable(islock.inputs); if (m_signer) { @@ -621,7 +621,7 @@ void CInstantSendManager::TruncateRecoveredSigsForInputs(const llmq::CInstantSen } } -void CInstantSendManager::TryEmplacePendingLock(const uint256& hash, const NodeId id, const CInstantSendLockPtr& islock) +void CInstantSendManager::TryEmplacePendingLock(const uint256& hash, const NodeId id, const instantsend::InstantSendLockPtr& islock) { if (db.KnownInstantSendLock(hash)) return; LOCK(cs_pendingLocks); @@ -695,7 +695,7 @@ void CInstantSendManager::HandleFullyConfirmedBlock(const CBlockIndex* pindex) } void CInstantSendManager::RemoveMempoolConflictsForLock(PeerManager& peerman, const uint256& hash, - const CInstantSendLock& islock) + const instantsend::InstantSendLock& islock) { std::unordered_map toDelete; @@ -728,7 +728,7 @@ void CInstantSendManager::RemoveMempoolConflictsForLock(PeerManager& peerman, co } } -void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const llmq::CInstantSendLock& islock) +void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const instantsend::InstantSendLock& islock) { // Lets first collect all non-locked TXs which conflict with the given ISLOCK std::unordered_map> conflicts; @@ -816,7 +816,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const } } -void CInstantSendManager::RemoveConflictingLock(const uint256& islockHash, const llmq::CInstantSendLock& islock) +void CInstantSendManager::RemoveConflictingLock(const uint256& islockHash, const instantsend::InstantSendLock& islock) { LogPrintf("CInstantSendManager::%s -- txid=%s, islock=%s: Removing ISLOCK and its chained children\n", __func__, islock.txid.ToString(), islockHash.ToString()); @@ -839,7 +839,7 @@ bool CInstantSendManager::AlreadyHave(const CInv& inv) const || db.KnownInstantSendLock(inv.hash); } -bool CInstantSendManager::GetInstantSendLockByHash(const uint256& hash, llmq::CInstantSendLock& ret) const +bool CInstantSendManager::GetInstantSendLockByHash(const uint256& hash, instantsend::InstantSendLock& ret) const { if (!IsInstantSendEnabled()) { return false; @@ -864,7 +864,7 @@ bool CInstantSendManager::GetInstantSendLockByHash(const uint256& hash, llmq::CI return true; } -CInstantSendLockPtr CInstantSendManager::GetInstantSendLockByTxid(const uint256& txid) const +instantsend::InstantSendLockPtr CInstantSendManager::GetInstantSendLockByTxid(const uint256& txid) const { if (!IsInstantSendEnabled()) { return nullptr; @@ -901,7 +901,7 @@ bool CInstantSendManager::IsWaitingForTx(const uint256& txHash) const return false; } -CInstantSendLockPtr CInstantSendManager::GetConflictingLock(const CTransaction& tx) const +instantsend::InstantSendLockPtr CInstantSendManager::GetConflictingLock(const CTransaction& tx) const { if (!IsInstantSendEnabled()) { return nullptr; diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index 6c3f1c2600ea..3d253a419d0e 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -61,9 +61,9 @@ class CInstantSendManager mutable Mutex cs_pendingLocks; // Incoming and not verified yet - std::unordered_map, StaticSaltedHasher> pendingInstantSendLocks GUARDED_BY(cs_pendingLocks); + std::unordered_map, StaticSaltedHasher> pendingInstantSendLocks GUARDED_BY(cs_pendingLocks); // Tried to verify but there is no tx yet - std::unordered_map, StaticSaltedHasher> pendingNoTxInstantSendLocks GUARDED_BY(cs_pendingLocks); + std::unordered_map, StaticSaltedHasher> pendingNoTxInstantSendLocks GUARDED_BY(cs_pendingLocks); // TXs which are neither IS locked nor ChainLocked. We use this to determine for which TXs we need to retry IS locking // of child TXs @@ -95,15 +95,15 @@ class CInstantSendManager void InterruptWorkerThread() { workInterrupt(); }; private: - PeerMsgRet ProcessMessageInstantSendLock(const CNode& pfrom, PeerManager& peerman, const CInstantSendLockPtr& islock); + PeerMsgRet ProcessMessageInstantSendLock(const CNode& pfrom, PeerManager& peerman, const instantsend::InstantSendLockPtr& islock); bool ProcessPendingInstantSendLocks(PeerManager& peerman) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); std::unordered_set ProcessPendingInstantSendLocks( const Consensus::LLMQParams& llmq_params, PeerManager& peerman, int signOffset, - const std::unordered_map, StaticSaltedHasher>& pend, bool ban) + const std::unordered_map, StaticSaltedHasher>& pend, bool ban) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); - void ProcessInstantSendLock(NodeId from, PeerManager& peerman, const uint256& hash, const CInstantSendLockPtr& islock) + void ProcessInstantSendLock(NodeId from, PeerManager& peerman, const uint256& hash, const instantsend::InstantSendLockPtr& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); void AddNonLockedTx(const CTransactionRef& tx, const CBlockIndex* pindexMined) @@ -112,11 +112,11 @@ class CInstantSendManager EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); void RemoveConflictedTx(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); - void TruncateRecoveredSigsForInputs(const CInstantSendLock& islock); + void TruncateRecoveredSigsForInputs(const instantsend::InstantSendLock& islock); - void RemoveMempoolConflictsForLock(PeerManager& peerman, const uint256& hash, const CInstantSendLock& islock) + void RemoveMempoolConflictsForLock(PeerManager& peerman, const uint256& hash, const instantsend::InstantSendLock& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); - void ResolveBlockConflicts(const uint256& islockHash, const CInstantSendLock& islock) + void ResolveBlockConflicts(const uint256& islockHash, const instantsend::InstantSendLock& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); void WorkThreadMain(PeerManager& peerman) @@ -128,7 +128,7 @@ class CInstantSendManager public: bool IsLocked(const uint256& txHash) const; bool IsWaitingForTx(const uint256& txHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); - CInstantSendLockPtr GetConflictingLock(const CTransaction& tx) const; + instantsend::InstantSendLockPtr GetConflictingLock(const CTransaction& tx) const; PeerMsgRet ProcessMessage(const CNode& pfrom, PeerManager& peerman, std::string_view msg_type, CDataStream& vRecv); @@ -140,17 +140,17 @@ class CInstantSendManager void BlockDisconnected(const std::shared_ptr& pblock, const CBlockIndex* pindexDisconnected); bool AlreadyHave(const CInv& inv) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); - bool GetInstantSendLockByHash(const uint256& hash, CInstantSendLock& ret) const + bool GetInstantSendLockByHash(const uint256& hash, instantsend::InstantSendLock& ret) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); - CInstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const; + instantsend::InstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const; void NotifyChainLock(const CBlockIndex* pindexChainLock) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); void UpdatedBlockTip(const CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); - void RemoveConflictingLock(const uint256& islockHash, const CInstantSendLock& islock); - void TryEmplacePendingLock(const uint256& hash, const NodeId id, const CInstantSendLockPtr& islock) + void RemoveConflictingLock(const uint256& islockHash, const instantsend::InstantSendLock& islock); + void TryEmplacePendingLock(const uint256& hash, const NodeId id, const instantsend::InstantSendLockPtr& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); size_t GetInstantSendLockCount() const; diff --git a/src/instantsend/lock.cpp b/src/instantsend/lock.cpp index c94b8b8273a5..3d093db77806 100644 --- a/src/instantsend/lock.cpp +++ b/src/instantsend/lock.cpp @@ -12,8 +12,8 @@ static const std::string_view ISLOCK_REQUESTID_PREFIX = "islock"; -namespace llmq { -uint256 CInstantSendLock::GetRequestId() const +namespace instantsend { +uint256 InstantSendLock::GetRequestId() const { CHashWriter hw(SER_GETHASH, 0); hw << ISLOCK_REQUESTID_PREFIX; @@ -25,7 +25,7 @@ uint256 CInstantSendLock::GetRequestId() const * Handles trivial ISLock verification * @return returns false if verification failed, otherwise true */ -bool CInstantSendLock::TriviallyValid() const +bool InstantSendLock::TriviallyValid() const { if (txid.IsNull() || inputs.empty()) { return false; @@ -41,4 +41,4 @@ bool CInstantSendLock::TriviallyValid() const return true; } -} // namespace llmq +} // namespace instantsend diff --git a/src/instantsend/lock.h b/src/instantsend/lock.h index fddd0bcde3de..5223ce5f9a76 100644 --- a/src/instantsend/lock.h +++ b/src/instantsend/lock.h @@ -15,8 +15,8 @@ class COutPoint; -namespace llmq { -struct CInstantSendLock { +namespace instantsend { +struct InstantSendLock { static constexpr uint8_t CURRENT_VERSION{1}; uint8_t nVersion{CURRENT_VERSION}; @@ -25,9 +25,9 @@ struct CInstantSendLock { uint256 cycleHash; CBLSLazySignature sig; - CInstantSendLock() = default; + InstantSendLock() = default; - SERIALIZE_METHODS(CInstantSendLock, obj) + SERIALIZE_METHODS(InstantSendLock, obj) { READWRITE(obj.nVersion); READWRITE(obj.inputs); @@ -40,7 +40,7 @@ struct CInstantSendLock { bool TriviallyValid() const; }; -using CInstantSendLockPtr = std::shared_ptr; -} // namespace llmq +using InstantSendLockPtr = std::shared_ptr; +} // namespace instantsend #endif // BITCOIN_INSTANTSEND_LOCK_H diff --git a/src/instantsend/signing.cpp b/src/instantsend/signing.cpp index 1053182afa5c..63bbcd13677a 100644 --- a/src/instantsend/signing.cpp +++ b/src/instantsend/signing.cpp @@ -66,7 +66,7 @@ void InstantSendSigner::ClearInputsFromQueue(const std::unordered_setGetRequestId()); @@ -228,7 +228,7 @@ bool InstantSendSigner::CheckCanLock(const COutPoint& outpoint, bool printDebug, void InstantSendSigner::HandleNewInstantSendLockRecoveredSig(const llmq::CRecoveredSig& recoveredSig) { - llmq::CInstantSendLockPtr islock; + InstantSendLockPtr islock; { LOCK(cs_creating); @@ -237,7 +237,7 @@ void InstantSendSigner::HandleNewInstantSendLockRecoveredSig(const llmq::CRecove return; } - islock = std::make_shared(std::move(it->second)); + islock = std::make_shared(std::move(it->second)); creatingInstantSendLocks.erase(it); txToCreatingInstantSendLocks.erase(islock->txid); } @@ -353,10 +353,10 @@ void InstantSendSigner::TrySignInstantSendLock(const CTransaction& tx) } } - LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: got all recovered sigs, creating CInstantSendLock\n", __func__, + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: got all recovered sigs, creating InstantSendLock\n", __func__, tx.GetHash().ToString()); - llmq::CInstantSendLock islock; + InstantSendLock islock; islock.txid = tx.GetHash(); for (const auto& in : tx.vin) { islock.inputs.emplace_back(in.prevout); diff --git a/src/instantsend/signing.h b/src/instantsend/signing.h index a5523795ff30..1256fcdefe08 100644 --- a/src/instantsend/signing.h +++ b/src/instantsend/signing.h @@ -53,9 +53,9 @@ class InstantSendSigner : public llmq::CRecoveredSigsListener * recovered signatures for all inputs of a TX. At the same time, we initiate signing of our sigshare for the islock. * When the recovered sig for the islock later arrives, we can finish the islock and propagate it. */ - std::unordered_map creatingInstantSendLocks GUARDED_BY(cs_creating); + std::unordered_map creatingInstantSendLocks GUARDED_BY(cs_creating); // maps from txid to the in-progress islock - std::unordered_map txToCreatingInstantSendLocks GUARDED_BY(cs_creating); + std::unordered_map txToCreatingInstantSendLocks GUARDED_BY(cs_creating); public: explicit InstantSendSigner(CChainState& chainstate, llmq::CChainLocksHandler& clhandler, @@ -70,7 +70,7 @@ class InstantSendSigner : public llmq::CRecoveredSigsListener void ClearInputsFromQueue(const std::unordered_set& ids) EXCLUSIVE_LOCKS_REQUIRED(!cs_inputReqests); - void ClearLockFromQueue(const llmq::CInstantSendLockPtr& islock) + void ClearLockFromQueue(const InstantSendLockPtr& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_creating); [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig) override diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 753b158055ae..5dc214fa54a7 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -31,9 +31,11 @@ enum class MemPoolRemovalReason; struct bilingual_str; struct CBlockLocator; struct FeeCalculation; +namespace instantsend { +struct InstantSendLock; +} // namespace instantsend namespace llmq { class CChainLockSig; -struct CInstantSendLock; } // namespace llmq namespace node { struct NodeContext; @@ -266,7 +268,7 @@ class Chain virtual void updatedBlockTip() {} virtual void chainStateFlushed(const CBlockLocator& locator) {} virtual void notifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr& clsig) {} - virtual void notifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) {} + virtual void notifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) {} }; //! Register handler for notifications. diff --git a/src/net_processing.cpp b/src/net_processing.cpp index b1f8def7b296..37d2fabf3bb4 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -2866,7 +2866,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic } if (!push && inv.type == MSG_ISDLOCK) { - llmq::CInstantSendLock o; + instantsend::InstantSendLock o; if (m_llmq_ctx->isman->GetInstantSendLockByHash(inv.hash, o)) { m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::ISDLOCK, o)); push = true; diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index b475c7fd5bee..b9b96e18082c 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -657,7 +657,7 @@ class NotificationsProxy : public CValidationInterface { m_notifications->notifyChainLock(pindexChainLock, clsig); } - void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) override + void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) override { m_notifications->notifyTransactionLock(tx, islock); } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 6c403e6f459b..0ad984c98faa 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -456,7 +456,7 @@ static RPCHelpMan getislocks() for (const auto idx : irange::range(txids.size())) { const uint256 txid(ParseHashV(txids[idx], "txid")); - if (const llmq::CInstantSendLockPtr islock = llmq_ctx.isman->GetInstantSendLockByTxid(txid); islock != nullptr) { + if (const instantsend::InstantSendLockPtr islock = llmq_ctx.isman->GetInstantSendLockByTxid(txid); islock != nullptr) { UniValue objIS(UniValue::VOBJ); objIS.pushKV("txid", islock->txid.ToString()); UniValue inputs(UniValue::VARR); diff --git a/src/test/evo_islock_tests.cpp b/src/test/evo_islock_tests.cpp index 42d50c0ee31b..fc4d6abe962b 100644 --- a/src/test/evo_islock_tests.cpp +++ b/src/test/evo_islock_tests.cpp @@ -24,10 +24,10 @@ uint256 CalculateRequestId(const std::vector& inputs) BOOST_AUTO_TEST_CASE(getrequestid) { // Create an empty InstantSendLock - llmq::CInstantSendLock islock; + instantsend::InstantSendLock islock; // Compute expected hash for an empty inputs vector. - // Note: CInstantSendLock::GetRequestId() serializes the prefix "islock" + // Note: InstantSendLock::GetRequestId() serializes the prefix "islock" // followed by the 'inputs' vector. { const uint256 expected = CalculateRequestId(islock.inputs); @@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(deserialize_instantlock_from_realdata2) // Convert hex string to a byte vector and deserialize. std::vector islockData = ParseHex(islockHex); CDataStream ss(islockData, SER_NETWORK, PROTOCOL_VERSION); - llmq::CInstantSendLock islock; + instantsend::InstantSendLock islock; ss >> islock; // Verify the calculated signHash diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 1758621965b9..ffdcafaa64d0 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -269,7 +269,7 @@ void CMainSignals::NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDo m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyHeaderTip(pindexNew, fInitialDownload); }); } -void CMainSignals::NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) { +void CMainSignals::NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) { auto event = [tx, islock, this] { m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyTransactionLock(tx, islock); }); }; diff --git a/src/validationinterface.h b/src/validationinterface.h index 281fad978bfa..5cb6bb96edcb 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -25,16 +25,15 @@ class CDeterministicMNListDiff; class uint256; class CScheduler; enum class MemPoolRemovalReason; - -namespace Governance -{ - class Object; -} - +namespace Governance { +class Object; +} // namespace Governance +namespace instantsend { +struct InstantSendLock; +} // namespace instantsend namespace llmq { - class CChainLockSig; - struct CInstantSendLock; - class CRecoveredSig; +class CChainLockSig; +class CRecoveredSig; } // namespace llmq /** Register subscriber */ @@ -164,7 +163,7 @@ class CValidationInterface { * Called on a background thread. */ virtual void BlockDisconnected(const std::shared_ptr &block, const CBlockIndex *pindex) {} - virtual void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) {} + virtual void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) {} virtual void NotifyChainLock(const CBlockIndex* pindex, const std::shared_ptr& clsig) {} virtual void NotifyGovernanceVote(const std::shared_ptr& tip_mn_list, const std::shared_ptr& vote) {} virtual void NotifyGovernanceObject(const std::shared_ptr& object) {} @@ -232,7 +231,7 @@ class CMainSignals { void TransactionRemovedFromMempool(const CTransactionRef&, MemPoolRemovalReason, uint64_t mempool_sequence); void BlockConnected(const std::shared_ptr &, const CBlockIndex *pindex); void BlockDisconnected(const std::shared_ptr &, const CBlockIndex* pindex); - void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock); + void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock); void NotifyChainLock(const CBlockIndex* pindex, const std::shared_ptr& clsig, const std::string& id); void NotifyGovernanceVote(const std::shared_ptr& tip_mn_list, const std::shared_ptr& vote, const std::string& id); void NotifyGovernanceObject(const std::shared_ptr& object, const std::string& id); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index c28e23fabe07..8883f3a0f41b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3409,7 +3409,7 @@ bool CWallet::AutoBackupWallet(const fs::path& wallet_path, bilingual_str& error } #endif // USE_BDB -void CWallet::notifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) +void CWallet::notifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) { LOCK(cs_wallet); // Only notify UI if this transaction is in this wallet diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index f59cc4de6da6..adf0329c650c 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -921,7 +921,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati /* Returns true if the wallet can give out new addresses. This means it has keys in the keypool or can generate new keys */ bool CanGetAddresses(bool internal = false) const; - void notifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) override; + void notifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) override; void notifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr& clsig) override; /** Load a CGovernanceObject into m_gobjects. */ diff --git a/src/zmq/zmqabstractnotifier.cpp b/src/zmq/zmqabstractnotifier.cpp index aa3feb605f70..f65aae46724a 100644 --- a/src/zmq/zmqabstractnotifier.cpp +++ b/src/zmq/zmqabstractnotifier.cpp @@ -48,7 +48,7 @@ bool CZMQAbstractNotifier::NotifyTransactionRemoval(const CTransaction &/*transa return true; } -bool CZMQAbstractNotifier::NotifyTransactionLock(const CTransactionRef &/*transaction*/, const std::shared_ptr& /*islock*/) +bool CZMQAbstractNotifier::NotifyTransactionLock(const CTransactionRef &/*transaction*/, const std::shared_ptr& /*islock*/) { return true; } diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h index c1a7dc67f882..c292eedd9cfc 100644 --- a/src/zmq/zmqabstractnotifier.h +++ b/src/zmq/zmqabstractnotifier.h @@ -14,20 +14,18 @@ class CDeterministicMNList; class CGovernanceVote; class CTransaction; class CZMQAbstractNotifier; - -typedef std::shared_ptr CTransactionRef; - -namespace Governance -{ - class Object; -} //namespace Governance - +namespace Governance { +class Object; +} // namespace Governance +namespace instantsend { +struct InstantSendLock; +} // namespace instantsend namespace llmq { - class CChainLockSig; - struct CInstantSendLock; - class CRecoveredSig; +class CChainLockSig; +class CRecoveredSig; } // namespace llmq +using CTransactionRef = std::shared_ptr; using CZMQNotifierFactory = std::unique_ptr (*)(); class CZMQAbstractNotifier @@ -71,7 +69,7 @@ class CZMQAbstractNotifier // Notifies of transactions added to mempool or appearing in blocks virtual bool NotifyTransaction(const CTransaction &transaction); virtual bool NotifyChainLock(const CBlockIndex *pindex, const std::shared_ptr& clsig); - virtual bool NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock); + virtual bool NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock); virtual bool NotifyGovernanceVote(const std::shared_ptr& tip_mn_list, const std::shared_ptr& vote); virtual bool NotifyGovernanceObject(const std::shared_ptr& object); virtual bool NotifyInstantSendDoubleSpendAttempt(const CTransactionRef& currentTx, const CTransactionRef& previousTx); diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index 82b683154001..dd1f5f8bbc8f 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -213,7 +213,7 @@ void CZMQNotificationInterface::BlockDisconnected(const std::shared_ptr& islock) +void CZMQNotificationInterface::NotifyTransactionLock(const CTransactionRef& tx, const std::shared_ptr& islock) { TryForEachAndRemoveFailed(notifiers, [&tx, &islock](CZMQAbstractNotifier* notifier) { return notifier->NotifyTransactionLock(tx, islock); diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h index 70510fee07fa..e42479df66be 100644 --- a/src/zmq/zmqnotificationinterface.h +++ b/src/zmq/zmqnotificationinterface.h @@ -32,7 +32,7 @@ class CZMQNotificationInterface final : public CValidationInterface void BlockDisconnected(const std::shared_ptr& pblock, const CBlockIndex* pindexDisconnected) override; void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override; void NotifyChainLock(const CBlockIndex *pindex, const std::shared_ptr& clsig) override; - void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) override; + void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr& islock) override; void NotifyGovernanceVote(const std::shared_ptr& tip_mn_list, const std::shared_ptr& vote) override; void NotifyGovernanceObject(const std::shared_ptr& object) override; void NotifyInstantSendDoubleSpendAttempt(const CTransactionRef& currentTx, const CTransactionRef& previousTx) override; diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index 230c6db71a75..017afcb30086 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -253,7 +253,7 @@ bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &t return SendZmqMessage(MSG_HASHTX, data, 32); } -bool CZMQPublishHashTransactionLockNotifier::NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) +bool CZMQPublishHashTransactionLockNotifier::NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) { uint256 hash = transaction->GetHash(); LogPrint(BCLog::ZMQ, "Publish hashtxlock %s to %s\n", hash.GetHex(), this->address); @@ -415,7 +415,7 @@ bool CZMQPublishSequenceNotifier::NotifyTransactionRemoval(const CTransaction &t return SendSequenceMsg(*this, hash, /* Mempool (R)emoval */ 'R', mempool_sequence); } -bool CZMQPublishRawTransactionLockNotifier::NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) +bool CZMQPublishRawTransactionLockNotifier::NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) { uint256 hash = transaction->GetHash(); LogPrint(BCLog::ZMQ, "Publish rawtxlock %s to %s\n", hash.GetHex(), this->address); @@ -424,7 +424,7 @@ bool CZMQPublishRawTransactionLockNotifier::NotifyTransactionLock(const CTransac return SendZmqMessage(MSG_RAWTXLOCK, &(*ss.begin()), ss.size()); } -bool CZMQPublishRawTransactionLockSigNotifier::NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) +bool CZMQPublishRawTransactionLockSigNotifier::NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) { uint256 hash = transaction->GetHash(); LogPrint(BCLog::ZMQ, "Publish rawtxlocksig %s to %s\n", hash.GetHex(), this->address); diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h index 2bcb3c068446..507db059291b 100644 --- a/src/zmq/zmqpublishnotifier.h +++ b/src/zmq/zmqpublishnotifier.h @@ -57,7 +57,7 @@ class CZMQPublishHashTransactionNotifier : public CZMQAbstractPublishNotifier class CZMQPublishHashTransactionLockNotifier : public CZMQAbstractPublishNotifier { public: - bool NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) override; + bool NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) override; }; class CZMQPublishHashGovernanceVoteNotifier : public CZMQAbstractPublishNotifier @@ -120,13 +120,13 @@ class CZMQPublishSequenceNotifier : public CZMQAbstractPublishNotifier class CZMQPublishRawTransactionLockNotifier : public CZMQAbstractPublishNotifier { public: - bool NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) override; + bool NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) override; }; class CZMQPublishRawTransactionLockSigNotifier : public CZMQAbstractPublishNotifier { public: - bool NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) override; + bool NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) override; }; class CZMQPublishRawGovernanceVoteNotifier : public CZMQAbstractPublishNotifier From d1de786e28a0ac68c2d5ac00a58682855df367cd Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:58:34 +0000 Subject: [PATCH 09/10] chore: cleanup unused headers from instantsend (dependent) sources --- src/instantsend/instantsend.cpp | 6 ------ src/instantsend/instantsend.h | 28 +++++++++++++++------------- src/rpc/mining.cpp | 1 - src/test/fuzz/process_message.cpp | 1 - src/test/miner_tests.cpp | 1 - 5 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 52cf2f870cbf..b46b6ceee3d4 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -6,24 +6,18 @@ #include #include -#include -#include #include #include #include #include -#include -#include #include #include #include -#include #include #include #include #include -#include #include #include diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index 3d253a419d0e..1e4f3c4e764f 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -5,18 +5,16 @@ #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 @@ -24,18 +22,22 @@ class CBlockIndex; class CChainState; -class CConnman; -class CDBWrapper; +class CDataStream; class CMasternodeSync; +class CNode; class CSporkManager; +class CTxMemPool; class PeerManager; - +namespace Consensus { +struct LLMQParams; +} // namespace Consensus namespace instantsend { class InstantSendSigner; } // namespace instantsend -namespace llmq -{ +using NodeId = int64_t; + +namespace llmq { class CChainLocksHandler; class CQuorumManager; class CSigningManager; diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 9367f5160c51..5f498d654cb0 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index 9e9c1696192b..5b458ba0a541 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 6ef2a0189e0d..8447a5e927da 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include From 6360725db965101dd99dd975257f15001e508bef Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Jul 2025 15:30:22 +0000 Subject: [PATCH 10/10] chore: resolve incomplete/missing copyright headers in unit tests --- src/test/cachemap_tests.cpp | 2 ++ src/test/cachemultimap_tests.cpp | 2 ++ src/test/evo_islock_tests.cpp | 4 ++++ src/test/governance_validators_tests.cpp | 2 ++ src/test/ratecheck_tests.cpp | 2 ++ 5 files changed, 12 insertions(+) diff --git a/src/test/cachemap_tests.cpp b/src/test/cachemap_tests.cpp index d8c4a8bc2e9a..5ee98bcd76a6 100644 --- a/src/test/cachemap_tests.cpp +++ b/src/test/cachemap_tests.cpp @@ -1,4 +1,6 @@ // Copyright (c) 2014-2023 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 diff --git a/src/test/cachemultimap_tests.cpp b/src/test/cachemultimap_tests.cpp index 61f78204ffed..e0a4ae6fff8b 100644 --- a/src/test/cachemultimap_tests.cpp +++ b/src/test/cachemultimap_tests.cpp @@ -1,4 +1,6 @@ // Copyright (c) 2014-2023 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 diff --git a/src/test/evo_islock_tests.cpp b/src/test/evo_islock_tests.cpp index fc4d6abe962b..1e35775c235f 100644 --- a/src/test/evo_islock_tests.cpp +++ b/src/test/evo_islock_tests.cpp @@ -1,3 +1,7 @@ +// 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 diff --git a/src/test/governance_validators_tests.cpp b/src/test/governance_validators_tests.cpp index f3bf4199f8b2..deb74d40dfea 100644 --- a/src/test/governance_validators_tests.cpp +++ b/src/test/governance_validators_tests.cpp @@ -1,4 +1,6 @@ // Copyright (c) 2014-2023 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 diff --git a/src/test/ratecheck_tests.cpp b/src/test/ratecheck_tests.cpp index 5c248e842264..9a97b9be22c1 100644 --- a/src/test/ratecheck_tests.cpp +++ b/src/test/ratecheck_tests.cpp @@ -1,4 +1,6 @@ // Copyright (c) 2014-2022 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. #include