aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am16
-rw-r--r--src/bench/bench.cpp2
-rw-r--r--src/bench/bench.h23
-rw-r--r--src/bitcoin-cli.cpp2
-rw-r--r--src/bitcoin-tx.cpp2
-rw-r--r--src/bitcoind.cpp2
-rw-r--r--src/consensus/consensus.h6
-rw-r--r--src/dbwrapper.h4
-rw-r--r--src/init.cpp36
-rw-r--r--src/main.cpp50
-rw-r--r--src/main.h4
-rw-r--r--src/memusage.h2
-rw-r--r--src/miner.cpp8
-rw-r--r--src/net.cpp94
-rw-r--r--src/net.h27
-rw-r--r--src/policy/policy.h9
-rw-r--r--src/rpcblockchain.cpp3
-rw-r--r--src/rpcnet.cpp13
-rw-r--r--src/rpcserver.cpp2
-rw-r--r--src/test/alert_tests.cpp4
-rw-r--r--src/test/data/tx_invalid.json10
-rw-r--r--src/test/miner_tests.cpp7
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/txmempool.cpp21
-rw-r--r--src/txmempool.h5
-rw-r--r--src/util.cpp11
-rw-r--r--src/util.h3
-rw-r--r--src/utiltime.cpp8
-rw-r--r--src/utiltime.h1
-rw-r--r--src/wallet/walletdb.cpp7
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()
diff --git a/src/net.h b/src/net.h
index 6842ee5ed..f90b3385a 100644
--- a/src/net.h
+++ b/src/net.h
@@ -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++;