diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -500,6 +500,9 @@ if(BUILD_BITCOIN_WALLET) add_subdirectory(wallet) target_link_libraries(server wallet) + # There is a circular dependency between wallet and server, see: + # https://github.com/bitcoin/bitcoin/pull/14437#discussion_r226237048 + target_link_libraries(wallet server) else() target_sources(server PRIVATE dummywallet.cpp) endif() diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -530,6 +530,7 @@ bitcoind_LDADD = \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_WALLET) \ + $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -11,20 +11,9 @@ bool HasWalletSupport() const override { return false; } void AddWalletOptions() const override; bool ParameterInteraction() const override { return true; } - void RegisterRPC(CRPCTable &) const override {} - bool Verify(const CChainParams &chainParams, - interfaces::Chain &chain) const override { - return true; - } - bool Open(const CChainParams &chainParams, - interfaces::Chain &chain) const override { + void Construct(InitInterfaces &interfaces) const override { LogPrintf("No wallet support compiled in!\n"); - return true; } - void Start(CScheduler &scheduler) const override {} - void Flush() const override {} - void Stop() const override {} - void Close() const override {} }; void DummyWalletInit::AddWalletOptions() const { diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -178,7 +179,9 @@ StopREST(); StopRPC(); StopHTTPServer(); - g_wallet_init_interface.Flush(); + for (const auto &client : interfaces.chain_clients) { + client->flush(); + } StopMapPort(); // Because these depend on each-other, we make sure that neither can be @@ -238,7 +241,9 @@ pcoinsdbview.reset(); pblocktree.reset(); } - g_wallet_init_interface.Stop(); + for (const auto &client : interfaces.chain_clients) { + client->stop(); + } #if ENABLE_ZMQ if (g_zmq_notification_interface) { @@ -258,7 +263,7 @@ UnregisterAllValidationInterfaces(); GetMainSignals().UnregisterBackgroundSignalScheduler(); GetMainSignals().UnregisterWithMempoolSignals(g_mempool); - g_wallet_init_interface.Close(); + interfaces.chain_clients.clear(); globalVerifyHandle.reset(); ECC_Stop(); LogPrintf("%s: done\n", __func__); @@ -1888,12 +1893,20 @@ GetMainSignals().RegisterBackgroundSignalScheduler(scheduler); GetMainSignals().RegisterWithMempoolSignals(g_mempool); + // 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(interfaces); + /** * Register RPC commands regardless of -server setting so they will be * available in the GUI RPC console even if external calls are disabled. */ RegisterAllRPCCommands(config, rpcServer, tableRPC); - g_wallet_init_interface.RegisterRPC(tableRPC); + for (const auto &client : interfaces.chain_clients) { + client->registerRpcs(); + } g_rpc_interfaces = &interfaces; #if ENABLE_ZMQ RegisterZMQRPCCommands(tableRPC); @@ -1914,8 +1927,10 @@ } // Step 5: verify wallet database integrity - if (!g_wallet_init_interface.Verify(chainparams, *interfaces.chain)) { - return false; + for (const auto &client : interfaces.chain_clients) { + if (!client->verify(chainparams)) { + return false; + } } // Step 6: network initialization @@ -2308,8 +2323,10 @@ } // Step 9: load wallet - if (!g_wallet_init_interface.Open(chainparams, *interfaces.chain)) { - return false; + for (const auto &client : interfaces.chain_clients) { + if (!client->load(chainparams)) { + return false; + } } // Step 10: data directory maintenance @@ -2466,7 +2483,9 @@ SetRPCWarmupFinished(); uiInterface.InitMessage(_("Done loading")); - g_wallet_init_interface.Start(scheduler); + for (const auto &client : interfaces.chain_clients) { + client->start(scheduler); + } scheduler.scheduleEvery( [] { diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -9,6 +9,9 @@ #include #include +class CChainParams; +class CScheduler; + namespace interfaces { //! Interface for giving wallet processes access to blockchain state. @@ -41,6 +44,24 @@ class ChainClient { public: virtual ~ChainClient() {} + + //! Register rpcs. + virtual void registerRpcs() = 0; + + //! Check for errors before loading. + virtual bool verify(const CChainParams &chainParams) = 0; + + //! Load saved state. + virtual bool load(const CChainParams &chainParams) = 0; + + //! Start client execution and provide a scheduler. + virtual void start(CScheduler &scheduler) = 0; + + //! Save state to disk. + virtual void flush() = 0; + + //! Shut down client. + virtual void stop() = 0; }; //! Return implementation of Chain interface. diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -7,12 +7,15 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include #include