aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/addrdb.cpp1
-rw-r--r--src/addrman.cpp6
-rw-r--r--src/addrman.h10
-rw-r--r--src/bench/base58.cpp2
-rw-r--r--src/bench/checkqueue.cpp2
-rw-r--r--src/chain.cpp11
-rw-r--r--src/chainparams.cpp7
-rw-r--r--src/checkpoints.cpp1
-rw-r--r--src/clientversion.cpp1
-rw-r--r--src/coins.cpp3
-rw-r--r--src/compat.h10
-rw-r--r--src/core_io.h2
-rw-r--r--src/core_read.cpp34
-rw-r--r--src/dbwrapper.cpp4
-rw-r--r--src/hash.cpp1
-rw-r--r--src/init.cpp32
-rw-r--r--src/key.cpp76
-rw-r--r--src/key.h28
-rw-r--r--src/keystore.cpp2
-rw-r--r--src/miner.cpp1
-rw-r--r--src/miner.h4
-rw-r--r--src/net.cpp127
-rw-r--r--src/net.h26
-rw-r--r--src/net_processing.cpp45
-rw-r--r--src/netaddress.cpp4
-rw-r--r--src/netbase.cpp74
-rw-r--r--src/netbase.h5
-rw-r--r--src/policy/fees.cpp70
-rw-r--r--src/protocol.h9
-rw-r--r--src/pubkey.cpp33
-rw-r--r--src/pubkey.h37
-rw-r--r--src/qt/bantablemodel.cpp6
-rw-r--r--src/qt/bitcoingui.cpp4
-rw-r--r--src/qt/coincontroldialog.cpp2
-rw-r--r--src/qt/forms/sendcoinsdialog.ui4
-rw-r--r--src/qt/guiutil.cpp1
-rw-r--r--src/qt/notificator.cpp1
-rw-r--r--src/qt/optionsdialog.cpp2
-rw-r--r--src/qt/optionsmodel.cpp110
-rw-r--r--src/qt/optionsmodel.h3
-rw-r--r--src/qt/platformstyle.cpp2
-rw-r--r--src/qt/receivecoinsdialog.cpp2
-rw-r--r--src/qt/receiverequestdialog.cpp1
-rw-r--r--src/qt/rpcconsole.cpp36
-rw-r--r--src/qt/sendcoinsdialog.cpp7
-rw-r--r--src/qt/sendcoinsentry.cpp1
-rw-r--r--src/qt/transactionfilterproxy.cpp15
-rw-r--r--src/qt/transactionfilterproxy.h4
-rw-r--r--src/qt/transactiontablemodel.cpp6
-rw-r--r--src/qt/transactionview.cpp15
-rw-r--r--src/qt/transactionview.h4
-rw-r--r--src/random.h2
-rw-r--r--src/rpc/blockchain.cpp9
-rw-r--r--src/rpc/client.cpp4
-rw-r--r--src/rpc/mining.cpp2
-rw-r--r--src/rpc/misc.cpp62
-rw-r--r--src/rpc/net.cpp6
-rw-r--r--src/rpc/protocol.cpp1
-rw-r--r--src/rpc/rawtransaction.cpp89
-rw-r--r--src/rpc/server.cpp6
-rw-r--r--src/script/interpreter.cpp13
-rw-r--r--src/script/interpreter.h23
-rw-r--r--src/script/ismine.cpp1
-rw-r--r--src/serialize.h4
-rw-r--r--src/streams.h4
-rw-r--r--src/support/cleanse.cpp6
-rw-r--r--src/sync.cpp20
-rw-r--r--src/sync.h16
-rw-r--r--src/test/README.md2
-rw-r--r--src/test/checkqueue_tests.cpp2
-rw-r--r--src/test/coins_tests.cpp22
-rw-r--r--src/test/crypto_tests.cpp41
-rw-r--r--src/test/data/script_tests.json2
-rw-r--r--src/test/miner_tests.cpp24
-rw-r--r--src/test/rpc_tests.cpp4
-rw-r--r--src/test/script_tests.cpp11
-rw-r--r--src/test/test_bitcoin.cpp6
-rw-r--r--src/test/txvalidation_tests.cpp61
-rw-r--r--src/test/txvalidationcache_tests.cpp22
-rw-r--r--src/test/univalue_tests.cpp333
-rw-r--r--src/txmempool.h10
-rw-r--r--src/univalue/.travis.yml1
-rw-r--r--src/univalue/test/object.cpp3
-rw-r--r--src/util.cpp47
-rw-r--r--src/util.h9
-rw-r--r--src/validation.cpp592
-rw-r--r--src/validation.h12
-rw-r--r--src/validationinterface.cpp7
-rw-r--r--src/wallet/db.cpp1
-rw-r--r--src/wallet/rpcdump.cpp6
-rw-r--r--src/wallet/rpcwallet.cpp28
-rw-r--r--src/wallet/test/accounting_tests.cpp16
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp4
-rw-r--r--src/wallet/test/wallet_test_fixture.h4
-rw-r--r--src/wallet/test/wallet_tests.cpp2
-rw-r--r--src/wallet/wallet.cpp115
-rw-r--r--src/wallet/wallet.h17
-rw-r--r--src/wallet/walletdb.cpp34
-rw-r--r--src/zmq/zmqnotificationinterface.cpp8
100 files changed, 1348 insertions, 1262 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index f037705aaf..49a814c3f6 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -80,10 +80,10 @@ BITCOIN_TESTS =\
test/timedata_tests.cpp \
test/torcontrol_tests.cpp \
test/transaction_tests.cpp \
+ test/txvalidation_tests.cpp \
test/txvalidationcache_tests.cpp \
test/versionbits_tests.cpp \
test/uint256_tests.cpp \
- test/univalue_tests.cpp \
test/util_tests.cpp
if ENABLE_WALLET
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 0f9ccf1e9a..7d7f34863d 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -8,7 +8,6 @@
#include <addrman.h>
#include <chainparams.h>
#include <clientversion.h>
-#include <fs.h>
#include <hash.h>
#include <random.h>
#include <streams.h>
diff --git a/src/addrman.cpp b/src/addrman.cpp
index ddcdf4c2f4..372cac8483 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -390,9 +390,9 @@ int CAddrMan::Check_()
if (vRandom.size() != nTried + nNew)
return -7;
- for (std::map<int, CAddrInfo>::iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
- int n = (*it).first;
- CAddrInfo& info = (*it).second;
+ for (const auto& entry : mapInfo) {
+ int n = entry.first;
+ const CAddrInfo& info = entry.second;
if (info.fInTried) {
if (!info.nLastSuccess)
return -1;
diff --git a/src/addrman.h b/src/addrman.h
index b06b272962..ea289d508c 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -313,9 +313,9 @@ public:
s << nUBuckets;
std::map<int, int> mapUnkIds;
int nIds = 0;
- for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
- mapUnkIds[(*it).first] = nIds;
- const CAddrInfo &info = (*it).second;
+ for (const auto& entry : mapInfo) {
+ mapUnkIds[entry.first] = nIds;
+ const CAddrInfo &info = entry.second;
if (info.nRefCount) {
assert(nIds != nNew); // this means nNew was wrong, oh ow
s << info;
@@ -323,8 +323,8 @@ public:
}
}
nIds = 0;
- for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
- const CAddrInfo &info = (*it).second;
+ for (const auto& entry : mapInfo) {
+ const CAddrInfo &info = entry.second;
if (info.fInTried) {
assert(nIds != nTried); // this means nTried was wrong, oh ow
s << info;
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index 8f6d07ac16..2d9a9f2908 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -22,7 +22,7 @@ static void Base58Encode(benchmark::State& state)
}
};
while (state.KeepRunning()) {
- EncodeBase58(buff.begin(), buff.end());
+ EncodeBase58(buff.data(), buff.data() + buff.size());
}
}
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
index 7e63e820db..35750aa1b6 100644
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -19,7 +19,7 @@ static const int MIN_CORES = 2;
static const size_t BATCHES = 101;
static const size_t BATCH_SIZE = 30;
static const int PREVECTOR_SIZE = 28;
-static const int QUEUE_BATCH_SIZE = 128;
+static const unsigned int QUEUE_BATCH_SIZE = 128;
static void CCheckQueueSpeed(benchmark::State& state)
{
struct FakeJobNoWork {
diff --git a/src/chain.cpp b/src/chain.cpp
index 9f40c41fde..7ebc08a50b 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -80,12 +80,13 @@ int static inline GetSkipHeight(int height) {
return (height & 1) ? InvertLowestOne(InvertLowestOne(height - 1)) + 1 : InvertLowestOne(height);
}
-CBlockIndex* CBlockIndex::GetAncestor(int height)
+const CBlockIndex* CBlockIndex::GetAncestor(int height) const
{
- if (height > nHeight || height < 0)
+ if (height > nHeight || height < 0) {
return nullptr;
+ }
- CBlockIndex* pindexWalk = this;
+ const CBlockIndex* pindexWalk = this;
int heightWalk = nHeight;
while (heightWalk > height) {
int heightSkip = GetSkipHeight(heightWalk);
@@ -106,9 +107,9 @@ CBlockIndex* CBlockIndex::GetAncestor(int height)
return pindexWalk;
}
-const CBlockIndex* CBlockIndex::GetAncestor(int height) const
+CBlockIndex* CBlockIndex::GetAncestor(int height)
{
- return const_cast<CBlockIndex*>(this)->GetAncestor(height);
+ return const_cast<CBlockIndex*>(static_cast<const CBlockIndex*>(this)->GetAncestor(height));
}
void CBlockIndex::BuildSkip()
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index e753c5ccff..a78f530036 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -146,7 +146,7 @@ public:
fRequireStandard = true;
fMineBlocksOnDemand = false;
- checkpointData = (CCheckpointData) {
+ checkpointData = {
{
{ 11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")},
{ 33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")},
@@ -231,6 +231,7 @@ public:
// nodes with support for servicebits filtering should be at the top
vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch", true);
vSeeds.emplace_back("seed.tbtc.petertodd.org", true);
+ vSeeds.emplace_back("seed.testnet.bitcoin.sprovoost.nl", true);
vSeeds.emplace_back("testnet-seed.bluematt.me", false);
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
@@ -248,7 +249,7 @@ public:
fMineBlocksOnDemand = false;
- checkpointData = (CCheckpointData) {
+ checkpointData = {
{
{546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")},
}
@@ -319,7 +320,7 @@ public:
fRequireStandard = false;
fMineBlocksOnDemand = true;
- checkpointData = (CCheckpointData) {
+ checkpointData = {
{
{0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")},
}
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 2ef4dd8330..929d864588 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -8,7 +8,6 @@
#include <chainparams.h>
#include <reverse_iterator.h>
#include <validation.h>
-#include <uint256.h>
#include <stdint.h>
diff --git a/src/clientversion.cpp b/src/clientversion.cpp
index f7ded63e6a..1934e71bbc 100644
--- a/src/clientversion.cpp
+++ b/src/clientversion.cpp
@@ -6,7 +6,6 @@
#include <tinyformat.h>
-#include <string>
/**
* Name of client reported in the 'version' message. Report the same name
diff --git a/src/coins.cpp b/src/coins.cpp
index 03138ef878..afaf5ccc13 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -5,11 +5,8 @@
#include <coins.h>
#include <consensus/consensus.h>
-#include <memusage.h>
#include <random.h>
-#include <assert.h>
-
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); }
diff --git a/src/compat.h b/src/compat.h
index 2d699159b7..89cc4709a4 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -31,6 +31,7 @@
#include <mswsock.h>
#include <windows.h>
#include <ws2tcpip.h>
+#include <stdint.h>
#else
#include <sys/fcntl.h>
#include <sys/mman.h>
@@ -71,6 +72,15 @@ typedef unsigned int SOCKET;
#else
#define MAX_PATH 1024
#endif
+#ifdef _MSC_VER
+#if !defined(ssize_t)
+#ifdef _WIN64
+typedef int64_t ssize_t;
+#else
+typedef int32_t ssize_t;
+#endif
+#endif
+#endif
#if HAVE_DECL_STRNLEN == 0
size_t strnlen( const char *start, size_t max_len);
diff --git a/src/core_io.h b/src/core_io.h
index 7ed84d6665..3cdae06dfb 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -20,7 +20,7 @@ class UniValue;
// core_read.cpp
CScript ParseScript(const std::string& s);
std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
-bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness = false);
+bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true);
bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
uint256 ParseHashUV(const UniValue& v, const std::string& strName);
uint256 ParseHashStr(const std::string&, const std::string& strName);
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 2f5b67b5c7..4f2dabe10f 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -108,39 +108,39 @@ bool CheckTxScriptsSanity(const CMutableTransaction& tx)
return true;
}
-bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness)
+bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness, bool try_witness)
{
- if (!IsHex(strHexTx)) {
+ if (!IsHex(hex_tx)) {
return false;
}
- std::vector<unsigned char> txData(ParseHex(strHexTx));
+ std::vector<unsigned char> txData(ParseHex(hex_tx));
- if (fTryNoWitness) {
+ if (try_no_witness) {
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
try {
ssData >> tx;
- if (ssData.eof() && CheckTxScriptsSanity(tx)) {
+ if (ssData.eof() && (!try_witness || CheckTxScriptsSanity(tx))) {
return true;
}
- }
- catch (const std::exception&) {
+ } catch (const std::exception&) {
// Fall through.
}
}
- CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
- try {
- ssData >> tx;
- if (!ssData.empty()) {
- return false;
+ if (try_witness) {
+ CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
+ try {
+ ssData >> tx;
+ if (ssData.empty()) {
+ return true;
+ }
+ } catch (const std::exception&) {
+ // Fall through.
}
}
- catch (const std::exception&) {
- return false;
- }
-
- return true;
+
+ return false;
}
bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 92c4fe363c..6ff740f581 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -4,8 +4,6 @@
#include <dbwrapper.h>
-#include <fs.h>
-#include <util.h>
#include <random.h>
#include <leveldb/cache.h>
@@ -64,7 +62,7 @@ public:
assert(p <= limit);
base[std::min(bufsize - 1, (int)(p - base))] = '\0';
- LogPrintStr(base);
+ LogPrintf("leveldb: %s", base);
if (base != buffer) {
delete[] base;
}
diff --git a/src/hash.cpp b/src/hash.cpp
index 1363d32cf4..ea61764ded 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -5,7 +5,6 @@
#include <hash.h>
#include <crypto/common.h>
#include <crypto/hmac_sha512.h>
-#include <pubkey.h>
inline uint32_t ROTL32(uint32_t x, int8_t r)
diff --git a/src/init.cpp b/src/init.cpp
index 439eaacfcc..e4cad01b70 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -193,8 +193,8 @@ void Shutdown()
// Because these depend on each-other, we make sure that neither can be
// using the other before destroying them.
- UnregisterValidationInterface(peerLogic.get());
- if(g_connman) g_connman->Stop();
+ if (peerLogic) UnregisterValidationInterface(peerLogic.get());
+ if (g_connman) g_connman->Stop();
peerLogic.reset();
g_connman.reset();
@@ -342,6 +342,7 @@ std::string HelpMessage(HelpMessageMode mode)
if (showDebug)
strUsage += HelpMessageOpt("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER));
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file on startup"));
+ strUsage += HelpMessageOpt("-debuglogfile=<file>", strprintf(_("Specify location of debug log file: this can be an absolute path or a path relative to the data directory (default: %s)"), DEFAULT_DEBUGLOGFILE));
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE));
strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf(_("Do not keep transactions in the mempool longer than <n> hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY));
@@ -815,7 +816,7 @@ namespace { // Variables internal to initialization process only
int nMaxConnections;
int nUserMaxConnections;
int nFD;
-ServiceFlags nLocalServices = NODE_NETWORK;
+ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK | NODE_NETWORK_LIMITED);
} // namespace
@@ -919,7 +920,8 @@ bool AppInitParameterInteraction()
// Special-case: if -debug=0/-nodebug is set, turn off debugging messages
const std::vector<std::string> categories = gArgs.GetArgs("-debug");
- if (find(categories.begin(), categories.end(), std::string("0")) == categories.end()) {
+ if (std::none_of(categories.begin(), categories.end(),
+ [](std::string cat){return cat == "0" || cat == "none";})) {
for (const auto& cat : categories) {
uint32_t flag = 0;
if (!GetLogCategory(&flag, &cat)) {
@@ -1030,11 +1032,6 @@ bool AppInitParameterInteraction()
fPruneMode = true;
}
- RegisterAllCoreRPCCommands(tableRPC);
-#ifdef ENABLE_WALLET
- RegisterWalletRPC(tableRPC);
-#endif
-
nConnectTimeout = gArgs.GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
if (nConnectTimeout <= 0)
nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
@@ -1213,8 +1210,11 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
ShrinkDebugFile();
}
- if (fPrintToDebugLog)
- OpenDebugLog();
+ if (fPrintToDebugLog) {
+ if (!OpenDebugLog()) {
+ return InitError(strprintf("Could not open debug log file %s", GetDebugLogPath().string()));
+ }
+ }
if (!fLogTimestamps)
LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()));
@@ -1239,6 +1239,14 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
GetMainSignals().RegisterWithMempoolSignals(mempool);
+ /* Register RPC commands regardless of -server setting so they will be
+ * available in the GUI RPC console even if external calls are disabled.
+ */
+ RegisterAllCoreRPCCommands(tableRPC);
+#ifdef ENABLE_WALLET
+ RegisterWalletRPC(tableRPC);
+#endif
+
/* Start the RPC server already. It will be started in "warmup" mode
* and not really process calls already (but it will signify connections
* that the server is there and will be ready later). Warmup mode will
@@ -1718,5 +1726,5 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
StartWallets(scheduler);
#endif
- return !fRequestShutdown;
+ return true;
}
diff --git a/src/key.cpp b/src/key.cpp
index 73983caf41..9893b88220 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -1,4 +1,5 @@
// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,7 +8,6 @@
#include <arith_uint256.h>
#include <crypto/common.h>
#include <crypto/hmac_sha512.h>
-#include <pubkey.h>
#include <random.h>
#include <secp256k1.h>
@@ -16,43 +16,62 @@
static secp256k1_context* secp256k1_context_sign = nullptr;
/** These functions are taken from the libsecp256k1 distribution and are very ugly. */
+
+/**
+ * This parses a format loosely based on a DER encoding of the ECPrivateKey type from
+ * section C.4 of SEC 1 <http://www.secg.org/sec1-v2.pdf>, with the following caveats:
+ *
+ * * The octet-length of the SEQUENCE must be encoded as 1 or 2 octets. It is not
+ * required to be encoded as one octet if it is less than 256, as DER would require.
+ * * The octet-length of the SEQUENCE must not be greater than the remaining
+ * length of the key encoding, but need not match it (i.e. the encoding may contain
+ * junk after the encoded SEQUENCE).
+ * * The privateKey OCTET STRING is zero-filled on the left to 32 octets.
+ * * Anything after the encoding of the privateKey OCTET STRING is ignored, whether
+ * or not it is validly encoded DER.
+ *
+ * out32 must point to an output buffer of length at least 32 bytes.
+ */
static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {
const unsigned char *end = privkey + privkeylen;
- int lenb = 0;
- int len = 0;
memset(out32, 0, 32);
/* sequence header */
- if (end < privkey+1 || *privkey != 0x30) {
+ if (end - privkey < 1 || *privkey != 0x30u) {
return 0;
}
privkey++;
/* sequence length constructor */
- if (end < privkey+1 || !(*privkey & 0x80)) {
+ if (end - privkey < 1 || !(*privkey & 0x80u)) {
return 0;
}
- lenb = *privkey & ~0x80; privkey++;
+ size_t lenb = *privkey & ~0x80u; privkey++;
if (lenb < 1 || lenb > 2) {
return 0;
}
- if (end < privkey+lenb) {
+ if (end - privkey < lenb) {
return 0;
}
/* sequence length */
- len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
+ size_t len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0u);
privkey += lenb;
- if (end < privkey+len) {
+ if (end - privkey < len) {
return 0;
}
/* sequence element 0: version number (=1) */
- if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) {
+ if (end - privkey < 3 || privkey[0] != 0x02u || privkey[1] != 0x01u || privkey[2] != 0x01u) {
return 0;
}
privkey += 3;
/* sequence element 1: octet string, up to 32 bytes */
- if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) {
+ if (end - privkey < 2 || privkey[0] != 0x04u) {
+ return 0;
+ }
+ size_t oslen = privkey[1];
+ privkey += 2;
+ if (oslen > 32 || end - privkey < oslen) {
return 0;
}
- memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]);
+ memcpy(out32 + (32 - oslen), privkey, oslen);
if (!secp256k1_ec_seckey_verify(ctx, out32)) {
memset(out32, 0, 32);
return 0;
@@ -60,7 +79,18 @@ static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *ou
return 1;
}
+/**
+ * This serializes to a DER encoding of the ECPrivateKey type from section C.4 of SEC 1
+ * <http://www.secg.org/sec1-v2.pdf>. The optional parameters and publicKey fields are
+ * included.
+ *
+ * privkey must point to an output buffer of length at least CKey::PRIVATE_KEY_SIZE bytes.
+ * privkeylen must initially be set to the size of the privkey buffer. Upon return it
+ * will be set to the number of bytes used in the buffer.
+ * key32 must point to a 32-byte raw private key.
+ */
static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) {
+ assert(*privkeylen >= CKey::PRIVATE_KEY_SIZE);
secp256k1_pubkey pubkey;
size_t pubkeylen = 0;
if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) {
@@ -86,10 +116,11 @@ static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *pr
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
memcpy(ptr, key32, 32); ptr += 32;
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
- pubkeylen = 33;
+ pubkeylen = CPubKey::COMPRESSED_PUBLIC_KEY_SIZE;
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED);
ptr += pubkeylen;
*privkeylen = ptr - privkey;
+ assert(*privkeylen == CKey::COMPRESSED_PRIVATE_KEY_SIZE);
} else {
static const unsigned char begin[] = {
0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
@@ -111,10 +142,11 @@ static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *pr
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
memcpy(ptr, key32, 32); ptr += 32;
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
- pubkeylen = 65;
+ pubkeylen = CPubKey::PUBLIC_KEY_SIZE;
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
ptr += pubkeylen;
*privkeylen = ptr - privkey;
+ assert(*privkeylen == CKey::PRIVATE_KEY_SIZE);
}
return 1;
}
@@ -136,8 +168,8 @@ CPrivKey CKey::GetPrivKey() const {
CPrivKey privkey;
int ret;
size_t privkeylen;
- privkey.resize(279);
- privkeylen = 279;
+ privkey.resize(PRIVATE_KEY_SIZE);
+ privkeylen = PRIVATE_KEY_SIZE;
ret = ec_privkey_export_der(secp256k1_context_sign, (unsigned char*) privkey.data(), &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
assert(ret);
privkey.resize(privkeylen);
@@ -147,7 +179,7 @@ CPrivKey CKey::GetPrivKey() const {
CPubKey CKey::GetPubKey() const {
assert(fValid);
secp256k1_pubkey pubkey;
- size_t clen = 65;
+ size_t clen = CPubKey::PUBLIC_KEY_SIZE;
CPubKey result;
int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin());
assert(ret);
@@ -160,8 +192,8 @@ CPubKey CKey::GetPubKey() const {
bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_t test_case) const {
if (!fValid)
return false;
- vchSig.resize(72);
- size_t nSigLen = 72;
+ vchSig.resize(CPubKey::SIGNATURE_SIZE);
+ size_t nSigLen = CPubKey::SIGNATURE_SIZE;
unsigned char extra_entropy[32] = {0};
WriteLE32(extra_entropy, test_case);
secp256k1_ecdsa_signature sig;
@@ -189,7 +221,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
if (!fValid)
return false;
- vchSig.resize(65);
+ vchSig.resize(CPubKey::COMPACT_SIGNATURE_SIZE);
int rec = -1;
secp256k1_ecdsa_recoverable_signature sig;
int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, nullptr);
@@ -219,10 +251,10 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
std::vector<unsigned char, secure_allocator<unsigned char>> vout(64);
if ((nChild >> 31) == 0) {
CPubKey pubkey = GetPubKey();
- assert(pubkey.begin() + 33 == pubkey.end());
+ assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, vout.data());
} else {
- assert(begin() + 32 == end());
+ assert(size() == 32);
BIP32Hash(cc, nChild, 0, begin(), vout.data());
}
memcpy(ccChild.begin(), vout.data()+32, 32);
diff --git a/src/key.h b/src/key.h
index c610e5e6cd..8ef6c51b14 100644
--- a/src/key.h
+++ b/src/key.h
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -16,24 +17,29 @@
/**
- * secp256k1:
- * const unsigned int PRIVATE_KEY_SIZE = 279;
- * const unsigned int PUBLIC_KEY_SIZE = 65;
- * const unsigned int SIGNATURE_SIZE = 72;
- *
- * see www.keylength.com
- * script supports up to 75 for single byte push
- */
-
-/**
* secure_allocator is defined in allocators.h
- * CPrivKey is a serialized private key, with all parameters included (279 bytes)
+ * CPrivKey is a serialized private key, with all parameters included
+ * (PRIVATE_KEY_SIZE bytes)
*/
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
/** An encapsulated private key. */
class CKey
{
+public:
+ /**
+ * secp256k1:
+ */
+ static const unsigned int PRIVATE_KEY_SIZE = 279;
+ static const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214;
+ /**
+ * see www.keylength.com
+ * script supports up to 75 for single byte push
+ */
+ static_assert(
+ PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE,
+ "COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE");
+
private:
//! Whether this private key is valid. We check for correctness when modifying the key
//! data, so fValid should always correspond to the actual state.
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 5718a14ca2..4ab089e032 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -5,8 +5,6 @@
#include <keystore.h>
-#include <key.h>
-#include <pubkey.h>
#include <util.h>
bool CKeyStore::AddKey(const CKey &key) {
diff --git a/src/miner.cpp b/src/miner.cpp
index 397d99fc9a..0fb9b774d3 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -22,7 +22,6 @@
#include <primitives/transaction.h>
#include <script/standard.h>
#include <timedata.h>
-#include <txmempool.h>
#include <util.h>
#include <utilmoneystr.h>
#include <validationinterface.h>
diff --git a/src/miner.h b/src/miner.h
index 36276dc362..d81ec6421c 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -71,7 +71,7 @@ struct modifiedentry_iter {
// except operating on CTxMemPoolModifiedEntry.
// TODO: refactor to avoid duplication of this logic.
struct CompareModifiedEntry {
- bool operator()(const CTxMemPoolModifiedEntry &a, const CTxMemPoolModifiedEntry &b)
+ bool operator()(const CTxMemPoolModifiedEntry &a, const CTxMemPoolModifiedEntry &b) const
{
double f1 = (double)a.nModFeesWithAncestors * b.nSizeWithAncestors;
double f2 = (double)b.nModFeesWithAncestors * a.nSizeWithAncestors;
@@ -86,7 +86,7 @@ struct CompareModifiedEntry {
// This is sufficient to sort an ancestor package in an order that is valid
// to appear in a block.
struct CompareTxIterByAncestorCount {
- bool operator()(const CTxMemPool::txiter &a, const CTxMemPool::txiter &b)
+ bool operator()(const CTxMemPool::txiter &a, const CTxMemPool::txiter &b) const
{
if (a->GetCountWithAncestors() != b->GetCountWithAncestors())
return a->GetCountWithAncestors() < b->GetCountWithAncestors();
diff --git a/src/net.cpp b/src/net.cpp
index a8e5143d5e..e00faaeecd 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -9,13 +9,11 @@
#include <net.h>
-#include <addrman.h>
#include <chainparams.h>
#include <clientversion.h>
#include <consensus/consensus.h>
#include <crypto/common.h>
#include <crypto/sha256.h>
-#include <hash.h>
#include <primitives/transaction.h>
#include <netbase.h>
#include <scheduler.h>
@@ -110,13 +108,13 @@ bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
int nBestReachability = -1;
{
LOCK(cs_mapLocalHost);
- for (std::map<CNetAddr, LocalServiceInfo>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
+ for (const auto& entry : mapLocalHost)
{
- int nScore = (*it).second.nScore;
- int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
+ int nScore = entry.second.nScore;
+ int nReachability = entry.first.GetReachabilityFrom(paddrPeer);
if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore))
{
- addr = CService((*it).first, (*it).second.nPort);
+ addr = CService(entry.first, entry.second.nPort);
nBestReachability = nReachability;
nBestScore = nScore;
}
@@ -417,39 +415,48 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
if (addrConnect.IsValid()) {
bool proxyConnectionFailed = false;
- if (GetProxy(addrConnect.GetNetwork(), proxy))
+ if (GetProxy(addrConnect.GetNetwork(), proxy)) {
+ hSocket = CreateSocket(proxy.proxy);
+ if (hSocket == INVALID_SOCKET) {
+ return nullptr;
+ }
connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(), hSocket, nConnectTimeout, &proxyConnectionFailed);
- else // no proxy needed (none set for target network)
+ } else {
+ // no proxy needed (none set for target network)
+ hSocket = CreateSocket(addrConnect);
+ if (hSocket == INVALID_SOCKET) {
+ return nullptr;
+ }
connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout);
+ }
if (!proxyConnectionFailed) {
// If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to
// the proxy, mark this as an attempt.
addrman.Attempt(addrConnect, fCountFailure);
}
} else if (pszDest && GetNameProxy(proxy)) {
+ hSocket = CreateSocket(proxy.proxy);
+ if (hSocket == INVALID_SOCKET) {
+ return nullptr;
+ }
std::string host;
int port = default_port;
SplitHostPort(std::string(pszDest), port, host);
connected = ConnectThroughProxy(proxy, host, port, hSocket, nConnectTimeout, nullptr);
}
- if (connected) {
- if (!IsSelectableSocket(hSocket)) {
- LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
- CloseSocket(hSocket);
- return nullptr;
- }
-
- // Add node
- NodeId id = GetNewNodeId();
- uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
- CAddress addr_bind = GetBindAddress(hSocket);
- CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false);
- pnode->AddRef();
-
- return pnode;
+ if (!connected) {
+ CloseSocket(hSocket);
+ return nullptr;
}
- return nullptr;
+ // Add node
+ NodeId id = GetNewNodeId();
+ uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
+ CAddress addr_bind = GetBindAddress(hSocket);
+ CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false);
+ pnode->AddRef();
+
+ return pnode;
}
void CConnman::DumpBanlist()
@@ -596,21 +603,28 @@ void CConnman::SetBanned(const banmap_t &banMap)
void CConnman::SweepBanned()
{
int64_t now = GetTime();
-
- LOCK(cs_setBanned);
- banmap_t::iterator it = setBanned.begin();
- while(it != setBanned.end())
+ bool notifyUI = false;
{
- CSubNet subNet = (*it).first;
- CBanEntry banEntry = (*it).second;
- if(now > banEntry.nBanUntil)
+ LOCK(cs_setBanned);
+ banmap_t::iterator it = setBanned.begin();
+ while(it != setBanned.end())
{
- setBanned.erase(it++);
- setBannedIsDirty = true;
- LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString());
+ CSubNet subNet = (*it).first;
+ CBanEntry banEntry = (*it).second;
+ if(now > banEntry.nBanUntil)
+ {
+ setBanned.erase(it++);
+ setBannedIsDirty = true;
+ notifyUI = true;
+ LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString());
+ }
+ else
+ ++it;
}
- else
- ++it;
+ }
+ // update UI
+ if(notifyUI && clientInterface) {
+ clientInterface->BannedListChanged();
}
}
@@ -1102,7 +1116,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
if (IsBanned(addr) && !whitelisted)
{
- LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
+ LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString());
CloseSocket(hSocket);
return;
}
@@ -2058,44 +2072,21 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b
return false;
}
- SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
+ SOCKET hListenSocket = CreateSocket(addrBind);
if (hListenSocket == INVALID_SOCKET)
{
strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError);
return false;
}
- if (!IsSelectableSocket(hListenSocket))
- {
- strError = "Error: Couldn't create a listenable socket for incoming connections";
- LogPrintf("%s\n", strError);
- return false;
- }
-
-
#ifndef WIN32
-#ifdef SO_NOSIGPIPE
- // Different way of disabling SIGPIPE on BSD
- setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
-#endif
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted.
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
- // Disable Nagle's algorithm
- setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&nOne, sizeof(int));
#else
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int));
- setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&nOne, sizeof(int));
#endif
- // Set to non-blocking, incoming connections will also inherit this
- if (!SetSocketNonBlocking(hListenSocket, true)) {
- CloseSocket(hListenSocket);
- strError = strprintf("BindListenPort: Setting listening socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
- LogPrintf("%s\n", strError);
- return false;
- }
-
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
// and enable it by default or not. Try to enable it, if possible.
if (addrBind.IsIPv6()) {
@@ -2269,10 +2260,16 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
{
Init(connOptions);
- nTotalBytesRecv = 0;
- nTotalBytesSent = 0;
- nMaxOutboundTotalBytesSentInCycle = 0;
- nMaxOutboundCycleStartTime = 0;
+ {
+ LOCK(cs_totalBytesRecv);
+ nTotalBytesRecv = 0;
+ }
+ {
+ LOCK(cs_totalBytesSent);
+ nTotalBytesSent = 0;
+ nMaxOutboundTotalBytesSentInCycle = 0;
+ nMaxOutboundCycleStartTime = 0;
+ }
if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) {
if (clientInterface) {
diff --git a/src/net.h b/src/net.h
index a7223050e7..d0fd050970 100644
--- a/src/net.h
+++ b/src/net.h
@@ -158,10 +158,16 @@ public:
m_msgproc = connOptions.m_msgproc;
nSendBufferMaxSize = connOptions.nSendBufferMaxSize;
nReceiveFloodSize = connOptions.nReceiveFloodSize;
- nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe;
- nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
+ {
+ LOCK(cs_totalBytesSent);
+ nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe;
+ nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
+ }
vWhitelistedRange = connOptions.vWhitelistedRange;
- vAddedNodes = connOptions.m_added_nodes;
+ {
+ LOCK(cs_vAddedNodes);
+ vAddedNodes = connOptions.m_added_nodes;
+ }
}
CConnman(uint64_t seed0, uint64_t seed1);
@@ -364,14 +370,14 @@ private:
// Network usage totals
CCriticalSection cs_totalBytesRecv;
CCriticalSection cs_totalBytesSent;
- uint64_t nTotalBytesRecv;
- uint64_t nTotalBytesSent;
+ uint64_t nTotalBytesRecv GUARDED_BY(cs_totalBytesRecv);
+ uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent);
// outbound limit & stats
- uint64_t nMaxOutboundTotalBytesSentInCycle;
- uint64_t nMaxOutboundCycleStartTime;
- uint64_t nMaxOutboundLimit;
- uint64_t nMaxOutboundTimeframe;
+ uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(cs_totalBytesSent);
+ uint64_t nMaxOutboundCycleStartTime GUARDED_BY(cs_totalBytesSent);
+ uint64_t nMaxOutboundLimit GUARDED_BY(cs_totalBytesSent);
+ uint64_t nMaxOutboundTimeframe GUARDED_BY(cs_totalBytesSent);
// Whitelisted ranges. Any node connecting from these is automatically
// whitelisted (as well as those connecting to whitelisted binds).
@@ -389,7 +395,7 @@ private:
CAddrMan addrman;
std::deque<std::string> vOneShots;
CCriticalSection cs_vOneShots;
- std::vector<std::string> vAddedNodes;
+ std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
CCriticalSection cs_vAddedNodes;
std::vector<CNode*> vNodes;
std::list<CNode*> vNodesDisconnected;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 442cd00c9b..20426eaceb 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -14,7 +14,6 @@
#include <init.h>
#include <validation.h>
#include <merkleblock.h>
-#include <net.h>
#include <netmessagemaker.h>
#include <netbase.h>
#include <policy/fees.h>
@@ -30,7 +29,6 @@
#include <util.h>
#include <utilmoneystr.h>
#include <utilstrencodings.h>
-#include <validationinterface.h>
#if defined(NDEBUG)
# error "Bitcoin cannot be compiled without assertions."
@@ -41,7 +39,7 @@ std::atomic<int64_t> nTimeBestReceived(0); // Used only to inform the wallet of
struct IteratorComparator
{
template<typename I>
- bool operator()(const I& a, const I& b)
+ bool operator()(const I& a, const I& b) const
{
return &(*a) < &(*b);
}
@@ -1078,7 +1076,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
send = BlockRequestAllowed(mi->second, consensusParams);
if (!send) {
- LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId());
+ LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId());
}
}
// disconnect node in case we have reached the outbound limit for serving historical blocks
@@ -1091,6 +1089,16 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
pfrom->fDisconnect = true;
send = false;
}
+ // Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
+ if (send && !pfrom->fWhitelisted && (
+ (((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (chainActive.Tip()->nHeight - mi->second->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
+ )) {
+ LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId());
+
+ //disconnect node and prevent it from stalling (would otherwise wait for the missing block)
+ 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))
@@ -1559,7 +1567,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (nVersion < MIN_PEER_PROTO_VERSION)
{
// disconnect from peers older than this proto version
- LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion);
+ LogPrint(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion);
connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)));
pfrom->fDisconnect = true;
@@ -1659,7 +1667,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (fLogIPs)
remoteAddr = ", peeraddr=" + pfrom->addr.ToString();
- LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n",
+ LogPrint(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n",
cleanSubVer, pfrom->nVersion,
pfrom->nStartingHeight, addrMe.ToString(), pfrom->GetId(),
remoteAddr);
@@ -1702,6 +1710,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// Mark this node as currently connected, so we update its timestamp later.
LOCK(cs_main);
State(pfrom->GetId())->fCurrentlyConnected = true;
+ LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s\n",
+ pfrom->nVersion.load(), pfrom->nStartingHeight, pfrom->GetId(),
+ (fLogIPs ? strprintf(", peeraddr=%s", pfrom->addr.ToString()) : ""));
}
if (pfrom->nVersion >= SENDHEADERS_VERSION) {
@@ -1980,7 +1991,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
BlockMap::iterator it = mapBlockIndex.find(req.blockhash);
if (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA)) {
- LogPrintf("Peer %d sent us a getblocktxn for a block we don't have", pfrom->GetId());
+ LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have", pfrom->GetId());
return true;
}
@@ -2032,7 +2043,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pindex = (*mi).second;
if (!BlockRequestAllowed(pindex, chainparams.GetConsensus())) {
- LogPrintf("%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom->GetId());
+ LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom->GetId());
return true;
}
}
@@ -2286,10 +2297,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
int nDoS;
if (state.IsInvalid(nDoS)) {
if (nDoS > 0) {
+ LogPrintf("Peer %d sent us invalid header via cmpctblock\n", pfrom->GetId());
LOCK(cs_main);
Misbehaving(pfrom->GetId(), nDoS);
+ } else {
+ LogPrint(BCLog::NET, "Peer %d sent us invalid header via cmpctblock\n", pfrom->GetId());
}
- LogPrintf("Peer %d sent us invalid header via cmpctblock\n", pfrom->GetId());
return true;
}
}
@@ -2891,7 +2904,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
msg.SetVersion(pfrom->GetRecvVersion());
// Scan for message start
if (memcmp(msg.hdr.pchMessageStart, chainparams.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0) {
- LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->GetId());
+ LogPrint(BCLog::NET, "PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->GetId());
pfrom->fDisconnect = true;
return false;
}
@@ -2900,7 +2913,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
CMessageHeader& hdr = msg.hdr;
if (!hdr.IsValid(chainparams.MessageStart()))
{
- LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->GetId());
+ LogPrint(BCLog::NET, "PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->GetId());
return fMoreWork;
}
std::string strCommand = hdr.GetCommand();
@@ -2913,7 +2926,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
const uint256& hash = msg.GetMessageHash();
if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0)
{
- LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR expected %s was %s\n", __func__,
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): CHECKSUM ERROR expected %s was %s\n", __func__,
SanitizeString(strCommand), nMessageSize,
HexStr(hash.begin(), hash.begin()+CMessageHeader::CHECKSUM_SIZE),
HexStr(hdr.pchChecksum, hdr.pchChecksum+CMessageHeader::CHECKSUM_SIZE));
@@ -2936,17 +2949,17 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
if (strstr(e.what(), "end of data"))
{
// Allow exceptions from under-length message on vRecv
- LogPrintf("%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
}
else if (strstr(e.what(), "size too large"))
{
// Allow exceptions from over-long size
- LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
}
else if (strstr(e.what(), "non-canonical ReadCompactSize()"))
{
// Allow exceptions from non-canonical encoding
- LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
}
else
{
@@ -2960,7 +2973,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
}
if (!fRet) {
- LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->GetId());
+ LogPrint(BCLog::NET, "%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->GetId());
}
LOCK(cs_main);
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 3ef3c67ae4..fa1c191559 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -3,10 +3,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifdef HAVE_CONFIG_H
-#include <config/bitcoin-config.h>
-#endif
-
#include <netaddress.h>
#include <hash.h>
#include <utilstrencodings.h>
diff --git a/src/netbase.cpp b/src/netbase.cpp
index bd1eaf062f..f4232fc42a 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -3,10 +3,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifdef HAVE_CONFIG_H
-#include <config/bitcoin-config.h>
-#endif
-
#include <netbase.h>
#include <hash.h>
@@ -317,12 +313,11 @@ std::string Socks5ErrorString(uint8_t err)
}
/** Connect using SOCKS5 (as described in RFC1928) */
-static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)
+static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, const SOCKET& hSocket)
{
IntrRecvError recvr;
LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
if (strDest.size() > 255) {
- CloseSocket(hSocket);
return error("Hostname too long");
}
// Accepted authentication methods
@@ -338,17 +333,14 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
}
ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5Init.size()) {
- CloseSocket(hSocket);
return error("Error sending to proxy");
}
uint8_t pchRet1[2];
if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
- CloseSocket(hSocket);
LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
return false;
}
if (pchRet1[0] != SOCKSVersion::SOCKS5) {
- CloseSocket(hSocket);
return error("Proxy failed to initialize");
}
if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) {
@@ -363,23 +355,19 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vAuth.size()) {
- CloseSocket(hSocket);
return error("Error sending authentication to proxy");
}
LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
uint8_t pchRetA[2];
if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
- CloseSocket(hSocket);
return error("Error reading proxy authentication response");
}
if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
- CloseSocket(hSocket);
return error("Proxy authentication unsuccessful");
}
} else if (pchRet1[1] == SOCKS5Method::NOAUTH) {
// Perform no authentication
} else {
- CloseSocket(hSocket);
return error("Proxy requested wrong authentication method %02x", pchRet1[1]);
}
std::vector<uint8_t> vSocks5;
@@ -393,12 +381,10 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
vSocks5.push_back((port >> 0) & 0xFF);
ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5.size()) {
- CloseSocket(hSocket);
return error("Error sending to proxy");
}
uint8_t pchRet2[4];
if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
- CloseSocket(hSocket);
if (recvr == IntrRecvError::Timeout) {
/* If a timeout happens here, this effectively means we timed out while connecting
* to the remote node. This is very common for Tor, so do not print an
@@ -409,17 +395,14 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
}
}
if (pchRet2[0] != SOCKSVersion::SOCKS5) {
- CloseSocket(hSocket);
return error("Proxy failed to accept request");
}
if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) {
// Failures to connect to a peer that are not proxy errors
- CloseSocket(hSocket);
LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1]));
return false;
}
if (pchRet2[2] != 0x00) { // Reserved field must be 0
- CloseSocket(hSocket);
return error("Error: malformed proxy response");
}
uint8_t pchRet3[256];
@@ -431,41 +414,42 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
{
recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
if (recvr != IntrRecvError::OK) {
- CloseSocket(hSocket);
return error("Error reading from proxy");
}
int nRecv = pchRet3[0];
recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
break;
}
- default: CloseSocket(hSocket); return error("Error: malformed proxy response");
+ default: return error("Error: malformed proxy response");
}
if (recvr != IntrRecvError::OK) {
- CloseSocket(hSocket);
return error("Error reading from proxy");
}
if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
- CloseSocket(hSocket);
return error("Error reading from proxy");
}
LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest);
return true;
}
-bool ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout)
+SOCKET CreateSocket(const CService &addrConnect)
{
- hSocketRet = INVALID_SOCKET;
-
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
- LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString());
- return false;
+ LogPrintf("Cannot create socket for %s: unsupported network\n", addrConnect.ToString());
+ return INVALID_SOCKET;
}
SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET)
- return false;
+ return INVALID_SOCKET;
+
+ if (!IsSelectableSocket(hSocket)) {
+ CloseSocket(hSocket);
+ LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
+ return INVALID_SOCKET;
+ }
#ifdef SO_NOSIGPIPE
int set = 1;
@@ -479,9 +463,23 @@ bool ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int
// Set to non-blocking
if (!SetSocketNonBlocking(hSocket, true)) {
CloseSocket(hSocket);
- return error("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
+ LogPrintf("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
}
+ return hSocket;
+}
+bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout)
+{
+ struct sockaddr_storage sockaddr;
+ socklen_t len = sizeof(sockaddr);
+ if (hSocket == INVALID_SOCKET) {
+ LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToString());
+ return false;
+ }
+ if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
+ LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString());
+ return false;
+ }
if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
@@ -496,13 +494,11 @@ bool ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int
if (nRet == 0)
{
LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
- CloseSocket(hSocket);
return false;
}
if (nRet == SOCKET_ERROR)
{
LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
- CloseSocket(hSocket);
return false;
}
socklen_t nRetSize = sizeof(nRet);
@@ -513,13 +509,11 @@ bool ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int
#endif
{
LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
- CloseSocket(hSocket);
return false;
}
if (nRet != 0)
{
LogPrintf("connect() to %s failed after select(): %s\n", addrConnect.ToString(), NetworkErrorString(nRet));
- CloseSocket(hSocket);
return false;
}
}
@@ -530,12 +524,9 @@ bool ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int
#endif
{
LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
- CloseSocket(hSocket);
return false;
}
}
-
- hSocketRet = hSocket;
return true;
}
@@ -587,9 +578,8 @@ bool IsProxy(const CNetAddr &addr) {
return false;
}
-bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
+bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocket, int nTimeout, bool *outProxyConnectionFailed)
{
- SOCKET hSocket = INVALID_SOCKET;
// first connect to proxy server
if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout)) {
if (outProxyConnectionFailed)
@@ -601,14 +591,14 @@ bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int
ProxyCredentials random_auth;
static std::atomic_int counter(0);
random_auth.username = random_auth.password = strprintf("%i", counter++);
- if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket))
+ if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket)) {
return false;
+ }
} else {
- if (!Socks5(strDest, (unsigned short)port, 0, hSocket))
+ if (!Socks5(strDest, (unsigned short)port, 0, hSocket)) {
return false;
+ }
}
-
- hSocketRet = hSocket;
return true;
}
bool LookupSubNet(const char* pszName, CSubNet& ret)
diff --git a/src/netbase.h b/src/netbase.h
index 0a07be87b7..c89bd5b88f 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -51,8 +51,9 @@ bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLoo
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions);
CService LookupNumeric(const char *pszName, int portDefault = 0);
bool LookupSubNet(const char *pszName, CSubNet& subnet);
-bool ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout);
-bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed);
+SOCKET CreateSocket(const CService &addrConnect);
+bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocketRet, int nTimeout);
+bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed);
/** Return readable error string for a network error code */
std::string NetworkErrorString(int err);
/** Close socket and set hSocket to INVALID_SOCKET */
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 013116318b..490986fc11 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -6,10 +6,8 @@
#include <policy/fees.h>
#include <policy/policy.h>
-#include <amount.h>
#include <clientversion.h>
#include <primitives/transaction.h>
-#include <random.h>
#include <streams.h>
#include <txmempool.h>
#include <util.h>
@@ -413,15 +411,13 @@ void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets
size_t maxConfirms, maxPeriods;
// The current version will store the decay with each individual TxConfirmStats and also keep a scale factor
- if (nFileVersion >= 149900) {
- filein >> decay;
- if (decay <= 0 || decay >= 1) {
- throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
- }
- filein >> scale;
- if (scale == 0) {
- throw std::runtime_error("Corrupt estimates file. Scale must be non-zero");
- }
+ filein >> decay;
+ if (decay <= 0 || decay >= 1) {
+ throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
+ }
+ filein >> scale;
+ if (scale == 0) {
+ throw std::runtime_error("Corrupt estimates file. Scale must be non-zero");
}
filein >> avg;
@@ -445,20 +441,13 @@ void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets
}
}
- if (nFileVersion >= 149900) {
- filein >> failAvg;
- if (maxPeriods != failAvg.size()) {
- throw std::runtime_error("Corrupt estimates file. Mismatch in confirms tracked for failures");
- }
- for (unsigned int i = 0; i < maxPeriods; i++) {
- if (failAvg[i].size() != numBuckets) {
- throw std::runtime_error("Corrupt estimates file. Mismatch in one of failure average bucket counts");
- }
- }
- } else {
- failAvg.resize(confAvg.size());
- for (unsigned int i = 0; i < failAvg.size(); i++) {
- failAvg[i].resize(numBuckets);
+ filein >> failAvg;
+ if (maxPeriods != failAvg.size()) {
+ throw std::runtime_error("Corrupt estimates file. Mismatch in confirms tracked for failures");
+ }
+ for (unsigned int i = 0; i < maxPeriods; i++) {
+ if (failAvg[i].size() != numBuckets) {
+ throw std::runtime_error("Corrupt estimates file. Mismatch in one of failure average bucket counts");
}
}
@@ -565,7 +554,7 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
if (mapMemPoolTxs.count(hash)) {
LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error mempool tx %s already being tracked\n",
hash.ToString().c_str());
- return;
+ return;
}
if (txHeight != nBestSeenHeight) {
@@ -946,32 +935,9 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein)
unsigned int nFileBestSeenHeight;
filein >> nFileBestSeenHeight;
- if (nVersionThatWrote < 149900) {
- // Read the old fee estimates file for temporary use, but then discard. Will start collecting data from scratch.
- // decay is stored before buckets in old versions, so pre-read decay and pass into TxConfirmStats constructor
- double tempDecay;
- filein >> tempDecay;
- if (tempDecay <= 0 || tempDecay >= 1)
- throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
-
- std::vector<double> tempBuckets;
- filein >> tempBuckets;
- size_t tempNum = tempBuckets.size();
- if (tempNum <= 1 || tempNum > 1000)
- throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
-
- std::map<double, unsigned int> tempMap;
-
- std::unique_ptr<TxConfirmStats> tempFeeStats(new TxConfirmStats(tempBuckets, tempMap, MED_BLOCK_PERIODS, tempDecay, 1));
- tempFeeStats->Read(filein, nVersionThatWrote, tempNum);
- // if nVersionThatWrote < 139900 then another TxConfirmStats (for priority) follows but can be ignored.
-
- tempMap.clear();
- for (unsigned int i = 0; i < tempBuckets.size(); i++) {
- tempMap[tempBuckets[i]] = i;
- }
- }
- else { // nVersionThatWrote >= 149900
+ if (nVersionRequired < 149900) {
+ LogPrintf("%s: incompatible old fee estimation data (non-fatal). Version: %d\n", __func__, nVersionRequired);
+ } else { // New format introduced in 149900
unsigned int nFileHistoricalFirst, nFileHistoricalBest;
filein >> nFileHistoricalFirst >> nFileHistoricalBest;
if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
diff --git a/src/protocol.h b/src/protocol.h
index bc31434515..cf1d40db77 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -246,9 +246,8 @@ const std::vector<std::string> &getAllNetMessageTypes();
enum ServiceFlags : uint64_t {
// Nothing
NODE_NONE = 0,
- // NODE_NETWORK means that the node is capable of serving the block chain. It is currently
- // set by all Bitcoin Core nodes, and is unset by SPV clients or other peers that just want
- // network services but don't provide them.
+ // NODE_NETWORK means that the node is capable of serving the complete block chain. It is currently
+ // set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light clients.
NODE_NETWORK = (1 << 0),
// NODE_GETUTXO means the node is capable of responding to the getutxo protocol request.
// Bitcoin Core does not support this but a patch set called Bitcoin XT does.
@@ -264,6 +263,10 @@ enum ServiceFlags : uint64_t {
// NODE_XTHIN means the node supports Xtreme Thinblocks
// If this is turned off then the node will not service nor make xthin requests
NODE_XTHIN = (1 << 4),
+ // NODE_NETWORK_LIMITED means the same as NODE_NETWORK with the limitation of only
+ // serving the last 288 (2 day) blocks
+ // See BIP159 for details on how this is implemented.
+ NODE_NETWORK_LIMITED = (1 << 10),
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
// isn't getting used, or one not being used much, and notify the
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index 7f5ec1e8de..e52acf077c 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -1,4 +1,5 @@
// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -46,7 +47,7 @@ static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
- if (pos + lenbyte > inputlen) {
+ if (lenbyte > inputlen - pos) {
return 0;
}
pos += lenbyte;
@@ -65,14 +66,15 @@ static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
- if (pos + lenbyte > inputlen) {
+ if (lenbyte > inputlen - pos) {
return 0;
}
while (lenbyte > 0 && input[pos] == 0) {
pos++;
lenbyte--;
}
- if (lenbyte >= sizeof(size_t)) {
+ static_assert(sizeof(size_t) >= 4, "size_t too small");
+ if (lenbyte >= 4) {
return 0;
}
rlen = 0;
@@ -103,14 +105,15 @@ static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
- if (pos + lenbyte > inputlen) {
+ if (lenbyte > inputlen - pos) {
return 0;
}
while (lenbyte > 0 && input[pos] == 0) {
pos++;
lenbyte--;
}
- if (lenbyte >= sizeof(size_t)) {
+ static_assert(sizeof(size_t) >= 4, "size_t too small");
+ if (lenbyte >= 4) {
return 0;
}
slen = 0;
@@ -181,7 +184,7 @@ bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchS
}
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
- if (vchSig.size() != 65)
+ if (vchSig.size() != COMPACT_SIGNATURE_SIZE)
return false;
int recid = (vchSig[0] - 27) & 3;
bool fComp = ((vchSig[0] - 27) & 4) != 0;
@@ -193,8 +196,8 @@ bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned cha
if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) {
return false;
}
- unsigned char pub[65];
- size_t publen = 65;
+ unsigned char pub[PUBLIC_KEY_SIZE];
+ size_t publen = PUBLIC_KEY_SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
Set(pub, pub + publen);
return true;
@@ -214,8 +217,8 @@ bool CPubKey::Decompress() {
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
return false;
}
- unsigned char pub[65];
- size_t publen = 65;
+ unsigned char pub[PUBLIC_KEY_SIZE];
+ size_t publen = PUBLIC_KEY_SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
Set(pub, pub + publen);
return true;
@@ -224,7 +227,7 @@ bool CPubKey::Decompress() {
bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {
assert(IsValid());
assert((nChild >> 31) == 0);
- assert(begin() + 33 == end());
+ assert(size() == COMPRESSED_PUBLIC_KEY_SIZE);
unsigned char out[64];
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
memcpy(ccChild.begin(), out+32, 32);
@@ -235,8 +238,8 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi
if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) {
return false;
}
- unsigned char pub[33];
- size_t publen = 33;
+ unsigned char pub[COMPRESSED_PUBLIC_KEY_SIZE];
+ size_t publen = COMPRESSED_PUBLIC_KEY_SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);
pubkeyChild.Set(pub, pub + publen);
return true;
@@ -248,8 +251,8 @@ void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
memcpy(code+9, chaincode.begin(), 32);
- assert(pubkey.size() == 33);
- memcpy(code+41, pubkey.begin(), 33);
+ assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
+ memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
}
void CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {
diff --git a/src/pubkey.h b/src/pubkey.h
index c9f3c18eb3..e6c32913de 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,16 +14,6 @@
#include <stdexcept>
#include <vector>
-/**
- * secp256k1:
- * const unsigned int PRIVATE_KEY_SIZE = 279;
- * const unsigned int PUBLIC_KEY_SIZE = 65;
- * const unsigned int SIGNATURE_SIZE = 72;
- *
- * see www.keylength.com
- * script supports up to 75 for single byte push
- */
-
const unsigned int BIP32_EXTKEY_SIZE = 74;
/** A reference to a CKey: the Hash160 of its serialized public key */
@@ -38,21 +29,37 @@ typedef uint256 ChainCode;
/** An encapsulated public key. */
class CPubKey
{
+public:
+ /**
+ * secp256k1:
+ */
+ static const unsigned int PUBLIC_KEY_SIZE = 65;
+ static const unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33;
+ static const unsigned int SIGNATURE_SIZE = 72;
+ static const unsigned int COMPACT_SIGNATURE_SIZE = 65;
+ /**
+ * see www.keylength.com
+ * script supports up to 75 for single byte push
+ */
+ static_assert(
+ PUBLIC_KEY_SIZE >= COMPRESSED_PUBLIC_KEY_SIZE,
+ "COMPRESSED_PUBLIC_KEY_SIZE is larger than PUBLIC_KEY_SIZE");
+
private:
/**
* Just store the serialized data.
* Its length can very cheaply be computed from the first byte.
*/
- unsigned char vch[65];
+ unsigned char vch[PUBLIC_KEY_SIZE];
//! Compute the length of a pubkey with a given first byte.
unsigned int static GetLen(unsigned char chHeader)
{
if (chHeader == 2 || chHeader == 3)
- return 33;
+ return COMPRESSED_PUBLIC_KEY_SIZE;
if (chHeader == 4 || chHeader == 6 || chHeader == 7)
- return 65;
+ return PUBLIC_KEY_SIZE;
return 0;
}
@@ -127,7 +134,7 @@ public:
void Unserialize(Stream& s)
{
unsigned int len = ::ReadCompactSize(s);
- if (len <= 65) {
+ if (len <= PUBLIC_KEY_SIZE) {
s.read((char*)vch, len);
} else {
// invalid pubkey, skip available data
@@ -166,7 +173,7 @@ public:
//! Check whether this is a compressed public key.
bool IsCompressed() const
{
- return size() == 33;
+ return size() == COMPRESSED_PUBLIC_KEY_SIZE;
}
/**
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index 84807da65d..c96bdfd5d7 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -55,11 +55,11 @@ public:
#if QT_VERSION >= 0x040700
cachedBanlist.reserve(banMap.size());
#endif
- for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
+ for (const auto& entry : banMap)
{
CCombinedBan banEntry;
- banEntry.subnet = (*it).first;
- banEntry.banEntry = (*it).second;
+ banEntry.subnet = entry.first;
+ banEntry.banEntry = entry.second;
cachedBanlist.append(banEntry);
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index cd3234c564..f925ec5359 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -2,10 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
#include <qt/bitcoingui.h>
#include <qt/bitcoinunits.h>
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 03e633e375..49f4e74a9f 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -28,9 +28,7 @@
#include <QFlags>
#include <QIcon>
#include <QSettings>
-#include <QString>
#include <QTreeWidget>
-#include <QTreeWidgetItem>
QList<CAmount> CoinControlDialog::payAmounts;
CCoinControl* CoinControlDialog::coinControl = new CCoinControl();
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index 9c89741afe..c6fd708cdf 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -1108,10 +1108,10 @@
<item>
<widget class="QCheckBox" name="optInRBF">
<property name="text">
- <string>Request Replace-By-Fee</string>
+ <string>Allow increasing fee</string>
</property>
<property name="toolTip">
- <string>Indicates that the sender may wish to replace this transaction with a new one paying higher fees (prior to being confirmed).</string>
+ <string>This allows you to increase the fee later if the transaction takes a long time to confirm. This will also cause the recommended fee to be lower. ("Replace-By-Fee", BIP 125)</string>
</property>
</widget>
</item>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 80ee35a341..eb5d3304af 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -9,7 +9,6 @@
#include <qt/qvalidatedlineedit.h>
#include <qt/walletmodel.h>
-#include <fs.h>
#include <primitives/transaction.h>
#include <init.h>
#include <policy/policy.h>
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index 4f8732a9ce..f4383bf679 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -6,7 +6,6 @@
#include <QApplication>
#include <QByteArray>
-#include <QIcon>
#include <QImageWriter>
#include <QMessageBox>
#include <QMetaType>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index d7aa8bc38b..a0f78d5ead 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -338,7 +338,7 @@ QValidator::State ProxyAddressValidator::validate(QString &input, int &pos) cons
{
Q_UNUSED(pos);
// Validate the proxy
- CService serv(LookupNumeric(input.toStdString().c_str(), 9050));
+ CService serv(LookupNumeric(input.toStdString().c_str(), DEFAULT_GUI_PROXY_PORT));
proxyType addrProxy = proxyType(serv, true);
if (addrProxy.IsValid())
return QValidator::Acceptable;
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index a0645d9a74..c9e4f517c7 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -11,7 +11,6 @@
#include <qt/bitcoinunits.h>
#include <qt/guiutil.h>
-#include <amount.h>
#include <init.h>
#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
#include <net.h>
@@ -28,6 +27,8 @@
#include <QSettings>
#include <QStringList>
+const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1";
+
OptionsModel::OptionsModel(QObject *parent, bool resetSettings) :
QAbstractListModel(parent)
{
@@ -124,8 +125,8 @@ void OptionsModel::Init(bool resetSettings)
if (!settings.contains("fUseProxy"))
settings.setValue("fUseProxy", false);
- if (!settings.contains("addrProxy") || !settings.value("addrProxy").toString().contains(':'))
- settings.setValue("addrProxy", "127.0.0.1:9050");
+ if (!settings.contains("addrProxy"))
+ settings.setValue("addrProxy", QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST, DEFAULT_GUI_PROXY_PORT));
// Only try to set -proxy, if user has enabled fUseProxy
if (settings.value("fUseProxy").toBool() && !gArgs.SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
addOverriddenOption("-proxy");
@@ -134,8 +135,8 @@ void OptionsModel::Init(bool resetSettings)
if (!settings.contains("fUseSeparateProxyTor"))
settings.setValue("fUseSeparateProxyTor", false);
- if (!settings.contains("addrSeparateProxyTor") || !settings.value("addrSeparateProxyTor").toString().contains(':'))
- settings.setValue("addrSeparateProxyTor", "127.0.0.1:9050");
+ if (!settings.contains("addrSeparateProxyTor"))
+ settings.setValue("addrSeparateProxyTor", QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST, DEFAULT_GUI_PROXY_PORT));
// Only try to set -onion, if user has enabled fUseSeparateProxyTor
if (settings.value("fUseSeparateProxyTor").toBool() && !gArgs.SoftSetArg("-onion", settings.value("addrSeparateProxyTor").toString().toStdString()))
addOverriddenOption("-onion");
@@ -200,6 +201,33 @@ int OptionsModel::rowCount(const QModelIndex & parent) const
return OptionIDRowCount;
}
+struct ProxySetting {
+ bool is_set;
+ QString ip;
+ QString port;
+};
+
+static ProxySetting GetProxySetting(QSettings &settings, const QString &name)
+{
+ static const ProxySetting default_val = {false, DEFAULT_GUI_PROXY_HOST, QString("%1").arg(DEFAULT_GUI_PROXY_PORT)};
+ // Handle the case that the setting is not set at all
+ if (!settings.contains(name)) {
+ return default_val;
+ }
+ // contains IP at index 0 and port at index 1
+ QStringList ip_port = settings.value(name).toString().split(":", QString::SkipEmptyParts);
+ if (ip_port.size() == 2) {
+ return {true, ip_port.at(0), ip_port.at(1)};
+ } else { // Invalid: return default
+ return default_val;
+ }
+}
+
+static void SetProxySetting(QSettings &settings, const QString &name, const ProxySetting &ip_port)
+{
+ settings.setValue(name, ip_port.ip + ":" + ip_port.port);
+}
+
// read QSettings values and return them
QVariant OptionsModel::data(const QModelIndex & index, int role) const
{
@@ -226,30 +254,18 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
// default proxy
case ProxyUse:
return settings.value("fUseProxy", false);
- case ProxyIP: {
- // contains IP at index 0 and port at index 1
- QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
- return strlIpPort.at(0);
- }
- case ProxyPort: {
- // contains IP at index 0 and port at index 1
- QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
- return strlIpPort.at(1);
- }
+ case ProxyIP:
+ return GetProxySetting(settings, "addrProxy").ip;
+ case ProxyPort:
+ return GetProxySetting(settings, "addrProxy").port;
// separate Tor proxy
case ProxyUseTor:
return settings.value("fUseSeparateProxyTor", false);
- case ProxyIPTor: {
- // contains IP at index 0 and port at index 1
- QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
- return strlIpPort.at(0);
- }
- case ProxyPortTor: {
- // contains IP at index 0 and port at index 1
- QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
- return strlIpPort.at(1);
- }
+ case ProxyIPTor:
+ return GetProxySetting(settings, "addrSeparateProxyTor").ip;
+ case ProxyPortTor:
+ return GetProxySetting(settings, "addrSeparateProxyTor").port;
#ifdef ENABLE_WALLET
case SpendZeroConfChange:
@@ -314,25 +330,19 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
}
break;
case ProxyIP: {
- // contains current IP at index 0 and current port at index 1
- QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
- // if that key doesn't exist or has a changed IP
- if (!settings.contains("addrProxy") || strlIpPort.at(0) != value.toString()) {
- // construct new value from new IP and current port
- QString strNewValue = value.toString() + ":" + strlIpPort.at(1);
- settings.setValue("addrProxy", strNewValue);
+ auto ip_port = GetProxySetting(settings, "addrProxy");
+ if (!ip_port.is_set || ip_port.ip != value.toString()) {
+ ip_port.ip = value.toString();
+ SetProxySetting(settings, "addrProxy", ip_port);
setRestartRequired(true);
}
}
break;
case ProxyPort: {
- // contains current IP at index 0 and current port at index 1
- QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
- // if that key doesn't exist or has a changed port
- if (!settings.contains("addrProxy") || strlIpPort.at(1) != value.toString()) {
- // construct new value from current IP and new port
- QString strNewValue = strlIpPort.at(0) + ":" + value.toString();
- settings.setValue("addrProxy", strNewValue);
+ auto ip_port = GetProxySetting(settings, "addrProxy");
+ if (!ip_port.is_set || ip_port.port != value.toString()) {
+ ip_port.port = value.toString();
+ SetProxySetting(settings, "addrProxy", ip_port);
setRestartRequired(true);
}
}
@@ -346,25 +356,19 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
}
break;
case ProxyIPTor: {
- // contains current IP at index 0 and current port at index 1
- QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
- // if that key doesn't exist or has a changed IP
- if (!settings.contains("addrSeparateProxyTor") || strlIpPort.at(0) != value.toString()) {
- // construct new value from new IP and current port
- QString strNewValue = value.toString() + ":" + strlIpPort.at(1);
- settings.setValue("addrSeparateProxyTor", strNewValue);
+ auto ip_port = GetProxySetting(settings, "addrSeparateProxyTor");
+ if (!ip_port.is_set || ip_port.ip != value.toString()) {
+ ip_port.ip = value.toString();
+ SetProxySetting(settings, "addrSeparateProxyTor", ip_port);
setRestartRequired(true);
}
}
break;
case ProxyPortTor: {
- // contains current IP at index 0 and current port at index 1
- QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
- // if that key doesn't exist or has a changed port
- if (!settings.contains("addrSeparateProxyTor") || strlIpPort.at(1) != value.toString()) {
- // construct new value from current IP and new port
- QString strNewValue = strlIpPort.at(0) + ":" + value.toString();
- settings.setValue("addrSeparateProxyTor", strNewValue);
+ auto ip_port = GetProxySetting(settings, "addrSeparateProxyTor");
+ if (!ip_port.is_set || ip_port.port != value.toString()) {
+ ip_port.port = value.toString();
+ SetProxySetting(settings, "addrSeparateProxyTor", ip_port);
setRestartRequired(true);
}
}
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index b6e8fdef68..f8782dd204 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -13,6 +13,9 @@ QT_BEGIN_NAMESPACE
class QNetworkProxy;
QT_END_NAMESPACE
+extern const char *DEFAULT_GUI_PROXY_HOST;
+static constexpr unsigned short DEFAULT_GUI_PROXY_PORT = 9050;
+
/** Interface from Qt to configuration data structure for Bitcoin client.
To Qt, the options are presented as a list with the different options
laid out vertically.
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
index cc8ea3622b..0e1bd59ada 100644
--- a/src/qt/platformstyle.cpp
+++ b/src/qt/platformstyle.cpp
@@ -8,10 +8,8 @@
#include <QApplication>
#include <QColor>
-#include <QIcon>
#include <QImage>
#include <QPalette>
-#include <QPixmap>
static const struct {
const char *platformId;
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index d6e2beb312..e9dcbc0a72 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -8,7 +8,6 @@
#include <qt/addressbookpage.h>
#include <qt/addresstablemodel.h>
#include <qt/bitcoinunits.h>
-#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/receiverequestdialog.h>
@@ -17,7 +16,6 @@
#include <QAction>
#include <QCursor>
-#include <QItemSelection>
#include <QMessageBox>
#include <QScrollBar>
#include <QTextDocument>
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index c69fea1c93..d30e9b2dca 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -9,7 +9,6 @@
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
-#include <qt/walletmodel.h>
#include <QClipboard>
#include <QDrag>
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 6687d62baa..0b90205270 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -11,7 +11,6 @@
#include <qt/bantablemodel.h>
#include <qt/clientmodel.h>
-#include <qt/guiutil.h>
#include <qt/platformstyle.h>
#include <chainparams.h>
#include <netbase.h>
@@ -35,7 +34,6 @@
#include <QScrollBar>
#include <QSettings>
#include <QSignalMapper>
-#include <QThread>
#include <QTime>
#include <QTimer>
#include <QStringList>
@@ -392,11 +390,37 @@ void RPCExecutor::request(const QString &command)
{
std::string result;
std::string executableCommand = command.toStdString() + "\n";
+
+ // Catch the console-only-help command before RPC call is executed and reply with help text as-if a RPC reply.
+ if(executableCommand == "help-console\n")
+ {
+ Q_EMIT reply(RPCConsole::CMD_REPLY, QString(("\n"
+ "This console accepts RPC commands using the standard syntax.\n"
+ " example: getblockhash 0\n\n"
+
+ "This console can also accept RPC commands using parenthesized syntax.\n"
+ " example: getblockhash(0)\n\n"
+
+ "Commands may be nested when specified with the parenthesized syntax.\n"
+ " example: getblock(getblockhash(0) 1)\n\n"
+
+ "A space or a comma can be used to delimit arguments for either syntax.\n"
+ " example: getblockhash 0\n"
+ " getblockhash,0\n\n"
+
+ "Named results can be queried with a non-quoted key string in brackets.\n"
+ " example: getblock(getblockhash(0) true)[tx]\n\n"
+
+ "Results without keys can be queried using an integer in brackets.\n"
+ " example: getblock(getblockhash(0),true)[tx][0]\n\n")));
+ return;
+ }
if(!RPCConsole::RPCExecuteCommandLine(result, executableCommand))
{
Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
return;
}
+
Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(result));
}
catch (UniValue& objError)
@@ -645,6 +669,7 @@ void RPCConsole::setClientModel(ClientModel *model)
wordList << ("help " + commandList[i]).c_str();
}
+ wordList << "help-console";
wordList.sort();
autoCompleter = new QCompleter(wordList, this);
autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
@@ -750,10 +775,11 @@ void RPCConsole::clear(bool clearHistory)
message(CMD_REPLY, (tr("Welcome to the %1 RPC console.").arg(tr(PACKAGE_NAME)) + "<br>" +
tr("Use up and down arrows to navigate history, and %1 to clear screen.").arg("<b>"+clsKey+"</b>") + "<br>" +
- tr("Type <b>help</b> for an overview of available commands.")) +
- "<br><span class=\"secwarning\">" +
+ tr("Type %1 for an overview of available commands.").arg("<b>help</b>") + "<br>" +
+ tr("For more information on using this console type %1.").arg("<b>help-console</b>") +
+ "<br><span class=\"secwarning\"><br>" +
tr("WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.") +
- "</span>",
+ "</span>"),
true);
}
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 036b6ebcc0..faddfcd4d0 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -13,7 +13,6 @@
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/sendcoinsentry.h>
-#include <qt/walletmodel.h>
#include <base58.h>
#include <chainparams.h>
@@ -25,11 +24,9 @@
#include <wallet/fees.h>
#include <QFontMetrics>
-#include <QMessageBox>
#include <QScrollBar>
#include <QSettings>
#include <QTextDocument>
-#include <QTimer>
static const std::array<int, 9> confTargets = { {2, 4, 6, 12, 24, 48, 144, 504, 1008} };
int getConfTargetForIndex(int index) {
@@ -165,7 +162,7 @@ void SendCoinsDialog::setModel(WalletModel *_model)
coinControlUpdateLabels();
// fee section
- for (const int &n : confTargets) {
+ for (const int n : confTargets) {
ui->confTargetSelector->addItem(tr("%1 (%2 blocks)").arg(GUIUtil::formatNiceTimeOffset(n*Params().GetConsensus().nPowTargetSpacing)).arg(n));
}
connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSmartFeeLabel()));
@@ -345,7 +342,7 @@ void SendCoinsDialog::on_sendButton_clicked()
if (ui->optInRBF->isChecked())
{
questionString.append("<hr /><span>");
- questionString.append(tr("This transaction signals replaceability (optin-RBF)."));
+ questionString.append(tr("You can increase the fee later (signals Replace-By-Fee)."));
questionString.append("</span>");
}
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index 20e39bdeba..4cf4bb9ef7 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -10,7 +10,6 @@
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
-#include <qt/walletmodel.h>
#include <QApplication>
#include <QClipboard>
diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp
index 15859bf36d..47890fc7e2 100644
--- a/src/qt/transactionfilterproxy.cpp
+++ b/src/qt/transactionfilterproxy.cpp
@@ -9,8 +9,6 @@
#include <cstdlib>
-#include <QDateTime>
-
// Earliest date that can be represented (far in the past)
const QDateTime TransactionFilterProxy::MIN_DATE = QDateTime::fromTime_t(0);
// Last date that can be represented (far in the future)
@@ -20,7 +18,7 @@ TransactionFilterProxy::TransactionFilterProxy(QObject *parent) :
QSortFilterProxyModel(parent),
dateFrom(MIN_DATE),
dateTo(MAX_DATE),
- addrPrefix(),
+ m_search_string(),
typeFilter(ALL_TYPES),
watchOnlyFilter(WatchOnlyFilter_All),
minAmount(0),
@@ -38,6 +36,7 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &
bool involvesWatchAddress = index.data(TransactionTableModel::WatchonlyRole).toBool();
QString address = index.data(TransactionTableModel::AddressRole).toString();
QString label = index.data(TransactionTableModel::LabelRole).toString();
+ QString txid = index.data(TransactionTableModel::TxIDRole).toString();
qint64 amount = llabs(index.data(TransactionTableModel::AmountRole).toLongLong());
int status = index.data(TransactionTableModel::StatusRole).toInt();
@@ -51,8 +50,11 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &
return false;
if(datetime < dateFrom || datetime > dateTo)
return false;
- if (!address.contains(addrPrefix, Qt::CaseInsensitive) && !label.contains(addrPrefix, Qt::CaseInsensitive))
+ if (!address.contains(m_search_string, Qt::CaseInsensitive) &&
+ ! label.contains(m_search_string, Qt::CaseInsensitive) &&
+ ! txid.contains(m_search_string, Qt::CaseInsensitive)) {
return false;
+ }
if(amount < minAmount)
return false;
@@ -66,9 +68,10 @@ void TransactionFilterProxy::setDateRange(const QDateTime &from, const QDateTime
invalidateFilter();
}
-void TransactionFilterProxy::setAddressPrefix(const QString &_addrPrefix)
+void TransactionFilterProxy::setSearchString(const QString &search_string)
{
- this->addrPrefix = _addrPrefix;
+ if (m_search_string == search_string) return;
+ m_search_string = search_string;
invalidateFilter();
}
diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h
index 4bdd9ea6c7..fea7502b26 100644
--- a/src/qt/transactionfilterproxy.h
+++ b/src/qt/transactionfilterproxy.h
@@ -35,7 +35,7 @@ public:
};
void setDateRange(const QDateTime &from, const QDateTime &to);
- void setAddressPrefix(const QString &addrPrefix);
+ void setSearchString(const QString &);
/**
@note Type filter takes a bit field created with TYPE() or ALL_TYPES
*/
@@ -57,7 +57,7 @@ protected:
private:
QDateTime dateFrom;
QDateTime dateTo;
- QString addrPrefix;
+ QString m_search_string;
quint32 typeFilter;
WatchOnlyFilter watchOnlyFilter;
CAmount minAmount;
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index cc0dc5ef48..67580f11ae 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -80,10 +80,10 @@ public:
cachedWallet.clear();
{
LOCK2(cs_main, wallet->cs_wallet);
- for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it)
+ for (const auto& entry : wallet->mapWallet)
{
- if(TransactionRecord::showTransaction(it->second))
- cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
+ if (TransactionRecord::showTransaction(entry.second))
+ cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, entry.second));
}
}
}
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 92e8e91600..b7e39e05ec 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -8,7 +8,6 @@
#include <qt/bitcoinunits.h>
#include <qt/csvmodelwriter.h>
#include <qt/editaddressdialog.h>
-#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/sendcoinsdialog.h>
@@ -95,11 +94,11 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
hlayout->addWidget(typeWidget);
- addressWidget = new QLineEdit(this);
+ search_widget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
- addressWidget->setPlaceholderText(tr("Enter address or label to search"));
+ search_widget->setPlaceholderText(tr("Enter address, transaction id, or label to search"));
#endif
- hlayout->addWidget(addressWidget);
+ hlayout->addWidget(search_widget);
amountWidget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
@@ -187,8 +186,8 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
connect(watchOnlyWidget, SIGNAL(activated(int)), this, SLOT(chooseWatchonly(int)));
connect(amountWidget, SIGNAL(textChanged(QString)), amount_typing_delay, SLOT(start()));
connect(amount_typing_delay, SIGNAL(timeout()), this, SLOT(changedAmount()));
- connect(addressWidget, SIGNAL(textChanged(QString)), prefix_typing_delay, SLOT(start()));
- connect(prefix_typing_delay, SIGNAL(timeout()), this, SLOT(changedPrefix()));
+ connect(search_widget, SIGNAL(textChanged(QString)), prefix_typing_delay, SLOT(start()));
+ connect(prefix_typing_delay, SIGNAL(timeout()), this, SLOT(changedSearch()));
connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
@@ -326,11 +325,11 @@ void TransactionView::chooseWatchonly(int idx)
(TransactionFilterProxy::WatchOnlyFilter)watchOnlyWidget->itemData(idx).toInt());
}
-void TransactionView::changedPrefix()
+void TransactionView::changedSearch()
{
if(!transactionProxyModel)
return;
- transactionProxyModel->setAddressPrefix(addressWidget->text());
+ transactionProxyModel->setSearchString(search_widget->text());
}
void TransactionView::changedAmount()
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index 5b28b34723..f72a828b00 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -66,7 +66,7 @@ private:
QComboBox *dateWidget;
QComboBox *typeWidget;
QComboBox *watchOnlyWidget;
- QLineEdit *addressWidget;
+ QLineEdit *search_widget;
QLineEdit *amountWidget;
QMenu *contextMenu;
@@ -113,7 +113,7 @@ public Q_SLOTS:
void chooseType(int idx);
void chooseWatchonly(int idx);
void changedAmount();
- void changedPrefix();
+ void changedSearch();
void exportClicked();
void focusTransaction(const QModelIndex&);
diff --git a/src/random.h b/src/random.h
index 9309917689..a984545467 100644
--- a/src/random.h
+++ b/src/random.h
@@ -128,7 +128,7 @@ public:
* sure that the underlying OS APIs for all platforms support the number.
* (many cap out at 256 bytes).
*/
-static const ssize_t NUM_OS_RANDOM_BYTES = 32;
+static const int NUM_OS_RANDOM_BYTES = 32;
/** Get 32 bytes of system entropy. Do not use this in application code: use
* GetStrongRandBytes instead.
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 601965d4c4..b7895b86f7 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1113,13 +1113,13 @@ static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Conse
return rv;
}
-void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const std::string &name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
+void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
{
// Deployments with timeout value of 0 are hidden.
// A timeout value of 0 guarantees a softfork will never be activated.
// This is used when softfork codes are merged without specifying the deployment schedule.
if (consensusParams.vDeployments[id].nTimeout > 0)
- bip9_softforks.push_back(Pair(name, BIP9SoftForkDesc(consensusParams, id)));
+ bip9_softforks.push_back(Pair(VersionBitsDeploymentInfo[id].name, BIP9SoftForkDesc(consensusParams, id)));
}
UniValue getblockchaininfo(const JSONRPCRequest& request)
@@ -1214,8 +1214,9 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
- BIP9SoftForkDescPushBack(bip9_softforks, "csv", consensusParams, Consensus::DEPLOYMENT_CSV);
- BIP9SoftForkDescPushBack(bip9_softforks, "segwit", consensusParams, Consensus::DEPLOYMENT_SEGWIT);
+ for (int pos = Consensus::DEPLOYMENT_CSV; pos != Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++pos) {
+ BIP9SoftForkDescPushBack(bip9_softforks, consensusParams, static_cast<Consensus::DeploymentPos>(pos));
+ }
obj.push_back(Pair("softforks", softforks));
obj.push_back(Pair("bip9_softforks", bip9_softforks));
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index a595b6ec27..e641493e1e 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -10,8 +10,6 @@
#include <set>
#include <stdint.h>
-#include <univalue.h>
-
class CRPCConvertParam
{
public:
@@ -93,11 +91,13 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "createrawtransaction", 1, "outputs" },
{ "createrawtransaction", 2, "locktime" },
{ "createrawtransaction", 3, "replaceable" },
+ { "decoderawtransaction", 1, "iswitness" },
{ "signrawtransaction", 1, "prevtxs" },
{ "signrawtransaction", 2, "privkeys" },
{ "sendrawtransaction", 1, "allowhighfees" },
{ "combinerawtransaction", 0, "txs" },
{ "fundrawtransaction", 1, "options" },
+ { "fundrawtransaction", 2, "iswitness" },
{ "gettxout", 1, "n" },
{ "gettxout", 2, "include_mempool" },
{ "gettxoutproof", 0, "txids" },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 1753ecd3fc..d003be4954 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -29,8 +29,6 @@
#include <memory>
#include <stdint.h>
-#include <univalue.h>
-
unsigned int ParseConfirmTarget(const UniValue& value)
{
int target = value.get_int();
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index b3e22f5f10..327af2e237 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -187,17 +187,24 @@ UniValue validateaddress(const JSONRPCRequest& request)
ret.push_back(Pair("account", pwallet->mapAddressBook[dest].name));
}
if (pwallet) {
- const auto& meta = pwallet->mapKeyMetadata;
- const CKeyID *keyID = boost::get<CKeyID>(&dest);
- auto it = keyID ? meta.find(*keyID) : meta.end();
- if (it == meta.end()) {
- it = meta.find(CScriptID(scriptPubKey));
+ const CKeyMetadata* meta = nullptr;
+ if (const CKeyID* key_id = boost::get<CKeyID>(&dest)) {
+ auto it = pwallet->mapKeyMetadata.find(*key_id);
+ if (it != pwallet->mapKeyMetadata.end()) {
+ meta = &it->second;
+ }
+ }
+ if (!meta) {
+ auto it = pwallet->m_script_metadata.find(CScriptID(scriptPubKey));
+ if (it != pwallet->m_script_metadata.end()) {
+ meta = &it->second;
+ }
}
- if (it != meta.end()) {
- ret.push_back(Pair("timestamp", it->second.nCreateTime));
- if (!it->second.hdKeypath.empty()) {
- ret.push_back(Pair("hdkeypath", it->second.hdKeypath));
- ret.push_back(Pair("hdmasterkeyid", it->second.hdMasterKeyID.GetHex()));
+ if (meta) {
+ ret.push_back(Pair("timestamp", meta->nCreateTime));
+ if (!meta->hdKeypath.empty()) {
+ ret.push_back(Pair("hdkeypath", meta->hdKeypath));
+ ret.push_back(Pair("hdmasterkeyid", meta->hdMasterKeyID.GetHex()));
}
}
}
@@ -533,6 +540,9 @@ uint32_t getCategoryMask(UniValue cats) {
if (!GetLogCategory(&flag, &cat)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat);
}
+ if (flag == BCLog::NONE) {
+ return 0;
+ }
mask |= flag;
}
return mask;
@@ -542,16 +552,32 @@ UniValue logging(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 2) {
throw std::runtime_error(
- "logging [include,...] <exclude>\n"
+ "logging ( <include> <exclude> )\n"
"Gets and sets the logging configuration.\n"
- "When called without an argument, returns the list of categories that are currently being debug logged.\n"
- "When called with arguments, adds or removes categories from debug logging.\n"
+ "When called without an argument, returns the list of categories with status that are currently being debug logged or not.\n"
+ "When called with arguments, adds or removes categories from debug logging and return the lists above.\n"
+ "The arguments are evaluated in order \"include\", \"exclude\".\n"
+ "If an item is both included and excluded, it will thus end up being excluded.\n"
"The valid logging categories are: " + ListLogCategories() + "\n"
- "libevent logging is configured on startup and cannot be modified by this RPC during runtime."
- "Arguments:\n"
- "1. \"include\" (array of strings) add debug logging for these categories.\n"
- "2. \"exclude\" (array of strings) remove debug logging for these categories.\n"
- "\nResult: <categories> (string): a list of the logging categories that are active.\n"
+ "In addition, the following are available as category names with special meanings:\n"
+ " - \"all\", \"1\" : represent all logging categories.\n"
+ " - \"none\", \"0\" : even if other logging categories are specified, ignore all of them.\n"
+ "\nArguments:\n"
+ "1. \"include\" (array of strings, optional) A json array of categories to add debug logging\n"
+ " [\n"
+ " \"category\" (string) the valid logging category\n"
+ " ,...\n"
+ " ]\n"
+ "2. \"exclude\" (array of strings, optional) A json array of categories to remove debug logging\n"
+ " [\n"
+ " \"category\" (string) the valid logging category\n"
+ " ,...\n"
+ " ]\n"
+ "\nResult:\n"
+ "{ (json object where keys are the logging categories, and values indicates its status\n"
+ " \"category\": 0|1, (numeric) if being debug logged or not. 0:inactive, 1:active\n"
+ " ...\n"
+ "}\n"
"\nExamples:\n"
+ HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
+ HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"")
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 322a3e0cbd..9de249855c 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -571,11 +571,11 @@ UniValue listbanned(const JSONRPCRequest& request)
g_connman->GetBanned(banMap);
UniValue bannedAddresses(UniValue::VARR);
- for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
+ for (const auto& entry : banMap)
{
- CBanEntry banEntry = (*it).second;
+ const CBanEntry& banEntry = entry.second;
UniValue rec(UniValue::VOBJ);
- rec.push_back(Pair("address", (*it).first.ToString()));
+ rec.push_back(Pair("address", entry.first.ToString()));
rec.push_back(Pair("banned_until", banEntry.nBanUntil));
rec.push_back(Pair("ban_created", banEntry.nCreateTime));
rec.push_back(Pair("ban_reason", banEntry.banReasonToString()));
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index 4cb28c2104..d999a08d74 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -12,7 +12,6 @@
#include <utiltime.h>
#include <version.h>
-#include <stdint.h>
#include <fstream>
/**
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index e65959bf0e..1049131d5e 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -64,12 +64,15 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
UniValue getrawtransaction(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw std::runtime_error(
- "getrawtransaction \"txid\" ( verbose )\n"
+ "getrawtransaction \"txid\" ( verbose \"blockhash\" )\n"
"\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n"
- "enabled, it also works for blockchain transactions.\n"
+ "enabled, it also works for blockchain transactions. If the block which contains the transaction\n"
+ "is known, its hash can be provided even for nodes without -txindex. Note that if a blockhash is\n"
+ "provided, only that block will be searched and if the transaction is in the mempool or other\n"
+ "blocks, or if this node does not have the given block available, the transaction will not be found.\n"
"DEPRECATED: for now, it also works for transactions with unspent outputs.\n"
"\nReturn the raw transaction data.\n"
@@ -78,13 +81,15 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
- "2. verbose (bool, optional, default=false) If false, return a string, otherwise return a json object\n"
+ "2. verbose (bool, optional, default=false) If false, return a string, otherwise return a json object\n"
+ "3. \"blockhash\" (string, optional) The block in which to look for the transaction\n"
"\nResult (if verbose is not set or set to false):\n"
"\"data\" (string) The serialized, hex-encoded data for 'txid'\n"
"\nResult (if verbose is set to true):\n"
"{\n"
+ " \"in_active_chain\": b, (bool) Whether specified block is in the active chain or not (only present with explicit \"blockhash\" argument)\n"
" \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n"
" \"txid\" : \"id\", (string) The transaction id (same as provided)\n"
" \"hash\" : \"id\", (string) The transaction hash (differs from txid for witness transactions)\n"
@@ -132,42 +137,56 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
+ HelpExampleCli("getrawtransaction", "\"mytxid\"")
+ HelpExampleCli("getrawtransaction", "\"mytxid\" true")
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", true")
+ + HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"")
+ + HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"")
);
LOCK(cs_main);
+ bool in_active_chain = true;
uint256 hash = ParseHashV(request.params[0], "parameter 1");
+ CBlockIndex* blockindex = nullptr;
// Accept either a bool (true) or a num (>=1) to indicate verbose output.
bool fVerbose = false;
if (!request.params[1].isNull()) {
- if (request.params[1].isNum()) {
- if (request.params[1].get_int() != 0) {
- fVerbose = true;
- }
- }
- else if(request.params[1].isBool()) {
- if(request.params[1].isTrue()) {
- fVerbose = true;
- }
- }
- else {
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid type provided. Verbose parameter must be a boolean.");
+ fVerbose = request.params[1].isNum() ? (request.params[1].get_int() != 0) : request.params[1].get_bool();
+ }
+
+ if (!request.params[2].isNull()) {
+ uint256 blockhash = ParseHashV(request.params[2], "parameter 3");
+ BlockMap::iterator it = mapBlockIndex.find(blockhash);
+ if (it == mapBlockIndex.end()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found");
}
+ blockindex = it->second;
+ in_active_chain = chainActive.Contains(blockindex);
}
CTransactionRef tx;
- uint256 hashBlock;
- if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string(fTxIndex ? "No such mempool or blockchain transaction"
- : "No such mempool transaction. Use -txindex to enable blockchain transaction queries") +
- ". Use gettransaction for wallet transactions.");
+ uint256 hash_block;
+ if (!GetTransaction(hash, tx, Params().GetConsensus(), hash_block, true, blockindex)) {
+ std::string errmsg;
+ if (blockindex) {
+ if (!(blockindex->nStatus & BLOCK_HAVE_DATA)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Block not available");
+ }
+ errmsg = "No such transaction found in the provided block";
+ } else {
+ errmsg = fTxIndex
+ ? "No such mempool or blockchain transaction"
+ : "No such mempool transaction. Use -txindex to enable blockchain transaction queries";
+ }
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errmsg + ". Use gettransaction for wallet transactions.");
+ }
- if (!fVerbose)
+ if (!fVerbose) {
return EncodeHexTx(*tx, RPCSerializationFlags());
+ }
UniValue result(UniValue::VOBJ);
- TxToJSON(*tx, hashBlock, result);
+ if (blockindex) result.push_back(Pair("in_active_chain", in_active_chain));
+ TxToJSON(*tx, hash_block, result);
return result;
}
@@ -330,7 +349,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"")
);
- RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VOBJ, UniValue::VNUM}, true);
+ RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VOBJ, UniValue::VNUM, UniValue::VBOOL}, true);
if (request.params[0].isNull() || request.params[1].isNull())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
@@ -422,13 +441,15 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
UniValue decoderawtransaction(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
- "decoderawtransaction \"hexstring\"\n"
+ "decoderawtransaction \"hexstring\" ( iswitness )\n"
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n"
"\nArguments:\n"
"1. \"hexstring\" (string, required) The transaction hex string\n"
+ "2. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction\n"
+ " If iswitness is not present, heuristic tests will be used in decoding\n"
"\nResult:\n"
"{\n"
@@ -476,12 +497,16 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)
);
LOCK(cs_main);
- RPCTypeCheck(request.params, {UniValue::VSTR});
+ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
CMutableTransaction mtx;
- if (!DecodeHexTx(mtx, request.params[0].get_str(), true))
+ bool try_witness = request.params[1].isNull() ? true : request.params[1].get_bool();
+ bool try_no_witness = request.params[1].isNull() ? true : !request.params[1].get_bool();
+
+ if (!DecodeHexTx(mtx, request.params[0].get_str(), try_no_witness, try_witness)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
+ }
UniValue result(UniValue::VOBJ);
TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false);
@@ -970,6 +995,10 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
}
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
+ } else {
+ // Make sure we don't block forever if re-sending
+ // a transaction already in mempool.
+ promise.set_value();
}
} // cs_main
@@ -991,9 +1020,9 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose"} },
+ { "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose","blockhash"} },
{ "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime","replaceable"} },
- { "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring"} },
+ { "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring","iswitness"} },
{ "rawtransactions", "decodescript", &decodescript, {"hexstring"} },
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees"} },
{ "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index fa81398272..2e7e0ba474 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -14,8 +14,6 @@
#include <util.h>
#include <utilstrencodings.h>
-#include <univalue.h>
-
#include <boost/bind.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/algorithm/string/case_conv.hpp> // for to_upper()
@@ -160,8 +158,8 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
std::set<rpcfn_type> setDone;
std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
- for (std::map<std::string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
- vCommands.push_back(make_pair(mi->second->category + mi->first, mi->second));
+ for (const auto& entry : mapCommands)
+ vCommands.push_back(make_pair(entry.second->category + entry.first, entry.second));
sort(vCommands.begin(), vCommands.end());
JSONRPCRequest jreq(helpreq);
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index d6348f17d8..62042e8e70 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -5,7 +5,6 @@
#include <script/interpreter.h>
-#include <primitives/transaction.h>
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
@@ -174,7 +173,13 @@ bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {
if (!IsValidSignatureEncoding(vchSig)) {
return set_error(serror, SCRIPT_ERR_SIG_DER);
}
+ // https://bitcoin.stackexchange.com/a/12556:
+ // Also note that inside transaction signatures, an extra hashtype byte
+ // follows the actual signature data.
std::vector<unsigned char> vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - 1);
+ // If the S value is above the order of the curve divided by two, its
+ // complement modulo the order could have been used instead, which is
+ // one byte shorter when encoded correctly.
if (!CPubKey::CheckLowS(vchSigCopy)) {
return set_error(serror, SCRIPT_ERR_SIG_HIGH_S);
}
@@ -349,9 +354,6 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
{
if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
// not enabled; treat as a NOP2
- if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
- return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
- }
break;
}
@@ -391,9 +393,6 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
{
if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
// not enabled; treat as a NOP3
- if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
- return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
- }
break;
}
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 2eae68179e..83a96739b1 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -27,37 +27,40 @@ enum
SIGHASH_ANYONECANPAY = 0x80,
};
-/** Script verification flags */
+/** Script verification flags.
+ *
+ * All flags are intended to be soft forks: the set of acceptable scripts under
+ * flags (A | B) is a subset of the acceptable scripts under flag (A).
+ */
enum
{
SCRIPT_VERIFY_NONE = 0,
- // Evaluate P2SH subscripts (softfork safe, BIP16).
+ // Evaluate P2SH subscripts (BIP16).
SCRIPT_VERIFY_P2SH = (1U << 0),
// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
// Evaluating a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script failure.
- // (softfork safe, but not used or intended as a consensus rule).
+ // (not used or intended as a consensus rule).
SCRIPT_VERIFY_STRICTENC = (1U << 1),
- // Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1)
+ // Passing a non-strict-DER signature to a checksig operation causes script failure (BIP62 rule 1)
SCRIPT_VERIFY_DERSIG = (1U << 2),
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
- // (softfork safe, BIP62 rule 5).
+ // (BIP62 rule 5).
SCRIPT_VERIFY_LOW_S = (1U << 3),
- // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7).
+ // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (BIP62 rule 7).
SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
- // Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2).
+ // Using a non-push operator in the scriptSig causes script failure (BIP62 rule 2).
SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5),
// Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct
// pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating
// any other push causes the script to fail (BIP62 rule 3).
// In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4).
- // (softfork safe)
SCRIPT_VERIFY_MINIMALDATA = (1U << 6),
// Discourage use of NOPs reserved for upgrades (NOP1-10)
@@ -68,12 +71,14 @@ enum
// discouraged NOPs fails the script. This verification flag will never be
// a mandatory flag applied to scripts in a block. NOPs that are not
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
+ // NOPs that have associated forks to give them new meaning (CLTV, CSV)
+ // are not subject to this rule.
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7),
// Require that only a single stack element remains after evaluation. This changes the success criterion from
// "At least one stack element must remain, and when interpreted as a boolean, it must be true" to
// "Exactly one stack element must remain, and when interpreted as a boolean, it must be true".
- // (softfork safe, BIP62 rule 6)
+ // (BIP62 rule 6)
// Note: CLEANSTACK should never be used without P2SH or WITNESS.
SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 60bef3b701..5849f55651 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -8,7 +8,6 @@
#include <key.h>
#include <keystore.h>
#include <script/script.h>
-#include <script/standard.h>
#include <script/sign.h>
diff --git a/src/serialize.h b/src/serialize.h
index 62ecde4823..02d3e4f7c6 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -732,8 +732,8 @@ template<typename Stream, typename K, typename T, typename Pred, typename A>
void Serialize(Stream& os, const std::map<K, T, Pred, A>& m)
{
WriteCompactSize(os, m.size());
- for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
- Serialize(os, (*mi));
+ for (const auto& entry : m)
+ Serialize(os, entry);
}
template<typename Stream, typename K, typename T, typename Pred, typename A>
diff --git a/src/streams.h b/src/streams.h
index a212691f6d..c26b1f618c 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -241,8 +241,8 @@ public:
const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
reference operator[](size_type pos) { return vch[pos + nReadPos]; }
void clear() { vch.clear(); nReadPos = 0; }
- iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); }
- void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); }
+ iterator insert(iterator it, const char x=char()) { return vch.insert(it, x); }
+ void insert(iterator it, size_type n, const char x) { vch.insert(it, n, x); }
value_type* data() { return vch.data() + nReadPos; }
const value_type* data() const { return vch.data() + nReadPos; }
diff --git a/src/support/cleanse.cpp b/src/support/cleanse.cpp
index 82cdfe707b..8d3c7369b4 100644
--- a/src/support/cleanse.cpp
+++ b/src/support/cleanse.cpp
@@ -7,6 +7,10 @@
#include <cstring>
+#if defined(_MSC_VER)
+#include <Windows.h> // For SecureZeroMemory.
+#endif
+
/* Compilers have a bad habit of removing "superfluous" memset calls that
* are trying to zero memory. For example, when memset()ing a buffer and
* then free()ing it, the compiler might decide that the memset is
@@ -32,7 +36,7 @@ void memory_cleanse(void *ptr, size_t len)
might try to eliminate "superfluous" memsets. If there's an easy way to
detect memset_s, it would be better to use that. */
#if defined(_MSC_VER)
- __asm;
+ SecureZeroMemory(ptr, len);
#else
__asm__ __volatile__("" : : "r"(ptr) : "memory");
#endif
diff --git a/src/sync.cpp b/src/sync.cpp
index fcc6ddc354..3f51383ea2 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -4,14 +4,16 @@
#include <sync.h>
+#include <set>
#include <util.h>
#include <utilstrencodings.h>
#include <stdio.h>
-#include <boost/thread.hpp>
-
#ifdef DEBUG_LOCKCONTENTION
+#if !defined(HAVE_THREAD_LOCAL)
+static_assert(false, "thread_local is not supported");
+#endif
void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
{
LogPrintf("LOCKCONTENTION: %s\n", pszName);
@@ -45,8 +47,8 @@ struct CLockLocation {
return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
}
- bool fTry;
private:
+ bool fTry;
std::string mutexName;
std::string sourceFile;
int sourceLine;
@@ -67,10 +69,10 @@ struct LockData {
LockOrders lockorders;
InvLockOrders invlockorders;
- boost::mutex dd_mutex;
+ std::mutex dd_mutex;
} static lockdata;
-boost::thread_specific_ptr<LockStack> lockstack;
+static thread_local std::unique_ptr<LockStack> lockstack;
static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
@@ -100,12 +102,12 @@ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch,
static void push_lock(void* c, const CLockLocation& locklocation)
{
- if (lockstack.get() == nullptr)
+ if (!lockstack)
lockstack.reset(new LockStack);
- boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
+ std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
- (*lockstack).push_back(std::make_pair(c, locklocation));
+ lockstack->push_back(std::make_pair(c, locklocation));
for (const std::pair<void*, CLockLocation> & i : (*lockstack)) {
if (i.first == c)
@@ -171,7 +173,7 @@ void DeleteLock(void* cs)
// We're already shutting down.
return;
}
- boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
+ std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
std::pair<void*, void*> item = std::make_pair(cs, nullptr);
LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
while (it != lockdata.lockorders.end() && it->first.first == cs) {
diff --git a/src/sync.h b/src/sync.h
index b0889be767..3af27c65d0 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -8,8 +8,6 @@
#include <threadsafety.h>
-#include <boost/thread/condition_variable.hpp>
-#include <boost/thread/mutex.hpp>
#include <condition_variable>
#include <thread>
#include <mutex>
@@ -196,8 +194,8 @@ public:
class CSemaphore
{
private:
- boost::condition_variable condition;
- boost::mutex mutex;
+ std::condition_variable condition;
+ std::mutex mutex;
int value;
public:
@@ -205,16 +203,14 @@ public:
void wait()
{
- boost::unique_lock<boost::mutex> lock(mutex);
- while (value < 1) {
- condition.wait(lock);
- }
+ std::unique_lock<std::mutex> lock(mutex);
+ condition.wait(lock, [&]() { return value >= 1; });
value--;
}
bool try_wait()
{
- boost::unique_lock<boost::mutex> lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
if (value < 1)
return false;
value--;
@@ -224,7 +220,7 @@ public:
void post()
{
{
- boost::unique_lock<boost::mutex> lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
value++;
}
condition.notify_one();
diff --git a/src/test/README.md b/src/test/README.md
index dbaa9c27f3..01da32109b 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -52,4 +52,4 @@ examine `uint256_tests.cpp`.
For further reading, I found the following website to be helpful in
explaining how the boost unit test framework works:
-[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/).
+[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://archive.is/dRBGf).
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index d8ad0d9165..42f9dd0600 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_tests.cpp
@@ -24,7 +24,7 @@
// otherwise.
BOOST_FIXTURE_TEST_SUITE(checkqueue_tests, TestingSetup)
-static const int QUEUE_BATCH_SIZE = 128;
+static const unsigned int QUEUE_BATCH_SIZE = 128;
struct FakeCheck {
bool operator()()
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 7c3d02ba63..ed556c07f4 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -81,8 +81,8 @@ public:
// Manually recompute the dynamic usage of the whole data, and compare it.
size_t ret = memusage::DynamicUsage(cacheCoins);
size_t count = 0;
- for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
- ret += it->second.coin.DynamicMemoryUsage();
+ for (const auto& entry : cacheCoins) {
+ ret += entry.second.coin.DynamicMemoryUsage();
++count;
}
BOOST_CHECK_EQUAL(GetCacheSize(), count);
@@ -189,15 +189,15 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
// Once every 1000 iterations and at the end, verify the full cache.
if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
- for (auto it = result.begin(); it != result.end(); it++) {
- bool have = stack.back()->HaveCoin(it->first);
- const Coin& coin = stack.back()->AccessCoin(it->first);
+ for (const auto& entry : result) {
+ bool have = stack.back()->HaveCoin(entry.first);
+ const Coin& coin = stack.back()->AccessCoin(entry.first);
BOOST_CHECK(have == !coin.IsSpent());
- BOOST_CHECK(coin == it->second);
+ BOOST_CHECK(coin == entry.second);
if (coin.IsSpent()) {
missed_an_entry = true;
} else {
- BOOST_CHECK(stack.back()->HaveCoinInCache(it->first));
+ BOOST_CHECK(stack.back()->HaveCoinInCache(entry.first));
found_an_entry = true;
}
}
@@ -420,11 +420,11 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// Once every 1000 iterations and at the end, verify the full cache.
if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
- for (auto it = result.begin(); it != result.end(); it++) {
- bool have = stack.back()->HaveCoin(it->first);
- const Coin& coin = stack.back()->AccessCoin(it->first);
+ for (const auto& entry : result) {
+ bool have = stack.back()->HaveCoin(entry.first);
+ const Coin& coin = stack.back()->AccessCoin(entry.first);
BOOST_CHECK(have == !coin.IsSpent());
- BOOST_CHECK(coin == it->second);
+ BOOST_CHECK(coin == entry.second);
}
}
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index a63d62bb37..125b68e76d 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -340,6 +340,22 @@ BOOST_AUTO_TEST_CASE(hmac_sha256_testvectors) {
"647320746f20626520686173686564206265666f7265206265696e6720757365"
"642062792074686520484d414320616c676f726974686d2e",
"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2");
+ // Test case with key length 63 bytes.
+ TestHMACSHA256("4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "9de4b546756c83516720a4ad7fe7bdbeac4298c6fdd82b15f895a6d10b0769a6");
+ // Test case with key length 64 bytes.
+ TestHMACSHA256("4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "528c609a4c9254c274585334946b7c2661bad8f1fc406b20f6892478d19163dd");
+ // Test case with key length 65 bytes.
+ TestHMACSHA256("4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "d06af337f359a2330deffb8e3cbe4b5b7aa8ca1f208528cdbd245d5dc63c4483");
}
BOOST_AUTO_TEST_CASE(hmac_sha512_testvectors) {
@@ -383,6 +399,31 @@ BOOST_AUTO_TEST_CASE(hmac_sha512_testvectors) {
"642062792074686520484d414320616c676f726974686d2e",
"e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944"
"b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58");
+ // Test case with key length 127 bytes.
+ TestHMACSHA512("4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "267424dfb8eeb999f3e5ec39a4fe9fd14c923e6187e0897063e5c9e02b2e624a"
+ "c04413e762977df71a9fb5d562b37f89dfdfb930fce2ed1fa783bbc2a203d80e");
+ // Test case with key length 128 bytes.
+ TestHMACSHA512("4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "43aaac07bb1dd97c82c04df921f83b16a68d76815cd1a30d3455ad43a3d80484"
+ "2bb35462be42cc2e4b5902de4d204c1c66d93b47d1383e3e13a3788687d61258");
+ // Test case with key length 129 bytes.
+ TestHMACSHA512("4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "0b273325191cfc1b4b71d5075c8fcad67696309d292b1dad2cd23983a35feb8e"
+ "fb29795e79f2ef27f68cb1e16d76178c307a67beaad9456fac5fdffeadb16e2c");
}
BOOST_AUTO_TEST_CASE(aes_testvectors) {
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
index 698e898231..63f43c0fc6 100644
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -862,8 +862,6 @@
["Ensure 100% coverage of discouraged NOPS"],
["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "CHECKLOCKTIMEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "CHECKSEQUENCEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP6", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index b1a2032ea8..97c548dbb0 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -26,6 +26,17 @@
BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup)
+// BOOST_CHECK_EXCEPTION predicates to check the specific validation error
+class HasReason {
+public:
+ HasReason(const std::string& reason) : m_reason(reason) {}
+ bool operator() (const std::runtime_error& e) const {
+ return std::string(e.what()).find(m_reason) != std::string::npos;
+ };
+private:
+ const std::string m_reason;
+};
+
static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
static BlockAssembler AssemblerForTest(const CChainParams& params) {
@@ -264,7 +275,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
tx.vin[0].prevout.hash = hash;
}
- BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
+
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops"));
mempool.clear();
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
@@ -304,7 +316,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
// orphan in mempool, template creation fails
hash = tx.GetHash();
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
- BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
mempool.clear();
// child with higher feerate than parent
@@ -332,7 +344,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
hash = tx.GetHash();
// give it a fee so it'll get mined
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
+ // Should throw bad-cb-multiple
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple"));
mempool.clear();
// double spend txn pair in mempool, template creation fails
@@ -345,7 +358,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].scriptPubKey = CScript() << OP_2;
hash = tx.GetHash();
mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
mempool.clear();
// subsidy changing
@@ -389,7 +402,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetHash();
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
+ // Should throw block-validation-failed
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed"));
mempool.clear();
// Delete the dummy blocks again.
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 710d09ead6..c69b5f1ca3 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -65,7 +65,9 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams)
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").get_int(), 193);
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1);
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0);
- BOOST_CHECK_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" extra"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC(std::string("decoderawtransaction ")+rawtx+" extra"), std::runtime_error);
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" false"));
+ BOOST_CHECK_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" false extra"), std::runtime_error);
BOOST_CHECK_THROW(CallRPC("signrawtransaction"), std::runtime_error);
BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), std::runtime_error);
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 57b3e501af..f96d867bc6 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -166,6 +166,17 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript
CMutableTransaction tx2 = tx;
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message);
BOOST_CHECK_MESSAGE(err == scriptError, std::string(FormatScriptError(err)) + " where " + std::string(FormatScriptError((ScriptError_t)scriptError)) + " expected: " + message);
+
+ // Verify that removing flags from a passing test or adding flags to a failing test does not change the result.
+ for (int i = 0; i < 16; ++i) {
+ int extra_flags = InsecureRandBits(16);
+ int combined_flags = expect ? (flags & ~extra_flags) : (flags | extra_flags);
+ // Weed out some invalid flag combinations.
+ if (combined_flags & SCRIPT_VERIFY_CLEANSTACK && ~combined_flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) continue;
+ if (combined_flags & SCRIPT_VERIFY_WITNESS && ~combined_flags & SCRIPT_VERIFY_P2SH) continue;
+ BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, combined_flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message + strprintf(" (with flags %x)", combined_flags));
+ }
+
#if defined(HAVE_CONSENSUS_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << tx2;
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 419106194e..f52c8ccc21 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -8,15 +8,9 @@
#include <consensus/consensus.h>
#include <consensus/validation.h>
#include <crypto/sha256.h>
-#include <fs.h>
-#include <key.h>
#include <validation.h>
#include <miner.h>
#include <net_processing.h>
-#include <pubkey.h>
-#include <random.h>
-#include <txdb.h>
-#include <txmempool.h>
#include <ui_interface.h>
#include <streams.h>
#include <rpc/server.h>
diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp
new file mode 100644
index 0000000000..2d1eb7b772
--- /dev/null
+++ b/src/test/txvalidation_tests.cpp
@@ -0,0 +1,61 @@
+// Copyright (c) 2017 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 <validation.h>
+#include <txmempool.h>
+#include <amount.h>
+#include <consensus/validation.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <test/test_bitcoin.h>
+
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_AUTO_TEST_SUITE(txvalidation_tests)
+
+/**
+ * Ensure that the mempool won't accept coinbase transactions.
+ */
+BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
+{
+ CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
+ CMutableTransaction coinbaseTx;
+
+ coinbaseTx.nVersion = 1;
+ coinbaseTx.vin.resize(1);
+ coinbaseTx.vout.resize(1);
+ coinbaseTx.vin[0].scriptSig = CScript() << OP_11 << OP_EQUAL;
+ coinbaseTx.vout[0].nValue = 1 * CENT;
+ coinbaseTx.vout[0].scriptPubKey = scriptPubKey;
+
+ assert(CTransaction(coinbaseTx).IsCoinBase());
+
+ CValidationState state;
+
+ LOCK(cs_main);
+
+ unsigned int initialPoolSize = mempool.size();
+
+ BOOST_CHECK_EQUAL(
+ false,
+ AcceptToMemoryPool(mempool, state, MakeTransactionRef(coinbaseTx),
+ nullptr /* pfMissingInputs */,
+ nullptr /* plTxnReplaced */,
+ true /* bypass_limits */,
+ 0 /* nAbsurdFee */));
+
+ // Check that the transaction hasn't been added to mempool.
+ BOOST_CHECK_EQUAL(mempool.size(), initialPoolSize);
+
+ // Check that the validation state reflects the unsuccessful attempt.
+ BOOST_CHECK(state.IsInvalid());
+ BOOST_CHECK_EQUAL(state.GetRejectReason(), "coinbase");
+
+ int nDoS;
+ BOOST_CHECK_EQUAL(state.IsInvalid(nDoS), true);
+ BOOST_CHECK_EQUAL(nDoS, 100);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index fa49b9c33b..fe8cb6126e 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -103,7 +103,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
// should fail.
// Capture this interaction with the upgraded_nop argument: set it when evaluating
// any script flag that is implemented as an upgraded NOP code.
-void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, uint32_t failing_flags, bool add_to_cache, bool upgraded_nop)
+void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, uint32_t failing_flags, bool add_to_cache)
{
PrecomputedTransactionData txdata(tx);
// If we add many more flags, this loop can get too expensive, but we can
@@ -124,12 +124,6 @@ void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, uint32_t failing_fl
// CheckInputs should succeed iff test_flags doesn't intersect with
// failing_flags
bool expected_return_value = !(test_flags & failing_flags);
- if (expected_return_value && upgraded_nop) {
- // If the script flag being tested corresponds to an upgraded NOP,
- // then script execution should fail if DISCOURAGE_UPGRADABLE_NOPS
- // is set.
- expected_return_value = !(test_flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS);
- }
BOOST_CHECK_EQUAL(ret, expected_return_value);
// Test the caching
@@ -218,7 +212,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
// not present. Don't add these checks to the cache, so that we can
// test later that block validation works fine in the absence of cached
// successes.
- ValidateCheckInputsForAllFlags(spend_tx, SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false, false);
+ ValidateCheckInputsForAllFlags(spend_tx, SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false);
// And if we produce a block with this tx, it should be valid (DERSIG not
// enabled yet), even though there's no cache entry.
@@ -243,7 +237,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
std::vector<unsigned char> vchSig2(p2pk_scriptPubKey.begin(), p2pk_scriptPubKey.end());
invalid_under_p2sh_tx.vin[0].scriptSig << vchSig2;
- ValidateCheckInputsForAllFlags(invalid_under_p2sh_tx, SCRIPT_VERIFY_P2SH, true, false);
+ ValidateCheckInputsForAllFlags(invalid_under_p2sh_tx, SCRIPT_VERIFY_P2SH, true);
}
// Test CHECKLOCKTIMEVERIFY
@@ -266,7 +260,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
vchSig.push_back((unsigned char)SIGHASH_ALL);
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
- ValidateCheckInputsForAllFlags(invalid_with_cltv_tx, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true);
+ ValidateCheckInputsForAllFlags(invalid_with_cltv_tx, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true);
// Make it valid, and check again
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
@@ -294,7 +288,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
vchSig.push_back((unsigned char)SIGHASH_ALL);
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
- ValidateCheckInputsForAllFlags(invalid_with_csv_tx, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true);
+ ValidateCheckInputsForAllFlags(invalid_with_csv_tx, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true);
// Make it valid, and check again
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
@@ -323,11 +317,11 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
UpdateTransaction(valid_with_witness_tx, 0, sigdata);
// This should be valid under all script flags.
- ValidateCheckInputsForAllFlags(valid_with_witness_tx, 0, true, false);
+ ValidateCheckInputsForAllFlags(valid_with_witness_tx, 0, true);
// Remove the witness, and check that it is now invalid.
valid_with_witness_tx.vin[0].scriptWitness.SetNull();
- ValidateCheckInputsForAllFlags(valid_with_witness_tx, SCRIPT_VERIFY_WITNESS, true, false);
+ ValidateCheckInputsForAllFlags(valid_with_witness_tx, SCRIPT_VERIFY_WITNESS, true);
}
{
@@ -352,7 +346,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
}
// This should be valid under all script flags
- ValidateCheckInputsForAllFlags(tx, 0, true, false);
+ ValidateCheckInputsForAllFlags(tx, 0, true);
// Check that if the second input is invalid, but the first input is
// valid, the transaction is not cached.
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
deleted file mode 100644
index 7386204437..0000000000
--- a/src/test/univalue_tests.cpp
+++ /dev/null
@@ -1,333 +0,0 @@
-// Copyright (c) 2014 BitPay Inc.
-// Copyright (c) 2014-2016 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include <stdint.h>
-#include <vector>
-#include <string>
-#include <map>
-#include <univalue.h>
-#include <test/test_bitcoin.h>
-
-#include <boost/test/unit_test.hpp>
-
-BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup)
-
-BOOST_AUTO_TEST_CASE(univalue_constructor)
-{
- UniValue v1;
- BOOST_CHECK(v1.isNull());
-
- UniValue v2(UniValue::VSTR);
- BOOST_CHECK(v2.isStr());
-
- UniValue v3(UniValue::VSTR, "foo");
- BOOST_CHECK(v3.isStr());
- BOOST_CHECK_EQUAL(v3.getValStr(), "foo");
-
- UniValue numTest;
- BOOST_CHECK(numTest.setNumStr("82"));
- BOOST_CHECK(numTest.isNum());
- BOOST_CHECK_EQUAL(numTest.getValStr(), "82");
-
- uint64_t vu64 = 82;
- UniValue v4(vu64);
- BOOST_CHECK(v4.isNum());
- BOOST_CHECK_EQUAL(v4.getValStr(), "82");
-
- int64_t vi64 = -82;
- UniValue v5(vi64);
- BOOST_CHECK(v5.isNum());
- BOOST_CHECK_EQUAL(v5.getValStr(), "-82");
-
- int vi = -688;
- UniValue v6(vi);
- BOOST_CHECK(v6.isNum());
- BOOST_CHECK_EQUAL(v6.getValStr(), "-688");
-
- double vd = -7.21;
- UniValue v7(vd);
- BOOST_CHECK(v7.isNum());
- BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
-
- std::string vs("yawn");
- UniValue v8(vs);
- BOOST_CHECK(v8.isStr());
- BOOST_CHECK_EQUAL(v8.getValStr(), "yawn");
-
- const char *vcs = "zappa";
- UniValue v9(vcs);
- BOOST_CHECK(v9.isStr());
- BOOST_CHECK_EQUAL(v9.getValStr(), "zappa");
-}
-
-BOOST_AUTO_TEST_CASE(univalue_typecheck)
-{
- UniValue v1;
- BOOST_CHECK(v1.setNumStr("1"));
- BOOST_CHECK(v1.isNum());
- BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error);
-
- UniValue v2;
- BOOST_CHECK(v2.setBool(true));
- BOOST_CHECK_EQUAL(v2.get_bool(), true);
- BOOST_CHECK_THROW(v2.get_int(), std::runtime_error);
-
- UniValue v3;
- BOOST_CHECK(v3.setNumStr("32482348723847471234"));
- BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error);
- BOOST_CHECK(v3.setNumStr("1000"));
- BOOST_CHECK_EQUAL(v3.get_int64(), 1000);
-
- UniValue v4;
- BOOST_CHECK(v4.setNumStr("2147483648"));
- BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648);
- BOOST_CHECK_THROW(v4.get_int(), std::runtime_error);
- BOOST_CHECK(v4.setNumStr("1000"));
- BOOST_CHECK_EQUAL(v4.get_int(), 1000);
- BOOST_CHECK_THROW(v4.get_str(), std::runtime_error);
- BOOST_CHECK_EQUAL(v4.get_real(), 1000);
- BOOST_CHECK_THROW(v4.get_array(), std::runtime_error);
- BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error);
- BOOST_CHECK_THROW(v4.getValues(), std::runtime_error);
- BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error);
-
- UniValue v5;
- BOOST_CHECK(v5.read("[true, 10]"));
- BOOST_CHECK_NO_THROW(v5.get_array());
- std::vector<UniValue> vals = v5.getValues();
- BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error);
- BOOST_CHECK_EQUAL(vals[0].get_bool(), true);
-
- BOOST_CHECK_EQUAL(vals[1].get_int(), 10);
- BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error);
-}
-
-BOOST_AUTO_TEST_CASE(univalue_set)
-{
- UniValue v(UniValue::VSTR, "foo");
- v.clear();
- BOOST_CHECK(v.isNull());
- BOOST_CHECK_EQUAL(v.getValStr(), "");
-
- BOOST_CHECK(v.setObject());
- BOOST_CHECK(v.isObject());
- BOOST_CHECK_EQUAL(v.size(), 0);
- BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);
- BOOST_CHECK(v.empty());
-
- BOOST_CHECK(v.setArray());
- BOOST_CHECK(v.isArray());
- BOOST_CHECK_EQUAL(v.size(), 0);
-
- BOOST_CHECK(v.setStr("zum"));
- BOOST_CHECK(v.isStr());
- BOOST_CHECK_EQUAL(v.getValStr(), "zum");
-
- BOOST_CHECK(v.setFloat(-1.01));
- BOOST_CHECK(v.isNum());
- BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
-
- BOOST_CHECK(v.setInt((int)1023));
- BOOST_CHECK(v.isNum());
- BOOST_CHECK_EQUAL(v.getValStr(), "1023");
-
- BOOST_CHECK(v.setInt((int64_t)-1023LL));
- BOOST_CHECK(v.isNum());
- BOOST_CHECK_EQUAL(v.getValStr(), "-1023");
-
- BOOST_CHECK(v.setInt((uint64_t)1023ULL));
- BOOST_CHECK(v.isNum());
- BOOST_CHECK_EQUAL(v.getValStr(), "1023");
-
- BOOST_CHECK(v.setNumStr("-688"));
- BOOST_CHECK(v.isNum());
- BOOST_CHECK_EQUAL(v.getValStr(), "-688");
-
- BOOST_CHECK(v.setBool(false));
- BOOST_CHECK_EQUAL(v.isBool(), true);
- BOOST_CHECK_EQUAL(v.isTrue(), false);
- BOOST_CHECK_EQUAL(v.isFalse(), true);
- BOOST_CHECK_EQUAL(v.getBool(), false);
-
- BOOST_CHECK(v.setBool(true));
- BOOST_CHECK_EQUAL(v.isBool(), true);
- BOOST_CHECK_EQUAL(v.isTrue(), true);
- BOOST_CHECK_EQUAL(v.isFalse(), false);
- BOOST_CHECK_EQUAL(v.getBool(), true);
-
- BOOST_CHECK(!v.setNumStr("zombocom"));
-
- BOOST_CHECK(v.setNull());
- BOOST_CHECK(v.isNull());
-}
-
-BOOST_AUTO_TEST_CASE(univalue_array)
-{
- UniValue arr(UniValue::VARR);
-
- UniValue v((int64_t)1023LL);
- BOOST_CHECK(arr.push_back(v));
-
- std::string vStr("zippy");
- BOOST_CHECK(arr.push_back(vStr));
-
- const char *s = "pippy";
- BOOST_CHECK(arr.push_back(s));
-
- std::vector<UniValue> vec;
- v.setStr("boing");
- vec.push_back(v);
-
- v.setStr("going");
- vec.push_back(v);
-
- BOOST_CHECK(arr.push_backV(vec));
-
- BOOST_CHECK_EQUAL(arr.empty(), false);
- BOOST_CHECK_EQUAL(arr.size(), 5);
-
- BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023");
- BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy");
- BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy");
- BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing");
- BOOST_CHECK_EQUAL(arr[4].getValStr(), "going");
-
- BOOST_CHECK_EQUAL(arr[999].getValStr(), "");
-
- arr.clear();
- BOOST_CHECK(arr.empty());
- BOOST_CHECK_EQUAL(arr.size(), 0);
-}
-
-BOOST_AUTO_TEST_CASE(univalue_object)
-{
- UniValue obj(UniValue::VOBJ);
- std::string strKey, strVal;
- UniValue v;
-
- strKey = "age";
- v.setInt(100);
- BOOST_CHECK(obj.pushKV(strKey, v));
-
- strKey = "first";
- strVal = "John";
- BOOST_CHECK(obj.pushKV(strKey, strVal));
-
- strKey = "last";
- const char *cVal = "Smith";
- BOOST_CHECK(obj.pushKV(strKey, cVal));
-
- strKey = "distance";
- BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25));
-
- strKey = "time";
- BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600));
-
- strKey = "calories";
- BOOST_CHECK(obj.pushKV(strKey, (int) 12));
-
- strKey = "temperature";
- BOOST_CHECK(obj.pushKV(strKey, (double) 90.012));
-
- UniValue obj2(UniValue::VOBJ);
- BOOST_CHECK(obj2.pushKV("cat1", 9000));
- BOOST_CHECK(obj2.pushKV("cat2", 12345));
-
- BOOST_CHECK(obj.pushKVs(obj2));
-
- BOOST_CHECK_EQUAL(obj.empty(), false);
- BOOST_CHECK_EQUAL(obj.size(), 9);
-
- BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100");
- BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John");
- BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith");
- BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25");
- BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600");
- BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12");
- BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012");
- BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000");
- BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345");
-
- BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), "");
-
- BOOST_CHECK(obj.exists("age"));
- BOOST_CHECK(obj.exists("first"));
- BOOST_CHECK(obj.exists("last"));
- BOOST_CHECK(obj.exists("distance"));
- BOOST_CHECK(obj.exists("time"));
- BOOST_CHECK(obj.exists("calories"));
- BOOST_CHECK(obj.exists("temperature"));
- BOOST_CHECK(obj.exists("cat1"));
- BOOST_CHECK(obj.exists("cat2"));
-
- BOOST_CHECK(!obj.exists("nyuknyuknyuk"));
-
- std::map<std::string, UniValue::VType> objTypes;
- objTypes["age"] = UniValue::VNUM;
- objTypes["first"] = UniValue::VSTR;
- objTypes["last"] = UniValue::VSTR;
- objTypes["distance"] = UniValue::VNUM;
- objTypes["time"] = UniValue::VNUM;
- objTypes["calories"] = UniValue::VNUM;
- objTypes["temperature"] = UniValue::VNUM;
- objTypes["cat1"] = UniValue::VNUM;
- objTypes["cat2"] = UniValue::VNUM;
- BOOST_CHECK(obj.checkObject(objTypes));
-
- objTypes["cat2"] = UniValue::VSTR;
- BOOST_CHECK(!obj.checkObject(objTypes));
-
- obj.clear();
- BOOST_CHECK(obj.empty());
- BOOST_CHECK_EQUAL(obj.size(), 0);
-}
-
-static const char *json1 =
-"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]";
-
-BOOST_AUTO_TEST_CASE(univalue_readwrite)
-{
- UniValue v;
- BOOST_CHECK(v.read(json1));
-
- std::string strJson1(json1);
- BOOST_CHECK(v.read(strJson1));
-
- BOOST_CHECK(v.isArray());
- BOOST_CHECK_EQUAL(v.size(), 2);
-
- BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000");
-
- UniValue obj = v[1];
- BOOST_CHECK(obj.isObject());
- BOOST_CHECK_EQUAL(obj.size(), 3);
-
- BOOST_CHECK(obj["key1"].isStr());
- std::string correctValue("str");
- correctValue.push_back('\0');
- BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue);
- BOOST_CHECK(obj["key2"].isNum());
- BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800");
- BOOST_CHECK(obj["key3"].isObject());
-
- BOOST_CHECK_EQUAL(strJson1, v.write());
-
- /* Check for (correctly reporting) a parsing error if the initial
- JSON construct is followed by more stuff. Note that whitespace
- is, of course, exempt. */
-
- BOOST_CHECK(v.read(" {}\n "));
- BOOST_CHECK(v.isObject());
- BOOST_CHECK(v.read(" []\n "));
- BOOST_CHECK(v.isArray());
-
- BOOST_CHECK(!v.read("@{}"));
- BOOST_CHECK(!v.read("{} garbage"));
- BOOST_CHECK(!v.read("[]{}"));
- BOOST_CHECK(!v.read("{}[]"));
- BOOST_CHECK(!v.read("{} 42"));
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/txmempool.h b/src/txmempool.h
index 346585ab11..86a008d7b2 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -204,7 +204,7 @@ struct mempoolentry_txid
class CompareTxMemPoolEntryByDescendantScore
{
public:
- bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
+ bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{
bool fUseADescendants = UseDescendantScore(a);
bool fUseBDescendants = UseDescendantScore(b);
@@ -226,7 +226,7 @@ public:
}
// Calculate which score to use for an entry (avoiding division).
- bool UseDescendantScore(const CTxMemPoolEntry &a)
+ bool UseDescendantScore(const CTxMemPoolEntry &a) const
{
double f1 = (double)a.GetModifiedFee() * a.GetSizeWithDescendants();
double f2 = (double)a.GetModFeesWithDescendants() * a.GetTxSize();
@@ -241,7 +241,7 @@ public:
class CompareTxMemPoolEntryByScore
{
public:
- bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
+ bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{
double f1 = (double)a.GetModifiedFee() * b.GetTxSize();
double f2 = (double)b.GetModifiedFee() * a.GetTxSize();
@@ -255,7 +255,7 @@ public:
class CompareTxMemPoolEntryByEntryTime
{
public:
- bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
+ bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{
return a.GetTime() < b.GetTime();
}
@@ -264,7 +264,7 @@ public:
class CompareTxMemPoolEntryByAncestorFee
{
public:
- bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
+ bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{
double aFees = a.GetModFeesWithAncestors();
double aSize = a.GetSizeWithAncestors();
diff --git a/src/univalue/.travis.yml b/src/univalue/.travis.yml
index 132743d349..43a1ed362e 100644
--- a/src/univalue/.travis.yml
+++ b/src/univalue/.travis.yml
@@ -25,7 +25,6 @@ addons:
- pkg-config
before_script:
- - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew uninstall libtool; brew install libtool; fi
- if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi
- test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh
diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp
index 02446292a1..679cc9f143 100644
--- a/src/univalue/test/object.cpp
+++ b/src/univalue/test/object.cpp
@@ -19,9 +19,10 @@
#define BOOST_CHECK_THROW(stmt, excMatch) { \
try { \
(stmt); \
+ assert(0 && "No exception caught"); \
} catch (excMatch & e) { \
} catch (...) { \
- assert(0); \
+ assert(0 && "Wrong exception caught"); \
} \
}
#define BOOST_CHECK_NO_THROW(stmt) { \
diff --git a/src/util.cpp b/src/util.cpp
index d58f39e969..a3e4b0acfb 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -3,18 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
#include <util.h>
#include <chainparamsbase.h>
-#include <fs.h>
#include <random.h>
#include <serialize.h>
#include <utilstrencodings.h>
-#include <utiltime.h>
#include <stdarg.h>
@@ -89,6 +83,7 @@ const int64_t nStartupTime = GetTime();
const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
+const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
ArgsManager gArgs;
bool fPrintToConsole = false;
@@ -189,26 +184,40 @@ static void DebugPrintInit()
vMsgsBeforeOpenLog = new std::list<std::string>;
}
-void OpenDebugLog()
+fs::path GetDebugLogPath()
+{
+ fs::path logfile(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
+ if (logfile.is_absolute()) {
+ return logfile;
+ } else {
+ return GetDataDir() / logfile;
+ }
+}
+
+bool OpenDebugLog()
{
boost::call_once(&DebugPrintInit, debugPrintInitFlag);
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
assert(fileout == nullptr);
assert(vMsgsBeforeOpenLog);
- fs::path pathDebug = GetDataDir() / "debug.log";
+ fs::path pathDebug = GetDebugLogPath();
+
fileout = fsbridge::fopen(pathDebug, "a");
- if (fileout) {
- setbuf(fileout, nullptr); // unbuffered
- // dump buffered messages from before we opened the log
- while (!vMsgsBeforeOpenLog->empty()) {
- FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
- vMsgsBeforeOpenLog->pop_front();
- }
+ if (!fileout) {
+ return false;
+ }
+
+ setbuf(fileout, nullptr); // unbuffered
+ // dump buffered messages from before we opened the log
+ while (!vMsgsBeforeOpenLog->empty()) {
+ FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
+ vMsgsBeforeOpenLog->pop_front();
}
delete vMsgsBeforeOpenLog;
vMsgsBeforeOpenLog = nullptr;
+ return true;
}
struct CLogCategoryDesc
@@ -220,6 +229,7 @@ struct CLogCategoryDesc
const CLogCategoryDesc LogCategories[] =
{
{BCLog::NONE, "0"},
+ {BCLog::NONE, "none"},
{BCLog::NET, "net"},
{BCLog::TOR, "tor"},
{BCLog::MEMPOOL, "mempool"},
@@ -354,7 +364,7 @@ int LogPrintStr(const std::string &str)
// reopen the log file, if requested
if (fReopenDebugLog) {
fReopenDebugLog = false;
- fs::path pathDebug = GetDataDir() / "debug.log";
+ fs::path pathDebug = GetDebugLogPath();
if (fsbridge::freopen(pathDebug,"a",fileout) != nullptr)
setbuf(fileout, nullptr); // unbuffered
}
@@ -623,6 +633,9 @@ void ArgsManager::ReadConfigFile(const std::string& confPath)
}
// If datadir is changed in .conf file:
ClearDatadirCache();
+ if (!fs::is_directory(GetDataDir(false))) {
+ throw std::runtime_error(strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", "").c_str()));
+ }
}
#ifndef WIN32
@@ -773,7 +786,7 @@ void ShrinkDebugFile()
// Amount of debug.log to save at end when shrinking (must fit in memory)
constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
// Scroll debug.log if it's getting too big
- fs::path pathLog = GetDataDir() / "debug.log";
+ fs::path pathLog = GetDebugLogPath();
FILE* file = fsbridge::fopen(pathLog, "r");
// If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
// trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
diff --git a/src/util.h b/src/util.h
index be5c99567d..3cc4c26817 100644
--- a/src/util.h
+++ b/src/util.h
@@ -28,6 +28,7 @@
#include <vector>
#include <boost/signals2/signal.hpp>
+#include <boost/thread/condition_variable.hpp> // for boost::thread_interrupted
// Application startup time (used for uptime calculation)
int64_t GetStartupTime();
@@ -35,6 +36,7 @@ int64_t GetStartupTime();
static const bool DEFAULT_LOGTIMEMICROS = false;
static const bool DEFAULT_LOGIPS = false;
static const bool DEFAULT_LOGTIMESTAMPS = true;
+extern const char * const DEFAULT_DEBUGLOGFILE;
/** Signals for translation. */
class CTranslationInterface
@@ -132,6 +134,10 @@ template<typename T, typename... Args> static inline void MarkUsed(const T& t, c
MarkUsed(args...);
}
+// Be conservative when using LogPrintf/error or other things which
+// unconditionally log to debug.log! It should not be the case that an inbound
+// peer can fill up a users disk with debug.log entries.
+
#ifdef USE_COVERAGE
#define LogPrintf(...) do { MarkUsed(__VA_ARGS__); } while(0)
#define LogPrint(category, ...) do { MarkUsed(__VA_ARGS__); } while(0)
@@ -179,7 +185,8 @@ void CreatePidFile(const fs::path &path, pid_t pid);
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
-void OpenDebugLog();
+fs::path GetDebugLogPath();
+bool OpenDebugLog();
void ShrinkDebugFile();
void runCommand(const std::string& strCommand);
diff --git a/src/validation.cpp b/src/validation.cpp
index 99ea1433f9..75c40b22fc 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -15,7 +15,6 @@
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
#include <cuckoocache.h>
-#include <fs.h>
#include <hash.h>
#include <init.h>
#include <policy/fees.h>
@@ -39,10 +38,8 @@
#include <utilmoneystr.h>
#include <utilstrencodings.h>
#include <validationinterface.h>
-#include <versionbits.h>
#include <warnings.h>
-#include <atomic>
#include <sstream>
#include <boost/algorithm/string/replace.hpp>
@@ -59,48 +56,7 @@
/**
* Global state
*/
-
-CCriticalSection cs_main;
-
-BlockMap mapBlockIndex;
-CChain chainActive;
-CBlockIndex *pindexBestHeader = nullptr;
-CWaitableCriticalSection csBestBlock;
-CConditionVariable cvBlockChange;
-int nScriptCheckThreads = 0;
-std::atomic_bool fImporting(false);
-std::atomic_bool fReindex(false);
-bool fTxIndex = false;
-bool fHavePruned = false;
-bool fPruneMode = false;
-bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
-bool fRequireStandard = true;
-bool fCheckBlockIndex = false;
-bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
-size_t nCoinCacheUsage = 5000 * 300;
-uint64_t nPruneTarget = 0;
-int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
-bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
-
-uint256 hashAssumeValid;
-arith_uint256 nMinimumChainWork;
-
-CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
-CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
-
-CBlockPolicyEstimator feeEstimator;
-CTxMemPool mempool(&feeEstimator);
-
-static void CheckBlockIndex(const Consensus::Params& consensusParams);
-
-/** Constant stuff for coinbase transactions we create: */
-CScript COINBASE_FLAGS;
-
-const std::string strMessageMagic = "Bitcoin Signed Message:\n";
-
-// Internal stuff
namespace {
-
struct CBlockIndexWorkComparator
{
bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
@@ -121,28 +77,39 @@ namespace {
return false;
}
};
+} // anon namespace
+
+enum DisconnectResult
+{
+ DISCONNECT_OK, // All good.
+ DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
+ DISCONNECT_FAILED // Something else went wrong.
+};
- CBlockIndex *pindexBestInvalid;
+class ConnectTrace;
+/**
+ * CChainState stores and provides an API to update our local knowledge of the
+ * current best chain and header tree.
+ *
+ * It generally provides access to the current block tree, as well as functions
+ * to provide new data, which it will appropriately validate and incorporate in
+ * its state as necessary.
+ *
+ * Eventually, the API here is targeted at being exposed externally as a
+ * consumable libconsensus library, so any functions added must only call
+ * other class member functions, pure functions in other parts of the consensus
+ * library, callbacks via the validation interface, or read/write-to-disk
+ * functions (eventually this will also be via callbacks).
+ */
+class CChainState {
+private:
/**
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
* as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
* missing the data for the block.
*/
std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
- /** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
- * Pruned nodes may have entries where B is missing data.
- */
- std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
-
- CCriticalSection cs_LastBlockFile;
- std::vector<CBlockFileInfo> vinfoBlockFile;
- int nLastBlockFile = 0;
- /** Global flag to indicate we should check to see if there are
- * block/undo files that should be deleted. Set on startup
- * or if we allocate more file space when we're in prune mode
- */
- bool fCheckForPruning = false;
/**
* Every received block is assigned a unique and increasing identifier, so we
@@ -176,6 +143,113 @@ namespace {
*/
std::set<CBlockIndex*> g_failed_blocks;
+public:
+ CChain chainActive;
+ BlockMap mapBlockIndex;
+ std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
+ CBlockIndex *pindexBestInvalid = nullptr;
+
+ bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree);
+
+ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock);
+
+ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex);
+ bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock);
+
+ // Block (dis)connection on a given view:
+ DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
+ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
+ CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false);
+
+ // Block disconnection on our pcoinsTip:
+ bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool);
+
+ // Manual block validity manipulation:
+ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex);
+ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex);
+ bool ResetBlockFailureFlags(CBlockIndex *pindex);
+
+ bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
+ bool RewindBlockIndex(const CChainParams& params);
+ bool LoadGenesisBlock(const CChainParams& chainparams);
+
+ void PruneBlockIndexCandidates();
+
+ void UnloadBlockIndex();
+
+private:
+ bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace);
+ bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool);
+
+ CBlockIndex* AddToBlockIndex(const CBlockHeader& block);
+ /** Create a new block index entry for a given block hash */
+ CBlockIndex * InsertBlockIndex(const uint256& hash);
+ void CheckBlockIndex(const Consensus::Params& consensusParams);
+
+ void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state);
+ CBlockIndex* FindMostWorkChain();
+ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams);
+
+
+ bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params);
+} g_chainstate;
+
+
+
+CCriticalSection cs_main;
+
+BlockMap& mapBlockIndex = g_chainstate.mapBlockIndex;
+CChain& chainActive = g_chainstate.chainActive;
+CBlockIndex *pindexBestHeader = nullptr;
+CWaitableCriticalSection csBestBlock;
+CConditionVariable cvBlockChange;
+int nScriptCheckThreads = 0;
+std::atomic_bool fImporting(false);
+std::atomic_bool fReindex(false);
+bool fTxIndex = false;
+bool fHavePruned = false;
+bool fPruneMode = false;
+bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
+bool fRequireStandard = true;
+bool fCheckBlockIndex = false;
+bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
+size_t nCoinCacheUsage = 5000 * 300;
+uint64_t nPruneTarget = 0;
+int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
+bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
+
+uint256 hashAssumeValid;
+arith_uint256 nMinimumChainWork;
+
+CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
+CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
+
+CBlockPolicyEstimator feeEstimator;
+CTxMemPool mempool(&feeEstimator);
+
+/** Constant stuff for coinbase transactions we create: */
+CScript COINBASE_FLAGS;
+
+const std::string strMessageMagic = "Bitcoin Signed Message:\n";
+
+// Internal stuff
+namespace {
+ CBlockIndex *&pindexBestInvalid = g_chainstate.pindexBestInvalid;
+
+ /** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
+ * Pruned nodes may have entries where B is missing data.
+ */
+ std::multimap<CBlockIndex*, CBlockIndex*>& mapBlocksUnlinked = g_chainstate.mapBlocksUnlinked;
+
+ CCriticalSection cs_LastBlockFile;
+ std::vector<CBlockFileInfo> vinfoBlockFile;
+ int nLastBlockFile = 0;
+ /** Global flag to indicate we should check to see if there are
+ * block/undo files that should be deleted. Set on startup
+ * or if we allocate more file space when we're in prune mode
+ */
+ bool fCheckForPruning = false;
+
/** Dirty block index entries. */
std::set<CBlockIndex*> setDirtyBlockIndex;
@@ -926,47 +1000,51 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, pfMissingInputs, GetTime(), plTxnReplaced, bypass_limits, nAbsurdFee);
}
-/** Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock */
-bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow)
+/**
+ * Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock.
+ * If blockIndex is provided, the transaction is fetched from the corresponding block.
+ */
+bool GetTransaction(const uint256& hash, CTransactionRef& txOut, const Consensus::Params& consensusParams, uint256& hashBlock, bool fAllowSlow, CBlockIndex* blockIndex)
{
- CBlockIndex *pindexSlow = nullptr;
+ CBlockIndex* pindexSlow = blockIndex;
LOCK(cs_main);
- CTransactionRef ptx = mempool.get(hash);
- if (ptx)
- {
- txOut = ptx;
- return true;
- }
-
- if (fTxIndex) {
- CDiskTxPos postx;
- if (pblocktree->ReadTxIndex(hash, postx)) {
- CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
- if (file.IsNull())
- return error("%s: OpenBlockFile failed", __func__);
- CBlockHeader header;
- try {
- file >> header;
- fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
- file >> txOut;
- } catch (const std::exception& e) {
- return error("%s: Deserialize or I/O error - %s", __func__, e.what());
- }
- hashBlock = header.GetHash();
- if (txOut->GetHash() != hash)
- return error("%s: txid mismatch", __func__);
+ if (!blockIndex) {
+ CTransactionRef ptx = mempool.get(hash);
+ if (ptx) {
+ txOut = ptx;
return true;
}
- // transaction not found in index, nothing more can be done
- return false;
- }
+ if (fTxIndex) {
+ CDiskTxPos postx;
+ if (pblocktree->ReadTxIndex(hash, postx)) {
+ CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
+ if (file.IsNull())
+ return error("%s: OpenBlockFile failed", __func__);
+ CBlockHeader header;
+ try {
+ file >> header;
+ fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
+ file >> txOut;
+ } catch (const std::exception& e) {
+ return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ }
+ hashBlock = header.GetHash();
+ if (txOut->GetHash() != hash)
+ return error("%s: txid mismatch", __func__);
+ return true;
+ }
+
+ // transaction not found in index, nothing more can be done
+ return false;
+ }
- if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
- const Coin& coin = AccessByTxid(*pcoinsTip, hash);
- if (!coin.IsSpent()) pindexSlow = chainActive[coin.nHeight];
+ if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
+ const Coin& coin = AccessByTxid(*pcoinsTip, hash);
+ if (!coin.IsSpent()) pindexSlow = chainActive[coin.nHeight];
+ }
}
if (pindexSlow) {
@@ -1197,7 +1275,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
CheckForkWarningConditions();
}
-void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
+void CChainState::InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
if (!state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
g_failed_blocks.insert(pindex);
@@ -1380,8 +1458,13 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint
return true;
}
-bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock)
+static bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex *pindex)
{
+ CDiskBlockPos pos = pindex->GetUndoPos();
+ if (pos.IsNull()) {
+ return error("%s: no undo data available", __func__);
+ }
+
// Open history file to read
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
@@ -1391,7 +1474,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
uint256 hashChecksum;
CHashVerifier<CAutoFile> verifier(&filein); // We need a CHashVerifier as reserializing may lose data
try {
- verifier << hashBlock;
+ verifier << pindex->pprev->GetBlockHash();
verifier >> blockundo;
filein >> hashChecksum;
}
@@ -1426,13 +1509,6 @@ bool AbortNode(CValidationState& state, const std::string& strMessage, const std
} // namespace
-enum DisconnectResult
-{
- DISCONNECT_OK, // All good.
- DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
- DISCONNECT_FAILED // Something else went wrong.
-};
-
/**
* Restore the UTXO in a Coin at a given COutPoint
* @param undo The Coin to be restored.
@@ -1469,17 +1545,12 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
* When FAILED is returned, view is left in an indeterminate state. */
-static DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)
+DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)
{
bool fClean = true;
CBlockUndo blockUndo;
- CDiskBlockPos pos = pindex->GetUndoPos();
- if (pos.IsNull()) {
- error("DisconnectBlock(): no undo data available");
- return DISCONNECT_FAILED;
- }
- if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) {
+ if (!UndoReadFromDisk(blockUndo, pindex)) {
error("DisconnectBlock(): failure reading undo data");
return DISCONNECT_FAILED;
}
@@ -1556,6 +1627,45 @@ void static FlushBlockFile(bool fFinalize = false)
static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize);
+static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, CValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams)
+{
+ // Write undo information to disk
+ if (pindex->GetUndoPos().IsNull()) {
+ CDiskBlockPos _pos;
+ if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
+ return error("ConnectBlock(): FindUndoPos failed");
+ if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart()))
+ return AbortNode(state, "Failed to write undo data");
+
+ // update nUndoPos in block index
+ pindex->nUndoPos = _pos.nPos;
+ pindex->nStatus |= BLOCK_HAVE_UNDO;
+ setDirtyBlockIndex.insert(pindex);
+ }
+
+ return true;
+}
+
+static bool WriteTxIndexDataForBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex)
+{
+ if (!fTxIndex) return true;
+
+ CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
+ std::vector<std::pair<uint256, CDiskTxPos> > vPos;
+ vPos.reserve(block.vtx.size());
+ for (const CTransactionRef& tx : block.vtx)
+ {
+ vPos.push_back(std::make_pair(tx->GetHash(), pos));
+ pos.nTxOffset += ::GetSerializeSize(*tx, SER_DISK, CLIENT_VERSION);
+ }
+
+ if (!pblocktree->WriteTxIndex(vPos)) {
+ return AbortNode(state, "Failed to write transaction index");
+ }
+
+ return true;
+}
+
static CCheckQueue<CScriptCheck> scriptcheckqueue(128);
void ThreadScriptCheck() {
@@ -1656,8 +1766,8 @@ static int64_t nBlocksTotal = 0;
/** Apply the effects of this block (with given index) on the UTXO set represented by coins.
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
* can fail if those validity checks fail (among other reasons). */
-static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
- CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false)
+bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
+ CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck)
{
AssertLockHeld(cs_main);
assert(pindex);
@@ -1667,6 +1777,18 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
int64_t nTimeStart = GetTimeMicros();
// Check it again in case a previous version let a bad block in
+ // NOTE: We don't currently (re-)invoke ContextualCheckBlock() or
+ // ContextualCheckBlockHeader() here. This means that if we add a new
+ // consensus rule that is enforced in one of those two functions, then we
+ // may have let in a block that violates the rule prior to updating the
+ // software, and we would NOT be enforcing the rule here. Fully solving
+ // upgrade from one software version to the next after a consensus rule
+ // change is potentially tricky and issue-specific (see RewindBlockIndex()
+ // for one general approach that was used for BIP 141 deployment).
+ // Also, currently the rule against blocks more than 2 hours in the future
+ // is enforced in ContextualCheckBlockHeader(); we wouldn't want to
+ // re-enforce that rule here (at least until we make it impossible for
+ // GetAdjustedTime() to go backward).
if (!CheckBlock(block, state, chainparams.GetConsensus(), !fJustCheck, !fJustCheck))
return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state));
@@ -1771,9 +1893,6 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
CAmount nFees = 0;
int nInputs = 0;
int64_t nSigOpsCost = 0;
- CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
- std::vector<std::pair<uint256, CDiskTxPos> > vPos;
- vPos.reserve(block.vtx.size());
blockundo.vtxundo.reserve(block.vtx.size() - 1);
std::vector<PrecomputedTransactionData> txdata;
txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
@@ -1834,9 +1953,6 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
blockundo.vtxundo.push_back(CTxUndo());
}
UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
-
- vPos.push_back(std::make_pair(tx.GetHash(), pos));
- pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
@@ -1856,28 +1972,16 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
if (fJustCheck)
return true;
- // Write undo information to disk
- if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS))
- {
- if (pindex->GetUndoPos().IsNull()) {
- CDiskBlockPos _pos;
- if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
- return error("ConnectBlock(): FindUndoPos failed");
- if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart()))
- return AbortNode(state, "Failed to write undo data");
-
- // update nUndoPos in block index
- pindex->nUndoPos = _pos.nPos;
- pindex->nStatus |= BLOCK_HAVE_UNDO;
- }
+ if (!WriteUndoDataForBlock(blockundo, state, pindex, chainparams))
+ return false;
+ if (!pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);
setDirtyBlockIndex.insert(pindex);
}
- if (fTxIndex)
- if (!pblocktree->WriteTxIndex(vPos))
- return AbortNode(state, "Failed to write transaction index");
+ if (!WriteTxIndexDataForBlock(block, state, pindex))
+ return false;
assert(pindex->phashBlock);
// add this block to the view's block chain
@@ -2029,10 +2133,8 @@ static void DoWarning(const std::string& strWarning)
}
}
-/** Update chainActive and related internal data structures. */
-void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
- chainActive.SetTip(pindexNew);
-
+/** Check warning conditions and do some notifications on new chain tip set. */
+void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainParams) {
// New best block
mempool.AddTransactionsUpdated(1);
@@ -2042,7 +2144,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
if (!IsInitialBlockDownload())
{
int nUpgraded = 0;
- const CBlockIndex* pindex = chainActive.Tip();
+ const CBlockIndex* pindex = pindexNew;
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
WarningBitsConditionChecker checker(bit);
ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]);
@@ -2073,10 +2175,10 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
}
}
LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)", __func__,
- chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion,
- log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx,
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
- GuessVerificationProgress(chainParams.TxData(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
+ pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion,
+ log(pindexNew->nChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx,
+ DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexNew->GetBlockTime()),
+ GuessVerificationProgress(chainParams.TxData(), pindexNew), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
if (!warningMessages.empty())
LogPrintf(" warning='%s'", boost::algorithm::join(warningMessages, ", "));
LogPrintf("\n");
@@ -2093,7 +2195,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
* disconnectpool (note that the caller is responsible for mempool consistency
* in any case).
*/
-bool static DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)
+bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)
{
CBlockIndex *pindexDelete = chainActive.Tip();
assert(pindexDelete);
@@ -2130,7 +2232,8 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
}
}
- // Update chainActive and related variables.
+ chainActive.SetTip(pindexDelete->pprev);
+
UpdateTip(pindexDelete->pprev, chainparams);
// Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted:
@@ -2215,7 +2318,7 @@ public:
*
* The block is added to connectTrace if connection succeeds.
*/
-bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
+bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
{
assert(pindexNew->pprev == chainActive.Tip());
// Read block from disk.
@@ -2259,6 +2362,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight);
disconnectpool.removeForBlock(blockConnecting.vtx);
// Update chainActive & related variables.
+ chainActive.SetTip(pindexNew);
UpdateTip(pindexNew, chainparams);
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
@@ -2273,7 +2377,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
* Return the tip of the chain with the most work in it, that isn't
* known to be invalid (it's however far from certain to be valid).
*/
-static CBlockIndex* FindMostWorkChain() {
+CBlockIndex* CChainState::FindMostWorkChain() {
do {
CBlockIndex *pindexNew = nullptr;
@@ -2328,7 +2432,7 @@ static CBlockIndex* FindMostWorkChain() {
}
/** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */
-static void PruneBlockIndexCandidates() {
+void CChainState::PruneBlockIndexCandidates() {
// Note that we can't delete the current block itself, as we may need to return to it later in case a
// reorganization to a better block fails.
std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin();
@@ -2343,7 +2447,7 @@ static void PruneBlockIndexCandidates() {
* Try to make some progress towards making pindexMostWork the active block.
* pblock is either nullptr or a pointer to a CBlock corresponding to pindexMostWork.
*/
-static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
+bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
{
AssertLockHeld(cs_main);
const CBlockIndex *pindexOldTip = chainActive.Tip();
@@ -2450,7 +2554,7 @@ static void NotifyHeaderTip() {
* or an activated best chain. pblock is either nullptr or a pointer to a block
* that is already loaded (to avoid loading it again from disk).
*/
-bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
+bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
// Note that while we're often called here from ProcessNewBlock, this is
// far from a guarantee. Things in the P2P/RPC will often end up calling
// us in the middle of ProcessNewBlock - do not assume pblock is set
@@ -2520,9 +2624,11 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
return true;
}
+bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
+ return g_chainstate.ActivateBestChain(state, chainparams, std::move(pblock));
+}
-
-bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
+bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
{
{
LOCK(cs_main);
@@ -2548,10 +2654,13 @@ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIn
}
}
- return ActivateBestChain(state, params);
+ return ActivateBestChain(state, params, std::shared_ptr<const CBlock>());
+}
+bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) {
+ return g_chainstate.PreciousBlock(state, params, pindex);
}
-bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
+bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
{
AssertLockHeld(cs_main);
@@ -2610,8 +2719,11 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);
return true;
}
+bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
+ return g_chainstate.InvalidateBlock(state, chainparams, pindex);
+}
-bool ResetBlockFailureFlags(CBlockIndex *pindex) {
+bool CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
AssertLockHeld(cs_main);
int nHeight = pindex->nHeight;
@@ -2644,8 +2756,11 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) {
}
return true;
}
+bool ResetBlockFailureFlags(CBlockIndex *pindex) {
+ return g_chainstate.ResetBlockFailureFlags(pindex);
+}
-static CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
+CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
{
// Check for duplicate
uint256 hash = block.GetHash();
@@ -2680,7 +2795,7 @@ static CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
}
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
-static bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
+bool CChainState::ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
{
pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0;
@@ -2728,7 +2843,7 @@ static bool ReceivedBlockTransactions(const CBlock &block, CValidationState& sta
return true;
}
-static bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false)
+static bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false)
{
LOCK(cs_LastBlockFile);
@@ -2777,7 +2892,7 @@ static bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned i
}
}
else
- return state.Error("out of disk space");
+ return error("out of disk space");
}
}
@@ -2952,7 +3067,13 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
/** Context-dependent validity checks.
* By "context", we mean only the previous block headers, but not the UTXO
- * set; UTXO-related validity checks are done in ConnectBlock(). */
+ * set; UTXO-related validity checks are done in ConnectBlock().
+ * NOTE: This function is not currently invoked by ConnectBlock(), so we
+ * should consider upgrade issues if we change which consensus rules are
+ * enforced in this function (eg by adding a new consensus rule). See comment
+ * in ConnectBlock().
+ * Note that -reindex-chainstate skips the validation that happens here!
+ */
static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime)
{
assert(pindexPrev != nullptr);
@@ -2992,6 +3113,12 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
return true;
}
+/** NOTE: This function is not currently invoked by ConnectBlock(), so we
+ * should consider upgrade issues if we change which consensus rules are
+ * enforced in this function (eg by adding a new consensus rule). See comment
+ * in ConnectBlock().
+ * Note that -reindex-chainstate skips the validation that happens here!
+ */
static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1;
@@ -3073,7 +3200,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
return true;
}
-static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
+bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
{
AssertLockHeld(cs_main);
// Check for duplicate
@@ -3140,7 +3267,7 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
LOCK(cs_main);
for (const CBlockHeader& header : headers) {
CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast
- if (!AcceptBlockHeader(header, state, chainparams, &pindex)) {
+ if (!g_chainstate.AcceptBlockHeader(header, state, chainparams, &pindex)) {
if (first_invalid) *first_invalid = header;
return false;
}
@@ -3154,7 +3281,26 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
}
/** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */
-static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
+static CDiskBlockPos SaveBlockToDisk(const CBlock& block, int nHeight, const CChainParams& chainparams, const CDiskBlockPos* dbp) {
+ unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
+ CDiskBlockPos blockPos;
+ if (dbp != nullptr)
+ blockPos = *dbp;
+ if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != nullptr)) {
+ error("%s: FindBlockPos failed", __func__);
+ return CDiskBlockPos();
+ }
+ if (dbp == nullptr) {
+ if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) {
+ AbortNode("Failed to write block");
+ return CDiskBlockPos();
+ }
+ }
+ return blockPos;
+}
+
+/** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */
+bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
{
const CBlock& block = *pblock;
@@ -3214,19 +3360,13 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
if (!IsInitialBlockDownload() && chainActive.Tip() == pindex->pprev)
GetMainSignals().NewPoWValidBlock(pindex, pblock);
- int nHeight = pindex->nHeight;
-
// Write block to history file
try {
- unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
- CDiskBlockPos blockPos;
- if (dbp != nullptr)
- blockPos = *dbp;
- if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != nullptr))
- return error("AcceptBlock(): FindBlockPos failed");
- if (dbp == nullptr)
- if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
- AbortNode(state, "Failed to write block");
+ CDiskBlockPos blockPos = SaveBlockToDisk(block, pindex->nHeight, chainparams, dbp);
+ if (blockPos.IsNull()) {
+ state.Error(strprintf("%s: Failed to find position to write new block to disk", __func__));
+ return false;
+ }
if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
return error("AcceptBlock(): ReceivedBlockTransactions failed");
} catch (const std::runtime_error& e) {
@@ -3236,6 +3376,8 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
if (fCheckForPruning)
FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE); // we just allocated more disk space for block files
+ CheckBlockIndex(chainparams.GetConsensus());
+
return true;
}
@@ -3253,9 +3395,8 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
if (ret) {
// Store to disk
- ret = AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
+ ret = g_chainstate.AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
}
- CheckBlockIndex(chainparams.GetConsensus());
if (!ret) {
GetMainSignals().BlockChecked(*pblock, state);
return error("%s: AcceptBlock FAILED (%s)", __func__, state.GetDebugMessage());
@@ -3265,7 +3406,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
NotifyHeaderTip();
CValidationState state; // Only used to report errors, not invalidity - ignore it
- if (!ActivateBestChain(state, chainparams, pblock))
+ if (!g_chainstate.ActivateBestChain(state, chainparams, pblock))
return error("%s: ActivateBestChain failed", __func__);
return true;
@@ -3287,7 +3428,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state));
if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev))
return error("%s: Consensus::ContextualCheckBlock: %s", __func__, FormatStateMessage(state));
- if (!ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
+ if (!g_chainstate.ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
return false;
assert(state.IsValid());
@@ -3315,8 +3456,8 @@ void PruneOneBlockFile(const int fileNumber)
{
LOCK(cs_LastBlockFile);
- for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); ++it) {
- CBlockIndex* pindex = it->second;
+ for (const auto& entry : mapBlockIndex) {
+ CBlockIndex* pindex = entry.second;
if (pindex->nFile == fileNumber) {
pindex->nStatus &= ~BLOCK_HAVE_DATA;
pindex->nStatus &= ~BLOCK_HAVE_UNDO;
@@ -3464,7 +3605,7 @@ static FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fRe
return nullptr;
fs::path path = GetBlockPosFilename(pos, prefix);
fs::create_directories(path.parent_path());
- FILE* file = fsbridge::fopen(path, "rb+");
+ FILE* file = fsbridge::fopen(path, fReadOnly ? "rb": "rb+");
if (!file && !fReadOnly)
file = fsbridge::fopen(path, "wb+");
if (!file) {
@@ -3495,7 +3636,7 @@ fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix)
return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile);
}
-CBlockIndex * InsertBlockIndex(uint256 hash)
+CBlockIndex * CChainState::InsertBlockIndex(const uint256& hash)
{
if (hash.IsNull())
return nullptr;
@@ -3513,9 +3654,9 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
return pindexNew;
}
-bool static LoadBlockIndexDB(const CChainParams& chainparams)
+bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree)
{
- if (!pblocktree->LoadBlockIndexGuts(chainparams.GetConsensus(), InsertBlockIndex))
+ if (!blocktree.LoadBlockIndexGuts(consensus_params, [this](const uint256& hash){ return this->InsertBlockIndex(hash); }))
return false;
boost::this_thread::interruption_point();
@@ -3562,6 +3703,14 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
pindexBestHeader = pindex;
}
+ return true;
+}
+
+bool static LoadBlockIndexDB(const CChainParams& chainparams)
+{
+ if (!g_chainstate.LoadBlockIndex(chainparams.GetConsensus(), *pblocktree))
+ return false;
+
// Load block file info
pblocktree->ReadLastBlockFile(nLastBlockFile);
vinfoBlockFile.resize(nLastBlockFile + 1);
@@ -3634,7 +3783,7 @@ bool LoadChainTip(const CChainParams& chainparams)
return false;
chainActive.SetTip(it->second);
- PruneBlockIndexCandidates();
+ g_chainstate.PruneBlockIndexCandidates();
LogPrintf("Loaded best chain: hashBestChain=%s height=%d date=%s progress=%f\n",
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(),
@@ -3699,16 +3848,16 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
// check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) {
CBlockUndo undo;
- CDiskBlockPos pos = pindex->GetUndoPos();
- if (!pos.IsNull()) {
- if (!UndoReadFromDisk(undo, pos, pindex->pprev->GetBlockHash()))
+ if (!pindex->GetUndoPos().IsNull()) {
+ if (!UndoReadFromDisk(undo, pindex)) {
return error("VerifyDB(): *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
+ }
}
}
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
assert(coins.GetBestBlock() == pindex->GetBlockHash());
- DisconnectResult res = DisconnectBlock(block, pindex, coins);
+ DisconnectResult res = g_chainstate.DisconnectBlock(block, pindex, coins);
if (res == DISCONNECT_FAILED) {
return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
}
@@ -3736,7 +3885,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
CBlock block;
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
- if (!ConnectBlock(block, state, pindex, coins, chainparams))
+ if (!g_chainstate.ConnectBlock(block, state, pindex, coins, chainparams))
return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
}
}
@@ -3748,7 +3897,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
}
/** Apply the effects of a block on the utxo cache, ignoring that it may already have been applied. */
-static bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params)
+bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params)
{
// TODO: merge with ConnectBlock
CBlock block;
@@ -3768,7 +3917,7 @@ static bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs,
return true;
}
-bool ReplayBlocks(const CChainParams& params, CCoinsView* view)
+bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view)
{
LOCK(cs_main);
@@ -3833,7 +3982,11 @@ bool ReplayBlocks(const CChainParams& params, CCoinsView* view)
return true;
}
-bool RewindBlockIndex(const CChainParams& params)
+bool ReplayBlocks(const CChainParams& params, CCoinsView* view) {
+ return g_chainstate.ReplayBlocks(params, view);
+}
+
+bool CChainState::RewindBlockIndex(const CChainParams& params)
{
LOCK(cs_main);
@@ -3870,8 +4023,8 @@ bool RewindBlockIndex(const CChainParams& params)
// Reduce validity flag and have-data flags.
// We do this after actual disconnecting, otherwise we'll end up writing the lack of data
// to disk before writing the chainstate, resulting in a failure to continue if interrupted.
- for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) {
- CBlockIndex* pindexIter = it->second;
+ for (const auto& entry : mapBlockIndex) {
+ CBlockIndex* pindexIter = entry.second;
// Note: If we encounter an insufficiently validated block that
// is on chainActive, it must be because we are a pruning node, and
@@ -3914,10 +4067,21 @@ bool RewindBlockIndex(const CChainParams& params)
PruneBlockIndexCandidates();
CheckBlockIndex(params.GetConsensus());
+ }
+ return true;
+}
+
+bool RewindBlockIndex(const CChainParams& params) {
+ if (!g_chainstate.RewindBlockIndex(params)) {
+ return false;
+ }
+
+ if (chainActive.Tip() != nullptr) {
// FlushStateToDisk can possibly read chainActive. Be conservative
// and skip it here, we're about to -reindex-chainstate anyway, so
// it'll get called a bunch real soon.
+ CValidationState state;
if (!FlushStateToDisk(params, state, FLUSH_STATE_ALWAYS)) {
return false;
}
@@ -3926,13 +4090,18 @@ bool RewindBlockIndex(const CChainParams& params)
return true;
}
+void CChainState::UnloadBlockIndex() {
+ nBlockSequenceId = 1;
+ g_failed_blocks.clear();
+ setBlockIndexCandidates.clear();
+}
+
// May NOT be used after any connections are up as much
// of the peer-processing logic assumes a consistent
// block index state
void UnloadBlockIndex()
{
LOCK(cs_main);
- setBlockIndexCandidates.clear();
chainActive.SetTip(nullptr);
pindexBestInvalid = nullptr;
pindexBestHeader = nullptr;
@@ -3940,9 +4109,7 @@ void UnloadBlockIndex()
mapBlocksUnlinked.clear();
vinfoBlockFile.clear();
nLastBlockFile = 0;
- nBlockSequenceId = 1;
setDirtyBlockIndex.clear();
- g_failed_blocks.clear();
setDirtyFileInfo.clear();
versionbitscache.Clear();
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
@@ -3954,6 +4121,8 @@ void UnloadBlockIndex()
}
mapBlockIndex.clear();
fHavePruned = false;
+
+ g_chainstate.UnloadBlockIndex();
}
bool LoadBlockIndex(const CChainParams& chainparams)
@@ -3981,7 +4150,7 @@ bool LoadBlockIndex(const CChainParams& chainparams)
return true;
}
-bool LoadGenesisBlock(const CChainParams& chainparams)
+bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
{
LOCK(cs_main);
@@ -3994,15 +4163,11 @@ bool LoadGenesisBlock(const CChainParams& chainparams)
try {
CBlock &block = const_cast<CBlock&>(chainparams.GenesisBlock());
- // Start new block file
- unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
- CDiskBlockPos blockPos;
- CValidationState state;
- if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime()))
- return error("%s: FindBlockPos failed", __func__);
- if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
+ CDiskBlockPos blockPos = SaveBlockToDisk(block, 0, chainparams, nullptr);
+ if (blockPos.IsNull())
return error("%s: writing genesis block to disk failed", __func__);
CBlockIndex *pindex = AddToBlockIndex(block);
+ CValidationState state;
if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
return error("%s: genesis block not accepted", __func__);
} catch (const std::runtime_error& e) {
@@ -4012,6 +4177,11 @@ bool LoadGenesisBlock(const CChainParams& chainparams)
return true;
}
+bool LoadGenesisBlock(const CChainParams& chainparams)
+{
+ return g_chainstate.LoadGenesisBlock(chainparams);
+}
+
bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp)
{
// Map of disk positions for blocks with unknown parent (only used for reindex)
@@ -4072,7 +4242,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
LOCK(cs_main);
CValidationState state;
- if (AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr))
+ if (g_chainstate.AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr))
nLoaded++;
if (state.IsError())
break;
@@ -4106,7 +4276,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
head.ToString());
LOCK(cs_main);
CValidationState dummy;
- if (AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
+ if (g_chainstate.AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
{
nLoaded++;
queue.push_back(pblockrecursive->GetHash());
@@ -4129,7 +4299,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
return nLoaded > 0;
}
-void static CheckBlockIndex(const Consensus::Params& consensusParams)
+void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
{
if (!fCheckBlockIndex) {
return;
@@ -4147,8 +4317,8 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
// Build forward-pointing map of the entire block tree.
std::multimap<CBlockIndex*,CBlockIndex*> forward;
- for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) {
- forward.insert(std::make_pair(it->second->pprev, it->second));
+ for (auto& entry : mapBlockIndex) {
+ forward.insert(std::make_pair(entry.second->pprev, entry.second));
}
assert(forward.size() == mapBlockIndex.size());
@@ -4471,7 +4641,7 @@ bool DumpMempool(void)
}
//! Guess how far we are in the verification process at the given block index
-double GuessVerificationProgress(const ChainTxData& data, CBlockIndex *pindex) {
+double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pindex) {
if (pindex == nullptr)
return 0.0;
diff --git a/src/validation.h b/src/validation.h
index 254f3e0754..4c8e041af0 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -159,7 +159,7 @@ extern CCriticalSection cs_main;
extern CBlockPolicyEstimator feeEstimator;
extern CTxMemPool mempool;
typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
-extern BlockMap mapBlockIndex;
+extern BlockMap& mapBlockIndex;
extern uint64_t nLastBlockTx;
extern uint64_t nLastBlockWeight;
extern const std::string strMessageMagic;
@@ -203,6 +203,8 @@ extern bool fPruneMode;
extern uint64_t nPruneTarget;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
+/** Minimum blocks required to signal NODE_NETWORK_LIMITED */
+static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
static const signed int DEFAULT_CHECKBLOCKS = 6;
static const unsigned int DEFAULT_CHECKLEVEL = 3;
@@ -273,13 +275,13 @@ void ThreadScriptCheck();
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
bool IsInitialBlockDownload();
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
-bool GetTransaction(const uint256 &hash, CTransactionRef &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false);
+bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, bool fAllowSlow = false, CBlockIndex* blockIndex = nullptr);
/** Find the best known block, and make it the tip of the block chain */
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>());
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
/** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */
-double GuessVerificationProgress(const ChainTxData& data, CBlockIndex* pindex);
+double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex* pindex);
/** Calculate the amount of disk space the block & undo files currently use */
uint64_t CalculateCurrentUsage();
@@ -294,8 +296,6 @@ void PruneOneBlockFile(const int fileNumber);
*/
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
-/** Create a new block index entry for a given block hash */
-CBlockIndex * InsertBlockIndex(uint256 hash);
/** Flush all state, indexes and buffers to disk. */
void FlushStateToDisk();
/** Prune block files and flush state to disk. */
@@ -441,7 +441,7 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
bool ResetBlockFailureFlags(CBlockIndex *pindex);
/** The currently-connected chain of blocks (protected by cs_main). */
-extern CChain chainActive;
+extern CChain& chainActive;
/** Global variable that points to the coins database (protected by cs_main) */
extern std::unique_ptr<CCoinsViewDB> pcoinsdbview;
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 5ceba17e06..abbd8cc4d2 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -49,7 +49,9 @@ void CMainSignals::UnregisterBackgroundSignalScheduler() {
}
void CMainSignals::FlushBackgroundCallbacks() {
- m_internals->m_schedulerClient.EmptyQueue();
+ if (m_internals) {
+ m_internals->m_schedulerClient.EmptyQueue();
+ }
}
void CMainSignals::RegisterWithMempoolSignals(CTxMemPool& pool) {
@@ -92,6 +94,9 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
}
void UnregisterAllValidationInterfaces() {
+ if (!g_signals.m_internals) {
+ return;
+ }
g_signals.m_internals->BlockChecked.disconnect_all_slots();
g_signals.m_internals->Broadcast.disconnect_all_slots();
g_signals.m_internals->Inventory.disconnect_all_slots();
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 79ff27279c..d4cd30dfac 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -6,7 +6,6 @@
#include <wallet/db.h>
#include <addrman.h>
-#include <fs.h>
#include <hash.h>
#include <protocol.h>
#include <util.h>
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index fcc4c43872..6ca947bf1b 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -165,7 +165,7 @@ UniValue abortrescan(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 0)
throw std::runtime_error(
"abortrescan\n"
- "\nStops current wallet rescan triggered e.g. by an importprivkey call.\n"
+ "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n"
"\nExamples:\n"
"\nImport a private key\n"
+ HelpExampleCli("importprivkey", "\"mykey\"") +
@@ -721,8 +721,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
- const bool& internal = data.exists("internal") ? data["internal"].get_bool() : false;
- const bool& watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
+ const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
+ const bool watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
const std::string& label = data.exists("label") && !internal ? data["label"].get_str() : "";
bool isScript = scriptPubKey.getType() == UniValue::VSTR;
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 9a7861f978..f839a18612 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -771,6 +771,8 @@ UniValue getbalance(const JSONRPCRequest& request)
throw std::runtime_error(
"getbalance ( \"account\" minconf include_watchonly )\n"
"\nIf account is not specified, returns the server's total available balance.\n"
+ "The available balance is what the wallet considers currently spendable, and is\n"
+ "thus affected by options which limit spendability such as -spendzeroconfchange.\n"
"If account is specified (DEPRECATED), returns the balance in the account.\n"
"Note that the account \"\" is not the same as leaving the parameter out.\n"
"The server total may be different to the balance in the default \"\" account.\n"
@@ -1439,14 +1441,14 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
if (fByAccounts)
{
- for (std::map<std::string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
+ for (const auto& entry : mapAccountTally)
{
- CAmount nAmount = (*it).second.nAmount;
- int nConf = (*it).second.nConf;
+ CAmount nAmount = entry.second.nAmount;
+ int nConf = entry.second.nConf;
UniValue obj(UniValue::VOBJ);
- if((*it).second.fIsWatchonly)
+ if (entry.second.fIsWatchonly)
obj.push_back(Pair("involvesWatchonly", true));
- obj.push_back(Pair("account", (*it).first));
+ obj.push_back(Pair("account", entry.first));
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
ret.push_back(obj);
@@ -2980,9 +2982,9 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw std::runtime_error(
- "fundrawtransaction \"hexstring\" ( options )\n"
+ "fundrawtransaction \"hexstring\" ( options iswitness )\n"
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
"This will not modify existing inputs, and will add at most one change output to the outputs.\n"
"No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
@@ -3017,6 +3019,9 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
" \"CONSERVATIVE\"\n"
" }\n"
" for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n"
+ "3. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction \n"
+ " If iswitness is not present, heuristic tests will be used in decoding\n"
+
"\nResult:\n"
"{\n"
" \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
@@ -3053,7 +3058,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
coinControl.fAllowWatchOnly = request.params[1].get_bool();
}
else {
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
+ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ, UniValue::VBOOL});
UniValue options = request.params[1];
@@ -3122,8 +3127,11 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
// parse hex string from parameter
CMutableTransaction tx;
- if (!DecodeHexTx(tx, request.params[0].get_str(), true))
+ bool try_witness = request.params[2].isNull() ? true : request.params[2].get_bool();
+ bool try_no_witness = request.params[2].isNull() ? true : !request.params[2].get_bool();
+ if (!DecodeHexTx(tx, request.params[0].get_str(), try_no_witness, try_witness)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
+ }
if (tx.vout.size() == 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");
@@ -3441,7 +3449,7 @@ extern UniValue rescanblockchain(const JSONRPCRequest& request);
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options"} },
+ { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} },
{ "hidden", "resendwallettransactions", &resendwallettransactions, {} },
{ "wallet", "abandontransaction", &abandontransaction, {"txid"} },
{ "wallet", "abortrescan", &abortrescan, {} },
diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp
index edbabcc921..b95bb14335 100644
--- a/src/wallet/test/accounting_tests.cpp
+++ b/src/wallet/test/accounting_tests.cpp
@@ -10,18 +10,16 @@
#include <boost/test/unit_test.hpp>
-extern std::unique_ptr<CWallet> pwalletMain;
-
BOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup)
static void
-GetResults(std::map<CAmount, CAccountingEntry>& results)
+GetResults(CWallet *wallet, std::map<CAmount, CAccountingEntry>& results)
{
std::list<CAccountingEntry> aes;
results.clear();
- BOOST_CHECK(pwalletMain->ReorderTransactions() == DB_LOAD_OK);
- pwalletMain->ListAccountCreditDebit("", aes);
+ BOOST_CHECK(wallet->ReorderTransactions() == DB_LOAD_OK);
+ wallet->ListAccountCreditDebit("", aes);
for (CAccountingEntry& ae : aes)
{
results[ae.nOrderPos] = ae;
@@ -54,7 +52,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.strOtherAccount = "c";
pwalletMain->AddAccountingEntry(ae);
- GetResults(results);
+ GetResults(pwalletMain.get(), results);
BOOST_CHECK(pwalletMain->nOrderPosNext == 3);
BOOST_CHECK(2 == results.size());
@@ -70,7 +68,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nOrderPos = pwalletMain->IncOrderPosNext();
pwalletMain->AddAccountingEntry(ae);
- GetResults(results);
+ GetResults(pwalletMain.get(), results);
BOOST_CHECK(results.size() == 3);
BOOST_CHECK(pwalletMain->nOrderPosNext == 4);
@@ -102,7 +100,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
vpwtx[2]->nTimeReceived = (unsigned int)1333333329;
vpwtx[2]->nOrderPos = -1;
- GetResults(results);
+ GetResults(pwalletMain.get(), results);
BOOST_CHECK(results.size() == 3);
BOOST_CHECK(pwalletMain->nOrderPosNext == 6);
@@ -120,7 +118,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nOrderPos = -1;
pwalletMain->AddAccountingEntry(ae);
- GetResults(results);
+ GetResults(pwalletMain.get(), results);
BOOST_CHECK(results.size() == 4);
BOOST_CHECK(pwalletMain->nOrderPosNext == 7);
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index 995ec640b1..3ee83d2d7c 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -6,9 +6,6 @@
#include <rpc/server.h>
#include <wallet/db.h>
-#include <wallet/wallet.h>
-
-std::unique_ptr<CWallet> pwalletMain;
WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
TestingSetup(chainName)
@@ -27,7 +24,6 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
WalletTestingSetup::~WalletTestingSetup()
{
UnregisterValidationInterface(pwalletMain.get());
- pwalletMain.reset();
bitdb.Flush(true);
bitdb.Reset();
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index a341bc698a..292d654438 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -7,11 +7,15 @@
#include <test/test_bitcoin.h>
+#include <wallet/wallet.h>
+
/** Testing setup and teardown for wallet.
*/
struct WalletTestingSetup: public TestingSetup {
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~WalletTestingSetup();
+
+ std::unique_ptr<CWallet> pwalletMain;
};
#endif
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 31b75120b4..80e31a1ce0 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -19,8 +19,6 @@
#include <boost/test/unit_test.hpp>
#include <univalue.h>
-extern std::unique_ptr<CWallet> pwalletMain;
-
extern UniValue importmulti(const JSONRPCRequest& request);
extern UniValue dumpwallet(const JSONRPCRequest& request);
extern UniValue importwallet(const JSONRPCRequest& request);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index edc1ca6ef8..dafd708d09 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -23,12 +23,10 @@
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <script/script.h>
-#include <script/sign.h>
#include <scheduler.h>
#include <timedata.h>
#include <txmempool.h>
#include <util.h>
-#include <ui_interface.h>
#include <utilmoneystr.h>
#include <wallet/fees.h>
@@ -284,7 +282,7 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
}
}
-bool CWallet::LoadKeyMetadata(const CTxDestination& keyID, const CKeyMetadata &meta)
+bool CWallet::LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &meta)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
UpdateTimeFirstKey(meta.nCreateTime);
@@ -292,6 +290,14 @@ bool CWallet::LoadKeyMetadata(const CTxDestination& keyID, const CKeyMetadata &m
return true;
}
+bool CWallet::LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &meta)
+{
+ AssertLockHeld(cs_wallet); // m_script_metadata
+ UpdateTimeFirstKey(meta.nCreateTime);
+ m_script_metadata[script_id] = meta;
+ return true;
+}
+
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
@@ -340,7 +346,7 @@ bool CWallet::AddWatchOnly(const CScript& dest)
{
if (!CCryptoKeyStore::AddWatchOnly(dest))
return false;
- const CKeyMetadata& meta = mapKeyMetadata[CScriptID(dest)];
+ const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)];
UpdateTimeFirstKey(meta.nCreateTime);
NotifyWatchonlyChanged(true);
return CWalletDB(*dbw).WriteWatchOnly(dest, meta);
@@ -348,7 +354,7 @@ bool CWallet::AddWatchOnly(const CScript& dest)
bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
{
- mapKeyMetadata[CScriptID(dest)].nCreateTime = nCreateTime;
+ m_script_metadata[CScriptID(dest)].nCreateTime = nCreateTime;
return AddWatchOnly(dest);
}
@@ -705,9 +711,9 @@ DBErrors CWallet::ReorderTransactions()
typedef std::multimap<int64_t, TxPair > TxItems;
TxItems txByTime;
- for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (auto& entry : mapWallet)
{
- CWalletTx* wtx = &((*it).second);
+ CWalletTx* wtx = &entry.second;
txByTime.insert(std::make_pair(wtx->nTimeReceived, TxPair(wtx, nullptr)));
}
std::list<CAccountingEntry> acentries;
@@ -1713,11 +1719,8 @@ void CWallet::ReacceptWalletTransactions()
}
// Try to add wallet transactions to memory pool
- for (std::pair<const int64_t, CWalletTx*>& item : mapSorted)
- {
+ for (std::pair<const int64_t, CWalletTx*>& item : mapSorted) {
CWalletTx& wtx = *(item.second);
-
- LOCK(mempool.cs);
CValidationState state;
wtx.AcceptToMemoryPool(maxTxFee, state);
}
@@ -1865,7 +1868,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
return nCredit;
}
-CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const
+CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const
{
if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
{
@@ -1879,7 +1882,7 @@ CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const
return 0;
}
-CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const
+CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool fUseCache) const
{
if (pwallet == nullptr)
return 0;
@@ -2026,9 +2029,9 @@ CAmount CWallet::GetBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &(*it).second;
+ const CWalletTx* pcoin = &entry.second;
if (pcoin->IsTrusted())
nTotal += pcoin->GetAvailableCredit();
}
@@ -2042,9 +2045,9 @@ CAmount CWallet::GetUnconfirmedBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &(*it).second;
+ const CWalletTx* pcoin = &entry.second;
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
nTotal += pcoin->GetAvailableCredit();
}
@@ -2057,9 +2060,9 @@ CAmount CWallet::GetImmatureBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &(*it).second;
+ const CWalletTx* pcoin = &entry.second;
nTotal += pcoin->GetImmatureCredit();
}
}
@@ -2071,9 +2074,9 @@ CAmount CWallet::GetWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &(*it).second;
+ const CWalletTx* pcoin = &entry.second;
if (pcoin->IsTrusted())
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
@@ -2087,9 +2090,9 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &(*it).second;
+ const CWalletTx* pcoin = &entry.second;
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
@@ -2102,9 +2105,9 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &(*it).second;
+ const CWalletTx* pcoin = &entry.second;
nTotal += pcoin->GetImmatureWatchOnlyCredit();
}
}
@@ -2169,7 +2172,7 @@ CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const
return balance;
}
-void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t &nMaximumCount, const int &nMinDepth, const int &nMaxDepth) const
+void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount, const int nMinDepth, const int nMaxDepth) const
{
vCoins.clear();
@@ -2178,10 +2181,10 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
CAmount nTotal = 0;
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const uint256& wtxid = it->first;
- const CWalletTx* pcoin = &(*it).second;
+ const uint256& wtxid = entry.first;
+ const CWalletTx* pcoin = &entry.second;
if (!CheckFinalTx(*pcoin->tx))
continue;
@@ -2242,10 +2245,10 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
if (pcoin->tx->vout[i].nValue < nMinimumAmount || pcoin->tx->vout[i].nValue > nMaximumAmount)
continue;
- if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint((*it).first, i)))
+ if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint(entry.first, i)))
continue;
- if (IsLockedCoin((*it).first, i))
+ if (IsLockedCoin(entry.first, i))
continue;
if (IsSpent(wtxid, i))
@@ -2592,9 +2595,8 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
{
std::vector<CRecipient> vecSend;
- // Turn the txout set into a CRecipient vector
- for (size_t idx = 0; idx < tx.vout.size(); idx++)
- {
+ // Turn the txout set into a CRecipient vector.
+ for (size_t idx = 0; idx < tx.vout.size(); idx++) {
const CTxOut& txOut = tx.vout[idx];
CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, setSubtractFeeFromOutputs.count(idx) == 1};
vecSend.push_back(recipient);
@@ -2602,8 +2604,13 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
coinControl.fAllowOtherInputs = true;
- for (const CTxIn& txin : tx.vin)
+ for (const CTxIn& txin : tx.vin) {
coinControl.Select(txin.prevout);
+ }
+
+ // Acquire the locks to prevent races to the new locked unspents between the
+ // CreateTransaction call and LockCoin calls (when lockUnspents is true).
+ LOCK2(cs_main, cs_wallet);
CReserveKey reservekey(this);
CWalletTx wtx;
@@ -2613,31 +2620,28 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
if (nChangePosInOut != -1) {
tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.tx->vout[nChangePosInOut]);
- // we don't have the normal Create/Commit cycle, and don't want to risk reusing change,
- // so just remove the key from the keypool here.
+ // We don't have the normal Create/Commit cycle, and don't want to risk
+ // reusing change, so just remove the key from the keypool here.
reservekey.KeepKey();
}
- // Copy output sizes from new transaction; they may have had the fee subtracted from them
- for (unsigned int idx = 0; idx < tx.vout.size(); idx++)
+ // Copy output sizes from new transaction; they may have had the fee
+ // subtracted from them.
+ for (unsigned int idx = 0; idx < tx.vout.size(); idx++) {
tx.vout[idx].nValue = wtx.tx->vout[idx].nValue;
+ }
- // Add new txins (keeping original txin scriptSig/order)
- for (const CTxIn& txin : wtx.tx->vin)
- {
- if (!coinControl.IsSelected(txin.prevout))
- {
+ // Add new txins while keeping original txin scriptSig/order.
+ for (const CTxIn& txin : wtx.tx->vin) {
+ if (!coinControl.IsSelected(txin.prevout)) {
tx.vin.push_back(txin);
- if (lockUnspents)
- {
- LOCK2(cs_main, cs_wallet);
- LockCoin(txin.prevout);
+ if (lockUnspents) {
+ LockCoin(txin.prevout);
}
}
}
-
return true;
}
@@ -3705,9 +3709,9 @@ void CWallet::GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) c
// find first block that affects those keys, if there are any left
std::vector<CKeyID> vAffected;
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
+ for (const auto& entry : mapWallet) {
// iterate over all wallet transactions...
- const CWalletTx &wtx = (*it).second;
+ const CWalletTx &wtx = entry.second;
BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) {
// ... which are already in a block
@@ -3727,8 +3731,8 @@ void CWallet::GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) c
}
// Extract block timestamps for those keys
- for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
- mapKeyBirth[it->first] = it->second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off
+ for (const auto& entry : mapKeyFirstBlock)
+ mapKeyBirth[entry.first] = entry.second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off
}
/**
@@ -4114,6 +4118,11 @@ int CMerkleTx::GetBlocksToMaturity() const
bool CWalletTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state)
{
+ // Quick check to avoid re-setting fInMempool to false
+ if (mempool.exists(tx->GetHash())) {
+ return false;
+ }
+
// We must set fInMempool here - while it will be re-set to true by the
// entered-mempool callback, if we did not there would be a race where a
// user could call sendmoney in a loop and hit spurious out of funds errors
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 1bd0be7bd0..97581794a8 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -445,8 +445,8 @@ public:
CAmount GetCredit(const isminefilter& filter) const;
CAmount GetImmatureCredit(bool fUseCache=true) const;
CAmount GetAvailableCredit(bool fUseCache=true) const;
- CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache=true) const;
- CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache=true) const;
+ CAmount GetImmatureWatchOnlyCredit(const bool fUseCache=true) const;
+ CAmount GetAvailableWatchOnlyCredit(const bool fUseCache=true) const;
CAmount GetChange() const;
void GetAmounts(std::list<COutputEntry>& listReceived,
@@ -761,9 +761,11 @@ public:
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool);
- // Map from Key ID (for regular keys) or Script ID (for watch-only keys) to
- // key metadata.
- std::map<CTxDestination, CKeyMetadata> mapKeyMetadata;
+ // Map from Key ID to key metadata.
+ std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
+
+ // Map from Script ID to key metadata (for watch-only keys).
+ std::map<CScriptID, CKeyMetadata> m_script_metadata;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
@@ -828,7 +830,7 @@ public:
/**
* populate vCoins with vector of available COutputs.
*/
- void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t& nMaximumCount = 0, const int& nMinDepth = 0, const int& nMaxDepth = 9999999) const;
+ void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0, const int nMinDepth = 0, const int nMaxDepth = 9999999) const;
/**
* Return list of available coins and locked coins grouped by non-change output address.
@@ -874,7 +876,8 @@ public:
//! Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
//! Load metadata (used by LoadWallet)
- bool LoadKeyMetadata(const CTxDestination& pubKey, const CKeyMetadata &metadata);
+ bool LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata);
+ bool LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata);
bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
void UpdateTimeFirstKey(int64_t nCreateTime);
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 5116d6419e..0b0d84708d 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -423,27 +423,23 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
wss.fIsEncrypted = true;
}
- else if (strType == "keymeta" || strType == "watchmeta")
+ else if (strType == "keymeta")
{
- CTxDestination keyID;
- if (strType == "keymeta")
- {
- CPubKey vchPubKey;
- ssKey >> vchPubKey;
- keyID = vchPubKey.GetID();
- }
- else if (strType == "watchmeta")
- {
- CScript script;
- ssKey >> script;
- keyID = CScriptID(script);
- }
-
+ CPubKey vchPubKey;
+ ssKey >> vchPubKey;
CKeyMetadata keyMeta;
ssValue >> keyMeta;
wss.nKeyMeta++;
-
- pwallet->LoadKeyMetadata(keyID, keyMeta);
+ pwallet->LoadKeyMetadata(vchPubKey.GetID(), keyMeta);
+ }
+ else if (strType == "watchmeta")
+ {
+ CScript script;
+ ssKey >> script;
+ CKeyMetadata keyMeta;
+ ssValue >> keyMeta;
+ wss.nKeyMeta++;
+ pwallet->LoadScriptMetadata(CScriptID(script), keyMeta);
}
else if (strType == "defaultkey")
{
@@ -630,7 +626,6 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
DBErrors CWalletDB::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx)
{
- bool fNoncriticalErrors = false;
DBErrors result = DB_LOAD_OK;
try {
@@ -685,9 +680,6 @@ DBErrors CWalletDB::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWal
result = DB_CORRUPT;
}
- if (fNoncriticalErrors && result == DB_LOAD_OK)
- result = DB_NONCRITICAL_ERROR;
-
return result;
}
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index 26587d38a3..b663615752 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -40,15 +40,15 @@ CZMQNotificationInterface* CZMQNotificationInterface::Create()
factories["pubrawblock"] = CZMQAbstractNotifier::Create<CZMQPublishRawBlockNotifier>;
factories["pubrawtx"] = CZMQAbstractNotifier::Create<CZMQPublishRawTransactionNotifier>;
- for (std::map<std::string, CZMQNotifierFactory>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
+ for (const auto& entry : factories)
{
- std::string arg("-zmq" + i->first);
+ std::string arg("-zmq" + entry.first);
if (gArgs.IsArgSet(arg))
{
- CZMQNotifierFactory factory = i->second;
+ CZMQNotifierFactory factory = entry.second;
std::string address = gArgs.GetArg(arg, "");
CZMQAbstractNotifier *notifier = factory();
- notifier->SetType(i->first);
+ notifier->SetType(entry.first);
notifier->SetAddress(address);
notifiers.push_back(notifier);
}