diff options
Diffstat (limited to 'src/init.cpp')
| -rw-r--r-- | src/init.cpp | 790 |
1 files changed, 499 insertions, 291 deletions
diff --git a/src/init.cpp b/src/init.cpp index 509bc45f5..93b4c80c0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2015 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. @@ -16,15 +16,21 @@ #include "checkpoints.h" #include "compat/sanity.h" #include "consensus/validation.h" +#include "fs.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 "net_processing.h" +#include "policy/feerate.h" +#include "policy/fees.h" #include "policy/policy.h" #include "rpc/server.h" #include "rpc/register.h" +#include "rpc/blockchain.h" #include "script/standard.h" #include "script/sigcache.h" #include "scheduler.h" @@ -39,8 +45,10 @@ #ifdef ENABLE_WALLET #include "wallet/wallet.h" #endif +#include "warnings.h" #include <stdint.h> #include <stdio.h> +#include <memory> #ifndef WIN32 #include <signal.h> @@ -51,7 +59,6 @@ #include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/split.hpp> #include <boost/bind.hpp> -#include <boost/filesystem.hpp> #include <boost/function.hpp> #include <boost/interprocess/sync/file_lock.hpp> #include <boost/thread.hpp> @@ -61,14 +68,14 @@ #include "zmq/zmqnotificationinterface.h" #endif -using namespace std; - 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; @@ -114,16 +121,13 @@ static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; // threads that should only be stopped after the main network-processing // threads have exited. // -// Note that if running -daemon the parent process returns from AppInit2 -// before adding any threads to the threadGroup, so .join_all() returns -// immediately and the parent exits from main(). -// // Shutdown for Qt is very similar, only it uses a QTimer to detect // fRequestShutdown getting set, and then does the normal Qt // shutdown thing. // std::atomic<bool> fRequestShutdown(false); +std::atomic<bool> fDumpMempoolLater(false); void StartShutdown() { @@ -161,7 +165,7 @@ public: static CCoinsViewDB *pcoinsdbview = NULL; static CCoinsViewErrorCatcher *pcoinscatcher = NULL; -static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle; +static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; void Interrupt(boost::thread_group& threadGroup) { @@ -170,6 +174,8 @@ void Interrupt(boost::thread_group& threadGroup) InterruptRPC(); InterruptREST(); InterruptTorControl(); + if (g_connman) + g_connman->Interrupt(); threadGroup.interrupt_all(); } @@ -181,7 +187,7 @@ void Shutdown() if (!lockShutdown) return; - /// Note: Shutdown() must be able to handle cases in which AppInit2() failed part of the way, + /// Note: Shutdown() must be able to handle cases in which initialization failed part of the way, /// for example if the data directory was found to be locked. /// Be sure that anything that writes files or flushes caches only does this if the respective /// module was initialized. @@ -196,16 +202,23 @@ void Shutdown() if (pwalletMain) pwalletMain->Flush(false); #endif - StopNode(); + MapPort(false); + UnregisterValidationInterface(peerLogic.get()); + peerLogic.reset(); + g_connman.reset(); + StopTorControl(); UnregisterNodeSignals(GetNodeSignals()); + if (fDumpMempoolLater && GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { + DumpMempool(); + } if (fFeeEstimatesInitialized) { - boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; - CAutoFile est_fileout(fopen(est_path.string().c_str(), "wb"), SER_DISK, CLIENT_VERSION); + fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; + CAutoFile est_fileout(fsbridge::fopen(est_path, "wb"), SER_DISK, CLIENT_VERSION); if (!est_fileout.IsNull()) - mempool.WriteFeeEstimates(est_fileout); + ::feeEstimator.Write(est_fileout); else LogPrintf("%s: Failed to write fee estimates to %s\n", __func__, est_path.string()); fFeeEstimatesInitialized = false; @@ -240,8 +253,8 @@ void Shutdown() #ifndef WIN32 try { - boost::filesystem::remove(GetPidFile()); - } catch (const boost::filesystem::filesystem_error& e) { + fs::remove(GetPidFile()); + } catch (const fs::filesystem_error& e) { LogPrintf("%s: Unable to remove pidfile: %s\n", __func__, e.what()); } #endif @@ -256,64 +269,86 @@ void Shutdown() } /** - * Signal handlers are very limited in what they are allowed to do, so: + * Signal handlers are very limited in what they are allowed to do. + * The execution context the handler is invoked in is not guaranteed, + * so we restrict handler operations to just touching variables: */ -void HandleSIGTERM(int) +static void HandleSIGTERM(int) { fRequestShutdown = true; } -void HandleSIGHUP(int) +static void HandleSIGHUP(int) { fReopenDebugLog = true; } -bool static Bind(const CService &addr, unsigned int flags) { +#ifndef WIN32 +static void registerSignalHandler(int signal, void(*handler)(int)) +{ + struct sigaction sa; + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(signal, &sa, NULL); +} +#endif + +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"); + LogPrint(BCLog::RPC, "RPC stopped.\n"); } void OnRPCPreCommand(const CRPCCommand& cmd) { // Observe safe mode - string strWarning = GetWarnings("rpc"); + 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) { + const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN); + const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET); + const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN); + const auto testnetChainParams = CreateChainParams(CBaseChainParams::TESTNET); 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:")); + std::string strUsage = HelpMessageGroup(_("Options:")); strUsage += HelpMessageOpt("-?", _("Print this help message and exit")); strUsage += HelpMessageOpt("-version", _("Print version and exit")); 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)")); if (showDebug) strUsage += HelpMessageOpt("-blocksonly", strprintf(_("Whether to operate in a blocks only mode (default: %u)"), DEFAULT_BLOCKSONLY)); - 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("-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)"), defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex())); strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME)); if (mode == HMM_BITCOIND) { -#ifndef WIN32 +#if HAVE_DECL_DAEMON strUsage += HelpMessageOpt("-daemon", _("Run in the background as a daemon and accept commands")); #endif } @@ -325,14 +360,16 @@ std::string HelpMessage(HelpMessageMode mode) 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("-persistmempool", strprintf(_("Whether to save the mempool on shutdown and load on restart (default: %u)"), DEFAULT_PERSIST_MEMPOOL)); + 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)"), -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS)); #ifndef WIN32 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 is incompatible with -txindex and -rescan. " + 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)); + "(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 @@ -345,10 +382,10 @@ std::string HelpMessage(HelpMessageMode mode) 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); -connect=0 disables 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") + " " + strprintf(_("(default: %u)"), DEFAULT_NAME_LOOKUP)); - strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)")); + strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)")); strUsage += HelpMessageOpt("-externalip=<ip>", _("Specify your own public address")); 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)")); @@ -361,7 +398,7 @@ std::string HelpMessage(HelpMessageMode mode) 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)"), 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("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), defaultChainParams->GetDefaultPort(), testnetChainParams->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)"), DEFAULT_PROXYRANDOMIZE)); strUsage += HelpMessageOpt("-seednode=<ip>", _("Connect to a node to retrieve peer addresses, and disconnect")); @@ -376,10 +413,8 @@ std::string HelpMessage(HelpMessageMode mode) #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 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 @@ -398,26 +433,27 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-uacomment=<cmt>", _("Append comment to the user agent string")); if (showDebug) { - 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("-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)", defaultChainParams->DefaultConsistencyChecks())); + strUsage += HelpMessageOpt("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u)", defaultChainParams->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("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT)); + strUsage += HelpMessageOpt("-stopatheight", strprintf("Stop running after reaching the given height in the main chain (default: %u)", DEFAULT_STOPATHEIGHT)); + 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, 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 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"); + _("If <category> is not supplied or if <category> = 1, output all debugging information.") + " " + _("<category> can be:") + " " + ListLogCategories() + "."); + strUsage += HelpMessageOpt("-debugexclude=<category>", strprintf(_("Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories."))); strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)")); 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)); @@ -425,49 +461,53 @@ std::string HelpMessage(HelpMessageMode mode) { 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 %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)", DEFAULT_PRINTPRIORITY)); + strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction 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)")); AppendParamsHelpMessages(strUsage, showDebug); strUsage += HelpMessageGroup(_("Node relay options:")); - if (showDebug) - strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard())); - strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Minimum bytes per sigop in transactions we relay and mine (default: %u)"), DEFAULT_BYTES_PER_SIGOP)); + if (showDebug) { + strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", defaultChainParams->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 += 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("-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 += HelpMessageGroup(_("Block creation options:")); - strUsage += HelpMessageOpt("-blockmaxcost=<n>", strprintf(_("Set maximum BIP141 block cost (default: %d)"), DEFAULT_BLOCK_MAX_COST)); + 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)"), 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("-rpcbind=<addr>[:port]", _("Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)")); 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("-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. 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("-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)"), defaultBaseParams->RPCPort(), testnetBaseParams->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("-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("-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)); @@ -481,7 +521,7 @@ std::string LicenseInfo() { const std::string URL_SOURCE_CODE = "<https://github.com/bitcoin/bitcoin>"; const std::string URL_WEBSITE = "<https://bitcoincore.org>"; - // todo: remove urls from translations on next change + return CopyrightHolders(strprintf(_("Copyright (C) %i-%i"), 2009, COPYRIGHT_YEAR) + " ") + "\n" + "\n" + strprintf(_("Please contribute if you find %s useful. " @@ -493,9 +533,9 @@ std::string LicenseInfo() "\n" + "\n" + _("This is experimental software.") + "\n" + - _("Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>.") + "\n" + + strprintf(_("Distributed under the MIT software license, see the accompanying file %s or %s"), "COPYING", "<https://opensource.org/licenses/MIT>") + "\n" + "\n" + - _("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.") + + 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."), "<https://www.openssl.org>") + "\n"; } @@ -510,6 +550,21 @@ static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex 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() { @@ -532,15 +587,14 @@ struct CImportingNow // works correctly. void CleanupBlockRevFiles() { - using namespace boost::filesystem; - map<string, path> mapBlockFiles; + std::map<std::string, fs::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++) { + fs::path blocksdir = GetDataDir() / "blocks"; + for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) { if (is_regular_file(*it) && it->path().filename().string().length() == 12 && it->path().filename().string().substr(8,4) == ".dat") @@ -557,7 +611,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, fs::path)& item, mapBlockFiles) { if (atoi(item.first) == nContigCounter) { nContigCounter++; continue; @@ -566,10 +620,12 @@ void CleanupBlockRevFiles() } } -void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) +void ThreadImport(std::vector<fs::path> vImportFiles) { const CChainParams& chainparams = Params(); RenameThread("bitcoin-loadblk"); + + { CImportingNow imp; // -reindex @@ -577,7 +633,7 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) int nFile = 0; while (true) { CDiskBlockPos pos(nFile, 0); - if (!boost::filesystem::exists(GetBlockPosFilename(pos, "blk"))) + if (!fs::exists(GetBlockPosFilename(pos, "blk"))) break; // No block files left to reindex FILE *file = OpenBlockFile(pos, true); if (!file) @@ -594,11 +650,11 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) } // hardcoded $DATADIR/bootstrap.dat - boost::filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat"; - if (boost::filesystem::exists(pathBootstrap)) { - FILE *file = fopen(pathBootstrap.string().c_str(), "rb"); + fs::path pathBootstrap = GetDataDir() / "bootstrap.dat"; + if (fs::exists(pathBootstrap)) { + FILE *file = fsbridge::fopen(pathBootstrap, "rb"); if (file) { - boost::filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; + fs::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; LogPrintf("Importing bootstrap.dat...\n"); LoadExternalBlockFile(chainparams, file); RenameOver(pathBootstrap, pathBootstrapOld); @@ -608,8 +664,8 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) } // -loadblock= - BOOST_FOREACH(const boost::filesystem::path& path, vImportFiles) { - FILE *file = fopen(path.string().c_str(), "rb"); + BOOST_FOREACH(const fs::path& path, vImportFiles) { + FILE *file = fsbridge::fopen(path, "rb"); if (file) { LogPrintf("Importing blocks file %s...\n", path.string()); LoadExternalBlockFile(chainparams, file); @@ -629,6 +685,11 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) LogPrintf("Stopping after block import\n"); StartShutdown(); } + } // End scope of CImportingNow + if (GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { + LoadMempool(); + fDumpMempoolLater = !fRequestShutdown; + } } /** Sanity checks @@ -641,14 +702,21 @@ bool InitSanityCheck(void) InitError("Elliptic curve cryptography sanity check failure. Aborting."); return false; } + if (!glibc_sanity_test() || !glibcxx_sanity_test()) return false; + if (!Random_SanityCheck()) { + InitError("OS cryptographic RNG sanity check failure. Aborting."); + return false; + } + return true; } bool AppInitServers(boost::thread_group& threadGroup) { + RPCServer::OnStarted(&OnRPCStarted); RPCServer::OnStopped(&OnRPCStopped); RPCServer::OnPreCommand(&OnRPCPreCommand); if (!InitHTTPServer()) @@ -669,16 +737,16 @@ void InitParameterInteraction() { // when specifying an explicit binding address, you want to listen on it // even when -connect or -proxy is specified - if (mapArgs.count("-bind")) { + if (IsArgSet("-bind")) { if (SoftSetBoolArg("-listen", true)) LogPrintf("%s: parameter interaction: -bind set -> setting -listen=1\n", __func__); } - if (mapArgs.count("-whitebind")) { + if (IsArgSet("-whitebind")) { if (SoftSetBoolArg("-listen", true)) LogPrintf("%s: parameter interaction: -whitebind set -> setting -listen=1\n", __func__); } - if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { + if (gArgs.IsArgSet("-connect")) { // 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__); @@ -686,7 +754,7 @@ void InitParameterInteraction() LogPrintf("%s: parameter interaction: -connect set -> setting -listen=0\n", __func__); } - if (mapArgs.count("-proxy")) { + 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__); @@ -709,32 +777,16 @@ void InitParameterInteraction() LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__); } - if (mapArgs.count("-externalip")) { + 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__); } - 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__); - } - - // -zapwallettx implies a rescan - if (GetBoolArg("-zapwallettxes", false)) { - if (SoftSetBoolArg("-rescan", true)) - LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__); - } - - // disable walletbroadcast and whitelistrelay in blocksonly mode + // 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__); -#ifdef ENABLE_WALLET - if (SoftSetBoolArg("-walletbroadcast", false)) - LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__); -#endif } // Forcing relay from whitelisted hosts implies we will accept relays from them in the first place. @@ -760,10 +812,30 @@ void InitLogging() LogPrintf("Bitcoin version %s\n", FormatFullVersion()); } -/** Initialize bitcoin. - * @pre Parameters should be parsed and config file should be read. - */ -bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) +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 @@ -793,78 +865,90 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError("Initializing networking failed"); #ifndef WIN32 - if (GetBoolArg("-sysperms", false)) { -#ifdef ENABLE_WALLET - if (!GetBoolArg("-disablewallet", false)) - return InitError("-sysperms is not allowed in combination with enabled wallet functionality"); -#endif - } else { + if (!GetBoolArg("-sysperms", false)) { umask(077); } // Clean shutdown on SIGTERM - struct sigaction sa; - sa.sa_handler = HandleSIGTERM; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); + registerSignalHandler(SIGTERM, HandleSIGTERM); + registerSignalHandler(SIGINT, HandleSIGTERM); // Reopen debug.log on SIGHUP - struct sigaction sa_hup; - sa_hup.sa_handler = HandleSIGHUP; - sigemptyset(&sa_hup.sa_mask); - sa_hup.sa_flags = 0; - sigaction(SIGHUP, &sa_hup, NULL); + registerSignalHandler(SIGHUP, HandleSIGHUP); // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly signal(SIGPIPE, SIG_IGN); #endif - // ********************************************************* Step 2: parameter interactions + std::set_new_handler(new_handler_terminate); + + return true; +} + +bool AppInitParameterInteraction() +{ const CChainParams& chainparams = Params(); + // ********************************************************* Step 2: parameter interactions // also see: InitParameterInteraction() - // if using block pruning, then disable txindex + // if using block pruning, then disallow txindex if (GetArg("-prune", 0)) { if (GetBoolArg("-txindex", DEFAULT_TXINDEX)) return InitError(_("Prune mode is incompatible with -txindex.")); -#ifdef ENABLE_WALLET - if (GetBoolArg("-rescan", false)) { - return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.")); - } -#endif } // Make sure enough file descriptors are available - int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1); - int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); + int nBind = std::max( + (gArgs.IsArgSet("-bind") ? gArgs.GetArgs("-bind").size() : 0) + + (gArgs.IsArgSet("-whitebind") ? gArgs.GetArgs("-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)), 0); - int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); + 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.")); - nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections); + nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, nMaxConnections); if (nMaxConnections < nUserMaxConnections) InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections)); // ********************************************************* Step 3: parameter-to-internal-flags + if (gArgs.IsArgSet("-debug")) { + // Special-case: if -debug=0/-nodebug is set, turn off debugging messages + const std::vector<std::string> categories = gArgs.GetArgs("-debug"); + + if (find(categories.begin(), categories.end(), std::string("0")) == categories.end()) { + for (const auto& cat : categories) { + uint32_t flag = 0; + if (!GetLogCategory(&flag, &cat)) { + InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat)); + continue; + } + logCategories |= flag; + } + } + } - fDebug = !mapMultiArgs["-debug"].empty(); - // Special-case: if -debug=0/-nodebug is set, turn off debugging messages - const vector<string>& categories = mapMultiArgs["-debug"]; - if (GetBoolArg("-nodebug", false) || find(categories.begin(), categories.end(), string("0")) != categories.end()) - fDebug = false; + // Now remove the logging categories which were explicitly excluded + if (gArgs.IsArgSet("-debugexclude")) { + for (const std::string& cat : gArgs.GetArgs("-debugexclude")) { + uint32_t flag = 0; + if (!GetLogCategory(&flag, &cat)) { + InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat)); + continue; + } + logCategories &= ~flag; + } + } // Check for -debugnet if (GetBoolArg("-debugnet", false)) 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")) + 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)) @@ -876,7 +960,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (GetBoolArg("-whitelistalwaysrelay", false)) InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.")); - if (mapArgs.count("-blockminsize")) + if (IsArgSet("-blockminsize")) InitWarning("Unsupported argument -blockminsize ignored."); // Checkmempool and checkblockindex default to true in regtest mode @@ -887,11 +971,26 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); fCheckpointsEnabled = GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED); + hashAssumeValid = uint256S(GetArg("-assumevalid", chainparams.GetConsensus().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 minimum 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); @@ -902,15 +1001,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS; - fServer = GetBoolArg("-server", false); - // block pruning; get the amount of disk space (in MiB) to allot for block & undo files - int64_t nSignedPruneTarget = GetArg("-prune", 0) * 1024 * 1024; - if (nSignedPruneTarget < 0) { + 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 MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); } @@ -920,39 +1021,61 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RegisterAllCoreRPCCommands(tableRPC); #ifdef ENABLE_WALLET - bool fDisableWallet = GetBoolArg("-disablewallet", false); - if (!fDisableWallet) - RegisterWalletRPCCommands(tableRPC); + RegisterWalletRPCCommands(tableRPC); #endif nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); if (nConnectTimeout <= 0) nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; - // Fee-per-kilobyte amount considered the same as "free" + // Fee-per-kilobyte amount required for mempool acceptance and relay // If you are mining, be careful setting this: // if you set it to zero then // a transaction spammer can cheaply fill blocks using - // 1-satoshi-fee transactions. It should be set above the real + // 0-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(AmountErrMsg("minrelaytxfee", mapArgs["-minrelaytxfee"])); + if (!ParseMoney(GetArg("-minrelaytxfee", ""), 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()); } - fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !Params().RequireStandard()); - if (Params().RequireStandard() && !fRequireStandard) + // 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(GetArg("-blockmintxfee", ""), n)) + return InitError(AmountErrMsg("blockmintxfee", GetArg("-blockmintxfee", ""))); + } + + // Feerate used to define dust. Shouldn't be changed lightly as old + // implementations may inadvertently create non-standard transactions + if (IsArgSet("-dustrelayfee")) + { + CAmount n = 0; + if (!ParseMoney(GetArg("-dustrelayfee", ""), n) || 0 == n) + return InitError(AmountErrMsg("dustrelayfee", GetArg("-dustrelayfee", ""))); + dustRelayFee = CFeeRate(n); + } + + 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); #ifdef ENABLE_WALLET if (!CWallet::ParameterInteraction()) return false; -#endif // ENABLE_WALLET +#endif fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); @@ -964,10 +1087,16 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM); + 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) && mapArgs.count("-mempoolreplacement")) { + if ((!fEnableReplacement) && IsArgSet("-mempoolreplacement")) { // Minimal effort at forwards compatibility std::string strReplacementModeList = GetArg("-mempoolreplacement", ""); // default is impossible std::vector<std::string> vstrReplacementModes; @@ -975,36 +1104,101 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fEnableReplacement = (std::find(vstrReplacementModes.begin(), vstrReplacementModes.end(), "fee") != vstrReplacementModes.end()); } - // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log - - // 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))); + if (gArgs.IsArgSet("-bip9params")) { + // Allow overriding BIP9 parameters for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError("BIP9 parameters may only be overridden on regtest."); + } + for (const std::string& strDeployment : gArgs.GetArgs("-bip9params")) { + std::vector<std::string> vDeploymentParams; + boost::split(vDeploymentParams, strDeployment, 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) { + UpdateBIP9Parameters(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(); // 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. + fs::path pathLockFile = GetDataDir() / ".lock"; + FILE* file = fsbridge::fopen(pathLockFile, "a"); // empty lock file; created if it doesn't exist. if (file) fclose(file); try { static boost::interprocess::file_lock lock(pathLockFile.string().c_str()); - if (!lock.try_lock()) + 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. %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", logCategories == BCLog::NONE)) { + // 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(); + } if (fPrintToDebugLog) OpenDebugLog(); @@ -1012,10 +1206,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) 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) { @@ -1032,7 +1227,7 @@ 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); if (!AppInitServers(threadGroup)) @@ -1043,22 +1238,32 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 5: verify wallet database integrity #ifdef ENABLE_WALLET - if (!fDisableWallet) { - if (!CWallet::Verify()) - return false; - } // (!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()); // sanitize comments per BIP-0014, format user agent and check total size - std::vector<string> uacomments; - BOOST_FOREACH(string cmt, mapMultiArgs["-uacomment"]) - { - if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) - return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt)); - uacomments.push_back(SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)); + std::vector<std::string> uacomments; + if (gArgs.IsArgSet("-uacomment")) { + BOOST_FOREACH(std::string cmt, gArgs.GetArgs("-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) { @@ -1066,9 +1271,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) strSubVersion.size(), MAX_SUBVERSION_LENGTH)); } - if (mapArgs.count("-onlynet")) { + if (gArgs.IsArgSet("-onlynet")) { std::set<enum Network> nets; - BOOST_FOREACH(const std::string& snet, mapMultiArgs["-onlynet"]) { + BOOST_FOREACH(const std::string& snet, gArgs.GetArgs("-onlynet")) { enum Network net = ParseNetwork(snet); if (net == NET_UNROUTABLE) return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet)); @@ -1081,24 +1286,33 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } - if (mapArgs.count("-whitelist")) { - BOOST_FOREACH(const std::string& net, mapMultiArgs["-whitelist"]) { - CSubNet subnet(net); + if (gArgs.IsArgSet("-whitelist")) { + BOOST_FOREACH(const std::string& net, gArgs.GetArgs("-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); } } + // Check for host lookup allowed before parsing any network related parameters + fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP); + 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") { - proxyType addrProxy = proxyType(CService(proxyArg, 9050), proxyRandomize); + CService proxyAddr; + if (!Lookup(proxyArg.c_str(), proxyAddr, 9050, fNameLookup)) { + return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg)); + } + + proxyType addrProxy = proxyType(proxyAddr, proxyRandomize); if (!addrProxy.IsValid()) - return InitError(strprintf(_("Invalid -proxy address: '%s'"), proxyArg)); + return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg)); SetProxy(NET_IPV4, addrProxy); SetProxy(NET_IPV6, addrProxy); @@ -1115,9 +1329,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (onionArg == "0") { // Handle -noonion/-onion=0 SetLimited(NET_TOR); // set onions as unreachable } else { - proxyType addrOnion = proxyType(CService(onionArg, 9050), proxyRandomize); + CService onionProxy; + if (!Lookup(onionArg.c_str(), onionProxy, 9050, fNameLookup)) { + return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg)); + } + proxyType addrOnion = proxyType(onionProxy, proxyRandomize); if (!addrOnion.IsValid()) - return InitError(strprintf(_("Invalid -onion address: '%s'"), onionArg)); + return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg)); SetProxy(NET_TOR, addrOnion); SetLimited(NET_TOR, false); } @@ -1126,39 +1344,40 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // see Step 2: parameter interactions for more information about these fListen = GetBoolArg("-listen", DEFAULT_LISTEN); fDiscover = GetBoolArg("-discover", 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(const std::string& strBind, mapMultiArgs["-bind"]) { + bool fBound = false; + if (gArgs.IsArgSet("-bind")) { + BOOST_FOREACH(const std::string& strBind, gArgs.GetArgs("-bind")) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) return InitError(ResolveErrMsg("bind", strBind)); - fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); + fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); } - BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) { + } + if (gArgs.IsArgSet("-whitebind")) { + BOOST_FOREACH(const std::string& strBind, gArgs.GetArgs("-whitebind")) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, 0, false)) 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 (!gArgs.IsArgSet("-bind") && !gArgs.IsArgSet("-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(const std::string& strAddr, mapMultiArgs["-externalip"]) { + if (gArgs.IsArgSet("-externalip")) { + BOOST_FOREACH(const std::string& strAddr, gArgs.GetArgs("-externalip")) { CService addrLocal; if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid()) AddLocal(addrLocal, LOCAL_MANUAL); @@ -1167,18 +1386,23 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } - BOOST_FOREACH(const std::string& strDest, mapMultiArgs["-seednode"]) - AddOneShot(strDest); + if (gArgs.IsArgSet("-seednode")) { + BOOST_FOREACH(const std::string& strDest, gArgs.GetArgs("-seednode")) + connman.AddOneShot(strDest); + } #if ENABLE_ZMQ - pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs); + pzmqNotificationInterface = CZMQNotificationInterface::Create(); if (pzmqNotificationInterface) { RegisterValidationInterface(pzmqNotificationInterface); } #endif - if (mapArgs.count("-maxuploadtarget")) { - CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024); + 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 @@ -1186,37 +1410,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) 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"; - if (!boost::filesystem::exists(blocksDir)) - { - boost::filesystem::create_directories(blocksDir); - bool linked = false; - for (unsigned int i = 1; i < 10000; i++) { - boost::filesystem::path source = GetDataDir() / strprintf("blk%04u.dat", i); - if (!boost::filesystem::exists(source)) break; - boost::filesystem::path dest = blocksDir / strprintf("blk%05u.dat", i-1); - try { - boost::filesystem::create_hard_link(source, dest); - LogPrintf("Hardlinked %s -> %s\n", source.string(), dest.string()); - linked = true; - } catch (const boost::filesystem::filesystem_error& e) { - // Note: hardlink creation failing is not a disaster, it just means - // blocks will get re-downloaded from peers. - LogPrintf("Error hardlinking blk%04u.dat: %s\n", i, e.what()); - break; - } - } - if (linked) - { - fReindex = true; - } - } + fs::create_directories(GetDataDir() / "blocks"); // 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; nBlockTreeDBCache = std::min(nBlockTreeDBCache, (GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20); nTotalCache -= nBlockTreeDBCache; @@ -1224,10 +1423,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) 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) { @@ -1257,7 +1457,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) CleanupBlockRevFiles(); } - if (!LoadBlockIndex()) { + if (!LoadBlockIndex(chainparams)) { strLoadError = _("Error loading block database"); break; } @@ -1286,7 +1486,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) break; } - if (!fReindex) { + 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"); @@ -1303,6 +1503,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) { 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. " @@ -1317,7 +1518,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) break; } } catch (const std::exception& e) { - if (fDebug) LogPrintf("%s\n", e.what()); + LogPrintf("%s\n", e.what()); strLoadError = _("Error opening block database"); break; } @@ -1355,26 +1556,20 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart); - boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; - CAutoFile est_filein(fopen(est_path.string().c_str(), "rb"), SER_DISK, CLIENT_VERSION); + fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; + CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION); // Allowed to fail as this file IS missing on first startup. if (!est_filein.IsNull()) - mempool.ReadFeeEstimates(est_filein); + ::feeEstimator.Read(est_filein); fFeeEstimatesInitialized = true; // ********************************************************* Step 8: load wallet #ifdef ENABLE_WALLET - if (fDisableWallet) { - pwalletMain = NULL; - LogPrintf("Wallet disabled!\n"); - } else { - CWallet::InitLoadWallet(); - if (!pwalletMain) - return false; - } -#else // ENABLE_WALLET + if (!CWallet::InitLoadWallet()) + return false; +#else LogPrintf("No wallet support compiled in!\n"); -#endif // !ENABLE_WALLET +#endif // ********************************************************* Step 9: data directory maintenance @@ -1389,8 +1584,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } - if (Params().GetConsensus().vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) { - // Only advertize witness capabilities if they have a reasonable start time. + if (chainparams.GetConsensus().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 @@ -1403,51 +1598,69 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 10: import blocks - if (mapArgs.count("-blocknotify")) + if (!CheckDiskSpace()) + return false; + + // 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 (IsArgSet("-blocknotify")) uiInterface.NotifyBlockTip.connect(BlockNotifyCallback); - std::vector<boost::filesystem::path> vImportFiles; - if (mapArgs.count("-loadblock")) + std::vector<fs::path> vImportFiles; + if (gArgs.IsArgSet("-loadblock")) { - BOOST_FOREACH(const std::string& strFile, mapMultiArgs["-loadblock"]) + BOOST_FOREACH(const std::string& strFile, gArgs.GetArgs("-loadblock")) vImportFiles.push_back(strFile); } + threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); // Wait for genesis block to be processed - bool fHaveGenesis = false; - while (!fHaveGenesis && !fRequestShutdown) { - { - LOCK(cs_main); - fHaveGenesis = (chainActive.Tip() != NULL); - } - - if (!fHaveGenesis) { - MilliSleep(10); + { + boost::unique_lock<boost::mutex> lock(cs_GenesisWait); + while (!fHaveGenesis) { + condvar_GenesisWait.wait(lock); } + uiInterface.NotifyBlockTip.disconnect(BlockNotifyGenesisWait); } // ********************************************************* Step 11: start node - if (!CheckDiskSpace()) - return false; - - if (!strErrors.str().empty()) - return InitError(strErrors.str()); - //// 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); + + // Map ports with UPnP + MapPort(GetBoolArg("-upnp", DEFAULT_UPNP)); + + 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); + + connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe; + connOptions.nMaxOutboundLimit = nMaxOutboundLimit; + + if (!connman.Start(scheduler, strNodeError, connOptions)) + return InitError(strNodeError); // ********************************************************* Step 12: finished @@ -1455,13 +1668,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) 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(scheduler); #endif return !fRequestShutdown; |