比特币开发:Bitcoin Core 0.11 (ch 3): Initialization and Startup

Bitcoin Core 0.11 (ch 3): Initialization and Startup

This page describes the Bitcoin Core code that manages startup and initialization.

Contents

  • 1 Program entry point
  • 2 Initialization steps (init.cpp)
  • 3 Cache Sizes
  • 4 Thread Startup
  • 5 See also

Program entry point

The program's entry point can be found in bitcoind.cpp.

main() is three lines of code:

  • SetupEnvironment() (all this does is set the program's locale)
  • Connect signal handlers
  • AppInit() (this function loops for the life of the program)


AppInit: this is located nearby in bitcoind.cpp:

  • Parses the command line
  • Opens the data directory
  • Reads the config file
  • Forks a process (if running as a daemon)
  • Passes control to AppInit2(), found in init.cpp.


Initialization steps (init.cpp)

AppInit2() initializes the bitcoin system.

It contains about 800 lines of code, which are broken into 12 steps.

Where each step begins is documented in the code. Init.cpp has a few functions at the top of the file, but for the most part it consists of AppInit2().

The following table summarizes the steps:

Initialization
Step
Short Description Longer Description
1 OS-specific setup tasks These tasks are not particularly interesting.
For more info, see the code.
2 Parameter Interactions Certain command-line options require other options to be set in a certain way.
For example, -zapwallettxes implies a -rescan, thus the code will set the -rescan flag=true if it isn't already.
3 Internal flags /
Parameter sanity-check
Sets global variables for certain parameters.
For the wallet, it sanity-checks transaction fee levels (makes sure your fee is high enough to qualify for relay [error]; but not absurdly high [warning]).
4 Application init. / RPC Server

Locks the data directory. (If unable, print error and quit.)
Spawn X threads for the Script-checking engine. (Default=0, meaning use all available processors; boost::thread::hardware_concurrency).
Start RPC server in "warmup" mode.

5 Verify wallet database integrity If wallet is enabled, try to open it.

If the user knows that the wallet has been corrupted (-salvagewallet), try to recover the private keys.

6 Network Initialization

The node registers for certain signals.
Checks whether the user wants to interact only with peers on a certain network (ip4, ip6, tor).
Checks whether to use onion routing (tor).
Checks whether the user wants to whitelist any specific peers.
Attempts to listen on the bitcoin port (exits on failure).
If user specified a certain peer to seed connections, attempt to connect.

7 Load the block chain.

Load the blockchain into memory and initialize the UTXO caches.

Calculate cache sizes.
There is a total cache size, which is divided amongst three specific caches.
Default total cache size = 100MB (Max: 4 GB, min: 4 MB).
1) Blockchain cache: 1/8 of the total cache, but shouldn't be larger than 2MB.
2) UTXO database cache : 25-50% of the remaining cache space. This is the LevelDB cache.
This stores uncompressed blocks of LevelDB data and is managed by LevelDB, as described in the LevelDB documentation.
3) UTXO in-memory cache: Half of the remaining cache space.
This cache size defines the size of the cacheCoins object (a protected member of CoinsViewCache).
TODO: verify that this statement is correct...

Load the blockchain into mapBlockIndex.
By "blockchain" this means the entire block tree (all known blocks, not just those in the active chain.)
What is loaded into memory are the CBlockIndex objects, which contain metadata about the block.
Verifies the last 288 blocks (VerifyDB).
Note: The program takes less than 1 second from startup until this point; this step takes about 10-20 seconds.

The UTXO set.
The UTXO set is not loaded into memory; instead, the cache will be filled as coins are accessed from the database.
Note that as of May 2015, storing the entire UTXO set in memory would require about 3.6 GB.
As of Jan. 2016, the compressed data on disk is about 1.2 GB.

8 Load the wallet. If this is the first time the program has been run, it creates a wallet and gives you an initial key (address).
9 Datadir maintenance If the user is block-pruning, unset NODE_NETWORK and call the pruning function.
10 Import blocks Scan for better chains in the block chain database, that are not yet connected as the active best chain.
11 Start node /
RPC server

Calls StartNode in net.cpp.
This starts up the networking thread group, including ThreadProcessMessage, which is the program's main thread (see below).
Transition RPC server from "warmup" mode to normal mode.

12 Finished


When AppInit2 finishes, control returns to AppInit() in bitcoind.cpp.

There, the code's top-level thread loops indefinitely in a function called WaitForShutdown(). It sleeps for 2 seconds and checks to see if the user pressed ctrl-C. If so, it calls Shutdown() back in init.cpp.

Shutdown() shuts down the RPC server, stops the node, unregisters the signal handlers, etc., and then the program completes.

Cache Sizes

Step 7 initialized the cache sizes. There are 3 caches contemplated in step 7. Two are LevelDB database caches and the other is the coins cache, whose size is managed by the flushing code in main.cpp.

