diff options
| author | Max K <[email protected]> | 2019-06-20 14:58:05 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2019-06-20 14:58:05 +0200 |
| commit | 458b4a7ee93b0f8c94c7a5de0c110bfda2335d6c (patch) | |
| tree | 624ce269edf96c4a4e840540d894d056676bce7f /src/init.cpp | |
| parent | Revert "Change fPIE to fPIC (#1420)" (#1447) (diff) | |
| parent | Update issue template (diff) | |
| download | discoin-458b4a7ee93b0f8c94c7a5de0c110bfda2335d6c.tar.xz discoin-458b4a7ee93b0f8c94c7a5de0c110bfda2335d6c.zip | |
Merge pull request #1587 from langerhans/masterv1.14.0
Merge 1.14 into master
Diffstat (limited to 'src/init.cpp')
| -rw-r--r-- | src/init.cpp | 1449 |
1 files changed, 825 insertions, 624 deletions
diff --git a/src/init.cpp b/src/init.cpp index 1bf6f28ed..0b7777fa0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,35 +11,49 @@ #include "addrman.h" #include "amount.h" +#include "chain.h" +#include "chainparams.h" #include "checkpoints.h" #include "compat/sanity.h" #include "consensus/validation.h" +#include "httpserver.h" +#include "httprpc.h" #include "key.h" -#include "main.h" +#include "validation.h" #include "miner.h" +#include "netbase.h" #include "net.h" -#include "rpcserver.h" +#include "net_processing.h" +#include "policy/policy.h" +#include "rpc/server.h" +#include "rpc/register.h" #include "script/standard.h" +#include "script/sigcache.h" #include "scheduler.h" +#include "timedata.h" #include "txdb.h" +#include "txmempool.h" +#include "torcontrol.h" #include "ui_interface.h" #include "util.h" #include "utilmoneystr.h" #include "validationinterface.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" -#include "wallet/walletdb.h" #endif - +#include "warnings.h" #include <stdint.h> #include <stdio.h> +#include <memory> #ifndef WIN32 #include <signal.h> #endif +#include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/replace.hpp> +#include <boost/algorithm/string/split.hpp> #include <boost/bind.hpp> #include <boost/filesystem.hpp> #include <boost/function.hpp> @@ -48,12 +62,22 @@ #include <boost/thread.hpp> #include <openssl/crypto.h> -using namespace std; - -#ifdef ENABLE_WALLET -CWallet* pwalletMain = NULL; +#if ENABLE_ZMQ +#include "zmq/zmqnotificationinterface.h" #endif + bool fFeeEstimatesInitialized = false; +static const bool DEFAULT_PROXYRANDOMIZE = true; +static const bool DEFAULT_REST_ENABLE = false; +static const bool DEFAULT_DISABLE_SAFEMODE = false; +static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; + +std::unique_ptr<CConnman> g_connman; +std::unique_ptr<PeerLogicValidation> peerLogic; + +#if ENABLE_ZMQ +static CZMQNotificationInterface* pzmqNotificationInterface = NULL; +#endif #ifdef WIN32 // Win32 LevelDB doesn't use filedescriptors, and the ones used for @@ -73,7 +97,6 @@ enum BindFlags { }; static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; -CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h ////////////////////////////////////////////////////////////////////////////// // @@ -105,7 +128,8 @@ CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h // shutdown thing. // -volatile bool fRequestShutdown = false; +std::atomic<bool> fRequestShutdown(false); +std::atomic<bool> fDumpMempoolLater(false); void StartShutdown() { @@ -116,6 +140,11 @@ bool ShutdownRequested() return fRequestShutdown; } +/** + * This is a minimally invasive approach to shutdown on LevelDB read errors from the + * chainstate, while keeping user interface out of the common library, which is shared + * between bitcoind, and bitcoin-qt and non-server tools. +*/ class CCoinsViewErrorCatcher : public CCoinsViewBacked { public: @@ -138,6 +167,19 @@ public: static CCoinsViewDB *pcoinsdbview = NULL; static CCoinsViewErrorCatcher *pcoinscatcher = NULL; +static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; + +void Interrupt(boost::thread_group& threadGroup) +{ + InterruptHTTPServer(); + InterruptHTTPRPC(); + InterruptRPC(); + InterruptREST(); + InterruptTorControl(); + if (g_connman) + g_connman->Interrupt(); + threadGroup.interrupt_all(); +} void Shutdown() { @@ -153,14 +195,25 @@ void Shutdown() /// module was initialized. RenameThread("dogecoin-shutoff"); mempool.AddTransactionsUpdated(1); - StopRPCThreads(); + + StopHTTPRPC(); + StopREST(); + StopRPC(); + StopHTTPServer(); #ifdef ENABLE_WALLET + // Dogecoin 1.14 TODO: ShutdownRPCMining(); if (pwalletMain) pwalletMain->Flush(false); - GenerateBitcoins(false, NULL, 0); #endif - StopNode(); + MapPort(false); + UnregisterValidationInterface(peerLogic.get()); + peerLogic.reset(); + g_connman.reset(); + + StopTorControl(); UnregisterNodeSignals(GetNodeSignals()); + if (fDumpMempoolLater) + DumpMempool(); if (fFeeEstimatesInitialized) { @@ -191,6 +244,15 @@ void Shutdown() if (pwalletMain) pwalletMain->Flush(true); #endif + +#if ENABLE_ZMQ + if (pzmqNotificationInterface) { + UnregisterValidationInterface(pzmqNotificationInterface); + delete pzmqNotificationInterface; + pzmqNotificationInterface = NULL; + } +#endif + #ifndef WIN32 try { boost::filesystem::remove(GetPidFile()); @@ -203,6 +265,7 @@ void Shutdown() delete pwalletMain; pwalletMain = NULL; #endif + globalVerifyHandle.reset(); ECC_Stop(); LogPrintf("%s: done\n", __func__); } @@ -220,32 +283,26 @@ 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) { +bool static Bind(CConnman& connman, const CService &addr, unsigned int flags) { if (!(flags & BF_EXPLICIT) && IsLimited(addr)) return false; std::string strError; - if (!BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) { + if (!connman.BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) { if (flags & BF_REPORT_ERROR) return InitError(strError); return false; } return true; } +void OnRPCStarted() +{ + uiInterface.NotifyBlockTip.connect(&RPCNotifyBlockChange); +} void OnRPCStopped() { + uiInterface.NotifyBlockTip.disconnect(&RPCNotifyBlockChange); + RPCNotifyBlockChange(false, nullptr); cvBlockChange.notify_all(); LogPrint("rpc", "RPC stopped.\n"); } @@ -253,10 +310,10 @@ void OnRPCStopped() void OnRPCPreCommand(const CRPCCommand& cmd) { // Observe safe mode - string strWarning = GetWarnings("rpc"); - if (strWarning != "" && !GetBoolArg("-disablesafemode", false) && + std::string strWarning = GetWarnings("rpc"); + if (strWarning != "" && !GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE) && !cmd.okSafeMode) - throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning); + throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + strWarning); } std::string HelpMessage(HelpMessageMode mode) @@ -264,184 +321,187 @@ std::string HelpMessage(HelpMessageMode mode) const bool showDebug = GetBoolArg("-help-debug", false); // When adding new options to the categories, please keep and ensure alphabetical ordering. - // Do not translate _(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators - - string strUsage = HelpMessageGroup(_("Options:")); - strUsage += HelpMessageOpt("-?", _("This help message")); + // Do not translate _(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators. + std::string strUsage = HelpMessageGroup(_("Options:")); + strUsage += HelpMessageOpt("-?", _("Print this help message and exit")); + strUsage += HelpMessageOpt("-version", _("Print version and exit")); strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS)); strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)")); strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash, %i is replaced by block number)")); - strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 288)); - strUsage += HelpMessageOpt("-checklevel=<n>", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), 3)); - strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), "dogecoin.conf")); + if (showDebug) + strUsage += HelpMessageOpt("-blocksonly", strprintf(_("Whether to operate in a blocks only mode (default: %u)"), DEFAULT_BLOCKSONLY)); + strUsage +=HelpMessageOpt("-assumevalid=<hex>", strprintf(_("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)"), Params(CBaseChainParams::MAIN).GetConsensus(0).defaultAssumeValid.GetHex(), Params(CBaseChainParams::TESTNET).GetConsensus(0).defaultAssumeValid.GetHex())); + strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME)); if (mode == HMM_BITCOIND) { -#if !defined(WIN32) +#if HAVE_DECL_DAEMON strUsage += HelpMessageOpt("-daemon", _("Run in the background as a daemon and accept commands")); #endif } strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory")); strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache)); - strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file") + " " + _("on startup")); + if (showDebug) + strUsage += HelpMessageOpt("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER)); + strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file on startup")); strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS)); + strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE)); + strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf(_("Do not keep transactions in the mempool longer than <n> hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY)); + strUsage += HelpMessageOpt("-blockreconstructionextratxn=<n>", strprintf(_("Extra transactions to keep in memory for compact block reconstructions (default: %u)"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN)); strUsage += HelpMessageOpt("-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)); + -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS)); #ifndef WIN32 - strUsage += HelpMessageOpt("-pid=<file>", strprintf(_("Specify pid file (default: %s)"), "dogecoind.pid")); + strUsage += HelpMessageOpt("-pid=<file>", strprintf(_("Specify pid file (default: %s)"), BITCOIN_PID_FILENAME)); #endif - strUsage += HelpMessageOpt("-prune=<n>", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. " + strUsage += HelpMessageOpt("-prune=<n>", strprintf(_("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. " "Warning: Reverting this setting requires re-downloading the entire blockchain. " - "(default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); - strUsage += HelpMessageOpt("-reindex", _("Rebuild block chain index from current blk000??.dat files on startup")); -#if !defined(WIN32) + "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >%u = automatically prune block files to stay under the specified target size in MiB)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); + strUsage += HelpMessageOpt("-reindex-chainstate", _("Rebuild chain state from the currently indexed blocks")); + strUsage += HelpMessageOpt("-reindex", _("Rebuild chain state and block index from the blk*.dat files on disk")); +#ifndef WIN32 strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)")); #endif - strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), 0)); + strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), DEFAULT_TXINDEX)); strUsage += HelpMessageGroup(_("Connection options:")); strUsage += HelpMessageOpt("-addnode=<ip>", _("Add a node to connect to and attempt to keep the connection open")); - strUsage += HelpMessageOpt("-banscore=<n>", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), 100)); - strUsage += HelpMessageOpt("-bantime=<n>", strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), 86400)); + strUsage += HelpMessageOpt("-banscore=<n>", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), DEFAULT_BANSCORE_THRESHOLD)); + strUsage += HelpMessageOpt("-bantime=<n>", strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), DEFAULT_MISBEHAVING_BANTIME)); strUsage += HelpMessageOpt("-bind=<addr>", _("Bind to given address and always listen on it. Use [host]:port notation for IPv6")); - strUsage += HelpMessageOpt("-connect=<ip>", _("Connect only to the specified node(s)")); + strUsage += HelpMessageOpt("-connect=<ip>", _("Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections")); strUsage += HelpMessageOpt("-discover", _("Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)")); - strUsage += HelpMessageOpt("-dns", _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + _("(default: 1)")); - strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)")); + strUsage += HelpMessageOpt("-dns", _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + strprintf(_("(default: %u)"), DEFAULT_NAME_LOOKUP)); + strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)")); strUsage += HelpMessageOpt("-externalip=<ip>", _("Specify your own public address")); - strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), 0)); - strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)")); - strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(_("Maintain at most <n> connections to peers (default: %u)"), 125)); - strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), 5000)); - strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf(_("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), 1000)); + strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), DEFAULT_FORCEDNSSEED)); + strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)")); + strUsage += HelpMessageOpt("-listenonion", strprintf(_("Automatically create Tor hidden service (default: %d)"), DEFAULT_LISTEN_ONION)); + strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(_("Maintain at most <n> connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS)); + strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXRECEIVEBUFFER)); + strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf(_("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXSENDBUFFER)); + strUsage += HelpMessageOpt("-maxtimeadjustment", strprintf(_("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)"), DEFAULT_MAX_TIME_ADJUSTMENT)); strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy")); strUsage += HelpMessageOpt("-onlynet=<net>", _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)")); - strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), 1)); - strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), 22556, 44556)); + strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), DEFAULT_PERMIT_BAREMULTISIG)); + strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with bloom filters (default: %u)"), DEFAULT_PEERBLOOMFILTERS)); + strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort())); strUsage += HelpMessageOpt("-proxy=<ip:port>", _("Connect through SOCKS5 proxy")); - strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), 1)); + strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE)); + strUsage += HelpMessageOpt("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION)); strUsage += HelpMessageOpt("-seednode=<ip>", _("Connect to a node to retrieve peer addresses, and disconnect")); strUsage += HelpMessageOpt("-timeout=<n>", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT)); - strUsage += HelpMessageOpt("-bloomfilters", _("Allow peers to set bloom filters (default: 1)")); + strUsage += HelpMessageOpt("-torcontrol=<ip>:<port>", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL)); + strUsage += HelpMessageOpt("-torpassword=<pass>", _("Tor control port password (default: empty)")); #ifdef USE_UPNP #if USE_UPNP - strUsage += HelpMessageOpt("-upnp", _("Use UPnP to map the listening port (default: 1 when listening)")); + strUsage += HelpMessageOpt("-upnp", _("Use UPnP to map the listening port (default: 1 when listening and no -proxy)")); #else strUsage += HelpMessageOpt("-upnp", strprintf(_("Use UPnP to map the listening port (default: %u)"), 0)); #endif #endif strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6")); - strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") + + strUsage += HelpMessageOpt("-whitelist=<IP address or network>", _("Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.") + " " + _("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")); - + strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY)); + strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY)); + strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET)); #ifdef ENABLE_WALLET - strUsage += HelpMessageGroup(_("Wallet options:")); - strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); - strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), 100)); - if (showDebug) - strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf("Fees (in DOGE/Kb) smaller than this are considered zero fee for transaction creation (default: %s)", - FormatMoney(CWallet::minTxFee.GetFeePerK()))); - strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in DOGE/kB) to add to transactions you send (default: %s)"), FormatMoney(payTxFee.GetFeePerK()))); - strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions") + " " + _("on startup")); - strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup")); - strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0)); - strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1)); - // Dogecoin: Disable TX confirm target as the dust prevention fees make - // the fee estimation code produce bizarre results. - // strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET)); - strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)"), - FormatMoney(maxTxFee))); - strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format") + " " + _("on startup")); - strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat")); - strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), true)); - strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); - strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") + - " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)")); + strUsage += CWallet::GetWalletHelpString(showDebug); +#endif +#if ENABLE_ZMQ + strUsage += HelpMessageGroup(_("ZeroMQ notification options:")); + strUsage += HelpMessageOpt("-zmqpubhashblock=<address>", _("Enable publish hash block in <address>")); + strUsage += HelpMessageOpt("-zmqpubhashtx=<address>", _("Enable publish hash transaction in <address>")); + strUsage += HelpMessageOpt("-zmqpubrawblock=<address>", _("Enable publish raw block in <address>")); + strUsage += HelpMessageOpt("-zmqpubrawtx=<address>", _("Enable publish raw transaction in <address>")); #endif strUsage += HelpMessageGroup(_("Debugging/Testing options:")); + strUsage += HelpMessageOpt("-uacomment=<cmt>", _("Append comment to the user agent string")); if (showDebug) { - strUsage += HelpMessageOpt("-checkpoints", strprintf("Only accept block chain matching built-in checkpoints (default: %u)", 1)); - strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush database activity from memory pool to disk log every <n> megabytes (default: %u)", 100)); - strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", 0)); - strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", 0)); + strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), DEFAULT_CHECKBLOCKS)); + strUsage += HelpMessageOpt("-checklevel=<n>", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), DEFAULT_CHECKLEVEL)); + strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); + strUsage += HelpMessageOpt("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); + strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED)); + strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", DEFAULT_DISABLE_SAFEMODE)); + strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", DEFAULT_TESTSAFEMODE)); strUsage += HelpMessageOpt("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages"); strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages"); - strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", 1)); - strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0)); + strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT)); + strUsage += HelpMessageOpt("-limitancestorcount=<n>", strprintf("Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)", DEFAULT_ANCESTOR_LIMIT)); + strUsage += HelpMessageOpt("-limitancestorsize=<n>", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT)); + strUsage += HelpMessageOpt("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT)); + strUsage += HelpMessageOpt("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT)); + strUsage += HelpMessageOpt("-bip9params=deployment:start:end", "Use given start/end times for specified BIP9 deployment (regtest-only)"); } - string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net, proxy, prune"; // Don't translate these and qt below + std::string debugCategories = "addrman, alert, bench, cmpctblock, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below if (mode == HMM_BITCOIN_QT) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " + - _("If <category> is not supplied, output all debugging information.") + _("<category> can be:") + " " + debugCategories + "."); -#ifdef ENABLE_WALLET - strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0)); - strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1)); -#endif + _("If <category> is not supplied or if <category> = 1, output all debugging information.") + _("<category> can be:") + " " + debugCategories + "."); + if (showDebug) + strUsage += HelpMessageOpt("-nodebug", "Turn off debugging messages, same as -debug=0"); strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)")); - strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), 0)); - strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), 1)); + strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), DEFAULT_LOGIPS)); + strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), DEFAULT_LOGTIMESTAMPS)); if (showDebug) { - strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", 15)); - strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 1)); - strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> entries (default: %u)", 50000)); + strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS)); + strUsage += HelpMessageOpt("-mocktime=<n>", "Replace actual time with <n> seconds since epoch (default: 0)"); + strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", DEFAULT_LIMITFREERELAY)); + strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", DEFAULT_RELAYPRIORITY)); + strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE)); + strUsage += HelpMessageOpt("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE)); } - strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in DOGE/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK()))); + strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)"), + CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE))); + strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)"), + CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE))); strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file")); if (showDebug) { - strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", 0)); - strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", 1)); - strUsage += HelpMessageOpt("-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."); + strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY)); } strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)")); - strUsage += HelpMessageOpt("-testnet", _("Use the test network")); + + AppendParamsHelpMessages(strUsage, showDebug); strUsage += HelpMessageGroup(_("Node relay options:")); - strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), 1)); + if (showDebug) { + strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard())); + strUsage += HelpMessageOpt("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE))); + strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost about 1/3 of its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE))); + } + strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Equivalent bytes per sigop in transactions for relay and mining (default: %u)"), DEFAULT_BYTES_PER_SIGOP)); + strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER)); strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY)); + strUsage += HelpMessageOpt("-mempoolreplacement", strprintf(_("Enable transaction replacement in the memory pool (default: %u)"), DEFAULT_ENABLE_REPLACEMENT)); strUsage += HelpMessageGroup(_("Block creation options:")); - strUsage += HelpMessageOpt("-blockminsize=<n>", strprintf(_("Set minimum block size in bytes (default: %u)"), 0)); + strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT)); strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE)); strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE)); + strUsage += HelpMessageOpt("-blockmintxfee=<amt>", strprintf(_("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE))); + if (showDebug) + strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios"); strUsage += HelpMessageGroup(_("RPC server options:")); strUsage += HelpMessageOpt("-server", _("Accept command line and JSON-RPC commands")); - strUsage += HelpMessageOpt("-rest", strprintf(_("Accept public REST requests (default: %u)"), 0)); + strUsage += HelpMessageOpt("-rest", strprintf(_("Accept public REST requests (default: %u)"), DEFAULT_REST_ENABLE)); strUsage += HelpMessageOpt("-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)")); + strUsage += HelpMessageOpt("-rpccookiefile=<loc>", _("Location of the auth cookie (default: data dir)")); strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections")); strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections")); - strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"), 8332, 18332)); + strUsage += HelpMessageOpt("-rpcauth=<userpw>", _("Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times")); + strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort())); strUsage += HelpMessageOpt("-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")); - strUsage += HelpMessageOpt("-rpcthreads=<n>", strprintf(_("Set the number of threads to service RPC calls (default: %d)"), 4)); - strUsage += HelpMessageOpt("-rpckeepalive", strprintf(_("RPC support for HTTP persistent connections (default: %d)"), 1)); - - strUsage += HelpMessageGroup(_("RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)")); - strUsage += HelpMessageOpt("-rpcssl", _("Use OpenSSL (https) for JSON-RPC connections")); - strUsage += HelpMessageOpt("-rpcsslcertificatechainfile=<file.cert>", strprintf(_("Server certificate file (default: %s)"), "server.cert")); - strUsage += HelpMessageOpt("-rpcsslprivatekeyfile=<file.pem>", strprintf(_("Server private key (default: %s)"), "server.pem")); - strUsage += HelpMessageOpt("-rpcsslciphers=<ciphers>", strprintf(_("Acceptable ciphers (default: %s)"), "TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH")); - - if (mode == HMM_BITCOIN_QT) - { - strUsage += HelpMessageGroup(_("UI Options:")); - if (showDebug) { - strUsage += HelpMessageOpt("-allowselfsignedrootcertificates", "Allow self signed root certificates (default: 0)"); - } - strUsage += HelpMessageOpt("-choosedatadir", _("Choose data directory on startup (default: 0)")); - strUsage += HelpMessageOpt("-lang=<lang>", _("Set language, for example \"de_DE\" (default: system locale)")); - strUsage += HelpMessageOpt("-min", _("Start minimized")); - strUsage += HelpMessageOpt("-rootcertificates=<file>", _("Set SSL root certificates for payment request (default: -system-)")); - strUsage += HelpMessageOpt("-splash", _("Show splash screen on startup (default: 1)")); - if (showDebug) { - strUsage += HelpMessageOpt("-uiplatform", "Select platform to customize UI for (one of windows, macosx, other; default: platform compiled on)"); - } + strUsage += HelpMessageOpt("-rpcthreads=<n>", strprintf(_("Set the number of threads to service RPC calls (default: %d)"), DEFAULT_HTTP_THREADS)); + if (showDebug) { + strUsage += HelpMessageOpt("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE)); + strUsage += HelpMessageOpt("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT)); } return strUsage; @@ -449,27 +509,53 @@ std::string HelpMessage(HelpMessageMode mode) std::string LicenseInfo() { - return FormatParagraph(strprintf(_("Copyright (C) 2009-%i The Bitcoin Core Developers"), COPYRIGHT_YEAR)) + "\n" + + const std::string URL_SOURCE_CODE = "<https://github.com/dogecoin/dogecoin>"; + const std::string URL_WEBSITE = "<https://dogecoin.com>"; + + return CopyrightHolders(strprintf(_("Copyright (C) %i-%i"), 2013, COPYRIGHT_YEAR) + " ") + "\n" + + "\n" + + strprintf(_("Please contribute if you find %s useful. " + "Visit %s for further information about the software."), + PACKAGE_NAME, URL_WEBSITE) + "\n" + - FormatParagraph(strprintf(_("Copyright (C) 2013-%i The Dogecoin Core Developers"), COPYRIGHT_YEAR)) + "\n" + + strprintf(_("The source code is available from %s."), + URL_SOURCE_CODE) + "\n" + - FormatParagraph(_("This is experimental software.")) + "\n" + "\n" + - FormatParagraph(_("Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>.")) + "\n" + + _("This is experimental software.") + "\n" + + strprintf(_("Distributed under the MIT software license, see the accompanying file %s or %s"), "COPYING", "<https://opensource.org/licenses/MIT>") + "\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. Paper wallet art provided by Anacoluthia.")) + + strprintf(_("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Paper wallet art provided by Anacoluthia."), "<https://www.openssl.org>") + "\n"; } -static void BlockNotifyCallback(const uint256& hashNewTip, const int nHeight) +static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex) { + if (initialSync || !pBlockIndex) + return; + std::string strCmd = GetArg("-blocknotify", ""); - boost::replace_all(strCmd, "%s", hashNewTip.GetHex()); - boost::replace_all(strCmd, "%i", boost::lexical_cast<std::string>(chainActive.Height())); + boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex()); + boost::replace_all(strCmd, "%i", boost::lexical_cast<std::string>(pBlockIndex->nHeight)); boost::thread t(runCommand, strCmd); // thread runs free } +static bool fHaveGenesis = false; +static boost::mutex cs_GenesisWait; +static CConditionVariable condvar_GenesisWait; + +static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex) +{ + if (pBlockIndex != NULL) { + { + boost::unique_lock<boost::mutex> lock_GenesisWait(cs_GenesisWait); + fHaveGenesis = true; + } + condvar_GenesisWait.notify_all(); + } +} + struct CImportingNow { CImportingNow() { @@ -492,15 +578,14 @@ struct CImportingNow // works correctly. void CleanupBlockRevFiles() { - using namespace boost::filesystem; - map<string, path> mapBlockFiles; + std::map<std::string, boost::filesystem::path> mapBlockFiles; // Glob all blk?????.dat and rev?????.dat files from the blocks directory. // Remove the rev files immediately and insert the blk file paths into an // ordered map keyed by block file index. LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n"); - path blocksdir = GetDataDir() / "blocks"; - for (directory_iterator it(blocksdir); it != directory_iterator(); it++) { + boost::filesystem::path blocksdir = GetDataDir() / "blocks"; + for (boost::filesystem::directory_iterator it(blocksdir); it != boost::filesystem::directory_iterator(); it++) { if (is_regular_file(*it) && it->path().filename().string().length() == 12 && it->path().filename().string().substr(8,4) == ".dat") @@ -517,7 +602,7 @@ void CleanupBlockRevFiles() // keeping a separate counter. Once we hit a gap (or if 0 doesn't exist) // start removing block files. int nContigCounter = 0; - BOOST_FOREACH(const PAIRTYPE(string, path)& item, mapBlockFiles) { + BOOST_FOREACH(const PAIRTYPE(std::string, boost::filesystem::path)& item, mapBlockFiles) { if (atoi(item.first) == nContigCounter) { nContigCounter++; continue; @@ -528,10 +613,14 @@ void CleanupBlockRevFiles() void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) { + const CChainParams& chainparams = Params(); RenameThread("dogecoin-loadblk"); + + { + CImportingNow imp; + // -reindex if (fReindex) { - CImportingNow imp; int nFile = 0; while (true) { CDiskBlockPos pos(nFile, 0); @@ -541,14 +630,14 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) if (!file) break; // This error is logged in OpenBlockFile LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile); - LoadExternalBlockFile(file, &pos); + LoadExternalBlockFile(chainparams, 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(); + InitBlockIndex(chainparams); } // hardcoded $DATADIR/bootstrap.dat @@ -556,10 +645,9 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) if (boost::filesystem::exists(pathBootstrap)) { FILE *file = fopen(pathBootstrap.string().c_str(), "rb"); if (file) { - CImportingNow imp; boost::filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; LogPrintf("Importing bootstrap.dat...\n"); - LoadExternalBlockFile(file); + LoadExternalBlockFile(chainparams, file); RenameOver(pathBootstrap, pathBootstrapOld); } else { LogPrintf("Warning: Could not open bootstrap file %s\n", pathBootstrap.string()); @@ -567,21 +655,30 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) } // -loadblock= - BOOST_FOREACH(boost::filesystem::path &path, vImportFiles) { + BOOST_FOREACH(const 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); + LoadExternalBlockFile(chainparams, file); } else { LogPrintf("Warning: Could not open blocks file %s\n", path.string()); } } - if (GetBoolArg("-stopafterblockimport", false)) { + // scan for better chains in the block chain database, that are not yet connected in the active best chain + CValidationState state; + if (!ActivateBestChain(state, chainparams)) { + LogPrintf("Failed to connect best block"); + StartShutdown(); + } + + if (GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { LogPrintf("Stopping after block import\n"); StartShutdown(); } + } // End scope of CImportingNow + LoadMempool(); + fDumpMempoolLater = !fRequestShutdown; } /** Sanity checks @@ -591,8 +688,7 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) 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"); + InitError("Elliptic curve cryptography sanity check failure. Aborting."); return false; } if (!glibc_sanity_test() || !glibcxx_sanity_test()) @@ -601,10 +697,128 @@ bool InitSanityCheck(void) return true; } -/** Initialize bitcoin. - * @pre Parameters should be parsed and config file should be read. - */ -bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) +bool AppInitServers(boost::thread_group& threadGroup) +{ + RPCServer::OnStarted(&OnRPCStarted); + RPCServer::OnStopped(&OnRPCStopped); + RPCServer::OnPreCommand(&OnRPCPreCommand); + if (!InitHTTPServer()) + return false; + if (!StartRPC()) + return false; + if (!StartHTTPRPC()) + return false; + if (GetBoolArg("-rest", DEFAULT_REST_ENABLE) && !StartREST()) + return false; + if (!StartHTTPServer()) + return false; + return true; +} + +// Parameter interaction based on rules +void InitParameterInteraction() +{ + // when specifying an explicit binding address, you want to listen on it + // even when -connect or -proxy is specified + if (IsArgSet("-bind")) { + if (SoftSetBoolArg("-listen", true)) + LogPrintf("%s: parameter interaction: -bind set -> setting -listen=1\n", __func__); + } + if (IsArgSet("-whitebind")) { + if (SoftSetBoolArg("-listen", true)) + LogPrintf("%s: parameter interaction: -whitebind set -> setting -listen=1\n", __func__); + } + + if (mapMultiArgs.count("-connect") && mapMultiArgs.at("-connect").size() > 0) { + // when only connecting to trusted nodes, do not seed via DNS, or listen by default + if (SoftSetBoolArg("-dnsseed", false)) + LogPrintf("%s: parameter interaction: -connect set -> setting -dnsseed=0\n", __func__); + if (SoftSetBoolArg("-listen", false)) + LogPrintf("%s: parameter interaction: -connect set -> setting -listen=0\n", __func__); + } + + if (IsArgSet("-proxy")) { + // to protect privacy, do not listen by default if a default proxy server is specified + if (SoftSetBoolArg("-listen", false)) + LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__); + // to protect privacy, do not use UPNP when a proxy is set. The user may still specify -listen=1 + // to listen locally, so don't rely on this happening through -listen below. + if (SoftSetBoolArg("-upnp", false)) + LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__); + // to protect privacy, do not discover addresses by default + if (SoftSetBoolArg("-discover", false)) + LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__); + } + + if (!GetBoolArg("-listen", DEFAULT_LISTEN)) { + // do not map ports or try to retrieve public IP when not listening (pointless) + if (SoftSetBoolArg("-upnp", false)) + LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__); + if (SoftSetBoolArg("-discover", false)) + LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__); + if (SoftSetBoolArg("-listenonion", false)) + LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__); + } + + if (IsArgSet("-externalip")) { + // if an explicit public IP is specified, do not try to find others + if (SoftSetBoolArg("-discover", false)) + LogPrintf("%s: parameter interaction: -externalip set -> setting -discover=0\n", __func__); + } + + // disable whitelistrelay in blocksonly mode + if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) { + if (SoftSetBoolArg("-whitelistrelay", false)) + LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__); + } + + // Forcing relay from whitelisted hosts implies we will accept relays from them in the first place. + if (GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { + if (SoftSetBoolArg("-whitelistrelay", true)) + LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__); + } +} + +static std::string ResolveErrMsg(const char * const optname, const std::string& strBind) +{ + return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind); +} + +void InitLogging() +{ + fPrintToConsole = GetBoolArg("-printtoconsole", false); + fLogTimestamps = GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); + fLogTimeMicros = GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); + fLogIPs = GetBoolArg("-logips", DEFAULT_LOGIPS); + + LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + LogPrintf("Dogecoin version %s\n", FormatFullVersion()); +} + +namespace { // Variables internal to initialization process only + +ServiceFlags nRelevantServices = NODE_NETWORK; +int nMaxConnections; +int nUserMaxConnections; +int nFD; +ServiceFlags nLocalServices = NODE_NETWORK; + +} + +[[noreturn]] static void new_handler_terminate() +{ + // Rather than throwing std::bad-alloc if allocation fails, terminate + // immediately to (try to) avoid chain corruption. + // Since LogPrintf may itself allocate memory, set the handler directly + // to terminate first. + std::set_new_handler(std::terminate); + LogPrintf("Error: Out of memory. Terminating.\n"); + + // The log was successful, terminate now. + std::terminate(); +}; + +bool AppInitBasicSetup() { // ********************************************************* Step 1: setup #ifdef _MSC_VER @@ -628,23 +842,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) 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 { + if (!SetupNetworking()) + return InitError("Initializing networking failed"); + +#ifndef WIN32 + if (!GetBoolArg("-sysperms", false)) { umask(077); } @@ -663,161 +867,133 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) sa_hup.sa_flags = 0; sigaction(SIGHUP, &sa_hup, NULL); -#if defined (__SVR4) && defined (__sun) - // ignore SIGPIPE on Solaris + // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly signal(SIGPIPE, SIG_IGN); #endif -#endif - // ********************************************************* Step 2: parameter interactions - const CChainParams& chainparams = Params(); - - // Set this early so that parameter interactions go to console - fPrintToConsole = GetBoolArg("-printtoconsole", false); - fLogTimestamps = GetBoolArg("-logtimestamps", true); - fLogIPs = GetBoolArg("-logips", false); - - fBloomFilters = GetBoolArg("-bloomfilters", true); - if (fBloomFilters) { - nLocalServices |= NODE_BLOOM; - } - - // when specifying an explicit binding address, you want to listen on it - // even when -connect or -proxy is specified - if (mapArgs.count("-bind")) { - if (SoftSetBoolArg("-listen", true)) - LogPrintf("%s: parameter interaction: -bind set -> setting -listen=1\n", __func__); - } - if (mapArgs.count("-whitebind")) { - if (SoftSetBoolArg("-listen", true)) - LogPrintf("%s: parameter interaction: -whitebind set -> setting -listen=1\n", __func__); - } - - 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("%s: parameter interaction: -connect set -> setting -dnsseed=0\n", __func__); - if (SoftSetBoolArg("-listen", false)) - LogPrintf("%s: parameter interaction: -connect set -> setting -listen=0\n", __func__); - } - - if (mapArgs.count("-proxy")) { - // to protect privacy, do not listen by default if a default proxy server is specified - if (SoftSetBoolArg("-listen", false)) - LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__); - // to protect privacy, do not use UPNP when a proxy is set. The user may still specify -listen=1 - // to listen locally, so don't rely on this happening through -listen below. - if (SoftSetBoolArg("-upnp", false)) - LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__); - // to protect privacy, do not discover addresses by default - if (SoftSetBoolArg("-discover", false)) - LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__); - } + std::set_new_handler(new_handler_terminate); - if (!GetBoolArg("-listen", DEFAULT_LISTEN)) { - // do not map ports or try to retrieve public IP when not listening (pointless) - if (SoftSetBoolArg("-upnp", false)) - LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__); - if (SoftSetBoolArg("-discover", false)) - LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__); - } + return true; +} - if (mapArgs.count("-externalip")) { - // if an explicit public IP is specified, do not try to find others - if (SoftSetBoolArg("-discover", false)) - LogPrintf("%s: parameter interaction: -externalip set -> setting -discover=0\n", __func__); - } +bool AppInitParameterInteraction() +{ + const CChainParams& chainparams = Params(); + // ********************************************************* Step 2: parameter interactions - if (GetBoolArg("-salvagewallet", false)) { - // Rewrite just private keys: rescan to find transactions - if (SoftSetBoolArg("-rescan", true)) - LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__); - } + // also see: InitParameterInteraction() - // -zapwallettx implies a rescan - if (GetBoolArg("-zapwallettxes", false)) { - if (SoftSetBoolArg("-rescan", true)) - LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__); + // if using block pruning, then disallow txindex + if (GetArg("-prune", 0)) { + if (GetBoolArg("-txindex", DEFAULT_TXINDEX)) + return InitError(_("Prune mode is incompatible with -txindex.")); } // 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); + int nBind = std::max( + (mapMultiArgs.count("-bind") ? mapMultiArgs.at("-bind").size() : 0) + + (mapMultiArgs.count("-whitebind") ? mapMultiArgs.at("-whitebind").size() : 0), size_t(1)); + nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); + nMaxConnections = std::max(nUserMaxConnections, 0); + + // Trim requested connection counts, to fit into system limitations + nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS)), 0); + nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS); if (nFD < MIN_CORE_FILEDESCRIPTORS) return InitError(_("Not enough file descriptors available.")); - if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections) - nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS; + nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, nMaxConnections); - // if using block pruning, then disable txindex - // also disable the wallet (for now, until SPV support is implemented in wallet) - if (GetArg("-prune", 0)) { - if (GetBoolArg("-txindex", false)) - return InitError(_("Prune mode is incompatible with -txindex.")); -#ifdef ENABLE_WALLET - if (!GetBoolArg("-disablewallet", false)) { - if (SoftSetBoolArg("-disablewallet", true)) - LogPrintf("%s : parameter interaction: -prune -> setting -disablewallet=1\n", __func__); - else - return InitError(_("Can't run with a wallet in prune mode.")); - } -#endif - } + if (nMaxConnections < nUserMaxConnections) + InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections)); // ********************************************************* Step 3: parameter-to-internal-flags - fDebug = !mapMultiArgs["-debug"].empty(); + fDebug = mapMultiArgs.count("-debug"); // 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; + if (fDebug) { + const std::vector<std::string>& categories = mapMultiArgs.at("-debug"); + if (GetBoolArg("-nodebug", false) || find(categories.begin(), categories.end(), std::string("0")) != categories.end()) + fDebug = false; + } // Check for -debugnet if (GetBoolArg("-debugnet", false)) - InitWarning(_("Warning: Unsupported argument -debugnet ignored, use -debug=net.")); + InitWarning(_("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.")); + if (IsArgSet("-socks")) + return InitError(_("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.")); + return InitError(_("Unsupported argument -tor found, use -onion.")); if (GetBoolArg("-benchmark", false)) - InitWarning(_("Warning: Unsupported argument -benchmark ignored, use -debug=bench.")); + InitWarning(_("Unsupported argument -benchmark ignored, use -debug=bench.")); + + if (GetBoolArg("-whitelistalwaysrelay", false)) + InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.")); + + if (IsArgSet("-blockminsize")) + InitWarning("Unsupported argument -blockminsize ignored."); // Checkmempool and checkblockindex default to true in regtest mode - mempool.setSanityCheck(GetBoolArg("-checkmempool", chainparams.DefaultConsistencyChecks())); + int ratio = std::min<int>(std::max<int>(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); + if (ratio != 0) { + mempool.setSanityCheck(1.0 / ratio); + } fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); - fCheckpointsEnabled = GetBoolArg("-checkpoints", true); + fCheckpointsEnabled = GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED); + + hashAssumeValid = uint256S(GetArg("-assumevalid", chainparams.GetConsensus(0).defaultAssumeValid.GetHex())); + if (!hashAssumeValid.IsNull()) + LogPrintf("Assuming ancestors of block %s have valid signatures.\n", hashAssumeValid.GetHex()); + else + LogPrintf("Validating signatures for all blocks.\n"); + + // mempool limits + int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; + int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; + if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin) + return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0))); + // incremental relay fee sets the minimimum feerate increase necessary for BIP 125 replacement in the mempool + // and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting. + if (IsArgSet("-incrementalrelayfee")) + { + CAmount n = 0; + if (!ParseMoney(GetArg("-incrementalrelayfee", ""), n)) + return InitError(AmountErrMsg("incrementalrelayfee", GetArg("-incrementalrelayfee", ""))); + incrementalRelayFee = CFeeRate(n); + } // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); if (nScriptCheckThreads <= 0) - nScriptCheckThreads += boost::thread::hardware_concurrency(); + nScriptCheckThreads += GetNumCores(); if (nScriptCheckThreads <= 1) nScriptCheckThreads = 0; else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS; - fServer = GetBoolArg("-server", false); - - // block pruning; get the amount of disk space (in MB) to allot for block & undo files - int64_t nSignedPruneTarget = GetArg("-prune", 0) * 1024 * 1024; - if (nSignedPruneTarget < 0) { + // block pruning; get the amount of disk space (in MiB) to allot for block & undo files + int64_t nPruneArg = GetArg("-prune", 0); + if (nPruneArg < 0) { return InitError(_("Prune cannot be configured with a negative value.")); } - nPruneTarget = (uint64_t) nSignedPruneTarget; - if (nPruneTarget) { + nPruneTarget = (uint64_t) nPruneArg * 1024 * 1024; + if (nPruneArg == 1) { // manual pruning: -prune=1 + LogPrintf("Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files.\n"); + nPruneTarget = std::numeric_limits<uint64_t>::max(); + fPruneMode = true; + } else if (nPruneTarget) { if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) { - return InitError(strprintf(_("Prune configured below the minimum of %d MB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); + return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); } LogPrintf("Prune configured to target %uMiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024); fPruneMode = true; } + RegisterAllCoreRPCCommands(tableRPC); #ifdef ENABLE_WALLET - bool fDisableWallet = GetBoolArg("-disablewallet", false); + RegisterWalletRPCCommands(tableRPC); #endif nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); @@ -830,82 +1006,118 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // 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")) + if (IsArgSet("-minrelaytxfee")) { CAmount n = 0; - if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0) - ::minRelayTxFee = CFeeRate(n); - else - return InitError(strprintf(_("Invalid amount for -minrelaytxfee=<amount>: '%s'"), mapArgs["-minrelaytxfee"])); + if (!ParseMoney(GetArg("-minrelaytxfee", ""), n) || 0 == n) + return InitError(AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", ""))); + // High fee check is done afterward in CWallet::ParameterInteraction() + ::minRelayTxFee = CFeeRate(n); + } else if (incrementalRelayFee > ::minRelayTxFee) { + // Allow only setting incrementalRelayFee to control both + ::minRelayTxFee = incrementalRelayFee; + LogPrintf("Increasing minrelaytxfee to %s to match incrementalrelayfee\n",::minRelayTxFee.ToString()); } -#ifdef ENABLE_WALLET - if (mapArgs.count("-mintxfee")) + // Sanity check argument for min fee for including tx in block + // TODO: Harmonize which arguments need sanity checking and where that happens + if (IsArgSet("-blockmintxfee")) { CAmount 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 (!ParseMoney(GetArg("-blockmintxfee", ""), n)) + return InitError(AmountErrMsg("blockmintxfee", GetArg("-blockmintxfee", ""))); } - if (mapArgs.count("-paytxfee")) - { - CAmount 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())); - } - } - if (mapArgs.count("-maxtxfee")) + + // Feerate used to define dust. Shouldn't be changed lightly as old + // implementations may inadvertently create non-standard transactions + if (IsArgSet("-dustrelayfee")) { - CAmount nMaxFee = 0; - if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee)) - return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s'"), mapArgs["-maptxfee"])); - if (nMaxFee > nHighTransactionMaxFeeWarning) - InitWarning(_("Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction.")); - maxTxFee = nMaxFee; - if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) - { - return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), - mapArgs["-maxtxfee"], ::minRelayTxFee.ToString())); - } + CAmount n = 0; + if (!ParseMoney(GetArg("-dustrelayfee", ""), n) || 0 == n) + return InitError(AmountErrMsg("dustrelayfee", GetArg("-dustrelayfee", ""))); + dustRelayFee = CFeeRate(n); } - // Dogecoin: Disable txconfirmtarget - // nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); - nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET; - bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", true); - fSendFreeTransactions = GetBoolArg("-sendfreetransactions", false); + fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard()); + if (chainparams.RequireStandard() && !fRequireStandard) + return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString())); + nBytesPerSigOp = GetArg("-bytespersigop", nBytesPerSigOp); - std::string strWalletFile = GetArg("-wallet", "wallet.dat"); -#endif // ENABLE_WALLET +#ifdef ENABLE_WALLET + if (!CWallet::ParameterInteraction()) + return false; +#endif - fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", true); + fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); + fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes); fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS); - // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log + // Option to startup with mocktime set (used for regression testing): + SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op - // Initialize elliptic curve code - ECC_Start(); + if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) + nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM); - // Sanity check - if (!InitSanityCheck()) - return InitError(_("Initialization sanity check failed. Dogecoin Core is shutting down.")); + if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0) + return InitError("rpcserialversion must be non-negative."); + + if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1) + return InitError("unknown rpcserialversion requested."); + + nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); + + fEnableReplacement = GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT); + if ((!fEnableReplacement) && IsArgSet("-mempoolreplacement")) { + // Minimal effort at forwards compatibility + std::string strReplacementModeList = GetArg("-mempoolreplacement", ""); // default is impossible + std::vector<std::string> vstrReplacementModes; + boost::split(vstrReplacementModes, strReplacementModeList, boost::is_any_of(",")); + fEnableReplacement = (std::find(vstrReplacementModes.begin(), vstrReplacementModes.end(), "fee") != vstrReplacementModes.end()); + } + + if (mapMultiArgs.count("-bip9params")) { + // Allow overriding BIP9 parameters for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError("BIP9 parameters may only be overridden on regtest."); + } + const std::vector<std::string>& deployments = mapMultiArgs.at("-bip9params"); + for (auto i : deployments) { + std::vector<std::string> vDeploymentParams; + boost::split(vDeploymentParams, i, boost::is_any_of(":")); + if (vDeploymentParams.size() != 3) { + return InitError("BIP9 parameters malformed, expecting deployment:start:end"); + } + int64_t nStartTime, nTimeout; + if (!ParseInt64(vDeploymentParams[1], &nStartTime)) { + return InitError(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1])); + } + if (!ParseInt64(vDeploymentParams[2], &nTimeout)) { + return InitError(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2])); + } + bool found = false; + for (int j=0; j<(int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) + { + if (vDeploymentParams[0].compare(VersionBitsDeploymentInfo[j].name) == 0) { + UpdateRegtestBIP9Parameters(Consensus::DeploymentPos(j), nStartTime, nTimeout); + found = true; + LogPrintf("Setting BIP9 activation parameters for %s to start=%ld, timeout=%ld\n", vDeploymentParams[0], nStartTime, nTimeout); + break; + } + } + if (!found) { + return InitError(strprintf("Invalid deployment (%s)", vDeploymentParams[0])); + } + } + } + return true; +} +static bool LockDataDirectory(bool probeOnly) +{ 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. @@ -913,30 +1125,66 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) try { 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. Dogecoin Core is probably already running."), strDataDir)); + if (!lock.try_lock()) { + return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), strDataDir, _(PACKAGE_NAME))); + } + if (probeOnly) { + lock.unlock(); + } } catch(const boost::interprocess::interprocess_exception& e) { - return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Dogecoin Core is probably already running.") + " %s.", strDataDir, e.what())); + return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running.") + " %s.", strDataDir, _(PACKAGE_NAME), e.what())); + } + return true; +} + +bool AppInitSanityChecks() +{ + // ********************************************************* Step 4: sanity checks + + // Initialize elliptic curve code + ECC_Start(); + globalVerifyHandle.reset(new ECCVerifyHandle()); + + // Sanity check + if (!InitSanityCheck()) + return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME))); + + // Probe the data directory lock to give an early error message, if possible + return LockDataDirectory(true); +} + +bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) +{ + const CChainParams& chainparams = Params(); + // ********************************************************* Step 4a: application initialization + // After daemonization get the data directory lock again and hold on to it until exit + // This creates a slight window for a race condition to happen, however this condition is harmless: it + // will at most make us exit without printing a message to console. + if (!LockDataDirectory(false)) { + // Detailed error printed inside LockDataDirectory + return false; } #ifndef WIN32 CreatePidFile(GetPidFile(), getpid()); #endif - if (GetBoolArg("-shrinkdebugfile", !fDebug)) + if (GetBoolArg("-shrinkdebugfile", !fDebug)) { + // Do this first since it both loads a bunch of debug.log into memory, + // and because this needs to happen before any other debug.log printing ShrinkDebugFile(); - LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - LogPrintf("Dogecoin 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 (fPrintToDebugLog) + OpenDebugLog(); + 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; + LogPrintf("Using data directory %s\n", GetDataDir().string()); + LogPrintf("Using config file %s\n", GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string()); + LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD); + + InitSignatureCache(); LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads); if (nScriptCheckThreads) { @@ -953,12 +1201,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) * that the server is there and will be ready later). Warmup mode will * be disabled when initialisation is finished. */ - if (fServer) + if (GetBoolArg("-server", false)) { uiInterface.InitMessage.connect(SetRPCWarmupStatus); - RPCServer::OnStopped(&OnRPCStopped); - RPCServer::OnPreCommand(&OnRPCPreCommand); - StartRPCThreads(); + if (!AppInitServers(threadGroup)) + return InitError(_("Unable to start HTTP server. See debug log for details.")); } int64_t nStart; @@ -969,30 +1216,42 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 5: verify wallet database integrity #ifdef ENABLE_WALLET - if (!fDisableWallet) { - LogPrintf("Using wallet %s\n", strWalletFile); - uiInterface.InitMessage(_("Verifying wallet...")); - - std::string warningString; - std::string errorString; - - if (!CWallet::Verify(strWalletFile, warningString, errorString)) - return false; - - if (!warningString.empty()) - InitWarning(warningString); - if (!errorString.empty()) - return InitError(warningString); - - } // (!fDisableWallet) -#endif // ENABLE_WALLET + if (!CWallet::Verify()) + return false; +#endif // ********************************************************* Step 6: network initialization + // Note that we absolutely cannot open any actual connections + // until the very end ("start node") as the UTXO/block state + // is not yet setup and may end up being set up twice if we + // need to reindex later. + assert(!g_connman); + g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()))); + CConnman& connman = *g_connman; + + peerLogic.reset(new PeerLogicValidation(&connman)); + RegisterValidationInterface(peerLogic.get()); RegisterNodeSignals(GetNodeSignals()); - if (mapArgs.count("-onlynet")) { + // sanitize comments per BIP-0014, format user agent and check total size + std::vector<std::string> uacomments; + if (mapMultiArgs.count("-uacomment")) { + BOOST_FOREACH(std::string cmt, mapMultiArgs.at("-uacomment")) + { + if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) + return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt)); + uacomments.push_back(cmt); + } + } + strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments); + if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) { + return InitError(strprintf(_("Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments."), + strSubVersion.size(), MAX_SUBVERSION_LENGTH)); + } + + if (mapMultiArgs.count("-onlynet")) { std::set<enum Network> nets; - BOOST_FOREACH(std::string snet, mapMultiArgs["-onlynet"]) { + BOOST_FOREACH(const std::string& snet, mapMultiArgs.at("-onlynet")) { enum Network net = ParseNetwork(snet); if (net == NET_UNROUTABLE) return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet)); @@ -1005,90 +1264,120 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } - if (mapArgs.count("-whitelist")) { - BOOST_FOREACH(const std::string& net, mapMultiArgs["-whitelist"]) { - CSubNet subnet(net); + if (mapMultiArgs.count("-whitelist")) { + BOOST_FOREACH(const std::string& net, mapMultiArgs.at("-whitelist")) { + CSubNet subnet; + LookupSubNet(net.c_str(), subnet); if (!subnet.IsValid()) return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net)); - CNode::AddWhitelistedRange(subnet); + connman.AddWhitelistedRange(subnet); } } - proxyType addrProxy; - bool fProxy = false; - if (mapArgs.count("-proxy")) { - addrProxy = proxyType(CService(mapArgs["-proxy"], 9050), GetBoolArg("-proxyrandomize", true)); + bool proxyRandomize = GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE); + // -proxy sets a proxy for all outgoing network traffic + // -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default + std::string proxyArg = GetArg("-proxy", ""); + SetLimited(NET_TOR); + if (proxyArg != "" && proxyArg != "0") { + CService resolved(LookupNumeric(proxyArg.c_str(), 9050)); + proxyType addrProxy = proxyType(resolved, proxyRandomize); if (!addrProxy.IsValid()) - return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"])); + return InitError(strprintf(_("Invalid -proxy address: '%s'"), proxyArg)); SetProxy(NET_IPV4, addrProxy); SetProxy(NET_IPV6, addrProxy); + SetProxy(NET_TOR, addrProxy); SetNameProxy(addrProxy); - fProxy = true; + SetLimited(NET_TOR, false); // by default, -proxy sets onion as reachable, unless -noonion later } - // -onion can override normal proxy, -noonion disables connecting to .onion entirely - if (!(mapArgs.count("-onion") && mapArgs["-onion"] == "0") && - (fProxy || mapArgs.count("-onion"))) { - proxyType addrOnion; - if (!mapArgs.count("-onion")) - addrOnion = addrProxy; - else - addrOnion = proxyType(CService(mapArgs["-onion"], 9050), GetBoolArg("-proxyrandomize", true)); - if (!addrOnion.IsValid()) - return InitError(strprintf(_("Invalid -onion address: '%s'"), mapArgs["-onion"])); - SetProxy(NET_TOR, addrOnion); - SetReachable(NET_TOR); + // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses + // -noonion (or -onion=0) disables connecting to .onion entirely + // An empty string is used to not override the onion proxy (in which case it defaults to -proxy set above, or none) + std::string onionArg = GetArg("-onion", ""); + if (onionArg != "") { + if (onionArg == "0") { // Handle -noonion/-onion=0 + SetLimited(NET_TOR); // set onions as unreachable + } else { + CService resolved(LookupNumeric(onionArg.c_str(), 9050)); + proxyType addrOnion = proxyType(resolved, proxyRandomize); + if (!addrOnion.IsValid()) + return InitError(strprintf(_("Invalid -onion address: '%s'"), onionArg)); + SetProxy(NET_TOR, addrOnion); + SetLimited(NET_TOR, false); + } } // see Step 2: parameter interactions for more information about these fListen = GetBoolArg("-listen", DEFAULT_LISTEN); fDiscover = GetBoolArg("-discover", true); - fNameLookup = GetBoolArg("-dns", true); + fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP); + fRelayTxes = !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); - bool fBound = false; if (fListen) { - if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) { - BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) { + bool fBound = false; + if (mapMultiArgs.count("-bind")) { + BOOST_FOREACH(const std::string& strBind, mapMultiArgs.at("-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)); + return InitError(ResolveErrMsg("bind", strBind)); + fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); } - BOOST_FOREACH(std::string strBind, mapMultiArgs["-whitebind"]) { + } + if (mapMultiArgs.count("-whitebind")) { + BOOST_FOREACH(const std::string& strBind, mapMultiArgs.at("-whitebind")) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, 0, false)) - return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind)); + return InitError(ResolveErrMsg("whitebind", 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)); + fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST)); } } - else { + if (!mapMultiArgs.count("-bind") && !mapMultiArgs.count("-whitebind")) { 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); + fBound |= Bind(connman, CService(in6addr_any, GetListenPort()), BF_NONE); + fBound |= Bind(connman, 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); + if (mapMultiArgs.count("-externalip")) { + BOOST_FOREACH(const std::string& strAddr, mapMultiArgs.at("-externalip")) { + CService addrLocal; + if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid()) + AddLocal(addrLocal, LOCAL_MANUAL); + else + return InitError(ResolveErrMsg("externalip", strAddr)); } } - BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"]) - AddOneShot(strDest); + if (mapMultiArgs.count("-seednode")) { + BOOST_FOREACH(const std::string& strDest, mapMultiArgs.at("-seednode")) + connman.AddOneShot(strDest); + } + +#if ENABLE_ZMQ + pzmqNotificationInterface = CZMQNotificationInterface::Create(); + + if (pzmqNotificationInterface) { + RegisterValidationInterface(pzmqNotificationInterface); + } +#endif + uint64_t nMaxOutboundLimit = 0; //unlimited unless -maxuploadtarget is set + uint64_t nMaxOutboundTimeframe = MAX_UPLOAD_TIMEFRAME; + + if (IsArgSet("-maxuploadtarget")) { + nMaxOutboundLimit = GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024; + } // ********************************************************* Step 7: load block chain fReindex = GetBoolArg("-reindex", false); + bool fReindexChainState = GetBoolArg("-reindex-chainstate", false); // Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/ boost::filesystem::path blocksDir = GetDataDir() / "blocks"; @@ -1120,18 +1409,19 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // cache size calculations int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20); nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache - nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache + nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache int64_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 + nBlockTreeDBCache = std::min(nBlockTreeDBCache, (GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20); nTotalCache -= nBlockTreeDBCache; int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache + nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20); // cap total coins db cache nTotalCache -= nCoinDBCache; nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache + int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; LogPrintf("Cache configuration:\n"); LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024)); - LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (1.0 / 1024 / 1024)); + LogPrintf("* Using %.1fMiB for in-memory UTXO set (plus up to %.1fMiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024)); bool fLoaded = false; while (!fLoaded) { @@ -1150,7 +1440,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) delete pblocktree; pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); - pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex); + pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState); pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview); pcoinsTip = new CCoinsViewCache(pcoinscatcher); @@ -1161,7 +1451,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) CleanupBlockRevFiles(); } - if (!LoadBlockIndex()) { + if (!LoadBlockIndex(chainparams)) { strLoadError = _("Error loading block database"); break; } @@ -1172,14 +1462,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) 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()) { + if (!InitBlockIndex(chainparams)) { 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"); + if (fTxIndex != GetBoolArg("-txindex", DEFAULT_TXINDEX)) { + strLoadError = _("You need to rebuild the database using -reindex-chainstate to change -txindex"); break; } @@ -1190,13 +1480,34 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) break; } + if (!fReindex && chainActive.Tip() != NULL) { + uiInterface.InitMessage(_("Rewinding blocks...")); + if (!RewindBlockIndex(chainparams)) { + strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain"); + break; + } + } + uiInterface.InitMessage(_("Verifying blocks...")); - if (fHavePruned && GetArg("-checkblocks", 288) > MIN_BLOCKS_TO_KEEP) { - LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n", - MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", 288)); + if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) { + LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks", + MIN_BLOCKS_TO_KEEP); } - if (!CVerifyDB().VerifyDB(pcoinsdbview, GetArg("-checklevel", 3), - GetArg("-checkblocks", 288))) { + + { + LOCK(cs_main); + CBlockIndex* tip = chainActive.Tip(); + RPCNotifyBlockChange(true, tip); + if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) { + strLoadError = _("The block database contains a block which appears to be from the future. " + "This may be due to your computer's date and time being set incorrectly. " + "Only rebuild the block database if you are sure that your computer's date and time are correct"); + break; + } + } + + if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, GetArg("-checklevel", DEFAULT_CHECKLEVEL), + GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) { strLoadError = _("Corrupted block database detected"); break; } @@ -1212,8 +1523,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (!fLoaded) { // first suggest a reindex if (!fReset) { - bool fRet = uiInterface.ThreadSafeMessageBox( + bool fRet = uiInterface.ThreadSafeQuestion( strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?"), + strLoadError + ".\nPlease restart with -reindex or -reindex-chainstate to recover.", "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT); if (fRet) { fReindex = true; @@ -1245,226 +1557,115 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) mempool.ReadFeeEstimates(est_filein); fFeeEstimatesInitialized = true; - // if prune mode, unset NODE_NETWORK and prune block files + // ********************************************************* Step 8: load wallet +#ifdef ENABLE_WALLET + if (!CWallet::InitLoadWallet()) + return false; +#else + LogPrintf("No wallet support compiled in!\n"); +#endif + + // ********************************************************* Step 9: data directory maintenance + + // if pruning, unset the service bit and perform the initial blockstore prune + // after any wallet rescanning has taken place. if (fPruneMode) { LogPrintf("Unsetting NODE_NETWORK on prune mode\n"); - nLocalServices &= ~NODE_NETWORK; + nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK); if (!fReindex) { + uiInterface.InitMessage(_("Pruning blockstore...")); PruneAndFlush(); } } - // ********************************************************* 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 Dogecoin Core") << "\n"; - else if (nLoadWalletRet == DB_NEED_REWRITE) - { - strErrors << _("Wallet needed to be rewritten: restart Dogecoin 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); + if (chainparams.GetConsensus(0).vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) { + // Only advertise witness capabilities if they have a reasonable start time. + // This allows us to have the code merged without a defined softfork, by setting its + // end time to 0. + // Note that setting NODE_WITNESS is never required: the only downside from not + // doing so is that after activation, no upgraded nodes will fetch from you. + nLocalServices = ServiceFlags(nLocalServices | NODE_WITNESS); + // Only care about others providing witness capabilities if there is a softfork + // defined. + nRelevantServices = ServiceFlags(nRelevantServices | NODE_WITNESS); + } - RegisterValidationInterface(pwalletMain); + // ********************************************************* Step 10: import blocks - CBlockIndex *pindexRescan = chainActive.Tip(); - if (GetBoolArg("-rescan", false)) - pindexRescan = chainActive.Genesis(); - else - { - CWalletDB walletdb(strWalletFile); - CBlockLocator locator; - if (walletdb.ReadBestBlock(locator)) - pindexRescan = FindForkInGlobalIndex(chainActive, 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") - { - CWalletDB walletdb(strWalletFile); + if (!CheckDiskSpace()) + return false; - 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(&walletdb); - } - } - } - } - pwalletMain->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", true)); - } // (!fDisableWallet) -#else // ENABLE_WALLET - LogPrintf("No wallet support compiled in!\n"); -#endif // !ENABLE_WALLET - // ********************************************************* Step 9: import blocks + // Either install a handler to notify us when genesis activates, or set fHaveGenesis directly. + // No locking, as this happens before any background thread is started. + if (chainActive.Tip() == NULL) { + uiInterface.NotifyBlockTip.connect(BlockNotifyGenesisWait); + } else { + fHaveGenesis = true; + } - if (mapArgs.count("-blocknotify")) + if (IsArgSet("-blocknotify")) uiInterface.NotifyBlockTip.connect(BlockNotifyCallback); - uiInterface.InitMessage(_("Activating best chain...")); - // 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")) + if (mapMultiArgs.count("-loadblock")) { - BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"]) + BOOST_FOREACH(const std::string& strFile, mapMultiArgs.at("-loadblock")) vImportFiles.push_back(strFile); } - threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); - if (chainActive.Tip() == NULL) { - LogPrintf("Waiting for genesis block to be imported...\n"); - while (!fRequestShutdown && chainActive.Tip() == NULL) - MilliSleep(10); - } - - // ********************************************************* Step 10: start node - if (!CheckDiskSpace()) - return false; + threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); - if (!strErrors.str().empty()) - return InitError(strErrors.str()); + // Wait for genesis block to be processed + { + boost::unique_lock<boost::mutex> lock(cs_GenesisWait); + while (!fHaveGenesis) { + condvar_GenesisWait.wait(lock); + } + uiInterface.NotifyBlockTip.disconnect(BlockNotifyGenesisWait); + } - RandAddSeedPerfmon(); + // ********************************************************* Step 11: start node //// 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 + if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) + StartTorControl(threadGroup, scheduler); - StartNode(threadGroup, scheduler); + Discover(threadGroup); - // Monitor the chain, and alert if we get blocks much quicker or slower than expected - int64_t nPowTargetSpacing = Params().GetConsensus(chainActive.Height()).nPowTargetSpacing; - CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload, - boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing); - scheduler.scheduleEvery(f, nPowTargetSpacing); + // Map ports with UPnP + MapPort(GetBoolArg("-upnp", DEFAULT_UPNP)); -#ifdef ENABLE_WALLET - // Generate coins in the background - if (pwalletMain) - GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 1)); + std::string strNodeError; + CConnman::Options connOptions; + connOptions.nLocalServices = nLocalServices; + connOptions.nRelevantServices = nRelevantServices; + connOptions.nMaxConnections = nMaxConnections; + connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections); + connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS; + connOptions.nMaxFeeler = 1; + connOptions.nBestHeight = chainActive.Height(); + connOptions.uiInterface = &uiInterface; + connOptions.nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); + connOptions.nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); -#endif + connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe; + connOptions.nMaxOutboundLimit = nMaxOutboundLimit; + + if (!connman.Start(scheduler, strNodeError, connOptions)) + return InitError(strNodeError); + + // ********************************************************* Step 12: finished - // ********************************************************* Step 11: finished + // Dogecoin: Do we need to do any RPC mining init here? SetRPCWarmupFinished(); 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))); - } + if (pwalletMain) + pwalletMain->postInitProcess(threadGroup); #endif return !fRequestShutdown; |