From 48fccdd010b3c191133ce7cfc5227475ff83c46c Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 24 Feb 2025 21:26:11 +0000 Subject: [PATCH 01/12] refactor: introduce `coinjoin status` for information on mix sessions This helps us get rid of having to report it through `coinjoin start`. Additionally, we won't try to jump ahead of the scheduler by starting denomination routines ourselves, let the scheduler run its course. This matters because we don't plan on exposing that capability through the interface as we are migrating to the interface in the next commit. --- doc/release-notes-6594.md | 7 +++++ src/coinjoin/client.cpp | 13 ++++----- src/coinjoin/client.h | 2 +- src/rpc/coinjoin.cpp | 47 +++++++++++++++++++++++++++++---- test/functional/rpc_coinjoin.py | 4 +++ 5 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 doc/release-notes-6594.md diff --git a/doc/release-notes-6594.md b/doc/release-notes-6594.md new file mode 100644 index 0000000000000..2f28971807229 --- /dev/null +++ b/doc/release-notes-6594.md @@ -0,0 +1,7 @@ +Updated RPCs +------------ + +* `coinjoin status` is a new RPC that reports the status message of all running mix + sessions. +* `coinjoin start` will no longer report errors from mix sessions, users are recommended + to query the status of mix sessions using `coinjoin status` instead. diff --git a/src/coinjoin/client.cpp b/src/coinjoin/client.cpp index 9becb2b9eea2a..65371ced6e411 100644 --- a/src/coinjoin/client.cpp +++ b/src/coinjoin/client.cpp @@ -350,17 +350,18 @@ bilingual_str CCoinJoinClientSession::GetStatus(bool fWaitForBlock) const } } -bilingual_str CCoinJoinClientManager::GetStatuses() +std::vector CCoinJoinClientManager::GetStatuses() const { - bilingual_str strStatus; - bool fWaitForBlock = WaitForAnotherBlock(); - AssertLockNotHeld(cs_deqsessions); + + bool fWaitForBlock{WaitForAnotherBlock()}; + std::vector ret; + LOCK(cs_deqsessions); for (const auto& session : deqSessions) { - strStatus = strStatus + session.GetStatus(fWaitForBlock) + Untranslated("; "); + ret.push_back(session.GetStatus(fWaitForBlock).original); } - return strStatus; + return ret; } std::string CCoinJoinClientManager::GetSessionDenoms() diff --git a/src/coinjoin/client.h b/src/coinjoin/client.h index dad2fd7638228..6c7e3205ee3b0 100644 --- a/src/coinjoin/client.h +++ b/src/coinjoin/client.h @@ -327,7 +327,7 @@ class CCoinJoinClientManager bool IsMixing() const; void ResetPool() EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); - bilingual_str GetStatuses() EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); + std::vector GetStatuses() const EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); std::string GetSessionDenoms() EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); bool GetMixingMasternodesInfo(std::vector& vecDmnsRet) const EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); diff --git a/src/rpc/coinjoin.cpp b/src/rpc/coinjoin.cpp index 7047b928a8ceb..64cc241508855 100644 --- a/src/rpc/coinjoin.cpp +++ b/src/rpc/coinjoin.cpp @@ -45,6 +45,7 @@ static RPCHelpMan coinjoin() return RPCHelpMan{"coinjoin", "\nAvailable commands:\n" " start - Start mixing\n" + " status - Get mixing status\n" " stop - Stop mixing\n" " reset - Reset mixing", { @@ -129,11 +130,46 @@ static RPCHelpMan coinjoin_start() throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing has been started already."); } - ChainstateManager& chainman = EnsureChainman(node); - CTxMemPool& mempool = EnsureMemPool(node); - CConnman& connman = EnsureConnman(node); - bool result = cj_clientman->DoAutomaticDenominating(chainman, connman, mempool); - return "Mixing " + (result ? "started successfully" : ("start failed: " + cj_clientman->GetStatuses().original + ", will retry")); + return "Mixing requested"; +}, + }; +} + +static RPCHelpMan coinjoin_status() +{ + return RPCHelpMan{"coinjoin status", + "\nGet status on CoinJoin mixing sessions\n", + {}, + RPCResult{ + RPCResult::Type::ARR, "", "", + {{RPCResult::Type::STR, "", "Status of mixing session"}}}, + RPCExamples{ + HelpExampleCli("coinjoin status", "") + + HelpExampleRpc("coinjoin status", "") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + const std::shared_ptr wallet = GetWalletForJSONRPCRequest(request); + if (!wallet) return NullUniValue; + + const NodeContext& node = EnsureAnyNodeContext(request.context); + + if (node.mn_activeman) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Client-side mixing is not supported on masternodes"); + } + + ValidateCoinJoinArguments(); + + auto cj_clientman = CHECK_NONFATAL(node.coinjoin_loader)->walletman().Get(wallet->GetName()); + if (!CHECK_NONFATAL(cj_clientman)->IsMixing()) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "No ongoing mix session"); + } + + UniValue ret(UniValue::VARR); + for (auto str_status : cj_clientman->GetStatuses()) { + ret.push_back(str_status); + } + return ret; }, }; } @@ -460,6 +496,7 @@ static const CRPCCommand commands[] = { "dash", &coinjoin, }, { "dash", &coinjoin_reset, }, { "dash", &coinjoin_start, }, + { "dash", &coinjoin_status, }, { "dash", &coinjoin_stop, }, { "dash", &coinjoinsalt, }, { "dash", &coinjoinsalt_generate, }, diff --git a/test/functional/rpc_coinjoin.py b/test/functional/rpc_coinjoin.py index 35ee13d5f5cd6..00c5ac8cd99e1 100755 --- a/test/functional/rpc_coinjoin.py +++ b/test/functional/rpc_coinjoin.py @@ -66,6 +66,8 @@ def test_coinjoin_start_stop(self, node): assert_equal(cj_info['running'], True) # Repeated start should yield error assert_raises_rpc_error(-32603, 'Mixing has been started already.', node.coinjoin, 'start') + # Requesting status shouldn't complain + node.coinjoin('status') # Stop mix session and ensure it's reported node.coinjoin('stop') @@ -74,6 +76,8 @@ def test_coinjoin_start_stop(self, node): assert_equal(cj_info['running'], False) # Repeated stop should yield error assert_raises_rpc_error(-32603, 'No mix session to stop', node.coinjoin, 'stop') + # Requesting status should tell us off + assert_raises_rpc_error(-32603, 'No ongoing mix session', node.coinjoin, 'status') # Reset mix session assert_equal(node.coinjoin('reset'), "Mixing was reset") From 398e9c3e9502722d32eab546cde93c0406292672 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sat, 22 Feb 2025 15:03:13 +0000 Subject: [PATCH 02/12] refactor: stop exposing `CoinJoinWalletManager` from `CoinJoin::Loader` --- src/coinjoin/interfaces.cpp | 14 ++++++++++---- src/interfaces/coinjoin.h | 6 +++++- src/rpc/coinjoin.cpp | 32 ++++++++++++++++---------------- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/coinjoin/interfaces.cpp b/src/coinjoin/interfaces.cpp index 6c40a3b6d3e07..850f9a516db74 100644 --- a/src/coinjoin/interfaces.cpp +++ b/src/coinjoin/interfaces.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include #include @@ -37,10 +39,18 @@ class CoinJoinClientImpl : public interfaces::CoinJoin::Client { return m_clientman.nCachedNumBlocks; } + void getJsonInfo(UniValue& obj) override + { + return m_clientman.GetJsonInfo(obj); + } std::string getSessionDenoms() override { return m_clientman.GetSessionDenoms(); } + std::vector getSessionStatuses() override + { + return m_clientman.GetStatuses(); + } void setCachedBlocks(int nCachedBlocks) override { m_clientman.nCachedNumBlocks = nCachedBlocks; @@ -81,10 +91,6 @@ class CoinJoinLoaderImpl : public interfaces::CoinJoin::Loader auto clientman = m_walletman.Get(name); return clientman ? std::make_unique(*clientman) : nullptr; } - CoinJoinWalletManager& walletman() override - { - return m_walletman; - } }; } // namespace diff --git a/src/interfaces/coinjoin.h b/src/interfaces/coinjoin.h index 7f881bf07f5c3..9d789df5fe1c5 100644 --- a/src/interfaces/coinjoin.h +++ b/src/interfaces/coinjoin.h @@ -7,10 +7,13 @@ #include #include +#include class CoinJoinWalletManager; class CWallet; +class UniValue; + namespace interfaces { namespace CoinJoin { //! Interface for the wallet constrained src/coinjoin part of a dash node (dashd process). @@ -21,6 +24,8 @@ class Client virtual void resetCachedBlocks() = 0; virtual void resetPool() = 0; virtual int getCachedBlocks() = 0; + virtual void getJsonInfo(UniValue& obj) = 0; + virtual std::vector getSessionStatuses() = 0; virtual std::string getSessionDenoms() = 0; virtual void setCachedBlocks(int nCachedBlocks) = 0; virtual void disableAutobackups() = 0; @@ -38,7 +43,6 @@ class Loader virtual void RemoveWallet(const std::string&) = 0; virtual void FlushWallet(const std::string&) = 0; virtual std::unique_ptr GetClient(const std::string&) = 0; - virtual CoinJoinWalletManager& walletman() = 0; }; } // namespace CoinJoin diff --git a/src/rpc/coinjoin.cpp b/src/rpc/coinjoin.cpp index 64cc241508855..bd7fe17a012ea 100644 --- a/src/rpc/coinjoin.cpp +++ b/src/rpc/coinjoin.cpp @@ -85,8 +85,8 @@ static RPCHelpMan coinjoin_reset() ValidateCoinJoinArguments(); - auto cj_clientman = CHECK_NONFATAL(node.coinjoin_loader)->walletman().Get(wallet->GetName()); - CHECK_NONFATAL(cj_clientman)->ResetPool(); + auto cj_clientman = CHECK_NONFATAL(node.coinjoin_loader)->GetClient(wallet->GetName()); + CHECK_NONFATAL(cj_clientman)->resetPool(); return "Mixing was reset"; }, @@ -125,8 +125,8 @@ static RPCHelpMan coinjoin_start() throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please unlock wallet for mixing with walletpassphrase first."); } - auto cj_clientman = CHECK_NONFATAL(CHECK_NONFATAL(node.coinjoin_loader)->walletman().Get(wallet->GetName())); - if (!cj_clientman->StartMixing()) { + auto cj_clientman = CHECK_NONFATAL(CHECK_NONFATAL(node.coinjoin_loader)->GetClient(wallet->GetName())); + if (!cj_clientman->startMixing()) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing has been started already."); } @@ -160,13 +160,13 @@ static RPCHelpMan coinjoin_status() ValidateCoinJoinArguments(); - auto cj_clientman = CHECK_NONFATAL(node.coinjoin_loader)->walletman().Get(wallet->GetName()); - if (!CHECK_NONFATAL(cj_clientman)->IsMixing()) { + auto cj_clientman = CHECK_NONFATAL(node.coinjoin_loader)->GetClient(wallet->GetName()); + if (!CHECK_NONFATAL(cj_clientman)->isMixing()) { throw JSONRPCError(RPC_INTERNAL_ERROR, "No ongoing mix session"); } UniValue ret(UniValue::VARR); - for (auto str_status : cj_clientman->GetStatuses()) { + for (auto str_status : cj_clientman->getSessionStatuses()) { ret.push_back(str_status); } return ret; @@ -200,13 +200,13 @@ static RPCHelpMan coinjoin_stop() ValidateCoinJoinArguments(); CHECK_NONFATAL(node.coinjoin_loader); - auto cj_clientman = node.coinjoin_loader->walletman().Get(wallet->GetName()); + auto cj_clientman = node.coinjoin_loader->GetClient(wallet->GetName()); CHECK_NONFATAL(cj_clientman); - if (!cj_clientman->IsMixing()) { + if (!cj_clientman->isMixing()) { throw JSONRPCError(RPC_INTERNAL_ERROR, "No mix session to stop"); } - cj_clientman->StopMixing(); + cj_clientman->stopMixing(); return "Mixing was stopped"; }, @@ -270,8 +270,8 @@ static RPCHelpMan coinjoinsalt_generate() const NodeContext& node = EnsureAnyNodeContext(request.context); if (node.coinjoin_loader != nullptr) { - auto cj_clientman = node.coinjoin_loader->walletman().Get(wallet->GetName()); - if (cj_clientman != nullptr && cj_clientman->IsMixing()) { + auto cj_clientman = node.coinjoin_loader->GetClient(wallet->GetName()); + if (cj_clientman != nullptr && cj_clientman->isMixing()) { throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Wallet \"%s\" is currently mixing, cannot change salt!", str_wallet)); } @@ -372,8 +372,8 @@ static RPCHelpMan coinjoinsalt_set() const NodeContext& node = EnsureAnyNodeContext(request.context); if (node.coinjoin_loader != nullptr) { - auto cj_clientman = node.coinjoin_loader->walletman().Get(wallet->GetName()); - if (cj_clientman != nullptr && cj_clientman->IsMixing()) { + auto cj_clientman = node.coinjoin_loader->GetClient(wallet->GetName()); + if (cj_clientman != nullptr && cj_clientman->isMixing()) { throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Wallet \"%s\" is currently mixing, cannot change salt!", str_wallet)); } @@ -467,8 +467,8 @@ static RPCHelpMan getcoinjoininfo() return obj; } - auto* manager = CHECK_NONFATAL(node.coinjoin_loader->walletman().Get(wallet->GetName())); - manager->GetJsonInfo(obj); + auto cj_clientman = CHECK_NONFATAL(node.coinjoin_loader)->GetClient(wallet->GetName()); + CHECK_NONFATAL(cj_clientman)->getJsonInfo(obj); std::string warning_msg{""}; if (wallet->IsLegacy()) { From 27f8d9c1efbb58302bac94a196fa5aad263d8363 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sat, 22 Feb 2025 15:26:45 +0000 Subject: [PATCH 03/12] refactor: defer accessing `CoinJoinWalletManager` to interface call `interfaces::CoinJoin::Loader` relies on `interfaces::WalletLoader` and vice-versa. Currently this isn't explicitly enumerated due to the global wallet state but when that goes away, we will need to defer access to one of them to break the tie. Let's do that now. --- src/coinjoin/interfaces.cpp | 27 +++++++++++++++++++-------- src/init.cpp | 2 +- src/interfaces/coinjoin.h | 4 ++-- src/test/util/setup_common.cpp | 2 +- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/coinjoin/interfaces.cpp b/src/coinjoin/interfaces.cpp index 850f9a516db74..e595efeb3db76 100644 --- a/src/coinjoin/interfaces.cpp +++ b/src/coinjoin/interfaces.cpp @@ -4,7 +4,10 @@ #include +#include #include +#include +#include #include #include @@ -71,31 +74,39 @@ class CoinJoinClientImpl : public interfaces::CoinJoin::Client class CoinJoinLoaderImpl : public interfaces::CoinJoin::Loader { - CoinJoinWalletManager& m_walletman; +private: + CoinJoinWalletManager& walletman() + { + return *Assert(Assert(m_node.cj_ctx)->walletman); + } public: - explicit CoinJoinLoaderImpl(CoinJoinWalletManager& walletman) - : m_walletman(walletman) {} + explicit CoinJoinLoaderImpl(NodeContext& node) : m_node(node) {} - void AddWallet(const std::shared_ptr& wallet) override { m_walletman.Add(wallet); } + void AddWallet(const std::shared_ptr& wallet) override + { + walletman().Add(wallet); + } void RemoveWallet(const std::string& name) override { - m_walletman.Remove(name); + walletman().Remove(name); } void FlushWallet(const std::string& name) override { - m_walletman.Flush(name); + walletman().Flush(name); } std::unique_ptr GetClient(const std::string& name) override { - auto clientman = m_walletman.Get(name); + auto clientman = walletman().Get(name); return clientman ? std::make_unique(*clientman) : nullptr; } + + NodeContext& m_node; }; } // namespace } // namespace coinjoin namespace interfaces { -std::unique_ptr MakeCoinJoinLoader(CoinJoinWalletManager& walletman) { return std::make_unique(walletman); } +std::unique_ptr MakeCoinJoinLoader(NodeContext& node) { return std::make_unique(node); } } // namespace interfaces diff --git a/src/init.cpp b/src/init.cpp index 7be800f83fb2f..26240fb6b1064 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2029,7 +2029,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) !ignores_incoming_txs); #ifdef ENABLE_WALLET - node.coinjoin_loader = interfaces::MakeCoinJoinLoader(*node.cj_ctx->walletman); + node.coinjoin_loader = interfaces::MakeCoinJoinLoader(node); g_wallet_init_interface.InitCoinJoinSettings(*node.cj_ctx->walletman); #endif // ENABLE_WALLET diff --git a/src/interfaces/coinjoin.h b/src/interfaces/coinjoin.h index 9d789df5fe1c5..a96c524080e71 100644 --- a/src/interfaces/coinjoin.h +++ b/src/interfaces/coinjoin.h @@ -9,8 +9,8 @@ #include #include -class CoinJoinWalletManager; class CWallet; +struct NodeContext; class UniValue; @@ -46,7 +46,7 @@ class Loader }; } // namespace CoinJoin -std::unique_ptr MakeCoinJoinLoader(CoinJoinWalletManager& walletman); +std::unique_ptr MakeCoinJoinLoader(NodeContext& node); } // namespace interfaces diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 4014ad6847fed..42a0680a68bcc 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -124,7 +124,7 @@ void DashPostChainstateSetup(NodeContext& node) /*mn_activeman=*/nullptr, *node.mn_sync, *node.llmq_ctx->isman, node.peerman, /*relay_txes=*/true); #ifdef ENABLE_WALLET - node.coinjoin_loader = interfaces::MakeCoinJoinLoader(*node.cj_ctx->walletman); + node.coinjoin_loader = interfaces::MakeCoinJoinLoader(node); #endif // ENABLE_WALLET } From 73671dd3442f61a053567d625242389b3047b1cd Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 23 Feb 2025 07:31:19 +0000 Subject: [PATCH 04/12] refactor: fold `InitCoinJoinSettings` calls into `CoinJoin::Loader` --- src/coinjoin/client.cpp | 20 +++++++------------- src/coinjoin/interfaces.cpp | 13 +++++++++++-- src/init.cpp | 1 - 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/coinjoin/client.cpp b/src/coinjoin/client.cpp index 65371ced6e411..a7e76fd10c100 100644 --- a/src/coinjoin/client.cpp +++ b/src/coinjoin/client.cpp @@ -1915,14 +1915,11 @@ void CCoinJoinClientManager::GetJsonInfo(UniValue& obj) const void CoinJoinWalletManager::Add(const std::shared_ptr& wallet) { - { - LOCK(cs_wallet_manager_map); - m_wallet_manager_map.try_emplace(wallet->GetName(), - std::make_unique(wallet, *this, m_dmnman, m_mn_metaman, - m_mn_sync, m_isman, m_queueman, - m_is_masternode)); - } - g_wallet_init_interface.InitCoinJoinSettings(*this); + LOCK(cs_wallet_manager_map); + m_wallet_manager_map.try_emplace(wallet->GetName(), + std::make_unique(wallet, *this, m_dmnman, m_mn_metaman, + m_mn_sync, m_isman, m_queueman, + m_is_masternode)); } void CoinJoinWalletManager::DoMaintenance(CConnman& connman) @@ -1934,11 +1931,8 @@ void CoinJoinWalletManager::DoMaintenance(CConnman& connman) } void CoinJoinWalletManager::Remove(const std::string& name) { - { - LOCK(cs_wallet_manager_map); - m_wallet_manager_map.erase(name); - } - g_wallet_init_interface.InitCoinJoinSettings(*this); + LOCK(cs_wallet_manager_map); + m_wallet_manager_map.erase(name); } void CoinJoinWalletManager::Flush(const std::string& name) diff --git a/src/coinjoin/interfaces.cpp b/src/coinjoin/interfaces.cpp index e595efeb3db76..ee457ca944426 100644 --- a/src/coinjoin/interfaces.cpp +++ b/src/coinjoin/interfaces.cpp @@ -4,11 +4,13 @@ #include -#include #include +#include +#include #include #include #include +#include #include @@ -81,15 +83,22 @@ class CoinJoinLoaderImpl : public interfaces::CoinJoin::Loader } public: - explicit CoinJoinLoaderImpl(NodeContext& node) : m_node(node) {} + explicit CoinJoinLoaderImpl(NodeContext& node) : + m_node(node) + { + // Enablement will be re-evaluated when a wallet is added or removed + CCoinJoinClientOptions::SetEnabled(false); + } void AddWallet(const std::shared_ptr& wallet) override { walletman().Add(wallet); + g_wallet_init_interface.InitCoinJoinSettings(walletman()); } void RemoveWallet(const std::string& name) override { walletman().Remove(name); + g_wallet_init_interface.InitCoinJoinSettings(walletman()); } void FlushWallet(const std::string& name) override { diff --git a/src/init.cpp b/src/init.cpp index 26240fb6b1064..de74216bf72ae 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2030,7 +2030,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) #ifdef ENABLE_WALLET node.coinjoin_loader = interfaces::MakeCoinJoinLoader(node); - g_wallet_init_interface.InitCoinJoinSettings(*node.cj_ctx->walletman); #endif // ENABLE_WALLET // ********************************************************* Step 7d: Setup other Dash services From b3ac5cfc11c1c80e3cda6f795fd36ea0350dadf4 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 23 Feb 2025 14:06:18 +0000 Subject: [PATCH 05/12] refactor: place `ArgsManager` before `interfaces::CoinJoin::Loader` --- src/dummywallet.cpp | 2 +- src/init/bitcoin-node.cpp | 3 ++- src/init/bitcoind.cpp | 3 ++- src/interfaces/wallet.h | 2 +- src/qt/test/addressbooktests.cpp | 2 +- src/qt/test/wallettests.cpp | 2 +- src/wallet/interfaces.cpp | 6 +++--- src/wallet/test/init_test_fixture.cpp | 2 +- src/wallet/test/wallet_test_fixture.cpp | 2 +- 9 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index 10cd516a00f30..569faeb92c48a 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -85,7 +85,7 @@ std::unique_ptr MakeWallet(const std::shared_ptr& wallet, const throw std::logic_error("Wallet function called in non-wallet build."); } -std::unique_ptr MakeWalletLoader(Chain& chain, const std::unique_ptr& coinjoin_loader, ArgsManager& args) +std::unique_ptr MakeWalletLoader(Chain& chain, ArgsManager& args, const std::unique_ptr& coinjoin_loader) { throw std::logic_error("Wallet function called in non-wallet build."); } diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp index 7300b36731fce..2e5014e02770a 100644 --- a/src/init/bitcoin-node.cpp +++ b/src/init/bitcoin-node.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -31,7 +32,7 @@ class BitcoinNodeInit : public interfaces::Init std::unique_ptr makeChain() override { return interfaces::MakeChain(m_node); } std::unique_ptr makeWalletLoader(interfaces::Chain& chain, const std::unique_ptr& loader) override { - return MakeWalletLoader(chain, loader, *Assert(m_node.args)); + return MakeWalletLoader(chain, *Assert(m_node.args), loader); } std::unique_ptr makeEcho() override { return interfaces::MakeEcho(); } interfaces::Ipc* ipc() override { return m_ipc.get(); } diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp index 1a084227ec1fc..44b044a7f6dd7 100644 --- a/src/init/bitcoind.cpp +++ b/src/init/bitcoind.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -26,7 +27,7 @@ class BitcoindInit : public interfaces::Init std::unique_ptr makeChain() override { return interfaces::MakeChain(m_node); } std::unique_ptr makeWalletLoader(interfaces::Chain& chain, const std::unique_ptr& loader) override { - return MakeWalletLoader(chain, loader, *Assert(m_node.args)); + return MakeWalletLoader(chain, *Assert(m_node.args), loader); } std::unique_ptr makeEcho() override { return interfaces::MakeEcho(); } NodeContext& m_node; diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index d6a0cf413a680..68ff3d00d20b5 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -444,7 +444,7 @@ std::unique_ptr MakeWallet(const std::shared_ptr& wallet); //! Return implementation of ChainClient interface for a wallet loader. This //! function will be undefined in builds where ENABLE_WALLET is false. -std::unique_ptr MakeWalletLoader(Chain& chain, const std::unique_ptr& coinjoin_loader, ArgsManager& args); +std::unique_ptr MakeWalletLoader(Chain& chain, ArgsManager& args, const std::unique_ptr& coinjoin_loader); } // namespace interfaces diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index ede8755afffcc..d0601ab767ca7 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -63,7 +63,7 @@ void EditAddressAndSubmit( void TestAddAddressesToSendBook(interfaces::Node& node) { TestChain100Setup test; - auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, test.m_node.coinjoin_loader, *Assert(test.m_node.args)); + auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args), test.m_node.coinjoin_loader); test.m_node.wallet_loader = wallet_loader.get(); node.setContext(&test.m_node); const std::shared_ptr wallet = std::make_shared(node.context()->chain.get(), node.context()->coinjoin_loader.get(), "", CreateMockWalletDatabase()); diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 4425b91b11118..15d61e6b4fd66 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -108,7 +108,7 @@ void TestGUI(interfaces::Node& node) for (int i = 0; i < 5; ++i) { test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey())); } - auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, test.m_node.coinjoin_loader, *Assert(test.m_node.args)); + auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args), test.m_node.coinjoin_loader); test.m_node.wallet_loader = wallet_loader.get(); node.setContext(&test.m_node); const std::shared_ptr wallet = std::make_shared(node.context()->chain.get(), node.context()->coinjoin_loader.get(), "", CreateMockWalletDatabase()); diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 67a2e5467a5af..f3ba99d4f9822 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -553,7 +553,7 @@ class WalletImpl : public Wallet class WalletLoaderImpl : public WalletLoader { public: - WalletLoaderImpl(Chain& chain, const std::unique_ptr& coinjoin_loader, ArgsManager& args) : + WalletLoaderImpl(Chain& chain, ArgsManager& args, const std::unique_ptr& coinjoin_loader) : m_context(coinjoin_loader) { m_context.chain = &chain; @@ -641,7 +641,7 @@ class WalletLoaderImpl : public WalletLoader namespace interfaces { std::unique_ptr MakeWallet(const std::shared_ptr& wallet) { return wallet ? std::make_unique(wallet) : nullptr; } -std::unique_ptr MakeWalletLoader(Chain& chain, const std::unique_ptr& coinjoin_loader, ArgsManager& args) { - return std::make_unique(chain, coinjoin_loader, args); +std::unique_ptr MakeWalletLoader(Chain& chain, ArgsManager& args, const std::unique_ptr& coinjoin_loader) { + return std::make_unique(chain, args, coinjoin_loader); } } // namespace interfaces diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp index 55d3e0b5d8028..88df028e6fa8a 100644 --- a/src/wallet/test/init_test_fixture.cpp +++ b/src/wallet/test/init_test_fixture.cpp @@ -14,7 +14,7 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainName) : BasicTestingSetup(chainName) { - m_wallet_loader = MakeWalletLoader(*m_node.chain, m_node.coinjoin_loader, *Assert(m_node.args)); + m_wallet_loader = MakeWalletLoader(*m_node.chain, *Assert(m_node.args), m_node.coinjoin_loader); std::string sep; sep += fs::path::preferred_separator; diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp index 93f635da79a9c..a72cd7b667bca 100644 --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -8,7 +8,7 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName) : TestingSetup(chainName), - m_wallet_loader{interfaces::MakeWalletLoader(*m_node.chain, m_node.coinjoin_loader, *Assert(m_node.args))}, + m_wallet_loader{interfaces::MakeWalletLoader(*m_node.chain, *Assert(m_node.args), m_node.coinjoin_loader)}, m_wallet(m_node.chain.get(), m_node.coinjoin_loader.get(), "", CreateMockWalletDatabase()) { m_wallet.LoadWallet(); From b14e55fdf5d36b304d77d3083b3d1105120f7b06 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 23 Feb 2025 13:31:09 +0000 Subject: [PATCH 06/12] chore: fix `MakeWallet` argument list in dummy wallet --- src/dummywallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index 569faeb92c48a..26226fedda14d 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -80,7 +80,7 @@ const WalletInitInterface& g_wallet_init_interface = DummyWalletInit(); namespace interfaces { -std::unique_ptr MakeWallet(const std::shared_ptr& wallet, const CoinJoinWalletManager& cjwalletman) +std::unique_ptr MakeWallet(const std::shared_ptr& wallet) { throw std::logic_error("Wallet function called in non-wallet build."); } From 846dc67de6c27742b3afc034f0eb9a0e40360a1f Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 24 Feb 2025 20:29:23 +0000 Subject: [PATCH 07/12] refactor: initialize CoinJoin loader in `WalletInit::Construct()` --- src/dummywallet.cpp | 5 +++++ src/init.cpp | 4 ---- src/init/bitcoin-node.cpp | 5 +++++ src/init/bitcoind.cpp | 5 +++++ src/interfaces/init.cpp | 2 ++ src/interfaces/init.h | 9 ++++----- src/wallet/init.cpp | 2 ++ src/wallet/test/init_test_fixture.cpp | 3 ++- src/wallet/test/wallet_test_fixture.cpp | 5 +++-- src/wallet/test/wallet_test_fixture.h | 2 ++ 10 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index 26226fedda14d..33e5dbc60e920 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -80,6 +80,11 @@ const WalletInitInterface& g_wallet_init_interface = DummyWalletInit(); namespace interfaces { +std::unique_ptr MakeCoinJoinLoader(NodeContext& node) +{ + throw std::logic_error("Wallet function called in non-wallet build."); +} + std::unique_ptr MakeWallet(const std::shared_ptr& wallet) { throw std::logic_error("Wallet function called in non-wallet build."); diff --git a/src/init.cpp b/src/init.cpp index de74216bf72ae..f1a0a49b020c7 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2028,10 +2028,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.mn_activeman.get(), *node.mn_sync, *node.llmq_ctx->isman, node.peerman, !ignores_incoming_txs); -#ifdef ENABLE_WALLET - node.coinjoin_loader = interfaces::MakeCoinJoinLoader(node); -#endif // ENABLE_WALLET - // ********************************************************* Step 7d: Setup other Dash services bool fLoadCacheFiles = !(fReindex || fReindexChainState) && (chainman.ActiveChain().Tip() != nullptr); diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp index 2e5014e02770a..9d47073fbee54 100644 --- a/src/init/bitcoin-node.cpp +++ b/src/init/bitcoin-node.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include @@ -30,6 +31,10 @@ class BitcoinNodeInit : public interfaces::Init } std::unique_ptr makeNode() override { return interfaces::MakeNode(m_node); } std::unique_ptr makeChain() override { return interfaces::MakeChain(m_node); } + std::unique_ptr makeCoinJoinLoader() override + { + return interfaces::MakeCoinJoinLoader(m_node); + } std::unique_ptr makeWalletLoader(interfaces::Chain& chain, const std::unique_ptr& loader) override { return MakeWalletLoader(chain, *Assert(m_node.args), loader); diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp index 44b044a7f6dd7..1787300ffaa05 100644 --- a/src/init/bitcoind.cpp +++ b/src/init/bitcoind.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include @@ -25,6 +26,10 @@ class BitcoindInit : public interfaces::Init } std::unique_ptr makeNode() override { return interfaces::MakeNode(m_node); } std::unique_ptr makeChain() override { return interfaces::MakeChain(m_node); } + std::unique_ptr makeCoinJoinLoader() override + { + return interfaces::MakeCoinJoinLoader(m_node); + } std::unique_ptr makeWalletLoader(interfaces::Chain& chain, const std::unique_ptr& loader) override { return MakeWalletLoader(chain, *Assert(m_node.args), loader); diff --git a/src/interfaces/init.cpp b/src/interfaces/init.cpp index 8c51948fe8b2d..6a0cf15d07884 100644 --- a/src/interfaces/init.cpp +++ b/src/interfaces/init.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include @@ -11,6 +12,7 @@ namespace interfaces { std::unique_ptr Init::makeNode() { return {}; } std::unique_ptr Init::makeChain() { return {}; } +std::unique_ptr Init::makeCoinJoinLoader() { return {}; } std::unique_ptr Init::makeWalletLoader(Chain& chain, const std::unique_ptr&) { return {}; } std::unique_ptr Init::makeEcho() { return {}; } Ipc* Init::ipc() { return nullptr; } diff --git a/src/interfaces/init.h b/src/interfaces/init.h index 75779e6e1b1db..30e1c4b3860bd 100644 --- a/src/interfaces/init.h +++ b/src/interfaces/init.h @@ -15,11 +15,9 @@ class Echo; class Ipc; class Node; class WalletLoader; - -namespace CoinJoin -{ - class Loader; -} +namespace CoinJoin { +class Loader; +} // namespace CoinJoin //! Initial interface created when a process is first started, and used to give //! and get access to other interfaces (Node, Chain, Wallet, etc). @@ -34,6 +32,7 @@ class Init virtual ~Init() = default; virtual std::unique_ptr makeNode(); virtual std::unique_ptr makeChain(); + virtual std::unique_ptr makeCoinJoinLoader(); virtual std::unique_ptr makeWalletLoader(interfaces::Chain&, const std::unique_ptr&); virtual std::unique_ptr makeEcho(); virtual Ipc* ipc(); diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index a141317d9f2fc..a125b05e162df 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -188,6 +189,7 @@ void WalletInit::Construct(NodeContext& node) const LogPrintf("Wallet disabled!\n"); return; } + node.coinjoin_loader = node.init->makeCoinJoinLoader(); auto wallet_loader = node.init->makeWalletLoader(*node.chain, node.coinjoin_loader); node.wallet_loader = wallet_loader.get(); node.chain_clients.emplace_back(std::move(wallet_loader)); diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp index 88df028e6fa8a..96e29be52aaba 100644 --- a/src/wallet/test/init_test_fixture.cpp +++ b/src/wallet/test/init_test_fixture.cpp @@ -14,7 +14,8 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainName) : BasicTestingSetup(chainName) { - m_wallet_loader = MakeWalletLoader(*m_node.chain, *Assert(m_node.args), m_node.coinjoin_loader); + m_coinjoin_loader = interfaces::MakeCoinJoinLoader(m_node); + m_wallet_loader = MakeWalletLoader(*m_node.chain, *Assert(m_node.args), m_coinjoin_loader); std::string sep; sep += fs::path::preferred_separator; diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp index a72cd7b667bca..adbe91613799d 100644 --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -8,8 +8,9 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName) : TestingSetup(chainName), - m_wallet_loader{interfaces::MakeWalletLoader(*m_node.chain, *Assert(m_node.args), m_node.coinjoin_loader)}, - m_wallet(m_node.chain.get(), m_node.coinjoin_loader.get(), "", CreateMockWalletDatabase()) + m_coinjoin_loader{interfaces::MakeCoinJoinLoader(m_node)}, + m_wallet_loader{interfaces::MakeWalletLoader(*m_node.chain, *Assert(m_node.args), m_coinjoin_loader)}, + m_wallet(m_node.chain.get(), m_coinjoin_loader.get(), "", CreateMockWalletDatabase()) { m_wallet.LoadWallet(); m_chain_notifications_handler = m_node.chain->handleNotifications({ &m_wallet, [](CWallet*) {} }); diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h index 752c8940888ac..c72693d1a7741 100644 --- a/src/wallet/test/wallet_test_fixture.h +++ b/src/wallet/test/wallet_test_fixture.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -21,6 +22,7 @@ struct WalletTestingSetup : public TestingSetup { explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); ~WalletTestingSetup(); + std::unique_ptr m_coinjoin_loader; std::unique_ptr m_wallet_loader; CWallet m_wallet; std::unique_ptr m_chain_notifications_handler; From 0760ae0959e791de3a16767cc12d631af247469e Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 23 Feb 2025 10:25:05 +0000 Subject: [PATCH 08/12] fix: resolve undefined reference linking error in `bench_dash` The previous commit removes the invocation of `MakeCoinJoinLoader` from `init.cpp`. For some reason this makes the linker unhappy when working with `bench_dash`. Fix it by adding the wallet library to `test_util`. ``` /usr/bin/ld: libtest_util.a(libtest_util_a-setup_common.o): in function `DashPostChainstateSetup(NodeContext&)': /src/dash/src/test/util/setup_common.cpp:127:(.text+0x1a8e): undefined reference to `interfaces::MakeCoinJoinLoader(NodeContext&)' collect2: error: ld returned 1 exit status ``` --- src/Makefile.test_util.include | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include index 5e17e398b1be9..ec3b0a27a6dc2 100644 --- a/src/Makefile.test_util.include +++ b/src/Makefile.test_util.include @@ -43,3 +43,6 @@ LIBTEST_UTIL += $(LIBBITCOIN_SERVER) LIBTEST_UTIL += $(LIBBITCOIN_COMMON) LIBTEST_UTIL += $(LIBBITCOIN_UTIL) LIBTEST_UTIL += $(LIBBITCOIN_CRYPTO_BASE) +if ENABLE_WALLET +LIBTEST_UTIL += $(LIBBITCOIN_WALLET) +endif From 0d8de7314c8ebbc7d2e4a6a1259571aec71eb3cc Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sat, 22 Feb 2025 20:17:14 +0000 Subject: [PATCH 09/12] refactor: make `WalletContext::coinjoin_loader` a pointer We now initialize the CoinJoin loader before initializing the wallet loader thanks to deferred access to `CoinJoinWalletManager`, so we no longer need the smart pointer ref workaround. --- src/dummywallet.cpp | 2 +- src/init/bitcoin-node.cpp | 4 ++-- src/init/bitcoind.cpp | 4 ++-- src/interfaces/init.cpp | 2 +- src/interfaces/init.h | 2 +- src/interfaces/wallet.h | 2 +- src/qt/test/addressbooktests.cpp | 2 +- src/qt/test/wallettests.cpp | 2 +- src/wallet/context.cpp | 4 +--- src/wallet/context.h | 6 ++---- src/wallet/init.cpp | 2 +- src/wallet/interfaces.cpp | 17 +++++++---------- src/wallet/rpcwallet.cpp | 6 +++--- src/wallet/test/init_test_fixture.cpp | 2 +- src/wallet/test/wallet_test_fixture.cpp | 2 +- 15 files changed, 26 insertions(+), 33 deletions(-) diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index 33e5dbc60e920..148f75f465bba 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -90,7 +90,7 @@ std::unique_ptr MakeWallet(const std::shared_ptr& wallet) throw std::logic_error("Wallet function called in non-wallet build."); } -std::unique_ptr MakeWalletLoader(Chain& chain, ArgsManager& args, const std::unique_ptr& coinjoin_loader) +std::unique_ptr MakeWalletLoader(Chain& chain, ArgsManager& args, interfaces::CoinJoin::Loader& coinjoin_loader) { throw std::logic_error("Wallet function called in non-wallet build."); } diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp index 9d47073fbee54..33a87b355fe41 100644 --- a/src/init/bitcoin-node.cpp +++ b/src/init/bitcoin-node.cpp @@ -35,9 +35,9 @@ class BitcoinNodeInit : public interfaces::Init { return interfaces::MakeCoinJoinLoader(m_node); } - std::unique_ptr makeWalletLoader(interfaces::Chain& chain, const std::unique_ptr& loader) override + std::unique_ptr makeWalletLoader(interfaces::Chain& chain, interfaces::CoinJoin::Loader& coinjoin_loader) override { - return MakeWalletLoader(chain, *Assert(m_node.args), loader); + return MakeWalletLoader(chain, *Assert(m_node.args), coinjoin_loader); } std::unique_ptr makeEcho() override { return interfaces::MakeEcho(); } interfaces::Ipc* ipc() override { return m_ipc.get(); } diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp index 1787300ffaa05..f04f89338c633 100644 --- a/src/init/bitcoind.cpp +++ b/src/init/bitcoind.cpp @@ -30,9 +30,9 @@ class BitcoindInit : public interfaces::Init { return interfaces::MakeCoinJoinLoader(m_node); } - std::unique_ptr makeWalletLoader(interfaces::Chain& chain, const std::unique_ptr& loader) override + std::unique_ptr makeWalletLoader(interfaces::Chain& chain, interfaces::CoinJoin::Loader& coinjoin_loader) override { - return MakeWalletLoader(chain, *Assert(m_node.args), loader); + return MakeWalletLoader(chain, *Assert(m_node.args), coinjoin_loader); } std::unique_ptr makeEcho() override { return interfaces::MakeEcho(); } NodeContext& m_node; diff --git a/src/interfaces/init.cpp b/src/interfaces/init.cpp index 6a0cf15d07884..797049d2438dc 100644 --- a/src/interfaces/init.cpp +++ b/src/interfaces/init.cpp @@ -13,7 +13,7 @@ namespace interfaces { std::unique_ptr Init::makeNode() { return {}; } std::unique_ptr Init::makeChain() { return {}; } std::unique_ptr Init::makeCoinJoinLoader() { return {}; } -std::unique_ptr Init::makeWalletLoader(Chain& chain, const std::unique_ptr&) { return {}; } +std::unique_ptr Init::makeWalletLoader(Chain& chain, CoinJoin::Loader& coinjoin_loader) { return {}; } std::unique_ptr Init::makeEcho() { return {}; } Ipc* Init::ipc() { return nullptr; } } // namespace interfaces diff --git a/src/interfaces/init.h b/src/interfaces/init.h index 30e1c4b3860bd..c1c6edab81481 100644 --- a/src/interfaces/init.h +++ b/src/interfaces/init.h @@ -33,7 +33,7 @@ class Init virtual std::unique_ptr makeNode(); virtual std::unique_ptr makeChain(); virtual std::unique_ptr makeCoinJoinLoader(); - virtual std::unique_ptr makeWalletLoader(interfaces::Chain&, const std::unique_ptr&); + virtual std::unique_ptr makeWalletLoader(interfaces::Chain&, CoinJoin::Loader&); virtual std::unique_ptr makeEcho(); virtual Ipc* ipc(); }; diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 68ff3d00d20b5..5f31da0318bd8 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -444,7 +444,7 @@ std::unique_ptr MakeWallet(const std::shared_ptr& wallet); //! Return implementation of ChainClient interface for a wallet loader. This //! function will be undefined in builds where ENABLE_WALLET is false. -std::unique_ptr MakeWalletLoader(Chain& chain, ArgsManager& args, const std::unique_ptr& coinjoin_loader); +std::unique_ptr MakeWalletLoader(Chain& chain, ArgsManager& args, CoinJoin::Loader& coinjoin_loader); } // namespace interfaces diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index d0601ab767ca7..dd2ffa4b76cb5 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -63,7 +63,7 @@ void EditAddressAndSubmit( void TestAddAddressesToSendBook(interfaces::Node& node) { TestChain100Setup test; - auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args), test.m_node.coinjoin_loader); + auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args), *Assert(test.m_node.coinjoin_loader)); test.m_node.wallet_loader = wallet_loader.get(); node.setContext(&test.m_node); const std::shared_ptr wallet = std::make_shared(node.context()->chain.get(), node.context()->coinjoin_loader.get(), "", CreateMockWalletDatabase()); diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 15d61e6b4fd66..98ef96bb3e7dd 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -108,7 +108,7 @@ void TestGUI(interfaces::Node& node) for (int i = 0; i < 5; ++i) { test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey())); } - auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args), test.m_node.coinjoin_loader); + auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args), *Assert(test.m_node.coinjoin_loader)); test.m_node.wallet_loader = wallet_loader.get(); node.setContext(&test.m_node); const std::shared_ptr wallet = std::make_shared(node.context()->chain.get(), node.context()->coinjoin_loader.get(), "", CreateMockWalletDatabase()); diff --git a/src/wallet/context.cpp b/src/wallet/context.cpp index d0cd59c8e5183..09b2f30467099 100644 --- a/src/wallet/context.cpp +++ b/src/wallet/context.cpp @@ -4,7 +4,5 @@ #include -WalletContext::WalletContext(const std::unique_ptr& coinjoin_loader) : - m_coinjoin_loader(coinjoin_loader) -{} +WalletContext::WalletContext() {} WalletContext::~WalletContext() {} diff --git a/src/wallet/context.h b/src/wallet/context.h index 059b7f1062395..d3ceba7cfd079 100644 --- a/src/wallet/context.h +++ b/src/wallet/context.h @@ -28,14 +28,12 @@ class Loader; struct WalletContext { interfaces::Chain* chain{nullptr}; ArgsManager* args{nullptr}; - // TODO: replace this unique_ptr to a pointer - // probably possible to do after bitcoin/bitcoin#22219 - const std::unique_ptr& m_coinjoin_loader; + interfaces::CoinJoin::Loader* coinjoin_loader{nullptr}; //! Declare default constructor and destructor that are not inline, so code //! instantiating the WalletContext struct doesn't need to #include class //! definitions for smart pointer and container members. - WalletContext(const std::unique_ptr& coinjoin_loader); + WalletContext(); ~WalletContext(); }; diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index a125b05e162df..f31d8ed2c7d73 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -190,7 +190,7 @@ void WalletInit::Construct(NodeContext& node) const return; } node.coinjoin_loader = node.init->makeCoinJoinLoader(); - auto wallet_loader = node.init->makeWalletLoader(*node.chain, node.coinjoin_loader); + auto wallet_loader = node.init->makeWalletLoader(*node.chain, *node.coinjoin_loader); node.wallet_loader = wallet_loader.get(); node.chain_clients.emplace_back(std::move(wallet_loader)); } diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index f3ba99d4f9822..765252f925b15 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -553,11 +553,11 @@ class WalletImpl : public Wallet class WalletLoaderImpl : public WalletLoader { public: - WalletLoaderImpl(Chain& chain, ArgsManager& args, const std::unique_ptr& coinjoin_loader) : - m_context(coinjoin_loader) + WalletLoaderImpl(Chain& chain, ArgsManager& args, interfaces::CoinJoin::Loader& coinjoin_loader) { m_context.chain = &chain; m_context.args = &args; + m_context.coinjoin_loader = &coinjoin_loader; } ~WalletLoaderImpl() override { UnloadWallets(); } @@ -574,7 +574,7 @@ class WalletLoaderImpl : public WalletLoader } } bool verify() override { return VerifyWallets(*m_context.chain); } - bool load() override { assert(m_context.m_coinjoin_loader); return LoadWallets(*m_context.chain, *m_context.m_coinjoin_loader); } + bool load() override { return LoadWallets(*m_context.chain, *m_context.coinjoin_loader); } void start(CScheduler& scheduler) override { return StartWallets(scheduler, *Assert(m_context.args)); } void flush() override { return FlushWallets(); } void stop() override { return StopWallets(); } @@ -589,22 +589,19 @@ class WalletLoaderImpl : public WalletLoader options.require_create = true; options.create_flags = wallet_creation_flags; options.create_passphrase = passphrase; - assert(m_context.m_coinjoin_loader); - return MakeWallet(CreateWallet(*m_context.chain, *m_context.m_coinjoin_loader, name, true /* load_on_start */, options, status, error, warnings)); + return MakeWallet(CreateWallet(*m_context.chain, *m_context.coinjoin_loader, name, true /* load_on_start */, options, status, error, warnings)); } std::unique_ptr loadWallet(const std::string& name, bilingual_str& error, std::vector& warnings) override { DatabaseOptions options; DatabaseStatus status; options.require_existing = true; - assert(m_context.m_coinjoin_loader); - return MakeWallet(LoadWallet(*m_context.chain, *m_context.m_coinjoin_loader, name, true /* load_on_start */, options, status, error, warnings)); + return MakeWallet(LoadWallet(*m_context.chain, *m_context.coinjoin_loader, name, true /* load_on_start */, options, status, error, warnings)); } std::unique_ptr restoreWallet(const fs::path& backup_file, const std::string& wallet_name, bilingual_str& error, std::vector& warnings) override { DatabaseStatus status; - assert(m_context.m_coinjoin_loader); - return MakeWallet(RestoreWallet(*m_context.chain, *m_context.m_coinjoin_loader, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings)); + return MakeWallet(RestoreWallet(*m_context.chain, *m_context.coinjoin_loader, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings)); } std::string getWalletDir() override { @@ -641,7 +638,7 @@ class WalletLoaderImpl : public WalletLoader namespace interfaces { std::unique_ptr MakeWallet(const std::shared_ptr& wallet) { return wallet ? std::make_unique(wallet) : nullptr; } -std::unique_ptr MakeWalletLoader(Chain& chain, ArgsManager& args, const std::unique_ptr& coinjoin_loader) { +std::unique_ptr MakeWalletLoader(Chain& chain, ArgsManager& args, interfaces::CoinJoin::Loader& coinjoin_loader) { return std::make_unique(chain, args, coinjoin_loader); } } // namespace interfaces diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5aa51e8ca6dbd..1ceac9fd32b13 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2747,7 +2747,7 @@ static RPCHelpMan loadwallet() bilingual_str error; std::vector warnings; std::optional load_on_start = request.params[1].isNull() ? std::nullopt : std::optional(request.params[1].get_bool()); - std::shared_ptr const wallet = LoadWallet(*context.chain, *context.m_coinjoin_loader, name, load_on_start, options, status, error, warnings); + std::shared_ptr const wallet = LoadWallet(*context.chain, *context.coinjoin_loader, name, load_on_start, options, status, error, warnings); HandleWalletError(wallet, status, error); @@ -2903,7 +2903,7 @@ static RPCHelpMan createwallet() options.create_passphrase = passphrase; bilingual_str error; std::optional load_on_start = request.params[6].isNull() ? std::nullopt : std::optional(request.params[6].get_bool()); - const std::shared_ptr wallet = CreateWallet(*context.chain, *context.m_coinjoin_loader, request.params[0].get_str(), load_on_start, options, status, error, warnings); + const std::shared_ptr wallet = CreateWallet(*context.chain, *context.coinjoin_loader, request.params[0].get_str(), load_on_start, options, status, error, warnings); if (!wallet) { RPCErrorCode code = status == DatabaseStatus::FAILED_ENCRYPT ? RPC_WALLET_ENCRYPTION_FAILED : RPC_WALLET_ERROR; throw JSONRPCError(code, error.original); @@ -2957,7 +2957,7 @@ static RPCHelpMan restorewallet() bilingual_str error; std::vector warnings; - const std::shared_ptr wallet = RestoreWallet(*context.chain, *context.m_coinjoin_loader, backup_file, wallet_name, load_on_start, status, error, warnings); + const std::shared_ptr wallet = RestoreWallet(*context.chain, *context.coinjoin_loader, backup_file, wallet_name, load_on_start, status, error, warnings); HandleWalletError(wallet, status, error); diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp index 96e29be52aaba..43ccd5729ae12 100644 --- a/src/wallet/test/init_test_fixture.cpp +++ b/src/wallet/test/init_test_fixture.cpp @@ -15,7 +15,7 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainName) : BasicTestingSetup(chainName) { m_coinjoin_loader = interfaces::MakeCoinJoinLoader(m_node); - m_wallet_loader = MakeWalletLoader(*m_node.chain, *Assert(m_node.args), m_coinjoin_loader); + m_wallet_loader = MakeWalletLoader(*m_node.chain, *Assert(m_node.args), *Assert(m_coinjoin_loader)); std::string sep; sep += fs::path::preferred_separator; diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp index adbe91613799d..534853200e643 100644 --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -9,7 +9,7 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName) : TestingSetup(chainName), m_coinjoin_loader{interfaces::MakeCoinJoinLoader(m_node)}, - m_wallet_loader{interfaces::MakeWalletLoader(*m_node.chain, *Assert(m_node.args), m_coinjoin_loader)}, + m_wallet_loader{interfaces::MakeWalletLoader(*m_node.chain, *Assert(m_node.args), *Assert(m_coinjoin_loader))}, m_wallet(m_node.chain.get(), m_coinjoin_loader.get(), "", CreateMockWalletDatabase()) { m_wallet.LoadWallet(); From 6502e542dfaa4601f51ff4cc617fd554af23afb8 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 24 Feb 2025 20:57:28 +0000 Subject: [PATCH 10/12] refactor: use `CoinJoin::Loader` in `InitCoinJoinSettings` --- src/coinjoin/interfaces.cpp | 4 ++-- src/dummywallet.cpp | 2 +- src/wallet/init.cpp | 12 +++++++----- src/walletinitinterface.h | 9 ++++++--- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/coinjoin/interfaces.cpp b/src/coinjoin/interfaces.cpp index ee457ca944426..1a5b5faba5d13 100644 --- a/src/coinjoin/interfaces.cpp +++ b/src/coinjoin/interfaces.cpp @@ -93,12 +93,12 @@ class CoinJoinLoaderImpl : public interfaces::CoinJoin::Loader void AddWallet(const std::shared_ptr& wallet) override { walletman().Add(wallet); - g_wallet_init_interface.InitCoinJoinSettings(walletman()); + g_wallet_init_interface.InitCoinJoinSettings(*this); } void RemoveWallet(const std::string& name) override { walletman().Remove(name); - g_wallet_init_interface.InitCoinJoinSettings(walletman()); + g_wallet_init_interface.InitCoinJoinSettings(*this); } void FlushWallet(const std::string& name) override { diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index 148f75f465bba..41f9670dc2c9b 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -29,7 +29,7 @@ class DummyWalletInit : public WalletInitInterface { // Dash Specific WalletInitInterface InitCoinJoinSettings void AutoLockMasternodeCollaterals() const override {} - void InitCoinJoinSettings(const CoinJoinWalletManager& cjwalletman) const override {} + void InitCoinJoinSettings(interfaces::CoinJoin::Loader& coinjoin_loader) const override {} bool InitAutoBackup() const override {return true;} }; diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index f31d8ed2c7d73..997b8bb4b913c 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -48,7 +48,7 @@ class WalletInit : public WalletInitInterface // Dash Specific Wallet Init void AutoLockMasternodeCollaterals() const override; - void InitCoinJoinSettings(const CoinJoinWalletManager& cjwalletman) const override; + void InitCoinJoinSettings(interfaces::CoinJoin::Loader& coinjoin_loader) const override; bool InitAutoBackup() const override; }; @@ -204,7 +204,7 @@ void WalletInit::AutoLockMasternodeCollaterals() const } } -void WalletInit::InitCoinJoinSettings(const CoinJoinWalletManager& cjwalletman) const +void WalletInit::InitCoinJoinSettings(interfaces::CoinJoin::Loader& coinjoin_loader) const { CCoinJoinClientOptions::SetEnabled(!GetWallets().empty() ? gArgs.GetBoolArg("-enablecoinjoin", true) : false); if (!CCoinJoinClientOptions::IsEnabled()) { @@ -212,12 +212,14 @@ void WalletInit::InitCoinJoinSettings(const CoinJoinWalletManager& cjwalletman) } bool fAutoStart = gArgs.GetBoolArg("-coinjoinautostart", DEFAULT_COINJOIN_AUTOSTART); for (auto& pwallet : GetWallets()) { - auto manager = cjwalletman.Get(pwallet->GetName()); + auto manager = coinjoin_loader.GetClient(pwallet->GetName()); assert(manager != nullptr); if (pwallet->IsLocked()) { - manager->StopMixing(); + manager->stopMixing(); + LogPrintf("CoinJoin: Mixing stopped for locked wallet \"%s\"\n", pwallet->GetName()); } else if (fAutoStart) { - manager->StartMixing(); + manager->startMixing(); + LogPrintf("CoinJoin: Automatic mixing started for wallet \"%s\"\n", pwallet->GetName()); } } LogPrintf("CoinJoin: autostart=%d, multisession=%d," /* Continued */ diff --git a/src/walletinitinterface.h b/src/walletinitinterface.h index cb70b76bc649e..7e3777f938c35 100644 --- a/src/walletinitinterface.h +++ b/src/walletinitinterface.h @@ -6,9 +6,12 @@ #define BITCOIN_WALLETINITINTERFACE_H class ArgsManager; -class CoinJoinWalletManager; - struct NodeContext; +namespace interfaces { +namespace CoinJoin { +class Loader; +} // namespace CoinJoin +} // namespace interfaces class WalletInitInterface { public: @@ -23,7 +26,7 @@ class WalletInitInterface { // Dash Specific WalletInitInterface virtual void AutoLockMasternodeCollaterals() const = 0; - virtual void InitCoinJoinSettings(const CoinJoinWalletManager& cjwalletman) const = 0; + virtual void InitCoinJoinSettings(interfaces::CoinJoin::Loader& coinjoin_loader) const = 0; virtual bool InitAutoBackup() const = 0; virtual ~WalletInitInterface() {} From c9c5275289823cd5893fa3239317c92323c79fe6 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 23 Feb 2025 11:20:50 +0000 Subject: [PATCH 11/12] refactor: get rid of `DashPostChainstateSetup()` `validation_chainstatemanager_tests` can work without `CJContext`, we can safely reincorporate it into `TestingSetup`. --- src/test/util/setup_common.cpp | 30 +++++++------------ src/test/util/setup_common.h | 4 --- .../validation_chainstatemanager_tests.cpp | 4 --- 3 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 42a0680a68bcc..a032ea3792316 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -118,24 +118,6 @@ void DashChainstateSetupClose(NodeContext& node) Assert(node.mempool.get())); } -void DashPostChainstateSetup(NodeContext& node) -{ - node.cj_ctx = std::make_unique(*node.chainman, *node.connman, *node.dmnman, *node.mn_metaman, *node.mempool, - /*mn_activeman=*/nullptr, *node.mn_sync, *node.llmq_ctx->isman, node.peerman, - /*relay_txes=*/true); -#ifdef ENABLE_WALLET - node.coinjoin_loader = interfaces::MakeCoinJoinLoader(node); -#endif // ENABLE_WALLET -} - -void DashPostChainstateSetupClose(NodeContext& node) -{ -#ifdef ENABLE_WALLET - node.coinjoin_loader.reset(); -#endif // ENABLE_WALLET - node.cj_ctx.reset(); -} - BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::vector& extra_args) : m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME / g_insecure_rand_ctx_temp_path.rand256().ToString()}, m_args{} @@ -330,7 +312,12 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vectorInit(options); } - DashPostChainstateSetup(m_node); + m_node.cj_ctx = std::make_unique(*m_node.chainman, *m_node.connman, *m_node.dmnman, *m_node.mn_metaman, *m_node.mempool, + /*mn_activeman=*/nullptr, *m_node.mn_sync, *m_node.llmq_ctx->isman, m_node.peerman, + /*relay_txes=*/true); +#ifdef ENABLE_WALLET + m_node.coinjoin_loader = interfaces::MakeCoinJoinLoader(m_node); +#endif // ENABLE_WALLET BlockValidationState state; if (!m_node.chainman->ActiveChainstate().ActivateBestChain(state)) { @@ -340,7 +327,10 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vectorInterrupt(); m_node.llmq_ctx->Stop(); @@ -85,7 +83,6 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) chainstates.push_back(&c2); DashChainstateSetup(manager, m_node, /*fReset=*/false, /*fReindexChainState=*/false, consensus_params); - DashPostChainstateSetup(m_node); BOOST_CHECK_EQUAL(manager.SnapshotBlockhash().value(), snapshot_blockhash); @@ -120,7 +117,6 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) // Let scheduler events finish running to avoid accessing memory that is going to be unloaded SyncWithValidationInterfaceQueue(); - DashPostChainstateSetupClose(m_node); if (m_node.llmq_ctx) { m_node.llmq_ctx->Interrupt(); m_node.llmq_ctx->Stop(); From 68cec8d6867c0b88eb34f6b01a8901de76308668 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 24 Feb 2025 20:55:41 +0000 Subject: [PATCH 12/12] refactor: use `interfaces::WalletLoader` in Dash-specific wallet init --- src/coinjoin/interfaces.cpp | 9 +++++++-- src/dummywallet.cpp | 5 +++-- src/init.cpp | 5 +++++ src/interfaces/wallet.h | 3 +++ src/node/blockstorage.cpp | 2 -- src/qt/test/addressbooktests.cpp | 2 -- src/qt/test/wallettests.cpp | 2 -- src/test/util/setup_common.cpp | 14 ++++++++++++++ src/wallet/init.cpp | 26 +++++++++++++------------- src/wallet/interfaces.cpp | 1 + src/walletinitinterface.h | 5 +++-- 11 files changed, 49 insertions(+), 25 deletions(-) diff --git a/src/coinjoin/interfaces.cpp b/src/coinjoin/interfaces.cpp index 1a5b5faba5d13..acb9565974e02 100644 --- a/src/coinjoin/interfaces.cpp +++ b/src/coinjoin/interfaces.cpp @@ -82,6 +82,11 @@ class CoinJoinLoaderImpl : public interfaces::CoinJoin::Loader return *Assert(Assert(m_node.cj_ctx)->walletman); } + interfaces::WalletLoader& wallet_loader() + { + return *Assert(m_node.wallet_loader); + } + public: explicit CoinJoinLoaderImpl(NodeContext& node) : m_node(node) @@ -93,12 +98,12 @@ class CoinJoinLoaderImpl : public interfaces::CoinJoin::Loader void AddWallet(const std::shared_ptr& wallet) override { walletman().Add(wallet); - g_wallet_init_interface.InitCoinJoinSettings(*this); + g_wallet_init_interface.InitCoinJoinSettings(*this, wallet_loader()); } void RemoveWallet(const std::string& name) override { walletman().Remove(name); - g_wallet_init_interface.InitCoinJoinSettings(*this); + g_wallet_init_interface.InitCoinJoinSettings(*this, wallet_loader()); } void FlushWallet(const std::string& name) override { diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index 41f9670dc2c9b..cc8e3c5af24d8 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -14,6 +14,7 @@ class Chain; class Handler; class Wallet; class WalletClient; +class WalletLoader; namespace CoinJoin { class Loader; } // namespcae CoinJoin @@ -28,8 +29,8 @@ class DummyWalletInit : public WalletInitInterface { void Construct(NodeContext& node) const override {LogPrintf("No wallet support compiled in!\n");} // Dash Specific WalletInitInterface InitCoinJoinSettings - void AutoLockMasternodeCollaterals() const override {} - void InitCoinJoinSettings(interfaces::CoinJoin::Loader& coinjoin_loader) const override {} + void AutoLockMasternodeCollaterals(interfaces::WalletLoader& wallet_loader) const override {} + void InitCoinJoinSettings(interfaces::CoinJoin::Loader& coinjoin_loader, interfaces::WalletLoader& wallet_loader) const override {} bool InitAutoBackup() const override {return true;} }; diff --git a/src/init.cpp b/src/init.cpp index f1a0a49b020c7..690c5ffe43776 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2202,6 +2202,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) chainman.m_load_block = std::thread(&util::TraceThread, "loadblk", [=, &args, &chainman, &node] { ThreadImport(chainman, *node.dmnman, *g_ds_notification_interface, vImportFiles, node.mn_activeman.get(), args); }); +#ifdef ENABLE_WALLET + if (!args.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { + g_wallet_init_interface.AutoLockMasternodeCollaterals(*node.wallet_loader); + } +#endif // ENABLE_WALLET // Wait for genesis block to be processed { diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 5f31da0318bd8..cfb904e870af9 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -86,6 +86,9 @@ class Wallet //! Abort a rescan. virtual void abortRescan() = 0; + //! Lock masternode collaterals + virtual void autoLockMasternodeCollaterals() = 0; + //! Back up wallet. virtual bool backupWallet(const std::string& filename) = 0; diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 0f00280734981..2034846086043 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -926,7 +926,5 @@ void ThreadImport(ChainstateManager& chainman, CDeterministicMNManager& dmnman, mn_activeman->Init(chainman.ActiveTip()); } - g_wallet_init_interface.AutoLockMasternodeCollaterals(); - chainman.ActiveChainstate().LoadMempool(args); } diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index dd2ffa4b76cb5..c4a47847aa1c7 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -63,8 +63,6 @@ void EditAddressAndSubmit( void TestAddAddressesToSendBook(interfaces::Node& node) { TestChain100Setup test; - auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args), *Assert(test.m_node.coinjoin_loader)); - test.m_node.wallet_loader = wallet_loader.get(); node.setContext(&test.m_node); const std::shared_ptr wallet = std::make_shared(node.context()->chain.get(), node.context()->coinjoin_loader.get(), "", CreateMockWalletDatabase()); wallet->SetupLegacyScriptPubKeyMan(); diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 98ef96bb3e7dd..effb354fd18e1 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -108,8 +108,6 @@ void TestGUI(interfaces::Node& node) for (int i = 0; i < 5; ++i) { test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey())); } - auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args), *Assert(test.m_node.coinjoin_loader)); - test.m_node.wallet_loader = wallet_loader.get(); node.setContext(&test.m_node); const std::shared_ptr wallet = std::make_shared(node.context()->chain.get(), node.context()->coinjoin_loader.get(), "", CreateMockWalletDatabase()); AddWallet(wallet); diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index a032ea3792316..83f3b4f164cbb 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -63,6 +63,7 @@ #ifdef ENABLE_WALLET #include +#include #endif // ENABLE_WALLET #include @@ -315,8 +316,16 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector(*m_node.chainman, *m_node.connman, *m_node.dmnman, *m_node.mn_metaman, *m_node.mempool, /*mn_activeman=*/nullptr, *m_node.mn_sync, *m_node.llmq_ctx->isman, m_node.peerman, /*relay_txes=*/true); + #ifdef ENABLE_WALLET + // WalletInit::Construct()-like logic needed for wallet tests that run on + // TestingSetup and its children (e.g. TestChain100Setup) instead of + // WalletTestingSetup m_node.coinjoin_loader = interfaces::MakeCoinJoinLoader(m_node); + + auto wallet_loader = interfaces::MakeWalletLoader(*m_node.chain, *m_node.args, *m_node.coinjoin_loader); + m_node.wallet_loader = wallet_loader.get(); + m_node.chain_clients.emplace_back(std::move(wallet_loader)); #endif // ENABLE_WALLET BlockValidationState state; @@ -328,6 +337,11 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vectorAutoLockMasternodeCollaterals(); + for (const auto& wallet : wallet_loader.getWallets()) { + wallet->autoLockMasternodeCollaterals(); } } -void WalletInit::InitCoinJoinSettings(interfaces::CoinJoin::Loader& coinjoin_loader) const +void WalletInit::InitCoinJoinSettings(interfaces::CoinJoin::Loader& coinjoin_loader, interfaces::WalletLoader& wallet_loader) const { - CCoinJoinClientOptions::SetEnabled(!GetWallets().empty() ? gArgs.GetBoolArg("-enablecoinjoin", true) : false); + const auto& wallets{wallet_loader.getWallets()}; + CCoinJoinClientOptions::SetEnabled(!wallets.empty() ? gArgs.GetBoolArg("-enablecoinjoin", true) : false); if (!CCoinJoinClientOptions::IsEnabled()) { return; } bool fAutoStart = gArgs.GetBoolArg("-coinjoinautostart", DEFAULT_COINJOIN_AUTOSTART); - for (auto& pwallet : GetWallets()) { - auto manager = coinjoin_loader.GetClient(pwallet->GetName()); - assert(manager != nullptr); - if (pwallet->IsLocked()) { + for (auto& wallet : wallets) { + auto manager = Assert(coinjoin_loader.GetClient(wallet->getWalletName())); + if (wallet->isLocked(/*fForMixing=*/false)) { manager->stopMixing(); - LogPrintf("CoinJoin: Mixing stopped for locked wallet \"%s\"\n", pwallet->GetName()); + LogPrintf("CoinJoin: Mixing stopped for locked wallet \"%s\"\n", wallet->getWalletName()); } else if (fAutoStart) { manager->startMixing(); - LogPrintf("CoinJoin: Automatic mixing started for wallet \"%s\"\n", pwallet->GetName()); + LogPrintf("CoinJoin: Automatic mixing started for wallet \"%s\"\n", wallet->getWalletName()); } } LogPrintf("CoinJoin: autostart=%d, multisession=%d," /* Continued */ diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 765252f925b15..c6450bcd619e2 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -147,6 +147,7 @@ class WalletImpl : public Wallet return m_wallet->ChangeWalletPassphrase(old_wallet_passphrase, new_wallet_passphrase); } void abortRescan() override { m_wallet->AbortRescan(); } + void autoLockMasternodeCollaterals() override { m_wallet->AutoLockMasternodeCollaterals(); } bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); } bool autoBackupWallet(const fs::path& wallet_path, bilingual_str& error_string, std::vector& warnings) override { diff --git a/src/walletinitinterface.h b/src/walletinitinterface.h index 7e3777f938c35..60a424d1248b2 100644 --- a/src/walletinitinterface.h +++ b/src/walletinitinterface.h @@ -8,6 +8,7 @@ class ArgsManager; struct NodeContext; namespace interfaces { +class WalletLoader; namespace CoinJoin { class Loader; } // namespace CoinJoin @@ -25,8 +26,8 @@ class WalletInitInterface { virtual void Construct(NodeContext& node) const = 0; // Dash Specific WalletInitInterface - virtual void AutoLockMasternodeCollaterals() const = 0; - virtual void InitCoinJoinSettings(interfaces::CoinJoin::Loader& coinjoin_loader) const = 0; + virtual void AutoLockMasternodeCollaterals(interfaces::WalletLoader& wallet_loader) const = 0; + virtual void InitCoinJoinSettings(interfaces::CoinJoin::Loader& coinjoin_loader, interfaces::WalletLoader& wallet_loader) const = 0; virtual bool InitAutoBackup() const = 0; virtual ~WalletInitInterface() {}