diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index 5ad17a73b..be0d2aa49 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -1,376 +1,387 @@
 // Copyright (c) 2018 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <interfaces/node.h>
 
 #include <addrdb.h>
 #include <banman.h>
 #include <chain.h>
 #include <chainparams.h>
 #include <config.h>
 #include <init.h>
 #include <interfaces/chain.h>
 #include <interfaces/handler.h>
 #include <interfaces/wallet.h>
 #include <net.h>
 #include <net_processing.h>
 #include <netaddress.h>
 #include <netbase.h>
 #include <node/context.h>
 #include <policy/fees.h>
 #include <policy/settings.h>
 #include <primitives/block.h>
 #include <rpc/server.h>
 #include <shutdown.h>
 #include <support/allocators/secure.h>
 #include <sync.h>
 #include <txmempool.h>
 #include <ui_interface.h>
 #include <util/ref.h>
 #include <util/system.h>
 #include <util/translation.h>
 #include <validation.h>
 #include <warnings.h>
 
 #if defined(HAVE_CONFIG_H)
 #include <config/bitcoin-config.h>
 #endif
 
 #include <univalue.h>
 
 class HTTPRPCRequestProcessor;
 class CWallet;
 fs::path GetWalletDir();
 std::vector<fs::path> ListWalletDir();
 std::vector<std::shared_ptr<CWallet>> GetWallets();
 std::shared_ptr<CWallet> LoadWallet(const CChainParams &chainParams,
                                     interfaces::Chain &chain,
                                     const std::string &name,
                                     bilingual_str &error,
                                     std::vector<bilingual_str> &warnings);
 WalletCreationStatus CreateWallet(const CChainParams &params,
                                   interfaces::Chain &chain,
                                   const SecureString &passphrase,
                                   uint64_t wallet_creation_flags,
                                   const std::string &name, bilingual_str &error,
                                   std::vector<bilingual_str> &warnings,
                                   std::shared_ptr<CWallet> &result);
 std::unique_ptr<interfaces::Handler>
 HandleLoadWallet(interfaces::Node::LoadWalletFn load_wallet);
 
 namespace interfaces {
 
 namespace {
 
     class NodeImpl : public Node {
     public:
+        NodeImpl(NodeContext *context) { setContext(context); }
         void initError(const std::string &message) override {
             InitError(Untranslated(message));
         }
         bool parseParameters(int argc, const char *const argv[],
                              std::string &error) override {
             return gArgs.ParseParameters(argc, argv, error);
         }
         bool readConfigFiles(std::string &error) override {
             return gArgs.ReadConfigFiles(error, true);
         }
         void forceSetArg(const std::string &arg,
                          const std::string &value) override {
             gArgs.ForceSetArg(arg, value);
         }
         bool softSetArg(const std::string &arg,
                         const std::string &value) override {
             return gArgs.SoftSetArg(arg, value);
         }
         bool softSetBoolArg(const std::string &arg, bool value) override {
             return gArgs.SoftSetBoolArg(arg, value);
         }
         void selectParams(const std::string &network) override {
             SelectParams(network);
         }
         uint64_t getAssumedBlockchainSize() override {
             return Params().AssumedBlockchainSize();
         }
         uint64_t getAssumedChainStateSize() override {
             return Params().AssumedChainStateSize();
         }
         std::string getNetwork() override { return Params().NetworkIDString(); }
         void initLogging() override { InitLogging(); }
         void initParameterInteraction() override { InitParameterInteraction(); }
         std::string getWarnings(const std::string &type) override {
             return GetWarnings(type);
         }
         bool baseInitialize(Config &config) override {
             return AppInitBasicSetup() && AppInitParameterInteraction(config) &&
                    AppInitSanityChecks() && AppInitLockDataDirectory();
         }
         bool
         appInitMain(Config &config, RPCServer &rpcServer,
                     HTTPRPCRequestProcessor &httpRPCRequestProcessor) override {
-            m_context.chain = MakeChain(m_context, config.GetChainParams());
+            m_context->chain = MakeChain(*m_context, config.GetChainParams());
             return AppInitMain(config, rpcServer, httpRPCRequestProcessor,
-                               m_context);
+                               *m_context);
         }
         void appShutdown() override {
-            Interrupt(m_context);
-            Shutdown(m_context);
+            Interrupt(*m_context);
+            Shutdown(*m_context);
         }
         void startShutdown() override { StartShutdown(); }
         bool shutdownRequested() override { return ShutdownRequested(); }
         void mapPort(bool use_upnp) override {
             if (use_upnp) {
                 StartMapPort();
             } else {
                 InterruptMapPort();
                 StopMapPort();
             }
         }
+        // PR18571: return SetupServerArgs(*m_context)
+        // See https://reviews.bitcoinabc.org/D7993
         void setupServerArgs() override { return SetupServerArgs(); }
         bool getProxy(Network net, proxyType &proxy_info) override {
             return GetProxy(net, proxy_info);
         }
         size_t getNodeCount(CConnman::NumConnections flags) override {
-            return m_context.connman ? m_context.connman->GetNodeCount(flags)
-                                     : 0;
+            return m_context->connman ? m_context->connman->GetNodeCount(flags)
+                                      : 0;
         }
         bool getNodesStats(NodesStats &stats) override {
             stats.clear();
 
-            if (m_context.connman) {
+            if (m_context->connman) {
                 std::vector<CNodeStats> stats_temp;
-                m_context.connman->GetNodeStats(stats_temp);
+                m_context->connman->GetNodeStats(stats_temp);
 
                 stats.reserve(stats_temp.size());
                 for (auto &node_stats_temp : stats_temp) {
                     stats.emplace_back(std::move(node_stats_temp), false,
                                        CNodeStateStats());
                 }
 
                 // Try to retrieve the CNodeStateStats for each node.
                 TRY_LOCK(::cs_main, lockMain);
                 if (lockMain) {
                     for (auto &node_stats : stats) {
                         std::get<1>(node_stats) =
                             GetNodeStateStats(std::get<0>(node_stats).nodeid,
                                               std::get<2>(node_stats));
                     }
                 }
                 return true;
             }
             return false;
         }
         bool getBanned(banmap_t &banmap) override {
-            if (m_context.banman) {
-                m_context.banman->GetBanned(banmap);
+            if (m_context->banman) {
+                m_context->banman->GetBanned(banmap);
                 return true;
             }
             return false;
         }
         bool ban(const CNetAddr &net_addr, int64_t ban_time_offset) override {
-            if (m_context.banman) {
-                m_context.banman->Ban(net_addr, ban_time_offset);
+            if (m_context->banman) {
+                m_context->banman->Ban(net_addr, ban_time_offset);
                 return true;
             }
             return false;
         }
         bool unban(const CSubNet &ip) override {
-            if (m_context.banman) {
-                m_context.banman->Unban(ip);
+            if (m_context->banman) {
+                m_context->banman->Unban(ip);
                 return true;
             }
             return false;
         }
         bool disconnect(const CNetAddr &net_addr) override {
-            if (m_context.connman) {
-                return m_context.connman->DisconnectNode(net_addr);
+            if (m_context->connman) {
+                return m_context->connman->DisconnectNode(net_addr);
             }
             return false;
         }
         bool disconnect(NodeId id) override {
-            if (m_context.connman) {
-                return m_context.connman->DisconnectNode(id);
+            if (m_context->connman) {
+                return m_context->connman->DisconnectNode(id);
             }
             return false;
         }
         int64_t getTotalBytesRecv() override {
-            return m_context.connman ? m_context.connman->GetTotalBytesRecv()
-                                     : 0;
+            return m_context->connman ? m_context->connman->GetTotalBytesRecv()
+                                      : 0;
         }
         int64_t getTotalBytesSent() override {
-            return m_context.connman ? m_context.connman->GetTotalBytesSent()
-                                     : 0;
+            return m_context->connman ? m_context->connman->GetTotalBytesSent()
+                                      : 0;
         }
         size_t getMempoolSize() override {
-            return m_context.mempool ? m_context.mempool->size() : 0;
+            return m_context->mempool ? m_context->mempool->size() : 0;
         }
         size_t getMempoolDynamicUsage() override {
-            return m_context.mempool ? m_context.mempool->DynamicMemoryUsage()
-                                     : 0;
+            return m_context->mempool ? m_context->mempool->DynamicMemoryUsage()
+                                      : 0;
         }
         bool getHeaderTip(int &height, int64_t &block_time) override {
             LOCK(::cs_main);
             if (::pindexBestHeader) {
                 height = ::pindexBestHeader->nHeight;
                 block_time = ::pindexBestHeader->GetBlockTime();
                 return true;
             }
             return false;
         }
         int getNumBlocks() override {
             LOCK(::cs_main);
             return ::ChainActive().Height();
         }
         int64_t getLastBlockTime() override {
             LOCK(::cs_main);
             if (::ChainActive().Tip()) {
                 return ::ChainActive().Tip()->GetBlockTime();
             }
             // Genesis block's time of current network
             return Params().GenesisBlock().GetBlockTime();
         }
         double getVerificationProgress() override {
             const CBlockIndex *tip;
             {
                 LOCK(::cs_main);
                 tip = ::ChainActive().Tip();
             }
             return GuessVerificationProgress(Params().TxData(), tip);
         }
         bool isInitialBlockDownload() override {
             return ::ChainstateActive().IsInitialBlockDownload();
         }
         bool getReindex() override { return ::fReindex; }
         bool getImporting() override { return ::fImporting; }
         void setNetworkActive(bool active) override {
-            if (m_context.connman) {
-                m_context.connman->SetNetworkActive(active);
+            if (m_context->connman) {
+                m_context->connman->SetNetworkActive(active);
             }
         }
         bool getNetworkActive() override {
-            return m_context.connman && m_context.connman->GetNetworkActive();
+            return m_context->connman && m_context->connman->GetNetworkActive();
         }
         CFeeRate estimateSmartFee() override {
-            return m_context.mempool ? m_context.mempool->estimateFee()
-                                     : CFeeRate();
+            return m_context->mempool ? m_context->mempool->estimateFee()
+                                      : CFeeRate();
         }
         CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
         UniValue executeRpc(Config &config, const std::string &command,
                             const UniValue &params,
                             const std::string &uri) override {
             JSONRPCRequest req(m_context_ref);
             req.params = params;
             req.strMethod = command;
             req.URI = uri;
             return ::tableRPC.execute(config, req);
         }
         std::vector<std::string> listRpcCommands() override {
             return ::tableRPC.listCommands();
         }
         void rpcSetTimerInterfaceIfUnset(RPCTimerInterface *iface) override {
             RPCSetTimerInterfaceIfUnset(iface);
         }
         void rpcUnsetTimerInterface(RPCTimerInterface *iface) override {
             RPCUnsetTimerInterface(iface);
         }
         bool getUnspentOutput(const COutPoint &output, Coin &coin) override {
             LOCK(::cs_main);
             return ::ChainstateActive().CoinsTip().GetCoin(output, coin);
         }
         std::string getWalletDir() override { return GetWalletDir().string(); }
         std::vector<std::string> listWalletDir() override {
             std::vector<std::string> paths;
             for (auto &path : ListWalletDir()) {
                 paths.push_back(path.string());
             }
             return paths;
         }
         std::vector<std::unique_ptr<Wallet>> getWallets() override {
             std::vector<std::unique_ptr<Wallet>> wallets;
-            for (auto &client : m_context.chain_clients) {
+            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<Wallet>
         loadWallet(const CChainParams &params, const std::string &name,
                    bilingual_str &error,
                    std::vector<bilingual_str> &warnings) const override {
             return MakeWallet(
-                LoadWallet(params, *m_context.chain, name, error, warnings));
+                LoadWallet(params, *m_context->chain, name, error, warnings));
         }
         WalletCreationStatus
         createWallet(const CChainParams &params, const SecureString &passphrase,
                      uint64_t wallet_creation_flags, const std::string &name,
                      bilingual_str &error, std::vector<bilingual_str> &warnings,
                      std::unique_ptr<Wallet> &result) override {
             std::shared_ptr<CWallet> wallet;
             WalletCreationStatus status = CreateWallet(
-                params, *m_context.chain, passphrase, wallet_creation_flags,
+                params, *m_context->chain, passphrase, wallet_creation_flags,
                 name, error, warnings, wallet);
             result = MakeWallet(wallet);
             return status;
         }
         std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override {
             return MakeHandler(::uiInterface.InitMessage_connect(fn));
         }
         std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) override {
             return MakeHandler(::uiInterface.ThreadSafeMessageBox_connect(fn));
         }
         std::unique_ptr<Handler> handleQuestion(QuestionFn fn) override {
             return MakeHandler(::uiInterface.ThreadSafeQuestion_connect(fn));
         }
         std::unique_ptr<Handler>
         handleShowProgress(ShowProgressFn fn) override {
             return MakeHandler(::uiInterface.ShowProgress_connect(fn));
         }
         std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) override {
             return HandleLoadWallet(std::move(fn));
         }
         std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(
             NotifyNumConnectionsChangedFn fn) override {
             return MakeHandler(
                 ::uiInterface.NotifyNumConnectionsChanged_connect(fn));
         }
         std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(
             NotifyNetworkActiveChangedFn fn) override {
             return MakeHandler(
                 ::uiInterface.NotifyNetworkActiveChanged_connect(fn));
         }
         std::unique_ptr<Handler>
         handleNotifyAlertChanged(NotifyAlertChangedFn fn) override {
             return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn));
         }
         std::unique_ptr<Handler>
         handleBannedListChanged(BannedListChangedFn fn) override {
             return MakeHandler(::uiInterface.BannedListChanged_connect(fn));
         }
         std::unique_ptr<Handler>
         handleNotifyBlockTip(NotifyBlockTipFn fn) override {
             return MakeHandler(::uiInterface.NotifyBlockTip_connect(
                 [fn](bool initial_download, const CBlockIndex *block) {
                     fn(initial_download, block->nHeight, block->GetBlockTime(),
                        GuessVerificationProgress(Params().TxData(), block));
                 }));
         }
         std::unique_ptr<Handler>
         handleNotifyHeaderTip(NotifyHeaderTipFn fn) override {
             return MakeHandler(::uiInterface.NotifyHeaderTip_connect(
                 [fn](bool initial_download, const CBlockIndex *block) {
                     fn(initial_download, block->nHeight, block->GetBlockTime(),
                        GuessVerificationProgress(Params().TxData(), block));
                 }));
         }
-        NodeContext *context() override { return &m_context; }
-        NodeContext m_context;
+        NodeContext *context() override { return m_context; }
+        void setContext(NodeContext *context) override {
+            m_context = context;
+            if (context) {
+                m_context_ref.Set(*context);
+            } else {
+                m_context_ref.Clear();
+            }
+        }
+        NodeContext *m_context{nullptr};
         util::Ref m_context_ref{m_context};
     };
 } // namespace
 
-std::unique_ptr<Node> MakeNode() {
-    return std::make_unique<NodeImpl>();
+std::unique_ptr<Node> MakeNode(NodeContext *context) {
+    return std::make_unique<NodeImpl>(context);
 }
 
 } // namespace interfaces
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 2f1320ed7..ba8108090 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -1,296 +1,298 @@
 // Copyright (c) 2018 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #ifndef BITCOIN_INTERFACES_NODE_H
 #define BITCOIN_INTERFACES_NODE_H
 
 #include <amount.h>     // For Amount
 #include <net.h>        // For CConnman::NumConnections
 #include <net_types.h>  // For banmap_t
 #include <netaddress.h> // For Network
 
 #include <support/allocators/secure.h> // For SecureString
 
 #include <cstddef>
 #include <cstdint>
 #include <functional>
 #include <memory>
 #include <string>
 #include <tuple>
 #include <vector>
 
 class BanMan;
 class CCoinControl;
 class CFeeRate;
 struct CNodeStateStats;
 struct CNodeStats;
 class Coin;
 class Config;
 class HTTPRPCRequestProcessor;
 struct NodeContext;
 class proxyType;
 class RPCServer;
 class RPCTimerInterface;
 class UniValue;
 enum class WalletCreationStatus;
 struct bilingual_str;
 
 namespace interfaces {
 class Handler;
 class Wallet;
 
 //! Top-level interface for a bitcoin node (bitcoind process).
 class Node {
 public:
     virtual ~Node() {}
 
     //! Send init error.
     virtual void initError(const std::string &message) = 0;
 
     //! Set command line arguments.
     virtual bool parseParameters(int argc, const char *const argv[],
                                  std::string &error) = 0;
 
     //! Set a command line argument
     virtual void forceSetArg(const std::string &arg,
                              const std::string &value) = 0;
 
     //! Set a command line argument if it doesn't already have a value
     virtual bool softSetArg(const std::string &arg,
                             const std::string &value) = 0;
 
     //! Set a command line boolean argument if it doesn't already have a value
     virtual bool softSetBoolArg(const std::string &arg, bool value) = 0;
 
     //! Load settings from configuration file.
     virtual bool readConfigFiles(std::string &error) = 0;
 
     //! Choose network parameters.
     virtual void selectParams(const std::string &network) = 0;
 
     //! Get the (assumed) blockchain size.
     virtual uint64_t getAssumedBlockchainSize() = 0;
 
     //! Get the (assumed) chain state size.
     virtual uint64_t getAssumedChainStateSize() = 0;
 
     //! Get network name.
     virtual std::string getNetwork() = 0;
 
     //! Init logging.
     virtual void initLogging() = 0;
 
     //! Init parameter interaction.
     virtual void initParameterInteraction() = 0;
 
     //! Get warnings.
     virtual std::string getWarnings(const std::string &type) = 0;
 
     //! Initialize app dependencies.
     virtual bool baseInitialize(Config &config) = 0;
 
     //! Start node.
     virtual bool
     appInitMain(Config &config, RPCServer &rpcServer,
                 HTTPRPCRequestProcessor &httpRPCRequestProcessor) = 0;
 
     //! Stop node.
     virtual void appShutdown() = 0;
 
     //! Start shutdown.
     virtual void startShutdown() = 0;
 
     //! Return whether shutdown was requested.
     virtual bool shutdownRequested() = 0;
 
     //! Setup arguments
     virtual void setupServerArgs() = 0;
 
     //! Map port.
     virtual void mapPort(bool use_upnp) = 0;
 
     //! Get proxy.
     virtual bool getProxy(Network net, proxyType &proxy_info) = 0;
 
     //! Get number of connections.
     virtual size_t getNodeCount(CConnman::NumConnections flags) = 0;
 
     //! Get stats for connected nodes.
     using NodesStats =
         std::vector<std::tuple<CNodeStats, bool, CNodeStateStats>>;
     virtual bool getNodesStats(NodesStats &stats) = 0;
 
     //! Get ban map entries.
     virtual bool getBanned(banmap_t &banmap) = 0;
 
     //! Ban node.
     virtual bool ban(const CNetAddr &net_addr, int64_t ban_time_offset) = 0;
 
     //! Unban node.
     virtual bool unban(const CSubNet &ip) = 0;
 
     //! Disconnect node by address.
     virtual bool disconnect(const CNetAddr &net_addr) = 0;
 
     //! Disconnect node by id.
     virtual bool disconnect(NodeId id) = 0;
 
     //! Get total bytes recv.
     virtual int64_t getTotalBytesRecv() = 0;
 
     //! Get total bytes sent.
     virtual int64_t getTotalBytesSent() = 0;
 
     //! Get mempool size.
     virtual size_t getMempoolSize() = 0;
 
     //! Get mempool dynamic usage.
     virtual size_t getMempoolDynamicUsage() = 0;
 
     //! Get header tip height and time.
     virtual bool getHeaderTip(int &height, int64_t &block_time) = 0;
 
     //! Get num blocks.
     virtual int getNumBlocks() = 0;
 
     //! Get last block time.
     virtual int64_t getLastBlockTime() = 0;
 
     //! Get verification progress.
     virtual double getVerificationProgress() = 0;
 
     //! Is initial block download.
     virtual bool isInitialBlockDownload() = 0;
 
     //! Get reindex.
     virtual bool getReindex() = 0;
 
     //! Get importing.
     virtual bool getImporting() = 0;
 
     //! Set network active.
     virtual void setNetworkActive(bool active) = 0;
 
     //! Get network active.
     virtual bool getNetworkActive() = 0;
 
     //! Estimate smart fee.
     virtual CFeeRate estimateSmartFee() = 0;
 
     //! Get dust relay fee.
     virtual CFeeRate getDustRelayFee() = 0;
 
     //! Execute rpc command.
     virtual UniValue executeRpc(Config &config, const std::string &command,
                                 const UniValue &params,
                                 const std::string &uri) = 0;
 
     //! List rpc commands.
     virtual std::vector<std::string> listRpcCommands() = 0;
 
     //! Set RPC timer interface if unset.
     virtual void rpcSetTimerInterfaceIfUnset(RPCTimerInterface *iface) = 0;
 
     //! Unset RPC timer interface.
     virtual void rpcUnsetTimerInterface(RPCTimerInterface *iface) = 0;
 
     //! 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<std::string> listWalletDir() = 0;
 
     //! Return interfaces for accessing wallets (if any).
     virtual std::vector<std::unique_ptr<Wallet>> 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<Wallet>
     loadWallet(const CChainParams &params, const std::string &name,
                bilingual_str &error,
                std::vector<bilingual_str> &warnings) const = 0;
 
     //! Create a wallet from file
     virtual WalletCreationStatus
     createWallet(const CChainParams &params, const SecureString &passphrase,
                  uint64_t wallet_creation_flags, const std::string &name,
                  bilingual_str &error, std::vector<bilingual_str> &warnings,
                  std::unique_ptr<Wallet> &result) = 0;
 
     //! Register handler for init messages.
     using InitMessageFn = std::function<void(const std::string &message)>;
     virtual std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) = 0;
 
     //! Register handler for message box messages.
     using MessageBoxFn =
         std::function<bool(const bilingual_str &message,
                            const std::string &caption, unsigned int style)>;
     virtual std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) = 0;
 
     //! Register handler for question messages.
     using QuestionFn =
         std::function<bool(const bilingual_str &message,
                            const std::string &non_interactive_message,
                            const std::string &caption, unsigned int style)>;
     virtual std::unique_ptr<Handler> handleQuestion(QuestionFn fn) = 0;
 
     //! Register handler for progress messages.
     using ShowProgressFn = std::function<void(
         const std::string &title, int progress, bool resume_possible)>;
     virtual std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) = 0;
 
     //! Register handler for load wallet messages.
     using LoadWalletFn = std::function<void(std::unique_ptr<Wallet> wallet)>;
     virtual std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) = 0;
 
     //! Register handler for number of connections changed messages.
     using NotifyNumConnectionsChangedFn =
         std::function<void(int new_num_connections)>;
     virtual std::unique_ptr<Handler>
     handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) = 0;
 
     //! Register handler for network active messages.
     using NotifyNetworkActiveChangedFn =
         std::function<void(bool network_active)>;
     virtual std::unique_ptr<Handler>
     handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) = 0;
 
     //! Register handler for notify alert messages.
     using NotifyAlertChangedFn = std::function<void()>;
     virtual std::unique_ptr<Handler>
     handleNotifyAlertChanged(NotifyAlertChangedFn fn) = 0;
 
     //! Register handler for ban list messages.
     using BannedListChangedFn = std::function<void()>;
     virtual std::unique_ptr<Handler>
     handleBannedListChanged(BannedListChangedFn fn) = 0;
 
     //! Register handler for block tip messages.
     using NotifyBlockTipFn =
         std::function<void(bool initial_download, int height,
                            int64_t block_time, double verification_progress)>;
     virtual std::unique_ptr<Handler>
     handleNotifyBlockTip(NotifyBlockTipFn fn) = 0;
 
     //! Register handler for header tip messages.
     using NotifyHeaderTipFn =
         std::function<void(bool initial_download, int height,
                            int64_t block_time, double verification_progress)>;
     virtual std::unique_ptr<Handler>
     handleNotifyHeaderTip(NotifyHeaderTipFn fn) = 0;
 
