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 000000000000..2f2897180722 --- /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 9becb2b9eea2..65371ced6e41 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 dad2fd763822..6c7e3205ee3b 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 7047b928a8ce..64cc24150885 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 35ee13d5f5cd..00c5ac8cd99e 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 6c40a3b6d3e0..850f9a516db7 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 7f881bf07f5c..9d789df5fe1c 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 64cc24150885..bd7fe17a012e 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 850f9a516db7..e595efeb3db7 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 7be800f83fb2..26240fb6b106 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 9d789df5fe1c..a96c524080e7 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 4014ad6847fe..42a0680a68bc 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 65371ced6e41..a7e76fd10c10 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 e595efeb3db7..ee457ca94442 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 26240fb6b106..de74216bf72a 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 10cd516a00f3..569faeb92c48 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 7300b36731fc..2e5014e02770 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 1a084227ec1f..44b044a7f6dd 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 d6a0cf413a68..68ff3d00d20b 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 ede8755afffc..d0601ab767ca 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 4425b91b1111..15d61e6b4fd6 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 67a2e5467a5a..f3ba99d4f982 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 55d3e0b5d802..88df028e6fa8 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 93f635da79a9..a72cd7b667bc 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 569faeb92c48..26226fedda14 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 26226fedda14..33e5dbc60e92 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 de74216bf72a..f1a0a49b020c 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 2e5014e02770..9d47073fbee5 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 44b044a7f6dd..1787300ffaa0 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 8c51948fe8b2..6a0cf15d0788 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 75779e6e1b1d..30e1c4b3860b 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 a141317d9f2f..a125b05e162d 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 88df028e6fa8..96e29be52aab 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 a72cd7b667bc..adbe91613799 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 752c8940888a..c72693d1a774 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 5e17e398b1be..ec3b0a27a6dc 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 33e5dbc60e92..148f75f465bb 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 9d47073fbee5..33a87b355fe4 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 1787300ffaa0..f04f89338c63 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 6a0cf15d0788..797049d2438d 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 30e1c4b3860b..c1c6edab8148 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 68ff3d00d20b..5f31da0318bd 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 d0601ab767ca..dd2ffa4b76cb 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 15d61e6b4fd6..98ef96bb3e7d 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 d0cd59c8e518..09b2f3046709 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 059b7f106239..d3ceba7cfd07 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 a125b05e162d..f31d8ed2c7d7 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 f3ba99d4f982..765252f925b1 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 5aa51e8ca6db..1ceac9fd32b1 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 96e29be52aab..43ccd5729ae1 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 adbe91613799..534853200e64 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 ee457ca94442..1a5b5faba5d1 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 148f75f465bb..41f9670dc2c9 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 f31d8ed2c7d7..997b8bb4b913 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 cb70b76bc649..7e3777f938c3 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 42a0680a68bc..a032ea379231 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 1a5b5faba5d1..acb9565974e0 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 41f9670dc2c9..cc8e3c5af24d 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 f1a0a49b020c..690c5ffe4377 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 5f31da0318bd..cfb904e870af 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 0f0028073498..203484608604 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 dd2ffa4b76cb..c4a47847aa1c 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 98ef96bb3e7d..effb354fd18e 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 a032ea379231..83f3b4f164cb 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 765252f925b1..c6450bcd619e 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 7e3777f938c3..60a424d1248b 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() {}