From b266b3e0bf29d0f3d5deaeec62d57c5025b35525 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Fri, 29 May 2020 00:07:18 -0400 Subject: [PATCH 1/3] refactor: Create interfaces earlier during initialization Add AppInitInterfaces function so wallet chain and chain client interfaces are created earlier during initialization. This is needed in the next commit to allow the gui splash screen to be able to register for wallet events through a dedicated WalletClient interface instead managing wallets indirectly through the Node interface. This only works if the wallet client interface is created before the splash screen needs to use it. --- src/bitcoind.cpp | 3 +-- src/init.cpp | 17 +++++++++++------ src/init.h | 4 ++++ src/interfaces/node.cpp | 3 +-- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 227626f40fa..02074f820aa 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -44,7 +44,6 @@ static void WaitForShutdown(NodeContext& node) static bool AppInit(int argc, char* argv[]) { NodeContext node; - node.chain = interfaces::MakeChain(node); bool fRet = false; @@ -144,7 +143,7 @@ static bool AppInit(int argc, char* argv[]) // If locking the data directory failed, exit immediately return false; } - fRet = AppInitMain(context, node); + fRet = AppInitInterfaces(node) && AppInitMain(context, node); } catch (const std::exception& e) { PrintExceptionContinue(&e, "AppInit()"); diff --git a/src/init.cpp b/src/init.cpp index ecd57960adc..4fc2c6211ac 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1229,6 +1229,17 @@ bool AppInitLockDataDirectory() return true; } +bool AppInitInterfaces(NodeContext& node) +{ + node.chain = interfaces::MakeChain(node); + // Create client interfaces for wallets that are supposed to be loaded + // according to -wallet and -disablewallet options. This only constructs + // the interfaces, it doesn't load wallet data. Wallets actually get loaded + // when load() and start() interface methods are called below. + g_wallet_init_interface.Construct(node); + return true; +} + bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) { const ArgsManager& args = *Assert(node.args); @@ -1318,12 +1329,6 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA GetMainSignals().RegisterBackgroundSignalScheduler(*node.scheduler); - // Create client interfaces for wallets that are supposed to be loaded - // according to -wallet and -disablewallet options. This only constructs - // the interfaces, it doesn't load wallet data. Wallets actually get loaded - // when load() and start() interface methods are called below. - g_wallet_init_interface.Construct(node); - /* Register RPC commands regardless of -server setting so they will be * available in the GUI RPC console even if external calls are disabled. */ diff --git a/src/init.h b/src/init.h index ce12a80dc71..679e875da1e 100644 --- a/src/init.h +++ b/src/init.h @@ -52,6 +52,10 @@ bool AppInitSanityChecks(); * @pre Parameters should be parsed and config file should be read, AppInitSanityChecks should have been called. */ bool AppInitLockDataDirectory(); +/** + * Initialize node and wallet interface pointers. Has no prerequisites or side effects besides allocating memory. + */ +bool AppInitInterfaces(NodeContext& node); /** * Bitcoin core main initialization. * @note This should only be done after daemonization. Call Shutdown() if this function fails. diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index 206262eb03e..73171686eb5 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -64,11 +64,10 @@ public: bool baseInitialize() override { return AppInitBasicSetup(gArgs) && AppInitParameterInteraction(gArgs) && AppInitSanityChecks() && - AppInitLockDataDirectory(); + AppInitLockDataDirectory() && AppInitInterfaces(*m_context); } bool appInitMain(interfaces::BlockAndHeaderTipInfo* tip_info) override { - m_context->chain = MakeChain(*m_context); return AppInitMain(m_context_ref, *m_context, tip_info); } void appShutdown() override From e4f435047121886edb6e6a6c4e4998e44ed2e36a Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Thu, 28 May 2020 09:48:30 -0400 Subject: [PATCH 2/3] refactor: Move wallet methods out of chain.h and node.h Add WalletClient interface so node interface is cleaner and don't need wallet-specific methods. The new NodeContext::wallet_client pointer will also be needed to eliminate global wallet variables like ::vpwallets, because createWallet(), loadWallet(), getWallets(), etc methods called by the GUI need a way to get a reference to the list of open wallets if it is no longer a global variable. Also tweaks splash screen registration for load wallet events to be delayed until after wallet client is created. --- src/dummywallet.cpp | 34 ------------------- src/interfaces/chain.h | 13 ------- src/interfaces/node.cpp | 45 ++----------------------- src/interfaces/node.h | 25 ++------------ src/interfaces/wallet.cpp | 36 ++++++++++++++++++-- src/interfaces/wallet.h | 35 +++++++++++++++++++ src/node/context.h | 5 +++ src/qt/bitcoin.cpp | 1 + src/qt/bitcoingui.cpp | 2 +- src/qt/splashscreen.cpp | 6 +++- src/qt/splashscreen.h | 3 ++ src/qt/walletcontroller.cpp | 10 +++--- src/qt/walletmodel.cpp | 2 +- src/wallet/init.cpp | 5 ++- src/wallet/test/init_test_fixture.cpp | 2 +- src/wallet/test/init_test_fixture.h | 3 +- src/wallet/test/init_tests.cpp | 14 ++++---- src/wallet/test/wallet_test_fixture.cpp | 2 +- src/wallet/test/wallet_test_fixture.h | 2 +- src/wallet/wallet.cpp | 5 --- 20 files changed, 111 insertions(+), 139 deletions(-) diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index 380d4eb8ac6..e54c2daaeb4 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -4,11 +4,8 @@ #include #include -#include class CWallet; -enum class WalletCreationStatus; -struct bilingual_str; namespace interfaces { class Chain; @@ -59,37 +56,6 @@ void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const const WalletInitInterface& g_wallet_init_interface = DummyWalletInit(); -fs::path GetWalletDir() -{ - throw std::logic_error("Wallet function called in non-wallet build."); -} - -std::vector ListWalletDir() -{ - throw std::logic_error("Wallet function called in non-wallet build."); -} - -std::vector> GetWallets() -{ - throw std::logic_error("Wallet function called in non-wallet build."); -} - -std::shared_ptr LoadWallet(interfaces::Chain& chain, const std::string& name, bilingual_str& error, std::vector& warnings) -{ - throw std::logic_error("Wallet function called in non-wallet build."); -} - -WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector& warnings, std::shared_ptr& result) -{ - throw std::logic_error("Wallet function called in non-wallet build."); -} - -using LoadWalletFn = std::function wallet)>; -std::unique_ptr HandleLoadWallet(LoadWalletFn load_wallet) -{ - throw std::logic_error("Wallet function called in non-wallet build."); -} - namespace interfaces { std::unique_ptr MakeWallet(const std::shared_ptr& wallet) diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 053d40335f2..6e50ccb27a3 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -314,24 +314,11 @@ public: //! Set mock time. virtual void setMockTime(int64_t time) = 0; - - //! Return interfaces for accessing wallets (if any). - virtual std::vector> getWallets() = 0; }; //! Return implementation of Chain interface. std::unique_ptr MakeChain(NodeContext& node); -//! Return implementation of ChainClient interface for a wallet client. This -//! function will be undefined in builds where ENABLE_WALLET is false. -//! -//! Currently, wallets are the only chain clients. But in the future, other -//! types of chain clients could be added, such as tools for monitoring, -//! analysis, or fee estimation. These clients need to expose their own -//! MakeXXXClient functions returning their implementations of the ChainClient -//! interface. -std::unique_ptr MakeWalletClient(Chain& chain, ArgsManager& args, std::vector wallet_filenames); - } // namespace interfaces #endif // BITCOIN_INTERFACES_CHAIN_H diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index 73171686eb5..2c5f8627e61 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -41,16 +42,7 @@ #include -class CWallet; -fs::path GetWalletDir(); -std::vector ListWalletDir(); -std::vector> GetWallets(); -std::shared_ptr LoadWallet(interfaces::Chain& chain, const std::string& name, bilingual_str& error, std::vector& warnings); -WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector& warnings, std::shared_ptr& result); -std::unique_ptr HandleLoadWallet(interfaces::Node::LoadWalletFn load_wallet); - namespace interfaces { - namespace { class NodeImpl : public Node @@ -239,36 +231,9 @@ public: LOCK(::cs_main); return ::ChainstateActive().CoinsTip().GetCoin(output, coin); } - std::string getWalletDir() override + WalletClient& walletClient() override { - return GetWalletDir().string(); - } - std::vector listWalletDir() override - { - std::vector paths; - for (auto& path : ListWalletDir()) { - paths.push_back(path.string()); - } - return paths; - } - std::vector> getWallets() override - { - std::vector> wallets; - for (auto& client : m_context->chain_clients) { - auto client_wallets = client->getWallets(); - std::move(client_wallets.begin(), client_wallets.end(), std::back_inserter(wallets)); - } - return wallets; - } - std::unique_ptr loadWallet(const std::string& name, bilingual_str& error, std::vector& warnings) override - { - return MakeWallet(LoadWallet(*m_context->chain, name, error, warnings)); - } - std::unique_ptr createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector& warnings, WalletCreationStatus& status) override - { - std::shared_ptr wallet; - status = CreateWallet(*m_context->chain, passphrase, wallet_creation_flags, name, error, warnings, wallet); - return MakeWallet(wallet); + return *Assert(m_context->wallet_client); } std::unique_ptr handleInitMessage(InitMessageFn fn) override { @@ -286,10 +251,6 @@ public: { return MakeHandler(::uiInterface.ShowProgress_connect(fn)); } - std::unique_ptr handleLoadWallet(LoadWalletFn fn) override - { - return HandleLoadWallet(std::move(fn)); - } std::unique_ptr handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override { return MakeHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn)); diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 0cff7ae3a10..5079be038eb 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -29,14 +29,13 @@ class RPCTimerInterface; class UniValue; class proxyType; enum class SynchronizationState; -enum class WalletCreationStatus; struct CNodeStateStats; struct NodeContext; struct bilingual_str; namespace interfaces { class Handler; -class Wallet; +class WalletClient; struct BlockTip; //! Block and header tip information @@ -173,22 +172,8 @@ public: //! Get unspent outputs associated with a transaction. virtual bool getUnspentOutput(const COutPoint& output, Coin& coin) = 0; - //! Return default wallet directory. - virtual std::string getWalletDir() = 0; - - //! Return available wallets in wallet directory. - virtual std::vector listWalletDir() = 0; - - //! Return interfaces for accessing wallets (if any). - virtual std::vector> getWallets() = 0; - - //! Attempts to load a wallet from file or directory. - //! The loaded wallet is also notified to handlers previously registered - //! with handleLoadWallet. - virtual std::unique_ptr loadWallet(const std::string& name, bilingual_str& error, std::vector& warnings) = 0; - - //! Create a wallet from file - virtual std::unique_ptr createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector& warnings, WalletCreationStatus& status) = 0; + //! Get wallet client. + virtual WalletClient& walletClient() = 0; //! Register handler for init messages. using InitMessageFn = std::function; @@ -210,10 +195,6 @@ public: using ShowProgressFn = std::function; virtual std::unique_ptr handleShowProgress(ShowProgressFn fn) = 0; - //! Register handler for load wallet messages. - using LoadWalletFn = std::function wallet)>; - virtual std::unique_ptr handleLoadWallet(LoadWalletFn fn) = 0; - //! Register handler for number of connections changed messages. using NotifyNumConnectionsChangedFn = std::function; virtual std::unique_ptr handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) = 0; diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 937e602fb0a..63c109658ea 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -485,7 +485,7 @@ public: std::shared_ptr m_wallet; }; -class WalletClientImpl : public ChainClient +class WalletClientImpl : public WalletClient { public: WalletClientImpl(Chain& chain, ArgsManager& args, std::vector wallet_filenames) @@ -494,6 +494,9 @@ public: m_context.chain = &chain; m_context.args = &args; } + ~WalletClientImpl() override { UnloadWallets(); } + + //! ChainClient methods void registerRpcs() override { for (const CRPCCommand& command : GetWalletRPCCommands()) { @@ -509,6 +512,30 @@ public: void flush() override { return FlushWallets(); } void stop() override { return StopWallets(); } void setMockTime(int64_t time) override { return SetMockTime(time); } + + //! WalletClient methods + std::unique_ptr createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, WalletCreationStatus& status, bilingual_str& error, std::vector& warnings) override + { + std::shared_ptr wallet; + status = CreateWallet(*m_context.chain, passphrase, wallet_creation_flags, name, error, warnings, wallet); + return MakeWallet(std::move(wallet)); + } + std::unique_ptr loadWallet(const std::string& name, bilingual_str& error, std::vector& warnings) override + { + return MakeWallet(LoadWallet(*m_context.chain, WalletLocation(name), error, warnings)); + } + std::string getWalletDir() override + { + return GetWalletDir().string(); + } + std::vector listWalletDir() override + { + std::vector paths; + for (auto& path : ListWalletDir()) { + paths.push_back(path.string()); + } + return paths; + } std::vector> getWallets() override { std::vector> wallets; @@ -517,7 +544,10 @@ public: } return wallets; } - ~WalletClientImpl() override { UnloadWallets(); } + std::unique_ptr handleLoadWallet(LoadWalletFn fn) override + { + return HandleLoadWallet(std::move(fn)); + } WalletContext m_context; const std::vector m_wallet_filenames; @@ -529,7 +559,7 @@ public: std::unique_ptr MakeWallet(const std::shared_ptr& wallet) { return wallet ? MakeUnique(wallet) : nullptr; } -std::unique_ptr MakeWalletClient(Chain& chain, ArgsManager& args, std::vector wallet_filenames) +std::unique_ptr MakeWalletClient(Chain& chain, ArgsManager& args, std::vector wallet_filenames) { return MakeUnique(chain, args, std::move(wallet_filenames)); } diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 3cdadbc72ec..186f5d81a5d 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -6,6 +6,7 @@ #define BITCOIN_INTERFACES_WALLET_H #include // For CAmount +#include // For ChainClient #include // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation) #include