dummywallet.cpp – Commented Bitcoin Core source code

dummywallet.cpp – Commented Bitcoin Core source code
on September 30, 2019

We mentioned in a previous Bitcoin Core source code article that bitcoind can be compiled without wallet support.

Why would anyone do that?

Historically there were 2 main functions for a full node running without a wallet: helping verify blocks and mining.

As we know, CPU mining using Bitcoin Core has long been obsolete. So the only purpose for a wallet-less compilation is to become a full verifying node.

As it turns out contributing to the Bitcoin network by running a full node has many advantages if you’re a developer!

First of all, you’ll have a local copy of the complete blockchain. With this data you can build block explorers, transaction inspection tools and so on. A full node can also work as your own telescope into the Bitcoin Core network. With it you can check mempool size, amount of banned hosts (is the network under attack?) and lots of other stuff only full nodes can do.

But what happens to the wallet subsystem when you don’t compile bitcoind with wallet support?

Bitcoin Core then generates a dummy wallet that implements the Wallet interface but doesn’t do anything. It only throws errors when any of its functions are called.

Let’s take a look at the dummy Wallet class!

First, the class declaration:

class DummyWalletInit : public WalletInitInterface {
public:

    bool HasWalletSupport() const override {return false;}
    void AddWalletOptions() const override;
    bool ParameterInteraction() const override {return true;}
    void Construct(InitInterfaces& interfaces) const override {LogPrintf("No wallet support compiled in!\n");}
};

The DummyWalletInitDummyWalletInitvis derived from WalletInitInterface

Three of its 4 methods are implemented inline: HasWalletSupport, ParameterInteraction,and Construct

These are all basically null methods.

void DummyWalletInit::AddWalletOptions() const is implemented next. It simply sets dummy command line parameters that aren’t set when a wallet-less bitcoind is run.

A global dummy wallet is declared and defined: const WalletInitInterface& g_wallet_init_interface = DummyWalletInit();

Whenever any part of the program looks for g_wallet_init_interface it’ll have been defined here.

All the other functions are global Wallet-related functions that the system uses when there’s a wallet compiled-in. As you can see here all they do is throw errors when called so that the caller knows this is a wallet-less compilation.

fs::path GetWalletDir()
{
    throw std::logic_error("Wallet function called in non-wallet build.");
}

std::vector<fs::path> ListWalletDir()
{
    throw std::logic_error("Wallet function called in non-wallet build.");
}

std::vector<std::shared_ptr<CWallet>> GetWallets()
{
    throw std::logic_error("Wallet function called in non-wallet build.");
}

std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning)
{
    throw std::logic_error("Wallet function called in non-wallet build.");
}

namespace interfaces {

class Wallet;

std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet)
{
    throw std::logic_error("Wallet function called in non-wallet build.");
}

} // namespace interfaces

Get, Make, List and Load getter methods all simply throw errors. It is assumed that the caller correctly handles std::logic_error

Note how all the components of a real wallet are all implemented in dummywallet.cpp – the last definition is a mock implementation of interfaces::MakeWallet which uses the incomplete type Wallet to define a std::unique_ptr return type.

When linked to a wallet-less compilation, dummywallet.cpp supplies all the wallet-related names and functions that are otherwise scattered throughout the source code.

Return to Bitcoin Core source code commentary index.