-    //! Return pointer to internal chain interface, useful for testing.
+    //! Get and set internal node context. Useful for testing, but not
+    //! accessible across processes.
     virtual NodeContext *context() { return nullptr; }
+    virtual void setContext(NodeContext *context) {}
 };
 
 //! Return implementation of Node interface.
-std::unique_ptr<Node> MakeNode();
+std::unique_ptr<Node> MakeNode(NodeContext *context = nullptr);
 
 } // namespace interfaces
 
 #endif // BITCOIN_INTERFACES_NODE_H
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 7a8c39439..e0bce4797 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -1,765 +1,768 @@
 // Copyright (c) 2011-2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <qt/bitcoin.h>
 
 #include <chainparams.h>
 #include <config.h>
 #include <httprpc.h>
 #include <interfaces/handler.h>
 #include <interfaces/node.h>
+#include <node/context.h>
 #include <noui.h>
 #include <qt/bitcoingui.h>
 #include <qt/clientmodel.h>
 #include <qt/guiconstants.h>
 #include <qt/guiutil.h>
 #include <qt/intro.h>
 #include <qt/networkstyle.h>
 #include <qt/optionsmodel.h>
 #include <qt/platformstyle.h>
 #include <qt/splashscreen.h>
 #include <qt/utilitydialog.h>
 #include <qt/winshutdownmonitor.h>
 #include <ui_interface.h>
 #include <uint256.h>
 #include <util/ref.h>
 #include <util/system.h>
 #include <util/threadnames.h>
 
 #ifdef ENABLE_WALLET
 #include <qt/paymentserver.h>
 #include <qt/walletcontroller.h>
 #include <qt/walletmodel.h>
 #endif // ENABLE_WALLET
 
 #include <QDebug>
 #include <QLibraryInfo>
 #include <QLocale>
 #include <QMessageBox>
 #include <QSettings>
 #include <QStringList>
 #include <QThread>
 #include <QTimer>
 #include <QTranslator>
 
 #if defined(QT_STATICPLUGIN)
 #include <QtPlugin>
 #if defined(QT_QPA_PLATFORM_XCB)
 Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
 #elif defined(QT_QPA_PLATFORM_WINDOWS)
 Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
 #elif defined(QT_QPA_PLATFORM_COCOA)
 Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
 #endif
 #endif
 
 // Declare meta types used for QMetaObject::invokeMethod
 Q_DECLARE_METATYPE(bool *)
 Q_DECLARE_METATYPE(Amount)
 Q_DECLARE_METATYPE(uint256)
 
 // Config is non-copyable so we can only register pointers to it
 Q_DECLARE_METATYPE(Config *)
 
 static QString GetLangTerritory() {
     QSettings settings;
     // Get desired locale (e.g. "de_DE")
     // 1) System default language
     QString lang_territory = QLocale::system().name();
     // 2) Language from QSettings
     QString lang_territory_qsettings =
         settings.value("language", "").toString();
     if (!lang_territory_qsettings.isEmpty()) {
         lang_territory = lang_territory_qsettings;
     }
     // 3) -lang command line argument
     lang_territory = QString::fromStdString(
         gArgs.GetArg("-lang", lang_territory.toStdString()));
     return lang_territory;
 }
 
 /** Set up translations */
 static void initTranslations(QTranslator &qtTranslatorBase,
                              QTranslator &qtTranslator,
                              QTranslator &translatorBase,
                              QTranslator &translator) {
     // Remove old translators
     QApplication::removeTranslator(&qtTranslatorBase);
     QApplication::removeTranslator(&qtTranslator);
     QApplication::removeTranslator(&translatorBase);
     QApplication::removeTranslator(&translator);
 
     // Get desired locale (e.g. "de_DE")
     // 1) System default language
     QString lang_territory = GetLangTerritory();
 
     // Convert to "de" only by truncating "_DE"
     QString lang = lang_territory;
     lang.truncate(lang_territory.lastIndexOf('_'));
 
     // Load language files for configured locale:
     // - First load the translator for the base language, without territory
     // - Then load the more specific locale translator
 
     // Load e.g. qt_de.qm
     if (qtTranslatorBase.load(
             "qt_" + lang,
             QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
         QApplication::installTranslator(&qtTranslatorBase);
     }
 
     // Load e.g. qt_de_DE.qm
     if (qtTranslator.load(
             "qt_" + lang_territory,
             QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
         QApplication::installTranslator(&qtTranslator);
     }
 
     // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in
     // bitcoin.qrc)
     if (translatorBase.load(lang, ":/translations/")) {
         QApplication::installTranslator(&translatorBase);
     }
 
     // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in
     // bitcoin.qrc)
     if (translator.load(lang_territory, ":/translations/")) {
         QApplication::installTranslator(&translator);
     }
 }
 
 /* qDebug() message handler --> debug.log */
 void DebugMessageHandler(QtMsgType type, const QMessageLogContext &context,
                          const QString &msg) {
     Q_UNUSED(context);
     if (type == QtDebugMsg) {
         LogPrint(BCLog::QT, "GUI: %s\n", msg.toStdString());
     } else {
         LogPrintf("GUI: %s\n", msg.toStdString());
     }
 }
 
 BitcoinABC::BitcoinABC(interfaces::Node &node) : QObject(), m_node(node) {}
 
 void BitcoinABC::handleRunawayException(const std::exception *e) {
     PrintExceptionContinue(e, "Runaway exception");
     Q_EMIT runawayException(QString::fromStdString(m_node.getWarnings("gui")));
 }
 
 void BitcoinABC::initialize(Config *config, RPCServer *rpcServer,
                             HTTPRPCRequestProcessor *httpRPCRequestProcessor) {
     try {
         qDebug() << __func__ << ": Running initialization in thread";
         util::ThreadRename("qt-init");
         bool rv =
             m_node.appInitMain(*config, *rpcServer, *httpRPCRequestProcessor);
         Q_EMIT initializeResult(rv);
     } catch (const std::exception &e) {
         handleRunawayException(&e);
     } catch (...) {
         handleRunawayException(nullptr);
     }
 }
 
 void BitcoinABC::shutdown() {
     try {
         qDebug() << __func__ << ": Running Shutdown in thread";
         m_node.appShutdown();
         qDebug() << __func__ << ": Shutdown finished";
         Q_EMIT shutdownResult();
     } catch (const std::exception &e) {
         handleRunawayException(&e);
     } catch (...) {
         handleRunawayException(nullptr);
     }
 }
 
 static int qt_argc = 1;
 static const char *qt_argv = "bitcoin-qt";
 
 BitcoinApplication::BitcoinApplication(interfaces::Node &node)
     : QApplication(qt_argc, const_cast<char **>(&qt_argv)), coreThread(nullptr),
       m_node(node), optionsModel(nullptr), clientModel(nullptr),
       window(nullptr), pollShutdownTimer(nullptr), returnValue(0),
       platformStyle(nullptr) {
     setQuitOnLastWindowClosed(false);
 }
 
 void BitcoinApplication::setupPlatformStyle() {
     // UI per-platform customization
     // This must be done inside the BitcoinApplication constructor, or after it,
     // because PlatformStyle::instantiate requires a QApplication.
     std::string platformName;
     platformName = gArgs.GetArg("-uiplatform", BitcoinGUI::DEFAULT_UIPLATFORM);
     platformStyle =
         PlatformStyle::instantiate(QString::fromStdString(platformName));
     // Fall back to "other" if specified name not found.
     if (!platformStyle) {
         platformStyle = PlatformStyle::instantiate("other");
     }
     assert(platformStyle);
 }
 
 BitcoinApplication::~BitcoinApplication() {
     if (coreThread) {
         qDebug() << __func__ << ": Stopping thread";
         coreThread->quit();
         coreThread->wait();
         qDebug() << __func__ << ": Stopped thread";
     }
 
     delete window;
     window = nullptr;
     delete optionsModel;
     optionsModel = nullptr;
     delete platformStyle;
     platformStyle = nullptr;
 }
 
 #ifdef ENABLE_WALLET
 void BitcoinApplication::createPaymentServer() {
     paymentServer = new PaymentServer(this);
 }
 #endif
 
 void BitcoinApplication::createOptionsModel(bool resetSettings) {
     optionsModel = new OptionsModel(m_node, nullptr, resetSettings);
 }
 
 void BitcoinApplication::createWindow(const Config *config,
                                       const NetworkStyle *networkStyle) {
     window =
         new BitcoinGUI(m_node, config, platformStyle, networkStyle, nullptr);
 
     pollShutdownTimer = new QTimer(window);
     connect(pollShutdownTimer, &QTimer::timeout, window,
             &BitcoinGUI::detectShutdown);
 }
 
 void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) {
     SplashScreen *splash = new SplashScreen(m_node, networkStyle);
     // We don't hold a direct pointer to the splash screen after creation, but
     // the splash screen will take care of deleting itself when finish()
     // happens.
     splash->show();
     connect(this, &BitcoinApplication::splashFinished, splash,
             &SplashScreen::finish);
     connect(this, &BitcoinApplication::requestedShutdown, splash,
             &QWidget::close);
 }
 
 bool BitcoinApplication::baseInitialize(Config &config) {
     return m_node.baseInitialize(config);
 }
 
 void BitcoinApplication::startThread() {
     if (coreThread) {
         return;
     }
     coreThread = new QThread(this);
     BitcoinABC *executor = new BitcoinABC(m_node);
     executor->moveToThread(coreThread);
 
     /*  communication to and from thread */
     connect(executor, &BitcoinABC::initializeResult, this,
             &BitcoinApplication::initializeResult);
     connect(executor, &BitcoinABC::shutdownResult, this,
             &BitcoinApplication::shutdownResult);
     connect(executor, &BitcoinABC::runawayException, this,
             &BitcoinApplication::handleRunawayException);
 
     // Note on how Qt works: it tries to directly invoke methods if the signal
     // is emitted on the same thread that the target object 'lives' on.
     // But if the target object 'lives' on another thread (executor here does)
     // the SLOT will be invoked asynchronously at a later time in the thread
     // of the target object.  So.. we pass a pointer around.  If you pass
     // a reference around (even if it's non-const) you'll get Qt generating
     // code to copy-construct the parameter in question (Q_DECLARE_METATYPE
     // and qRegisterMetaType generate this code).  For the Config class,
     // which is noncopyable, we can't do this.  So.. we have to pass
     // pointers to Config around.  Make sure Config &/Config * isn't a
     // temporary (eg it lives somewhere aside from the stack) or this will
     // crash because initialize() gets executed in another thread at some
     // unspecified time (after) requestedInitialize() is emitted!
     connect(this, &BitcoinApplication::requestedInitialize, executor,
             &BitcoinABC::initialize);
 
     connect(this, &BitcoinApplication::requestedShutdown, executor,
             &BitcoinABC::shutdown);
     /*  make sure executor object is deleted in its own thread */
     connect(coreThread, &QThread::finished, executor, &QObject::deleteLater);
 
     coreThread->start();
 }
 
 void BitcoinApplication::parameterSetup() {
     // Default printtoconsole to false for the GUI. GUI programs should not
     // print to the console unnecessarily.
     gArgs.SoftSetBoolArg("-printtoconsole", false);
 
     m_node.initLogging();
     m_node.initParameterInteraction();
 }
 
 void BitcoinApplication::SetPrune(bool prune, bool force) {
     optionsModel->SetPrune(prune, force);
 }
 
 void BitcoinApplication::requestInitialize(
     Config &config, RPCServer &rpcServer,
     HTTPRPCRequestProcessor &httpRPCRequestProcessor) {
     qDebug() << __func__ << ": Requesting initialize";
     startThread();
     // IMPORTANT: config must NOT be a reference to a temporary because below
     // signal may be connected to a slot that will be executed as a queued
     // connection in another thread!
     Q_EMIT requestedInitialize(&config, &rpcServer, &httpRPCRequestProcessor);
 }
 
 void BitcoinApplication::requestShutdown(Config &config) {
     // Show a simple window indicating shutdown status. Do this first as some of
     // the steps may take some time below, for example the RPC console may still
     // be executing a command.
     shutdownWindow.reset(ShutdownWindow::showShutdownWindow(window));
 
     qDebug() << __func__ << ": Requesting shutdown";
     startThread();
     window->hide();
     // Must disconnect node signals otherwise current thread can deadlock since
     // no event loop is running.
     window->unsubscribeFromCoreSignals();
     // Request node shutdown, which can interrupt long operations, like
     // rescanning a wallet.
     m_node.startShutdown();
     // Unsetting the client model can cause the current thread to wait for node
     // to complete an operation, like wait for a RPC execution to complate.
     window->setClientModel(nullptr);
     pollShutdownTimer->stop();
 
     delete clientModel;
     clientModel = nullptr;
 
     // Request shutdown from core thread
     Q_EMIT requestedShutdown();
 }
 
 void BitcoinApplication::initializeResult(bool success) {
     qDebug() << __func__ << ": Initialization result: " << success;
     returnValue = success ? EXIT_SUCCESS : EXIT_FAILURE;
     if (!success) {
         // Make sure splash screen doesn't stick around during shutdown.
         Q_EMIT splashFinished();
         // Exit first main loop invocation.
         quit();
         return;
     }
     // Log this only after AppInitMain finishes, as then logging setup is
     // guaranteed complete.
     qWarning() << "Platform customization:" << platformStyle->getName();
     clientModel = new ClientModel(m_node, optionsModel);
     window->setClientModel(clientModel);
 #ifdef ENABLE_WALLET
     if (WalletModel::isWalletEnabled()) {
         m_wallet_controller =
             new WalletController(m_node, platformStyle, optionsModel, this);
         window->setWalletController(m_wallet_controller);
         if (paymentServer) {
             paymentServer->setOptionsModel(optionsModel);
 #ifdef ENABLE_BIP70
             PaymentServer::LoadRootCAs();
             connect(m_wallet_controller, &WalletController::coinsSent,
                     paymentServer, &PaymentServer::fetchPaymentACK);
 #endif
         }
     }
 #endif // ENABLE_WALLET
 
     // If -min option passed, start window minimized(iconified)
     // or minimized to tray
     if (!gArgs.GetBoolArg("-min", false)) {
         window->show();
     } else if (clientModel->getOptionsModel()->getMinimizeToTray() &&
                window->hasTrayIcon()) {
         // do nothing as the window is managed by the tray icon
     } else {
         window->showMinimized();
     }
     Q_EMIT splashFinished();
     Q_EMIT windowShown(window);
 
 #ifdef ENABLE_WALLET
     // Now that initialization/startup is done, process any command-line
     // bitcoincash: URIs or payment requests:
     if (paymentServer) {
         connect(paymentServer, &PaymentServer::receivedPaymentRequest, window,
                 &BitcoinGUI::handlePaymentRequest);
         connect(window, &BitcoinGUI::receivedURI, paymentServer,
                 &PaymentServer::handleURIOrFile);
         connect(paymentServer, &PaymentServer::message,
                 [this](const QString &title, const QString &message,
                        unsigned int style) {
                     window->message(title, message, style);
                 });
         QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady);
     }
 #endif
 
     pollShutdownTimer->start(200);
 }
 
 void BitcoinApplication::shutdownResult() {
     // Exit second main loop invocation after shutdown finished.
     quit();
 }
 
 void BitcoinApplication::handleRunawayException(const QString &message) {
     QMessageBox::critical(
         nullptr, "Runaway exception",
         BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue "
                        "safely and will quit.") +
             QString("\n\n") + message);
     ::exit(EXIT_FAILURE);
 }
 
 WId BitcoinApplication::getMainWinId() const {
     if (!window) {
         return 0;
     }
 
     return window->winId();
 }
 
 static void SetupUIArgs() {
 #if defined(ENABLE_WALLET) && defined(ENABLE_BIP70)
     gArgs.AddArg("-allowselfsignedrootcertificates",
                  strprintf("Allow self signed root certificates (default: %d)",
                            DEFAULT_SELFSIGNED_ROOTCERTS),
                  ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                  OptionsCategory::GUI);
 #endif
     gArgs.AddArg("-choosedatadir",
                  strprintf("Choose data directory on startup (default: %d)",
                            DEFAULT_CHOOSE_DATADIR),
                  ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
     gArgs.AddArg("-lang=<lang>",
                  "Set language, for example \"de_DE\" (default: system locale)",
                  ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
     gArgs.AddArg("-min", "Start minimized", ArgsManager::ALLOW_ANY,
                  OptionsCategory::GUI);
     gArgs.AddArg(
         "-rootcertificates=<file>",
         "Set SSL root certificates for payment request (default: -system-)",
         ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
     gArgs.AddArg("-splash",
                  strprintf("Show splash screen on startup (default: %d)",
                            DEFAULT_SPLASHSCREEN),
                  ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
     gArgs.AddArg("-resetguisettings", "Reset all settings changed in the GUI",
                  ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
     gArgs.AddArg("-uiplatform",
                  strprintf("Select platform to customize UI for (one of "
                            "windows, macosx, other; default: %s)",
                            BitcoinGUI::DEFAULT_UIPLATFORM),
                  ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                  OptionsCategory::GUI);
 }
 
 static void MigrateSettings() {
     assert(!QApplication::applicationName().isEmpty());
 
     static const QString legacyAppName("Bitcoin-Qt"),
 #ifdef Q_OS_DARWIN
         // Macs and/or iOS et al use a domain-style name for Settings
         // files. All other platforms use a simple orgname. This
         // difference is documented in the QSettings class documentation.
         legacyOrg("bitcoin.org");
 #else
         legacyOrg("Bitcoin");
 #endif
     QSettings
         // below picks up settings file location based on orgname,appname
         legacy(legacyOrg, legacyAppName),
         // default c'tor below picks up settings file location based on
         // QApplication::applicationName(), et al -- which was already set
         // in main()
         abc;
 #ifdef Q_OS_DARWIN
     // Disable bogus OSX keys from MacOS system-wide prefs that may cloud our
     // judgement ;) (this behavior is also documented in QSettings docs)
     legacy.setFallbacksEnabled(false);
     abc.setFallbacksEnabled(false);
 #endif
     const QStringList legacyKeys(legacy.allKeys());
 
     // We only migrate settings if we have Core settings but no Bitcoin-ABC
     // settings
     if (!legacyKeys.isEmpty() && abc.allKeys().isEmpty()) {
         for (const QString &key : legacyKeys) {
             // now, copy settings over
             abc.setValue(key, legacy.value(key));
         }
     }
 }
 
 int GuiMain(int argc, char *argv[]) {
 #ifdef WIN32
     util::WinCmdLineArgs winArgs;
     std::tie(argc, argv) = winArgs.get();
 #endif
     SetupEnvironment();
     util::ThreadSetInternalName("main");
 
-    std::unique_ptr<interfaces::Node> node = interfaces::MakeNode();
+    NodeContext node_context;
+    std::unique_ptr<interfaces::Node> node =
+        interfaces::MakeNode(&node_context);
 
     // Subscribe to global signals from core
     std::unique_ptr<interfaces::Handler> handler_message_box =
         node->handleMessageBox(noui_ThreadSafeMessageBox);
     std::unique_ptr<interfaces::Handler> handler_question =
         node->handleQuestion(noui_ThreadSafeQuestion);
     std::unique_ptr<interfaces::Handler> handler_init_message =
         node->handleInitMessage(noui_InitMessage);
 
     // Do not refer to data directory yet, this can be overridden by
     // Intro::pickDataDirectory
 
     /// 1. Basic Qt initialization (not dependent on parameters or
     /// configuration)
     Q_INIT_RESOURCE(bitcoin);
     Q_INIT_RESOURCE(bitcoin_locale);
 
     // Generate high-dpi pixmaps
     QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
     QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
 #ifdef Q_OS_MAC
     QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
 #endif
 
     BitcoinApplication app(*node);
 
     // Register meta types used for QMetaObject::invokeMethod
     qRegisterMetaType<bool *>();
 #ifdef ENABLE_WALLET
     qRegisterMetaType<WalletModel *>();
 #endif
     //   Need to pass name here as Amount is a typedef (see
     //   http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
     //   IMPORTANT if it is no longer a typedef use the normal variant above
     qRegisterMetaType<Amount>("Amount");
     qRegisterMetaType<std::function<void()>>("std::function<void()>");
     qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
 
     // Need to register any types Qt doesn't know about if you intend
     // to use them with the signal/slot mechanism Qt provides. Even pointers.
     // Note that class Config is noncopyable and so we can't register a
     // non-pointer version of it with Qt, because Qt expects to be able to
     // copy-construct non-pointers to objects for invoking slots
     // behind-the-scenes in the 'Queued' connection case.
     qRegisterMetaType<Config *>();
 
     /// 2. Parse command-line options. We do this after qt in order to show an
     /// error if there are problems parsing these
     // Command-line options take precedence:
     node->setupServerArgs();
     SetupUIArgs();
     std::string error;
     if (!node->parseParameters(argc, argv, error)) {
         node->initError(
             strprintf("Error parsing command line arguments: %s\n", error));
         // Create a message box, because the gui has neither been created nor
         // has subscribed to core signals
         QMessageBox::critical(
             nullptr, PACKAGE_NAME,
             // message can not be translated because translations have not been
             // initialized
             QString::fromStdString("Error parsing command line arguments: %1.")
                 .arg(QString::fromStdString(error)));
         return EXIT_FAILURE;
     }
 
     // Now that the QApplication is setup and we have parsed our parameters, we
     // can set the platform style
     app.setupPlatformStyle();
 
     /// 3. Application identification
     // must be set before OptionsModel is initialized or translations are
     // loaded, as it is used to locate QSettings.
     // Note: If you move these calls somewhere else, be sure to bring
     // MigrateSettings() below along for the ride.
     QApplication::setOrganizationName(QAPP_ORG_NAME);
     QApplication::setOrganizationDomain(QAPP_ORG_DOMAIN);
     QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT);
     // Migrate settings from core's/our old GUI settings to Bitcoin ABC
     // only if core's exist but Bitcoin ABC's doesn't.
     // NOTE -- this function needs to be called *after* the above 3 lines
     // that set the app orgname and app name! If you move the above 3 lines
     // to elsewhere, take this call with you!
     MigrateSettings();
 
     /// 4. Initialization of translations, so that intro dialog is in user's
     /// language. Now that QSettings are accessible, initialize translations.
     QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
     initTranslations(qtTranslatorBase, qtTranslator, translatorBase,
                      translator);
 
     // Show help message immediately after parsing command-line options (for
     // "-lang") and setting locale, but before showing splash screen.
     if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
         HelpMessageDialog help(*node, nullptr, gArgs.IsArgSet("-version"));
         help.showOrPrint();
         return EXIT_SUCCESS;
     }
 
     /// 5. Now that settings and translations are available, ask user for data
     /// directory. User language is set up: pick a data directory.
     bool did_show_intro = false;
     // Intro dialog prune check box
     bool prune = false;
     // Gracefully exit if the user cancels
     if (!Intro::showIfNeeded(*node, did_show_intro, prune)) {
         return EXIT_SUCCESS;
     }
 
     /// 6. Determine availability of data directory and parse
     /// bitcoin.conf
     /// - Do not call GetDataDir(true) before this step finishes.
     if (!CheckDataDirOption()) {
         node->initError(
             strprintf("Specified data directory \"%s\" does not exist.\n",
                       gArgs.GetArg("-datadir", "")));
         QMessageBox::critical(
             nullptr, PACKAGE_NAME,
             QObject::tr(
                 "Error: Specified data directory \"%1\" does not exist.")
                 .arg(QString::fromStdString(gArgs.GetArg("-datadir", ""))));
         return EXIT_FAILURE;
     }
     if (!node->readConfigFiles(error)) {
         node->initError(
             strprintf("Error reading configuration file: %s\n", error));
         QMessageBox::critical(
             nullptr, PACKAGE_NAME,
             QObject::tr("Error: Cannot parse configuration file: %1.")
                 .arg(QString::fromStdString(error)));
         return EXIT_FAILURE;
     }
 
     /// 7. Determine network (and switch to network specific options)
     // - Do not call Params() before this step.
     // - Do this after parsing the configuration file, as the network can be
     // switched there.
     // - QSettings() will use the new application name after this, resulting in
     // network-specific settings.
     // - Needs to be done before createOptionsModel.
 
     // Check for -chain, -testnet or -regtest parameter (Params() calls are only
     // valid after this clause)
     try {
         node->selectParams(gArgs.GetChainName());
     } catch (std::exception &e) {
         node->initError(strprintf("%s\n", e.what()));
         QMessageBox::critical(nullptr, PACKAGE_NAME,
                               QObject::tr("Error: %1").arg(e.what()));
         return EXIT_FAILURE;
     }
 #ifdef ENABLE_WALLET
     // Parse URIs on command line -- this can affect Params()
     PaymentServer::ipcParseCommandLine(*node, argc, argv);
 #endif
 
     QScopedPointer<const NetworkStyle> networkStyle(
         NetworkStyle::instantiate(Params().NetworkIDString()));
     assert(!networkStyle.isNull());
     // Allow for separate UI settings for testnets
     QApplication::setApplicationName(networkStyle->getAppName());
     // Re-initialize translations after changing application name (language in
     // network-specific settings can be different)
     initTranslations(qtTranslatorBase, qtTranslator, translatorBase,
                      translator);
 
 #ifdef ENABLE_WALLET
     /// 8. URI IPC sending
     // - Do this early as we don't want to bother initializing if we are just
     // calling IPC
     // - Do this *after* setting up the data directory, as the data directory
     // hash is used in the name
     // of the server.
     // - Do this after creating app and setting up translations, so errors are
     // translated properly.
     if (PaymentServer::ipcSendCommandLine()) {
         exit(EXIT_SUCCESS);
     }
 
     // Start up the payment server early, too, so impatient users that click on
     // bitcoincash: links repeatedly have their payment requests routed to this
     // process:
     if (WalletModel::isWalletEnabled()) {
         app.createPaymentServer();
     }
 #endif // ENABLE_WALLET
 
     /// 9. Main GUI initialization
     // Install global event filter that makes sure that long tooltips can be
     // word-wrapped.
     app.installEventFilter(
         new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
 #if defined(Q_OS_WIN)
     // Install global event filter for processing Windows session related
     // Windows messages (WM_QUERYENDSESSION and WM_ENDSESSION)
     qApp->installNativeEventFilter(new WinShutdownMonitor());
 #endif
     // Install qDebug() message handler to route to debug.log
     qInstallMessageHandler(DebugMessageHandler);
     // Allow parameter interaction before we create the options model
     app.parameterSetup();
     // Load GUI settings from QSettings
     app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false));
 
     if (did_show_intro) {
         // Store intro dialog settings other than datadir (network specific)
         app.SetPrune(prune, true);
     }
 
     // Get global config
     Config &config = const_cast<Config &>(GetConfig());
 
     if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) &&
         !gArgs.GetBoolArg("-min", false)) {
         app.createSplashScreen(networkStyle.data());
     }
 
     RPCServer rpcServer;
     util::Ref context{node};
     HTTPRPCRequestProcessor httpRPCRequestProcessor(config, rpcServer, context);
 
     try {
         app.createWindow(&config, networkStyle.data());
         // Perform base initialization before spinning up
         // initialization/shutdown thread. This is acceptable because this
         // function only contains steps that are quick to execute, so the GUI
         // thread won't be held up.
         if (!app.baseInitialize(config)) {
             // A dialog with detailed error will have been shown by InitError()
             return EXIT_FAILURE;
         }
         app.requestInitialize(config, rpcServer, httpRPCRequestProcessor);
 #if defined(Q_OS_WIN)
         WinShutdownMonitor::registerShutdownBlockReason(
             QObject::tr("%1 didn't yet exit safely...").arg(PACKAGE_NAME),
             (HWND)app.getMainWinId());
 #endif
         app.exec();
         app.requestShutdown(config);
         app.exec();
         return app.getReturnValue();
     } catch (const std::exception &e) {
         PrintExceptionContinue(&e, "Runaway exception");
         app.handleRunawayException(
             QString::fromStdString(node->getWarnings("gui")));
     } catch (...) {
         PrintExceptionContinue(nullptr, "Runaway exception");
         app.handleRunawayException(
             QString::fromStdString(node->getWarnings("gui")));
     }
     return EXIT_FAILURE;
 }
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index d53236286..5dff53320 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -1,166 +1,168 @@
 #include <qt/test/addressbooktests.h>
 #include <test/util/setup_common.h>
 
 #include <interfaces/chain.h>
 #include <interfaces/node.h>
 #include <qt/editaddressdialog.h>
 #include <qt/optionsmodel.h>
 #include <qt/platformstyle.h>
 #include <qt/qvalidatedlineedit.h>
 #include <qt/test/util.h>
 #include <qt/walletmodel.h>
 
 #include <cashaddrenc.h>
 #include <key.h>
 #include <key_io.h>
 #include <wallet/wallet.h>
