// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# if defined(HAVE_CONFIG_H)
# include "config/bitcoin-config.h"
# endif
# include "init.h"
# include "addrman.h"
# include "checkpoints.h"
# include "key.h"
# include "main.h"
# include "miner.h"
# include "net.h"
# include "rpcserver.h"
# include "txdb.h"
# include "ui_interface.h"
# include "util.h"
# ifdef ENABLE_WALLET
# include "db.h"
# include "wallet.h"
# include "walletdb.h"
# endif
# include <stdint.h>
# include <stdio.h>
# ifndef WIN32
# include <signal.h>
# endif
# include "compat/sanity.h"
# include <boost/algorithm/string/predicate.hpp>
# include <boost/filesystem.hpp>
# include <boost/interprocess/sync/file_lock.hpp>
# include <openssl/crypto.h>
using namespace boost ;
using namespace std ;
# ifdef ENABLE_WALLET
CWallet * pwalletMain ;
# endif
# ifdef WIN32
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
// accessing block files, don't count towards to fd_set size limit
// anyway.
# define MIN_CORE_FILEDESCRIPTORS 0
# else
# define MIN_CORE_FILEDESCRIPTORS 150
# endif
// Used to pass flags to the Bind() function
enum BindFlags {
BF_NONE = 0 ,
BF_EXPLICIT = ( 1U < < 0 ) ,
BF_REPORT_ERROR = ( 1U < < 1 ) ,
BF_WHITELIST = ( 1U < < 2 ) ,
} ;
static const char * FEE_ESTIMATES_FILENAME = " fee_estimates.dat " ;
CClientUIInterface uiInterface ;
//////////////////////////////////////////////////////////////////////////////
//
// Shutdown
//
//
// Thread management and startup/shutdown:
//
// The network-processing threads are all part of a thread group
// created by AppInit() or the Qt main() function.
//
// A clean exit happens when StartShutdown() or the SIGTERM
// signal handler sets fRequestShutdown, which triggers
// the DetectShutdownThread(), which interrupts the main thread group.
// DetectShutdownThread() then exits, which causes AppInit() to
// continue (it .joins the shutdown thread).
// Shutdown() is then
// called to clean up database connections, and stop other
// threads that should only be stopped after the main network-processing
// threads have exited.
//
// Note that if running -daemon the parent process returns from AppInit2
// before adding any threads to the threadGroup, so .join_all() returns
// immediately and the parent exits from main().
//
// Shutdown for Qt is very similar, only it uses a QTimer to detect
// fRequestShutdown getting set, and then does the normal Qt
// shutdown thing.
//
volatile bool fRequestShutdown = false ;
void StartShutdown ( )
{
fRequestShutdown = true ;
}
bool ShutdownRequested ( )
{
return fRequestShutdown ;
}
static CCoinsViewDB * pcoinsdbview ;
void Shutdown ( )
{
LogPrintf ( " %s: In progress... \n " , __func__ ) ;
static CCriticalSection cs_Shutdown ;
TRY_LOCK ( cs_Shutdown , lockShutdown ) ;
if ( ! lockShutdown )
return ;
RenameThread ( " bitcoin-shutoff " ) ;
mempool . AddTransactionsUpdated ( 1 ) ;
StopRPCThreads ( ) ;
# ifdef ENABLE_WALLET
if ( pwalletMain )
bitdb . Flush ( false ) ;
GenerateBitcoins ( false , NULL , 0 ) ;
# endif
StopNode ( ) ;
UnregisterNodeSignals ( GetNodeSignals ( ) ) ;
{
boost : : filesystem : : path est_path = GetDataDir ( ) / FEE_ESTIMATES_FILENAME ;
CAutoFile est_fileout ( fopen ( est_path . string ( ) . c_str ( ) , " wb " ) , SER_DISK , CLIENT_VERSION ) ;
if ( est_fileout )
mempool . WriteFeeEstimates ( est_fileout ) ;
else
LogPrintf ( " %s: Failed to write fee estimates to %s \n " , __func__ , est_path . string ( ) ) ;
}
{
LOCK ( cs_main ) ;
# ifdef ENABLE_WALLET
if ( pwalletMain )
pwalletMain - > SetBestChain ( chainActive . GetLocator ( ) ) ;
# endif
if ( pblocktree )
pblocktree - > Flush ( ) ;
if ( pcoinsTip )
pcoinsTip - > Flush ( ) ;
delete pcoinsTip ;
pcoinsTip = NULL ;
delete pcoinsdbview ;
pcoinsdbview = NULL ;
delete pblocktree ;
pblocktree = NULL ;
}
# ifdef ENABLE_WALLET
if ( pwalletMain )
bitdb . Flush ( true ) ;
# endif
boost : : filesystem : : remove ( GetPidFile ( ) ) ;
UnregisterAllWallets ( ) ;
# ifdef ENABLE_WALLET
if ( pwalletMain )
delete pwalletMain ;
# endif
LogPrintf ( " %s: done \n " , __func__ ) ;
}
//
// Signal handlers are very limited in what they are allowed to do, so:
//
void HandleSIGTERM ( int )
{
fRequestShutdown = true ;
}
void HandleSIGHUP ( int )
{
fReopenDebugLog = true ;
}
bool static InitError ( const std : : string & str )
{
uiInterface . ThreadSafeMessageBox ( str , " " , CClientUIInterface : : MSG_ERROR ) ;
return false ;
}
bool static InitWarning ( const std : : string & str )
{
uiInterface . ThreadSafeMessageBox ( str , " " , CClientUIInterface : : MSG_WARNING ) ;
return true ;
}
bool static Bind ( const CService & addr , unsigned int flags ) {
if ( ! ( flags & BF_EXPLICIT ) & & IsLimited ( addr ) )
return false ;
std : : string strError ;
if ( ! BindListenPort ( addr , strError , flags & BF_WHITELIST ) ) {
if ( flags & BF_REPORT_ERROR )
return InitError ( strError ) ;
return false ;
}
return true ;
}
std : : string HelpMessage ( HelpMessageMode mode )
{
// When adding new options to the categories, please keep and ensure alphabetical ordering.
string strUsage = _ ( " Options: " ) + " \n " ;
strUsage + = " -? " + _ ( " This help message " ) + " \n " ;
strUsage + = " -alertnotify=<cmd> " + _ ( " Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) " ) + " \n " ;
strUsage + = " -blocknotify=<cmd> " + _ ( " Execute command when the best block changes (%s in cmd is replaced by block hash) " ) + " \n " ;
strUsage + = " -checkblocks=<n> " + _ ( " How many blocks to check at startup (default: 288, 0 = all) " ) + " \n " ;
strUsage + = " -checklevel=<n> " + _ ( " How thorough the block verification of -checkblocks is (0-4, default: 3) " ) + " \n " ;
strUsage + = " -conf=<file> " + _ ( " Specify configuration file (default: bitcoin.conf) " ) + " \n " ;
if ( mode = = HMM_BITCOIND )
{
# if !defined(WIN32)
strUsage + = " -daemon " + _ ( " Run in the background as a daemon and accept commands " ) + " \n " ;
# endif
}
strUsage + = " -datadir=<dir> " + _ ( " Specify data directory " ) + " \n " ;
strUsage + = " -dbcache=<n> " + strprintf ( _ ( " Set database cache size in megabytes (%d to %d, default: %d) " ) , nMinDbCache , nMaxDbCache , nDefaultDbCache ) + " \n " ;
strUsage + = " -loadblock=<file> " + _ ( " Imports blocks from external blk000??.dat file " ) + " " + _ ( " on startup " ) + " \n " ;
strUsage + = " -maxorphanblocks=<n> " + strprintf ( _ ( " Keep at most <n> unconnectable blocks in memory (default: %u) " ) , DEFAULT_MAX_ORPHAN_BLOCKS ) + " \n " ;
strUsage + = " -par=<n> " + strprintf ( _ ( " Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) " ) , - ( int ) boost : : thread : : hardware_concurrency ( ) , MAX_SCRIPTCHECK_THREADS , DEFAULT_SCRIPTCHECK_THREADS ) + " \n " ;
strUsage + = " -pid=<file> " + _ ( " Specify pid file (default: bitcoind.pid) " ) + " \n " ;
strUsage + = " -reindex " + _ ( " Rebuild block chain index from current blk000??.dat files " ) + " " + _ ( " on startup " ) + " \n " ;
# if !defined(WIN32)
strUsage + = " -sysperms " + _ ( " Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality) " ) + " \n " ;
# endif
strUsage + = " -txindex " + _ ( " Maintain a full transaction index (default: 0) " ) + " \n " ;
strUsage + = " \n " + _ ( " Connection options: " ) + " \n " ;
strUsage + = " -addnode=<ip> " + _ ( " Add a node to connect to and attempt to keep the connection open " ) + " \n " ;
strUsage + = " -banscore=<n> " + _ ( " Threshold for disconnecting misbehaving peers (default: 100) " ) + " \n " ;
strUsage + = " -bantime=<n> " + _ ( " Number of seconds to keep misbehaving peers from reconnecting (default: 86400) " ) + " \n " ;
strUsage + = " -bind=<addr> " + _ ( " Bind to given address and always listen on it. Use [host]:port notation for IPv6 " ) + " \n " ;
strUsage + = " -connect=<ip> " + _ ( " Connect only to the specified node(s) " ) + " \n " ;
strUsage + = " -discover " + _ ( " Discover own IP address (default: 1 when listening and no -externalip) " ) + " \n " ;
strUsage + = " -dns " + _ ( " Allow DNS lookups for -addnode, -seednode and -connect " ) + " " + _ ( " (default: 1) " ) + " \n " ;
strUsage + = " -dnsseed " + _ ( " Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) " ) + " \n " ;
strUsage + = " -forcednsseed " + _ ( " Always query for peer addresses via DNS lookup (default: 0) " ) + " \n " ;
strUsage + = " -externalip=<ip> " + _ ( " Specify your own public address " ) + " \n " ;
strUsage + = " -listen " + _ ( " Accept connections from outside (default: 1 if no -proxy or -connect) " ) + " \n " ;
strUsage + = " -maxconnections=<n> " + _ ( " Maintain at most <n> connections to peers (default: 125) " ) + " \n " ;
strUsage + = " -maxreceivebuffer=<n> " + _ ( " Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) " ) + " \n " ;
strUsage + = " -maxsendbuffer=<n> " + _ ( " Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) " ) + " \n " ;
strUsage + = " -onion=<ip:port> " + _ ( " Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy) " ) + " \n " ;
strUsage + = " -onlynet=<net> " + _ ( " Only connect to nodes in network <net> (IPv4, IPv6 or Tor) " ) + " \n " ;
strUsage + = " -permitbaremultisig " + _ ( " Relay non-P2SH multisig (default: 1) " ) + " \n " ;
strUsage + = " -port=<port> " + _ ( " Listen for connections on <port> (default: 8333 or testnet: 18333) " ) + " \n " ;
strUsage + = " -proxy=<ip:port> " + _ ( " Connect through SOCKS5 proxy " ) + " \n " ;
strUsage + = " -seednode=<ip> " + _ ( " Connect to a node to retrieve peer addresses, and disconnect " ) + " \n " ;
strUsage + = " -timeout=<n> " + _ ( " Specify connection timeout in milliseconds (default: 5000) " ) + " \n " ;
# ifdef USE_UPNP
# if USE_UPNP
strUsage + = " -upnp " + _ ( " Use UPnP to map the listening port (default: 1 when listening) " ) + " \n " ;
# else
strUsage + = " -upnp " + _ ( " Use UPnP to map the listening port (default: 0) " ) + " \n " ;
# endif
# endif
strUsage + = " -whitebind=<addr> " + _ ( " Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 " ) + " \n " ;
strUsage + = " -whitelist=<netmask> " + _ ( " Whitelist peers connecting from the given netmask or ip. Can be specified multiple times. " ) + " \n " ;
strUsage + = " " + _ ( " Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway " ) + " \n " ;
# ifdef ENABLE_WALLET
strUsage + = " \n " + _ ( " Wallet options: " ) + " \n " ;
strUsage + = " -disablewallet " + _ ( " Do not load the wallet and disable wallet RPC calls " ) + " \n " ;
strUsage + = " -keypool=<n> " + _ ( " Set key pool size to <n> (default: 100) " ) + " \n " ;
if ( GetBoolArg ( " -help-debug " , false ) )
strUsage + = " -mintxfee=<amt> " + strprintf ( _ ( " Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s) " ) , FormatMoney ( CWallet : : minTxFee . GetFeePerK ( ) ) ) + " \n " ;
strUsage + = " -paytxfee=<amt> " + strprintf ( _ ( " Fee (in BTC/kB) to add to transactions you send (default: %s) " ) , FormatMoney ( payTxFee . GetFeePerK ( ) ) ) + " \n " ;
strUsage + = " -rescan " + _ ( " Rescan the block chain for missing wallet transactions " ) + " " + _ ( " on startup " ) + " \n " ;
strUsage + = " -respendnotify=<cmd> " + _ ( " Execute command when a network tx respends wallet tx input (%s=respend TxID, %t=wallet TxID) " ) + " \n " ;
strUsage + = " -salvagewallet " + _ ( " Attempt to recover private keys from a corrupt wallet.dat " ) + " " + _ ( " on startup " ) + " \n " ;
strUsage + = " -spendzeroconfchange " + _ ( " Spend unconfirmed change when sending transactions (default: 1) " ) + " \n " ;
strUsage + = " -txconfirmtarget=<n> " + _ ( " If paytxfee is not set, include enough fee so transactions are confirmed on average within n blocks (default: 1) " ) + " \n " ;
strUsage + = " -upgradewallet " + _ ( " Upgrade wallet to latest format " ) + " " + _ ( " on startup " ) + " \n " ;
strUsage + = " -wallet=<file> " + _ ( " Specify wallet file (within data directory) " ) + " " + _ ( " (default: wallet.dat) " ) + " \n " ;
strUsage + = " -walletnotify=<cmd> " + _ ( " Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) " ) + " \n " ;
strUsage + = " -zapwallettxes=<mode> " + _ ( " Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup " ) + " \n " ;
strUsage + = " " + _ ( " (default: 1, 1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) " ) + " \n " ;
# endif
strUsage + = " \n " + _ ( " Debugging/Testing options: " ) + " \n " ;
if ( GetBoolArg ( " -help-debug " , false ) )
{
strUsage + = " -checkpoints " + _ ( " Only accept block chain matching built-in checkpoints (default: 1) " ) + " \n " ;
strUsage + = " -dblogsize=<n> " + _ ( " Flush database activity from memory pool to disk log every <n> megabytes (default: 100) " ) + " \n " ;
strUsage + = " -disablesafemode " + _ ( " Disable safemode, override a real safe mode event (default: 0) " ) + " \n " ;
strUsage + = " -testsafemode " + _ ( " Force safe mode (default: 0) " ) + " \n " ;
strUsage + = " -dropmessagestest=<n> " + _ ( " Randomly drop 1 of every <n> network messages " ) + " \n " ;
strUsage + = " -fuzzmessagestest=<n> " + _ ( " Randomly fuzz 1 of every <n> network messages " ) + " \n " ;
strUsage + = " -flushwallet " + _ ( " Run a thread to flush wallet periodically (default: 1) " ) + " \n " ;
strUsage + = " -stopafterblockimport " + _ ( " Stop running after importing blocks from disk (default: 0) " ) + " \n " ;
}
strUsage + = " -debug=<category> " + _ ( " Output debugging information (default: 0, supplying <category> is optional) " ) + " \n " ;
strUsage + = " " + _ ( " If <category> is not supplied, output all debugging information. " ) + " \n " ;
strUsage + = " " + _ ( " <category> can be: " ) ;
strUsage + = " addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net " ; // Don't translate these and qt below
if ( mode = = HMM_BITCOIN_QT )
strUsage + = " , qt " ;
strUsage + = " . \n " ;
# ifdef ENABLE_WALLET
strUsage + = " -gen " + _ ( " Generate coins (default: 0) " ) + " \n " ;
strUsage + = " -genproclimit=<n> " + _ ( " Set the processor limit for when generation is on (-1 = unlimited, default: -1) " ) + " \n " ;
# endif
strUsage + = " -help-debug " + _ ( " Show all debugging options (usage: --help -help-debug) " ) + " \n " ;
strUsage + = " -logips " + _ ( " Include IP addresses in debug output (default: 0) " ) + " \n " ;
strUsage + = " -logtimestamps " + _ ( " Prepend debug output with timestamp (default: 1) " ) + " \n " ;
if ( GetBoolArg ( " -help-debug " , false ) )
{
strUsage + = " -limitfreerelay=<n> " + _ ( " Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:15) " ) + " \n " ;
strUsage + = " -maxsigcachesize=<n> " + _ ( " Limit size of signature cache to <n> entries (default: 50000) " ) + " \n " ;
}
strUsage + = " -minrelaytxfee=<amt> " + strprintf ( _ ( " Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) " ) , FormatMoney ( : : minRelayTxFee . GetFeePerK ( ) ) ) + " \n " ;
strUsage + = " -printtoconsole " + _ ( " Send trace/debug info to console instead of debug.log file " ) + " \n " ;
if ( GetBoolArg ( " -help-debug " , false ) )
{
strUsage + = " -printblock=<hash> " + _ ( " Print block on startup, if found in block index " ) + " \n " ;
strUsage + = " -printblocktree " + _ ( " Print block tree on startup (default: 0) " ) + " \n " ;
strUsage + = " -printpriority " + _ ( " Log transaction priority and fee per kB when mining blocks (default: 0) " ) + " \n " ;
strUsage + = " -privdb " + _ ( " Sets the DB_PRIVATE flag in the wallet db environment (default: 1) " ) + " \n " ;
strUsage + = " -regtest " + _ ( " Enter regression test mode, which uses a special chain in which blocks can be solved instantly. " ) + " \n " ;
strUsage + = " " + _ ( " This is intended for regression testing tools and app development. " ) + " \n " ;
strUsage + = " " + _ ( " In this mode -genproclimit controls how many blocks are generated immediately. " ) + " \n " ;
}
strUsage + = " -shrinkdebugfile " + _ ( " Shrink debug.log file on client startup (default: 1 when no -debug) " ) + " \n " ;
strUsage + = " -testnet " + _ ( " Use the test network " ) + " \n " ;
strUsage + = " \n " + _ ( " Node relay options: " ) + " \n " ;
strUsage + = " -datacarrier " + _ ( " Relay and mine data carrier transactions (default: 1) " ) + " \n " ;
strUsage + = " \n " + _ ( " Block creation options: " ) + " \n " ;
strUsage + = " -blockminsize=<n> " + _ ( " Set minimum block size in bytes (default: 0) " ) + " \n " ;
strUsage + = " -blockmaxsize=<n> " + strprintf ( _ ( " Set maximum block size in bytes (default: %d) " ) , DEFAULT_BLOCK_MAX_SIZE ) + " \n " ;
strUsage + = " -blockprioritysize=<n> " + strprintf ( _ ( " Set maximum size of high-priority/low-fee transactions in bytes (default: %d) " ) , DEFAULT_BLOCK_PRIORITY_SIZE ) + " \n " ;
strUsage + = " \n " + _ ( " RPC server options: " ) + " \n " ;
strUsage + = " -server " + _ ( " Accept command line and JSON-RPC commands " ) + " \n " ;
strUsage + = " -rpcbind=<addr> " + _ ( " Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces) " ) + " \n " ;
strUsage + = " -rpcuser=<user> " + _ ( " Username for JSON-RPC connections " ) + " \n " ;
strUsage + = " -rpcpassword=<pw> " + _ ( " Password for JSON-RPC connections " ) + " \n " ;
strUsage + = " -rpcport=<port> " + _ ( " Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) " ) + " \n " ;
strUsage + = " -rpcallowip=<ip> " + _ ( " Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times " ) + " \n " ;
strUsage + = " -rpcthreads=<n> " + _ ( " Set the number of threads to service RPC calls (default: 4) " ) + " \n " ;
strUsage + = " \n " + _ ( " RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) " ) + " \n " ;
strUsage + = " -rpcssl " + _ ( " Use OpenSSL (https) for JSON-RPC connections " ) + " \n " ;
strUsage + = " -rpcsslcertificatechainfile=<file.cert> " + _ ( " Server certificate file (default: server.cert) " ) + " \n " ;
strUsage + = " -rpcsslprivatekeyfile=<file.pem> " + _ ( " Server private key (default: server.pem) " ) + " \n " ;
strUsage + = " -rpcsslciphers=<ciphers> " + _ ( " Acceptable ciphers (default: TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH) " ) + " \n " ;
return strUsage ;
}
std : : string LicenseInfo ( )
{
return FormatParagraph ( strprintf ( _ ( " Copyright (C) 2009-%i The Bitcoin Core Developers " ) , COPYRIGHT_YEAR ) ) + " \n " +
" \n " +
FormatParagraph ( _ ( " This is experimental software. " ) ) + " \n " +
" \n " +
FormatParagraph ( _ ( " Distributed under the MIT/X11 software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. " ) ) + " \n " +
" \n " +
FormatParagraph ( _ ( " This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. " ) ) +
" \n " ;
}
struct CImportingNow
{
CImportingNow ( ) {
assert ( fImporting = = false ) ;
fImporting = true ;
}
~ CImportingNow ( ) {
assert ( fImporting = = true ) ;
fImporting = false ;
}
} ;
void ThreadImport ( std : : vector < boost : : filesystem : : path > vImportFiles )
{
RenameThread ( " bitcoin-loadblk " ) ;
// -reindex
if ( fReindex ) {
CImportingNow imp ;
int nFile = 0 ;
while ( true ) {
CDiskBlockPos pos ( nFile , 0 ) ;
FILE * file = OpenBlockFile ( pos , true ) ;
if ( ! file )
break ;
LogPrintf ( " Reindexing block file blk%05u.dat... \n " , ( unsigned int ) nFile ) ;
LoadExternalBlockFile ( file , & pos ) ;
nFile + + ;
}
pblocktree - > WriteReindexing ( false ) ;
fReindex = false ;
LogPrintf ( " Reindexing finished \n " ) ;
// To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
InitBlockIndex ( ) ;
}
// hardcoded $DATADIR/bootstrap.dat
filesystem : : path pathBootstrap = GetDataDir ( ) / " bootstrap.dat " ;
if ( filesystem : : exists ( pathBootstrap ) ) {
FILE * file = fopen ( pathBootstrap . string ( ) . c_str ( ) , " rb " ) ;
if ( file ) {
CImportingNow imp ;
filesystem : : path pathBootstrapOld = GetDataDir ( ) / " bootstrap.dat.old " ;
LogPrintf ( " Importing bootstrap.dat... \n " ) ;
LoadExternalBlockFile ( file ) ;
RenameOver ( pathBootstrap , pathBootstrapOld ) ;
} else {
LogPrintf ( " Warning: Could not open bootstrap file %s \n " , pathBootstrap . string ( ) ) ;
}
}
// -loadblock=
BOOST_FOREACH ( boost : : filesystem : : path & path , vImportFiles ) {
FILE * file = fopen ( path . string ( ) . c_str ( ) , " rb " ) ;
if ( file ) {
CImportingNow imp ;
LogPrintf ( " Importing blocks file %s... \n " , path . string ( ) ) ;
LoadExternalBlockFile ( file ) ;
} else {
LogPrintf ( " Warning: Could not open blocks file %s \n " , path . string ( ) ) ;
}
}
if ( GetBoolArg ( " -stopafterblockimport " , false ) ) {
LogPrintf ( " Stopping after block import \n " ) ;
StartShutdown ( ) ;
}
}
/** Sanity checks
* Ensure that Bitcoin is running in a usable environment with all
* necessary library support .
*/
bool InitSanityCheck ( void )
{
if ( ! ECC_InitSanityCheck ( ) ) {
InitError ( " OpenSSL appears to lack support for elliptic curve cryptography. For more "
" information, visit https://en.bitcoin.it/wiki/OpenSSL_and_EC_Libraries " ) ;
return false ;
}
if ( ! glibc_sanity_test ( ) | | ! glibcxx_sanity_test ( ) )
return false ;
return true ;
}
/** Initialize bitcoin.
* @ pre Parameters should be parsed and config file should be read .
*/
bool AppInit2 ( boost : : thread_group & threadGroup )
{
// ********************************************************* Step 1: setup
# ifdef _MSC_VER
// Turn off Microsoft heap dump noise
_CrtSetReportMode ( _CRT_WARN , _CRTDBG_MODE_FILE ) ;
_CrtSetReportFile ( _CRT_WARN , CreateFileA ( " NUL " , GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ) ;
# endif
# if _MSC_VER >= 1400
// Disable confusing "helpful" text message on abort, Ctrl-C
_set_abort_behavior ( 0 , _WRITE_ABORT_MSG | _CALL_REPORTFAULT ) ;
# endif
# ifdef WIN32
// Enable Data Execution Prevention (DEP)
// Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008
// A failure is non-critical and needs no further attention!
# ifndef PROCESS_DEP_ENABLE
// We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7),
// which is not correct. Can be removed, when GCCs winbase.h is fixed!
# define PROCESS_DEP_ENABLE 0x00000001
# endif
typedef BOOL ( WINAPI * PSETPROCDEPPOL ) ( DWORD ) ;
PSETPROCDEPPOL setProcDEPPol = ( PSETPROCDEPPOL ) GetProcAddress ( GetModuleHandleA ( " Kernel32.dll " ) , " SetProcessDEPPolicy " ) ;
if ( setProcDEPPol ! = NULL ) setProcDEPPol ( PROCESS_DEP_ENABLE ) ;
// Initialize Windows Sockets
WSADATA wsadata ;
int ret = WSAStartup ( MAKEWORD ( 2 , 2 ) , & wsadata ) ;
if ( ret ! = NO_ERROR | | LOBYTE ( wsadata . wVersion ) ! = 2 | | HIBYTE ( wsadata . wVersion ) ! = 2 )
{
return InitError ( strprintf ( " Error: Winsock library failed to start (WSAStartup returned error %d) " , ret)) ;
}
# endif
# ifndef WIN32
if ( GetBoolArg ( " -sysperms " , false ) ) {
# ifdef ENABLE_WALLET
if ( ! GetBoolArg ( " -disablewallet " , false ) )
return InitError ( " Error: -sysperms is not allowed in combination with enabled wallet functionality " ) ;
# endif
} else {
umask ( 077 ) ;
}
// Clean shutdown on SIGTERM
struct sigaction sa ;
sa . sa_handler = HandleSIGTERM ;
sigemptyset ( & sa . sa_mask ) ;
sa . sa_flags = 0 ;
sigaction ( SIGTERM , & sa , NULL ) ;
sigaction ( SIGINT , & sa , NULL ) ;
// Reopen debug.log on SIGHUP
struct sigaction sa_hup ;
sa_hup . sa_handler = HandleSIGHUP ;
sigemptyset ( & sa_hup . sa_mask ) ;
sa_hup . sa_flags = 0 ;
sigaction ( SIGHUP , & sa_hup , NULL ) ;
# if defined (__SVR4) && defined (__sun)
// ignore SIGPIPE on Solaris
signal ( SIGPIPE , SIG_IGN ) ;
# endif
# endif
// ********************************************************* Step 2: parameter interactions
if ( mapArgs . count ( " -bind " ) | | mapArgs . count ( " -whitebind " ) ) {
// when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
if ( SoftSetBoolArg ( " -listen " , true ) )
LogPrintf ( " AppInit2 : parameter interaction: -bind or -whitebind set -> setting -listen=1 \n " ) ;
}
if ( mapArgs . count ( " -connect " ) & & mapMultiArgs [ " -connect " ] . size ( ) > 0 ) {
// when only connecting to trusted nodes, do not seed via DNS, or listen by default
if ( SoftSetBoolArg ( " -dnsseed " , false ) )
LogPrintf ( " AppInit2 : parameter interaction: -connect set -> setting -dnsseed=0 \n " ) ;
if ( SoftSetBoolArg ( " -listen " , false ) )
LogPrintf ( " AppInit2 : parameter interaction: -connect set -> setting -listen=0 \n " ) ;
}
if ( mapArgs . count ( " -proxy " ) ) {
// to protect privacy, do not listen by default if a default proxy server is specified
if ( SoftSetBoolArg ( " -listen " , false ) )
LogPrintf ( " AppInit2 : parameter interaction: -proxy set -> setting -listen=0 \n " ) ;
}
if ( ! GetBoolArg ( " -listen " , true ) ) {
// do not map ports or try to retrieve public IP when not listening (pointless)
if ( SoftSetBoolArg ( " -upnp " , false ) )
LogPrintf ( " AppInit2 : parameter interaction: -listen=0 -> setting -upnp=0 \n " ) ;
if ( SoftSetBoolArg ( " -discover " , false ) )
LogPrintf ( " AppInit2 : parameter interaction: -listen=0 -> setting -discover=0 \n " ) ;
}
if ( mapArgs . count ( " -externalip " ) ) {
// if an explicit public IP is specified, do not try to find others
if ( SoftSetBoolArg ( " -discover " , false ) )
LogPrintf ( " AppInit2 : parameter interaction: -externalip set -> setting -discover=0 \n " ) ;
}
if ( GetBoolArg ( " -salvagewallet " , false ) ) {
// Rewrite just private keys: rescan to find transactions
if ( SoftSetBoolArg ( " -rescan " , true ) )
LogPrintf ( " AppInit2 : parameter interaction: -salvagewallet=1 -> setting -rescan=1 \n " ) ;
}
// -zapwallettx implies a rescan
if ( GetBoolArg ( " -zapwallettxes " , false ) ) {
if ( SoftSetBoolArg ( " -rescan " , true ) )
LogPrintf ( " AppInit2 : parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1 \n " ) ;
}
// Make sure enough file descriptors are available
int nBind = std : : max ( ( int ) mapArgs . count ( " -bind " ) + ( int ) mapArgs . count ( " -whitebind " ) , 1 ) ;
nMaxConnections = GetArg ( " -maxconnections " , 125 ) ;
nMaxConnections = std : : max ( std : : min ( nMaxConnections , ( int ) ( FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS ) ) , 0 ) ;
int nFD = RaiseFileDescriptorLimit ( nMaxConnections + MIN_CORE_FILEDESCRIPTORS ) ;
if ( nFD < MIN_CORE_FILEDESCRIPTORS )
return InitError ( _ ( " Not enough file descriptors available. " ) ) ;
if ( nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections )
nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS ;
// ********************************************************* Step 3: parameter-to-internal-flags
fDebug = ! mapMultiArgs [ " -debug " ] . empty ( ) ;
// Special-case: if -debug=0/-nodebug is set, turn off debugging messages
const vector < string > & categories = mapMultiArgs [ " -debug " ] ;
if ( GetBoolArg ( " -nodebug " , false ) | | find ( categories . begin ( ) , categories . end ( ) , string ( " 0 " ) ) ! = categories . end ( ) )
fDebug = false ;
// Check for -debugnet
if ( GetBoolArg ( " -debugnet " , false ) )
InitWarning ( _ ( " Warning: Unsupported argument -debugnet ignored, use -debug=net. " ) ) ;
// Check for -socks - as this is a privacy risk to continue, exit here
if ( mapArgs . count ( " -socks " ) )
return InitError ( _ ( " Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. " ) ) ;
// Check for -tor - as this is a privacy risk to continue, exit here
if ( GetBoolArg ( " -tor " , false ) )
return InitError ( _ ( " Error: Unsupported argument -tor found, use -onion. " ) ) ;
if ( GetBoolArg ( " -benchmark " , false ) )
InitWarning ( _ ( " Warning: Unsupported argument -benchmark ignored, use -debug=bench. " ) ) ;
// Checkmempool defaults to true in regtest mode
mempool . setSanityCheck ( GetBoolArg ( " -checkmempool " , Params ( ) . DefaultCheckMemPool ( ) ) ) ;
Checkpoints : : fEnabled = GetBoolArg ( " -checkpoints " , true ) ;
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
nScriptCheckThreads = GetArg ( " -par " , DEFAULT_SCRIPTCHECK_THREADS ) ;
if ( nScriptCheckThreads < = 0 )
nScriptCheckThreads + = boost : : thread : : hardware_concurrency ( ) ;
if ( nScriptCheckThreads < = 1 )
nScriptCheckThreads = 0 ;
else if ( nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS )
nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS ;
fServer = GetBoolArg ( " -server " , false ) ;
fPrintToConsole = GetBoolArg ( " -printtoconsole " , false ) ;
fLogTimestamps = GetBoolArg ( " -logtimestamps " , true ) ;
fLogIPs = GetBoolArg ( " -logips " , false ) ;
setvbuf ( stdout , NULL , _IOLBF , 0 ) ;
# ifdef ENABLE_WALLET
bool fDisableWallet = GetBoolArg ( " -disablewallet " , false ) ;
# endif
if ( mapArgs . count ( " -timeout " ) )
{
int nNewTimeout = GetArg ( " -timeout " , 5000 ) ;
if ( nNewTimeout > 0 & & nNewTimeout < 600000 )
nConnectTimeout = nNewTimeout ;
}
// Continue to put "/P2SH/" in the coinbase to monitor
// BIP16 support.
// This can be removed eventually...
const char * pszP2SH = " /P2SH/ " ;
COINBASE_FLAGS < < std : : vector < unsigned char > ( pszP2SH , pszP2SH + strlen ( pszP2SH ) ) ;
// Fee-per-kilobyte amount considered the same as "free"
// If you are mining, be careful setting this:
// if you set it to zero then
// a transaction spammer can cheaply fill blocks using
// 1-satoshi-fee transactions. It should be set above the real
// cost to you of processing a transaction.
if ( mapArgs . count ( " -minrelaytxfee " ) )
{
int64_t n = 0 ;
if ( ParseMoney ( mapArgs [ " -minrelaytxfee " ] , n ) & & n > 0 )
: : minRelayTxFee = CFeeRate ( n ) ;
else
return InitError ( strprintf ( _ ( " Invalid amount for -minrelaytxfee=<amount>: '%s' " ) , mapArgs [ " -minrelaytxfee " ] ) ) ;
}
# ifdef ENABLE_WALLET
if ( mapArgs . count ( " -mintxfee " ) )
{
int64_t n = 0 ;
if ( ParseMoney ( mapArgs [ " -mintxfee " ] , n ) & & n > 0 )
CWallet : : minTxFee = CFeeRate ( n ) ;
else
return InitError ( strprintf ( _ ( " Invalid amount for -mintxfee=<amount>: '%s' " ) , mapArgs [ " -mintxfee " ] ) ) ;
}
if ( mapArgs . count ( " -paytxfee " ) )
{
int64_t nFeePerK = 0 ;
if ( ! ParseMoney ( mapArgs [ " -paytxfee " ] , nFeePerK ) )
return InitError ( strprintf ( _ ( " Invalid amount for -paytxfee=<amount>: '%s' " ) , mapArgs [ " -paytxfee " ] ) ) ;
if ( nFeePerK > nHighTransactionFeeWarning )
InitWarning ( _ ( " Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. " ) ) ;
payTxFee = CFeeRate ( nFeePerK , 1000 ) ;
if ( payTxFee < : : minRelayTxFee )
{
return InitError ( strprintf ( _ ( " Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) " ) ,
mapArgs [ " -paytxfee " ] , : : minRelayTxFee . ToString ( ) ) ) ;
}
}
nTxConfirmTarget = GetArg ( " -txconfirmtarget " , 1 ) ;
bSpendZeroConfChange = GetArg ( " -spendzeroconfchange " , true ) ;
std : : string strWalletFile = GetArg ( " -wallet " , " wallet.dat " ) ;
# endif // ENABLE_WALLET
fIsBareMultisigStd = GetArg ( " -permitbaremultisig " , true ) ;
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
// Sanity check
if ( ! InitSanityCheck ( ) )
return InitError ( _ ( " Initialization sanity check failed. Bitcoin Core is shutting down. " ) ) ;
std : : string strDataDir = GetDataDir ( ) . string ( ) ;
# ifdef ENABLE_WALLET
// Wallet file must be a plain filename without a directory
if ( strWalletFile ! = boost : : filesystem : : basename ( strWalletFile ) + boost : : filesystem : : extension ( strWalletFile ) )
return InitError ( strprintf ( _ ( " Wallet %s resides outside data directory %s " ) , strWalletFile , strDataDir ) ) ;
# endif
// Make sure only a single Bitcoin process is using the data directory.
boost : : filesystem : : path pathLockFile = GetDataDir ( ) / " .lock " ;
FILE * file = fopen ( pathLockFile . string ( ) . c_str ( ) , " a " ) ; // empty lock file; created if it doesn't exist.
if ( file ) fclose ( file ) ;
static boost : : interprocess : : file_lock lock ( pathLockFile . string ( ) . c_str ( ) ) ;
if ( ! lock . try_lock ( ) )
return InitError ( strprintf ( _ ( " Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running. " ) , strDataDir ) ) ;
if ( GetBoolArg ( " -shrinkdebugfile " , ! fDebug ) )
ShrinkDebugFile ( ) ;
LogPrintf ( " \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n " ) ;
LogPrintf ( " Bitcoin version %s (%s) \n " , FormatFullVersion ( ) , CLIENT_DATE ) ;
LogPrintf ( " Using OpenSSL version %s \n " , SSLeay_version ( SSLEAY_VERSION ) ) ;
# ifdef ENABLE_WALLET
LogPrintf ( " Using BerkeleyDB version %s \n " , DbEnv : : version ( 0 , 0 , 0 ) ) ;
# endif
if ( ! fLogTimestamps )
LogPrintf ( " Startup time: %s \n " , DateTimeStrFormat ( " %Y-%m-%d %H:%M:%S " , GetTime ( ) ) ) ;
LogPrintf ( " Default data directory %s \n " , GetDefaultDataDir ( ) . string ( ) ) ;
LogPrintf ( " Using data directory %s \n " , strDataDir ) ;
LogPrintf ( " Using config file %s \n " , GetConfigFile ( ) . string ( ) ) ;
LogPrintf ( " Using at most %i connections (%i file descriptors available) \n " , nMaxConnections , nFD ) ;
std : : ostringstream strErrors ;
if ( nScriptCheckThreads ) {
LogPrintf ( " Using %u threads for script verification \n " , nScriptCheckThreads ) ;
for ( int i = 0 ; i < nScriptCheckThreads - 1 ; i + + )
threadGroup . create_thread ( & ThreadScriptCheck ) ;
}
int64_t nStart ;
// ********************************************************* Step 5: verify wallet database integrity
# ifdef ENABLE_WALLET
if ( ! fDisableWallet ) {
LogPrintf ( " Using wallet %s \n " , strWalletFile ) ;
uiInterface . InitMessage ( _ ( " Verifying wallet... " ) ) ;
if ( ! bitdb . Open ( GetDataDir ( ) ) )
{
// try moving the database env out of the way
boost : : filesystem : : path pathDatabase = GetDataDir ( ) / " database " ;
boost : : filesystem : : path pathDatabaseBak = GetDataDir ( ) / strprintf ( " database.%d.bak " , GetTime ( ) ) ;
try {
boost : : filesystem : : rename ( pathDatabase , pathDatabaseBak ) ;
LogPrintf ( " Moved old %s to %s. Retrying. \n " , pathDatabase . string ( ) , pathDatabaseBak . string ( ) ) ;
} catch ( boost : : filesystem : : filesystem_error & error ) {
// failure is ok (well, not really, but it's not worse than what we started with)
}
// try again
if ( ! bitdb . Open ( GetDataDir ( ) ) ) {
// if it still fails, it probably means we can't even create the database env
string msg = strprintf ( _ ( " Error initializing wallet database environment %s! " ) , strDataDir ) ;
return InitError ( msg ) ;
}
}
if ( GetBoolArg ( " -salvagewallet " , false ) )
{
// Recover readable keypairs:
if ( ! CWalletDB : : Recover ( bitdb , strWalletFile , true ) )
return false ;
}
if ( filesystem : : exists ( GetDataDir ( ) / strWalletFile ) )
{
CDBEnv : : VerifyResult r = bitdb . Verify ( strWalletFile , CWalletDB : : Recover ) ;
if ( r = = CDBEnv : : RECOVER_OK )
{
string msg = strprintf ( _ ( " Warning: wallet.dat corrupt, data salvaged! "
" Original wallet.dat saved as wallet.{timestamp}.bak in %s; if "
" your balance or transactions are incorrect you should "
" restore from a backup. " ) , strDataDir ) ;
InitWarning ( msg ) ;
}
if ( r = = CDBEnv : : RECOVER_FAIL )
return InitError ( _ ( " wallet.dat corrupt, salvage failed " ) ) ;
}
} // (!fDisableWallet)
# endif // ENABLE_WALLET
// ********************************************************* Step 6: network initialization
RegisterNodeSignals ( GetNodeSignals ( ) ) ;
if ( mapArgs . count ( " -onlynet " ) ) {
std : : set < enum Network > nets ;
BOOST_FOREACH ( std : : string snet , mapMultiArgs [ " -onlynet " ] ) {
enum Network net = ParseNetwork ( snet ) ;
if ( net = = NET_UNROUTABLE )
return InitError ( strprintf ( _ ( " Unknown network specified in -onlynet: '%s' " ) , snet ) ) ;
nets . insert ( net ) ;
}
for ( int n = 0 ; n < NET_MAX ; n + + ) {
enum Network net = ( enum Network ) n ;
if ( ! nets . count ( net ) )
SetLimited ( net ) ;
}
}
if ( mapArgs . count ( " -whitelist " ) ) {
BOOST_FOREACH ( const std : : string & net , mapMultiArgs [ " -whitelist " ] ) {
CSubNet subnet ( net ) ;
if ( ! subnet . IsValid ( ) )
return InitError ( strprintf ( _ ( " Invalid netmask specified in -whitelist: '%s' " ) , net ) ) ;
CNode : : AddWhitelistedRange ( subnet ) ;
}
}
CService addrProxy ;
bool fProxy = false ;
if ( mapArgs . count ( " -proxy " ) ) {
addrProxy = CService ( mapArgs [ " -proxy " ] , 9050 ) ;
if ( ! addrProxy . IsValid ( ) )
return InitError ( strprintf ( _ ( " Invalid -proxy address: '%s' " ) , mapArgs [ " -proxy " ] ) ) ;
if ( ! IsLimited ( NET_IPV4 ) )
SetProxy ( NET_IPV4 , addrProxy ) ;
if ( ! IsLimited ( NET_IPV6 ) )
SetProxy ( NET_IPV6 , addrProxy ) ;
SetNameProxy ( addrProxy ) ;
fProxy = true ;
}
// -onion can override normal proxy, -noonion disables tor entirely
if ( ! ( mapArgs . count ( " -onion " ) & & mapArgs [ " -onion " ] = = " 0 " ) & &
( fProxy | | mapArgs . count ( " -onion " ) ) ) {
CService addrOnion ;
if ( ! mapArgs . count ( " -onion " ) )
addrOnion = addrProxy ;
else
addrOnion = CService ( mapArgs [ " -onion " ] , 9050 ) ;
if ( ! addrOnion . IsValid ( ) )
return InitError ( strprintf ( _ ( " Invalid -onion address: '%s' " ) , mapArgs [ " -onion " ] ) ) ;
SetProxy ( NET_TOR , addrOnion ) ;
SetReachable ( NET_TOR ) ;
}
// see Step 2: parameter interactions for more information about these
fListen = GetBoolArg ( " -listen " , DEFAULT_LISTEN ) ;
fDiscover = GetBoolArg ( " -discover " , true ) ;
fNameLookup = GetBoolArg ( " -dns " , true ) ;
bool fBound = false ;
if ( fListen ) {
if ( mapArgs . count ( " -bind " ) | | mapArgs . count ( " -whitebind " ) ) {
BOOST_FOREACH ( std : : string strBind , mapMultiArgs [ " -bind " ] ) {
CService addrBind ;
if ( ! Lookup ( strBind . c_str ( ) , addrBind , GetListenPort ( ) , false ) )
return InitError ( strprintf ( _ ( " Cannot resolve -bind address: '%s' " ) , strBind ) ) ;
fBound | = Bind ( addrBind , ( BF_EXPLICIT | BF_REPORT_ERROR ) ) ;
}
BOOST_FOREACH ( std : : string strBind , mapMultiArgs [ " -whitebind " ] ) {
CService addrBind ;
if ( ! Lookup ( strBind . c_str ( ) , addrBind , 0 , false ) )
return InitError ( strprintf ( _ ( " Cannot resolve -whitebind address: '%s' " ) , strBind ) ) ;
if ( addrBind . GetPort ( ) = = 0 )
return InitError ( strprintf ( _ ( " Need to specify a port with -whitebind: '%s' " ) , strBind ) ) ;
fBound | = Bind ( addrBind , ( BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST ) ) ;
}
}
else {
struct in_addr inaddr_any ;
inaddr_any . s_addr = INADDR_ANY ;
fBound | = Bind ( CService ( in6addr_any , GetListenPort ( ) ) , BF_NONE ) ;
fBound | = Bind ( CService ( inaddr_any , GetListenPort ( ) ) , ! fBound ? BF_REPORT_ERROR : BF_NONE ) ;
}
if ( ! fBound )
return InitError ( _ ( " Failed to listen on any port. Use -listen=0 if you want this. " ) ) ;
}
if ( mapArgs . count ( " -externalip " ) ) {
BOOST_FOREACH ( string strAddr , mapMultiArgs [ " -externalip " ] ) {
CService addrLocal ( strAddr , GetListenPort ( ) , fNameLookup ) ;
if ( ! addrLocal . IsValid ( ) )
return InitError ( strprintf ( _ ( " Cannot resolve -externalip address: '%s' " ) , strAddr ) ) ;
AddLocal ( CService ( strAddr , GetListenPort ( ) , fNameLookup ) , LOCAL_MANUAL ) ;
}
}
BOOST_FOREACH ( string strDest , mapMultiArgs [ " -seednode " ] )
AddOneShot ( strDest ) ;
// ********************************************************* Step 7: load block chain
fReindex = GetBoolArg ( " -reindex " , false ) ;
// Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/
filesystem : : path blocksDir = GetDataDir ( ) / " blocks " ;
if ( ! filesystem : : exists ( blocksDir ) )
{
filesystem : : create_directories ( blocksDir ) ;
bool linked = false ;
for ( unsigned int i = 1 ; i < 10000 ; i + + ) {
filesystem : : path source = GetDataDir ( ) / strprintf ( " blk%04u.dat " , i ) ;
if ( ! filesystem : : exists ( source ) ) break ;
filesystem : : path dest = blocksDir / strprintf ( " blk%05u.dat " , i - 1 ) ;
try {
filesystem : : create_hard_link ( source , dest ) ;
LogPrintf ( " Hardlinked %s -> %s \n " , source . string ( ) , dest . string ( ) ) ;
linked = true ;
} catch ( filesystem : : filesystem_error & e ) {
// Note: hardlink creation failing is not a disaster, it just means
// blocks will get re-downloaded from peers.
LogPrintf ( " Error hardlinking blk%04u.dat : %s \n " , i , e . what ( ) ) ;
break ;
}
}
if ( linked )
{
fReindex = true ;
}
}
// cache size calculations
size_t nTotalCache = ( GetArg ( " -dbcache " , nDefaultDbCache ) < < 20 ) ;
if ( nTotalCache < ( nMinDbCache < < 20 ) )
nTotalCache = ( nMinDbCache < < 20 ) ; // total cache cannot be less than nMinDbCache
else if ( nTotalCache > ( nMaxDbCache < < 20 ) )
nTotalCache = ( nMaxDbCache < < 20 ) ; // total cache cannot be greater than nMaxDbCache
size_t nBlockTreeDBCache = nTotalCache / 8 ;
if ( nBlockTreeDBCache > ( 1 < < 21 ) & & ! GetBoolArg ( " -txindex " , false ) )
nBlockTreeDBCache = ( 1 < < 21 ) ; // block tree db cache shouldn't be larger than 2 MiB
nTotalCache - = nBlockTreeDBCache ;
size_t nCoinDBCache = nTotalCache / 2 ; // use half of the remaining cache for coindb cache
nTotalCache - = nCoinDBCache ;
nCoinCacheSize = nTotalCache / 300 ; // coins in memory require around 300 bytes
bool fLoaded = false ;
while ( ! fLoaded ) {
bool fReset = fReindex ;
std : : string strLoadError ;
uiInterface . InitMessage ( _ ( " Loading block index... " ) ) ;
nStart = GetTimeMillis ( ) ;
do {
try {
UnloadBlockIndex ( ) ;
delete pcoinsTip ;
delete pcoinsdbview ;
delete pblocktree ;
pblocktree = new CBlockTreeDB ( nBlockTreeDBCache , false , fReindex ) ;
pcoinsdbview = new CCoinsViewDB ( nCoinDBCache , false , fReindex ) ;
pcoinsTip = new CCoinsViewCache ( * pcoinsdbview ) ;
if ( fReindex )
pblocktree - > WriteReindexing ( true ) ;
if ( ! LoadBlockIndex ( ) ) {
strLoadError = _ ( " Error loading block database " ) ;
break ;
}
// If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around).
if ( ! mapBlockIndex . empty ( ) & & chainActive . Genesis ( ) = = NULL )
return InitError ( _ ( " Incorrect or no genesis block found. Wrong datadir for network? " ) ) ;
// Initialize the block index (no-op if non-empty database was already loaded)
if ( ! InitBlockIndex ( ) ) {
strLoadError = _ ( " Error initializing block database " ) ;
break ;
}
// Check for changed -txindex state
if ( fTxIndex ! = GetBoolArg ( " -txindex " , false ) ) {
strLoadError = _ ( " You need to rebuild the database using -reindex to change -txindex " ) ;
break ;
}
uiInterface . InitMessage ( _ ( " Verifying blocks... " ) ) ;
if ( ! CVerifyDB ( ) . VerifyDB ( GetArg ( " -checklevel " , 3 ) ,
GetArg ( " -checkblocks " , 288 ) ) ) {
strLoadError = _ ( " Corrupted block database detected " ) ;
break ;
}
} catch ( std : : exception & e ) {
if ( fDebug ) LogPrintf ( " %s \n " , e . what ( ) ) ;
strLoadError = _ ( " Error opening block database " ) ;
break ;
}
fLoaded = true ;
} while ( false ) ;
if ( ! fLoaded ) {
// first suggest a reindex
if ( ! fReset ) {
bool fRet = uiInterface . ThreadSafeMessageBox (
strLoadError + " . \n \n " + _ ( " Do you want to rebuild the block database now? " ) ,
" " , CClientUIInterface : : MSG_ERROR | CClientUIInterface : : BTN_ABORT ) ;
if ( fRet ) {
fReindex = true ;
fRequestShutdown = false ;
} else {
LogPrintf ( " Aborted block database rebuild. Exiting. \n " ) ;
return false ;
}
} else {
return InitError ( strLoadError ) ;
}
}
}
// As LoadBlockIndex can take several minutes, it's possible the user
// requested to kill the GUI during the last operation. If so, exit.
// As the program has not fully started yet, Shutdown() is possibly overkill.
if ( fRequestShutdown )
{
LogPrintf ( " Shutdown requested. Exiting. \n " ) ;
return false ;
}
LogPrintf ( " block index %15dms \n " , GetTimeMillis ( ) - nStart ) ;
if ( GetBoolArg ( " -printblockindex " , false ) | | GetBoolArg ( " -printblocktree " , false ) )
{
PrintBlockTree ( ) ;
return false ;
}
if ( mapArgs . count ( " -printblock " ) )
{
string strMatch = mapArgs [ " -printblock " ] ;
int nFound = 0 ;
for ( map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . begin ( ) ; mi ! = mapBlockIndex . end ( ) ; + + mi )
{
uint256 hash = ( * mi ) . first ;
if ( boost : : algorithm : : starts_with ( hash . ToString ( ) , strMatch ) )
{
CBlockIndex * pindex = ( * mi ) . second ;
CBlock block ;
ReadBlockFromDisk ( block , pindex ) ;
block . BuildMerkleTree ( ) ;
block . print ( ) ;
LogPrintf ( " \n " ) ;
nFound + + ;
}
}
if ( nFound = = 0 )
LogPrintf ( " No blocks matching %s were found \n " , strMatch ) ;
return false ;
}
boost : : filesystem : : path est_path = GetDataDir ( ) / FEE_ESTIMATES_FILENAME ;
CAutoFile est_filein = CAutoFile ( fopen ( est_path . string ( ) . c_str ( ) , " rb " ) , SER_DISK , CLIENT_VERSION ) ;
// Allowed to fail as this file IS missing on first startup.
if ( est_filein )
mempool . ReadFeeEstimates ( est_filein ) ;
// ********************************************************* Step 8: load wallet
# ifdef ENABLE_WALLET
if ( fDisableWallet ) {
pwalletMain = NULL ;
LogPrintf ( " Wallet disabled! \n " ) ;
} else {
// needed to restore wallet transaction meta data after -zapwallettxes
std : : vector < CWalletTx > vWtx ;
if ( GetBoolArg ( " -zapwallettxes " , false ) ) {
uiInterface . InitMessage ( _ ( " Zapping all transactions from wallet... " ) ) ;
pwalletMain = new CWallet ( strWalletFile ) ;
DBErrors nZapWalletRet = pwalletMain - > ZapWalletTx ( vWtx ) ;
if ( nZapWalletRet ! = DB_LOAD_OK ) {
uiInterface . InitMessage ( _ ( " Error loading wallet.dat: Wallet corrupted " ) ) ;
return false ;
}
delete pwalletMain ;
pwalletMain = NULL ;
}
uiInterface . InitMessage ( _ ( " Loading wallet... " ) ) ;
nStart = GetTimeMillis ( ) ;
bool fFirstRun = true ;
pwalletMain = new CWallet ( strWalletFile ) ;
DBErrors nLoadWalletRet = pwalletMain - > LoadWallet ( fFirstRun ) ;
if ( nLoadWalletRet ! = DB_LOAD_OK )
{
if ( nLoadWalletRet = = DB_CORRUPT )
strErrors < < _ ( " Error loading wallet.dat: Wallet corrupted " ) < < " \n " ;
else if ( nLoadWalletRet = = DB_NONCRITICAL_ERROR )
{
string msg ( _ ( " Warning: error reading wallet.dat! All keys read correctly, but transaction data "
" or address book entries might be missing or incorrect. " ) ) ;
InitWarning ( msg ) ;
}
else if ( nLoadWalletRet = = DB_TOO_NEW )
strErrors < < _ ( " Error loading wallet.dat: Wallet requires newer version of Bitcoin Core " ) < < " \n " ;
else if ( nLoadWalletRet = = DB_NEED_REWRITE )
{
strErrors < < _ ( " Wallet needed to be rewritten: restart Bitcoin Core to complete " ) < < " \n " ;
LogPrintf ( " %s " , strErrors . str ( ) ) ;
return InitError ( strErrors . str ( ) ) ;
}
else
strErrors < < _ ( " Error loading wallet.dat " ) < < " \n " ;
}
if ( GetBoolArg ( " -upgradewallet " , fFirstRun ) )
{
int nMaxVersion = GetArg ( " -upgradewallet " , 0 ) ;
if ( nMaxVersion = = 0 ) // the -upgradewallet without argument case
{
LogPrintf ( " Performing wallet upgrade to %i \n " , FEATURE_LATEST ) ;
nMaxVersion = CLIENT_VERSION ;
pwalletMain - > SetMinVersion ( FEATURE_LATEST ) ; // permanently upgrade the wallet immediately
}
else
LogPrintf ( " Allowing wallet upgrade up to %i \n " , nMaxVersion ) ;
if ( nMaxVersion < pwalletMain - > GetVersion ( ) )
strErrors < < _ ( " Cannot downgrade wallet " ) < < " \n " ;
pwalletMain - > SetMaxVersion ( nMaxVersion ) ;
}
if ( fFirstRun )
{
// Create new keyUser and set as default key
RandAddSeedPerfmon ( ) ;
CPubKey newDefaultKey ;
if ( pwalletMain - > GetKeyFromPool ( newDefaultKey ) ) {
pwalletMain - > SetDefaultKey ( newDefaultKey ) ;
if ( ! pwalletMain - > SetAddressBook ( pwalletMain - > vchDefaultKey . GetID ( ) , " " , " receive " ) )
strErrors < < _ ( " Cannot write default address " ) < < " \n " ;
}
pwalletMain - > SetBestChain ( chainActive . GetLocator ( ) ) ;
}
LogPrintf ( " %s " , strErrors . str ( ) ) ;
LogPrintf ( " wallet %15dms \n " , GetTimeMillis ( ) - nStart ) ;
RegisterWallet ( pwalletMain ) ;
CBlockIndex * pindexRescan = chainActive . Tip ( ) ;
if ( GetBoolArg ( " -rescan " , false ) )
pindexRescan = chainActive . Genesis ( ) ;
else
{
CWalletDB walletdb ( strWalletFile ) ;
CBlockLocator locator ;
if ( walletdb . ReadBestBlock ( locator ) )
pindexRescan = chainActive . FindFork ( locator ) ;
else
pindexRescan = chainActive . Genesis ( ) ;
}
if ( chainActive . Tip ( ) & & chainActive . Tip ( ) ! = pindexRescan )
{
uiInterface . InitMessage ( _ ( " Rescanning... " ) ) ;
LogPrintf ( " Rescanning last %i blocks (from block %i)... \n " , chainActive . Height ( ) - pindexRescan - > nHeight , pindexRescan - > nHeight ) ;
nStart = GetTimeMillis ( ) ;
pwalletMain - > ScanForWalletTransactions ( pindexRescan , true ) ;
LogPrintf ( " rescan %15dms \n " , GetTimeMillis ( ) - nStart ) ;
pwalletMain - > SetBestChain ( chainActive . GetLocator ( ) ) ;
nWalletDBUpdated + + ;
// Restore wallet transaction metadata after -zapwallettxes=1
if ( GetBoolArg ( " -zapwallettxes " , false ) & & GetArg ( " -zapwallettxes " , " 1 " ) ! = " 2 " )
{
BOOST_FOREACH ( const CWalletTx & wtxOld , vWtx )
{
uint256 hash = wtxOld . GetHash ( ) ;
std : : map < uint256 , CWalletTx > : : iterator mi = pwalletMain - > mapWallet . find ( hash ) ;
if ( mi ! = pwalletMain - > mapWallet . end ( ) )
{
const CWalletTx * copyFrom = & wtxOld ;
CWalletTx * copyTo = & mi - > second ;
copyTo - > mapValue = copyFrom - > mapValue ;
copyTo - > vOrderForm = copyFrom - > vOrderForm ;
copyTo - > nTimeReceived = copyFrom - > nTimeReceived ;
copyTo - > nTimeSmart = copyFrom - > nTimeSmart ;
copyTo - > fFromMe = copyFrom - > fFromMe ;
copyTo - > strFromAccount = copyFrom - > strFromAccount ;
copyTo - > nOrderPos = copyFrom - > nOrderPos ;
copyTo - > WriteToDisk ( ) ;
}
}
}
}
} // (!fDisableWallet)
# else // ENABLE_WALLET
LogPrintf ( " No wallet compiled in! \n " ) ;
# endif // !ENABLE_WALLET
// ********************************************************* Step 9: import blocks
// scan for better chains in the block chain database, that are not yet connected in the active best chain
CValidationState state ;
if ( ! ActivateBestChain ( state ) )
strErrors < < " Failed to connect best block " ;
std : : vector < boost : : filesystem : : path > vImportFiles ;
if ( mapArgs . count ( " -loadblock " ) )
{
BOOST_FOREACH ( string strFile , mapMultiArgs [ " -loadblock " ] )
vImportFiles . push_back ( strFile ) ;
}
threadGroup . create_thread ( boost : : bind ( & ThreadImport , vImportFiles ) ) ;
// ********************************************************* Step 10: load peers
uiInterface . InitMessage ( _ ( " Loading addresses... " ) ) ;
nStart = GetTimeMillis ( ) ;
{
CAddrDB adb ;
if ( ! adb . Read ( addrman ) )
LogPrintf ( " Invalid or missing peers.dat; recreating \n " ) ;
}
LogPrintf ( " Loaded %i addresses from peers.dat %dms \n " ,
addrman . size ( ) , GetTimeMillis ( ) - nStart ) ;
// ********************************************************* Step 11: start node
if ( ! CheckDiskSpace ( ) )
return false ;
if ( ! strErrors . str ( ) . empty ( ) )
return InitError ( strErrors . str ( ) ) ;
RandAddSeedPerfmon ( ) ;
//// debug print
LogPrintf ( " mapBlockIndex.size() = %u \n " , mapBlockIndex . size ( ) ) ;
LogPrintf ( " nBestHeight = %d \n " , chainActive . Height ( ) ) ;
# ifdef ENABLE_WALLET
LogPrintf ( " setKeyPool.size() = %u \n " , pwalletMain ? pwalletMain - > setKeyPool . size ( ) : 0 ) ;
LogPrintf ( " mapWallet.size() = %u \n " , pwalletMain ? pwalletMain - > mapWallet . size ( ) : 0 ) ;
LogPrintf ( " mapAddressBook.size() = %u \n " , pwalletMain ? pwalletMain - > mapAddressBook . size ( ) : 0 ) ;
# endif
StartNode ( threadGroup ) ;
if ( fServer )
StartRPCThreads ( ) ;
# ifdef ENABLE_WALLET
// Generate coins in the background
if ( pwalletMain )
GenerateBitcoins ( GetBoolArg ( " -gen " , false ) , pwalletMain , GetArg ( " -genproclimit " , - 1 ) ) ;
# endif
// ********************************************************* Step 12: finished
uiInterface . InitMessage ( _ ( " Done loading " ) ) ;
# ifdef ENABLE_WALLET
if ( pwalletMain ) {
// Add wallet transactions that aren't already in a block to mapTransactions
pwalletMain - > ReacceptWalletTransactions ( ) ;
// Run a thread to flush wallet periodically
threadGroup . create_thread ( boost : : bind ( & ThreadFlushWalletDB , boost : : ref ( pwalletMain - > strWalletFile ) ) ) ;
}
# endif
return ! fRequestShutdown ;
}