Skip to content

Commit

Permalink
refactor: Move wallet methods out of chain.h and node.h
Browse files Browse the repository at this point in the history
Add WalletClient interface so node interface is cleaner and don't need
wallet-specific methods.

The new NodeContext::wallet_client pointer will also be needed to eliminate
global wallet variables like ::vpwallets, because createWallet(), loadWallet(),
getWallets(), etc methods called by the GUI need a way to get a reference to
the list of open wallets if it is no longer a global variable.

Also tweaks splash screen registration for load wallet events to be delayed
until after wallet client is created.
  • Loading branch information
ryanofsky committed May 28, 2020
1 parent 23c53e0 commit 6a67d63
Show file tree
Hide file tree
Showing 19 changed files with 147 additions and 91 deletions.
17 changes: 14 additions & 3 deletions src/interfaces/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,14 +307,12 @@ class ChainClient

//! Set mock time.
virtual void setMockTime(int64_t time) = 0;

//! Return interfaces for accessing wallets (if any).
virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;
};

//! Return implementation of Chain interface.
std::unique_ptr<Chain> MakeChain(NodeContext& node);

<<<<<<< HEAD
//! Return implementation of ChainClient interface for a wallet client. This
//! function will be undefined in builds where ENABLE_WALLET is false.
//!
Expand All @@ -325,6 +323,19 @@ std::unique_ptr<Chain> MakeChain(NodeContext& node);
//! interface.
std::unique_ptr<ChainClient> MakeWalletClient(Chain& chain, ArgsManager& args, std::vector<std::string> wallet_filenames);

||||||| merged common ancestors
//! 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<ChainClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames);

=======
>>>>>>> refactor: Move wallet methods out of chain.h and node.h
} // namespace interfaces

#endif // BITCOIN_INTERFACES_CHAIN_H
45 changes: 3 additions & 42 deletions src/interfaces/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,7 @@

#include <boost/signals2/signal.hpp>

class CWallet;
fs::path GetWalletDir();
std::vector<fs::path> ListWalletDir();
std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings);
WalletCreationStatus CreateWallet(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
Expand Down Expand Up @@ -253,36 +244,10 @@ class NodeImpl : public Node
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
WalletClient& walletClient() override
{
std::vector<std::unique_ptr<Wallet>> 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<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
{
return MakeWallet(LoadWallet(*m_context->chain, name, error, warnings));
}
std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, WalletCreationStatus& status) override
{
std::shared_ptr<CWallet> wallet;
status = CreateWallet(*m_context->chain, passphrase, wallet_creation_flags, name, error, warnings, wallet);
return MakeWallet(wallet);
assert (m_context->wallet_client);
return *m_context->wallet_client;
}
std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
{
Expand All @@ -300,10 +265,6 @@ class NodeImpl : public Node
{
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));
Expand Down
25 changes: 3 additions & 22 deletions src/interfaces/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@ class RPCTimerInterface;
class UniValue;
class proxyType;
enum class SynchronizationState;
enum class WalletCreationStatus;
struct CNodeStateStats;
struct NodeContext;
struct bilingual_str;

namespace interfaces {
class Handler;
class Wallet;
class WalletClient;
struct BlockTip;

//! Top-level interface for a bitcoin node (bitcoind process).
Expand Down Expand Up @@ -196,22 +195,8 @@ class Node
//! 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 std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;

//! Create a wallet from file
virtual std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, WalletCreationStatus& status) = 0;
//! Get wallet client.
virtual WalletClient& walletClient() = 0;

//! Register handler for init messages.
using InitMessageFn = std::function<void(const std::string& message)>;
Expand All @@ -233,10 +218,6 @@ class Node
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;
Expand Down
40 changes: 38 additions & 2 deletions src/interfaces/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ class WalletImpl : public Wallet
std::shared_ptr<CWallet> m_wallet;
};

class WalletClientImpl : public ChainClient
class WalletClientImpl : public WalletClient
{
public:
WalletClientImpl(Chain& chain, ArgsManager& args, std::vector<std::string> wallet_filenames)
Expand All @@ -489,6 +489,9 @@ class WalletClientImpl : public ChainClient
m_context.chain = &chain;
m_context.args = &args;
}
~WalletClientImpl() override { UnloadWallets(); }

//! ChainClient methods
void registerRpcs() override
{
for (const CRPCCommand& command : GetWalletRPCCommands()) {
Expand All @@ -504,6 +507,30 @@ class WalletClientImpl : public ChainClient
void flush() override { return FlushWallets(); }
void stop() override { return StopWallets(); }
void setMockTime(int64_t time) override { return SetMockTime(time); }

//! WalletClient methods
std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, WalletCreationStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings) override
{
std::shared_ptr<CWallet> wallet;
status = CreateWallet(*m_context.chain, passphrase, wallet_creation_flags, name, error, warnings, wallet);
return MakeWallet(std::move(wallet));
}
std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
{
return MakeWallet(LoadWallet(*m_context.chain, WalletLocation(name), error, warnings));
}
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;
Expand All @@ -512,7 +539,10 @@ class WalletClientImpl : public ChainClient
}
return wallets;
}
~WalletClientImpl() override { UnloadWallets(); }
std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) override
{
return HandleLoadWallet(std::move(fn));
}

WalletContext m_context;
const std::vector<std::string> m_wallet_filenames;
Expand All @@ -524,7 +554,13 @@ class WalletClientImpl : public ChainClient

std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? MakeUnique<WalletImpl>(wallet) : nullptr; }

