diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 16 | ||||
| -rw-r--r-- | src/bench/bench.cpp | 2 | ||||
| -rw-r--r-- | src/bench/bench.h | 23 | ||||
| -rw-r--r-- | src/bitcoin-cli.cpp | 2 | ||||
| -rw-r--r-- | src/bitcoin-tx.cpp | 2 | ||||
| -rw-r--r-- | src/bitcoind.cpp | 2 | ||||
| -rw-r--r-- | src/consensus/consensus.h | 6 | ||||
| -rw-r--r-- | src/dbwrapper.h | 4 | ||||
| -rw-r--r-- | src/init.cpp | 36 | ||||
| -rw-r--r-- | src/main.cpp | 50 | ||||
| -rw-r--r-- | src/main.h | 4 | ||||
| -rw-r--r-- | src/memusage.h | 2 | ||||
| -rw-r--r-- | src/miner.cpp | 8 | ||||
| -rw-r--r-- | src/net.cpp | 94 | ||||
| -rw-r--r-- | src/net.h | 27 | ||||
| -rw-r--r-- | src/policy/policy.h | 9 | ||||
| -rw-r--r-- | src/rpcblockchain.cpp | 3 | ||||
| -rw-r--r-- | src/rpcnet.cpp | 13 | ||||
| -rw-r--r-- | src/rpcserver.cpp | 2 | ||||
| -rw-r--r-- | src/test/alert_tests.cpp | 4 | ||||
| -rw-r--r-- | src/test/data/tx_invalid.json | 10 | ||||
| -rw-r--r-- | src/test/miner_tests.cpp | 7 | ||||
| -rw-r--r-- | src/txdb.cpp | 2 | ||||
| -rw-r--r-- | src/txmempool.cpp | 21 | ||||
| -rw-r--r-- | src/txmempool.h | 5 | ||||
| -rw-r--r-- | src/util.cpp | 11 | ||||
| -rw-r--r-- | src/util.h | 3 | ||||
| -rw-r--r-- | src/utiltime.cpp | 8 | ||||
| -rw-r--r-- | src/utiltime.h | 1 | ||||
| -rw-r--r-- | src/wallet/walletdb.cpp | 7 |
30 files changed, 318 insertions, 66 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 312643cec..f35b9dc89 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -412,7 +412,19 @@ libbitcoinconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BIT endif # -CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno +CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a +CLEANFILES += *.gcda *.gcno +CLEANFILES += compat/*.gcda compat/*.gcno +CLEANFILES += consensus/*.gcda consensus/*.gcno +CLEANFILES += crypto/*.gcda crypto/*.gcno +CLEANFILES += policy/*.gcda policy/*.gcno +CLEANFILES += primitives/*.gcda primitives/*.gcno +CLEANFILES += script/*.gcda script/*.gcno +CLEANFILES += support/*.gcda support/*.gcno +CLEANFILES += univalue/*.gcda univalue/*.gcno +CLEANFILES += wallet/*.gcda wallet/*.gcno +CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno +CLEANFILES += zmq/*.gcda zmq/*.gcno DISTCLEANFILES = obj/build.h @@ -422,7 +434,7 @@ clean-local: -$(MAKE) -C leveldb clean -$(MAKE) -C secp256k1 clean -$(MAKE) -C univalue clean - rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno + -rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno -rm -f config.h .rc.o: diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index 89c3b0cc2..6ee3cdc27 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -1,7 +1,9 @@ // Copyright (c) 2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "bench.h" + #include <iostream> #include <sys/time.h> diff --git a/src/bench/bench.h b/src/bench/bench.h index bf591a2be..5ce13c642 100644 --- a/src/bench/bench.h +++ b/src/bench/bench.h @@ -1,8 +1,16 @@ // Copyright (c) 2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_BENCH_H -#define BITCOIN_BENCH_H + +#ifndef BITCOIN_BENCH_BENCH_H +#define BITCOIN_BENCH_BENCH_H + +#include <map> +#include <string> + +#include <boost/function.hpp> +#include <boost/preprocessor/cat.hpp> +#include <boost/preprocessor/stringize.hpp> // Simple micro-benchmarking framework; API mostly matches a subset of the Google Benchmark // framework (see https://github.com/google/benchmark) @@ -25,14 +33,7 @@ static void CODE_TO_TIME(benchmark::State& state) BENCHMARK(CODE_TO_TIME); */ - - -#include <boost/function.hpp> -#include <boost/preprocessor/cat.hpp> -#include <boost/preprocessor/stringize.hpp> -#include <map> -#include <string> - + namespace benchmark { class State { @@ -68,4 +69,4 @@ namespace benchmark { #define BENCHMARK(n) \ benchmark::BenchRunner BOOST_PP_CAT(bench_, BOOST_PP_CAT(__LINE__, n))(BOOST_PP_STRINGIZE(n), n); -#endif // BITCOIN_BENCH_H +#endif // BITCOIN_BENCH_BENCH_H diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 6f22c7049..956457365 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -94,7 +94,7 @@ static bool AppInitRPC(int argc, char* argv[]) // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause) try { SelectBaseParams(ChainNameFromCommandLine()); - } catch(std::exception &e) { + } catch (const std::exception& e) { fprintf(stderr, "Error: %s\n", e.what()); return false; } diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 3330fe5d1..48033cd8a 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -37,7 +37,7 @@ static bool AppInitRawTx(int argc, char* argv[]) // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) try { SelectParams(ChainNameFromCommandLine()); - } catch(std::exception &e) { + } catch (const std::exception& e) { fprintf(stderr, "Error: %s\n", e.what()); return false; } diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index d2af89724..addf0e6a2 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -109,7 +109,7 @@ bool AppInit(int argc, char* argv[]) // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) try { SelectParams(ChainNameFromCommandLine()); - } catch(std::exception &e) { + } catch (const std::exception& e) { fprintf(stderr, "Error: %s\n", e.what()); return false; } diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index f937844e9..6d6ce7e09 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -13,4 +13,10 @@ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ static const int COINBASE_MATURITY = 100; +/** Flags for LockTime() */ +enum { + /* Use GetMedianTimePast() instead of nTime for end point timestamp. */ + LOCKTIME_MEDIAN_TIME_PAST = (1 << 1), +}; + #endif // BITCOIN_CONSENSUS_CONSENSUS_H diff --git a/src/dbwrapper.h b/src/dbwrapper.h index aa2876750..1d31ab8ae 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -104,7 +104,7 @@ public: try { CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); ssKey >> key; - } catch(std::exception &e) { + } catch (const std::exception&) { return false; } return true; @@ -120,7 +120,7 @@ public: CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); ssValue.Xor(*obfuscate_key); ssValue >> value; - } catch(std::exception &e) { + } catch (const std::exception&) { return false; } return true; diff --git a/src/init.cpp b/src/init.cpp index dd9259d4c..76adca769 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -369,6 +369,7 @@ std::string HelpMessage(HelpMessageMode mode) 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.") + " " + _("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("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), 0)); #ifdef ENABLE_WALLET strUsage += HelpMessageGroup(_("Wallet options:")); @@ -430,6 +431,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), 1)); if (showDebug) { + strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS)); strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", 15)); strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 1)); strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> entries (default: %u)", 50000)); @@ -690,13 +692,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #endif if (!SetupNetworking()) - return InitError("Error: Initializing networking failed"); + return InitError("Initializing networking failed"); #ifndef WIN32 if (GetBoolArg("-sysperms", false)) { #ifdef ENABLE_WALLET if (!GetBoolArg("-disablewallet", false)) - return InitError("Error: -sysperms is not allowed in combination with enabled wallet functionality"); + return InitError("-sysperms is not allowed in combination with enabled wallet functionality"); #endif } else { umask(077); @@ -727,6 +729,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // Set this early so that parameter interactions go to console fPrintToConsole = GetBoolArg("-printtoconsole", false); fLogTimestamps = GetBoolArg("-logtimestamps", true); + fLogTimeMicros = GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); 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"); @@ -826,19 +829,22 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // Check for -debugnet if (GetBoolArg("-debugnet", false)) - InitWarning(_("Warning: Unsupported argument -debugnet ignored, use -debug=net.")); + InitWarning(_("Unsupported argument -debugnet ignored, use -debug=net.")); // Check for -socks - as this is a privacy risk to continue, exit here if (mapArgs.count("-socks")) - return InitError(_("Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.")); + return InitError(_("Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.")); // Check for -tor - as this is a privacy risk to continue, exit here if (GetBoolArg("-tor", false)) - return InitError(_("Error: Unsupported argument -tor found, use -onion.")); + return InitError(_("Unsupported argument -tor found, use -onion.")); if (GetBoolArg("-benchmark", false)) - InitWarning(_("Warning: Unsupported argument -benchmark ignored, use -debug=bench.")); + InitWarning(_("Unsupported argument -benchmark ignored, use -debug=bench.")); // Checkmempool and checkblockindex default to true in regtest mode - mempool.setSanityCheck(GetBoolArg("-checkmempool", chainparams.DefaultConsistencyChecks())); + int ratio = std::min<int>(std::max<int>(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); + if (ratio != 0) { + mempool.setSanityCheck(1.0 / ratio); + } fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); fCheckpointsEnabled = GetBoolArg("-checkpoints", true); @@ -846,7 +852,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) int64_t nMempoolSizeLimit = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; int64_t nMempoolDescendantSizeLimit = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000; if (nMempoolSizeLimit < 0 || nMempoolSizeLimit < nMempoolDescendantSizeLimit * 40) - return InitError(strprintf(_("Error: -maxmempool must be at least %d MB"), GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) / 25)); + return InitError(strprintf(_("-maxmempool must be at least %d MB"), GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) / 25)); // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); @@ -915,7 +921,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK)) return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s'"), mapArgs["-paytxfee"])); if (nFeePerK > nHighTransactionFeeWarning) - InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); + InitWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); payTxFee = CFeeRate(nFeePerK, 1000); if (payTxFee < ::minRelayTxFee) { @@ -929,7 +935,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee)) return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s'"), mapArgs["-maptxfee"])); if (nMaxFee > nHighTransactionMaxFeeWarning) - InitWarning(_("Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction.")); + InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); maxTxFee = nMaxFee; if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) { @@ -1056,12 +1062,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) 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)); + return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt)); uacomments.push_back(SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)); } strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments); if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) { - return InitError(strprintf("Total length of network version string %i exceeds maximum of %i characters. Reduce the number and/or size of uacomments.", + return InitError(strprintf(_("Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments."), strSubVersion.size(), MAX_SUBVERSION_LENGTH)); } @@ -1174,6 +1180,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RegisterValidationInterface(pzmqNotificationInterface); } #endif + if (mapArgs.count("-maxuploadtarget")) { + CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", 0)*1024*1024); + } // ********************************************************* Step 7: load block chain @@ -1382,9 +1391,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n"; else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) { - string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data" + InitWarning(_("Error reading wallet.dat! All keys read correctly, but transaction data" " or address book entries might be missing or incorrect.")); - InitWarning(msg); } else if (nLoadWalletRet == DB_TOO_NEW) strErrors << _("Error loading wallet.dat: Wallet requires newer version of Bitcoin Core") << "\n"; diff --git a/src/main.cpp b/src/main.cpp index 30df2744a..e038fe366 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -650,10 +650,35 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) return true; } -bool CheckFinalTx(const CTransaction &tx) +bool CheckFinalTx(const CTransaction &tx, int flags) { AssertLockHeld(cs_main); - return IsFinalTx(tx, chainActive.Height() + 1, GetAdjustedTime()); + + // By convention a negative value for flags indicates that the + // current network-enforced consensus rules should be used. In + // a future soft-fork scenario that would mean checking which + // rules would be enforced for the next block and setting the + // appropriate flags. At the present time no soft-forks are + // scheduled, so no flags are set. + flags = std::max(flags, 0); + + // CheckFinalTx() uses chainActive.Height()+1 to evaluate + // nLockTime because when IsFinalTx() is called within + // CBlock::AcceptBlock(), the height of the block *being* + // evaluated is what is used. Thus if we want to know if a + // transaction can be part of the *next* block, we need to call + // IsFinalTx() with one more than chainActive.Height(). + const int nBlockHeight = chainActive.Height() + 1; + + // Timestamps on the other hand don't get any special treatment, + // because we can't know what timestamp the next block will have, + // and there aren't timestamp applications where it matters. + // However this changes once median past time-locks are enforced: + const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) + ? chainActive.Tip()->GetMedianTimePast() + : GetAdjustedTime(); + + return IsFinalTx(tx, nBlockHeight, nBlockTime); } unsigned int GetLegacySigOpCount(const CTransaction& tx) @@ -797,7 +822,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Only accept nLockTime-using transactions that can be mined in the next // block; we don't want our mempool filled up with transactions that can't // be mined yet. - if (!CheckFinalTx(tx)) + if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) return state.DoS(0, false, REJECT_NONSTANDARD, "non-final"); // is it already in the memory pool? @@ -2723,10 +2748,15 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn const Consensus::Params& consensusParams = Params().GetConsensus(); // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, block.vtx) - if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) { + BOOST_FOREACH(const CTransaction& tx, block.vtx) { + int nLockTimeFlags = 0; + int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST) + ? pindexPrev->GetMedianTimePast() + : block.GetBlockTime(); + if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { return state.DoS(10, error("%s: contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); } + } // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): @@ -3805,6 +3835,16 @@ void static ProcessGetData(CNode* pfrom) } } } + // disconnect node in case we have reached the outbound limit for serving historical blocks + static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical + if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) ) + { + LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); + + //disconnect node + pfrom->fDisconnect = true; + send = false; + } // Pruned nodes may have deleted the block, so check whether // it's available before trying to send. if (send && (mi->second->nStatus & BLOCK_HAVE_DATA)) diff --git a/src/main.h b/src/main.h index 202d2c772..65732d770 100644 --- a/src/main.h +++ b/src/main.h @@ -308,8 +308,10 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime); * Check if transaction will be final in the next block to be created. * * Calls IsFinalTx() with current block height and appropriate block time. + * + * See consensus/consensus.h for flag definitions. */ -bool CheckFinalTx(const CTransaction &tx); +bool CheckFinalTx(const CTransaction &tx, int flags = -1); /** * Closure representing one script verification diff --git a/src/memusage.h b/src/memusage.h index b475c3313..e96c5bf03 100644 --- a/src/memusage.h +++ b/src/memusage.h @@ -121,4 +121,4 @@ static inline size_t DynamicUsage(const boost::unordered_map<X, Y, Z>& m) } -#endif +#endif // BITCOIN_MEMUSAGE_H diff --git a/src/miner.cpp b/src/miner.cpp index 42c8bb970..053d9cdbc 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -148,6 +148,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) CBlockIndex* pindexPrev = chainActive.Tip(); const int nHeight = pindexPrev->nHeight + 1; pblock->nTime = GetAdjustedTime(); + const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); CCoinsViewCache view(pcoinsTip); // Priority order to process transactions @@ -162,7 +163,12 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) mi != mempool.mapTx.end(); ++mi) { const CTransaction& tx = mi->GetTx(); - if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, pblock->nTime)) + + int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) + ? nMedianTimePast + : pblock->GetBlockTime(); + + if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff)) continue; COrphan* porphan = NULL; diff --git a/src/net.cpp b/src/net.cpp index 58b946f4a..e18e8d0e2 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -12,6 +12,7 @@ #include "addrman.h" #include "chainparams.h" #include "clientversion.h" +#include "consensus/consensus.h" #include "crypto/common.h" #include "hash.h" #include "primitives/transaction.h" @@ -326,6 +327,11 @@ uint64_t CNode::nTotalBytesSent = 0; CCriticalSection CNode::cs_totalBytesRecv; CCriticalSection CNode::cs_totalBytesSent; +uint64_t CNode::nMaxOutboundLimit = 0; +uint64_t CNode::nMaxOutboundTotalBytesSentInCycle = 0; +uint64_t CNode::nMaxOutboundTimeframe = 60*60*24; //1 day +uint64_t CNode::nMaxOutboundCycleStartTime = 0; + CNode* FindNode(const CNetAddr& ip) { LOCK(cs_vNodes); @@ -2083,6 +2089,94 @@ void CNode::RecordBytesSent(uint64_t bytes) { LOCK(cs_totalBytesSent); nTotalBytesSent += bytes; + + uint64_t now = GetTime(); + if (nMaxOutboundCycleStartTime + nMaxOutboundTimeframe < now) + { + // timeframe expired, reset cycle + nMaxOutboundCycleStartTime = now; + nMaxOutboundTotalBytesSentInCycle = 0; + } + + // TODO, exclude whitebind peers + nMaxOutboundTotalBytesSentInCycle += bytes; +} + +void CNode::SetMaxOutboundTarget(uint64_t limit) +{ + LOCK(cs_totalBytesSent); + uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SIZE; + nMaxOutboundLimit = limit; + + if (limit < recommendedMinimum) + LogPrintf("Max outbound target is very small (%s) and will be overshot. Recommended minimum is %s\n.", nMaxOutboundLimit, recommendedMinimum); +} + +uint64_t CNode::GetMaxOutboundTarget() +{ + LOCK(cs_totalBytesSent); + return nMaxOutboundLimit; +} + +uint64_t CNode::GetMaxOutboundTimeframe() +{ + LOCK(cs_totalBytesSent); + return nMaxOutboundTimeframe; +} + +uint64_t CNode::GetMaxOutboundTimeLeftInCycle() +{ + LOCK(cs_totalBytesSent); + if (nMaxOutboundLimit == 0) + return 0; + + if (nMaxOutboundCycleStartTime == 0) + return nMaxOutboundTimeframe; + + uint64_t cycleEndTime = nMaxOutboundCycleStartTime + nMaxOutboundTimeframe; + uint64_t now = GetTime(); + return (cycleEndTime < now) ? 0 : cycleEndTime - GetTime(); +} + +void CNode::SetMaxOutboundTimeframe(uint64_t timeframe) +{ + LOCK(cs_totalBytesSent); + if (nMaxOutboundTimeframe != timeframe) + { + // reset measure-cycle in case of changing + // the timeframe + nMaxOutboundCycleStartTime = GetTime(); + } + nMaxOutboundTimeframe = timeframe; +} + +bool CNode::OutboundTargetReached(bool historicalBlockServingLimit) +{ + LOCK(cs_totalBytesSent); + if (nMaxOutboundLimit == 0) + return false; + + if (historicalBlockServingLimit) + { + // keep a large enought buffer to at least relay each block once + uint64_t timeLeftInCycle = GetMaxOutboundTimeLeftInCycle(); + uint64_t buffer = timeLeftInCycle / 600 * MAX_BLOCK_SIZE; + if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer) + return true; + } + else if (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) + return true; + + return false; +} + +uint64_t CNode::GetOutboundTargetBytesLeft() +{ + LOCK(cs_totalBytesSent); + if (nMaxOutboundLimit == 0) + return 0; + + return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle; } uint64_t CNode::GetTotalBytesRecv() @@ -400,6 +400,12 @@ private: static uint64_t nTotalBytesRecv; static uint64_t nTotalBytesSent; + // outbound limit & stats + static uint64_t nMaxOutboundTotalBytesSentInCycle; + static uint64_t nMaxOutboundCycleStartTime; + static uint64_t nMaxOutboundLimit; + static uint64_t nMaxOutboundTimeframe; + CNode(const CNode&); void operator=(const CNode&); @@ -701,6 +707,27 @@ public: static uint64_t GetTotalBytesRecv(); static uint64_t GetTotalBytesSent(); + + //!set the max outbound target in bytes + static void SetMaxOutboundTarget(uint64_t limit); + static uint64_t GetMaxOutboundTarget(); + + //!set the timeframe for the max outbound target + static void SetMaxOutboundTimeframe(uint64_t timeframe); + static uint64_t GetMaxOutboundTimeframe(); + + //!check if the outbound target is reached + // if param historicalBlockServingLimit is set true, the function will + // response true if the limit for serving historical blocks has been reached + static bool OutboundTargetReached(bool historicalBlockServingLimit); + + //!response the bytes left in the current max outbound cycle + // in case of no limit, it will always response 0 + static uint64_t GetOutboundTargetBytesLeft(); + + //!response the time in second left in the current max outbound cycle + // in case of no limit, it will always response 0 + static uint64_t GetMaxOutboundTimeLeftInCycle(); }; diff --git a/src/policy/policy.h b/src/policy/policy.h index 0ea0d435a..f269e8d47 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -3,8 +3,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_POLICY_H -#define BITCOIN_POLICY_H +#ifndef BITCOIN_POLICY_POLICY_H +#define BITCOIN_POLICY_POLICY_H #include "consensus/consensus.h" #include "script/interpreter.h" @@ -43,6 +43,9 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY /** For convenience, standard but not mandatory verify flags. */ static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; +/** Used as the flags parameter to CheckFinalTx() in non-consensus code */ +static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_MEDIAN_TIME_PAST; + bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType); /** * Check for standard transaction types @@ -56,4 +59,4 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason); */ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); -#endif // BITCOIN_POLICY_H +#endif // BITCOIN_POLICY_POLICY_H diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 20c0c1fb2..4786d72a3 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -773,6 +773,9 @@ UniValue mempoolInfoToJSON() ret.push_back(Pair("size", (int64_t) mempool.size())); ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize())); ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage())); + size_t maxmempool = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; + ret.push_back(Pair("maxmempool", (int64_t) maxmempool)); + ret.push_back(Pair("mempoolminfee", ValueFromAmount(mempool.GetMinFee(maxmempool).GetFeePerK()))); return ret; } diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 7746be25f..9bf017e38 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -29,7 +29,7 @@ UniValue getconnectioncount(const UniValue& params, bool fHelp) throw runtime_error( "getconnectioncount\n" "\nReturns the number of connections to other nodes.\n" - "\nbResult:\n" + "\nResult:\n" "n (numeric) The connection count\n" "\nExamples:\n" + HelpExampleCli("getconnectioncount", "") @@ -83,7 +83,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) throw runtime_error( "getpeerinfo\n" "\nReturns data about each connected network node as a json array of objects.\n" - "\nbResult:\n" + "\nResult:\n" "[\n" " {\n" " \"id\": n, (numeric) Peer index\n" @@ -379,6 +379,15 @@ UniValue getnettotals(const UniValue& params, bool fHelp) obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv())); obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent())); obj.push_back(Pair("timemillis", GetTimeMillis())); + + UniValue outboundLimit(UniValue::VOBJ); + outboundLimit.push_back(Pair("timeframe", CNode::GetMaxOutboundTimeframe())); + outboundLimit.push_back(Pair("target", CNode::GetMaxOutboundTarget())); + outboundLimit.push_back(Pair("target_reached", CNode::OutboundTargetReached(false))); + outboundLimit.push_back(Pair("serve_historical_blocks", !CNode::OutboundTargetReached(true))); + outboundLimit.push_back(Pair("bytes_left_in_cycle", CNode::GetOutboundTargetBytesLeft())); + outboundLimit.push_back(Pair("time_left_in_cycle", CNode::GetMaxOutboundTimeLeftInCycle())); + obj.push_back(Pair("uploadtarget", outboundLimit)); return obj; } diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index fa60f8c83..8bda5a037 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -563,7 +563,7 @@ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int6 deadlineTimers.erase(name); RPCTimerInterface* timerInterface = timerInterfaces[0]; LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name()); - deadlineTimers.insert(std::make_pair(name, timerInterface->NewTimer(func, nSeconds*1000))); + deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000)))); } const CRPCTable tableRPC; diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index dd3c51d09..468eda1c9 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -217,10 +217,12 @@ BOOST_AUTO_TEST_CASE(PartitionAlert) // use them } + strMiscWarning = ""; + // Test 1: chain with blocks every nPowTargetSpacing seconds, // as normal, no worries: PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); - BOOST_CHECK(strMiscWarning.empty()); + BOOST_CHECK_MESSAGE(strMiscWarning.empty(), strMiscWarning); // Test 2: go 3.5 hours without a block, expect a warning: now += 3*60*60+30*60; diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index d3c859434..cc059e814 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -64,9 +64,13 @@ [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"], -["Null txin"], -[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "HASH160 0x14 0x02dae7dbbda56097959cba59b1989dd3e47937bf EQUAL"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", "P2SH"], +["Null txin, but without being a coinbase (because there are two inputs)"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"], + ["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"01000000020000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff010000000000000000015100000000", "P2SH"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"], + ["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], +"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff010000000000000000015100000000", "P2SH"], ["Same as the transactions in valid with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 91a3a5738..827525783 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -4,6 +4,7 @@ #include "chainparams.h" #include "coins.h" +#include "consensus/consensus.h" #include "consensus/validation.h" #include "main.h" #include "miner.h" @@ -229,7 +230,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.nLockTime = chainActive.Tip()->nHeight+1; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(!CheckFinalTx(tx)); + BOOST_CHECK(!CheckFinalTx(tx, LOCKTIME_MEDIAN_TIME_PAST)); // time locked tx2.vin.resize(1); @@ -243,7 +244,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1; hash = tx2.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx2, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(!CheckFinalTx(tx2)); + BOOST_CHECK(!CheckFinalTx(tx2, LOCKTIME_MEDIAN_TIME_PAST)); BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); @@ -261,7 +262,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) //BOOST_CHECK(CheckFinalTx(tx2)); BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); - BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3); + BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 2); delete pblocktemplate; chainActive.Tip()->nHeight--; diff --git a/src/txdb.cpp b/src/txdb.cpp index f0868a1eb..cd76c0155 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -121,7 +121,7 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { nTotalAmount += out.nValue; } } - stats.nSerializedSize += 32 + pcursor->GetKeySize(); + stats.nSerializedSize += 32 + pcursor->GetValueSize(); ss << VARINT(0); } else { return error("CCoinsViewDB::GetStats() : unable to read value"); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index bb148005c..a772e7ade 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -309,12 +309,12 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) : nTransactionsUpdated(0) { - clear(); + _clear(); //lock free clear // Sanity checks off by default for performance, because otherwise // accepting transactions becomes O(N^2) where N is the number // of transactions in the pool - fSanityCheck = false; + nCheckFrequency = 0; minerPolicyEstimator = new CBlockPolicyEstimator(_minReasonableRelayFee); minReasonableRelayFee = _minReasonableRelayFee; @@ -487,7 +487,7 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned in if (it2 != mapTx.end()) continue; const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); - if (fSanityCheck) assert(coins); + if (nCheckFrequency != 0) assert(coins); if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) { transactionsToRemove.push_back(tx); break; @@ -512,6 +512,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction> if (txConflict != tx) { remove(txConflict, removed, true); + ClearPrioritisation(txConflict.GetHash()); } } } @@ -546,9 +547,8 @@ void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned i blockSinceLastRollingFeeBump = true; } -void CTxMemPool::clear() +void CTxMemPool::_clear() { - LOCK(cs); mapLinks.clear(); mapTx.clear(); mapNextTx.clear(); @@ -560,9 +560,18 @@ void CTxMemPool::clear() ++nTransactionsUpdated; } +void CTxMemPool::clear() +{ + LOCK(cs); + _clear(); +} + void CTxMemPool::check(const CCoinsViewCache *pcoins) const { - if (!fSanityCheck) + if (nCheckFrequency == 0) + return; + + if (insecure_rand() >= nCheckFrequency) return; LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); diff --git a/src/txmempool.h b/src/txmempool.h index d44995eef..7b5843a8d 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -278,7 +278,7 @@ public: class CTxMemPool { private: - bool fSanityCheck; //! Normally false, true if -checkmempool or -regtest + uint32_t nCheckFrequency; //! Value n means that n times in 2^32 we check. unsigned int nTransactionsUpdated; CBlockPolicyEstimator* minerPolicyEstimator; @@ -360,7 +360,7 @@ public: * check does nothing. */ void check(const CCoinsViewCache *pcoins) const; - void setSanityCheck(bool _fSanityCheck) { fSanityCheck = _fSanityCheck; } + void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967295.0; } // addUnchecked must updated state for all ancestors of a given transaction, // to track size/count of descendant transactions. First version of @@ -375,6 +375,7 @@ public: void removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight, std::list<CTransaction>& conflicts, bool fCurrentEstimate = true); void clear(); + void _clear(); //lock free void queryHashes(std::vector<uint256>& vtxid); void pruneSpent(const uint256& hash, CCoins &coins); unsigned int GetTransactionsUpdated() const; diff --git a/src/util.cpp b/src/util.cpp index 8192a7c71..e8514a2ef 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -108,6 +108,7 @@ bool fDaemon = false; bool fServer = false; string strMiscWarning; bool fLogTimestamps = false; +bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS; bool fLogIPs = false; volatile bool fReopenDebugLog = false; CTranslationInterface translationInterface; @@ -263,9 +264,13 @@ static std::string LogTimestampStr(const std::string &str, bool *fStartedNewLine if (!fLogTimestamps) return str; - if (*fStartedNewLine) - strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()) + ' ' + str; - else + if (*fStartedNewLine) { + int64_t nTimeMicros = GetLogTimeMicros(); + strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTimeMicros/1000000); + if (fLogTimeMicros) + strStamped += strprintf(".%06d", nTimeMicros%1000000); + strStamped += ' ' + str; + } else strStamped = str; if (!str.empty() && str[str.size()-1] == '\n') diff --git a/src/util.h b/src/util.h index 0b2dc01ac..b2779fe78 100644 --- a/src/util.h +++ b/src/util.h @@ -28,6 +28,8 @@ #include <boost/signals2/signal.hpp> #include <boost/thread/exceptions.hpp> +static const bool DEFAULT_LOGTIMEMICROS = false; + /** Signals for translation. */ class CTranslationInterface { @@ -44,6 +46,7 @@ extern bool fPrintToDebugLog; extern bool fServer; extern std::string strMiscWarning; extern bool fLogTimestamps; +extern bool fLogTimeMicros; extern bool fLogIPs; extern volatile bool fReopenDebugLog; extern CTranslationInterface translationInterface; diff --git a/src/utiltime.cpp b/src/utiltime.cpp index d31628899..3202c47f1 100644 --- a/src/utiltime.cpp +++ b/src/utiltime.cpp @@ -40,6 +40,14 @@ int64_t GetTimeMicros() boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds(); } +/** Return a time useful for the debug log */ +int64_t GetLogTimeMicros() +{ + if (nMockTime) return nMockTime*1000000; + + return GetTimeMicros(); +} + void MilliSleep(int64_t n) { diff --git a/src/utiltime.h b/src/utiltime.h index 900992f87..241b5211e 100644 --- a/src/utiltime.h +++ b/src/utiltime.h @@ -12,6 +12,7 @@ int64_t GetTime(); int64_t GetTimeMillis(); int64_t GetTimeMicros(); +int64_t GetLogTimeMicros(); void SetMockTime(int64_t nMockTimeIn); void MilliSleep(int64_t n); diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 0624e442d..ea8a4eb04 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -512,8 +512,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } else if (strType == "ckey") { - vector<unsigned char> vchPubKey; + CPubKey vchPubKey; ssKey >> vchPubKey; + if (!vchPubKey.IsValid()) + { + strErr = "Error reading wallet database: CPubKey corrupt"; + return false; + } vector<unsigned char> vchPrivKey; ssValue >> vchPrivKey; wss.nCKeys++; |