aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/Makefile.bench.include4
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/addrman.h8
-rw-r--r--src/bench/base58.cpp56
-rw-r--r--src/bench/bench.cpp35
-rw-r--r--src/bench/bench.h7
-rw-r--r--src/bench/crypto_hash.cpp78
-rw-r--r--src/coins.cpp6
-rw-r--r--src/coins.h14
-rw-r--r--src/hash.cpp94
-rw-r--r--src/hash.h15
-rw-r--r--src/init.cpp56
-rw-r--r--src/key.cpp3
-rw-r--r--src/main.cpp204
-rw-r--r--src/main.h6
-rw-r--r--src/net.cpp270
-rw-r--r--src/net.h13
-rw-r--r--src/netbase.cpp37
-rw-r--r--src/qt/askpassphrasedialog.cpp21
-rw-r--r--src/qt/askpassphrasedialog.h1
-rw-r--r--src/qt/bitcoin.cpp1
-rw-r--r--src/qt/bitcoingui.cpp50
-rw-r--r--src/qt/bitcoingui.h6
-rw-r--r--src/qt/clientmodel.cpp18
-rw-r--r--src/qt/clientmodel.h2
-rw-r--r--src/qt/forms/optionsdialog.ui10
-rw-r--r--src/qt/optionsdialog.cpp14
-rw-r--r--src/qt/optionsdialog.h2
-rw-r--r--src/qt/optionsmodel.cpp14
-rw-r--r--src/qt/optionsmodel.h4
-rw-r--r--src/qt/overviewpage.cpp2
-rw-r--r--src/qt/rpcconsole.cpp17
-rw-r--r--src/qt/rpcconsole.h2
-rw-r--r--src/qt/sendcoinsdialog.cpp2
-rw-r--r--src/qt/transactionview.cpp2
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/random.cpp66
-rw-r--r--src/random.h11
-rw-r--r--src/rpc/net.cpp12
-rw-r--r--src/rpc/rawtransaction.cpp7
-rw-r--r--src/test/data/script_tests.json18
-rw-r--r--src/test/hash_tests.cpp20
-rw-r--r--src/test/net_tests.cpp145
-rw-r--r--src/test/script_tests.cpp5
-rw-r--r--src/test/sighash_tests.cpp1
-rw-r--r--src/test/txvalidationcache_tests.cpp2
-rw-r--r--src/txmempool.cpp10
-rw-r--r--src/txmempool.h4
-rw-r--r--src/ui_interface.h3
-rw-r--r--src/uint256.cpp64
-rw-r--r--src/uint256.h18
-rw-r--r--src/util.cpp2
-rw-r--r--src/util.h6
-rw-r--r--src/wallet/rpcwallet.cpp44
-rw-r--r--src/wallet/wallet.cpp85
-rw-r--r--src/wallet/wallet.h4
-rw-r--r--src/wallet/walletdb.cpp40
-rw-r--r--src/wallet/walletdb.h1
59 files changed, 1150 insertions, 498 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index cb8a99fe9a..ea49efe92d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -367,7 +367,8 @@ endif
bitcoin_cli_LDADD = \
$(LIBBITCOIN_CLI) \
$(LIBUNIVALUE) \
- $(LIBBITCOIN_UTIL)
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CRYPTO)
bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS)
#
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 24e2b3e0c8..4067ceb399 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -8,7 +8,9 @@ bench_bench_bitcoin_SOURCES = \
bench/bench.cpp \
bench/bench.h \
bench/Examples.cpp \
- bench/rollingbloom.cpp
+ bench/rollingbloom.cpp \
+ bench/crypto_hash.cpp \
+ bench/base58.cpp
bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index d443b6d34a..77cf1001e1 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -59,6 +59,7 @@ BITCOIN_TESTS =\
test/merkle_tests.cpp \
test/miner_tests.cpp \
test/multisig_tests.cpp \
+ test/net_tests.cpp \
test/netbase_tests.cpp \
test/pmt_tests.cpp \
test/policyestimator_tests.cpp \
diff --git a/src/addrman.h b/src/addrman.h
index 4f3de8d7c5..3085450450 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -350,6 +350,14 @@ public:
nUBuckets ^= (1 << 30);
}
+ if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
+ throw std::ios_base::failure("Corrupt CAddrMan serialization, nNew exceeds limit.");
+ }
+
+ if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
+ throw std::ios_base::failure("Corrupt CAddrMan serialization, nTried exceeds limit.");
+ }
+
// Deserialize entries from the new table.
for (int n = 0; n < nNew; n++) {
CAddrInfo &info = mapInfo[n];
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
new file mode 100644
index 0000000000..1279c3e7df
--- /dev/null
+++ b/src/bench/base58.cpp
@@ -0,0 +1,56 @@
+// Copyright (c) 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 "bench.h"
+
+#include "main.h"
+#include "base58.h"
+
+#include <vector>
+#include <string>
+
+
+static void Base58Encode(benchmark::State& state)
+{
+ unsigned char buff[32] = {
+ 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
+ 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
+ 200, 24
+ };
+ unsigned char* b = buff;
+ while (state.KeepRunning()) {
+ EncodeBase58(b, b + 32);
+ }
+}
+
+
+static void Base58CheckEncode(benchmark::State& state)
+{
+ unsigned char buff[32] = {
+ 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
+ 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
+ 200, 24
+ };
+ unsigned char* b = buff;
+ std::vector<unsigned char> vch;
+ vch.assign(b, b + 32);
+ while (state.KeepRunning()) {
+ EncodeBase58Check(vch);
+ }
+}
+
+
+static void Base58Decode(benchmark::State& state)
+{
+ const char* addr = "17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem";
+ std::vector<unsigned char> vch;
+ while (state.KeepRunning()) {
+ DecodeBase58(addr, vch);
+ }
+}
+
+
+BENCHMARK(Base58Encode);
+BENCHMARK(Base58CheckEncode);
+BENCHMARK(Base58Decode);
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 6ee3cdc27a..227546a7a7 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -5,6 +5,7 @@
#include "bench.h"
#include <iostream>
+#include <iomanip>
#include <sys/time.h>
using namespace benchmark;
@@ -25,7 +26,7 @@ BenchRunner::BenchRunner(std::string name, BenchFunction func)
void
BenchRunner::RunAll(double elapsedTimeForOne)
{
- std::cout << "Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << "\n";
+ std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << "\n";
for (std::map<std::string,BenchFunction>::iterator it = benchmarks.begin();
it != benchmarks.end(); ++it) {
@@ -38,22 +39,34 @@ BenchRunner::RunAll(double elapsedTimeForOne)
bool State::KeepRunning()
{
+ if (count & countMask) {
+ ++count;
+ return true;
+ }
double now;
if (count == 0) {
- beginTime = now = gettimedouble();
+ lastTime = beginTime = now = gettimedouble();
}
else {
- // timeCheckCount is used to avoid calling gettime most of the time,
- // so benchmarks that run very quickly get consistent results.
- if ((count+1)%timeCheckCount != 0) {
- ++count;
- return true; // keep going
- }
now = gettimedouble();
- double elapsedOne = (now - lastTime)/timeCheckCount;
+ double elapsed = now - lastTime;
+ double elapsedOne = elapsed * countMaskInv;
if (elapsedOne < minTime) minTime = elapsedOne;
if (elapsedOne > maxTime) maxTime = elapsedOne;
- if (elapsedOne*timeCheckCount < maxElapsed/16) timeCheckCount *= 2;
+ if (elapsed*128 < maxElapsed) {
+ // If the execution was much too fast (1/128th of maxElapsed), increase the count mask by 8x and restart timing.
+ // The restart avoids including the overhead of this code in the measurement.
+ countMask = ((countMask<<3)|7) & ((1LL<<60)-1);
+ countMaskInv = 1./(countMask+1);
+ count = 0;
+ minTime = std::numeric_limits<double>::max();
+ maxTime = std::numeric_limits<double>::min();
+ return true;
+ }
+ if (elapsed*16 < maxElapsed) {
+ countMask = ((countMask<<1)|1) & ((1LL<<60)-1);
+ countMaskInv = 1./(countMask+1);
+ }
}
lastTime = now;
++count;
@@ -64,7 +77,7 @@ bool State::KeepRunning()
// Output results
double average = (now-beginTime)/count;
- std::cout << name << "," << count << "," << minTime << "," << maxTime << "," << average << "\n";
+ std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << minTime << "," << maxTime << "," << average << "\n";
return false;
}
diff --git a/src/bench/bench.h b/src/bench/bench.h
index 5ce13c642b..f13b145aaf 100644
--- a/src/bench/bench.h
+++ b/src/bench/bench.h
@@ -40,14 +40,15 @@ namespace benchmark {
std::string name;
double maxElapsed;
double beginTime;
- double lastTime, minTime, maxTime;
+ double lastTime, minTime, maxTime, countMaskInv;
int64_t count;
- int64_t timeCheckCount;
+ int64_t countMask;
public:
State(std::string _name, double _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {
minTime = std::numeric_limits<double>::max();
maxTime = std::numeric_limits<double>::min();
- timeCheckCount = 1;
+ countMask = 1;
+ countMaskInv = 1./(countMask + 1);
}
bool KeepRunning();
};
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
new file mode 100644
index 0000000000..168006154f
--- /dev/null
+++ b/src/bench/crypto_hash.cpp
@@ -0,0 +1,78 @@
+// Copyright (c) 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 <iostream>
+
+#include "bench.h"
+#include "bloom.h"
+#include "hash.h"
+#include "uint256.h"
+#include "utiltime.h"
+#include "crypto/ripemd160.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/sha512.h"
+
+/* Number of bytes to hash per iteration */
+static const uint64_t BUFFER_SIZE = 1000*1000;
+
+static void RIPEMD160(benchmark::State& state)
+{
+ uint8_t hash[CRIPEMD160::OUTPUT_SIZE];
+ std::vector<uint8_t> in(BUFFER_SIZE,0);
+ while (state.KeepRunning())
+ CRIPEMD160().Write(begin_ptr(in), in.size()).Finalize(hash);
+}
+
+static void SHA1(benchmark::State& state)
+{
+ uint8_t hash[CSHA1::OUTPUT_SIZE];
+ std::vector<uint8_t> in(BUFFER_SIZE,0);
+ while (state.KeepRunning())
+ CSHA1().Write(begin_ptr(in), in.size()).Finalize(hash);
+}
+
+static void SHA256(benchmark::State& state)
+{
+ uint8_t hash[CSHA256::OUTPUT_SIZE];
+ std::vector<uint8_t> in(BUFFER_SIZE,0);
+ while (state.KeepRunning())
+ CSHA256().Write(begin_ptr(in), in.size()).Finalize(hash);
+}
+
+static void SHA256_32b(benchmark::State& state)
+{
+ std::vector<uint8_t> in(32,0);
+ while (state.KeepRunning()) {
+ for (int i = 0; i < 1000000; i++) {
+ CSHA256().Write(begin_ptr(in), in.size()).Finalize(&in[0]);
+ }
+ }
+}
+
+static void SHA512(benchmark::State& state)
+{
+ uint8_t hash[CSHA512::OUTPUT_SIZE];
+ std::vector<uint8_t> in(BUFFER_SIZE,0);
+ while (state.KeepRunning())
+ CSHA512().Write(begin_ptr(in), in.size()).Finalize(hash);
+}
+
+static void SipHash_32b(benchmark::State& state)
+{
+ uint256 x;
+ while (state.KeepRunning()) {
+ for (int i = 0; i < 1000000; i++) {
+ *((uint64_t*)x.begin()) = SipHashUint256(0, i, x);
+ }
+ }
+}
+
+BENCHMARK(RIPEMD160);
+BENCHMARK(SHA1);
+BENCHMARK(SHA256);
+BENCHMARK(SHA512);
+
+BENCHMARK(SHA256_32b);
+BENCHMARK(SipHash_32b);
diff --git a/src/coins.cpp b/src/coins.cpp
index 1c329740b4..b7dd293d69 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -56,7 +56,11 @@ void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
-CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
+SaltedTxidHasher::SaltedTxidHasher()
+{
+ GetRandBytes((unsigned char*)&k0, sizeof(k0));
+ GetRandBytes((unsigned char*)&k1, sizeof(k1));
+}
CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), cachedCoinsUsage(0) { }
diff --git a/src/coins.h b/src/coins.h
index d72f885473..1dd908700b 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -8,6 +8,7 @@
#include "compressor.h"
#include "core_memusage.h"
+#include "hash.h"
#include "memusage.h"
#include "serialize.h"
#include "uint256.h"
@@ -264,21 +265,22 @@ public:
}
};
-class CCoinsKeyHasher
+class SaltedTxidHasher
{
private:
- uint256 salt;
+ /** Salt */
+ uint64_t k0, k1;
public:
- CCoinsKeyHasher();
+ SaltedTxidHasher();
/**
* This *must* return size_t. With Boost 1.46 on 32-bit systems the
* unordered_map will behave unpredictably if the custom hasher returns a
* uint64_t, resulting in failures when syncing the chain (#4634).
*/
- size_t operator()(const uint256& key) const {
- return key.GetHash(salt);
+ size_t operator()(const uint256& txid) const {
+ return SipHashUint256(k0, k1, txid);
}
};
@@ -295,7 +297,7 @@ struct CCoinsCacheEntry
CCoinsCacheEntry() : coins(), flags(0) {}
};
-typedef boost::unordered_map<uint256, CCoinsCacheEntry, CCoinsKeyHasher> CCoinsMap;
+typedef boost::unordered_map<uint256, CCoinsCacheEntry, SaltedTxidHasher> CCoinsMap;
/** Cursor for iterating over CoinsView state */
class CCoinsViewCursor
diff --git a/src/hash.cpp b/src/hash.cpp
index 7f3cf1a1fa..a518314a53 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -81,3 +81,97 @@ void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char he
num[3] = (nChild >> 0) & 0xFF;
CHMAC_SHA512(chainCode.begin(), chainCode.size()).Write(&header, 1).Write(data, 32).Write(num, 4).Finalize(output);
}
+
+#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
+
+#define SIPROUND do { \
+ v0 += v1; v1 = ROTL(v1, 13); v1 ^= v0; \
+ v0 = ROTL(v0, 32); \
+ v2 += v3; v3 = ROTL(v3, 16); v3 ^= v2; \
+ v0 += v3; v3 = ROTL(v3, 21); v3 ^= v0; \
+ v2 += v1; v1 = ROTL(v1, 17); v1 ^= v2; \
+ v2 = ROTL(v2, 32); \
+} while (0)
+
+CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
+{
+ v[0] = 0x736f6d6570736575ULL ^ k0;
+ v[1] = 0x646f72616e646f6dULL ^ k1;
+ v[2] = 0x6c7967656e657261ULL ^ k0;
+ v[3] = 0x7465646279746573ULL ^ k1;
+ count = 0;
+}
+
+CSipHasher& CSipHasher::Write(uint64_t data)
+{
+ uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
+
+ v3 ^= data;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= data;
+
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ v[3] = v3;
+
+ count++;
+ return *this;
+}
+
+uint64_t CSipHasher::Finalize() const
+{
+ uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
+
+ v3 ^= ((uint64_t)count) << 59;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= ((uint64_t)count) << 59;
+ v2 ^= 0xFF;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ return v0 ^ v1 ^ v2 ^ v3;
+}
+
+uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
+{
+ /* Specialized implementation for efficiency */
+ uint64_t d = val.GetUint64(0);
+
+ uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
+ uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
+ uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
+ uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
+
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(1);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(2);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(3);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ v3 ^= ((uint64_t)4) << 59;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= ((uint64_t)4) << 59;
+ v2 ^= 0xFF;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ return v0 ^ v1 ^ v2 ^ v3;
+}
diff --git a/src/hash.h b/src/hash.h
index 97955c8d5a..600dabec56 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -171,4 +171,19 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);
+/** SipHash-2-4, using a uint64_t-based (rather than byte-based) interface */
+class CSipHasher
+{
+private:
+ uint64_t v[4];
+ int count;
+
+public:
+ CSipHasher(uint64_t k0, uint64_t k1);
+ CSipHasher& Write(uint64_t data);
+ uint64_t Finalize() const;
+};
+
+uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
+
#endif // BITCOIN_HASH_H
diff --git a/src/init.cpp b/src/init.cpp
index a46cc52a84..98c0894122 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -123,7 +123,7 @@ static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
// shutdown thing.
//
-volatile bool fRequestShutdown = false;
+volatile sig_atomic_t fRequestShutdown = false;
void StartShutdown()
{
@@ -134,6 +134,11 @@ bool ShutdownRequested()
return fRequestShutdown;
}
+/**
+ * This is a minimally invasive approach to shutdown on LevelDB read errors from the
+ * chainstate, while keeping user interface out of the common library, which is shared
+ * between bitcoind, and bitcoin-qt and non-server tools.
+*/
class CCoinsViewErrorCatcher : public CCoinsViewBacked
{
public:
@@ -327,7 +332,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-prune=<n>", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. "
"Warning: Reverting this setting requires re-downloading the entire blockchain. "
"(default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
- strUsage += HelpMessageOpt("-reindex", _("Rebuild block chain index from current blk000??.dat files on startup"));
+ strUsage += HelpMessageOpt("-reindex-chainstate", _("Rebuild chain state from the currently indexed blocks"));
+ strUsage += HelpMessageOpt("-reindex", _("Rebuild chain state and block index from the blk*.dat files on disk"));
#ifndef WIN32
strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)"));
#endif
@@ -404,7 +410,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT));
strUsage += HelpMessageOpt("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT));
}
- string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune, http, libevent, tor, zmq"; // Don't translate these and qt below
+ string debugCategories = "addrman, alert, bench, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below
if (mode == HMM_BITCOIN_QT)
debugCategories += ", qt";
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
@@ -554,9 +560,10 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
{
const CChainParams& chainparams = Params();
RenameThread("bitcoin-loadblk");
+ CImportingNow imp;
+
// -reindex
if (fReindex) {
- CImportingNow imp;
int nFile = 0;
while (true) {
CDiskBlockPos pos(nFile, 0);
@@ -581,7 +588,6 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
if (boost::filesystem::exists(pathBootstrap)) {
FILE *file = fopen(pathBootstrap.string().c_str(), "rb");
if (file) {
- CImportingNow imp;
boost::filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old";
LogPrintf("Importing bootstrap.dat...\n");
LoadExternalBlockFile(chainparams, file);
@@ -595,7 +601,6 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
BOOST_FOREACH(const boost::filesystem::path& path, vImportFiles) {
FILE *file = fopen(path.string().c_str(), "rb");
if (file) {
- CImportingNow imp;
LogPrintf("Importing blocks file %s...\n", path.string());
LoadExternalBlockFile(chainparams, file);
} else {
@@ -603,6 +608,13 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
}
}
+ // scan for better chains in the block chain database, that are not yet connected in the active best chain
+ CValidationState state;
+ if (!ActivateBestChain(state, chainparams)) {
+ LogPrintf("Failed to connect best block");
+ StartShutdown();
+ }
+
if (GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
LogPrintf("Stopping after block import\n");
StartShutdown();
@@ -1102,6 +1114,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fListen = GetBoolArg("-listen", DEFAULT_LISTEN);
fDiscover = GetBoolArg("-discover", true);
fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
+ fRelayTxes = !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
bool fBound = false;
if (fListen) {
@@ -1158,6 +1171,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 7: load block chain
fReindex = GetBoolArg("-reindex", false);
+ bool fReindexChainState = GetBoolArg("-reindex-chainstate", false);
// Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/
boost::filesystem::path blocksDir = GetDataDir() / "blocks";
@@ -1219,7 +1233,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
delete pblocktree;
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
- pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
+ pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState);
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
@@ -1248,7 +1262,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Check for changed -txindex state
if (fTxIndex != GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
- strLoadError = _("You need to rebuild the database using -reindex to change -txindex");
+ strLoadError = _("You need to rebuild the database using -reindex-chainstate to change -txindex");
break;
}
@@ -1261,8 +1275,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
uiInterface.InitMessage(_("Verifying blocks..."));
if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
- LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n",
- MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", DEFAULT_CHECKBLOCKS));
+ LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks",
+ MIN_BLOCKS_TO_KEEP);
}
{
@@ -1358,12 +1372,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (mapArgs.count("-blocknotify"))
uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);
- uiInterface.InitMessage(_("Activating best chain..."));
- // scan for better chains in the block chain database, that are not yet connected in the active best chain
- CValidationState state;
- if (!ActivateBestChain(state, chainparams))
- strErrors << "Failed to connect best block";
-
std::vector<boost::filesystem::path> vImportFiles;
if (mapArgs.count("-loadblock"))
{
@@ -1371,10 +1379,18 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
vImportFiles.push_back(strFile);
}
threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));
- if (chainActive.Tip() == NULL) {
- LogPrintf("Waiting for genesis block to be imported...\n");
- while (!fRequestShutdown && chainActive.Tip() == NULL)
+
+ // Wait for genesis block to be processed
+ bool fHaveGenesis = false;
+ while (!fHaveGenesis && !fRequestShutdown) {
+ {
+ LOCK(cs_main);
+ fHaveGenesis = (chainActive.Tip() != NULL);
+ }
+
+ if (!fHaveGenesis) {
MilliSleep(10);
+ }
}
// ********************************************************* Step 11: start node
@@ -1385,8 +1401,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (!strErrors.str().empty())
return InitError(strErrors.str());
- RandAddSeedPerfmon();
-
//// debug print
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
LogPrintf("nBestHeight = %d\n", chainActive.Height());
diff --git a/src/key.cpp b/src/key.cpp
index 6a3d9aa140..79023566c3 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -124,9 +124,8 @@ bool CKey::Check(const unsigned char *vch) {
}
void CKey::MakeNewKey(bool fCompressedIn) {
- RandAddSeedPerfmon();
do {
- GetRandBytes(vch, sizeof(vch));
+ GetStrongRandBytes(vch, sizeof(vch));
} while (!Check(vch));
fValid = true;
fCompressed = fCompressedIn;
diff --git a/src/main.cpp b/src/main.cpp
index ee30954b48..f9b8ab37e3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -40,6 +40,7 @@
#include <sstream>
#include <boost/algorithm/string/replace.hpp>
+#include <boost/algorithm/string/join.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/math/distributions/poisson.hpp>
@@ -79,6 +80,10 @@ uint64_t nPruneTarget = 0;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
+std::map<uint256, CTransaction> mapRelay;
+std::deque<std::pair<int64_t, uint256> > vRelayExpiration;
+CCriticalSection cs_mapRelay;
+
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
@@ -1005,7 +1010,7 @@ std::string FormatStateMessage(const CValidationState &state)
}
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree,
- bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
+ bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
std::vector<uint256>& vHashTxnToUncache)
{
const uint256 hash = tx.GetHash();
@@ -1170,9 +1175,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp);
unsigned int nSize = entry.GetTxSize();
- if (txFeeRate) {
- *txFeeRate = CFeeRate(nFees, nSize);
- }
// Check that the transaction doesn't have an excessive number of
// sigops, making it impossible to mine. Since the coinbase transaction
@@ -1421,10 +1423,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
}
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
+ bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
{
std::vector<uint256> vHashTxToUncache;
- bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, txFeeRate, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
+ bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
if (!res) {
BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache)
pcoinsTip->Uncache(hashTx);
@@ -2574,16 +2576,10 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
nTimeBestReceived = GetTime();
mempool.AddTransactionsUpdated(1);
- LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utx)\n", __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()),
- Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
-
cvBlockChange.notify_all();
- // Check the version of the last 100 blocks to see if we need to upgrade:
static bool fWarned = false;
+ std::vector<std::string> warningMessages;
if (!IsInitialBlockDownload())
{
int nUpgraded = 0;
@@ -2599,10 +2595,11 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
fWarned = true;
}
} else {
- LogPrintf("%s: unknown new rules are about to activate (versionbit %i)\n", __func__, bit);
+ warningMessages.push_back(strprintf("unknown new rules are about to activate (versionbit %i)", bit));
}
}
}
+ // Check the version of the last 100 blocks to see if we need to upgrade:
for (int i = 0; i < 100 && pindex != NULL; i++)
{
int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus());
@@ -2611,7 +2608,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
pindex = pindex->pprev;
}
if (nUpgraded > 0)
- LogPrintf("%s: %d of last 100 blocks have unexpected version\n", __func__, nUpgraded);
+ warningMessages.push_back(strprintf("%d of last 100 blocks have unexpected version", nUpgraded));
if (nUpgraded > 100/2)
{
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
@@ -2622,6 +2619,15 @@ 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(%utx)", __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()),
+ Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
+ if (!warningMessages.empty())
+ LogPrintf(" warning='%s'", boost::algorithm::join(warningMessages, ", "));
+ LogPrintf("\n");
+
}
/** Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */
@@ -2651,7 +2657,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
// ignore validation errors in resurrected transactions
list<CTransaction> removed;
CValidationState stateDummy;
- if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, NULL, true)) {
+ if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) {
mempool.removeRecursive(tx, removed);
} else if (mempool.exists(tx.GetHash())) {
vHashUpdate.push_back(tx.GetHash());
@@ -2814,10 +2820,9 @@ static void PruneBlockIndexCandidates() {
* Try to make some progress towards making pindexMostWork the active block.
* pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
*/
-static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock)
+static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound)
{
AssertLockHeld(cs_main);
- bool fInvalidFound = false;
const CBlockIndex *pindexOldTip = chainActive.Tip();
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
@@ -2887,6 +2892,28 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
return true;
}
+static void NotifyHeaderTip() {
+ bool fNotify = false;
+ bool fInitialBlockDownload = false;
+ static CBlockIndex* pindexHeaderOld = NULL;
+ CBlockIndex* pindexHeader = NULL;
+ {
+ LOCK(cs_main);
+ if (!setBlockIndexCandidates.empty()) {
+ pindexHeader = *setBlockIndexCandidates.rbegin();
+ }
+ if (pindexHeader != pindexHeaderOld) {
+ fNotify = true;
+ fInitialBlockDownload = IsInitialBlockDownload();
+ pindexHeaderOld = pindexHeader;
+ }
+ }
+ // Send block tip changed notifications without cs_main
+ if (fNotify) {
+ uiInterface.NotifyHeaderTip(fInitialBlockDownload, pindexHeader);
+ }
+}
+
/**
* Make the best chain active, in multiple steps. The result is either failure
* or an activated best chain. pblock is either NULL or a pointer to a block
@@ -2905,15 +2932,22 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
{
LOCK(cs_main);
CBlockIndex *pindexOldTip = chainActive.Tip();
- pindexMostWork = FindMostWorkChain();
+ if (pindexMostWork == NULL) {
+ pindexMostWork = FindMostWorkChain();
+ }
// Whether we have anything to do at all.
if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip())
return true;
- if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL))
+ bool fInvalidFound = false;
+ if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL, fInvalidFound))
return false;
+ if (fInvalidFound) {
+ // Wipe cache, we may need another branch now.
+ pindexMostWork = NULL;
+ }
pindexNewTip = chainActive.Tip();
pindexFork = chainActive.FindFork(pindexOldTip);
fInitialDownload = IsInitialBlockDownload();
@@ -3401,11 +3435,12 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
}
/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
-static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp)
+static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp)
{
AssertLockHeld(cs_main);
- CBlockIndex *&pindex = *ppindex;
+ CBlockIndex *pindexDummy = NULL;
+ CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy;
if (!AcceptBlockHeader(block, state, chainparams, &pindex))
return false;
@@ -3477,7 +3512,7 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned
}
-bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp)
+bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp)
{
{
LOCK(cs_main);
@@ -3495,6 +3530,8 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c
return error("%s: AcceptBlock FAILED", __func__);
}
+ NotifyHeaderTip();
+
if (!ActivateBestChain(state, chainparams, pblock))
return error("%s: ActivateBestChain failed", __func__);
@@ -3843,6 +3880,11 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))));
if (pindex->nHeight < chainActive.Height()-nCheckDepth)
break;
+ if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
+ // If pruning, only go back as far as we have data.
+ LogPrintf("VerifyDB(): block verification stopping at height %d (pruning, no data)\n", pindex->nHeight);
+ break;
+ }
CBlock block;
// check level 0: read from disk
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
@@ -4040,15 +4082,26 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
// process in case the block isn't known yet
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
+ LOCK(cs_main);
CValidationState state;
- if (ProcessNewBlock(state, chainparams, NULL, &block, true, dbp))
+ if (AcceptBlock(block, state, chainparams, NULL, true, dbp))
nLoaded++;
if (state.IsError())
break;
} else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) {
- LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight);
+ LogPrint("reindex", "Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight);
}
+ // Activate the genesis block so normal node progress can continue
+ if (hash == chainparams.GetConsensus().hashGenesisBlock) {
+ CValidationState state;
+ if (!ActivateBestChain(state, chainparams)) {
+ break;
+ }
+ }
+
+ NotifyHeaderTip();
+
// Recursively process earlier encountered successors of this block
deque<uint256> queue;
queue.push_back(hash);
@@ -4060,10 +4113,11 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
std::multimap<uint256, CDiskBlockPos>::iterator it = range.first;
if (ReadBlockFromDisk(block, it->second, chainparams.GetConsensus()))
{
- LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(),
+ LogPrint("reindex", "%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(),
head.ToString());
+ LOCK(cs_main);
CValidationState dummy;
- if (ProcessNewBlock(dummy, chainparams, NULL, &block, true, &it->second))
+ if (AcceptBlock(block, dummy, chainparams, NULL, true, &it->second))
{
nLoaded++;
queue.push_back(block.GetHash());
@@ -4071,6 +4125,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
}
range.first++;
mapBlocksUnknownParent.erase(it);
+ NotifyHeaderTip();
}
}
} catch (const std::exception& e) {
@@ -4450,24 +4505,28 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
else if (inv.IsKnownType())
{
+ CTransaction tx;
// Send stream from relay memory
- bool pushed = false;
+ bool push = false;
{
LOCK(cs_mapRelay);
map<uint256, CTransaction>::iterator mi = mapRelay.find(inv.hash);
if (mi != mapRelay.end()) {
- pfrom->PushMessage(inv.GetCommand(), (*mi).second);
- pushed = true;
+ tx = (*mi).second;
+ push = true;
}
}
- if (!pushed && inv.type == MSG_TX) {
- CTransaction tx;
- if (mempool.lookup(inv.hash, tx)) {
- pfrom->PushMessage(NetMsgType::TX, tx);
- pushed = true;
+ if (!push && inv.type == MSG_TX) {
+ int64_t txtime;
+ // To protect privacy, do not answer getdata using the mempool when
+ // that TX couldn't have been INVed in reply to a MEMPOOL request.
+ if (mempool.lookup(inv.hash, tx, txtime) && txtime <= pfrom->timeLastMempoolReq) {
+ push = true;
}
}
- if (!pushed) {
+ if (push) {
+ pfrom->PushMessage(inv.GetCommand(), tx);
+ } else {
vNotFound.push_back(inv);
}
}
@@ -4496,7 +4555,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams)
{
- RandAddSeedPerfmon();
LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
@@ -4701,25 +4759,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LOCK(cs_vNodes);
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the addrKnowns of the chosen nodes prevent repeats
- static uint256 hashSalt;
- if (hashSalt.IsNull())
- hashSalt = GetRandHash();
+ static uint64_t salt0 = 0, salt1 = 0;
+ while (salt0 == 0 && salt1 == 0) {
+ GetRandBytes((unsigned char*)&salt0, sizeof(salt0));
+ GetRandBytes((unsigned char*)&salt1, sizeof(salt1));
+ }
uint64_t hashAddr = addr.GetHash();
- uint256 hashRand = ArithToUint256(UintToArith256(hashSalt) ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60)));
- hashRand = Hash(BEGIN(hashRand), END(hashRand));
- multimap<uint256, CNode*> mapMix;
+ multimap<uint64_t, CNode*> mapMix;
+ const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
BOOST_FOREACH(CNode* pnode, vNodes)
{
if (pnode->nVersion < CADDR_TIME_VERSION)
continue;
- unsigned int nPointer;
- memcpy(&nPointer, &pnode, sizeof(nPointer));
- uint256 hashKey = ArithToUint256(UintToArith256(hashRand) ^ nPointer);
- hashKey = Hash(BEGIN(hashKey), END(hashKey));
+ uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize();
mapMix.insert(make_pair(hashKey, pnode));
}
int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
- for (multimap<uint256, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
+ for (multimap<uint64_t, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
((*mi).second)->PushAddress(addr);
}
}
@@ -4751,7 +4807,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return error("message inv size() = %u", vInv.size());
}
- bool fBlocksOnly = GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
+ bool fBlocksOnly = !fRelayTxes;
// Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true
if (pfrom->fWhitelisted && GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))
@@ -4934,7 +4990,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
{
// Stop processing the transaction early if
// We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
- if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && (!pfrom->fWhitelisted || !GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
+ if (!fRelayTxes && (!pfrom->fWhitelisted || !GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
{
LogPrint("net", "transaction sent in violation of protocol peer=%d\n", pfrom->id);
return true;
@@ -4956,10 +5012,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->setAskFor.erase(inv.hash);
mapAlreadyAskedFor.erase(inv.hash);
- CFeeRate txFeeRate = CFeeRate(0);
- if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, &txFeeRate)) {
+ if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) {
mempool.check(pcoinsTip);
- RelayTransaction(tx, txFeeRate);
+ RelayTransaction(tx);
vWorkQueue.push_back(inv.hash);
LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
@@ -4990,10 +5045,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (setMisbehaving.count(fromPeer))
continue;
- CFeeRate orphanFeeRate = CFeeRate(0);
- if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2, &orphanFeeRate)) {
+ if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) {
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
- RelayTransaction(orphanTx, orphanFeeRate);
+ RelayTransaction(orphanTx);
vWorkQueue.push_back(orphanHash);
vEraseQueue.push_back(orphanHash);
}
@@ -5046,7 +5100,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS = 0;
if (!state.IsInvalid(nDoS) || nDoS == 0) {
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
- RelayTransaction(tx, txFeeRate);
+ RelayTransaction(tx);
} else {
LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
}
@@ -5084,6 +5138,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
}
+ {
LOCK(cs_main);
if (nCount == 0) {
@@ -5091,6 +5146,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return true;
}
+ // If we already know the last header in the message, then it contains
+ // no new information for us. In this case, we do not request
+ // more headers later. This prevents multiple chains of redundant
+ // getheader requests from running in parallel if triggered by incoming
+ // blocks while the node is still in initial headers sync.
+ const bool hasNewHeaders = (mapBlockIndex.count(headers.back().GetHash()) == 0);
+
CBlockIndex *pindexLast = NULL;
BOOST_FOREACH(const CBlockHeader& header, headers) {
CValidationState state;
@@ -5111,7 +5173,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (pindexLast)
UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash());
- if (nCount == MAX_HEADERS_RESULTS && pindexLast) {
+ if (nCount == MAX_HEADERS_RESULTS && pindexLast && hasNewHeaders) {
// Headers message had its maximum size; the peer may have more headers.
// TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
// from there instead.
@@ -5167,6 +5229,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
CheckBlockIndex(chainparams.GetConsensus());
+ }
+
+ NotifyHeaderTip();
}
else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
@@ -5854,6 +5919,7 @@ bool SendMessages(CNode* pto)
vInv.clear();
}
}
+ pto->timeLastMempoolReq = GetTime();
}
// Determine transactions to relay
@@ -5897,14 +5963,26 @@ bool SendMessages(CNode* pto)
if (filterrate && feeRate.GetFeePerK() < filterrate) {
continue;
}
- if (pto->pfilter) {
- CTransaction tx;
- if (!mempool.lookup(hash, tx)) continue;
- if (!pto->pfilter->IsRelevantAndUpdate(tx)) continue;
- }
+ CTransaction tx;
+ if (!mempool.lookup(hash, tx)) continue;
+ if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(tx)) continue;
// Send
vInv.push_back(CInv(MSG_TX, hash));
nRelayedTransactions++;
+ {
+ LOCK(cs_mapRelay);
+ // Expire old relay messages
+ while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
+ {
+ mapRelay.erase(vRelayExpiration.front().second);
+ vRelayExpiration.pop_front();
+ }
+
+ auto ret = mapRelay.insert(std::make_pair(hash, tx));
+ if (ret.second) {
+ vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, hash));
+ }
+ }
if (vInv.size() == MAX_INV_SZ) {
pto->PushMessage(NetMsgType::INV, vInv);
vInv.clear();
diff --git a/src/main.h b/src/main.h
index 548218a1b5..f287171f14 100644
--- a/src/main.h
+++ b/src/main.h
@@ -212,10 +212,10 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
* @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
* @param[in] pblock The block we want to process.
* @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers.
- * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location.
+ * @param[out] dbp The already known disk position of pblock, or NULL if not yet stored.
* @return True if state.IsValid()
*/
-bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp);
+bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
@@ -295,7 +295,7 @@ void PruneAndFlush();
/** (try to) add transaction to memory pool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
+ bool* pfMissingInputs, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state);
diff --git a/src/net.cpp b/src/net.cpp
index 5e810a0f15..c09e3aedb6 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -56,7 +56,6 @@
#endif
#endif
-using namespace std;
namespace {
const int MAX_OUTBOUND_CONNECTIONS = 8;
@@ -77,8 +76,9 @@ const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
bool fDiscover = true;
bool fListen = true;
uint64_t nLocalServices = NODE_NETWORK;
+bool fRelayTxes = true;
CCriticalSection cs_mapLocalHost;
-map<CNetAddr, LocalServiceInfo> mapLocalHost;
+std::map<CNetAddr, LocalServiceInfo> mapLocalHost;
static bool vfLimited[NET_MAX] = {};
static CNode* pnodeLocalHost = NULL;
uint64_t nLocalHostNonce = 0;
@@ -88,20 +88,14 @@ int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS;
bool fAddressesInitialized = false;
std::string strSubVersion;
-vector<CNode*> vNodes;
+std::vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
-map<uint256, CTransaction> mapRelay;
-deque<pair<int64_t, uint256> > vRelayExpiration;
-CCriticalSection cs_mapRelay;
limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
-static deque<string> vOneShots;
+static std::deque<std::string> vOneShots;
CCriticalSection cs_vOneShots;
-set<CNetAddr> setservAddNodeAddresses;
-CCriticalSection cs_setservAddNodeAddresses;
-
-vector<std::string> vAddedNodes;
+std::vector<std::string> vAddedNodes;
CCriticalSection cs_vAddedNodes;
NodeId nLastNodeId = 0;
@@ -135,7 +129,7 @@ bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
int nBestReachability = -1;
{
LOCK(cs_mapLocalHost);
- for (map<CNetAddr, LocalServiceInfo>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
+ for (std::map<CNetAddr, LocalServiceInfo>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
{
int nScore = (*it).second.nScore;
int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
@@ -426,6 +420,26 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
return NULL;
}
+static void DumpBanlist()
+{
+ CNode::SweepBanned(); // clean unused entries (if bantime has expired)
+
+ if (!CNode::BannedSetIsDirty())
+ return;
+
+ int64_t nStart = GetTimeMillis();
+
+ CBanDB bandb;
+ banmap_t banmap;
+ CNode::SetBannedSetDirty(false);
+ CNode::GetBanned(banmap);
+ if (!bandb.Write(banmap))
+ CNode::SetBannedSetDirty(true);
+
+ LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
+ banmap.size(), GetTimeMillis() - nStart);
+}
+
void CNode::CloseSocketDisconnect()
{
fDisconnect = true;
@@ -443,7 +457,7 @@ void CNode::CloseSocketDisconnect()
void CNode::PushVersion()
{
- int nBestHeight = g_signals.GetHeight().get_value_or(0);
+ int nBestHeight = GetNodeSignals().GetHeight().get_value_or(0);
int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime());
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
@@ -454,7 +468,7 @@ void CNode::PushVersion()
else
LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
- nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY));
+ nLocalHostNonce, strSubVersion, nBestHeight, ::fRelayTxes);
}
@@ -467,9 +481,13 @@ bool CNode::setBannedIsDirty;
void CNode::ClearBanned()
{
- LOCK(cs_setBanned);
- setBanned.clear();
- setBannedIsDirty = true;
+ {
+ LOCK(cs_setBanned);
+ setBanned.clear();
+ setBannedIsDirty = true;
+ }
+ DumpBanlist(); //store banlist to disk
+ uiInterface.BannedListChanged();
}
bool CNode::IsBanned(CNetAddr ip)
@@ -520,11 +538,25 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti
}
banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;
- LOCK(cs_setBanned);
- if (setBanned[subNet].nBanUntil < banEntry.nBanUntil)
- setBanned[subNet] = banEntry;
-
- setBannedIsDirty = true;
+ {
+ LOCK(cs_setBanned);
+ if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) {
+ setBanned[subNet] = banEntry;
+ setBannedIsDirty = true;
+ }
+ else
+ return;
+ }
+ uiInterface.BannedListChanged();
+ {
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pnode, vNodes) {
+ if (subNet.Match((CNetAddr)pnode->addr))
+ pnode->fDisconnect = true;
+ }
+ }
+ if(banReason == BanReasonManuallyAdded)
+ DumpBanlist(); //store banlist to disk immediately if user requested ban
}
bool CNode::Unban(const CNetAddr &addr) {
@@ -533,13 +565,15 @@ bool CNode::Unban(const CNetAddr &addr) {
}
bool CNode::Unban(const CSubNet &subNet) {
- LOCK(cs_setBanned);
- if (setBanned.erase(subNet))
{
+ LOCK(cs_setBanned);
+ if (!setBanned.erase(subNet))
+ return false;
setBannedIsDirty = true;
- return true;
}
- return false;
+ uiInterface.BannedListChanged();
+ DumpBanlist(); //store banlist to disk immediately
+ return true;
}
void CNode::GetBanned(banmap_t &banMap)
@@ -796,53 +830,24 @@ void SocketSendData(CNode *pnode)
pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it);
}
-static list<CNode*> vNodesDisconnected;
+static std::list<CNode*> vNodesDisconnected;
-class CNodeRef {
-public:
- CNodeRef(CNode *pnode) : _pnode(pnode) {
- LOCK(cs_vNodes);
- _pnode->AddRef();
- }
-
- ~CNodeRef() {
- LOCK(cs_vNodes);
- _pnode->Release();
- }
-
- CNode& operator *() const {return *_pnode;};
- CNode* operator ->() const {return _pnode;};
-
- CNodeRef& operator =(const CNodeRef& other)
- {
- if (this != &other) {
- LOCK(cs_vNodes);
-
- _pnode->Release();
- _pnode = other._pnode;
- _pnode->AddRef();
- }
- return *this;
- }
-
- CNodeRef(const CNodeRef& other):
- _pnode(other._pnode)
- {
- LOCK(cs_vNodes);
- _pnode->AddRef();
- }
-private:
- CNode *_pnode;
+struct NodeEvictionCandidate
+{
+ NodeId id;
+ int64_t nTimeConnected;
+ int64_t nMinPingUsecTime;
+ CAddress addr;
};
-static bool ReverseCompareNodeMinPingTime(const CNodeRef &a, const CNodeRef &b)
+static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
{
- return a->nMinPingUsecTime > b->nMinPingUsecTime;
+ return a.nMinPingUsecTime > b.nMinPingUsecTime;
}
-static bool ReverseCompareNodeTimeConnected(const CNodeRef &a, const CNodeRef &b)
+static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
{
- return a->nTimeConnected > b->nTimeConnected;
+ return a.nTimeConnected > b.nTimeConnected;
}
class CompareNetGroupKeyed
@@ -855,14 +860,14 @@ public:
GetRandBytes(vchSecretKey.data(), vchSecretKey.size());
}
- bool operator()(const CNodeRef &a, const CNodeRef &b)
+ bool operator()(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
{
std::vector<unsigned char> vchGroupA, vchGroupB;
CSHA256 hashA, hashB;
std::vector<unsigned char> vchA(32), vchB(32);
- vchGroupA = a->addr.GetGroup();
- vchGroupB = b->addr.GetGroup();
+ vchGroupA = a.addr.GetGroup();
+ vchGroupB = b.addr.GetGroup();
hashA.Write(begin_ptr(vchGroupA), vchGroupA.size());
hashB.Write(begin_ptr(vchGroupB), vchGroupB.size());
@@ -886,7 +891,7 @@ public:
* simultaneously better at all of them than honest peers.
*/
static bool AttemptToEvictConnection(bool fPreferNewConnection) {
- std::vector<CNodeRef> vEvictionCandidates;
+ std::vector<NodeEvictionCandidate> vEvictionCandidates;
{
LOCK(cs_vNodes);
@@ -897,7 +902,8 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
continue;
if (node->fDisconnect)
continue;
- vEvictionCandidates.push_back(CNodeRef(node));
+ NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr};
+ vEvictionCandidates.push_back(candidate);
}
}
@@ -932,16 +938,16 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
std::vector<unsigned char> naMostConnections;
unsigned int nMostConnections = 0;
int64_t nMostConnectionsTime = 0;
- std::map<std::vector<unsigned char>, std::vector<CNodeRef> > mapAddrCounts;
- BOOST_FOREACH(const CNodeRef &node, vEvictionCandidates) {
- mapAddrCounts[node->addr.GetGroup()].push_back(node);
- int64_t grouptime = mapAddrCounts[node->addr.GetGroup()][0]->nTimeConnected;
- size_t groupsize = mapAddrCounts[node->addr.GetGroup()].size();
+ std::map<std::vector<unsigned char>, std::vector<NodeEvictionCandidate> > mapAddrCounts;
+ BOOST_FOREACH(const NodeEvictionCandidate &node, vEvictionCandidates) {
+ mapAddrCounts[node.addr.GetGroup()].push_back(node);
+ int64_t grouptime = mapAddrCounts[node.addr.GetGroup()][0].nTimeConnected;
+ size_t groupsize = mapAddrCounts[node.addr.GetGroup()].size();
if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) {
nMostConnections = groupsize;
nMostConnectionsTime = grouptime;
- naMostConnections = node->addr.GetGroup();
+ naMostConnections = node.addr.GetGroup();
}
}
@@ -956,9 +962,15 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
return false;
// Disconnect from the network group with the most connections
- vEvictionCandidates[0]->fDisconnect = true;
-
- return true;
+ NodeId evicted = vEvictionCandidates.front().id;
+ LOCK(cs_vNodes);
+ for(std::vector<CNode*>::const_iterator it(vNodes.begin()); it != vNodes.end(); ++it) {
+ if ((*it)->GetId() == evicted) {
+ (*it)->fDisconnect = true;
+ return true;
+ }
+ }
+ return false;
}
static void AcceptConnection(const ListenSocket& hListenSocket) {
@@ -1045,7 +1057,7 @@ void ThreadSocketHandler()
{
LOCK(cs_vNodes);
// Disconnect unused nodes
- vector<CNode*> vNodesCopy = vNodes;
+ std::vector<CNode*> vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
if (pnode->fDisconnect ||
@@ -1069,7 +1081,7 @@ void ThreadSocketHandler()
}
{
// Delete disconnected nodes
- list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
+ std::list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy)
{
// wait until threads are done using it
@@ -1120,7 +1132,7 @@ void ThreadSocketHandler()
BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket) {
FD_SET(hListenSocket.socket, &fdsetRecv);
- hSocketMax = max(hSocketMax, hListenSocket.socket);
+ hSocketMax = std::max(hSocketMax, hListenSocket.socket);
have_fds = true;
}
@@ -1131,7 +1143,7 @@ void ThreadSocketHandler()
if (pnode->hSocket == INVALID_SOCKET)
continue;
FD_SET(pnode->hSocket, &fdsetError);
- hSocketMax = max(hSocketMax, pnode->hSocket);
+ hSocketMax = std::max(hSocketMax, pnode->hSocket);
have_fds = true;
// Implement the following logic:
@@ -1198,7 +1210,7 @@ void ThreadSocketHandler()
//
// Service each socket
//
- vector<CNode*> vNodesCopy;
+ std::vector<CNode*> vNodesCopy;
{
LOCK(cs_vNodes);
vNodesCopy = vNodes;
@@ -1355,7 +1367,7 @@ void ThreadMapPort()
}
}
- string strDesc = "Bitcoin " + FormatFullVersion();
+ std::string strDesc = "Bitcoin " + FormatFullVersion();
try {
while (true) {
@@ -1441,7 +1453,7 @@ void ThreadDNSAddressSeed()
}
}
- const vector<CDNSSeedData> &vSeeds = Params().DNSSeeds();
+ const std::vector<CDNSSeedData> &vSeeds = Params().DNSSeeds();
int found = 0;
LogPrintf("Loading addresses from DNS seeds (could take a while)\n");
@@ -1450,8 +1462,8 @@ void ThreadDNSAddressSeed()
if (HaveNameProxy()) {
AddOneShot(seed.host);
} else {
- vector<CNetAddr> vIPs;
- vector<CAddress> vAdd;
+ std::vector<CNetAddr> vIPs;
+ std::vector<CAddress> vAdd;
if (LookupHost(seed.host.c_str(), vIPs, 0, true))
{
BOOST_FOREACH(const CNetAddr& ip, vIPs)
@@ -1508,7 +1520,7 @@ void DumpData()
void static ProcessOneShot()
{
- string strDest;
+ std::string strDest;
{
LOCK(cs_vOneShots);
if (vOneShots.empty())
@@ -1574,7 +1586,7 @@ void ThreadOpenConnections()
// Only connect out to one peer per network group (/16 for IPv4).
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
int nOutbound = 0;
- set<vector<unsigned char> > setConnected;
+ std::set<std::vector<unsigned char> > setConnected;
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes) {
@@ -1632,7 +1644,7 @@ void ThreadOpenAddedConnections()
if (HaveNameProxy()) {
while(true) {
- list<string> lAddresses(0);
+ std::list<std::string> lAddresses(0);
{
LOCK(cs_vAddedNodes);
BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
@@ -1650,32 +1662,25 @@ void ThreadOpenAddedConnections()
for (unsigned int i = 0; true; i++)
{
- list<string> lAddresses(0);
+ std::list<std::string> lAddresses(0);
{
LOCK(cs_vAddedNodes);
BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
lAddresses.push_back(strAddNode);
}
- list<vector<CService> > lservAddressesToAdd(0);
+ std::list<std::vector<CService> > lservAddressesToAdd(0);
BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
- vector<CService> vservNode(0);
+ std::vector<CService> vservNode(0);
if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
- {
lservAddressesToAdd.push_back(vservNode);
- {
- LOCK(cs_setservAddNodeAddresses);
- BOOST_FOREACH(const CService& serv, vservNode)
- setservAddNodeAddresses.insert(serv);
- }
- }
}
// Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
// (keeping in mind that addnode entries can have many IPs if fNameLookup)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
- for (list<vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
+ for (std::list<std::vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
BOOST_FOREACH(const CService& addrNode, *(it))
if (pnode->addr == addrNode)
{
@@ -1684,7 +1689,7 @@ void ThreadOpenAddedConnections()
break;
}
}
- BOOST_FOREACH(vector<CService>& vserv, lservAddressesToAdd)
+ BOOST_FOREACH(std::vector<CService>& vserv, lservAddressesToAdd)
{
CSemaphoreGrant grant(*semOutbound);
OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant);
@@ -1731,7 +1736,7 @@ void ThreadMessageHandler()
while (true)
{
- vector<CNode*> vNodesCopy;
+ std::vector<CNode*> vNodesCopy;
{
LOCK(cs_vNodes);
vNodesCopy = vNodes;
@@ -1752,7 +1757,7 @@ void ThreadMessageHandler()
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
if (lockRecv)
{
- if (!g_signals.ProcessMessages(pnode))
+ if (!GetNodeSignals().ProcessMessages(pnode))
pnode->CloseSocketDisconnect();
if (pnode->nSendSize < SendBufferSize())
@@ -1770,7 +1775,7 @@ void ThreadMessageHandler()
{
TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend)
- g_signals.SendMessages(pnode);
+ GetNodeSignals().SendMessages(pnode);
}
boost::this_thread::interruption_point();
}
@@ -1791,7 +1796,7 @@ void ThreadMessageHandler()
-bool BindListenPort(const CService &addrBind, string& strError, bool fWhitelisted)
+bool BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted)
{
strError = "";
int nOne = 1;
@@ -1899,7 +1904,7 @@ void static Discover(boost::thread_group& threadGroup)
char pszHostName[256] = "";
if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
{
- vector<CNetAddr> vaddr;
+ std::vector<CNetAddr> vaddr;
if (LookupHost(pszHostName, vaddr, 0, true))
{
BOOST_FOREACH (const CNetAddr &addr, vaddr)
@@ -1950,6 +1955,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if (adb.Read(addrman))
LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart);
else {
+ addrman.Clear(); // Addrman can be in an inconsistent state after failure, reset it
LogPrintf("Invalid or missing peers.dat; recreating\n");
DumpAddresses();
}
@@ -2069,21 +2075,9 @@ public:
instance_of_cnetcleanup;
-void RelayTransaction(const CTransaction& tx, CFeeRate feerate)
+void RelayTransaction(const CTransaction& tx)
{
CInv inv(MSG_TX, tx.GetHash());
- {
- LOCK(cs_mapRelay);
- // Expire old relay messages
- while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
- {
- mapRelay.erase(vRelayExpiration.front().second);
- vRelayExpiration.pop_front();
- }
-
- mapRelay.insert(std::make_pair(inv.hash, tx));
- vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv.hash));
- }
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
@@ -2299,7 +2293,7 @@ bool CAddrDB::Read(CAddrMan& addr)
// Don't try to resize to a negative number if file is small
if (fileSize >= sizeof(uint256))
dataSize = fileSize - sizeof(uint256);
- vector<unsigned char> vchData;
+ std::vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
@@ -2320,6 +2314,11 @@ bool CAddrDB::Read(CAddrMan& addr)
if (hashIn != hashTmp)
return error("%s: Checksum mismatch, data corrupted", __func__);
+ return Read(addr, ssPeers);
+}
+
+bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers)
+{
unsigned char pchMsgTmp[4];
try {
// de-serialize file header (network specific magic number) and ..
@@ -2333,6 +2332,8 @@ bool CAddrDB::Read(CAddrMan& addr)
ssPeers >> addr;
}
catch (const std::exception& e) {
+ // de-serialization has failed, ensure addrman is left in a clean state
+ addr.Clear();
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
@@ -2381,6 +2382,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
fRelayTxes = false;
fSentAddr = false;
pfilter = new CBloomFilter();
+ timeLastMempoolReq = 0;
nPingNonceSent = 0;
nPingUsecStart = 0;
nPingUsecTime = 0;
@@ -2579,7 +2581,7 @@ bool CBanDB::Read(banmap_t& banSet)
// Don't try to resize to a negative number if file is small
if (fileSize >= sizeof(uint256))
dataSize = fileSize - sizeof(uint256);
- vector<unsigned char> vchData;
+ std::vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
@@ -2619,26 +2621,6 @@ bool CBanDB::Read(banmap_t& banSet)
return true;
}
-void DumpBanlist()
-{
- CNode::SweepBanned(); // clean unused entries (if bantime has expired)
-
- if (!CNode::BannedSetIsDirty())
- return;
-
- int64_t nStart = GetTimeMillis();
-
- CBanDB bandb;
- banmap_t banmap;
- CNode::SetBannedSetDirty(false);
- CNode::GetBanned(banmap);
- if (!bandb.Write(banmap))
- CNode::SetBannedSetDirty(true);
-
- LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
- banmap.size(), GetTimeMillis() - nStart);
-}
-
int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) {
return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);
}
diff --git a/src/net.h b/src/net.h
index b6ec7bf3e2..403653e8c8 100644
--- a/src/net.h
+++ b/src/net.h
@@ -17,6 +17,7 @@
#include "sync.h"
#include "uint256.h"
+#include <atomic>
#include <deque>
#include <stdint.h>
@@ -83,7 +84,6 @@ CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip);
-CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL);
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
@@ -153,6 +153,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
extern bool fDiscover;
extern bool fListen;
extern uint64_t nLocalServices;
+extern bool fRelayTxes;
extern uint64_t nLocalHostNonce;
extern CAddrMan addrman;
@@ -161,9 +162,6 @@ extern int nMaxConnections;
extern std::vector<CNode*> vNodes;
extern CCriticalSection cs_vNodes;
-extern std::map<uint256, CTransaction> mapRelay;
-extern std::deque<std::pair<int64_t, uint256> > vRelayExpiration;
-extern CCriticalSection cs_mapRelay;
extern limitedmap<uint256, int64_t> mapAlreadyAskedFor;
extern std::vector<std::string> vAddedNodes;
@@ -414,6 +412,8 @@ public:
// Used for BIP35 mempool sending, also protected by cs_inventory
bool fSendMempool;
+ // Last time a "MEMPOOL" request was serviced.
+ std::atomic<int64_t> timeLastMempoolReq;
// Ping time measurement:
// The pong reply we're expecting, or 0 if no pong expected.
uint64_t nPingNonceSent;
@@ -783,7 +783,7 @@ public:
class CTransaction;
-void RelayTransaction(const CTransaction& tx, CFeeRate feerate);
+void RelayTransaction(const CTransaction& tx);
/** Access to the (IP) address database (peers.dat) */
class CAddrDB
@@ -794,6 +794,7 @@ public:
CAddrDB();
bool Write(const CAddrMan& addr);
bool Read(CAddrMan& addr);
+ bool Read(CAddrMan& addr, CDataStream& ssPeers);
};
/** Access to the banlist database (banlist.dat) */
@@ -807,8 +808,6 @@ public:
bool Read(banmap_t& banSet);
};
-void DumpBanlist();
-
/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */
int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds);
diff --git a/src/netbase.cpp b/src/netbase.cpp
index b44a8b16e2..572ae70871 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -291,10 +291,25 @@ struct ProxyCredentials
std::string password;
};
+std::string Socks5ErrorString(int err)
+{
+ switch(err) {
+ case 0x01: return "general failure";
+ case 0x02: return "connection not allowed";
+ case 0x03: return "network unreachable";
+ case 0x04: return "host unreachable";
+ case 0x05: return "connection refused";
+ case 0x06: return "TTL expired";
+ case 0x07: return "protocol error";
+ case 0x08: return "address type not supported";
+ default: return "unknown";
+ }
+}
+
/** Connect using SOCKS5 (as described in RFC1928) */
static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)
{
- LogPrintf("SOCKS5 connecting %s\n", strDest);
+ LogPrint("net", "SOCKS5 connecting %s\n", strDest);
if (strDest.size() > 255) {
CloseSocket(hSocket);
return error("Hostname too long");
@@ -318,7 +333,8 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
char pchRet1[2];
if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) {
CloseSocket(hSocket);
- return error("Error reading proxy response");
+ LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
+ return false;
}
if (pchRet1[0] != 0x05) {
CloseSocket(hSocket);
@@ -379,19 +395,10 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
return error("Proxy failed to accept request");
}
if (pchRet2[1] != 0x00) {
+ // Failures to connect to a peer that are not proxy errors
CloseSocket(hSocket);
- switch (pchRet2[1])
- {
- case 0x01: return error("Proxy error: general failure");
- case 0x02: return error("Proxy error: connection not allowed");
- case 0x03: return error("Proxy error: network unreachable");
- case 0x04: return error("Proxy error: host unreachable");
- case 0x05: return error("Proxy error: connection refused");
- case 0x06: return error("Proxy error: TTL expired");
- case 0x07: return error("Proxy error: protocol error");
- case 0x08: return error("Proxy error: address type not supported");
- default: return error("Proxy error: unknown");
- }
+ LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1]));
+ return false;
}
if (pchRet2[2] != 0x00) {
CloseSocket(hSocket);
@@ -423,7 +430,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
CloseSocket(hSocket);
return error("Error reading from proxy");
}
- LogPrintf("SOCKS5 connected %s\n", strDest);
+ LogPrint("net", "SOCKS5 connected %s\n", strDest);
return true;
}
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index 415bffb991..e8aa79679c 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -77,10 +77,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
AskPassphraseDialog::~AskPassphraseDialog()
{
- // Attempt to overwrite text so that they do not linger around in memory
- ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
- ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
- ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
+ secureClearPassFields();
delete ui;
}
@@ -103,6 +100,8 @@ void AskPassphraseDialog::accept()
newpass1.assign(ui->passEdit2->text().toStdString().c_str());
newpass2.assign(ui->passEdit3->text().toStdString().c_str());
+ secureClearPassFields();
+
switch(mode)
{
case Encrypt: {
@@ -260,3 +259,17 @@ bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event)
}
return QDialog::eventFilter(object, event);
}
+
+static void SecureClearQLineEdit(QLineEdit* edit)
+{
+ // Attempt to overwrite text so that they do not linger around in memory
+ edit->setText(QString(" ").repeated(edit->text().size()));
+ edit->clear();
+}
+
+void AskPassphraseDialog::secureClearPassFields()
+{
+ SecureClearQLineEdit(ui->passEdit1);
+ SecureClearQLineEdit(ui->passEdit2);
+ SecureClearQLineEdit(ui->passEdit3);
+}
diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h
index 727b5a1ada..34bf7ccb31 100644
--- a/src/qt/askpassphrasedialog.h
+++ b/src/qt/askpassphrasedialog.h
@@ -42,6 +42,7 @@ private:
private Q_SLOTS:
void textChanged();
+ void secureClearPassFields();
protected:
bool event(QEvent *event);
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 9c21bb24ce..6218ab6ab0 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -370,6 +370,7 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
splash->setAttribute(Qt::WA_DeleteOnClose);
splash->show();
connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*)));
+ connect(this, SIGNAL(requestedShutdown()), splash, SLOT(close()));
}
void BitcoinApplication::startThread()
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index b00cdfcaf2..50c19c3848 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -320,12 +320,14 @@ void BitcoinGUI::createActions()
aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About %1").arg(tr(PACKAGE_NAME)), this);
aboutAction->setStatusTip(tr("Show information about %1").arg(tr(PACKAGE_NAME)));
aboutAction->setMenuRole(QAction::AboutRole);
+ aboutAction->setEnabled(false);
aboutQtAction = new QAction(platformStyle->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
aboutQtAction->setStatusTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
optionsAction = new QAction(platformStyle->TextColorIcon(":/icons/options"), tr("&Options..."), this);
optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(tr(PACKAGE_NAME)));
optionsAction->setMenuRole(QAction::PreferencesRole);
+ optionsAction->setEnabled(false);
toggleHideAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
@@ -343,6 +345,8 @@ void BitcoinGUI::createActions()
openRPCConsoleAction = new QAction(platformStyle->TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this);
openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
+ // initially disable the debug window menu item
+ openRPCConsoleAction->setEnabled(false);
usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
@@ -457,8 +461,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
setNumConnections(clientModel->getNumConnections());
connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
- setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate(), clientModel->getVerificationProgress(NULL));
- connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(setNumBlocks(int,QDateTime,double)));
+ setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate(), clientModel->getVerificationProgress(NULL), false);
+ connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
// Receive and report messages from client model
connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
@@ -474,6 +478,16 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
}
#endif // ENABLE_WALLET
unitDisplayControl->setOptionsModel(clientModel->getOptionsModel());
+
+ OptionsModel* optionsModel = clientModel->getOptionsModel();
+ if(optionsModel)
+ {
+ // be aware of the tray icon disable state change reported by the OptionsModel object.
+ connect(optionsModel,SIGNAL(hideTrayIconChanged(bool)),this,SLOT(setTrayIconVisible(bool)));
+
+ // initialize the disable state of the tray icon with the current value in the model.
+ setTrayIconVisible(optionsModel->getHideTrayIcon());
+ }
} else {
// Disable possibility to show main window via action
toggleHideAction->setEnabled(false);
@@ -535,7 +549,7 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText();
trayIcon->setToolTip(toolTip);
trayIcon->setIcon(networkStyle->getTrayAndWindowIcon());
- trayIcon->show();
+ trayIcon->hide();
#endif
notificator = new Notificator(QApplication::applicationName(), trayIcon, this);
@@ -686,7 +700,7 @@ void BitcoinGUI::setNumConnections(int count)
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
}
-void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress)
+void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header)
{
if(!clientModel)
return;
@@ -698,15 +712,25 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
enum BlockSource blockSource = clientModel->getBlockSource();
switch (blockSource) {
case BLOCK_SOURCE_NETWORK:
+ if (header) {
+ return;
+ }
progressBarLabel->setText(tr("Synchronizing with network..."));
break;
case BLOCK_SOURCE_DISK:
- progressBarLabel->setText(tr("Importing blocks from disk..."));
+ if (header) {
+ progressBarLabel->setText(tr("Indexing blocks on disk..."));
+ } else {
+ progressBarLabel->setText(tr("Processing blocks on disk..."));
+ }
break;
case BLOCK_SOURCE_REINDEX:
progressBarLabel->setText(tr("Reindexing blocks on disk..."));
break;
case BLOCK_SOURCE_NONE:
+ if (header) {
+ return;
+ }
// Case: not Importing, not Reindexing and no network connection
progressBarLabel->setText(tr("No block source available..."));
break;
@@ -891,6 +915,14 @@ void BitcoinGUI::closeEvent(QCloseEvent *event)
QMainWindow::closeEvent(event);
}
+void BitcoinGUI::showEvent(QShowEvent *event)
+{
+ // enable the debug window when the main window shows up
+ openRPCConsoleAction->setEnabled(true);
+ aboutAction->setEnabled(true);
+ optionsAction->setEnabled(true);
+}
+
#ifdef ENABLE_WALLET
void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label)
{
@@ -1044,6 +1076,14 @@ void BitcoinGUI::showProgress(const QString &title, int nProgress)
progressDialog->setValue(nProgress);
}
+void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon)
+{
+ if (trayIcon)
+ {
+ trayIcon->setVisible(!fHideTrayIcon);
+ }
+}
+
static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style)
{
bool modal = (style & CClientUIInterface::MODAL);
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 871ca1ba34..12e7702ed8 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -72,6 +72,7 @@ public:
protected:
void changeEvent(QEvent *e);
void closeEvent(QCloseEvent *event);
+ void showEvent(QShowEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
bool eventFilter(QObject *object, QEvent *event);
@@ -150,7 +151,7 @@ public Q_SLOTS:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set number of blocks and last block date shown in the UI */
- void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress);
+ void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers);
/** Notify the user of an event from the core network or transaction handling code.
@param[in] title the message box / notification title
@@ -218,6 +219,9 @@ private Q_SLOTS:
/** Show progress dialog e.g. for verifychain */
void showProgress(const QString &title, int nProgress);
+
+ /** When hideTrayIcon setting is changed in OptionsModel hide or show the icon accordingly. */
+ void setTrayIconVisible(bool);
};
class UnitDisplayStatusBarControl : public QLabel
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 697736cc88..108500654b 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -24,6 +24,7 @@
class CBlockIndex;
static const int64_t nClientStartupTime = GetTime();
+static int64_t nLastHeaderTipUpdateNotification = 0;
static int64_t nLastBlockTipUpdateNotification = 0;
ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
@@ -226,7 +227,7 @@ static void BannedListChanged(ClientModel *clientmodel)
QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
}
-static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex)
+static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex, bool fHeader)
{
// lock free async UI updates in case we have a new block tip
// during initial sync, only update the UI if the last update
@@ -235,14 +236,17 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB
if (initialSync)
now = GetTimeMillis();
+ int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
+
// if we are in-sync, update the UI regardless of last update time
- if (!initialSync || now - nLastBlockTipUpdateNotification > MODEL_UPDATE_DELAY) {
+ if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
//pass a async signal to the UI thread
QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
Q_ARG(int, pIndex->nHeight),
Q_ARG(QDateTime, QDateTime::fromTime_t(pIndex->GetBlockTime())),
- Q_ARG(double, clientmodel->getVerificationProgress(pIndex)));
- nLastBlockTipUpdateNotification = now;
+ Q_ARG(double, clientmodel->getVerificationProgress(pIndex)),
+ Q_ARG(bool, fHeader));
+ nLastUpdateNotification = now;
}
}
@@ -253,7 +257,8 @@ void ClientModel::subscribeToCoreSignals()
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this));
uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this));
- uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2));
+ uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2, false));
+ uiInterface.NotifyHeaderTip.connect(boost::bind(BlockTipChanged, this, _1, _2, true));
}
void ClientModel::unsubscribeFromCoreSignals()
@@ -263,5 +268,6 @@ void ClientModel::unsubscribeFromCoreSignals()
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this));
uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this));
- uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2));
+ uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, false));
+ uiInterface.NotifyHeaderTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, true));
}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 109f95a2a7..4396804319 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -89,7 +89,7 @@ private:
Q_SIGNALS:
void numConnectionsChanged(int count);
- void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress);
+ void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress, bool header);
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes);
void alertsChanged(const QString &warnings);
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut);
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index c712e6ea01..0b29201872 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -505,6 +505,16 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_Window">
<item>
+ <widget class="QCheckBox" name="hideTrayIcon">
+ <property name="toolTip">
+ <string>&amp;Hide the icon from the system tray.</string>
+ </property>
+ <property name="text">
+ <string>Hide tray icon</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QCheckBox" name="minimizeToTray">
<property name="toolTip">
<string>Show only a tray icon after minimizing the window.</string>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 95a3fa8d21..f2db398899 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -198,6 +198,7 @@ void OptionsDialog::setMapper()
/* Window */
#ifndef Q_OS_MAC
+ mapper->addMapping(ui->hideTrayIcon, OptionsModel::HideTrayIcon);
mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose);
#endif
@@ -243,6 +244,19 @@ void OptionsDialog::on_cancelButton_clicked()
reject();
}
+void OptionsDialog::on_hideTrayIcon_stateChanged(int fState)
+{
+ if(fState)
+ {
+ ui->minimizeToTray->setChecked(false);
+ ui->minimizeToTray->setEnabled(false);
+ }
+ else
+ {
+ ui->minimizeToTray->setEnabled(true);
+ }
+}
+
void OptionsDialog::showRestartWarning(bool fPersistent)
{
ui->statusLabel->setStyleSheet("QLabel { color: red; }");
diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h
index e944fb9ee9..41b56d1386 100644
--- a/src/qt/optionsdialog.h
+++ b/src/qt/optionsdialog.h
@@ -49,6 +49,8 @@ private Q_SLOTS:
void on_resetButton_clicked();
void on_okButton_clicked();
void on_cancelButton_clicked();
+
+ void on_hideTrayIcon_stateChanged(int fState);
void showRestartWarning(bool fPersistent = false);
void clearStatusLabel();
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index d091bb9e61..cc2cbc0e66 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -51,9 +51,14 @@ void OptionsModel::Init(bool resetSettings)
// These are Qt-only settings:
// Window
+ if (!settings.contains("fHideTrayIcon"))
+ settings.setValue("fHideTrayIcon", false);
+ fHideTrayIcon = settings.value("fHideTrayIcon").toBool();
+ Q_EMIT hideTrayIconChanged(fHideTrayIcon);
+
if (!settings.contains("fMinimizeToTray"))
settings.setValue("fMinimizeToTray", false);
- fMinimizeToTray = settings.value("fMinimizeToTray").toBool();
+ fMinimizeToTray = settings.value("fMinimizeToTray").toBool() && !fHideTrayIcon;
if (!settings.contains("fMinimizeOnClose"))
settings.setValue("fMinimizeOnClose", false);
@@ -166,6 +171,8 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
{
case StartAtStartup:
return GUIUtil::GetStartOnSystemStartup();
+ case HideTrayIcon:
+ return fHideTrayIcon;
case MinimizeToTray:
return fMinimizeToTray;
case MapPortUPnP:
@@ -242,6 +249,11 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
case StartAtStartup:
successful = GUIUtil::SetStartOnSystemStartup(value.toBool());
break;
+ case HideTrayIcon:
+ fHideTrayIcon = value.toBool();
+ settings.setValue("fHideTrayIcon", fHideTrayIcon);
+ Q_EMIT hideTrayIconChanged(fHideTrayIcon);
+ break;
case MinimizeToTray:
fMinimizeToTray = value.toBool();
settings.setValue("fMinimizeToTray", fMinimizeToTray);
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 841711dd2d..3b491ceac2 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -28,6 +28,7 @@ public:
enum OptionID {
StartAtStartup, // bool
+ HideTrayIcon, // bool
MinimizeToTray, // bool
MapPortUPnP, // bool
MinimizeOnClose, // bool
@@ -58,6 +59,7 @@ public:
void setDisplayUnit(const QVariant &value);
/* Explicit getters */
+ bool getHideTrayIcon() { return fHideTrayIcon; }
bool getMinimizeToTray() { return fMinimizeToTray; }
bool getMinimizeOnClose() { return fMinimizeOnClose; }
int getDisplayUnit() { return nDisplayUnit; }
@@ -72,6 +74,7 @@ public:
private:
/* Qt-only settings */
+ bool fHideTrayIcon;
bool fMinimizeToTray;
bool fMinimizeOnClose;
QString language;
@@ -87,6 +90,7 @@ private:
Q_SIGNALS:
void displayUnitChanged(int unit);
void coinControlFeaturesChanged(bool);
+ void hideTrayIconChanged(bool);
};
#endif // BITCOIN_QT_OPTIONSMODEL_H
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index d577345e49..6a0404cbf7 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -219,7 +219,7 @@ void OverviewPage::setWalletModel(WalletModel *model)
filter->setDynamicSortFilter(true);
filter->setSortRole(Qt::EditRole);
filter->setShowInactive(false);
- filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);
+ filter->sort(TransactionTableModel::Date, Qt::DescendingOrder);
ui->listTransactions->setModel(filter);
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index d8647d902a..b11648e46f 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -353,8 +353,8 @@ void RPCConsole::setClientModel(ClientModel *model)
setNumConnections(model->getNumConnections());
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
- setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(NULL));
- connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(setNumBlocks(int,QDateTime,double)));
+ setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(NULL), false);
+ connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent());
connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
@@ -585,10 +585,12 @@ void RPCConsole::setNumConnections(int count)
ui->numberOfConnections->setText(connections);
}
-void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress)
+void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers)
{
- ui->numberOfBlocks->setText(QString::number(count));
- ui->lastBlockTime->setText(blockDate.toString());
+ if (!headers) {
+ ui->numberOfBlocks->setText(QString::number(count));
+ ui->lastBlockTime->setText(blockDate.toString());
+ }
}
void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage)
@@ -885,15 +887,13 @@ void RPCConsole::banSelectedNode(int bantime)
// Get currently selected peer address
QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
// Find possible nodes, ban it and clear the selected node
- if (CNode *bannedNode = FindNode(strNode.toStdString())) {
+ if (FindNode(strNode.toStdString())) {
std::string nStr = strNode.toStdString();
std::string addr;
int port = 0;
SplitHostPort(nStr, port, addr);
CNode::Ban(CNetAddr(addr), BanReasonManuallyAdded, bantime);
- bannedNode->fDisconnect = true;
- DumpBanlist();
clearSelectedNode();
clientModel->getBanTableModel()->refresh();
@@ -912,7 +912,6 @@ void RPCConsole::unbanSelectedNode()
if (possibleSubnet.IsValid())
{
CNode::Unban(possibleSubnet);
- DumpBanlist();
clientModel->getBanTableModel()->refresh();
}
}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 2923587bc8..28affa954d 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -87,7 +87,7 @@ public Q_SLOTS:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set number of blocks and last block date shown in the UI */
- void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress);
+ void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers);
/** Set size (number of transactions and memory usage) of the mempool in the UI */
void setMempoolSize(long numberOfTxs, size_t dynUsage);
/** Go forward or back in history */
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 54ebd25833..6d50be56ec 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -124,7 +124,7 @@ void SendCoinsDialog::setClientModel(ClientModel *clientModel)
this->clientModel = clientModel;
if (clientModel) {
- connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(updateSmartFeeLabel()));
+ connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(updateSmartFeeLabel()));
}
}
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index eb6111e682..199a7b2d77 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -203,7 +203,7 @@ void TransactionView::setModel(WalletModel *model)
transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
transactionView->setSortingEnabled(true);
- transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
+ transactionView->sortByColumn(TransactionTableModel::Date, Qt::DescendingOrder);
transactionView->verticalHeader()->hide();
transactionView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH);
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index a0d0e70442..3867310cd6 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -447,7 +447,7 @@ bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureStri
bool WalletModel::backupWallet(const QString &filename)
{
- return BackupWallet(*wallet, filename.toLocal8Bit().data());
+ return wallet->BackupWallet(filename.toLocal8Bit().data());
}
// Handlers for core signals
diff --git a/src/random.cpp b/src/random.cpp
index 6155c0d8cf..d9a8cc145e 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -5,14 +5,17 @@
#include "random.h"
+#include "crypto/sha512.h"
#include "support/cleanse.h"
#ifdef WIN32
#include "compat.h" // for Windows API
+#include <wincrypt.h>
#endif
#include "serialize.h" // for begin_ptr(vec)
#include "util.h" // for LogPrint()
#include "utilstrencodings.h" // for GetTime()
+#include <stdlib.h>
#include <limits>
#ifndef WIN32
@@ -22,6 +25,12 @@
#include <openssl/err.h>
#include <openssl/rand.h>
+static void RandFailure()
+{
+ LogPrintf("Failed to read randomness, aborting\n");
+ abort();
+}
+
static inline int64_t GetPerformanceCounter()
{
int64_t nCounter = 0;
@@ -43,7 +52,7 @@ void RandAddSeed()
memory_cleanse((void*)&nCounter, sizeof(nCounter));
}
-void RandAddSeedPerfmon()
+static void RandAddSeedPerfmon()
{
RandAddSeed();
@@ -83,14 +92,65 @@ void RandAddSeedPerfmon()
#endif
}
+/** Get 32 bytes of system entropy. */
+static void GetOSRand(unsigned char *ent32)
+{
+#ifdef WIN32
+ HCRYPTPROV hProvider;
+ int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+ if (!ret) {
+ RandFailure();
+ }
+ ret = CryptGenRandom(hProvider, 32, ent32);
+ if (!ret) {
+ RandFailure();
+ }
+ CryptReleaseContext(hProvider, 0);
+#else
+ int f = open("/dev/urandom", O_RDONLY);
+ if (f == -1) {
+ RandFailure();
+ }
+ int have = 0;
+ do {
+ ssize_t n = read(f, ent32 + have, 32 - have);
+ if (n <= 0 || n + have > 32) {
+ RandFailure();
+ }
+ have += n;
+ } while (have < 32);
+ close(f);
+#endif
+}
+
void GetRandBytes(unsigned char* buf, int num)
{
if (RAND_bytes(buf, num) != 1) {
- LogPrintf("%s: OpenSSL RAND_bytes() failed with error: %s\n", __func__, ERR_error_string(ERR_get_error(), NULL));
- assert(false);
+ RandFailure();
}
}
+void GetStrongRandBytes(unsigned char* out, int num)
+{
+ assert(num <= 32);
+ CSHA512 hasher;
+ unsigned char buf[64];
+
+ // First source: OpenSSL's RNG
+ RandAddSeedPerfmon();
+ GetRandBytes(buf, 32);
+ hasher.Write(buf, 32);
+
+ // Second source: OS RNG
+ GetOSRand(buf);
+ hasher.Write(buf, 32);
+
+ // Produce output
+ hasher.Finalize(buf);
+ memcpy(out, buf, num);
+ memory_cleanse(buf, 64);
+}
+
uint64_t GetRand(uint64_t nMax)
{
if (nMax == 0)
diff --git a/src/random.h b/src/random.h
index 1a2d3e8ee2..31b80bd565 100644
--- a/src/random.h
+++ b/src/random.h
@@ -10,11 +10,8 @@
#include <stdint.h>
-/**
- * Seed OpenSSL PRNG with additional entropy data
- */
+/* Seed OpenSSL PRNG with additional entropy data */
void RandAddSeed();
-void RandAddSeedPerfmon();
/**
* Functions to gather random data via the OpenSSL PRNG
@@ -25,6 +22,12 @@ int GetRandInt(int nMax);
uint256 GetRandHash();
/**
+ * Function to gather random data from multiple sources, failing whenever any
+ * of those source fail to provide a result.
+ */
+void GetStrongRandBytes(unsigned char* buf, int num);
+
+/**
* Seed insecure_rand using the random pool.
* @param Deterministic Use a deterministic seed
*/
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 320091b9c4..36178bfb4c 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -460,6 +460,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
" \"subversion\": \"/Satoshi:x.x.x/\", (string) the server subversion string\n"
" \"protocolversion\": xxxxx, (numeric) the protocol version\n"
" \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n"
+ " \"localrelay\": true|false, (bool) true if transaction relay is requested from peers\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of connections\n"
" \"networks\": [ (array) information per network\n"
@@ -494,6 +495,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("subversion", strSubVersion));
obj.push_back(Pair("protocolversion",PROTOCOL_VERSION));
obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
+ obj.push_back(Pair("localrelay", fRelayTxes));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("networks", GetNetworksInfo()));
@@ -565,20 +567,12 @@ UniValue setban(const UniValue& params, bool fHelp)
absolute = true;
isSubnet ? CNode::Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : CNode::Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
-
- //disconnect possible nodes
- while(CNode *bannedNode = (isSubnet ? FindNode(subNet) : FindNode(netAddr)))
- bannedNode->fDisconnect = true;
}
else if(strCommand == "remove")
{
if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) ))
throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
}
-
- DumpBanlist(); //store banlist to disk
- uiInterface.BannedListChanged();
-
return NullUniValue;
}
@@ -624,8 +618,6 @@ UniValue clearbanned(const UniValue& params, bool fHelp)
);
CNode::ClearBanned();
- DumpBanlist(); //store banlist to disk
- uiInterface.BannedListChanged();
return NullUniValue;
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index de8cd68f66..483fe746ca 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -211,7 +211,7 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
"\nNOTE: By default this function only works sometimes. This is when there is an\n"
"unspent output in the utxo for this transaction. To make it always work,\n"
"you need to maintain a transaction index, using the -txindex command line option or\n"
- "specify the block in which the transaction is included in manually (by blockhash).\n"
+ "specify the block in which the transaction is included manually (by blockhash).\n"
"\nReturn the raw transaction data.\n"
"\nArguments:\n"
"1. \"txids\" (string) A json array of txids to filter\n"
@@ -819,12 +819,11 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
const CCoins* existingCoins = view.AccessCoins(hashTx);
bool fHaveMempool = mempool.exists(hashTx);
bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000;
- CFeeRate txFeeRate = CFeeRate(0);
if (!fHaveMempool && !fHaveChain) {
// push to local node and sync with wallets
CValidationState state;
bool fMissingInputs;
- if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, &txFeeRate, false, nMaxRawTxFee)) {
+ if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, nMaxRawTxFee)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
@@ -837,7 +836,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
}
- RelayTransaction(tx, txFeeRate);
+ RelayTransaction(tx);
return hashTx.GetHex();
}
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
index e75b7825ed..0bdac182e0 100644
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -700,6 +700,8 @@
["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Zero-length R is correctly encoded"],
["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "", "OK", "Zero-length S is correctly encoded for DERSIG"],
["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Negative S is correctly encoded"],
+
+["2147483648", "NOP3", "CHECKSEQUENCEVERIFY", "OK", "CSV passes if stack top bit 1 << 31 is set"],
["", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE", "Test the test: we should have an empty stack after scriptSig evaluation"],
[" ", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE", "and multiple spaces should not change that."],
@@ -855,7 +857,7 @@
["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"],
["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"],
-["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
+["1", "NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
["Ensure 100% coverage of discouraged NOPS"],
@@ -1309,6 +1311,13 @@
"P2SH(P2PK), bad redeemscript"
],
[
+ "0x47 0x30440220781ba4f59a7b207a10db87628bc2168df4d59b844b397d2dbc9a5835fb2f2b7602206ed8fbcc1072fe2dfc5bb25909269e5dc42ffcae7ec2bc81d59692210ff30c2b01 0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x19 0x76a91491b24bf9f5288532960ac687abb035127b1d28a588ac",
+ "HASH160 0x14 0x7f67f0521934a57d3039f77f9f32cf313f3ac74b EQUAL",
+ "P2SH",
+ "OK",
+ "P2SH(P2PKH)"
+],
+[
"0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
"HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",
"",
@@ -1820,5 +1829,12 @@
"P2SH with CLEANSTACK"
],
+["CHECKSEQUENCEVERIFY tests"],
+["", "NOP3", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a empty stack"],
+["-1", "NOP3", "CHECKSEQUENCEVERIFY", "NEGATIVE_LOCKTIME", "CSV automatically fails if stack top is negative"],
+["0x0100", "NOP3", "CHECKSEQUENCEVERIFY,MINIMALDATA", "UNKNOWN_ERROR", "CSV fails if stack top is not minimally encoded"],
+["0", "NOP3", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is set and the tx version < 2"],
+["4294967296", "NOP3", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME",
+ "CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"],
["The End"]
]
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
index 35079d1614..8baaf3645f 100644
--- a/src/test/hash_tests.cpp
+++ b/src/test/hash_tests.cpp
@@ -47,4 +47,24 @@ BOOST_AUTO_TEST_CASE(murmurhash3)
#undef T
}
+BOOST_AUTO_TEST_CASE(siphash)
+{
+ CSipHasher hasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0x726fdb47dd0e0e31ull);
+ hasher.Write(0x0706050403020100ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0x93f5f5799a932462ull);
+ hasher.Write(0x0F0E0D0C0B0A0908ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0x3f2acc7f57c29bdbull);
+ hasher.Write(0x1716151413121110ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0xb8ad50c6f649af94ull);
+ hasher.Write(0x1F1E1D1C1B1A1918ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0x7127512f72f27cceull);
+ hasher.Write(0x2726252423222120ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0x0e3ea96b5304a7d0ull);
+ hasher.Write(0x2F2E2D2C2B2A2928ULL);
+ BOOST_CHECK_EQUAL(hasher.Finalize(), 0xe612a3cb9ecba951ull);
+
+ BOOST_CHECK_EQUAL(SipHashUint256(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL, uint256S("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100")), 0x7127512f72f27cceull);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
new file mode 100644
index 0000000000..b38d61f330
--- /dev/null
+++ b/src/test/net_tests.cpp
@@ -0,0 +1,145 @@
+// Copyright (c) 2012-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 "addrman.h"
+#include "test/test_bitcoin.h"
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include "hash.h"
+#include "serialize.h"
+#include "streams.h"
+#include "net.h"
+#include "chainparams.h"
+
+using namespace std;
+
+class CAddrManSerializationMock : public CAddrMan
+{
+public:
+ virtual void Serialize(CDataStream& s, int nType, int nVersionDummy) const = 0;
+
+ //! Ensure that bucket placement is always the same for testing purposes.
+ void MakeDeterministic()
+ {
+ nKey.SetNull();
+ seed_insecure_rand(true);
+ }
+};
+
+class CAddrManUncorrupted : public CAddrManSerializationMock
+{
+public:
+ void Serialize(CDataStream& s, int nType, int nVersionDummy) const
+ {
+ CAddrMan::Serialize(s, nType, nVersionDummy);
+ }
+};
+
+class CAddrManCorrupted : public CAddrManSerializationMock
+{
+public:
+ void Serialize(CDataStream& s, int nType, int nVersionDummy) const
+ {
+ // Produces corrupt output that claims addrman has 20 addrs when it only has one addr.
+ unsigned char nVersion = 1;
+ s << nVersion;
+ s << ((unsigned char)32);
+ s << nKey;
+ s << 10; // nNew
+ s << 10; // nTried
+
+ int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
+ s << nUBuckets;
+
+ CAddress addr = CAddress(CService("252.1.1.1", 7777));
+ CAddrInfo info = CAddrInfo(addr, CNetAddr("252.2.2.2"));
+ s << info;
+ }
+};
+
+CDataStream AddrmanToStream(CAddrManSerializationMock& addrman)
+{
+ CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
+ ssPeersIn << FLATDATA(Params().MessageStart());
+ ssPeersIn << addrman;
+ std::string str = ssPeersIn.str();
+ vector<unsigned char> vchData(str.begin(), str.end());
+ return CDataStream(vchData, SER_DISK, CLIENT_VERSION);
+}
+
+BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(caddrdb_read)
+{
+ CAddrManUncorrupted addrmanUncorrupted;
+ addrmanUncorrupted.MakeDeterministic();
+
+ CService addr1 = CService("250.7.1.1", 8333);
+ CService addr2 = CService("250.7.2.2", 9999);
+ CService addr3 = CService("250.7.3.3", 9999);
+
+ // Add three addresses to new table.
+ addrmanUncorrupted.Add(CAddress(addr1), CService("252.5.1.1", 8333));
+ addrmanUncorrupted.Add(CAddress(addr2), CService("252.5.1.1", 8333));
+ addrmanUncorrupted.Add(CAddress(addr3), CService("252.5.1.1", 8333));
+
+ // Test that the de-serialization does not throw an exception.
+ CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);
+ bool exceptionThrown = false;
+ CAddrMan addrman1;
+
+ BOOST_CHECK(addrman1.size() == 0);
+ try {
+ unsigned char pchMsgTmp[4];
+ ssPeers1 >> FLATDATA(pchMsgTmp);
+ ssPeers1 >> addrman1;
+ } catch (const std::exception& e) {
+ exceptionThrown = true;
+ }
+
+ BOOST_CHECK(addrman1.size() == 3);
+ BOOST_CHECK(exceptionThrown == false);
+
+ // Test that CAddrDB::Read creates an addrman with the correct number of addrs.
+ CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted);
+
+ CAddrMan addrman2;
+ CAddrDB adb;
+ BOOST_CHECK(addrman2.size() == 0);
+ adb.Read(addrman2, ssPeers2);
+ BOOST_CHECK(addrman2.size() == 3);
+}
+
+
+BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
+{
+ CAddrManCorrupted addrmanCorrupted;
+ addrmanCorrupted.MakeDeterministic();
+
+ // Test that the de-serialization of corrupted addrman throws an exception.
+ CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted);
+ bool exceptionThrown = false;
+ CAddrMan addrman1;
+ BOOST_CHECK(addrman1.size() == 0);
+ try {
+ unsigned char pchMsgTmp[4];
+ ssPeers1 >> FLATDATA(pchMsgTmp);
+ ssPeers1 >> addrman1;
+ } catch (const std::exception& e) {
+ exceptionThrown = true;
+ }
+ // Even through de-serialization failed addrman is not left in a clean state.
+ BOOST_CHECK(addrman1.size() == 1);
+ BOOST_CHECK(exceptionThrown);
+
+ // Test that CAddrDB::Read leaves addrman in a clean state if de-serialization fails.
+ CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted);
+
+ CAddrMan addrman2;
+ CAddrDB adb;
+ BOOST_CHECK(addrman2.size() == 0);
+ adb.Read(addrman2, ssPeers2);
+ BOOST_CHECK(addrman2.size() == 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 5e9711a4a7..39089f103d 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -427,7 +427,10 @@ BOOST_AUTO_TEST_CASE(script_build)
tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG,
"P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key0).PushRedeem().DamagePush(10).ScriptError(SCRIPT_ERR_EVAL_FALSE));
-
+
+ tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey0.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,
+ "P2SH(P2PKH)", SCRIPT_VERIFY_P2SH, true
+ ).PushSig(keys.key0).Push(keys.pubkey0).PushRedeem());
tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,
"P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true
).PushSig(keys.key0).DamagePush(10).PushRedeem());
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 04c6fa9625..e43b2ff6c4 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -195,7 +195,6 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
nHashType = test[3].get_int();
sigHashHex = test[4].get_str();
- uint256 sh;
CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
stream >> tx;
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 237b26329b..c29e30792a 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -23,7 +23,7 @@ ToMemPool(CMutableTransaction& tx)
LOCK(cs_main);
CValidationState state;
- return AcceptToMemoryPool(mempool, state, tx, false, NULL, NULL, true, 0);
+ return AcceptToMemoryPool(mempool, state, tx, false, NULL, true, 0);
}
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index aa5df6ca4e..4f17e7f8ca 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -789,15 +789,23 @@ void CTxMemPool::queryHashes(vector<uint256>& vtxid)
std::sort(vtxid.begin(), vtxid.end(), DepthAndScoreComparator(this));
}
-bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
+
+bool CTxMemPool::lookup(uint256 hash, CTransaction& result, int64_t& time) const
{
LOCK(cs);
indexed_transaction_set::const_iterator i = mapTx.find(hash);
if (i == mapTx.end()) return false;
result = i->GetTx();
+ time = i->GetTime();
return true;
}
+bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
+{
+ int64_t time;
+ return CTxMemPool::lookup(hash, result, time);
+}
+
bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const
{
LOCK(cs);
diff --git a/src/txmempool.h b/src/txmempool.h
index bca8dd9791..75cf0f4c12 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -17,6 +17,7 @@
#undef foreach
#include "boost/multi_index_container.hpp"
#include "boost/multi_index/ordered_index.hpp"
+#include "boost/multi_index/hashed_index.hpp"
class CAutoFile;
class CBlockIndex;
@@ -422,7 +423,7 @@ public:
CTxMemPoolEntry,
boost::multi_index::indexed_by<
// sorted by txid
- boost::multi_index::ordered_unique<mempoolentry_txid>,
+ boost::multi_index::hashed_unique<mempoolentry_txid, SaltedTxidHasher>,
// sorted by fee rate
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<descendant_score>,
@@ -601,6 +602,7 @@ public:
}
bool lookup(uint256 hash, CTransaction& result) const;
+ bool lookup(uint256 hash, CTransaction& result, int64_t& time) const;
bool lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const;
/** Estimate fee rate needed to get into the next nBlocks
diff --git a/src/ui_interface.h b/src/ui_interface.h
index a27918c507..7ebfc17e5d 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -96,6 +96,9 @@ public:
/** New block has been accepted */
boost::signals2::signal<void (bool, const CBlockIndex *)> NotifyBlockTip;
+ /** Best header has changed */
+ boost::signals2::signal<void (bool, const CBlockIndex *)> NotifyHeaderTip;
+
/** Banlist did change. */
boost::signals2::signal<void (void)> BannedListChanged;
};
diff --git a/src/uint256.cpp b/src/uint256.cpp
index c58c88bf4a..f22ddcd1ef 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -80,67 +80,3 @@ template std::string base_blob<256>::GetHex() const;
template std::string base_blob<256>::ToString() const;
template void base_blob<256>::SetHex(const char*);
template void base_blob<256>::SetHex(const std::string&);
-
-static void inline HashMix(uint32_t& a, uint32_t& b, uint32_t& c)
-{
- // Taken from lookup3, by Bob Jenkins.
- a -= c;
- a ^= ((c << 4) | (c >> 28));
- c += b;
- b -= a;
- b ^= ((a << 6) | (a >> 26));
- a += c;
- c -= b;
- c ^= ((b << 8) | (b >> 24));
- b += a;
- a -= c;
- a ^= ((c << 16) | (c >> 16));
- c += b;
- b -= a;
- b ^= ((a << 19) | (a >> 13));
- a += c;
- c -= b;
- c ^= ((b << 4) | (b >> 28));
- b += a;
-}
-
-static void inline HashFinal(uint32_t& a, uint32_t& b, uint32_t& c)
-{
- // Taken from lookup3, by Bob Jenkins.
- c ^= b;
- c -= ((b << 14) | (b >> 18));
- a ^= c;
- a -= ((c << 11) | (c >> 21));
- b ^= a;
- b -= ((a << 25) | (a >> 7));
- c ^= b;
- c -= ((b << 16) | (b >> 16));
- a ^= c;
- a -= ((c << 4) | (c >> 28));
- b ^= a;
- b -= ((a << 14) | (a >> 18));
- c ^= b;
- c -= ((b << 24) | (b >> 8));
-}
-
-uint64_t uint256::GetHash(const uint256& salt) const
-{
- uint32_t a, b, c;
- const uint32_t *pn = (const uint32_t*)data;
- const uint32_t *salt_pn = (const uint32_t*)salt.data;
- a = b = c = 0xdeadbeef + WIDTH;
-
- a += pn[0] ^ salt_pn[0];
- b += pn[1] ^ salt_pn[1];
- c += pn[2] ^ salt_pn[2];
- HashMix(a, b, c);
- a += pn[3] ^ salt_pn[3];
- b += pn[4] ^ salt_pn[4];
- c += pn[5] ^ salt_pn[5];
- HashMix(a, b, c);
- a += pn[6] ^ salt_pn[6];
- b += pn[7] ^ salt_pn[7];
- HashFinal(a, b, c);
-
- return ((((uint64_t)b) << 32) | c);
-}
diff --git a/src/uint256.h b/src/uint256.h
index bcdb6dd7c2..dd8432d74c 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -83,6 +83,19 @@ public:
return sizeof(data);
}
+ uint64_t GetUint64(int pos) const
+ {
+ const uint8_t* ptr = data + pos * 8;
+ return ((uint64_t)ptr[0]) | \
+ ((uint64_t)ptr[1]) << 8 | \
+ ((uint64_t)ptr[2]) << 16 | \
+ ((uint64_t)ptr[3]) << 24 | \
+ ((uint64_t)ptr[4]) << 32 | \
+ ((uint64_t)ptr[5]) << 40 | \
+ ((uint64_t)ptr[6]) << 48 | \
+ ((uint64_t)ptr[7]) << 56;
+ }
+
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const
{
@@ -127,11 +140,6 @@ public:
{
return ReadLE64(data);
}
-
- /** A more secure, salted hash function.
- * @note This hash is not stable between little and big endian.
- */
- uint64_t GetHash(const uint256& salt) const;
};
/* uint256 from const char *.
diff --git a/src/util.cpp b/src/util.cpp
index 3f0f8be544..80f2193016 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -113,7 +113,7 @@ string strMiscWarning;
bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
bool fLogIPs = DEFAULT_LOGIPS;
-volatile bool fReopenDebugLog = false;
+volatile sig_atomic_t fReopenDebugLog = false;
CTranslationInterface translationInterface;
/** Init OpenSSL library multithreading support */
diff --git a/src/util.h b/src/util.h
index 45e81ab67f..88a00d3ca1 100644
--- a/src/util.h
+++ b/src/util.h
@@ -28,6 +28,10 @@
#include <boost/signals2/signal.hpp>
#include <boost/thread/exceptions.hpp>
+#ifndef WIN32
+#include <signal.h>
+#endif
+
static const bool DEFAULT_LOGTIMEMICROS = false;
static const bool DEFAULT_LOGIPS = false;
static const bool DEFAULT_LOGTIMESTAMPS = true;
@@ -50,7 +54,7 @@ extern std::string strMiscWarning;
extern bool fLogTimestamps;
extern bool fLogTimeMicros;
extern bool fLogIPs;
-extern volatile bool fReopenDebugLog;
+extern volatile sig_atomic_t fReopenDebugLog;
extern CTranslationInterface translationInterface;
extern const char * const BITCOIN_CONF_FILENAME;
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 623037e766..b9f086b092 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -673,38 +673,6 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
}
-CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
-{
- CAmount nBalance = 0;
-
- // Tally wallet transactions
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
- if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
- continue;
-
- CAmount nReceived, nSent, nFee;
- wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
-
- if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
- nBalance += nReceived;
- nBalance -= nSent + nFee;
- }
-
- // Tally internal accounting entries
- nBalance += walletdb.GetAccountCreditDebit(strAccount);
-
- return nBalance;
-}
-
-CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
-{
- CWalletDB walletdb(pwalletMain->strWalletFile);
- return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
-}
-
-
UniValue getbalance(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
@@ -775,7 +743,7 @@ UniValue getbalance(const UniValue& params, bool fHelp)
string strAccount = AccountFromValue(params[0]);
- CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
+ CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, filter);
return ValueFromAmount(nBalance);
}
@@ -923,7 +891,7 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
EnsureWalletIsUnlocked();
// Check funds
- CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
+ CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
if (nAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
@@ -1026,7 +994,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
EnsureWalletIsUnlocked();
// Check funds
- CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
+ CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
if (totalAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
@@ -1836,7 +1804,7 @@ UniValue backupwallet(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
string strDest = params[0].get_str();
- if (!BackupWallet(*pwalletMain, strDest))
+ if (!pwalletMain->BackupWallet(strDest))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
return NullUniValue;
@@ -2233,7 +2201,7 @@ UniValue settxfee(const UniValue& params, bool fHelp)
"settxfee amount\n"
"\nSet the transaction fee per kB. Overwrites the paytxfee parameter.\n"
"\nArguments:\n"
- "1. amount (numeric or sting, required) The transaction fee in " + CURRENCY_UNIT + "/kB\n"
+ "1. amount (numeric or string, required) The transaction fee in " + CURRENCY_UNIT + "/kB\n"
"\nResult\n"
"true|false (boolean) Returns true if successful\n"
"\nExamples:\n"
@@ -2328,8 +2296,6 @@ UniValue listunspent(const UniValue& params, bool fHelp)
"\nReturns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n"
"Optionally filter to only include txouts paid to specified addresses.\n"
- "Results are an array of Objects, each of which has:\n"
- "{txid, vout, scriptPubKey, amount, confirmations}\n"
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
"2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index a18b669b32..da0d6f272b 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -509,16 +509,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
return false;
CKeyingMaterial vMasterKey;
- RandAddSeedPerfmon();
vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
- GetRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
+ GetStrongRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
CMasterKey kMasterKey;
- RandAddSeedPerfmon();
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
- GetRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
+ GetStrongRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
CCrypter crypter;
int64_t nStartTime = GetTimeMillis();
@@ -1272,9 +1270,7 @@ bool CWalletTx::RelayWalletTransaction()
{
if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
- CFeeRate feeRate;
- mempool.lookupFeeRate(GetHash(), feeRate);
- RelayTransaction((CTransaction)*this, feeRate);
+ RelayTransaction((CTransaction)*this);
return true;
}
}
@@ -2761,6 +2757,37 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
return ret;
}
+CAmount CWallet::GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter)
+{
+ CWalletDB walletdb(strWalletFile);
+ return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
+}
+
+CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter)
+{
+ CAmount nBalance = 0;
+
+ // Tally wallet transactions
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx& wtx = (*it).second;
+ if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
+ continue;
+
+ CAmount nReceived, nSent, nFee;
+ wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
+
+ if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
+ nBalance += nReceived;
+ nBalance -= nSent + nFee;
+ }
+
+ // Tally internal accounting entries
+ nBalance += walletdb.GetAccountCreditDebit(strAccount);
+
+ return nBalance;
+}
+
std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
{
LOCK(cs_wallet);
@@ -3118,8 +3145,6 @@ bool CWallet::InitLoadWallet()
if (fFirstRun)
{
// Create new keyUser and set as default key
- RandAddSeedPerfmon();
-
CPubKey newDefaultKey;
if (walletInstance->GetKeyFromPool(newDefaultKey)) {
walletInstance->SetDefaultKey(newDefaultKey);
@@ -3254,6 +3279,46 @@ bool CWallet::ParameterInteraction()
return true;
}
+bool CWallet::BackupWallet(const std::string& strDest)
+{
+ if (!fFileBacked)
+ return false;
+ while (true)
+ {
+ {
+ LOCK(bitdb.cs_db);
+ if (!bitdb.mapFileUseCount.count(strWalletFile) || bitdb.mapFileUseCount[strWalletFile] == 0)
+ {
+ // Flush log data to the dat file
+ bitdb.CloseDb(strWalletFile);
+ bitdb.CheckpointLSN(strWalletFile);
+ bitdb.mapFileUseCount.erase(strWalletFile);
+
+ // Copy wallet file
+ boost::filesystem::path pathSrc = GetDataDir() / strWalletFile;
+ boost::filesystem::path pathDest(strDest);
+ if (boost::filesystem::is_directory(pathDest))
+ pathDest /= strWalletFile;
+
+ try {
+#if BOOST_VERSION >= 104000
+ boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
+#else
+ boost::filesystem::copy_file(pathSrc, pathDest);
+#endif
+ LogPrintf("copied %s to %s\n", strWalletFile, pathDest.string());
+ return true;
+ } catch (const boost::filesystem::filesystem_error& e) {
+ LogPrintf("error copying %s to %s - %s\n", strWalletFile, pathDest.string(), e.what());
+ return false;
+ }
+ }
+ }
+ MilliSleep(100);
+ }
+ return false;
+}
+
CKeyPool::CKeyPool()
{
nTime = GetTime();
@@ -3331,5 +3396,5 @@ int CMerkleTx::GetBlocksToMaturity() const
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee)
{
CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, NULL, false, nAbsurdFee);
+ return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee);
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index cc568c3749..b2180a5a26 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -776,6 +776,8 @@ public:
std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<CTxDestination, CAmount> GetAddressBalances();
+ CAmount GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter);
+ CAmount GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter);
std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;
isminetype IsMine(const CTxIn& txin) const;
@@ -883,6 +885,8 @@ public:
/* Wallets parameter interaction */
static bool ParameterInteraction();
+
+ bool BackupWallet(const std::string& strDest);
};
/** A key allocated from the key pool. */
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 48579b2821..b5037c9a65 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -903,46 +903,6 @@ void ThreadFlushWalletDB(const string& strFile)
}
}
-bool BackupWallet(const CWallet& wallet, const string& strDest)
-{
- if (!wallet.fFileBacked)
- return false;
- while (true)
- {
- {
- LOCK(bitdb.cs_db);
- if (!bitdb.mapFileUseCount.count(wallet.strWalletFile) || bitdb.mapFileUseCount[wallet.strWalletFile] == 0)
- {
- // Flush log data to the dat file
- bitdb.CloseDb(wallet.strWalletFile);
- bitdb.CheckpointLSN(wallet.strWalletFile);
- bitdb.mapFileUseCount.erase(wallet.strWalletFile);
-
- // Copy wallet file
- boost::filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile;
- boost::filesystem::path pathDest(strDest);
- if (boost::filesystem::is_directory(pathDest))
- pathDest /= wallet.strWalletFile;
-
- try {
-#if BOOST_VERSION >= 104000
- boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
-#else
- boost::filesystem::copy_file(pathSrc, pathDest);
-#endif
- LogPrintf("copied %s to %s\n", wallet.strWalletFile, pathDest.string());
- return true;
- } catch (const boost::filesystem::filesystem_error& e) {
- LogPrintf("error copying %s to %s - %s\n", wallet.strWalletFile, pathDest.string(), e.what());
- return false;
- }
- }
- }
- MilliSleep(100);
- }
- return false;
-}
-
//
// Try to (very carefully!) recover wallet file if there is a problem.
//
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 5345c0907e..00c10ea70f 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -141,7 +141,6 @@ private:
bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry);
};
-bool BackupWallet(const CWallet& wallet, const std::string& strDest);
void ThreadFlushWalletDB(const std::string& strFile);
#endif // BITCOIN_WALLET_WALLETDB_H