+#include <walletinitinterface.h>
 
 #include <QApplication>
 #include <QMessageBox>
 #include <QTimer>
 
 #include <memory>
 
 namespace {
 
 /**
  * Fill the edit address dialog box with data, submit it, and ensure that
  * the resulting message meets expectations.
  */
 void EditAddressAndSubmit(EditAddressDialog *dialog, const QString &label,
                           const QString &address, QString expected_msg) {
     QString warning_text;
 
     dialog->findChild<QLineEdit *>("labelEdit")->setText(label);
     dialog->findChild<QValidatedLineEdit *>("addressEdit")->setText(address);
 
     ConfirmMessage(&warning_text, 5);
     dialog->accept();
     QCOMPARE(warning_text, expected_msg);
 }
 
 /**
  * Test adding various send addresses to the address book.
  *
  * There are three cases tested:
  *
  *   - new_address: a new address which should add as a send address
  * successfully.
  *   - existing_s_address: an existing sending address which won't add
  * successfully.
  *   - existing_r_address: an existing receiving address which won't add
  * successfully.
  *
  * In each case, verify the resulting state of the address book and optionally
  * the warning message presented to the user.
  */
 void TestAddAddressesToSendBook(interfaces::Node &node) {
     TestChain100Setup test;
+    node.setContext(&test.m_node);
 
     std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(
         Params(), node.context()->chain.get(), WalletLocation(),
         WalletDatabase::CreateMock());
     wallet->SetupLegacyScriptPubKeyMan();
 
     bool firstRun;
     wallet->LoadWallet(firstRun);
 
     auto build_address = [&wallet]() {
         CKey key;
         key.MakeNewKey(true);
         CTxDestination dest(GetDestinationForKey(
             key.GetPubKey(), wallet->m_default_address_type));
 
         return std::make_pair(
             dest, QString::fromStdString(EncodeCashAddr(dest, Params())));
     };
 
     CTxDestination r_key_dest, s_key_dest;
 
     // Add a preexisting "receive" entry in the address book.
     QString preexisting_r_address;
     QString r_label("already here (r)");
 
     // Add a preexisting "send" entry in the address book.
     QString preexisting_s_address;
     QString s_label("already here (s)");
 
     // Define a new address (which should add to the address book successfully).
     QString new_address;
 
     std::tie(r_key_dest, preexisting_r_address) = build_address();
     std::tie(s_key_dest, preexisting_s_address) = build_address();
     std::tie(std::ignore, new_address) = build_address();
 
     {
         LOCK(wallet->cs_wallet);
         wallet->SetAddressBook(r_key_dest, r_label.toStdString(), "receive");
         wallet->SetAddressBook(s_key_dest, s_label.toStdString(), "send");
     }
 
     auto check_addbook_size = [&wallet](int expected_size) {
         LOCK(wallet->cs_wallet);
         QCOMPARE(static_cast<int>(wallet->m_address_book.size()),
                  expected_size);
     };
 
     // We should start with the two addresses we added earlier and nothing else.
     check_addbook_size(2);
 
     // Initialize relevant QT models.
     std::unique_ptr<const PlatformStyle> platformStyle(
         PlatformStyle::instantiate("other"));
     OptionsModel optionsModel(node);
     AddWallet(wallet);
     WalletModel walletModel(interfaces::MakeWallet(wallet), node,
                             platformStyle.get(), &optionsModel);
     RemoveWallet(wallet);
     EditAddressDialog editAddressDialog(EditAddressDialog::NewSendingAddress);
     editAddressDialog.setModel(walletModel.getAddressTableModel());
 
     EditAddressAndSubmit(
         &editAddressDialog, QString("uhoh"), preexisting_r_address,
         QString(
             "Address \"%1\" already exists as a receiving address with label "
             "\"%2\" and so cannot be added as a sending address.")
             .arg(preexisting_r_address)
             .arg(r_label));
 
     check_addbook_size(2);
 
     EditAddressAndSubmit(
         &editAddressDialog, QString("uhoh, different"), preexisting_s_address,
         QString(
             "The entered address \"%1\" is already in the address book with "
             "label \"%2\".")
             .arg(preexisting_s_address)
             .arg(s_label));
 
     check_addbook_size(2);
 
     // Submit a new address which should add successfully - we expect the
     // warning message to be blank.
     EditAddressAndSubmit(&editAddressDialog, QString("new"), new_address,
                          QString(""));
 
     check_addbook_size(3);
 }
 
 } // namespace
 
 void AddressBookTests::addressBookTests() {
 #ifdef Q_OS_MAC
     if (QApplication::platformName() == "minimal") {
         // Disable for mac on "minimal" platform to avoid crashes inside the Qt
         // framework when it tries to look up unimplemented cocoa functions,
         // and fails to handle returned nulls
         // (https://bugreports.qt.io/browse/QTBUG-49686).
         QWARN("Skipping AddressBookTests on mac build with 'minimal' platform "
               "set due to Qt bugs. To run AppTests, invoke with "
               "'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a "
               "linux or windows build.");
         return;
     }
 #endif
     TestAddAddressesToSendBook(m_node);
 }
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index d39442436..e1c1792ee 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -1,114 +1,116 @@
 // Copyright (c) 2009-2016 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #if defined(HAVE_CONFIG_H)
 #include <config/bitcoin-config.h>
 #endif
 
 #include <compat/setenv.h>
 #include <interfaces/node.h>
 #include <key.h>
 
 #include <qt/bitcoin.h>
 #include <qt/test/apptests.h>
 #include <qt/test/bitcoinaddressvalidatortests.h>
 #include <qt/test/compattests.h>
 #include <qt/test/guiutiltests.h>
 #include <qt/test/rpcnestedtests.h>
 #include <qt/test/uritests.h>
 #ifdef ENABLE_WALLET
 #include <qt/test/addressbooktests.h>
 #ifdef ENABLE_BIP70
 #include <qt/test/paymentservertests.h>
 #endif // ENABLE_BIP70
 #include <qt/test/wallettests.h>
 #endif // ENABLE_WALLET
 
 #include <test/util/setup_common.h>
 
 #include <QApplication>
 #include <QObject>
 #include <QTest>
 
 #if defined(QT_STATICPLUGIN)
 #include <QtPlugin>
 #if defined(QT_QPA_PLATFORM_MINIMAL)
 Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin);
 #endif
 #if defined(QT_QPA_PLATFORM_XCB)
 Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
 #elif defined(QT_QPA_PLATFORM_WINDOWS)
 Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
 #elif defined(QT_QPA_PLATFORM_COCOA)
 Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
 #endif
 #endif
 
 // This is all you need to run all the tests
 int main(int argc, char *argv[]) {
     // Initialize persistent globals with the testing setup state for sanity.
     // E.g. -datadir in gArgs is set to a temp directory dummy value (instead
     // of defaulting to the default datadir), or globalChainParams is set to
     // regtest params.
     //
     // All tests must use their own testing setup (if needed).
     { BasicTestingSetup dummy{CBaseChainParams::REGTEST}; }
 
-    std::unique_ptr<interfaces::Node> node = interfaces::MakeNode();
+    NodeContext node_context;
+    std::unique_ptr<interfaces::Node> node =
+        interfaces::MakeNode(&node_context);
 
     bool fInvalid = false;
 
     // Prefer the "minimal" platform for the test instead of the normal default
     // platform ("xcb", "windows", or "cocoa") so tests can't unintentionally
     // interfere with any background GUIs and don't require extra resources.
     setenv("QT_QPA_PLATFORM", "minimal", /* overwrite */ 0);
 
     // Don't remove this, it's needed to access
     // QApplication:: and QCoreApplication:: in the tests
     BitcoinApplication app(*node);
     app.setApplicationName("BitcoinABC-Qt-test");
 
     AppTests app_tests(app);
     if (QTest::qExec(&app_tests) != 0) {
         fInvalid = true;
     }
     URITests test1;
     if (QTest::qExec(&test1) != 0) {
         fInvalid = true;
     }
 #if defined(ENABLE_WALLET) && defined(ENABLE_BIP70)
     PaymentServerTests test2;
     if (QTest::qExec(&test2) != 0) {
         fInvalid = true;
     }
 #endif
     RPCNestedTests test3(*node);
     if (QTest::qExec(&test3) != 0) {
         fInvalid = true;
     }
     CompatTests test4;
     if (QTest::qExec(&test4) != 0) {
         fInvalid = true;
     }
     GUIUtilTests test5;
     if (QTest::qExec(&test5) != 0) {
         fInvalid = true;
     }
     BitcoinAddressValidatorTests test6;
     if (QTest::qExec(&test6) != 0) {
         fInvalid = true;
     }
 #ifdef ENABLE_WALLET
     WalletTests test7(*node);
     if (QTest::qExec(&test7) != 0) {
         fInvalid = true;
     }
     AddressBookTests test8(*node);
     if (QTest::qExec(&test8) != 0) {
         fInvalid = true;
     }
 #endif
 
     return fInvalid;
 }
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index dbf3624e7..6342ffa28 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -1,263 +1,262 @@
 #include <qt/test/util.h>
 #include <qt/test/wallettests.h>
 
 #include <cashaddrenc.h>
 #include <chain.h>
 #include <chainparams.h>
 #include <interfaces/chain.h>
 #include <interfaces/node.h>
 #include <key_io.h>
 #include <qt/bitcoinamountfield.h>
 #include <qt/optionsmodel.h>
 #include <qt/overviewpage.h>
 #include <qt/platformstyle.h>
 #include <qt/qvalidatedlineedit.h>
 #include <qt/receivecoinsdialog.h>
 #include <qt/receiverequestdialog.h>
 #include <qt/recentrequeststablemodel.h>
 #include <qt/sendcoinsdialog.h>
 #include <qt/sendcoinsentry.h>
 #include <qt/transactiontablemodel.h>
 #include <qt/walletmodel.h>
 #include <validation.h>
 #include <wallet/wallet.h>
 
 #include <test/util/setup_common.h>
 
 #include <QAbstractButton>
 #include <QApplication>
 #include <QDialogButtonBox>
 #include <QListView>
 #include <QPushButton>
 #include <QTextEdit>
 #include <QTimer>
 #include <QVBoxLayout>
 
 #include <memory>
 
 namespace {
 //! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
 void ConfirmSend(QString *text = nullptr, bool cancel = false) {
     QTimer::singleShot(0, Qt::PreciseTimer, [text, cancel]() {
         for (QWidget *widget : QApplication::topLevelWidgets()) {
             if (widget->inherits("SendConfirmationDialog")) {
                 SendConfirmationDialog *dialog =
                     qobject_cast<SendConfirmationDialog *>(widget);
                 if (text) {
                     *text = dialog->text();
                 }
                 QAbstractButton *button = dialog->button(
                     cancel ? QMessageBox::Cancel : QMessageBox::Yes);
                 button->setEnabled(true);
                 button->click();
             }
         }
     });
 }
 
 //! Send coins to address and return txid.
 TxId SendCoins(CWallet &wallet, SendCoinsDialog &sendCoinsDialog,
                const CTxDestination &address, Amount amount) {
     QVBoxLayout *entries = sendCoinsDialog.findChild<QVBoxLayout *>("entries");
     SendCoinsEntry *entry =
         qobject_cast<SendCoinsEntry *>(entries->itemAt(0)->widget());
     entry->findChild<QValidatedLineEdit *>("payTo")->setText(
         QString::fromStdString(EncodeCashAddr(address, Params())));
     entry->findChild<BitcoinAmountField *>("payAmount")->setValue(amount);
     TxId txid;
     boost::signals2::scoped_connection c =
         wallet.NotifyTransactionChanged.connect(
             [&txid](CWallet *, const TxId &hash, ChangeType status) {
                 if (status == CT_NEW) {
                     txid = hash;
                 }
             });
     ConfirmSend();
     bool invoked =
         QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
     assert(invoked);
     return txid;
 }
 
 //! Find index of txid in transaction list.
 QModelIndex FindTx(const QAbstractItemModel &model, const uint256 &txid) {
     QString hash = QString::fromStdString(txid.ToString());
     int rows = model.rowCount({});
     for (int row = 0; row < rows; ++row) {
         QModelIndex index = model.index(row, 0, {});
         if (model.data(index, TransactionTableModel::TxHashRole) == hash) {
             return index;
         }
     }
     return {};
 }
 
 //! Simple qt wallet tests.
 //
 // Test widgets can be debugged interactively calling show() on them and
 // manually running the event loop, e.g.:
 //
 //     sendCoinsDialog.show();
 //     QEventLoop().exec();
 //
 // This also requires overriding the default minimal Qt platform:
 //
 //     QT_QPA_PLATFORM=xcb     src/qt/test/test_bitcoin-qt  # Linux
 //     QT_QPA_PLATFORM=windows src/qt/test/test_bitcoin-qt  # Windows
 //     QT_QPA_PLATFORM=cocoa   src/qt/test/test_bitcoin-qt  # macOS
 void TestGUI(interfaces::Node &node) {
     // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
     TestChain100Setup test;
     for (int i = 0; i < 5; ++i) {
         test.CreateAndProcessBlock(
             {}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
     }
-    node.context()->connman = std::move(test.m_node.connman);
-    node.context()->mempool = std::move(test.m_node.mempool);
+    node.setContext(&test.m_node);
     std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(
         Params(), node.context()->chain.get(), WalletLocation(),
         WalletDatabase::CreateMock());
 
     bool firstRun;
     wallet->LoadWallet(firstRun);
     {
         auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
         LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
         wallet->SetAddressBook(
             GetDestinationForKey(test.coinbaseKey.GetPubKey(),
                                  wallet->m_default_address_type),
             "", "receive");
         spk_man->AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
         wallet->SetLastBlockProcessed(105,
                                       ::ChainActive().Tip()->GetBlockHash());
     }
     {
         WalletRescanReserver reserver(*wallet);
         reserver.reserve();
         CWallet::ScanResult result = wallet->ScanForWalletTransactions(
             Params().GetConsensus().hashGenesisBlock, 0 /* block height */,
             {} /* max height */, reserver, true /* fUpdate */);
         QCOMPARE(result.status, CWallet::ScanResult::SUCCESS);
         QCOMPARE(result.last_scanned_block,
                  ::ChainActive().Tip()->GetBlockHash());
         QVERIFY(result.last_failed_block.IsNull());
     }
     wallet->SetBroadcastTransactions(true);
 
     // Create widgets for sending coins and listing transactions.
     std::unique_ptr<const PlatformStyle> platformStyle(
         PlatformStyle::instantiate("other"));
     OptionsModel optionsModel(node);
     AddWallet(wallet);
     WalletModel walletModel(interfaces::MakeWallet(wallet), node,
                             platformStyle.get(), &optionsModel);
     RemoveWallet(wallet);
 
     // Send two transactions, and verify they are added to transaction list.
     SendCoinsDialog sendCoinsDialog(platformStyle.get(), &walletModel);
     TransactionTableModel *transactionTableModel =
         walletModel.getTransactionTableModel();
     QCOMPARE(transactionTableModel->rowCount({}), 105);
     TxId txid1 = SendCoins(*wallet.get(), sendCoinsDialog,
                            CTxDestination(PKHash()), 5 * COIN);
     TxId txid2 = SendCoins(*wallet.get(), sendCoinsDialog,
                            CTxDestination(PKHash()), 10 * COIN);
     QCOMPARE(transactionTableModel->rowCount({}), 107);
     QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
     QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
 
     // Check current balance on OverviewPage
     OverviewPage overviewPage(platformStyle.get());
     overviewPage.setWalletModel(&walletModel);
     QLabel *balanceLabel = overviewPage.findChild<QLabel *>("labelBalance");
     QString balanceText = balanceLabel->text();
     int unit = walletModel.getOptionsModel()->getDisplayUnit();
     Amount balance = walletModel.wallet().getBalance();
     QString balanceComparison = BitcoinUnits::formatWithUnit(
         unit, balance, false, BitcoinUnits::separatorAlways);
     QCOMPARE(balanceText, balanceComparison);
 
     // Check Request Payment button
     ReceiveCoinsDialog receiveCoinsDialog(platformStyle.get());
     receiveCoinsDialog.setModel(&walletModel);
     RecentRequestsTableModel *requestTableModel =
         walletModel.getRecentRequestsTableModel();
 
     // Label input
     QLineEdit *labelInput =
         receiveCoinsDialog.findChild<QLineEdit *>("reqLabel");
     labelInput->setText("TEST_LABEL_1");
 
     // Amount input
     BitcoinAmountField *amountInput =
         receiveCoinsDialog.findChild<BitcoinAmountField *>("reqAmount");
     amountInput->setValue(1 * SATOSHI);
 
     // Message input
     QLineEdit *messageInput =
         receiveCoinsDialog.findChild<QLineEdit *>("reqMessage");
     messageInput->setText("TEST_MESSAGE_1");
     int initialRowCount = requestTableModel->rowCount({});
     QPushButton *requestPaymentButton =
         receiveCoinsDialog.findChild<QPushButton *>("receiveButton");
     requestPaymentButton->click();
     for (QWidget *widget : QApplication::topLevelWidgets()) {
         if (widget->inherits("ReceiveRequestDialog")) {
             ReceiveRequestDialog *receiveRequestDialog =
                 qobject_cast<ReceiveRequestDialog *>(widget);
             QTextEdit *rlist =
                 receiveRequestDialog->QObject::findChild<QTextEdit *>("outUri");
             QString paymentText = rlist->toPlainText();
             QStringList paymentTextList = paymentText.split('\n');
             QCOMPARE(paymentTextList.at(0), QString("Payment information"));
             QVERIFY(paymentTextList.at(1).indexOf(QString("URI: bchreg:")) !=
                     -1);
             QVERIFY(paymentTextList.at(2).indexOf(QString("Address:")) != -1);
             QCOMPARE(paymentTextList.at(3),
                      QString("Amount: 0.00000001 ") +
                          QString::fromStdString(CURRENCY_UNIT));
             QCOMPARE(paymentTextList.at(4), QString("Label: TEST_LABEL_1"));
             QCOMPARE(paymentTextList.at(5), QString("Message: TEST_MESSAGE_1"));
         }
     }
 
     // Clear button
     QPushButton *clearButton =
         receiveCoinsDialog.findChild<QPushButton *>("clearButton");
     clearButton->click();
     QCOMPARE(labelInput->text(), QString(""));
     QCOMPARE(amountInput->value(), Amount::zero());
     QCOMPARE(messageInput->text(), QString(""));
 
     // Check addition to history
     int currentRowCount = requestTableModel->rowCount({});
     QCOMPARE(currentRowCount, initialRowCount + 1);
 
     // Check Remove button
     QTableView *table =
         receiveCoinsDialog.findChild<QTableView *>("recentRequestsView");
     table->selectRow(currentRowCount - 1);
     QPushButton *removeRequestButton =
         receiveCoinsDialog.findChild<QPushButton *>("removeRequestButton");
     removeRequestButton->click();
     QCOMPARE(requestTableModel->rowCount({}), currentRowCount - 1);
 }
 
 } // namespace
 
 void WalletTests::walletTests() {
 #ifdef Q_OS_MAC
     if (QApplication::platformName() == "minimal") {
         // Disable for mac on "minimal" platform to avoid crashes inside the Qt
         // framework when it tries to look up unimplemented cocoa functions,
         // and fails to handle returned nulls
         // (https://bugreports.qt.io/browse/QTBUG-49686).
         QWARN(
             "Skipping WalletTests on mac build with 'minimal' platform set due "
             "to Qt bugs. To run AppTests, invoke with 'QT_QPA_PLATFORM=cocoa "
             "test_bitcoin-qt' on mac, or else use a linux or windows build.");
         return;
     }
 #endif
     TestGUI(m_node);
 }
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 5edb85eb6..0ee456687 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -1,366 +1,371 @@
 // Copyright (c) 2011-2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <test/util/setup_common.h>
 
 #include <banman.h>
 #include <chainparams.h>
 #include <config.h>
 #include <consensus/consensus.h>
 #include <consensus/validation.h>
 #include <crypto/sha256.h>
 #include <init.h>
+#include <interfaces/chain.h>
 #include <logging.h>
 #include <miner.h>
 #include <net.h>
 #include <noui.h>
 #include <pow/pow.h>
 #include <rpc/blockchain.h>
 #include <rpc/register.h>
 #include <rpc/server.h>
 #include <script/script_error.h>
 #include <script/scriptcache.h>
 #include <script/sigcache.h>
 #include <streams.h>
 #include <txdb.h>
 #include <txmempool.h>
 #include <util/strencodings.h>
 #include <util/time.h>
 #include <util/translation.h>
 #include <util/validation.h>
 #include <validation.h>
 #include <validationinterface.h>
+#include <walletinitinterface.h>
 
 #include <functional>
 #include <memory>
 
 const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr;
 
 FastRandomContext g_insecure_rand_ctx;
 /**
  * Random context to get unique temp data dirs. Separate from
  * g_insecure_rand_ctx, which can be seeded from a const env var
  */
 static FastRandomContext g_insecure_rand_ctx_temp_path;
 
 /**
  * Return the unsigned from the environment var if available,
  * otherwise 0
  */
 static uint256 GetUintFromEnv(const std::string &env_name) {
     const char *num = std::getenv(env_name.c_str());
     if (!num) {
         return {};
     }
     return uint256S(num);
 }
 
 void Seed(FastRandomContext &ctx) {
     // Should be enough to get the seed once for the process
     static uint256 seed{};
     static const std::string RANDOM_CTX_SEED{"RANDOM_CTX_SEED"};
     if (seed.IsNull()) {
         seed = GetUintFromEnv(RANDOM_CTX_SEED);
     }
     if (seed.IsNull()) {
         seed = GetRandHash();
     }
     LogPrintf("%s: Setting random seed for current tests to %s=%s\n", __func__,
               RANDOM_CTX_SEED, seed.GetHex());
     ctx = FastRandomContext(seed);
 }
 
 std::ostream &operator<<(std::ostream &os, const uint256 &num) {
     os << num.ToString();
     return os;
 }
 
 std::ostream &operator<<(std::ostream &os, const ScriptError &err) {
     os << ScriptErrorString(err);
     return os;
 }
 
 BasicTestingSetup::BasicTestingSetup(const std::string &chainName)
     : m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME /
                   std::to_string(g_insecure_rand_ctx_temp_path.rand32())} {
     SetMockTime(0);
     fs::create_directories(m_path_root);
     gArgs.ForceSetArg("-datadir", m_path_root.string());
     ClearDatadirCache();
     SelectParams(chainName);
     SeedInsecureRand();
     gArgs.ForceSetArg("-printtoconsole", "0");
     InitLogging();
     LogInstance().StartLogging();
     SHA256AutoDetect();
     ECC_Start();
     SetupEnvironment();
     SetupNetworking();
     InitSignatureCache();
     InitScriptExecutionCache();
 
+    m_node.chain = interfaces::MakeChain(m_node, Params());
+    g_wallet_init_interface.Construct(m_node);
+
     fCheckBlockIndex = true;
     static bool noui_connected = false;
     if (!noui_connected) {
         noui_connect();
         noui_connected = true;
     }
 }
 
 BasicTestingSetup::~BasicTestingSetup() {
     LogInstance().DisconnectTestLogger();
     fs::remove_all(m_path_root);
     ECC_Stop();
 }
 
 TestingSetup::TestingSetup(const std::string &chainName)
     : BasicTestingSetup(chainName) {
     const Config &config = GetConfig();
     const CChainParams &chainparams = config.GetChainParams();
 
     // Ideally we'd move all the RPC tests to the functional testing framework
     // instead of unit tests, but for now we need these here.
     RPCServer rpcServer;
     RegisterAllRPCCommands(config, rpcServer, tableRPC);
 
     /**
      * RPC does not come out of the warmup state on its own. Normally, this is
      * handled in bitcoind's init path, but unit tests do not trigger this
      * codepath, so we call it explicitly as part of setup.
      */
     std::string rpcWarmupStatus;
     if (RPCIsInWarmup(&rpcWarmupStatus)) {
         SetRPCWarmupFinished();
     }
 
     m_node.scheduler = std::make_unique<CScheduler>();
 
     // We have to run a scheduler thread to prevent ActivateBestChain
     // from blocking due to queue overrun.
     threadGroup.create_thread([&] { m_node.scheduler->serviceQueue(); });
     GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler);
 
     pblocktree.reset(new CBlockTreeDB(1 << 20, true));
     g_chainstate = std::make_unique<CChainState>();
     ::ChainstateActive().InitCoinsDB(
         /* cache_size_bytes */ 1 << 23, /* in_memory */ true,
         /* should_wipe */ false);
     assert(!::ChainstateActive().CanFlushToDisk());
     ::ChainstateActive().InitCoinsCache();
     assert(::ChainstateActive().CanFlushToDisk());
     if (!LoadGenesisBlock(chainparams)) {
         throw std::runtime_error("LoadGenesisBlock failed.");
     }
     {
         BlockValidationState state;
         if (!ActivateBestChain(config, state)) {
             throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)",
                                                FormatStateMessage(state)));
         }
     }
     constexpr int script_check_threads = 2;
     for (int i = 0; i < script_check_threads; ++i) {
         threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
     }
 
     m_node.mempool = &::g_mempool;
     m_node.mempool->setSanityCheck(1.0);
     m_node.banman =
         std::make_unique<BanMan>(GetDataDir() / "banlist.dat", chainparams,
                                  nullptr, DEFAULT_MISBEHAVING_BANTIME);
     // Deterministic randomness for tests.
     m_node.connman = std::make_unique<CConnman>(config, 0x1337, 0x1337);
 }
 
 TestingSetup::~TestingSetup() {
     if (m_node.scheduler) {
         m_node.scheduler->stop();
     }
     threadGroup.interrupt_all();
     threadGroup.join_all();
     GetMainSignals().FlushBackgroundCallbacks();
     GetMainSignals().UnregisterBackgroundSignalScheduler();
     m_node.connman.reset();
     m_node.banman.reset();
     m_node.mempool = nullptr;
     m_node.scheduler.reset();
     UnloadBlockIndex();
     g_chainstate.reset();
     pblocktree.reset();
 }
 
 TestChain100Setup::TestChain100Setup() {
     // Generate a 100-block chain:
     coinbaseKey.MakeNewKey(true);
     CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey())
                                      << OP_CHECKSIG;
     for (int i = 0; i < COINBASE_MATURITY; i++) {
         std::vector<CMutableTransaction> noTxns;
         CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
         m_coinbase_txns.push_back(b.vtx[0]);
     }
 }
 
 //
 // Create a new block with just given transactions, coinbase paying to
 // scriptPubKey, and try to add it to the current chain.
 //
 CBlock TestChain100Setup::CreateAndProcessBlock(
     const std::vector<CMutableTransaction> &txns, const CScript &scriptPubKey) {
     const Config &config = GetConfig();
     std::unique_ptr<CBlockTemplate> pblocktemplate =
         BlockAssembler(config, *m_node.mempool).CreateNewBlock(scriptPubKey);
     CBlock &block = pblocktemplate->block;
 
     // Replace mempool-selected txns with just coinbase plus passed-in txns:
     block.vtx.resize(1);
     for (const CMutableTransaction &tx : txns) {
         block.vtx.push_back(MakeTransactionRef(tx));
     }
 
     // Order transactions by canonical order
     std::sort(std::begin(block.vtx) + 1, std::end(block.vtx),
               [](const std::shared_ptr<const CTransaction> &txa,
                  const std::shared_ptr<const CTransaction> &txb) -> bool {
                   return txa->GetId() < txb->GetId();
               });
 
     // IncrementExtraNonce creates a valid coinbase and merkleRoot
     {
         LOCK(cs_main);
         unsigned int extraNonce = 0;
         IncrementExtraNonce(&block, ::ChainActive().Tip(),
                             config.GetMaxBlockSize(), extraNonce);
     }
 
     const Consensus::Params &params = config.GetChainParams().GetConsensus();
     while (!CheckProofOfWork(block.GetHash(), block.nBits, params)) {
         ++block.nNonce;
     }
 
     std::shared_ptr<const CBlock> shared_pblock =
         std::make_shared<const CBlock>(block);
     ProcessNewBlock(config, shared_pblock, true, nullptr);
 
     CBlock result = block;
     return result;
 }
 
 TestChain100Setup::~TestChain100Setup() {}
 
 CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {
     return FromTx(MakeTransactionRef(tx));
 }
 
 CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef &tx) {
     return CTxMemPoolEntry(tx, nFee, nTime, nHeight, spendsCoinbase,
                            nSigOpCount, LockPoints());
 }
 
 /**
  * @returns a real block
  * (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af) with 9
  * txs.
  */
 CBlock getBlock13b8a() {
     CBlock block;
     CDataStream stream(
         ParseHex(
             "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb680000000"
             "0000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558"
             "da2fdb261b4d4c86041b1ab1bf9309010000000100000000000000000000000000"
             "00000000000000000000000000000000000000ffffffff07044c86041b0146ffff"
             "ffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf2"
             "54bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c"
             "4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada9027"
             "80da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100da"
             "b24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd0221"
             "00fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb4"
             "01ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369e"
             "d2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98e"
             "c706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad"
             "2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21ad"
             "c6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e86"
             "25a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d8982"
             "35e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff02"
             "80969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388"
             "ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd3"
             "88ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c522"
             "92d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3"
             "889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2f"
             "afd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d3"
             "1b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83aba"
             "f975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cb"
             "cba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044"
             "022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae7406056"
             "58022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e0100"
             "3614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c342"
             "3e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc"
             "2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13"
             "fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021"
             "e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91"
             "c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b4830"
             "4502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9"
             "236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddc"
             "ce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d78990"
             "4f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8"
             "ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942"
             "fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad5652937"
             "1864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd9"
             "0111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37"
             "f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b"
             "25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d0014104"
             "43bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf"
             "7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffff"
             "ffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a1232"
             "2d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70a"
             "e67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176"
             "f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf"
             "062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b956"
             "00db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd40"
             "67b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c6"
             "9b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e"
             "58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b217901000000"
             "8b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3c"
             "a2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b49"
             "1d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33"
             "d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312e"
             "f1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144a"
             "f553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd"
             "48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b"
             "659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0"
             "aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc3"
             "1895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9"
             "944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830"
             "450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1a"
             "f03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d9"
             "8a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d78990"
             "4f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8"
             "ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a03"
             "8fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261"
             "b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f6351285"
             "0811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa4207"
             "0082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0"
             "c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c0000000000"
             "1976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000"
             "000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed"
             "8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc"
             "87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded"
             "4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e"
             "3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29"
             "934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695"
             "a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93"
             "376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e9"
             "1349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49"
             "304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654"
             "d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66"
             "ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e88"
             "60c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8"
             "fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb604203"
             "4aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75e"
             "ef7942fc9288edd37c32f5c388ac00000000"),
         SER_NETWORK, PROTOCOL_VERSION);
     stream >> block;
     return block;
 }