title: bitcoind
theme: sjaakvandenberg/cleaver-light
Bitcoind
Bitcoind
- Bitcoind is a headless daemon, and also bundles a testing tool for the same daemon.
- It provides a JSON-RPC interface, allowing it to be controlled locally or remotely which makes it useful for integration with other software or in larger payment systems.
Bitcoind
- bitcoind is a multithreaded C++ program.
- It is designed to be portable across Windows, Mac, and Linux systems.
- Also, the code is aggressive in the use of C++ constructs, so it will help to be fluent with map, multimap, set, string, vector, iostream, and templates.
- As is typical of a C++ program, a lot of code tends to end up in the header files so be sure to search both the .cpp and .h files when looking for a function.
marksu@~/work/githubBlockchain/bitcoin $ git branch -avv
* 0.15 51bad91 [origin/0.15] Merge #11445: [qa] 0.15.1 Backports
master 424be03 [origin/master: behind 10] Merge #10099: Slightly Improve Unit Tests for Checkqueue
remotes/origin/0.10 9cea169 net: Disable P2P alert system
remotes/origin/0.11 0bace83 net: Disable P2P alert system
remotes/origin/0.12 c1b7421 Merge #9211: [0.12 branch] Backports
remotes/origin/0.13 b654842 Populate services in GetLocalAddress
remotes/origin/0.14 b9ca778 Merge #11296: [0.14] travis: filter out pyenv (Cory Fields)
remotes/origin/0.15 51bad91 Merge #11445: [qa] 0.15.1 Backports
remotes/origin/0.8 9d11aba Merge #5765: Implement BIP66 (0.8)
remotes/origin/0.9 460ccfb Disable upnp by default
remotes/origin/HEAD -> origin/master
remotes/origin/master 6ab0e4c Merge #10672: Avoid division by zero in the case of a corrupt estimates file
Operation
- Initialization and Startup
- Node Discovery
- Node Connectivity
- Sockets and Messages
- Block Exchange
- Transaction Exchange
- Wallet Services
- RPC Interface
- User Interface
1. Startup Process
- Step 1: setup
- Step 2: parameter interactions
- Step 3: parameter-to-internal-flags
- Step 4: sanity checks
- Step 5: verify wallet database integrity
- Step 6: network initialization
- Step 7: load block chain
- Step 8: load wallet
- Step 9: data directory maintenance
- Step 10: import blocks
- Step 11: start node
- Step 12: finished
main() in bitcoind.cpp
int main(int argc, char* argv[])
{
SetupEnvironment();
// Connect bitcoind signal handlers
noui_connect();
return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
}
AppInit() in bitcoind.cpp?
bool AppInit(int argc, char* argv[]) {
InitLogging();
InitParameterInteraction();
if (!AppInitBasicSetup())
if (!AppInitParameterInteraction())
if (!AppInitSanityChecks())
// Lock data directory after daemonization
if (!AppInitLockDataDirectory())
fRet = AppInitMain(threadGroup, scheduler);
AppInitMain() in init.cpp?
bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) {
InitSignatureCache();
InitScriptExecutionCache();
// Start the lightweight task scheduler thread
CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler);
threadGroup.create_thread(boost::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
if (!AppInitServers(threadGroup))
Step 1: setup
Step 2: parameter interactions
Step 3: parameter-to-internal-flags
Step 4: sanity checks
Step 5: verify wallet database integrity
#ifdef ENABLE_WALLET
if (!CWallet::Verify())
return false;
#endif
Step 6: network initialization
Step 7: load block chain
Step 8: load wallet
#ifdef ENABLE_WALLET
if (!CWallet::InitLoadWallet())
return false;
#else
LogPrintf("No wallet support compiled in!\n");
#endif
Step 9: data directory maintenance
// if pruning, unset the service bit and perform the initial blockstore prune
// after any wallet rescanning has taken place.
if (fPruneMode) {
uiInterface.InitMessage(_("Pruning blockstore..."));
LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
nLocalServices &= ~NODE_NETWORK;
if (!fReindex) {
PruneAndFlush();
}
}
Step 10: import blocks
if (!CheckDiskSpace())
return false;
...
threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));
// Wait for genesis block to be processed
{
boost::unique_lock<boost::mutex> lock(cs_GenesisWait);
while (!fHaveGenesis) {
condvar_GenesisWait.wait(lock);
}
uiInterface.NotifyBlockTip.disconnect(BlockNotifyGenesisWait);
}
Step 11: start node
//// debug print
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
LogPrintf("nBestHeight = %d\n", chainActive.Height());
if (gArgs.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
StartTorControl(threadGroup, scheduler);
Discover(threadGroup);
// Map ports with UPnP
MapPort(gArgs.GetBoolArg("-upnp", DEFAULT_UPNP));
if (!connman.Start(scheduler, connOptions)) {
return false;
}
Step 12: finished
SetRPCWarmupFinished();
uiInterface.InitMessage(_("Done loading"));
#ifdef ENABLE_WALLET
for (CWalletRef pwallet : vpwallets) {
pwallet->postInitProcess(scheduler);
}
#endif
return !fRequestShutdown;
2. Node Discovery
- Nodes discover their own external address by various methods.
- Nodes receive the callback address of remote nodes that connect to them.
- Nodes makes DNS request to receive IP addresses.
- Nodes can use addresses hard coded into the software.
- Nodes exchange addresses with other nodes.
- Nodes store addresses in a database and read that database on startup.
- Nodes can be provided addresses as command line arguments
- Nodes read addresses from a user provided text file on startup
- A timestamp is kept for each address to keep track of when the node address was last seen.
- The AddressCurrentlyConnected in net.cpp handles updating the timestamp whenever a message is received from a node.
- Timestamps are only updated on an address and saved to the database when the timestamp is over 20 minutes old. *By understanding the role of timestamps, it will become more clear why timestamps are kept the way they are for each of the different ways an address is discovered.
Handling Message "getaddr"
- When a node receives a "getaddr" request, it first figures out how many addresses it has that have a timestamp in the last 3 hours.
- Then it sends those addresses, but if there are more than 2500 addresses seen in the last 3 hours, it selects around 2500 out of the available recent addresses by using random selection.
Discovery Methods
- Local Client's External Address
- Connect Callback Address
- IRC Addresses
- DNS Addresses
- Hard Coded "Seed" Addresses
- Ongoing "addr" advertisements
3. Node Connectivity
- The Satoshi bitcoin client creates a thread to manage making connections to other nodes.
- The code for that thread is in a function called ThreadOpenConnections in net.cpp.
- The client also handles accepting new inbound connections and disconnecting nodes when appropriate in a a thread called ThreadSocketHandler, which is also in net.cpp.
- The thread making connections does not discover the addresses of other nodes. The connection thread chooses among the available addresses and makes connections and disconnects nodes when appropriate.
Connection Rules
Node addresses are chosen based on the following set of rules.
- Outbound Static Addresses
- Outbound Limiting
- Seed Nodes
- Outbound Random Selection
Running
//To use locally, first start the program in daemon mode:
bitcoind -daemon
//Then you can execute API commands, e.g.:
bitcoin-cli getinfo
bitcoin-cli listtransactions
//To stop the bitcoin daemon, execute:
bitcoin-cli stop