2011-05-14 20:10:21 +02:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2013-10-20 21:25:06 +02:00
// Copyright (c) 2009-2013 The Bitcoin developers
2011-05-14 20:10:21 +02:00
// Distributed under the MIT/X11 software license, see the accompanying
2012-05-18 16:02:28 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2012-11-05 08:04:21 +01:00
2013-05-28 01:55:01 +02:00
# if defined(HAVE_CONFIG_H)
# include "bitcoin-config.h"
# endif
2013-01-07 17:07:51 +01:00
# include "init.h"
# include "main.h"
2013-01-08 13:17:15 +01:00
# include "core.h"
2013-05-07 15:16:25 +02:00
# include "chainparams.h"
2012-09-03 21:14:03 +02:00
# include "txdb.h"
2012-04-15 23:39:49 +02:00
# include "walletdb.h"
2011-07-03 20:53:56 +02:00
# include "bitcoinrpc.h"
2011-06-18 18:46:01 +02:00
# include "net.h"
2012-04-15 22:10:54 +02:00
# include "util.h"
2013-07-31 15:43:35 +02:00
# include "miner.h"
2012-04-15 22:10:54 +02:00
# include "ui_interface.h"
2013-05-24 17:10:53 +02:00
# include "checkpoints.h"
2012-11-05 08:04:21 +01:00
2011-06-26 19:23:24 +02:00
# include <boost/filesystem.hpp>
2011-06-18 18:46:01 +02:00
# include <boost/filesystem/fstream.hpp>
2011-12-20 00:49:07 +01:00
# include <boost/filesystem/convenience.hpp>
2011-06-18 18:46:01 +02:00
# include <boost/interprocess/sync/file_lock.hpp>
2012-05-20 00:46:23 +02:00
# include <boost/algorithm/string/predicate.hpp>
2012-06-14 19:23:59 +02:00
# include <openssl/crypto.h>
2011-05-14 20:10:21 +02:00
2012-04-15 22:10:54 +02:00
# ifndef WIN32
# include <signal.h>
2012-03-18 23:14:03 +01:00
# endif
2011-10-07 16:46:56 +02:00
2011-05-14 20:10:21 +02:00
using namespace std ;
using namespace boost ;
2012-06-03 01:19:07 +02:00
std : : string strWalletFile ;
2011-06-26 19:23:24 +02:00
CWallet * pwalletMain ;
2012-05-06 19:40:58 +02:00
CClientUIInterface uiInterface ;
2011-06-26 19:23:24 +02:00
2013-04-26 00:46:47 +02:00
# 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
2012-09-03 15:54:47 +02:00
// Used to pass flags to the Bind() function
enum BindFlags {
2012-11-14 16:07:40 +01:00
BF_NONE = 0 ,
BF_EXPLICIT = ( 1U < < 0 ) ,
BF_REPORT_ERROR = ( 1U < < 1 )
2012-09-03 15:54:47 +02:00
} ;
2013-01-07 16:35:31 +01:00
2011-05-14 20:10:21 +02:00
//////////////////////////////////////////////////////////////////////////////
//
// Shutdown
//
2013-03-09 18:02:57 +01:00
//
// 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
2013-03-23 23:14:12 +01:00
// fRequestShutdown getting set, and then does the normal Qt
// shutdown thing.
2013-03-09 18:02:57 +01:00
//
volatile bool fRequestShutdown = false ;
2011-05-14 20:10:21 +02:00
2012-06-11 07:40:14 +02:00
void StartShutdown ( )
{
2013-03-09 18:02:57 +01:00
fRequestShutdown = true ;
2012-06-11 07:40:14 +02:00
}
2013-03-23 23:14:12 +01:00
bool ShutdownRequested ( )
{
return fRequestShutdown ;
}
2012-06-11 07:40:14 +02:00
2012-07-06 16:33:34 +02:00
static CCoinsViewDB * pcoinsdbview ;
2013-03-09 18:02:57 +01:00
void Shutdown ( )
2011-05-14 20:10:21 +02:00
{
2013-10-01 09:44:56 +02:00
LogPrintf ( " Shutdown : In progress... \n " ) ;
2011-05-14 20:10:21 +02:00
static CCriticalSection cs_Shutdown ;
2013-03-09 18:02:57 +01:00
TRY_LOCK ( cs_Shutdown , lockShutdown ) ;
if ( ! lockShutdown ) return ;
2012-06-24 17:03:57 +02:00
RenameThread ( " bitcoin-shutoff " ) ;
2013-03-07 04:31:26 +01:00
nTransactionsUpdated + + ;
StopRPCThreads ( ) ;
2013-05-30 15:51:41 +02:00
ShutdownRPCMining ( ) ;
2013-08-25 06:00:02 +02:00
if ( pwalletMain )
bitdb . Flush ( false ) ;
2013-01-07 16:35:31 +01:00
GenerateBitcoins ( false , NULL ) ;
2013-03-07 04:31:26 +01:00
StopNode ( ) ;
2011-05-14 20:10:21 +02:00
{
2013-03-09 18:02:57 +01:00
LOCK ( cs_main ) ;
2013-05-24 21:52:52 +02:00
if ( pwalletMain )
2013-10-12 15:18:08 +02:00
pwalletMain - > SetBestChain ( chainActive . GetLocator ( ) ) ;
2013-03-09 18:02:57 +01:00
if ( pblocktree )
pblocktree - > Flush ( ) ;
if ( pcoinsTip )
pcoinsTip - > Flush ( ) ;
delete pcoinsTip ; pcoinsTip = NULL ;
delete pcoinsdbview ; pcoinsdbview = NULL ;
delete pblocktree ; pblocktree = NULL ;
2011-05-14 20:10:21 +02:00
}
2013-08-25 06:00:02 +02:00
if ( pwalletMain )
bitdb . Flush ( true ) ;
2013-03-09 18:02:57 +01:00
boost : : filesystem : : remove ( GetPidFile ( ) ) ;
2013-01-23 21:48:35 +01:00
UnregisterAllWallets ( ) ;
2013-08-25 06:00:02 +02:00
if ( pwalletMain )
delete pwalletMain ;
2013-10-01 09:44:56 +02:00
LogPrintf ( " Shutdown : done \n " ) ;
2011-05-14 20:10:21 +02:00
}
2013-03-07 04:16:05 +01:00
//
// Signal handlers are very limited in what they are allowed to do, so:
//
2011-05-14 20:10:21 +02:00
void HandleSIGTERM ( int )
{
fRequestShutdown = true ;
}
2012-03-02 20:31:16 +01:00
void HandleSIGHUP ( int )
{
fReopenDebugLog = true ;
}
2011-05-14 20:10:21 +02:00
2012-05-13 12:35:39 +02:00
bool static InitError ( const std : : string & str )
{
2012-11-05 08:04:21 +01:00
uiInterface . ThreadSafeMessageBox ( str , " " , CClientUIInterface : : MSG_ERROR ) ;
2012-05-13 12:35:39 +02:00
return false ;
}
bool static InitWarning ( const std : : string & str )
{
2012-11-05 08:04:21 +01:00
uiInterface . ThreadSafeMessageBox ( str , " " , CClientUIInterface : : MSG_WARNING ) ;
2012-05-13 12:35:39 +02:00
return true ;
}
2012-11-14 16:07:40 +01:00
bool static Bind ( const CService & addr , unsigned int flags ) {
2012-09-03 15:54:47 +02:00
if ( ! ( flags & BF_EXPLICIT ) & & IsLimited ( addr ) )
2012-05-11 15:28:59 +02:00
return false ;
std : : string strError ;
2012-05-24 19:02:21 +02:00
if ( ! BindListenPort ( addr , strError ) ) {
2012-09-03 15:54:47 +02:00
if ( flags & BF_REPORT_ERROR )
2012-05-24 19:02:21 +02:00
return InitError ( strError ) ;
return false ;
}
2012-05-11 15:28:59 +02:00
return true ;
}
2013-10-11 23:09:59 +02:00
// Core-specific options shared between UI, daemon and RPC client
std : : string HelpMessage ( HelpMessageMode hmm )
2012-05-13 11:36:10 +02:00
{
2013-05-26 20:05:53 +02:00
string strUsage = _ ( " Options: " ) + " \n " ;
strUsage + = " -? " + _ ( " This help message " ) + " \n " ;
strUsage + = " -conf=<file> " + _ ( " Specify configuration file (default: bitcoin.conf) " ) + " \n " ;
strUsage + = " -datadir=<dir> " + _ ( " Specify data directory " ) + " \n " ;
2013-10-11 23:09:59 +02:00
strUsage + = " -testnet " + _ ( " Use the test network " ) + " \n " ;
if ( hmm = = HMM_BITCOIND | | hmm = = HMM_BITCOIN_QT )
{
strUsage + = " -pid=<file> " + _ ( " Specify pid file (default: bitcoind.pid) " ) + " \n " ;
strUsage + = " -gen " + _ ( " Generate coins (default: 0) " ) + " \n " ;
strUsage + = " -wallet=<file> " + _ ( " Specify wallet file (within data directory) " ) + " \n " ;
strUsage + = " -dbcache=<n> " + _ ( " Set database cache size in megabytes (default: 25) " ) + " \n " ;
strUsage + = " -timeout=<n> " + _ ( " Specify connection timeout in milliseconds (default: 5000) " ) + " \n " ;
strUsage + = " -proxy=<ip:port> " + _ ( " Connect through socks proxy " ) + " \n " ;
strUsage + = " -socks=<n> " + _ ( " Select the version of socks proxy to use (4-5, default: 5) " ) + " \n " ;
strUsage + = " -onion=<ip:port> " + _ ( " Use proxy to reach tor hidden services (default: same as -proxy) " ) + " \n " ;
strUsage + = " -dns " + _ ( " Allow DNS lookups for -addnode, -seednode and -connect " ) + " \n " ;
strUsage + = " -port=<port> " + _ ( " Listen for connections on <port> (default: 8333 or testnet: 18333) " ) + " \n " ;
strUsage + = " -maxconnections=<n> " + _ ( " Maintain at most <n> connections to peers (default: 125) " ) + " \n " ;
strUsage + = " -addnode=<ip> " + _ ( " Add a node to connect to and attempt to keep the connection open " ) + " \n " ;
strUsage + = " -connect=<ip> " + _ ( " Connect only to the specified node(s) " ) + " \n " ;
strUsage + = " -seednode=<ip> " + _ ( " Connect to a node to retrieve peer addresses, and disconnect " ) + " \n " ;
strUsage + = " -externalip=<ip> " + _ ( " Specify your own public address " ) + " \n " ;
strUsage + = " -onlynet=<net> " + _ ( " Only connect to nodes in network <net> (IPv4, IPv6 or Tor) " ) + " \n " ;
strUsage + = " -discover " + _ ( " Discover own IP address (default: 1 when listening and no -externalip) " ) + " \n " ;
strUsage + = " -checkpoints " + _ ( " Only accept block chain matching built-in checkpoints (default: 1) " ) + " \n " ;
strUsage + = " -listen " + _ ( " Accept connections from outside (default: 1 if no -proxy or -connect) " ) + " \n " ;
strUsage + = " -bind=<addr> " + _ ( " Bind to given address and always listen on it. Use [host]:port notation for IPv6 " ) + " \n " ;
strUsage + = " -dnsseed " + _ ( " Find peers using DNS lookup (default: 1 unless -connect) " ) + " \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 + = " -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 " ;
2012-05-13 11:36:10 +02:00
# ifdef USE_UPNP
# if USE_UPNP
2013-10-11 23:09:59 +02:00
strUsage + = " -upnp " + _ ( " Use UPnP to map the listening port (default: 1 when listening) " ) + " \n " ;
2012-05-13 11:36:10 +02:00
# else
2013-10-11 23:09:59 +02:00
strUsage + = " -upnp " + _ ( " Use UPnP to map the listening port (default: 0) " ) + " \n " ;
# endif
2012-05-13 11:36:10 +02:00
# endif
2013-10-11 23:09:59 +02:00
strUsage + = " -paytxfee=<amt> " + _ ( " Fee per KB to add to transactions you send " ) + " \n " ;
strUsage + = " -debug " + _ ( " Output extra debugging information. Implies all other -debug* options " ) + " \n " ;
strUsage + = " -debugnet " + _ ( " Output extra network debugging information " ) + " \n " ;
strUsage + = " -logtimestamps " + _ ( " Prepend debug output with timestamp " ) + " \n " ;
strUsage + = " -shrinkdebugfile " + _ ( " Shrink debug.log file on client startup (default: 1 when no -debug) " ) + " \n " ;
strUsage + = " -printtoconsole " + _ ( " Send trace/debug info to console instead of debug.log file " ) + " \n " ;
strUsage + = " -regtest " + _ ( " Enter regression test mode, which uses a special chain in which blocks can be "
" solved instantly. This is intended for regression testing tools and app development. " ) + " \n " ;
# ifdef WIN32
strUsage + = " -printtodebugger " + _ ( " Send trace/debug info to debugger " ) + " \n " ;
2012-05-13 11:36:10 +02:00
# endif
2013-10-11 23:09:59 +02:00
}
if ( hmm = = HMM_BITCOIN_QT )
{
2013-05-26 20:10:38 +02:00
strUsage + = " -server " + _ ( " Accept command line and JSON-RPC commands " ) + " \n " ;
2013-10-11 23:09:59 +02:00
}
if ( hmm = = HMM_BITCOIND )
{
2013-05-26 20:10:38 +02:00
# if !defined(WIN32)
strUsage + = " -daemon " + _ ( " Run in the background as a daemon and accept commands " ) + " \n " ;
2012-05-13 11:36:10 +02:00
# endif
2013-10-11 23:09:59 +02:00
}
if ( hmm = = HMM_BITCOIND | | hmm = = HMM_BITCOIN_CLI )
{
strUsage + = " -rpcconnect=<ip> " + _ ( " Send commands to node running on <ip> (default: 127.0.0.1) " ) + " \n " ;
}
2013-05-26 20:05:53 +02:00
strUsage + = " -rpcuser=<user> " + _ ( " Username for JSON-RPC connections " ) + " \n " ;
strUsage + = " -rpcpassword=<pw> " + _ ( " Password for JSON-RPC connections " ) + " \n " ;
2013-10-11 23:09:59 +02:00
if ( hmm = = HMM_BITCOIND | | hmm = = HMM_BITCOIN_QT )
{
strUsage + = " -rpcport=<port> " + _ ( " Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) " ) + " \n " ;
} else {
strUsage + = " -rpcport=<port> " + _ ( " Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332) " ) + " \n " ;
}
if ( hmm = = HMM_BITCOIND | | hmm = = HMM_BITCOIN_QT )
{
strUsage + = " -rpcallowip=<ip> " + _ ( " Allow JSON-RPC connections from specified IP address " ) + " \n " ;
strUsage + = " -rpcthreads=<n> " + _ ( " Set the number of threads to service RPC calls (default: 4) " ) + " \n " ;
strUsage + = " -blocknotify=<cmd> " + _ ( " Execute command when the best block changes (%s in cmd is replaced by block hash) " ) + " \n " ;
strUsage + = " -walletnotify=<cmd> " + _ ( " Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) " ) + " \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 + = " -upgradewallet " + _ ( " Upgrade wallet to latest format " ) + " \n " ;
strUsage + = " -keypool=<n> " + _ ( " Set key pool size to <n> (default: 100) " ) + " \n " ;
strUsage + = " -rescan " + _ ( " Rescan the block chain for missing wallet transactions " ) + " \n " ;
strUsage + = " -salvagewallet " + _ ( " Attempt to recover private keys from a corrupt wallet.dat " ) + " \n " ;
strUsage + = " -checkblocks=<n> " + _ ( " How many blocks to check at startup (default: 288, 0 = all) " ) + " \n " ;
strUsage + = " -checklevel=<n> " + _ ( " How thorough the block verification is (0-4, default: 3) " ) + " \n " ;
strUsage + = " -txindex " + _ ( " Maintain a full transaction index (default: 0) " ) + " \n " ;
strUsage + = " -loadblock=<file> " + _ ( " Imports blocks from external blk000??.dat file " ) + " \n " ;
strUsage + = " -reindex " + _ ( " Rebuild block chain index from current blk000??.dat files " ) + " \n " ;
strUsage + = " -par=<n> " + _ ( " Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) " ) + " \n " ;
strUsage + = " \n " + _ ( " Block creation options: " ) + " \n " ;
strUsage + = " -blockminsize=<n> " + _ ( " Set minimum block size in bytes (default: 0) " ) + " \n " ;
strUsage + = " -blockmaxsize=<n> " + _ ( " Set maximum block size in bytes (default: 250000) " ) + " \n " ;
strUsage + = " -blockprioritysize=<n> " + _ ( " Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) " ) + " \n " ;
}
2012-05-13 11:36:10 +02:00
2013-07-21 18:13:00 +02:00
strUsage + = " \n " + _ ( " SSL options: (see the Bitcoin Wiki for SSL setup instructions) " ) + " \n " ;
2013-05-26 20:05:53 +02:00
strUsage + = " -rpcssl " + _ ( " Use OpenSSL (https) for JSON-RPC connections " ) + " \n " ;
2013-10-11 23:09:59 +02:00
if ( hmm = = HMM_BITCOIND | | hmm = = HMM_BITCOIN_QT )
{
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 " ;
}
2012-05-13 11:36:10 +02:00
return strUsage ;
}
2012-10-22 22:45:26 +02:00
struct CImportingNow
{
CImportingNow ( ) {
assert ( fImporting = = false ) ;
fImporting = true ;
}
~ CImportingNow ( ) {
assert ( fImporting = = true ) ;
fImporting = false ;
}
} ;
2013-03-07 04:31:26 +01:00
void ThreadImport ( std : : vector < boost : : filesystem : : path > vImportFiles )
{
2012-10-22 22:45:26 +02:00
RenameThread ( " bitcoin-loadblk " ) ;
2012-10-21 21:23:13 +02:00
// -reindex
if ( fReindex ) {
CImportingNow imp ;
int nFile = 0 ;
2013-03-07 04:31:26 +01:00
while ( true ) {
2012-12-03 10:14:54 +01:00
CDiskBlockPos pos ( nFile , 0 ) ;
2012-10-21 21:23:13 +02:00
FILE * file = OpenBlockFile ( pos , true ) ;
if ( ! file )
break ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " Reindexing block file blk%05u.dat... \n " , ( unsigned int ) nFile ) ;
2012-10-21 21:23:13 +02:00
LoadExternalBlockFile ( file , & pos ) ;
nFile + + ;
}
2013-03-07 04:31:26 +01:00
pblocktree - > WriteReindexing ( false ) ;
fReindex = false ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " Reindexing finished \n " ) ;
2013-03-07 04:31:26 +01:00
// To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
InitBlockIndex ( ) ;
2012-10-22 22:45:26 +02:00
}
// hardcoded $DATADIR/bootstrap.dat
filesystem : : path pathBootstrap = GetDataDir ( ) / " bootstrap.dat " ;
2013-03-07 04:31:26 +01:00
if ( filesystem : : exists ( pathBootstrap ) ) {
2012-10-22 22:45:26 +02:00
FILE * file = fopen ( pathBootstrap . string ( ) . c_str ( ) , " rb " ) ;
if ( file ) {
2012-10-21 21:23:13 +02:00
CImportingNow imp ;
2012-10-22 22:45:26 +02:00
filesystem : : path pathBootstrapOld = GetDataDir ( ) / " bootstrap.dat.old " ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " Importing bootstrap.dat... \n " ) ;
2012-10-22 22:45:26 +02:00
LoadExternalBlockFile ( file ) ;
RenameOver ( pathBootstrap , pathBootstrapOld ) ;
}
}
2012-10-21 21:23:13 +02:00
// -loadblock=
2013-03-07 04:31:26 +01:00
BOOST_FOREACH ( boost : : filesystem : : path & path , vImportFiles ) {
2012-10-21 21:23:13 +02:00
FILE * file = fopen ( path . string ( ) . c_str ( ) , " rb " ) ;
if ( file ) {
CImportingNow imp ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " Importing %s... \n " , path . string ( ) . c_str ( ) ) ;
2012-10-21 21:23:13 +02:00
LoadExternalBlockFile ( file ) ;
}
}
2012-10-22 22:45:26 +02:00
}
2012-05-13 11:36:10 +02:00
/** Initialize bitcoin.
* @ pre Parameters should be parsed and config file should be read .
*/
2013-03-07 04:16:05 +01:00
bool AppInit2 ( boost : : thread_group & threadGroup )
2011-05-14 20:10:21 +02:00
{
2012-05-21 16:47:29 +02:00
// ********************************************************* Step 1: setup
2011-05-14 20:10:21 +02:00
# ifdef _MSC_VER
2012-07-26 02:48:39 +02:00
// Turn off Microsoft heap dump noise
2011-05-14 20:10:21 +02:00
_CrtSetReportMode ( _CRT_WARN , _CRTDBG_MODE_FILE ) ;
_CrtSetReportFile ( _CRT_WARN , CreateFileA ( " NUL " , GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ) ;
# endif
# if _MSC_VER >= 1400
2012-07-26 02:48:39 +02:00
// Disable confusing "helpful" text message on abort, Ctrl-C
2011-05-14 20:10:21 +02:00
_set_abort_behavior ( 0 , _WRITE_ABORT_MSG | _CALL_REPORTFAULT ) ;
# endif
2012-07-20 08:45:49 +02:00
# 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
2013-10-01 09:47:16 +02:00
// 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!
2012-07-20 08:45:49 +02:00
# 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 ) ;
2013-04-28 08:51:49 +02:00
// Initialize Windows Sockets
WSADATA wsadata ;
int ret = WSAStartup ( MAKEWORD ( 2 , 2 ) , & wsadata ) ;
2013-04-30 18:16:07 +02:00
if ( ret ! = NO_ERROR | | LOBYTE ( wsadata . wVersion ) ! = 2 | | HIBYTE ( wsadata . wVersion ) ! = 2 )
2013-04-28 08:51:49 +02:00
{
2013-04-30 18:16:07 +02:00
return InitError ( strprintf ( " Error: Winsock library failed to start (WSAStartup returned error %d) " , ret)) ;
2013-04-28 08:51:49 +02:00
}
2011-05-14 20:10:21 +02:00
# endif
2011-10-07 17:02:21 +02:00
# ifndef WIN32
2012-07-20 08:45:49 +02:00
umask ( 077 ) ;
2011-05-14 20:10:21 +02:00
// 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 ) ;
2012-03-02 20:31:16 +01:00
// 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 ) ;
2013-05-05 07:37:03 +02:00
# if defined (__SVR4) && defined (__sun)
// ignore SIGPIPE on Solaris
signal ( SIGPIPE , SIG_IGN ) ;
# endif
2011-05-14 20:10:21 +02:00
# endif
2012-05-21 16:47:29 +02:00
// ********************************************************* Step 2: parameter interactions
2012-05-24 19:02:21 +02:00
if ( mapArgs . count ( " -bind " ) ) {
// when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
2012-05-21 16:47:29 +02:00
SoftSetBoolArg ( " -listen " , true ) ;
2012-05-24 19:02:21 +02:00
}
2012-05-21 16:47:29 +02:00
2012-08-21 17:32:04 +02:00
if ( mapArgs . count ( " -connect " ) & & mapMultiArgs [ " -connect " ] . size ( ) > 0 ) {
2012-05-24 19:02:21 +02:00
// when only connecting to trusted nodes, do not seed via DNS, or listen by default
SoftSetBoolArg ( " -dnsseed " , false ) ;
SoftSetBoolArg ( " -listen " , false ) ;
}
if ( mapArgs . count ( " -proxy " ) ) {
// to protect privacy, do not listen by default if a proxy server is specified
2012-05-21 16:47:29 +02:00
SoftSetBoolArg ( " -listen " , false ) ;
2012-05-24 19:02:21 +02:00
}
2012-06-17 18:12:56 +02:00
if ( ! GetBoolArg ( " -listen " , true ) ) {
2012-05-24 19:02:21 +02:00
// do not map ports or try to retrieve public IP when not listening (pointless)
2012-05-21 16:47:29 +02:00
SoftSetBoolArg ( " -upnp " , false ) ;
SoftSetBoolArg ( " -discover " , false ) ;
}
2012-05-24 19:02:21 +02:00
if ( mapArgs . count ( " -externalip " ) ) {
// if an explicit public IP is specified, do not try to find others
SoftSetBoolArg ( " -discover " , false ) ;
}
2013-04-28 17:37:50 +02:00
if ( GetBoolArg ( " -salvagewallet " , false ) ) {
2012-09-18 20:30:47 +02:00
// Rewrite just private keys: rescan to find transactions
SoftSetBoolArg ( " -rescan " , true ) ;
}
2013-04-26 00:46:47 +02:00
// Make sure enough file descriptors are available
int nBind = std : : max ( ( int ) mapArgs . count ( " -bind " ) , 1 ) ;
nMaxConnections = GetArg ( " -maxconnections " , 125 ) ;
2013-05-24 15:40:51 +02:00
nMaxConnections = std : : max ( std : : min ( nMaxConnections , ( int ) ( FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS ) ) , 0 ) ;
2013-04-26 00:46:47 +02:00
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 ;
2012-05-21 16:47:29 +02:00
// ********************************************************* Step 3: parameter-to-internal-flags
2013-09-18 10:03:21 +02:00
if ( mapMultiArgs . count ( " -debug " ) ) fDebug = true ;
2013-04-28 17:37:50 +02:00
fBenchmark = GetBoolArg ( " -benchmark " , false ) ;
2013-08-03 13:08:34 +02:00
mempool . fChecks = GetBoolArg ( " -checkmempool " , RegTest ( ) ) ;
2013-08-25 13:25:21 +02:00
Checkpoints : : fEnabled = GetBoolArg ( " -checkpoints " , true ) ;
2012-06-22 19:11:57 +02:00
2012-12-01 23:04:14 +01:00
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
nScriptCheckThreads = GetArg ( " -par " , 0 ) ;
2013-04-29 19:35:47 +02:00
if ( nScriptCheckThreads < = 0 )
nScriptCheckThreads + = boost : : thread : : hardware_concurrency ( ) ;
2013-01-18 15:07:05 +01:00
if ( nScriptCheckThreads < = 1 )
2012-12-01 23:04:14 +01:00
nScriptCheckThreads = 0 ;
else if ( nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS )
nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS ;
2012-06-22 19:11:57 +02:00
// -debug implies fDebug*
if ( fDebug )
fDebugNet = true ;
else
2013-04-28 17:37:50 +02:00
fDebugNet = GetBoolArg ( " -debugnet " , false ) ;
2012-06-22 19:11:57 +02:00
2011-05-14 20:10:21 +02:00
if ( fDaemon )
fServer = true ;
else
2013-04-28 17:37:50 +02:00
fServer = GetBoolArg ( " -server " , false ) ;
2011-05-14 20:10:21 +02:00
/* force fServer when running without GUI */
2013-05-26 20:10:38 +02:00
if ( ! fHaveGUI )
fServer = true ;
2013-04-28 17:37:50 +02:00
fPrintToConsole = GetBoolArg ( " -printtoconsole " , false ) ;
fPrintToDebugger = GetBoolArg ( " -printtodebugger " , false ) ;
fLogTimestamps = GetBoolArg ( " -logtimestamps " , false ) ;
2011-05-14 20:10:21 +02:00
2012-05-21 16:47:29 +02:00
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 ) ) ;
2013-04-26 02:11:27 +02:00
// 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 ( " -mintxfee " ) )
{
int64 n = 0 ;
if ( ParseMoney ( mapArgs [ " -mintxfee " ] , n ) & & n > 0 )
CTransaction : : nMinTxFee = n ;
else
return InitError ( strprintf ( _ ( " Invalid amount for -mintxfee=<amount>: '%s' " ) , mapArgs [ " -mintxfee " ] . c_str ( ) ) ) ;
}
if ( mapArgs . count ( " -minrelaytxfee " ) )
{
int64 n = 0 ;
if ( ParseMoney ( mapArgs [ " -minrelaytxfee " ] , n ) & & n > 0 )
CTransaction : : nMinRelayTxFee = n ;
else
return InitError ( strprintf ( _ ( " Invalid amount for -minrelaytxfee=<amount>: '%s' " ) , mapArgs [ " -minrelaytxfee " ] . c_str ( ) ) ) ;
}
2012-05-21 16:47:29 +02:00
if ( mapArgs . count ( " -paytxfee " ) )
{
if ( ! ParseMoney ( mapArgs [ " -paytxfee " ] , nTransactionFee ) )
return InitError ( strprintf ( _ ( " Invalid amount for -paytxfee=<amount>: '%s' " ) , mapArgs [ " -paytxfee " ] . c_str ( ) ) ) ;
if ( nTransactionFee > 0.25 * COIN )
2012-07-27 08:36:43 +02:00
InitWarning ( _ ( " Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. " ) ) ;
2012-05-21 16:47:29 +02:00
}
2012-06-03 01:19:07 +02:00
strWalletFile = GetArg ( " -wallet " , " wallet.dat " ) ;
2012-05-21 16:47:29 +02:00
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
2012-10-12 03:09:05 +02:00
std : : string strDataDir = GetDataDir ( ) . string ( ) ;
2012-09-18 20:30:47 +02:00
2012-06-03 01:19:07 +02:00
// Wallet file must be a plain filename without a directory
if ( strWalletFile ! = boost : : filesystem : : basename ( strWalletFile ) + boost : : filesystem : : extension ( strWalletFile ) )
2013-08-06 10:28:52 +02:00
return InitError ( strprintf ( _ ( " Wallet %s resides outside data directory %s " ) , strWalletFile . c_str ( ) , strDataDir . c_str ( ) ) ) ;
2012-06-03 01:19:07 +02:00
2012-05-21 16:47:29 +02:00
// 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 ( ) )
2012-09-18 18:26:02 +02:00
return InitError ( strprintf ( _ ( " Cannot obtain a lock on data directory %s. Bitcoin is probably already running. " ) , strDataDir . c_str ( ) ) ) ;
2012-05-21 16:47:29 +02:00
2012-05-29 18:13:15 +02:00
if ( GetBoolArg ( " -shrinkdebugfile " , ! fDebug ) )
2011-05-14 20:10:21 +02:00
ShrinkDebugFile ( ) ;
2013-09-18 12:38:08 +02:00
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 ( ) . c_str ( ) , CLIENT_DATE . c_str ( ) ) ;
LogPrintf ( " Using OpenSSL version %s \n " , SSLeay_version ( SSLEAY_VERSION ) ) ;
2012-09-04 18:24:08 +02:00
if ( ! fLogTimestamps )
2013-09-18 12:38:08 +02:00
LogPrintf ( " Startup time: %s \n " , DateTimeStrFormat ( " %Y-%m-%d %H:%M:%S " , GetTime ( ) ) . c_str ( ) ) ;
LogPrintf ( " Default data directory %s \n " , GetDefaultDataDir ( ) . string ( ) . c_str ( ) ) ;
LogPrintf ( " Using data directory %s \n " , strDataDir . c_str ( ) ) ;
LogPrintf ( " Using at most %i connections (%i file descriptors available) \n " , nMaxConnections , nFD ) ;
2012-05-21 16:47:29 +02:00
std : : ostringstream strErrors ;
2011-05-14 20:10:21 +02:00
2012-05-21 16:47:29 +02:00
if ( fDaemon )
fprintf ( stdout , " Bitcoin server starting \n " ) ;
2012-12-01 23:04:14 +01:00
if ( nScriptCheckThreads ) {
2013-09-18 12:38:08 +02:00
LogPrintf ( " Using %u threads for script verification \n " , nScriptCheckThreads ) ;
2012-12-01 23:04:14 +01:00
for ( int i = 0 ; i < nScriptCheckThreads - 1 ; i + + )
2013-03-07 04:31:26 +01:00
threadGroup . create_thread ( & ThreadScriptCheck ) ;
2012-12-01 23:04:14 +01:00
}
2012-05-21 16:47:29 +02:00
int64 nStart ;
2013-01-11 23:18:00 +01:00
// ********************************************************* Step 5: verify wallet database integrity
2012-09-18 20:30:47 +02:00
2013-02-23 23:48:02 +01:00
uiInterface . InitMessage ( _ ( " Verifying wallet... " ) ) ;
2012-09-18 20:30:47 +02:00
if ( ! bitdb . Open ( GetDataDir ( ) ) )
{
2013-04-24 00:41:04 +02:00
// try moving the database env out of the way
boost : : filesystem : : path pathDatabase = GetDataDir ( ) / " database " ;
boost : : filesystem : : path pathDatabaseBak = GetDataDir ( ) / strprintf ( " database.% " PRI64d " .bak " , GetTime ( ) ) ;
try {
boost : : filesystem : : rename ( pathDatabase , pathDatabaseBak ) ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " Moved old %s to %s. Retrying. \n " , pathDatabase . string ( ) . c_str ( ) , pathDatabaseBak . string ( ) . c_str ( ) ) ;
2013-04-24 00:41:04 +02:00
} 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 . c_str ( ) ) ;
return InitError ( msg ) ;
}
2012-09-18 20:30:47 +02:00
}
2013-04-28 17:37:50 +02:00
if ( GetBoolArg ( " -salvagewallet " , false ) )
2012-09-18 20:30:47 +02:00
{
// Recover readable keypairs:
2012-06-03 01:19:07 +02:00
if ( ! CWalletDB : : Recover ( bitdb , strWalletFile , true ) )
2012-09-18 20:30:47 +02:00
return false ;
}
2012-06-03 01:19:07 +02:00
if ( filesystem : : exists ( GetDataDir ( ) / strWalletFile ) )
2012-09-18 20:30:47 +02:00
{
2012-06-03 01:19:07 +02:00
CDBEnv : : VerifyResult r = bitdb . Verify ( strWalletFile , CWalletDB : : Recover ) ;
2012-10-06 01:26:54 +02:00
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 "
2012-10-12 03:09:05 +02:00
" restore from a backup. " ) , strDataDir . c_str ( ) ) ;
2012-11-05 08:04:21 +01:00
InitWarning ( msg ) ;
2012-10-06 01:26:54 +02:00
}
if ( r = = CDBEnv : : RECOVER_FAIL )
return InitError ( _ ( " wallet.dat corrupt, salvage failed " ) ) ;
2012-09-18 20:30:47 +02:00
}
// ********************************************************* Step 6: network initialization
2012-05-21 16:47:29 +02:00
2013-06-06 05:21:41 +02:00
RegisterNodeSignals ( GetNodeSignals ( ) ) ;
2013-05-07 15:16:25 +02:00
2012-05-24 19:02:21 +02:00
int nSocksVersion = GetArg ( " -socks " , 5 ) ;
2012-05-21 16:47:29 +02:00
if ( nSocksVersion ! = 4 & & nSocksVersion ! = 5 )
return InitError ( strprintf ( _ ( " Unknown -socks proxy version requested: %i " ) , nSocksVersion ) ) ;
2011-05-14 20:10:21 +02:00
2012-05-21 16:47:29 +02:00
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 . c_str ( ) ) ) ;
nets . insert ( net ) ;
}
for ( int n = 0 ; n < NET_MAX ; n + + ) {
enum Network net = ( enum Network ) n ;
if ( ! nets . count ( net ) )
SetLimited ( net ) ;
}
}
2012-06-08 18:43:06 +02:00
# if defined(USE_IPV6)
# if ! USE_IPV6
else
SetLimited ( NET_IPV6 ) ;
# endif
# endif
2012-05-21 16:47:29 +02:00
2012-05-01 21:04:07 +02:00
CService addrProxy ;
bool fProxy = false ;
2012-05-24 19:02:21 +02:00
if ( mapArgs . count ( " -proxy " ) ) {
2012-05-01 21:04:07 +02:00
addrProxy = CService ( mapArgs [ " -proxy " ] , 9050 ) ;
2012-05-24 19:02:21 +02:00
if ( ! addrProxy . IsValid ( ) )
return InitError ( strprintf ( _ ( " Invalid -proxy address: '%s' " ) , mapArgs [ " -proxy " ] . c_str ( ) ) ) ;
if ( ! IsLimited ( NET_IPV4 ) )
SetProxy ( NET_IPV4 , addrProxy , nSocksVersion ) ;
if ( nSocksVersion > 4 ) {
# ifdef USE_IPV6
if ( ! IsLimited ( NET_IPV6 ) )
SetProxy ( NET_IPV6 , addrProxy , nSocksVersion ) ;
# endif
SetNameProxy ( addrProxy , nSocksVersion ) ;
}
2012-05-01 21:04:07 +02:00
fProxy = true ;
}
2013-09-08 13:54:06 +02:00
// -onion can override normal proxy, -noonion disables tor entirely
// -tor here is a temporary backwards compatibility measure
if ( mapArgs . count ( " -tor " ) )
printf ( " Notice: option -tor has been replaced with -onion and will be removed in a later version. \n " ) ;
if ( ! ( mapArgs . count ( " -onion " ) & & mapArgs [ " -onion " ] = = " 0 " ) & &
! ( mapArgs . count ( " -tor " ) & & mapArgs [ " -tor " ] = = " 0 " ) & &
( fProxy | | mapArgs . count ( " -onion " ) | | mapArgs . count ( " -tor " ) ) ) {
2012-05-01 21:04:07 +02:00
CService addrOnion ;
2013-09-08 13:54:06 +02:00
if ( ! mapArgs . count ( " -onion " ) & & ! mapArgs . count ( " -tor " ) )
2012-05-01 21:04:07 +02:00
addrOnion = addrProxy ;
else
2013-09-08 13:54:06 +02:00
addrOnion = mapArgs . count ( " -onion " ) ? CService ( mapArgs [ " -onion " ] , 9050 ) : CService ( mapArgs [ " -tor " ] , 9050 ) ;
2012-05-01 21:04:07 +02:00
if ( ! addrOnion . IsValid ( ) )
2013-09-08 13:54:06 +02:00
return InitError ( strprintf ( _ ( " Invalid -onion address: '%s' " ) , mapArgs . count ( " -onion " ) ? mapArgs [ " -onion " ] . c_str ( ) : mapArgs [ " -tor " ] . c_str ( ) ) ) ;
2012-05-01 21:04:07 +02:00
SetProxy ( NET_TOR , addrOnion , 5 ) ;
SetReachable ( NET_TOR ) ;
2012-05-24 19:02:21 +02:00
}
// see Step 2: parameter interactions for more information about these
fNoListen = ! GetBoolArg ( " -listen " , true ) ;
fDiscover = GetBoolArg ( " -discover " , true ) ;
fNameLookup = GetBoolArg ( " -dns " , true ) ;
2012-05-17 04:11:19 +02:00
2012-05-21 16:47:29 +02:00
bool fBound = false ;
2012-09-03 15:54:47 +02:00
if ( ! fNoListen ) {
2012-05-21 16:47:29 +02:00
if ( mapArgs . count ( " -bind " ) ) {
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 . c_str ( ) ) ) ;
2012-09-03 15:54:47 +02:00
fBound | = Bind ( addrBind , ( BF_EXPLICIT | BF_REPORT_ERROR ) ) ;
2012-05-21 16:47:29 +02:00
}
2012-09-03 15:54:47 +02:00
}
else {
2012-05-21 16:47:29 +02:00
struct in_addr inaddr_any ;
inaddr_any . s_addr = INADDR_ANY ;
# ifdef USE_IPV6
2012-09-03 15:54:47 +02:00
fBound | = Bind ( CService ( in6addr_any , GetListenPort ( ) ) , BF_NONE ) ;
2012-05-21 16:47:29 +02:00
# endif
2012-09-03 15:54:47 +02:00
fBound | = Bind ( CService ( inaddr_any , GetListenPort ( ) ) , ! fBound ? BF_REPORT_ERROR : BF_NONE ) ;
2012-05-21 16:47:29 +02:00
}
if ( ! fBound )
2012-05-24 19:02:21 +02:00
return InitError ( _ ( " Failed to listen on any port. Use -listen=0 if you want this. " ) ) ;
2012-05-17 04:11:19 +02:00
}
2012-09-03 15:54:47 +02:00
if ( mapArgs . count ( " -externalip " ) ) {
2012-05-21 16:47:29 +02:00
BOOST_FOREACH ( string strAddr , mapMultiArgs [ " -externalip " ] ) {
CService addrLocal ( strAddr , GetListenPort ( ) , fNameLookup ) ;
if ( ! addrLocal . IsValid ( ) )
return InitError ( strprintf ( _ ( " Cannot resolve -externalip address: '%s' " ) , strAddr . c_str ( ) ) ) ;
AddLocal ( CService ( strAddr , GetListenPort ( ) , fNameLookup ) , LOCAL_MANUAL ) ;
}
}
2012-05-24 19:02:21 +02:00
BOOST_FOREACH ( string strDest , mapMultiArgs [ " -seednode " ] )
AddOneShot ( strDest ) ;
2012-10-05 19:22:21 +02:00
// ********************************************************* Step 7: load block chain
2012-05-21 16:47:29 +02:00
2013-04-28 17:37:50 +02:00
fReindex = GetBoolArg ( " -reindex " , false ) ;
2012-10-21 21:23:13 +02:00
2012-12-12 22:11:52 +01:00
// 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 ) ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " Hardlinked %s -> %s \n " , source . string ( ) . c_str ( ) , dest . string ( ) . c_str ( ) ) ;
2012-12-12 22:11:52 +01:00
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.
2013-09-18 12:38:08 +02:00
LogPrintf ( " Error hardlinking blk%04u.dat : %s \n " , i , e . what ( ) ) ;
2012-12-12 22:11:52 +01:00
break ;
}
}
if ( linked )
{
fReindex = true ;
}
}
2012-11-04 17:11:48 +01:00
// cache size calculations
size_t nTotalCache = GetArg ( " -dbcache " , 25 ) < < 20 ;
if ( nTotalCache < ( 1 < < 22 ) )
nTotalCache = ( 1 < < 22 ) ; // total cache cannot be less than 4 MiB
size_t nBlockTreeDBCache = nTotalCache / 8 ;
2013-01-11 01:47:57 +01:00
if ( nBlockTreeDBCache > ( 1 < < 21 ) & & ! GetBoolArg ( " -txindex " , false ) )
2012-11-04 17:11:48 +01:00
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
2013-02-16 17:58:45 +01:00
bool fLoaded = false ;
while ( ! fLoaded ) {
bool fReset = fReindex ;
std : : string strLoadError ;
2013-01-11 22:57:22 +01:00
2013-02-16 17:58:45 +01:00
uiInterface . InitMessage ( _ ( " Loading block index... " ) ) ;
2012-07-06 16:33:34 +02:00
2013-02-16 17:58:45 +01:00
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 ;
}
2013-05-12 12:03:32 +02:00
// If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around).
2013-10-10 23:07:44 +02:00
if ( ! mapBlockIndex . empty ( ) & & chainActive . Genesis ( ) = = NULL )
2013-05-12 12:03:32 +02:00
return InitError ( _ ( " Incorrect or no genesis block found. Wrong datadir for network? " ) ) ;
2013-02-16 17:58:45 +01:00
// Initialize the block index (no-op if non-empty database was already loaded)
if ( ! InitBlockIndex ( ) ) {
strLoadError = _ ( " Error initializing block database " ) ;
break ;
}
2013-06-22 16:03:11 +02:00
// Check for changed -txindex state
if ( fTxIndex ! = GetBoolArg ( " -txindex " , false ) ) {
strLoadError = _ ( " You need to rebuild the database using -reindex to change -txindex " ) ;
break ;
}
2013-02-23 23:48:02 +01:00
uiInterface . InitMessage ( _ ( " Verifying blocks... " ) ) ;
2013-06-19 17:32:49 +02:00
if ( ! VerifyDB ( GetArg ( " -checklevel " , 3 ) ,
2013-08-31 01:11:12 +02:00
GetArg ( " -checkblocks " , 288 ) ) ) {
2013-02-16 17:58:45 +01:00
strLoadError = _ ( " Corrupted block database detected " ) ;
break ;
}
} catch ( std : : exception & e ) {
2013-09-18 12:38:08 +02:00
if ( fDebug ) LogPrintf ( " %s \n " , e . what ( ) ) ;
2013-02-16 17:58:45 +01:00
strLoadError = _ ( " Error opening block database " ) ;
break ;
}
2013-01-03 15:29:07 +01:00
2013-02-16 17:58:45 +01:00
fLoaded = true ;
} while ( false ) ;
if ( ! fLoaded ) {
// first suggest a reindex
if ( ! fReset ) {
bool fRet = uiInterface . ThreadSafeMessageBox (
2013-05-13 08:26:29 +02:00
strLoadError + " . \n \n " + _ ( " Do you want to rebuild the block database now? " ) ,
2013-02-16 17:58:45 +01:00
" " , CClientUIInterface : : MSG_ERROR | CClientUIInterface : : BTN_ABORT ) ;
if ( fRet ) {
fReindex = true ;
fRequestShutdown = false ;
} else {
2013-09-18 12:38:08 +02:00
LogPrintf ( " Aborted block database rebuild. Exiting. \n " ) ;
2013-02-16 17:58:45 +01:00
return false ;
}
} else {
return InitError ( strLoadError ) ;
}
}
}
2012-04-18 13:30:24 +02:00
// as LoadBlockIndex can take several minutes, it's possible the user
// requested to kill bitcoin-qt during the last operation. If so, exit.
// As the program has not fully started yet, Shutdown() is possibly overkill.
if ( fRequestShutdown )
{
2013-09-18 12:38:08 +02:00
LogPrintf ( " Shutdown requested. Exiting. \n " ) ;
2012-04-18 13:30:24 +02:00
return false ;
}
2013-09-18 12:38:08 +02:00
LogPrintf ( " block index %15 " PRI64d " ms \n " , GetTimeMillis ( ) - nStart ) ;
2011-05-14 20:10:21 +02:00
2013-04-28 17:37:50 +02:00
if ( GetBoolArg ( " -printblockindex " , false ) | | GetBoolArg ( " -printblocktree " , false ) )
2012-02-20 20:50:26 +01:00
{
2012-05-21 16:47:29 +02:00
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 )
2012-02-20 20:50:26 +01:00
{
2012-05-21 16:47:29 +02:00
uint256 hash = ( * mi ) . first ;
if ( strncmp ( hash . ToString ( ) . c_str ( ) , strMatch . c_str ( ) , strMatch . size ( ) ) = = 0 )
{
CBlockIndex * pindex = ( * mi ) . second ;
CBlock block ;
2013-06-24 03:10:02 +02:00
ReadBlockFromDisk ( block , pindex ) ;
2012-05-21 16:47:29 +02:00
block . BuildMerkleTree ( ) ;
block . print ( ) ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " \n " ) ;
2012-05-21 16:47:29 +02:00
nFound + + ;
}
2012-02-20 20:50:26 +01:00
}
2012-05-21 16:47:29 +02:00
if ( nFound = = 0 )
2013-09-18 12:38:08 +02:00
LogPrintf ( " No blocks matching %s were found \n " , strMatch . c_str ( ) ) ;
2012-05-21 16:47:29 +02:00
return false ;
2012-02-20 20:50:26 +01:00
}
2012-09-18 20:30:47 +02:00
// ********************************************************* Step 8: load wallet
2012-05-21 16:47:29 +02:00
2012-05-06 19:40:58 +02:00
uiInterface . InitMessage ( _ ( " Loading wallet... " ) ) ;
2013-01-11 22:57:22 +01:00
2011-05-14 20:10:21 +02:00
nStart = GetTimeMillis ( ) ;
2012-09-04 18:24:08 +02:00
bool fFirstRun = true ;
2012-06-03 01:19:07 +02:00
pwalletMain = new CWallet ( strWalletFile ) ;
2012-09-18 20:30:47 +02:00
DBErrors nLoadWalletRet = pwalletMain - > LoadWallet ( fFirstRun ) ;
2011-07-05 03:06:19 +02:00
if ( nLoadWalletRet ! = DB_LOAD_OK )
{
if ( nLoadWalletRet = = DB_CORRUPT )
2011-12-16 23:13:45 +01:00
strErrors < < _ ( " Error loading wallet.dat: Wallet corrupted " ) < < " \n " ;
2012-09-18 20:30:47 +02:00
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. " ) ) ;
2012-11-05 08:04:21 +01:00
InitWarning ( msg ) ;
2012-09-18 20:30:47 +02:00
}
2011-07-05 03:06:19 +02:00
else if ( nLoadWalletRet = = DB_TOO_NEW )
2011-12-16 23:13:45 +01:00
strErrors < < _ ( " Error loading wallet.dat: Wallet requires newer version of Bitcoin " ) < < " \n " ;
2011-11-11 03:12:46 +01:00
else if ( nLoadWalletRet = = DB_NEED_REWRITE )
{
2011-12-16 23:13:45 +01:00
strErrors < < _ ( " Wallet needed to be rewritten: restart Bitcoin to complete " ) < < " \n " ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " %s " , strErrors . str ( ) . c_str ( ) ) ;
2012-05-13 12:35:39 +02:00
return InitError ( strErrors . str ( ) ) ;
2011-11-11 03:12:46 +01:00
}
2011-07-05 03:06:19 +02:00
else
2011-12-16 23:13:45 +01:00
strErrors < < _ ( " Error loading wallet.dat " ) < < " \n " ;
2011-07-05 03:06:19 +02:00
}
2012-03-22 03:56:31 +01:00
if ( GetBoolArg ( " -upgradewallet " , fFirstRun ) )
{
int nMaxVersion = GetArg ( " -upgradewallet " , 0 ) ;
2012-06-24 18:08:27 +02:00
if ( nMaxVersion = = 0 ) // the -upgradewallet without argument case
2012-03-22 03:56:31 +01:00
{
2013-09-18 12:38:08 +02:00
LogPrintf ( " Performing wallet upgrade to %i \n " , FEATURE_LATEST ) ;
2012-03-22 03:56:31 +01:00
nMaxVersion = CLIENT_VERSION ;
pwalletMain - > SetMinVersion ( FEATURE_LATEST ) ; // permanently upgrade the wallet immediately
}
else
2013-09-18 12:38:08 +02:00
LogPrintf ( " Allowing wallet upgrade up to %i \n " , nMaxVersion ) ;
2012-03-22 03:56:31 +01:00
if ( nMaxVersion < pwalletMain - > GetVersion ( ) )
strErrors < < _ ( " Cannot downgrade wallet " ) < < " \n " ;
pwalletMain - > SetMaxVersion ( nMaxVersion ) ;
}
if ( fFirstRun )
{
// Create new keyUser and set as default key
RandAddSeedPerfmon ( ) ;
2012-05-14 19:07:52 +02:00
CPubKey newDefaultKey ;
2013-08-23 21:54:50 +02:00
if ( pwalletMain - > GetKeyFromPool ( newDefaultKey ) ) {
2013-04-25 19:30:28 +02:00
pwalletMain - > SetDefaultKey ( newDefaultKey ) ;
2013-07-22 08:50:39 +02:00
if ( ! pwalletMain - > SetAddressBook ( pwalletMain - > vchDefaultKey . GetID ( ) , " " , " receive " ) )
2013-04-25 19:30:28 +02:00
strErrors < < _ ( " Cannot write default address " ) < < " \n " ;
}
2013-05-22 20:58:53 +02:00
2013-10-12 15:18:08 +02:00
pwalletMain - > SetBestChain ( chainActive . GetLocator ( ) ) ;
2012-03-22 03:56:31 +01:00
}
2013-09-18 12:38:08 +02:00
LogPrintf ( " %s " , strErrors . str ( ) . c_str ( ) ) ;
LogPrintf ( " wallet %15 " PRI64d " ms \n " , GetTimeMillis ( ) - nStart ) ;
2011-05-14 20:10:21 +02:00
2011-06-26 19:23:24 +02:00
RegisterWallet ( pwalletMain ) ;
2013-10-10 23:07:44 +02:00
CBlockIndex * pindexRescan = chainActive . Tip ( ) ;
2013-04-28 17:37:50 +02:00
if ( GetBoolArg ( " -rescan " , false ) )
2013-10-10 23:07:44 +02:00
pindexRescan = chainActive . Genesis ( ) ;
2011-05-14 20:10:21 +02:00
else
{
2012-06-03 01:19:07 +02:00
CWalletDB walletdb ( strWalletFile ) ;
2011-05-14 20:10:21 +02:00
CBlockLocator locator ;
if ( walletdb . ReadBestBlock ( locator ) )
2013-10-12 15:18:08 +02:00
pindexRescan = chainActive . FindFork ( locator ) ;
2013-05-01 19:09:04 +02:00
else
2013-10-10 23:07:44 +02:00
pindexRescan = chainActive . Genesis ( ) ;
2011-05-14 20:10:21 +02:00
}
2013-10-10 23:07:44 +02:00
if ( chainActive . Tip ( ) & & chainActive . Tip ( ) ! = pindexRescan )
2011-05-14 20:10:21 +02:00
{
2012-05-06 19:40:58 +02:00
uiInterface . InitMessage ( _ ( " Rescanning... " ) ) ;
2013-10-10 23:07:44 +02:00
LogPrintf ( " Rescanning last %i blocks (from block %i)... \n " , chainActive . Height ( ) - pindexRescan - > nHeight , pindexRescan - > nHeight ) ;
2011-05-14 20:10:21 +02:00
nStart = GetTimeMillis ( ) ;
2011-06-26 19:23:24 +02:00
pwalletMain - > ScanForWalletTransactions ( pindexRescan , true ) ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " rescan %15 " PRI64d " ms \n " , GetTimeMillis ( ) - nStart ) ;
2013-10-12 15:18:08 +02:00
pwalletMain - > SetBestChain ( chainActive . GetLocator ( ) ) ;
2013-05-01 19:09:04 +02:00
nWalletDBUpdated + + ;
2011-05-14 20:10:21 +02:00
}
2012-09-18 20:30:47 +02:00
// ********************************************************* Step 9: import blocks
2012-01-03 16:14:22 +01:00
2012-08-10 15:13:57 +02:00
// scan for better chains in the block chain database, that are not yet connected in the active best chain
2013-01-27 00:14:11 +01:00
CValidationState state ;
if ( ! ConnectBestBlock ( state ) )
2012-08-19 00:33:01 +02:00
strErrors < < " Failed to connect best block " ;
2012-08-10 15:13:57 +02:00
2013-03-07 04:31:26 +01:00
std : : vector < boost : : filesystem : : path > vImportFiles ;
2012-05-21 16:47:29 +02:00
if ( mapArgs . count ( " -loadblock " ) )
2011-05-14 20:10:21 +02:00
{
2012-05-21 16:47:29 +02:00
BOOST_FOREACH ( string strFile , mapMultiArgs [ " -loadblock " ] )
2013-03-07 04:31:26 +01:00
vImportFiles . push_back ( strFile ) ;
2012-09-24 19:37:03 +02:00
}
2013-03-07 04:31:26 +01:00
threadGroup . create_thread ( boost : : bind ( & ThreadImport , vImportFiles ) ) ;
2012-09-24 19:37:03 +02:00
2012-09-18 20:30:47 +02:00
// ********************************************************* Step 10: load peers
2012-01-03 16:14:22 +01:00
2012-05-21 16:47:29 +02:00
uiInterface . InitMessage ( _ ( " Loading addresses... " ) ) ;
2013-01-11 22:57:22 +01:00
2012-05-21 16:47:29 +02:00
nStart = GetTimeMillis ( ) ;
2012-02-06 21:48:00 +01:00
2012-01-03 16:14:22 +01:00
{
2012-05-21 16:47:29 +02:00
CAddrDB adb ;
if ( ! adb . Read ( addrman ) )
2013-09-18 12:38:08 +02:00
LogPrintf ( " Invalid or missing peers.dat; recreating \n " ) ;
2012-01-03 16:14:22 +01:00
}
2013-09-18 12:38:08 +02:00
LogPrintf ( " Loaded %i addresses from peers.dat % " PRI64d " ms \n " ,
2012-05-21 16:47:29 +02:00
addrman . size ( ) , GetTimeMillis ( ) - nStart ) ;
2011-05-14 20:10:21 +02:00
2012-09-18 20:30:47 +02:00
// ********************************************************* Step 11: start node
2011-05-14 20:10:21 +02:00
if ( ! CheckDiskSpace ( ) )
return false ;
2013-05-02 18:26:33 +02:00
if ( ! strErrors . str ( ) . empty ( ) )
return InitError ( strErrors . str ( ) ) ;
2011-05-14 20:10:21 +02:00
RandAddSeedPerfmon ( ) ;
2012-05-21 16:47:29 +02:00
//// debug print
2013-09-18 12:38:08 +02:00
LogPrintf ( " mapBlockIndex.size() = % " PRIszu " \n " , mapBlockIndex . size ( ) ) ;
2013-10-10 23:07:44 +02:00
LogPrintf ( " nBestHeight = %d \n " , chainActive . Height ( ) ) ;
2013-08-25 06:00:02 +02:00
LogPrintf ( " setKeyPool.size() = % " PRIszu " \n " , pwalletMain ? pwalletMain - > setKeyPool . size ( ) : 0 ) ;
LogPrintf ( " mapWallet.size() = % " PRIszu " \n " , pwalletMain ? pwalletMain - > mapWallet . size ( ) : 0 ) ;
LogPrintf ( " mapAddressBook.size() = % " PRIszu " \n " , pwalletMain ? pwalletMain - > mapAddressBook . size ( ) : 0 ) ;
2012-05-21 16:47:29 +02:00
2013-03-09 18:02:57 +01:00
StartNode ( threadGroup ) ;
2011-05-14 20:10:21 +02:00
2013-05-30 15:51:41 +02:00
// InitRPCMining is needed here so getwork/getblocktemplate in the GUI debug console works properly.
InitRPCMining ( ) ;
2011-05-14 20:10:21 +02:00
if ( fServer )
2013-03-07 04:31:26 +01:00
StartRPCThreads ( ) ;
2011-05-14 20:10:21 +02:00
2013-03-31 07:54:27 +02:00
// Generate coins in the background
2013-08-25 06:00:02 +02:00
if ( pwalletMain )
GenerateBitcoins ( GetBoolArg ( " -gen " , false ) , pwalletMain ) ;
2013-03-31 07:54:27 +02:00
2012-09-18 20:30:47 +02:00
// ********************************************************* Step 12: finished
2012-05-21 16:47:29 +02:00
uiInterface . InitMessage ( _ ( " Done loading " ) ) ;
2013-08-25 06:00:02 +02:00
if ( pwalletMain ) {
// Add wallet transactions that aren't already in a block to mapTransactions
pwalletMain - > ReacceptWalletTransactions ( ) ;
2012-05-21 16:47:29 +02:00
2013-08-25 06:00:02 +02:00
// Run a thread to flush wallet periodically
threadGroup . create_thread ( boost : : bind ( & ThreadFlushWalletDB , boost : : ref ( pwalletMain - > strWalletFile ) ) ) ;
}
2011-05-14 20:10:21 +02:00
2013-03-09 18:02:57 +01:00
return ! fRequestShutdown ;
2011-05-14 20:10:21 +02:00
}