diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -3,14 +3,11 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include -#include #include #include class CChainParams; class CWallet; -enum class WalletCreationStatus; -struct bilingual_str; namespace interfaces { class Chain; @@ -42,43 +39,6 @@ const WalletInitInterface &g_wallet_init_interface = DummyWalletInit(); -fs::path GetWalletDir() { - throw std::logic_error("Wallet function called in non-wallet build."); -} - -std::vector ListWalletDir() { - throw std::logic_error("Wallet function called in non-wallet build."); -} - -std::vector> GetWallets() { - throw std::logic_error("Wallet function called in non-wallet build."); -} - -std::shared_ptr LoadWallet(const CChainParams &chainParams, - interfaces::Chain &chain, - const std::string &name, - bilingual_str &error, - std::vector &warnings) { - throw std::logic_error("Wallet function called in non-wallet build."); -} - -WalletCreationStatus CreateWallet(const CChainParams &chainParams, - interfaces::Chain &chain, - const SecureString &passphrase, - uint64_t wallet_creation_flags, - const std::string &name, bilingual_str &error, - std::vector &warnings, - std::shared_ptr &result) { - throw std::logic_error("Wallet function called in non-wallet build."); -} - -using LoadWalletFn = - std::function wallet)>; -std::unique_ptr -HandleLoadWallet(LoadWalletFn load_wallet) { - throw std::logic_error("Wallet function called in non-wallet build."); -} - namespace interfaces { std::unique_ptr MakeWallet(const std::shared_ptr &wallet) { diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -345,26 +345,11 @@ //! Set mock time. virtual void setMockTime(int64_t time) = 0; - - //! Return interfaces for accessing wallets (if any). - virtual std::vector> getWallets() = 0; }; //! Return implementation of Chain interface. std::unique_ptr MakeChain(NodeContext &node, const CChainParams ¶ms); -//! Return implementation of ChainClient interface for a wallet client. This -//! function will be undefined in builds where ENABLE_WALLET is false. -//! -//! Currently, wallets are the only chain clients. But in the future, other -//! types of chain clients could be added, such as tools for monitoring, -//! analysis, or fee estimation. These clients need to expose their own -//! MakeXXXClient functions returning their implementations of the ChainClient -//! interface. -std::unique_ptr -MakeWalletClient(Chain &chain, ArgsManager &args, - std::vector wallet_filenames); - } // namespace interfaces #endif // BITCOIN_INTERFACES_CHAIN_H diff --git a/src/interfaces/node.h b/src/interfaces/node.h --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -35,12 +35,11 @@ class RPCTimerInterface; enum class SynchronizationState; class UniValue; -enum class WalletCreationStatus; struct bilingual_str; namespace interfaces { class Handler; -class Wallet; +class WalletClient; struct BlockTip; //! Block and header tip information @@ -178,29 +177,8 @@ //! Get unspent outputs associated with a transaction. virtual bool getUnspentOutput(const COutPoint &output, Coin &coin) = 0; - //! Return default wallet directory. - virtual std::string getWalletDir() = 0; - - //! Return available wallets in wallet directory. - virtual std::vector listWalletDir() = 0; - - //! Return interfaces for accessing wallets (if any). - virtual std::vector> getWallets() = 0; - - //! Attempts to load a wallet from file or directory. - //! The loaded wallet is also notified to handlers previously registered - //! with handleLoadWallet. - virtual std::unique_ptr - loadWallet(const CChainParams ¶ms, const std::string &name, - bilingual_str &error, - std::vector &warnings) const = 0; - - //! Create a wallet from file - virtual std::unique_ptr - createWallet(const CChainParams ¶ms, const SecureString &passphrase, - uint64_t wallet_creation_flags, const std::string &name, - bilingual_str &error, std::vector &warnings, - WalletCreationStatus &status) = 0; + //! Get wallet client. + virtual WalletClient &walletClient() = 0; //! Register handler for init messages. using InitMessageFn = std::function; @@ -224,10 +202,6 @@ const std::string &title, int progress, bool resume_possible)>; virtual std::unique_ptr handleShowProgress(ShowProgressFn fn) = 0; - //! Register handler for load wallet messages. - using LoadWalletFn = std::function wallet)>; - virtual std::unique_ptr handleLoadWallet(LoadWalletFn fn) = 0; - //! Register handler for number of connections changed messages. using NotifyNumConnectionsChangedFn = std::function; diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -42,27 +43,7 @@ #include class HTTPRPCRequestProcessor; -class CWallet; -fs::path GetWalletDir(); -std::vector ListWalletDir(); -std::vector> GetWallets(); -std::shared_ptr LoadWallet(const CChainParams &chainParams, - interfaces::Chain &chain, - const std::string &name, - bilingual_str &error, - std::vector &warnings); -WalletCreationStatus CreateWallet(const CChainParams ¶ms, - interfaces::Chain &chain, - const SecureString &passphrase, - uint64_t wallet_creation_flags, - const std::string &name, bilingual_str &error, - std::vector &warnings, - std::shared_ptr &result); -std::unique_ptr -HandleLoadWallet(interfaces::Node::LoadWalletFn load_wallet); - namespace interfaces { - namespace { class NodeImpl : public Node { @@ -263,40 +244,8 @@ LOCK(::cs_main); return ::ChainstateActive().CoinsTip().GetCoin(output, coin); } - std::string getWalletDir() override { return GetWalletDir().string(); } - std::vector listWalletDir() override { - std::vector paths; - for (auto &path : ListWalletDir()) { - paths.push_back(path.string()); - } - return paths; - } - std::vector> getWallets() override { - std::vector> wallets; - for (auto &client : m_context->chain_clients) { - auto client_wallets = client->getWallets(); - std::move(client_wallets.begin(), client_wallets.end(), - std::back_inserter(wallets)); - } - return wallets; - } - std::unique_ptr - loadWallet(const CChainParams ¶ms, const std::string &name, - bilingual_str &error, - std::vector &warnings) const override { - return MakeWallet( - LoadWallet(params, *m_context->chain, name, error, warnings)); - } - std::unique_ptr - createWallet(const CChainParams ¶ms, const SecureString &passphrase, - uint64_t wallet_creation_flags, const std::string &name, - bilingual_str &error, std::vector &warnings, - WalletCreationStatus &status) override { - std::shared_ptr wallet; - status = CreateWallet(params, *m_context->chain, passphrase, - wallet_creation_flags, name, error, warnings, - wallet); - return MakeWallet(wallet); + WalletClient &walletClient() override { + return *Assert(m_context->wallet_client); } std::unique_ptr handleInitMessage(InitMessageFn fn) override { return MakeHandler(::uiInterface.InitMessage_connect(fn)); @@ -311,9 +260,6 @@ handleShowProgress(ShowProgressFn fn) override { return MakeHandler(::uiInterface.ShowProgress_connect(fn)); } - std::unique_ptr handleLoadWallet(LoadWalletFn fn) override { - return HandleLoadWallet(std::move(fn)); - } std::unique_ptr handleNotifyNumConnectionsChanged( NotifyNumConnectionsChangedFn fn) override { return MakeHandler( diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -5,7 +5,8 @@ #ifndef BITCOIN_INTERFACES_WALLET_H #define BITCOIN_INTERFACES_WALLET_H -#include // For Amount +#include // For Amount +#include // For ChainClient #include #include // For CTxOut #include // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation) @@ -34,9 +35,11 @@ enum class FeeReason; enum class OutputType; enum class TransactionError; +enum class WalletCreationStatus; enum isminetype : unsigned int; struct CRecipient; struct PartiallySignedTransaction; +struct WalletContext; typedef uint8_t isminefilter; struct TxId; struct bilingual_str; @@ -300,6 +303,39 @@ virtual CWallet *wallet() { return nullptr; } }; +//! Wallet chain client that in addition to having chain client methods for +//! starting up, shutting down, and registering RPCs, also has additional +//! methods (called by the GUI) to load and create wallets. +class WalletClient : public ChainClient { +public: + //! Create new wallet. + virtual std::unique_ptr + createWallet(const CChainParams ¶ms, const std::string &name, + const SecureString &passphrase, uint64_t wallet_creation_flags, + WalletCreationStatus &status, bilingual_str &error, + std::vector &warnings) = 0; + + //! Load existing wallet. + virtual std::unique_ptr + loadWallet(const CChainParams ¶ms, const std::string &name, + bilingual_str &error, std::vector &warnings) = 0; + + //! Return default wallet directory. + virtual std::string getWalletDir() = 0; + + //! Return available wallets in wallet directory. + virtual std::vector listWalletDir() = 0; + + //! Return interfaces for accessing wallets (if any). + virtual std::vector> getWallets() = 0; + + //! Register handler for load wallet messages. This callback is triggered by + //! createWallet and loadWallet above, and also triggered when wallets are + //! loaded at startup or by RPC. + using LoadWalletFn = std::function wallet)>; + virtual std::unique_ptr handleLoadWallet(LoadWalletFn fn) = 0; +}; + //! Information about one wallet address. struct WalletAddress { CTxDestination dest; @@ -375,6 +411,12 @@ //! dummywallet.cpp and throws if the wallet component is not compiled. std::unique_ptr MakeWallet(const std::shared_ptr &wallet); +//! Return implementation of ChainClient interface for a wallet client. This +//! function will be undefined in builds where ENABLE_WALLET is false. +std::unique_ptr +MakeWalletClient(Chain &chain, ArgsManager &args, + std::vector wallet_filenames); + } // namespace interfaces #endif // BITCOIN_INTERFACES_WALLET_H diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -460,7 +460,7 @@ std::shared_ptr m_wallet; }; - class WalletClientImpl : public ChainClient { + class WalletClientImpl : public WalletClient { public: WalletClientImpl(Chain &chain, ArgsManager &args, std::vector wallet_filenames) @@ -468,7 +468,9 @@ m_context.chain = &chain; m_context.args = &args; } + ~WalletClientImpl() override { UnloadWallets(); } + //! ChainClient methods void registerRpcs(const Span &commands) { for (const CRPCCommand &command : commands) { m_rpc_commands.emplace_back( @@ -503,6 +505,37 @@ void flush() override { return FlushWallets(); } void stop() override { return StopWallets(); } void setMockTime(int64_t time) override { return SetMockTime(time); } + + //! WalletClient methods + std::unique_ptr + createWallet(const CChainParams ¶ms, const std::string &name, + const SecureString &passphrase, + uint64_t wallet_creation_flags, + WalletCreationStatus &status, bilingual_str &error, + std::vector &warnings) override { + std::shared_ptr wallet; + status = CreateWallet(params, *m_context.chain, passphrase, + wallet_creation_flags, name, error, warnings, + wallet); + return MakeWallet(std::move(wallet)); + } + std::unique_ptr + loadWallet(const CChainParams ¶ms, const std::string &name, + bilingual_str &error, + std::vector &warnings) override { + return MakeWallet(LoadWallet(params, *m_context.chain, + WalletLocation(name), error, + warnings)); + } + std::string getWalletDir() override { return GetWalletDir().string(); } + std::vector listWalletDir() override { + std::vector paths; + for (auto &path : ListWalletDir()) { + paths.push_back(path.string()); + } + return paths; + } + std::vector> getWallets() override { std::vector> wallets; for (const auto &wallet : GetWallets()) { @@ -510,7 +543,10 @@ } return wallets; } - ~WalletClientImpl() override { UnloadWallets(); } + + std::unique_ptr handleLoadWallet(LoadWalletFn fn) override { + return HandleLoadWallet(std::move(fn)); + } WalletContext m_context; const std::vector m_wallet_filenames; @@ -524,7 +560,7 @@ return wallet ? std::make_unique(wallet) : nullptr; } -std::unique_ptr +std::unique_ptr MakeWalletClient(Chain &chain, ArgsManager &args, std::vector wallet_filenames) { return std::make_unique(chain, args, diff --git a/src/node/context.h b/src/node/context.h --- a/src/node/context.h +++ b/src/node/context.h @@ -20,6 +20,7 @@ namespace interfaces { class Chain; class ChainClient; +class WalletClient; } // namespace interfaces //! NodeContext struct containing references to chain state and connection @@ -42,7 +43,12 @@ // Currently a raw pointer because the memory is not managed by this struct ArgsManager *args{nullptr}; std::unique_ptr chain; + //! List of all chain clients (wallet processes or other client) connected + //! to node. std::vector> chain_clients; + //! Reference to chain client that should used to load or create wallets + //! opened by the gui. + interfaces::WalletClient *wallet_client{nullptr}; std::unique_ptr scheduler; std::function rpc_interruption_point = [] {}; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -280,6 +280,8 @@ // the splash screen will take care of deleting itself when finish() // happens. m_splash->show(); + connect(this, &BitcoinApplication::requestedInitialize, m_splash, + &SplashScreen::handleLoadWallet); connect(this, &BitcoinApplication::splashFinished, m_splash, &SplashScreen::finish); connect(this, &BitcoinApplication::requestedShutdown, m_splash, diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1319,7 +1319,8 @@ QString msg = tr("Date: %1\n").arg(date) + tr("Amount: %1\n") .arg(BitcoinUnits::formatWithUnit(unit, amount, true)); - if (m_node.getWallets().size() > 1 && !walletName.isEmpty()) { + if (m_node.walletClient().getWallets().size() > 1 && + !walletName.isEmpty()) { msg += tr("Wallet: %1\n").arg(walletName); } msg += tr("Type: %1\n").arg(type); diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h --- a/src/qt/splashscreen.h +++ b/src/qt/splashscreen.h @@ -44,6 +44,9 @@ void showMessage(const QString &message, int alignment, const QColor &color); + /** Handle wallet load notifications. */ + void handleLoadWallet(); + protected: bool eventFilter(QObject *obj, QEvent *ev) override; diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -222,8 +223,14 @@ m_handler_show_progress = m_node->handleShowProgress( std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); +} + +void SplashScreen::handleLoadWallet() { #ifdef ENABLE_WALLET - m_handler_load_wallet = m_node->handleLoadWallet( + if (!WalletModel::isWalletEnabled()) { + return; + } + m_handler_load_wallet = m_node->walletClient().handleLoadWallet( [this](std::unique_ptr wallet) { ConnectWallet(std::move(wallet)); }); diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -30,12 +30,13 @@ m_activity_worker(new QObject), m_client_model(client_model), m_node(client_model.node()), m_platform_style(platform_style), m_options_model(client_model.getOptionsModel()) { - m_handler_load_wallet = m_node.handleLoadWallet( + m_handler_load_wallet = m_node.walletClient().handleLoadWallet( [this](std::unique_ptr wallet) { getOrCreateWallet(std::move(wallet)); }); - for (std::unique_ptr &wallet : m_node.getWallets()) { + for (std::unique_ptr &wallet : + m_node.walletClient().getWallets()) { getOrCreateWallet(std::move(wallet)); } @@ -59,7 +60,7 @@ std::map WalletController::listWalletDir() const { QMutexLocker locker(&m_mutex); std::map wallets; - for (const std::string &name : m_node.listWalletDir()) { + for (const std::string &name : m_node.walletClient().listWalletDir()) { wallets[name] = false; } for (WalletModel *wallet_model : m_wallets) { @@ -255,8 +256,9 @@ QTimer::singleShot(500, worker(), [this, name, flags] { WalletCreationStatus status; std::unique_ptr wallet = - node().createWallet(m_chainparams, m_passphrase, flags, name, - m_error_message, m_warning_message, status); + node().walletClient().createWallet( + m_chainparams, name, m_passphrase, flags, status, + m_error_message, m_warning_message); if (status == WalletCreationStatus::SUCCESS) { m_wallet_model = @@ -340,8 +342,9 @@ tr("Opening Wallet %1...").arg(name.toHtmlEscaped())); QTimer::singleShot(0, worker(), [this, path] { - std::unique_ptr wallet = node().loadWallet( - this->m_chainparams, path, m_error_message, m_warning_message); + std::unique_ptr wallet = + node().walletClient().loadWallet( + this->m_chainparams, path, m_error_message, m_warning_message); if (wallet) { m_wallet_model = diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -525,7 +525,7 @@ } bool WalletModel::isMultiwallet() { - return m_node.getWallets().size() > 1; + return m_node.walletClient().getWallets().size() > 1; } const CChainParams &WalletModel::getChainParams() const { diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -226,6 +227,8 @@ return; } args.SoftSetArg("-wallet", ""); - node.chain_clients.emplace_back(interfaces::MakeWalletClient( - *node.chain, args, args.GetArgs("-wallet"))); + auto wallet_client = interfaces::MakeWalletClient(*node.chain, args, + args.GetArgs("-wallet")); + node.wallet_client = wallet_client.get(); + node.chain_clients.emplace_back(std::move(wallet_client)); } diff --git a/src/wallet/test/init_test_fixture.h b/src/wallet/test/init_test_fixture.h --- a/src/wallet/test/init_test_fixture.h +++ b/src/wallet/test/init_test_fixture.h @@ -6,7 +6,7 @@ #define BITCOIN_WALLET_TEST_INIT_TEST_FIXTURE_H #include - +#include #include #include @@ -20,7 +20,7 @@ fs::path m_cwd; std::map m_walletdir_path_cases; std::unique_ptr m_chain; - std::unique_ptr m_chain_client; + std::unique_ptr m_wallet_client; }; #endif // BITCOIN_WALLET_TEST_INIT_TEST_FIXTURE_H diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp --- a/src/wallet/test/init_test_fixture.cpp +++ b/src/wallet/test/init_test_fixture.cpp @@ -13,7 +13,7 @@ const std::string &chainName) : BasicTestingSetup(chainName) { m_chain = interfaces::MakeChain(m_node, Params()); - m_chain_client = MakeWalletClient(*m_chain, *Assert(m_node.args), {}); + m_wallet_client = MakeWalletClient(*m_chain, *Assert(m_node.args), {}); std::string sep; sep += fs::path::preferred_separator; diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp --- a/src/wallet/test/init_tests.cpp +++ b/src/wallet/test/init_tests.cpp @@ -16,7 +16,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default) { SetWalletDir(m_walletdir_path_cases["default"]); - bool result = m_chain_client->verify(Params()); + bool result = m_wallet_client->verify(Params()); BOOST_CHECK(result == true); fs::path walletdir = gArgs.GetArg("-walletdir", ""); fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); @@ -25,7 +25,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_custom) { SetWalletDir(m_walletdir_path_cases["custom"]); - bool result = m_chain_client->verify(Params()); + bool result = m_wallet_client->verify(Params()); BOOST_CHECK(result == true); fs::path walletdir = gArgs.GetArg("-walletdir", ""); fs::path expected_path = fs::canonical(m_walletdir_path_cases["custom"]); @@ -36,7 +36,7 @@ SetWalletDir(m_walletdir_path_cases["nonexistent"]); { ASSERT_DEBUG_LOG("does not exist"); - bool result = m_chain_client->verify(Params()); + bool result = m_wallet_client->verify(Params()); BOOST_CHECK(result == false); } } @@ -45,7 +45,7 @@ SetWalletDir(m_walletdir_path_cases["file"]); { ASSERT_DEBUG_LOG("is not a directory"); - bool result = m_chain_client->verify(Params()); + bool result = m_wallet_client->verify(Params()); BOOST_CHECK(result == false); } } @@ -54,14 +54,14 @@ SetWalletDir(m_walletdir_path_cases["relative"]); { ASSERT_DEBUG_LOG("is a relative path"); - bool result = m_chain_client->verify(Params()); + bool result = m_wallet_client->verify(Params()); BOOST_CHECK(result == false); } } BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing) { SetWalletDir(m_walletdir_path_cases["trailing"]); - bool result = m_chain_client->verify(Params()); + bool result = m_wallet_client->verify(Params()); BOOST_CHECK(result == true); fs::path walletdir = gArgs.GetArg("-walletdir", ""); fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); @@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing2) { SetWalletDir(m_walletdir_path_cases["trailing2"]); - bool result = m_chain_client->verify(Params()); + bool result = m_wallet_client->verify(Params()); BOOST_CHECK(result == true); fs::path walletdir = gArgs.GetArg("-walletdir", ""); fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h --- a/src/wallet/test/wallet_test_fixture.h +++ b/src/wallet/test/wallet_test_fixture.h @@ -23,7 +23,7 @@ const std::string &chainName = CBaseChainParams::MAIN); std::unique_ptr m_chain; - std::unique_ptr m_chain_client = + std::unique_ptr m_wallet_client = interfaces::MakeWalletClient(*m_chain, *Assert(m_node.args), {}); CWallet m_wallet; std::unique_ptr m_chain_notifications_handler; diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -15,5 +15,5 @@ m_wallet.LoadWallet(fFirstRun); m_chain_notifications_handler = m_chain->handleNotifications({&m_wallet, [](CWallet *) {}}); - m_chain_client->registerRpcs(); + m_wallet_client->registerRpcs(); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -198,15 +198,6 @@ return wallet; } -std::shared_ptr LoadWallet(const CChainParams &chainParams, - interfaces::Chain &chain, - const std::string &name, - bilingual_str &error, - std::vector &warnings) { - return LoadWallet(chainParams, chain, WalletLocation(name), error, - warnings); -} - WalletCreationStatus CreateWallet(const CChainParams ¶ms, interfaces::Chain &chain, const SecureString &passphrase,