<<<<<<< HEAD
std::unique_ptr<ChainClient> MakeWalletClient(Chain& chain, ArgsManager& args, std::vector<std::string> wallet_filenames)
||||||| merged common ancestors
std::unique_ptr<ChainClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames)
=======
std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames)
>>>>>>> refactor: Move wallet methods out of chain.h and node.h
{
return MakeUnique<WalletClientImpl>(chain, args, std::move(wallet_filenames));
}
Expand Down
35 changes: 35 additions & 0 deletions src/interfaces/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define BITCOIN_INTERFACES_WALLET_H

#include <amount.h> // For CAmount
#include <interfaces/chain.h> // For ChainClient
#include <pubkey.h> // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation)
#include <script/standard.h> // For CTxDestination
#include <support/allocators/secure.h> // For SecureString
Expand All @@ -28,9 +29,11 @@ class CWallet;
enum class FeeReason;
enum class OutputType;
enum class TransactionError;
enum class WalletCreationStatus;
enum isminetype : unsigned int;
struct CRecipient;
struct PartiallySignedTransaction;
struct WalletContext;
struct bilingual_str;
typedef uint8_t isminefilter;

Expand Down Expand Up @@ -301,6 +304,34 @@ class Wallet
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<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, WalletCreationStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;

//! Load existing wallet.
virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 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;

//! 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<void(std::unique_ptr<Wallet> wallet)>;
virtual std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) = 0;
};

//! Information about one wallet address.
struct WalletAddress
{
Expand Down Expand Up @@ -379,6 +410,10 @@ struct WalletTxOut
//! dummywallet.cpp and throws if the wallet component is not compiled.
std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& 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<WalletClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames);

} // namespace interfaces

#endif // BITCOIN_INTERFACES_WALLET_H
5 changes: 5 additions & 0 deletions src/node/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class PeerLogicValidation;
namespace interfaces {
class Chain;
class ChainClient;
class WalletClient;
} // namespace interfaces

//! NodeContext struct containing references to chain state and connection
Expand All @@ -39,7 +40,11 @@ struct NodeContext {
std::unique_ptr<BanMan> banman;
ArgsManager* args{nullptr}; // Currently a raw pointer because the memory is not managed by this struct
std::unique_ptr<interfaces::Chain> chain;
//! List of all chain clients (wallet processes or other client) connected to node.
std::vector<std::unique_ptr<interfaces::ChainClient>> 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<CScheduler> scheduler;

//! Declare default constructor and destructor that are not inline, so code
Expand Down
1 change: 1 addition & 0 deletions src/qt/bitcoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *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::requestedInitialize, splash, &SplashScreen::handleLoadWallet);
connect(this, &BitcoinApplication::splashFinished, splash, &SplashScreen::finish);
connect(this, &BitcoinApplication::requestedShutdown, splash, &QWidget::close);
}
Expand Down
2 changes: 1 addition & 1 deletion src/qt/bitcoingui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1189,7 +1189,7 @@ void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmoun
// On new transaction, make an info balloon
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);
Expand Down
6 changes: 5 additions & 1 deletion src/qt/splashscreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,12 @@ void SplashScreen::subscribeToCoreSignals()
// Connect signals to client
m_handler_init_message = m_node.handleInitMessage(std::bind(InitMessage, this, std::placeholders::_1));
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([this](std::unique_ptr<interfaces::Wallet> wallet) { ConnectWallet(std::move(wallet)); });
m_handler_load_wallet = m_node.walletClient().handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { ConnectWallet(std::move(wallet)); });
#endif
}

Expand Down
3 changes: 3 additions & 0 deletions src/qt/splashscreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ public Q_SLOTS:
/** Show message and progress */
void showMessage(const QString &message, int alignment, const QColor &color);

/** Handle wallet load notifications. */
void handleLoadWallet();

protected:
bool eventFilter(QObject * obj, QEvent * ev) override;

Expand Down
10 changes: 5 additions & 5 deletions src/qt/walletcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ WalletController::WalletController(ClientModel& client_model, const PlatformStyl
, m_platform_style(platform_style)
, m_options_model(client_model.getOptionsModel())
{
m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) {
m_handler_load_wallet = m_node.walletClient().handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) {
getOrCreateWallet(std::move(wallet));
});

for (std::unique_ptr<interfaces::Wallet>& wallet : m_node.getWallets()) {
for (std::unique_ptr<interfaces::Wallet>& wallet : m_node.walletClient().getWallets()) {
getOrCreateWallet(std::move(wallet));
}

Expand All @@ -66,7 +66,7 @@ std::map<std::string, bool> WalletController::listWalletDir() const
{
QMutexLocker locker(&m_mutex);
std::map<std::string, bool> 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) {
Expand Down Expand Up @@ -250,7 +250,7 @@ void CreateWalletActivity::createWallet()

QTimer::singleShot(500, worker(), [this, name, flags] {
WalletCreationStatus status;
std::unique_ptr<interfaces::Wallet> wallet = node().createWallet(m_passphrase, flags, name, m_error_message, m_warning_message, status);
std::unique_ptr<interfaces::Wallet> wallet = node().walletClient().createWallet(name, m_passphrase, flags, status, m_error_message, m_warning_message);

if (status == WalletCreationStatus::SUCCESS) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));

Expand Down Expand Up @@ -321,7 +321,7 @@ void OpenWalletActivity::open(const std::string& path)
showProgressDialog(tr("Opening Wallet <b>%1</b>...").arg(name.toHtmlEscaped()));

QTimer::singleShot(0, worker(), [this, path] {
std::unique_ptr<interfaces::Wallet> wallet = node().loadWallet(path, m_error_message, m_warning_message);
std::unique_ptr<interfaces::Wallet> wallet = node().walletClient().loadWallet(path, m_error_message, m_warning_message);

if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));

Expand Down
Loading

0 comments on commit 6a67d63

Please sign in to comment.