diff --git a/configure.ac b/configure.ac index e7fb4a927..84c66624b 100644 --- a/configure.ac +++ b/configure.ac @@ -178,12 +178,13 @@ AC_ARG_ENABLE([debug], [enable_debug=no]) if test "x$enable_debug" = xyes; then + CPPFLAGS="$CPPFLAGS -DDEBUG -DDEBUG_LOCKORDER" if test "x$GCC" = xyes; then - CFLAGS="-g3 -O0 -DDEBUG" + CFLAGS="$CFLAGS -g3 -O0" fi if test "x$GXX" = xyes; then - CXXFLAGS="-g3 -O0 -DDEBUG" + CXXFLAGS="$CXXFLAGS -g3 -O0" fi fi @@ -193,7 +194,7 @@ fi if test "x$CXXFLAGS_overridden" = "xno"; then CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter -Wno-self-assign" fi -CPPFLAGS="$CPPFLAGS -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" +CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" AC_ARG_WITH([utils], [AS_HELP_STRING([--with-utils], diff --git a/contrib/init/bitcoind.openrc b/contrib/init/bitcoind.openrc index a94f03680..eda1a96fb 100644 --- a/contrib/init/bitcoind.openrc +++ b/contrib/init/bitcoind.openrc @@ -32,7 +32,11 @@ required_files="${BITCOIND_CONFIGFILE}" start_stop_daemon_args="-u ${BITCOIND_USER} \ -N ${BITCOIND_NICE} -w 2000" pidfile="${BITCOIND_PIDFILE}" -retry=60 + +# The retry schedule to use when stopping the daemon. Could be either +# a timeout in seconds or multiple signal/timeout pairs (like +# "SIGKILL/180 SIGTERM/300") +retry="${BITCOIND_SIGTERM_TIMEOUT}" depend() { need localmount net diff --git a/contrib/init/bitcoind.openrcconf b/contrib/init/bitcoind.openrcconf index d8d7f5833..0cbff6d30 100644 --- a/contrib/init/bitcoind.openrcconf +++ b/contrib/init/bitcoind.openrcconf @@ -25,3 +25,9 @@ # Additional options (avoid -conf and -datadir, use flags above) BITCOIND_OPTS="-disablewallet" +# The timeout in seconds OpenRC will wait for bitcoind to terminate +# after a SIGTERM has been raised. +# Note that this will be mapped as argument to start-stop-daemon's +# '--retry' option, which means you can specify a retry schedule +# here. For more information see man 8 start-stop-daemon. +BITCOIND_SIGTERM_TIMEOUT=60 diff --git a/contrib/linearize/README.md b/contrib/linearize/README.md index 157586e4d..06f278f3b 100644 --- a/contrib/linearize/README.md +++ b/contrib/linearize/README.md @@ -3,7 +3,7 @@ Construct a linear, no-fork, best version of the blockchain. ## Step 1: Download hash list - $ ./linearize-hashes.py linearize.cfg > hashlist.txt + $ ./linearize-hashes.py linearize.cfg > hashlist.txt Required configuration file settings for linearize-hashes: * RPC: rpcuser, rpcpassword @@ -14,7 +14,7 @@ Optional config file setting for linearize-hashes: ## Step 2: Copy local block data - $ ./linearize-data.py linearize.cfg + $ ./linearize-data.py linearize.cfg Required configuration file settings: * "input": bitcoind blocks/ directory containing blkNNNNN.dat @@ -26,7 +26,7 @@ output. Optional config file setting for linearize-data: * "netmagic": network magic number -* "max_out_sz": maximum output file size (default 1000*1000*1000) +* "max_out_sz": maximum output file size (default `1000*1000*1000`) * "split_timestamp": Split files when a new month is first seen, in addition to reaching a maximum file size. * "file_timestamp": Set each file's last-modified time to that of the diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py index 7947c6bf7..0f6fde2a6 100755 --- a/contrib/linearize/linearize-data.py +++ b/contrib/linearize/linearize-data.py @@ -12,6 +12,7 @@ import json import struct import re import os +import os.path import base64 import httplib import sys @@ -115,19 +116,20 @@ class BlockDataCopier: self.setFileTime = True if settings['split_timestamp'] != 0: self.timestampSplit = True - # Extents and cache for out-of-order blocks + # Extents and cache for out-of-order blocks self.blockExtents = {} self.outOfOrderData = {} self.outOfOrderSize = 0 # running total size for items in outOfOrderData def writeBlock(self, inhdr, blk_hdr, rawblock): - if not self.fileOutput and ((self.outsz + self.inLen) > self.maxOutSz): + blockSizeOnDisk = len(inhdr) + len(blk_hdr) + len(rawblock) + if not self.fileOutput and ((self.outsz + blockSizeOnDisk) > self.maxOutSz): self.outF.close() if self.setFileTime: os.utime(outFname, (int(time.time()), highTS)) self.outF = None self.outFname = None - self.outFn = outFn + 1 + self.outFn = self.outFn + 1 self.outsz = 0 (blkDate, blkTS) = get_blk_dt(blk_hdr) @@ -147,7 +149,7 @@ class BlockDataCopier: if self.fileOutput: outFname = self.settings['output_file'] else: - outFname = "%s/blk%05d.dat" % (self.settings['output'], outFn) + outFname = os.path.join(self.settings['output'], "blk%05d.dat" % self.outFn) print("Output file " + outFname) self.outF = open(outFname, "wb") @@ -165,7 +167,7 @@ class BlockDataCopier: (self.blkCountIn, self.blkCountOut, len(self.blkindex), 100.0 * self.blkCountOut / len(self.blkindex))) def inFileName(self, fn): - return "%s/blk%05d.dat" % (self.settings['input'], fn) + return os.path.join(self.settings['input'], "blk%05d.dat" % fn) def fetchBlock(self, extent): '''Fetch block contents from disk given extents''' diff --git a/qa/rpc-tests/proxy_test.py b/qa/rpc-tests/proxy_test.py index 9a9b2f530..3623c1616 100755 --- a/qa/rpc-tests/proxy_test.py +++ b/qa/rpc-tests/proxy_test.py @@ -68,10 +68,10 @@ class ProxyTest(BitcoinTestFramework): ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'], ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'], ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'], - ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0'] + ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion'] ]) - def node_test(self, node, proxies, auth): + def node_test(self, node, proxies, auth, test_onion=True): rv = [] # Test: outgoing IPv4 connection through node node.addnode("15.61.23.23:1234", "onetry") @@ -99,17 +99,18 @@ class ProxyTest(BitcoinTestFramework): assert_equal(cmd.password, None) rv.append(cmd) - # Test: outgoing onion connection through node - node.addnode("bitcoinostk4e4re.onion:8333", "onetry") - cmd = proxies[2].queue.get() - assert(isinstance(cmd, Socks5Command)) - assert_equal(cmd.atyp, AddressType.DOMAINNAME) - assert_equal(cmd.addr, "bitcoinostk4e4re.onion") - assert_equal(cmd.port, 8333) - if not auth: - assert_equal(cmd.username, None) - assert_equal(cmd.password, None) - rv.append(cmd) + if test_onion: + # Test: outgoing onion connection through node + node.addnode("bitcoinostk4e4re.onion:8333", "onetry") + cmd = proxies[2].queue.get() + assert(isinstance(cmd, Socks5Command)) + assert_equal(cmd.atyp, AddressType.DOMAINNAME) + assert_equal(cmd.addr, "bitcoinostk4e4re.onion") + assert_equal(cmd.port, 8333) + if not auth: + assert_equal(cmd.username, None) + assert_equal(cmd.password, None) + rv.append(cmd) # Test: outgoing DNS name connection through node node.addnode("node.noumenon:8333", "onetry") @@ -139,8 +140,41 @@ class ProxyTest(BitcoinTestFramework): assert_equal(len(credentials), 4) # proxy on IPv6 localhost - self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3], False) + self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3], False, False) + + def networks_dict(d): + r = {} + for x in d['networks']: + r[x['name']] = x + return r + + # test RPC getnetworkinfo + n0 = networks_dict(self.nodes[0].getnetworkinfo()) + for net in ['ipv4','ipv6','onion']: + assert_equal(n0[net]['proxy'], '%s:%i' % (self.conf1.addr)) + assert_equal(n0[net]['proxy_randomize_credentials'], True) + assert_equal(n0['onion']['reachable'], True) + + n1 = networks_dict(self.nodes[1].getnetworkinfo()) + for net in ['ipv4','ipv6']: + assert_equal(n1[net]['proxy'], '%s:%i' % (self.conf1.addr)) + assert_equal(n1[net]['proxy_randomize_credentials'], False) + assert_equal(n1['onion']['proxy'], '%s:%i' % (self.conf2.addr)) + assert_equal(n1['onion']['proxy_randomize_credentials'], False) + assert_equal(n1['onion']['reachable'], True) + n2 = networks_dict(self.nodes[2].getnetworkinfo()) + for net in ['ipv4','ipv6','onion']: + assert_equal(n2[net]['proxy'], '%s:%i' % (self.conf2.addr)) + assert_equal(n2[net]['proxy_randomize_credentials'], True) + assert_equal(n2['onion']['reachable'], True) + + n3 = networks_dict(self.nodes[3].getnetworkinfo()) + for net in ['ipv4','ipv6']: + assert_equal(n3[net]['proxy'], '[%s]:%i' % (self.conf3.addr)) + assert_equal(n3[net]['proxy_randomize_credentials'], False) + assert_equal(n3['onion']['reachable'], False) + if __name__ == '__main__': ProxyTest().main() diff --git a/src/addrman.h b/src/addrman.h index cde9430ae..2a08076b7 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -470,7 +470,7 @@ public: } //! Return the number of (unique) addresses in all tables. - int size() + size_t size() const { return vRandom.size(); } diff --git a/src/alert.cpp b/src/alert.cpp index 6e41b11a2..ea9cbad21 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -50,7 +50,7 @@ std::string CUnsignedAlert::ToString() const BOOST_FOREACH(int n, setCancel) strSetCancel += strprintf("%d ", n); std::string strSetSubVer; - BOOST_FOREACH(std::string str, setSubVer) + BOOST_FOREACH(const std::string& str, setSubVer) strSetSubVer += "\"" + str + "\" "; return strprintf( "CAlert(\n" @@ -112,7 +112,7 @@ bool CAlert::Cancels(const CAlert& alert) const return (alert.nID <= nCancel || setCancel.count(alert.nID)); } -bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const +bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const { // TODO: rework for client-version-embedded-in-strSubVer ? return (IsInEffect() && diff --git a/src/alert.h b/src/alert.h index b5e1cd110..76d8d916e 100644 --- a/src/alert.h +++ b/src/alert.h @@ -97,7 +97,7 @@ public: uint256 GetHash() const; bool IsInEffect() const; bool Cancels(const CAlert& alert) const; - bool AppliesTo(int nVersion, std::string strSubVerIn) const; + bool AppliesTo(int nVersion, const std::string& strSubVerIn) const; bool AppliesToMe() const; bool RelayTo(CNode* pnode) const; bool CheckSignature(const std::vector& alertKey) const; diff --git a/src/amount.h b/src/amount.h index 9212244a8..7dc62edac 100644 --- a/src/amount.h +++ b/src/amount.h @@ -16,7 +16,15 @@ typedef int64_t CAmount; static const CAmount COIN = 100000000; static const CAmount CENT = 1000000; -/** No amount larger than this (in satoshi) is valid */ +/** No amount larger than this (in satoshi) is valid. + * + * Note that this constant is *not* the total money supply, which in Bitcoin + * currently happens to be less than 21,000,000 BTC for various reasons, but + * rather a sanity check. As this sanity check is used by consensus-critical + * validation code, the exact value of the MAX_MONEY constant is consensus + * critical; in unusual circumstances like a(nother) overflow bug that allowed + * for the creation of coins out of thin air modification could lead to a fork. + * */ static const CAmount MAX_MONEY = 21000000 * COIN; inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } diff --git a/src/base58.h b/src/base58.h index d3967ec4e..88efadbd6 100644 --- a/src/base58.h +++ b/src/base58.h @@ -171,7 +171,10 @@ public: K GetKey() { K ret; - ret.Decode(&vchData[0], &vchData[Size]); + if (vchData.size() == Size) { + //if base58 encouded data not holds a ext key, return a !IsValid() key + ret.Decode(&vchData[0]); + } return ret; } @@ -179,6 +182,10 @@ public: SetKey(key); } + CBitcoinExtKeyBase(const std::string& strBase58c) { + SetString(strBase58c.c_str(), Params().Base58Prefix(Type).size()); + } + CBitcoinExtKeyBase() {} }; diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 6e54cd97a..0e692622b 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -200,6 +200,15 @@ int CommandLineRPC(int argc, char *argv[]) throw CConnectionFailed("server in warmup"); strPrint = "error: " + error.write(); nRet = abs(code); + if (error.isObject()) + { + UniValue errCode = find_value(error, "code"); + UniValue errMsg = find_value(error, "message"); + strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n"; + + if (errMsg.isStr()) + strPrint += "error message:\n"+errMsg.get_str(); + } } else { // Result if (result.isNull()) diff --git a/src/chain.cpp b/src/chain.cpp index 719256106..5b8ce076c 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -82,9 +82,10 @@ CBlockIndex* CBlockIndex::GetAncestor(int height) while (heightWalk > height) { int heightSkip = GetSkipHeight(heightWalk); int heightSkipPrev = GetSkipHeight(heightWalk - 1); - if (heightSkip == height || - (heightSkip > height && !(heightSkipPrev < heightSkip - 2 && - heightSkipPrev >= height))) { + if (pindexWalk->pskip != NULL && + (heightSkip == height || + (heightSkip > height && !(heightSkipPrev < heightSkip - 2 && + heightSkipPrev >= height)))) { // Only follow pskip if pprev->pskip isn't better than pskip->pprev. pindexWalk = pindexWalk->pskip; heightWalk = heightSkip; diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 202448613..87f4ad7f2 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -24,15 +24,6 @@ namespace Checkpoints { */ static const double SIGCHECK_VERIFICATION_FACTOR = 5.0; - bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash) - { - const MapCheckpoints& checkpoints = data.mapCheckpoints; - - MapCheckpoints::const_iterator i = checkpoints.find(nHeight); - if (i == checkpoints.end()) return true; - return hash == i->second; - } - //! Guess how far we are in the verification process at the given block index double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex *pindex, bool fSigchecks) { if (pindex==NULL) diff --git a/src/checkpoints.h b/src/checkpoints.h index a720f096c..001e3cc80 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -26,9 +26,6 @@ struct CCheckpointData { double fTransactionsPerDay; }; -//! Returns true if block passes checkpoint checks -bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash); - //! Return conservative estimate of total number of blocks, 0 if unknown int GetTotalBlocksEstimate(const CCheckpointData& data); diff --git a/src/consensus/validation.h b/src/consensus/validation.h index d0ea30bf4..c62adcd8f 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -48,7 +48,7 @@ public: unsigned char _chRejectCode=0, std::string _strRejectReason="") { return DoS(0, ret, _chRejectCode, _strRejectReason); } - virtual bool Error(std::string strRejectReasonIn="") { + virtual bool Error(const std::string& strRejectReasonIn) { if (mode == MODE_VALID) strRejectReason = strRejectReasonIn; mode = MODE_ERROR; diff --git a/src/core_io.h b/src/core_io.h index 0989cf743..115e3199d 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -15,7 +15,7 @@ class uint256; class UniValue; // core_read.cpp -extern CScript ParseScript(std::string s); +extern CScript ParseScript(const std::string& s); extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); extern bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); extern uint256 ParseHashUV(const UniValue& v, const std::string& strName); diff --git a/src/core_read.cpp b/src/core_read.cpp index 1b3e9025d..4be24f8e0 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -22,7 +22,7 @@ using namespace std; -CScript ParseScript(std::string s) +CScript ParseScript(const std::string& s) { CScript result; diff --git a/src/init.cpp b/src/init.cpp index cff7bfd90..5d7f4d3f1 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -357,7 +357,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-timeout=", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT)); #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 @@ -387,7 +387,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-walletnotify=", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); strUsage += HelpMessageOpt("-zapwallettxes=", _("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)")); - #endif #if ENABLE_ZMQ @@ -401,7 +400,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Debugging/Testing options:")); if (showDebug) { - strUsage += HelpMessageOpt("-checkpoints", strprintf("Only accept block chain matching built-in checkpoints (default: %u)", 1)); + strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", 1)); strUsage += HelpMessageOpt("-dblogsize=", strprintf("Flush database activity from memory pool to disk log every 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)); @@ -446,6 +445,8 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-blockminsize=", strprintf(_("Set minimum block size in bytes (default: %u)"), 0)); strUsage += HelpMessageOpt("-blockmaxsize=", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE)); strUsage += HelpMessageOpt("-blockprioritysize=", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE)); + if (GetBoolArg("-help-debug", false)) + strUsage += HelpMessageOpt("-blockversion=", strprintf("Override block version to test forking scenarios (default: %d)", (int)CBlock::CURRENT_VERSION)); #ifdef ENABLE_MINING strUsage += HelpMessageGroup(_("Mining options:")); @@ -612,7 +613,7 @@ void ThreadImport(std::vector 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; @@ -766,6 +767,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fLogTimestamps = GetBoolArg("-logtimestamps", true); fLogIPs = GetBoolArg("-logips", false); + LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + LogPrintf("Zcash version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); + // when specifying an explicit binding address, you want to listen on it // even when -connect or -proxy is specified if (mapArgs.count("-bind")) { @@ -1030,8 +1034,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #endif if (GetBoolArg("-shrinkdebugfile", !fDebug)) ShrinkDebugFile(); - LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - LogPrintf("Zcash version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); + + if (fPrintToDebugLog) + OpenDebugLog(); + LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION)); #ifdef ENABLE_WALLET LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); @@ -1096,15 +1102,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) 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 // ********************************************************* Step 6: network initialization @@ -1113,7 +1119,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (mapArgs.count("-onlynet")) { std::set nets; - BOOST_FOREACH(std::string snet, mapMultiArgs["-onlynet"]) { + BOOST_FOREACH(const std::string& snet, mapMultiArgs["-onlynet"]) { enum Network net = ParseNetwork(snet); if (net == NET_UNROUTABLE) return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet)); @@ -1135,31 +1141,36 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } - proxyType addrProxy; - bool fProxy = false; - if (mapArgs.count("-proxy")) { - addrProxy = proxyType(CService(mapArgs["-proxy"], 9050), GetBoolArg("-proxyrandomize", true)); + bool proxyRandomize = GetBoolArg("-proxyrandomize", true); + // -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", ""); + if (proxyArg != "" && proxyArg != "0") { + proxyType addrProxy = proxyType(CService(proxyArg, 9050), 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; + SetReachable(NET_TOR); // 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 + SetReachable(NET_TOR, false); // set onions as unreachable + } else { + proxyType addrOnion = proxyType(CService(onionArg, 9050), proxyRandomize); + if (!addrOnion.IsValid()) + return InitError(strprintf(_("Invalid -onion address: '%s'"), onionArg)); + SetProxy(NET_TOR, addrOnion); + SetReachable(NET_TOR); + } } // see Step 2: parameter interactions for more information about these @@ -1170,13 +1181,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) bool fBound = false; if (fListen) { if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) { - BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) { + BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-bind"]) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind)); fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); } - BOOST_FOREACH(std::string strBind, mapMultiArgs["-whitebind"]) { + BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, 0, false)) return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind)); @@ -1196,7 +1207,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } if (mapArgs.count("-externalip")) { - BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"]) { + BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-externalip"]) { CService addrLocal(strAddr, GetListenPort(), fNameLookup); if (!addrLocal.IsValid()) return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr)); @@ -1204,7 +1215,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } - BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"]) + BOOST_FOREACH(const std::string& strDest, mapMultiArgs["-seednode"]) AddOneShot(strDest); #if ENABLE_ZMQ @@ -1572,7 +1583,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) std::vector vImportFiles; if (mapArgs.count("-loadblock")) { - BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"]) + BOOST_FOREACH(const std::string& strFile, mapMultiArgs["-loadblock"]) vImportFiles.push_back(strFile); } threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); diff --git a/src/main.cpp b/src/main.cpp index 207c0d458..4e9230c51 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -740,7 +740,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags) /** * Check transaction inputs to mitigate two * potential denial-of-service attacks: - * + * * 1. scriptSigs with extra data stuffed into them, * not consumed by scriptPubKey (or P2SH script) * 2. P2SH scripts with a crazy number of expensive @@ -1607,13 +1607,16 @@ bool CScriptCheck::operator()() { return true; } -bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector *pvChecks) +int GetSpendHeight(const CCoinsViewCache& inputs) { - if (!tx.IsCoinBase()) - { - if (pvChecks) - pvChecks->reserve(tx.vin.size()); + LOCK(cs_main); + CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; + return pindexPrev->nHeight + 1; +} +namespace Consensus { +bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams) +{ // This doesn't trigger the DoS code on purpose; if it did, it would make it easier // for an attacker to attempt to split the network. if (!inputs.HaveInputs(tx)) @@ -1632,6 +1635,13 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c assert(coins); if (coins->IsCoinBase()) { + // Ensure that coinbases are matured + if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) { + return state.Invalid( + error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight), + REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); + } + // Ensure that coinbases cannot be spent to transparent outputs // Disabled on regtest if (fCoinbaseEnforcedProtectionEnabled && @@ -1670,6 +1680,19 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c if (!MoneyRange(nFees)) return state.DoS(100, error("CheckInputs(): nFees out of range"), REJECT_INVALID, "bad-txns-fee-outofrange"); + return true; +} +}// namespace Consensus + +bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector *pvChecks) +{ + if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs), consensusParams)) + return false; + + if (!tx.IsCoinBase()) + { + if (pvChecks) + pvChecks->reserve(tx.vin.size()); // The first loop above does all the inexpensive checks. // Only if ALL inputs pass do we perform expensive ECDSA signature checks. @@ -1718,40 +1741,6 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c return true; } -bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector *pvChecks) -{ - if (!NonContextualCheckInputs(tx, state, inputs, fScriptChecks, flags, cacheStore, consensusParams, pvChecks)) { - return false; - } - - if (!tx.IsCoinBase()) - { - // While checking, GetBestBlock() refers to the parent block. - // This is also true for mempool checks. - CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; - int nSpendHeight = pindexPrev->nHeight + 1; - for (unsigned int i = 0; i < tx.vin.size(); i++) - { - const COutPoint &prevout = tx.vin[i].prevout; - const CCoins *coins = inputs.AccessCoins(prevout.hash); - // Assertion is okay because NonContextualCheckInputs ensures the inputs - // are available. - assert(coins); - - // If prev is coinbase, check that it's matured - if (coins->IsCoinBase()) { - if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) { - return state.Invalid( - error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight), - REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); - } - } - } - } - - return true; -} - namespace { bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart) @@ -2044,7 +2033,15 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); - bool fExpensiveChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints())); + bool fExpensiveChecks = true; + if (fCheckpointsEnabled) { + CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints()); + if (pindexLastCheckpoint && pindexLastCheckpoint->GetAncestor(pindex->nHeight) == pindex) { + // This block is an ancestor of a checkpoint: disable script checks + fExpensiveChecks = false; + } + } + auto verifier = libzcash::ProofVerifier::Strict(); auto disabledVerifier = libzcash::ProofVerifier::Disabled(); @@ -2457,7 +2454,7 @@ static int64_t nTimeFlush = 0; static int64_t nTimeChainState = 0; static int64_t nTimePostConnect = 0; -/** +/** * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock * corresponding to pindexNew, to bypass loading it again from disk. */ @@ -2481,7 +2478,6 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); { CCoinsViewCache view(pcoinsTip); - CInv inv(MSG_BLOCK, pindexNew->GetBlockHash()); bool rv = ConnectBlock(*pblock, state, pindexNew, view); GetMainSignals().BlockChecked(*pblock, state); if (!rv) { @@ -2489,7 +2485,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * InvalidBlockFound(pindexNew, state); return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); } - mapBlockSource.erase(inv.hash); + mapBlockSource.erase(pindexNew->GetBlockHash()); nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2; LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001); assert(view.Flush()); @@ -3066,13 +3062,8 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta return state.Invalid(error("%s: block's timestamp is too early", __func__), REJECT_INVALID, "time-too-old"); - if(fCheckpointsEnabled) + if (fCheckpointsEnabled) { - // Check that the block chain matches the known block chain up to a checkpoint - if (!Checkpoints::CheckBlock(chainParams.Checkpoints(), nHeight, hash)) - return state.DoS(100, error("%s: rejected by checkpoint lock-in at %d", __func__, nHeight), - REJECT_CHECKPOINT, "checkpoint mismatch"); - // Don't accept any forks from the main chain prior to last checkpoint CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints()); if (pcheckpoint && nHeight < pcheckpoint->nHeight) @@ -4072,7 +4063,7 @@ void static CheckBlockIndex() // CAlert // -string GetWarnings(string strFor) +std::string GetWarnings(const std::string& strFor) { int nPriority = 0; string strStatusBar; diff --git a/src/main.h b/src/main.h index 289e908d2..886542db7 100644 --- a/src/main.h +++ b/src/main.h @@ -145,7 +145,7 @@ extern bool fPruneMode; /** Number of MiB of block files that we're trying to stay below. */ extern uint64_t nPruneTarget; /** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */ -static const signed int MIN_BLOCKS_TO_KEEP = 288; +static const unsigned int MIN_BLOCKS_TO_KEEP = 288; // Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat) // At 1MB per block, 288 blocks = 288MB. @@ -155,7 +155,7 @@ static const signed int MIN_BLOCKS_TO_KEEP = 288; // full block file chunks, we need the high water mark which triggers the prune to be // one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB // Setting the target to > than 550MB will make it likely we can respect the target. -static const signed int MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024; +static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024; /** Register with a network node to receive its signals */ void RegisterNodeSignals(CNodeSignals& nodeSignals); @@ -207,7 +207,7 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const /** Check whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(); /** Format a string that describes several potential problems detected by the core */ -std::string GetWarnings(std::string strFor); +std::string GetWarnings(const std::string& strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false); /** Find the best known block, and make it the tip of the block chain */ @@ -332,10 +332,6 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector *pvChecks = NULL); -bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks, - unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, - std::vector *pvChecks = NULL); - /** Apply the effects of this transaction on the UTXO set represented by view */ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight); @@ -520,4 +516,15 @@ extern CCoinsViewCache *pcoinsTip; /** Global variable that points to the active block tree (protected by cs_main) */ extern CBlockTreeDB *pblocktree; +/** + * Return the spend height, which is one more than the inputs.GetBestBlock(). + * While checking, GetBestBlock() refers to the parent block. (protected by cs_main) + * This is also true for mempool checks. + */ +int GetSpendHeight(const CCoinsViewCache& inputs); + +namespace Consensus { +bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams); +} + #endif // BITCOIN_MAIN_H diff --git a/src/net.cpp b/src/net.cpp index 0a96d01f2..4ae5a6b2c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -107,7 +107,7 @@ boost::condition_variable messageHandlerCondition; static CNodeSignals g_signals; CNodeSignals& GetNodeSignals() { return g_signals; } -void AddOneShot(string strDest) +void AddOneShot(const std::string& strDest) { LOCK(cs_vOneShots); vOneShots.push_back(strDest); @@ -1316,7 +1316,7 @@ void ThreadDNSAddressSeed() vector vAdd; if (LookupHost(seed.host.c_str(), vIPs)) { - BOOST_FOREACH(CNetAddr& ip, vIPs) + BOOST_FOREACH(const CNetAddr& ip, vIPs) { int nOneDay = 24*3600; CAddress addr = CAddress(CService(ip, Params().GetDefaultPort())); @@ -1380,7 +1380,7 @@ void ThreadOpenConnections() for (int64_t nLoop = 0;; nLoop++) { ProcessOneShot(); - BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"]) + BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"]) { CAddress addr; OpenNetworkConnection(addr, NULL, strAddr.c_str()); @@ -1483,10 +1483,10 @@ void ThreadOpenAddedConnections() list lAddresses(0); { LOCK(cs_vAddedNodes); - BOOST_FOREACH(string& strAddNode, vAddedNodes) + BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) lAddresses.push_back(strAddNode); } - BOOST_FOREACH(string& strAddNode, lAddresses) { + BOOST_FOREACH(const std::string& strAddNode, lAddresses) { CAddress addr; CSemaphoreGrant grant(*semOutbound); OpenNetworkConnection(addr, &grant, strAddNode.c_str()); @@ -1501,20 +1501,19 @@ void ThreadOpenAddedConnections() list lAddresses(0); { LOCK(cs_vAddedNodes); - BOOST_FOREACH(string& strAddNode, vAddedNodes) + BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) lAddresses.push_back(strAddNode); } list > lservAddressesToAdd(0); - BOOST_FOREACH(string& strAddNode, lAddresses) - { + BOOST_FOREACH(const std::string& strAddNode, lAddresses) { vector vservNode(0); if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) { lservAddressesToAdd.push_back(vservNode); { LOCK(cs_setservAddNodeAddresses); - BOOST_FOREACH(CService& serv, vservNode) + BOOST_FOREACH(const CService& serv, vservNode) setservAddNodeAddresses.insert(serv); } } @@ -1525,7 +1524,7 @@ void ThreadOpenAddedConnections() LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) for (list >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++) - BOOST_FOREACH(CService& addrNode, *(it)) + BOOST_FOREACH(const CService& addrNode, *(it)) if (pnode->addr == addrNode) { it = lservAddressesToAdd.erase(it); @@ -2110,7 +2109,7 @@ bool CAddrDB::Read(CAddrMan& addr) unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } -CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fInboundIn) : +CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addrKnown(5000, 0.001), setInventoryKnown(SendBufferSize() / 1000) diff --git a/src/net.h b/src/net.h index 50fb90dca..bf152b832 100644 --- a/src/net.h +++ b/src/net.h @@ -65,7 +65,7 @@ static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ; unsigned int ReceiveFloodSize(); unsigned int SendBufferSize(); -void AddOneShot(std::string strDest); +void AddOneShot(const std::string& strDest); void AddressCurrentlyConnected(const CService& addr); CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const std::string& addrName); @@ -328,7 +328,7 @@ public: // Whether a ping is requested. bool fPingQueued; - CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false); + CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false); ~CNode(); private: diff --git a/src/rest.cpp b/src/rest.cpp index 82155bab1..52d766b3d 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -20,7 +20,7 @@ using namespace std; -static const int MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once +static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once enum RetFormat { RF_UNDEF, diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index dd622444e..b46c939c1 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -651,8 +651,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) UniValue transactions(UniValue::VARR); map setTxIndex; int i = 0; - BOOST_FOREACH (CTransaction& tx, pblock->vtx) - { + BOOST_FOREACH (const CTransaction& tx, pblock->vtx) { uint256 txHash = tx.GetHash(); setTxIndex[txHash] = i++; diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 522edc741..d1c7c1051 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -253,19 +253,20 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) if (params.size() == 1) { LOCK(cs_vAddedNodes); - BOOST_FOREACH(string& strAddNode, vAddedNodes) + BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) laddedNodes.push_back(strAddNode); } else { string strNode = params[1].get_str(); LOCK(cs_vAddedNodes); - BOOST_FOREACH(string& strAddNode, vAddedNodes) + BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) { if (strAddNode == strNode) { laddedNodes.push_back(strAddNode); break; } + } if (laddedNodes.size() == 0) throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); } @@ -273,8 +274,7 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) UniValue ret(UniValue::VARR); if (!fDns) { - BOOST_FOREACH(string& strAddNode, laddedNodes) - { + BOOST_FOREACH (const std::string& strAddNode, laddedNodes) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("addednode", strAddNode)); ret.push_back(obj); @@ -283,8 +283,7 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) } list > > laddedAddreses(0); - BOOST_FOREACH(string& strAddNode, laddedNodes) - { + BOOST_FOREACH(const std::string& strAddNode, laddedNodes) { vector vservNode(0); if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) laddedAddreses.push_back(make_pair(strAddNode, vservNode)); @@ -306,12 +305,11 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) UniValue addresses(UniValue::VARR); bool fConnected = false; - BOOST_FOREACH(CService& addrNode, it->second) - { + BOOST_FOREACH(const CService& addrNode, it->second) { bool fFound = false; UniValue node(UniValue::VOBJ); node.push_back(Pair("address", addrNode.ToString())); - BOOST_FOREACH(CNode* pnode, vNodes) + BOOST_FOREACH(CNode* pnode, vNodes) { if (pnode->addr == addrNode) { fFound = true; @@ -319,6 +317,7 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound")); break; } + } if (!fFound) node.push_back(Pair("connected", "false")); addresses.push_back(node); diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp index 684feb823..ecc1d952a 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpcprotocol.cpp @@ -253,7 +253,6 @@ int ReadHTTPMessage(std::basic_istream& stream, map ParseHexO(const UniValue& o, string strKey) * Note: This interface may still be subject to change. */ -string CRPCTable::help(string strCommand) const +std::string CRPCTable::help(const std::string& strCommand) const { string strRet; string category; @@ -419,7 +419,7 @@ CRPCTable::CRPCTable() } } -const CRPCCommand *CRPCTable::operator[](string name) const +const CRPCCommand *CRPCTable::operator[](const std::string& name) const { map::const_iterator it = mapCommands.find(name); if (it == mapCommands.end()) @@ -1071,11 +1071,13 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms g_rpcSignals.PostCommand(*pcmd); } -std::string HelpExampleCli(string methodname, string args){ +std::string HelpExampleCli(const std::string& methodname, const std::string& args) +{ return "> zcash-cli " + methodname + " " + args + "\n"; } -std::string HelpExampleRpc(string methodname, string args){ +std::string HelpExampleRpc(const std::string& methodname, const std::string& args) +{ return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", " "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8232/\n"; } diff --git a/src/rpcserver.h b/src/rpcserver.h index 6ee17da68..59154954c 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -61,7 +61,7 @@ bool IsRPCRunning(); std::shared_ptr getAsyncRPCQueue(); -/** +/** * Set the RPC warmup status. When this is done, all RPC calls will error out * immediately with RPC_IN_WARMUP. */ @@ -116,8 +116,8 @@ private: std::map mapCommands; public: CRPCTable(); - const CRPCCommand* operator[](std::string name) const; - std::string help(std::string name) const; + const CRPCCommand* operator[](const std::string& name) const; + std::string help(const std::string& name) const; /** * Execute a method. @@ -149,8 +149,8 @@ extern UniValue ValueFromAmount(const CAmount& amount); extern double GetDifficulty(const CBlockIndex* blockindex = NULL); extern double GetNetworkDifficulty(const CBlockIndex* blockindex = NULL); extern std::string HelpRequiringPassphrase(); -extern std::string HelpExampleCli(std::string methodname, std::string args); -extern std::string HelpExampleRpc(std::string methodname, std::string args); +extern std::string HelpExampleCli(const std::string& methodname, const std::string& args); +extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args); extern void EnsureWalletIsUnlocked(); diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp index c32a424f1..d15203945 100644 --- a/src/test/Checkpoints_tests.cpp +++ b/src/test/Checkpoints_tests.cpp @@ -23,21 +23,7 @@ BOOST_FIXTURE_TEST_SUITE(Checkpoints_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sanity) { const Checkpoints::CCheckpointData& checkpoints = Params(CBaseChainParams::MAIN).Checkpoints(); - uint256 p11111 = uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"); - uint256 p134444 = uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"); - BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111, p11111)); - BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444, p134444)); - - - // Wrong hashes at checkpoints should fail: - BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 11111, p134444)); - BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 134444, p11111)); - - // ... but any hash not at a checkpoint should succeed: - BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111+1, p134444)); - BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444+1, p11111)); - BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate(checkpoints) >= 134444); -} +} */ BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 0d815c27f..69084213a 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -88,12 +88,23 @@ void RunTest(const TestVector &test) { unsigned char data[74]; key.Encode(data); pubkey.Encode(data); + // Test private key CBitcoinExtKey b58key; b58key.SetKey(key); BOOST_CHECK(b58key.ToString() == derive.prv); + + CBitcoinExtKey b58keyDecodeCheck(derive.prv); + CExtKey checkKey = b58keyDecodeCheck.GetKey(); + assert(checkKey == key); //ensure a base58 decoded key also matches + // Test public key CBitcoinExtPubKey b58pubkey; b58pubkey.SetKey(pubkey); BOOST_CHECK(b58pubkey.ToString() == derive.pub); + + CBitcoinExtPubKey b58PubkeyDecodeCheck(derive.pub); + CExtPubKey checkPubKey = b58PubkeyDecodeCheck.GetKey(); + assert(checkPubKey == pubkey); //ensure a base58 decoded pubkey also matches + // Derive new keys CExtKey keyNew; BOOST_CHECK(key.Derive(keyNew, derive.nChild)); diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index ea7e81851..67b97a0ba 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -756,7 +756,7 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends) { CTransaction tx2(mtx2); - BOOST_CHECK(NonContextualCheckInputs(tx2, state, cache, false, SCRIPT_VERIFY_NONE, false, Params().GetConsensus())); + BOOST_CHECK(Consensus::CheckTxInputs(tx2, state, cache, 100+COINBASE_MATURITY, Params().GetConsensus())); } mtx2.vout.resize(1); @@ -765,7 +765,7 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends) { CTransaction tx2(mtx2); - BOOST_CHECK(!NonContextualCheckInputs(tx2, state, cache, false, SCRIPT_VERIFY_NONE, false, Params().GetConsensus())); + BOOST_CHECK(!Consensus::CheckTxInputs(tx2, state, cache, 100+COINBASE_MATURITY, Params().GetConsensus())); BOOST_CHECK(state.GetRejectReason() == "bad-txns-coinbase-spend-has-transparent-outputs"); } } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index e9c846485..3f0e3938a 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -176,7 +176,7 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned in continue; const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); if (fSanityCheck) assert(coins); - if (!coins || (coins->IsCoinBase() && nMemPoolHeight - coins->nHeight < COINBASE_MATURITY)) { + if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) { transactionsToRemove.push_back(tx); break; } diff --git a/src/util.cpp b/src/util.cpp index 0023cd380..8ce727609 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -165,23 +165,51 @@ instance_of_cinit; */ static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT; + /** - * We use boost::call_once() to make sure these are initialized - * in a thread-safe manner the first time called: + * We use boost::call_once() to make sure mutexDebugLog and + * vMsgsBeforeOpenLog are initialized in a thread-safe manner. + * + * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog + * are leaked on exit. This is ugly, but will be cleaned up by + * the OS/libc. When the shutdown sequence is fully audited and + * tested, explicit destruction of these objects can be implemented. */ static FILE* fileout = NULL; static boost::mutex* mutexDebugLog = NULL; +static list *vMsgsBeforeOpenLog; + +static int FileWriteStr(const std::string &str, FILE *fp) +{ + return fwrite(str.data(), 1, str.size(), fp); +} static void DebugPrintInit() { - assert(fileout == NULL); assert(mutexDebugLog == NULL); + mutexDebugLog = new boost::mutex(); + vMsgsBeforeOpenLog = new list; +} +void OpenDebugLog() +{ + boost::call_once(&DebugPrintInit, debugPrintInitFlag); + boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); + + assert(fileout == NULL); + assert(vMsgsBeforeOpenLog); boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; fileout = fopen(pathDebug.string().c_str(), "a"); if (fileout) setbuf(fileout, NULL); // unbuffered - mutexDebugLog = new boost::mutex(); + // dump buffered messages from before we opened the log + while (!vMsgsBeforeOpenLog->empty()) { + FileWriteStr(vMsgsBeforeOpenLog->front(), fileout); + vMsgsBeforeOpenLog->pop_front(); + } + + delete vMsgsBeforeOpenLog; + vMsgsBeforeOpenLog = NULL; } bool LogAcceptCategory(const char* category) @@ -213,44 +241,67 @@ bool LogAcceptCategory(const char* category) return true; } +/** + * fStartedNewLine is a state variable held by the calling context that will + * suppress printing of the timestamp when multiple calls are made that don't + * end in a newline. Initialize it to true, and hold it, in the calling context. + */ +static std::string LogTimestampStr(const std::string &str, bool *fStartedNewLine) +{ + string strStamped; + + if (!fLogTimestamps) + return str; + + if (*fStartedNewLine) + strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()) + ' ' + str; + else + strStamped = str; + + if (!str.empty() && str[str.size()-1] == '\n') + *fStartedNewLine = true; + else + *fStartedNewLine = false; + + return strStamped; +} + int LogPrintStr(const std::string &str) { int ret = 0; // Returns total number of characters written + static bool fStartedNewLine = true; if (fPrintToConsole) { // print to console ret = fwrite(str.data(), 1, str.size(), stdout); fflush(stdout); } - else if (fPrintToDebugLog && AreBaseParamsConfigured()) + else if (fPrintToDebugLog) { - static bool fStartedNewLine = true; boost::call_once(&DebugPrintInit, debugPrintInitFlag); - - if (fileout == NULL) - return ret; - boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); - // reopen the log file, if requested - if (fReopenDebugLog) { - fReopenDebugLog = false; - boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; - if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) - setbuf(fileout, NULL); // unbuffered + string strTimestamped = LogTimestampStr(str, &fStartedNewLine); + + // buffer if we haven't opened the log yet + if (fileout == NULL) { + assert(vMsgsBeforeOpenLog); + ret = strTimestamped.length(); + vMsgsBeforeOpenLog->push_back(strTimestamped); } - - // Debug print useful for profiling - if (fLogTimestamps && fStartedNewLine) - ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); - if (!str.empty() && str[str.size()-1] == '\n') - fStartedNewLine = true; else - fStartedNewLine = false; + { + // reopen the log file, if requested + if (fReopenDebugLog) { + fReopenDebugLog = false; + boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; + if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) + setbuf(fileout, NULL); // unbuffered + } - ret = fwrite(str.data(), 1, str.size(), fileout); + ret = FileWriteStr(strTimestamped, fileout); + } } - return ret; } @@ -770,7 +821,7 @@ boost::filesystem::path GetTempPath() { #endif } -void runCommand(std::string strCommand) +void runCommand(const std::string& strCommand) { int nErr = ::system(strCommand.c_str()); if (nErr) diff --git a/src/util.h b/src/util.h index 3e4113164..e4eea2ba1 100644 --- a/src/util.h +++ b/src/util.h @@ -136,8 +136,9 @@ void ReadConfigFile(std::map& mapSettingsRet, std::map boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif boost::filesystem::path GetTempPath(); +void OpenDebugLog(); void ShrinkDebugFile(); -void runCommand(std::string strCommand); +void runCommand(const std::string& strCommand); const boost::filesystem::path GetExportDir(); /** Returns licensing information (for -version) */ diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 142d5a4eb..054992cfb 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -488,7 +488,7 @@ bool ParseDouble(const std::string& str, double *out) return text.eof() && !text.fail(); } -std::string FormatParagraph(const std::string in, size_t width, size_t indent) +std::string FormatParagraph(const std::string& in, size_t width, size_t indent) { std::stringstream out; size_t col = 0; diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index 08d337727..d6973a130 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -89,11 +89,11 @@ inline std::string HexStr(const T& vch, bool fSpaces=false) return HexStr(vch.begin(), vch.end(), fSpaces); } -/** +/** * Format a paragraph of text to a fixed width, adding spaces for * indentation to any added line. */ -std::string FormatParagraph(const std::string in, size_t width=79, size_t indent=0); +std::string FormatParagraph(const std::string& in, size_t width = 79, size_t indent = 0); /** * Timing-attack-resistant comparison. diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 154adca60..b8c983b3a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3148,7 +3148,7 @@ set< set > CWallet::GetAddressGroupings() return ret; } -set CWallet::GetAccountAddresses(string strAccount) const +std::set CWallet::GetAccountAddresses(const std::string& strAccount) const { LOCK(cs_wallet); set result; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 222c8cea9..07d0f1f91 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -708,7 +708,7 @@ public: SetNull(); } - CWallet(std::string strWalletFileIn) + CWallet(const std::string& strWalletFileIn) { SetNull(); @@ -931,7 +931,7 @@ public: std::set< std::set > GetAddressGroupings(); std::map GetAddressBalances(); - std::set GetAccountAddresses(std::string strAccount) const; + std::set GetAccountAddresses(const std::string& strAccount) const; boost::optional GetNoteNullifier( const JSDescription& jsdesc,