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 DummyWalletInit
DummyWalletInitv
is 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.