The user can allocate a total cache size with -dbcache. The user cannot pick and choose how much space to allocate to each specific cache. The default total cache size = 100MB (Max: 4 GB, min: 4 MB).

1) Block index cache

This cache stores uncompressed chunks of the /blocks/index LevelDB data and is managed by LevelDB, as described in the LevelDB documentation.

If the user enables a full transaction index (-txindex=1) it can be up to 1/8 of the total cache size. If -txindex is not enabled then only 2 MiB is needed.


2) UTXO database cache

This is the LevelDB cache for the /chainstate database.

This cache is allocated 25-50% of the remaining cache space, depending on the total cache size.


3) UTXO in-memory cache

This is the coins cache that is managed by the main.cpp code. (see FlushStateToDisk and related functions)

The variable (nCoinsCache) is declared as extern in main.h. In main.cpp, it is hard-coded to 5000 * 300 (in-memory coins are about 300 bytes, so this means 5000 coins), however it should be re-initialized in Step 7.

This cache is given all of the remaining cache space.

This cache is not loaded during initialization, rather it is filled as coins are accessed. (This can be verified by the CCoinsViewCache constructor, which sets cachedCoinsUsage=0.)

Thread Startup

The code uses boost::thread_groups to manage the various threads.

It should be noted that although Bitcoin Core is a multi-threaded program, "the reference Satoshi client is largely single-threaded." Comment by Mike Hearn in BIP 31 (2012)

What is meant is that the vast majority of the program's activity takes place in the messaging thread (ThreadMessageHandler - see below.)

Almost all of the threads are part of a single, master thread group that is created on the stack at program startup (see bitcoind.cpp). This thread group is passed to init.cpp which creates a few child threads (including a number of script-checking threads, but these are all part of the master thread group, not a separate group.)

The thread group is passed to net.cpp, which creates the networking threads, including the message-processing thread.

The two other thread groups are task-specific:

  • rpc server thread group (see rpcserver.h/cpp)
  • miner thread group

Naturally, the node will only create the RPC server thread group if the RPC server is activated, and will only create the miner thread group if it is mining. If both are disabled, then Bitcoin Core only has a single thread group.

Child Threads

The parent thread (meaning the thread in which the program begins operating) delegates almost all of the program's work to child threads. After spawning threads in init.cpp and net.cpp, the parent thread simply listens for a shutdown command, at which time the parent thread needs only to interrupt the threads in its thread group and proceed with shutdown.

The child threads are summarized in this table, listed in the order in which they are created:


Thread When / Where Created Description
Script-checking Step 4
init.cpp
This is a set of threads - 4 by default.
Script-checking (including signature checking) is expensive so is handled in separate threads.
Scheduler Step 4
init.cpp
Scheduler thread.
(TODO: describe)
RPC Threads Step 4
rpcserver.cpp
If RPC server enabled, start a group of threads to handle RPC calls.
Import Step 10
init.cpp
Imports blocks. Three scenarios:
1) Reindex (rescan all known blocks from blk???.dat files).
2) Bootstrap (use bootstrap.dat as an alternative to full IBD from the network.)
3) -loadblock (scan a specific blk???.dat file)
If none of those apply, this thread does nothing.
DNSAddressSeed Step 11
net.cpp
Attempts to build a vector of IP addresses based on the dns seeds, stores the vector and the thread exits.
In a test in June 2014, this took about 4 seconds and found 158 addresses.
Plug & Play Step 11
net.cpp
UPNP (Universal Plug & Play)
Deals with port mapping for UPNP.
SocketHandler Step 11
net.cpp
This thread services the sockets:
Waits for I/O on all the relevant sockets with a 50ms timeout.
Processes new incoming connections on listening socket and creates a CNode for the new peer.
Receives and sends data streams.
Sets sockets that have not done anything to a disconnected state.
OpenAddedConnections Step 11
net.cpp
Initiates outbound connections specified by the user with the –addnode parameter.
If can't connect, sleeps for 2 minutes each cycle.
OpenConnections Step 11
net.cpp
Initiates other outbound connections from DNS seeds (if that fails, find nodes based on fixed seeds)
If can't connect, sleeps for 500 milliseconds each cycle.
MessageHandler Step 11
net.cpp
This is the program's main thread.
This thread runs a while(true) loop, receiving and sending messages. (See net.cpp:1049)
The code uses boost::signals2 to call the ProcessMessages and SendMessages functions in main.cpp.
(The code introducing signals is in PR 2154 - see the next-to-last commit in that pull.)
ProcessMessage and SendMessage run in this thread.
So, most of the code in main.cpp runs in this thread.
Wallet Flusher Step 12
init.cpp
If wallet is enabled, this thread flushes the wallet periodically.


你可能感兴趣的:(区块链)