aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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/crypto_hash.cpp53
-rw-r--r--src/bench/rollingbloom.cpp43
-rw-r--r--src/bloom.cpp40
-rw-r--r--src/bloom.h13
-rw-r--r--src/chain.h54
-rw-r--r--src/coins.cpp6
-rw-r--r--src/coins.h14
-rw-r--r--src/compat.h11
-rw-r--r--src/hash.cpp94
-rw-r--r--src/hash.h15
-rw-r--r--src/httpserver.cpp29
-rw-r--r--src/init.cpp35
-rw-r--r--src/main.cpp351
-rw-r--r--src/main.h98
-rw-r--r--src/net.cpp272
-rw-r--r--src/net.h30
-rw-r--r--src/netbase.cpp37
-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/rpcconsole.cpp17
-rw-r--r--src/qt/rpcconsole.h2
-rw-r--r--src/qt/sendcoinsdialog.cpp55
-rw-r--r--src/qt/sendcoinsdialog.h22
-rw-r--r--src/rpc/blockchain.cpp8
-rw-r--r--src/rpc/misc.cpp43
-rw-r--r--src/rpc/net.cpp10
-rw-r--r--src/rpc/rawtransaction.cpp5
-rw-r--r--src/scheduler.cpp1
-rw-r--r--src/script/script.h15
-rw-r--r--src/test/bloom_tests.cpp5
-rw-r--r--src/test/coins_tests.cpp3
-rw-r--r--src/test/data/script_tests.json11
-rw-r--r--src/test/hash_tests.cpp20
-rw-r--r--src/test/net_tests.cpp145
-rw-r--r--src/test/scheduler_tests.cpp2
-rw-r--r--src/test/script_tests.cpp117
-rw-r--r--src/test/txvalidationcache_tests.cpp2
-rw-r--r--src/txdb.cpp8
-rw-r--r--src/txdb.h33
-rw-r--r--src/txmempool.cpp33
-rw-r--r--src/txmempool.h8
-rw-r--r--src/ui_interface.h3
-rw-r--r--src/uint256.cpp64
-rw-r--r--src/uint256.h18
-rw-r--r--src/util.cpp15
-rw-r--r--src/util.h7
-rw-r--r--src/wallet/rpcwallet.cpp4
-rw-r--r--src/wallet/wallet.cpp21
-rw-r--r--src/wallet/wallet.h2
-rw-r--r--src/wallet/walletdb.cpp10
-rw-r--r--src/wallet/walletdb.h2
62 files changed, 1404 insertions, 636 deletions
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 8e7b59b461..65fd24e051 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -7,7 +7,9 @@ bench_bench_bitcoin_SOURCES = \
bench/bench_bitcoin.cpp \
bench/bench.cpp \
bench/bench.h \
- bench/Examples.cpp
+ bench/Examples.cpp \
+ bench/rollingbloom.cpp \
+ bench/crypto_hash.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 08e2f6af4d..897a7dd4a2 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/crypto_hash.cpp b/src/bench/crypto_hash.cpp
new file mode 100644
index 0000000000..6b753f6308
--- /dev/null
+++ b/src/bench/crypto_hash.cpp
@@ -0,0 +1,53 @@
+// 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 "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 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);
+}
+
+BENCHMARK(RIPEMD160);
+BENCHMARK(SHA1);
+BENCHMARK(SHA256);
+BENCHMARK(SHA512);
diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp
new file mode 100644
index 0000000000..73c02cf718
--- /dev/null
+++ b/src/bench/rollingbloom.cpp
@@ -0,0 +1,43 @@
+// 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 "utiltime.h"
+
+static void RollingBloom(benchmark::State& state)
+{
+ CRollingBloomFilter filter(120000, 0.000001);
+ std::vector<unsigned char> data(32);
+ uint32_t count = 0;
+ uint32_t nEntriesPerGeneration = (120000 + 1) / 2;
+ uint32_t countnow = 0;
+ uint64_t match = 0;
+ while (state.KeepRunning()) {
+ count++;
+ data[0] = count;
+ data[1] = count >> 8;
+ data[2] = count >> 16;
+ data[3] = count >> 24;
+ if (countnow == nEntriesPerGeneration) {
+ int64_t b = GetTimeMicros();
+ filter.insert(data);
+ int64_t e = GetTimeMicros();
+ std::cout << "RollingBloom-refresh,1," << (e-b)*0.000001 << "," << (e-b)*0.000001 << "," << (e-b)*0.000001 << "\n";
+ countnow = 0;
+ } else {
+ filter.insert(data);
+ }
+ countnow++;
+ data[0] = count >> 24;
+ data[1] = count >> 16;
+ data[2] = count >> 8;
+ data[3] = count;
+ match += filter.contains(data);
+ }
+}
+
+BENCHMARK(RollingBloom);
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 4e6f0e5d2d..fd328e8e96 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -234,14 +234,18 @@ CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate)
*/
uint32_t nFilterBits = (uint32_t)ceil(-1.0 * nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs)));
data.clear();
- /* We store up to 16 'bits' per data element. */
- data.resize((nFilterBits + 15) / 16);
+ /* For each data element we need to store 2 bits. If both bits are 0, the
+ * bit is treated as unset. If the bits are (01), (10), or (11), the bit is
+ * treated as set in generation 1, 2, or 3 respectively.
+ * These bits are stored in separate integers: position P corresponds to bit
+ * (P & 63) of the integers data[(P >> 6) * 2] and data[(P >> 6) * 2 + 1]. */
+ data.resize(((nFilterBits + 63) / 64) << 1);
reset();
}
/* Similar to CBloomFilter::Hash */
-inline unsigned int CRollingBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const {
- return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (data.size() * 16);
+static inline uint32_t RollingBloomHash(unsigned int nHashNum, uint32_t nTweak, const std::vector<unsigned char>& vDataToHash) {
+ return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash);
}
void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
@@ -252,18 +256,25 @@ void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
if (nGeneration == 4) {
nGeneration = 1;
}
+ uint64_t nGenerationMask1 = -(uint64_t)(nGeneration & 1);
+ uint64_t nGenerationMask2 = -(uint64_t)(nGeneration >> 1);
/* Wipe old entries that used this generation number. */
- for (uint32_t p = 0; p < data.size() * 16; p++) {
- if (get(p) == nGeneration) {
- put(p, 0);
- }
+ for (uint32_t p = 0; p < data.size(); p += 2) {
+ uint64_t p1 = data[p], p2 = data[p + 1];
+ uint64_t mask = (p1 ^ nGenerationMask1) | (p2 ^ nGenerationMask2);
+ data[p] = p1 & mask;
+ data[p + 1] = p2 & mask;
}
}
nEntriesThisGeneration++;
for (int n = 0; n < nHashFuncs; n++) {
- uint32_t h = Hash(n, vKey);
- put(h, nGeneration);
+ uint32_t h = RollingBloomHash(n, nTweak, vKey);
+ int bit = h & 0x3F;
+ uint32_t pos = (h >> 6) % data.size();
+ /* The lowest bit of pos is ignored, and set to zero for the first bit, and to one for the second. */
+ data[pos & ~1] = (data[pos & ~1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration & 1)) << bit;
+ data[pos | 1] = (data[pos | 1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration >> 1)) << bit;
}
}
@@ -276,8 +287,11 @@ void CRollingBloomFilter::insert(const uint256& hash)
bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
{
for (int n = 0; n < nHashFuncs; n++) {
- uint32_t h = Hash(n, vKey);
- if (get(h) == 0) {
+ uint32_t h = RollingBloomHash(n, nTweak, vKey);
+ int bit = h & 0x3F;
+ uint32_t pos = (h >> 6) % data.size();
+ /* If the relevant bit is not set in either data[pos & ~1] or data[pos | 1], the filter does not contain vKey */
+ if (!(((data[pos & ~1] | data[pos | 1]) >> bit) & 1)) {
return false;
}
}
@@ -295,7 +309,7 @@ void CRollingBloomFilter::reset()
nTweak = GetRand(std::numeric_limits<unsigned int>::max());
nEntriesThisGeneration = 0;
nGeneration = 1;
- for (std::vector<uint32_t>::iterator it = data.begin(); it != data.end(); it++) {
+ for (std::vector<uint64_t>::iterator it = data.begin(); it != data.end(); it++) {
*it = 0;
}
}
diff --git a/src/bloom.h b/src/bloom.h
index b0ad8b875d..ad6de625d8 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -135,20 +135,9 @@ private:
int nEntriesPerGeneration;
int nEntriesThisGeneration;
int nGeneration;
- std::vector<uint32_t> data;
+ std::vector<uint64_t> data;
unsigned int nTweak;
int nHashFuncs;
-
- unsigned int Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const;
-
- inline int get(uint32_t position) const {
- return (data[(position >> 4) % data.size()] >> (2 * (position & 0xF))) & 0x3;
- }
-
- inline void put(uint32_t position, uint32_t val) {
- uint32_t& cell = data[(position >> 4) % data.size()];
- cell = (cell & ~(((uint32_t)3) << (2 * (position & 0xF)))) | (val << (2 * (position & 0xF)));
- }
};
#endif // BITCOIN_BLOOM_H
diff --git a/src/chain.h b/src/chain.h
index 017d4fe457..a13dae33d1 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -14,6 +14,60 @@
#include <vector>
+class CBlockFileInfo
+{
+public:
+ unsigned int nBlocks; //!< number of blocks stored in file
+ unsigned int nSize; //!< number of used bytes of block file
+ unsigned int nUndoSize; //!< number of used bytes in the undo file
+ unsigned int nHeightFirst; //!< lowest height of block in file
+ unsigned int nHeightLast; //!< highest height of block in file
+ uint64_t nTimeFirst; //!< earliest time of block in file
+ uint64_t nTimeLast; //!< latest time of block in file
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(VARINT(nBlocks));
+ READWRITE(VARINT(nSize));
+ READWRITE(VARINT(nUndoSize));
+ READWRITE(VARINT(nHeightFirst));
+ READWRITE(VARINT(nHeightLast));
+ READWRITE(VARINT(nTimeFirst));
+ READWRITE(VARINT(nTimeLast));
+ }
+
+ void SetNull() {
+ nBlocks = 0;
+ nSize = 0;
+ nUndoSize = 0;
+ nHeightFirst = 0;
+ nHeightLast = 0;
+ nTimeFirst = 0;
+ nTimeLast = 0;
+ }
+
+ CBlockFileInfo() {
+ SetNull();
+ }
+
+ std::string ToString() const;
+
+ /** update statistics (does not update nSize) */
+ void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) {
+ if (nBlocks==0 || nHeightFirst > nHeightIn)
+ nHeightFirst = nHeightIn;
+ if (nBlocks==0 || nTimeFirst > nTimeIn)
+ nTimeFirst = nTimeIn;
+ nBlocks++;
+ if (nHeightIn > nHeightLast)
+ nHeightLast = nHeightIn;
+ if (nTimeIn > nTimeLast)
+ nTimeLast = nTimeIn;
+ }
+};
+
struct CDiskBlockPos
{
int nFile;
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/compat.h b/src/compat.h
index 1225ea18ed..79a297e5e4 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -78,17 +78,6 @@ typedef u_int SOCKET;
#define MSG_NOSIGNAL 0
#endif
-#ifndef WIN32
-// PRIO_MAX is not defined on Solaris
-#ifndef PRIO_MAX
-#define PRIO_MAX 20
-#endif
-#define THREAD_PRIORITY_LOWEST PRIO_MAX
-#define THREAD_PRIORITY_BELOW_NORMAL 2
-#define THREAD_PRIORITY_NORMAL 0
-#define THREAD_PRIORITY_ABOVE_NORMAL (-2)
-#endif
-
#if HAVE_DECL_STRNLEN == 0
size_t strnlen( const char *start, size_t max_len);
#endif // HAVE_DECL_STRNLEN
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/httpserver.cpp b/src/httpserver.cpp
index a98eff7c16..812940eaf9 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -36,7 +36,6 @@
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <boost/foreach.hpp>
-#include <boost/scoped_ptr.hpp>
/** Maximum size of http request (request line + headers) */
static const size_t MAX_HEADERS_SIZE = 8192;
@@ -45,8 +44,8 @@ static const size_t MAX_HEADERS_SIZE = 8192;
class HTTPWorkItem : public HTTPClosure
{
public:
- HTTPWorkItem(HTTPRequest* req, const std::string &path, const HTTPRequestHandler& func):
- req(req), path(path), func(func)
+ HTTPWorkItem(std::unique_ptr<HTTPRequest> req, const std::string &path, const HTTPRequestHandler& func):
+ req(std::move(req)), path(path), func(func)
{
}
void operator()()
@@ -54,7 +53,7 @@ public:
func(req.get(), path);
}
- boost::scoped_ptr<HTTPRequest> req;
+ std::unique_ptr<HTTPRequest> req;
private:
std::string path;
@@ -71,8 +70,7 @@ private:
/** Mutex protects entire object */
CWaitableCriticalSection cs;
CConditionVariable cond;
- /* XXX in C++11 we can use std::unique_ptr here and avoid manual cleanup */
- std::deque<WorkItem*> queue;
+ std::deque<std::unique_ptr<WorkItem>> queue;
bool running;
size_t maxDepth;
int numThreads;
@@ -101,15 +99,11 @@ public:
numThreads(0)
{
}
- /*( Precondition: worker threads have all stopped
+ /** Precondition: worker threads have all stopped
* (call WaitExit)
*/
~WorkQueue()
{
- while (!queue.empty()) {
- delete queue.front();
- queue.pop_front();
- }
}
/** Enqueue a work item */
bool Enqueue(WorkItem* item)
@@ -118,7 +112,7 @@ public:
if (queue.size() >= maxDepth) {
return false;
}
- queue.push_back(item);
+ queue.emplace_back(std::unique_ptr<WorkItem>(item));
cond.notify_one();
return true;
}
@@ -127,18 +121,17 @@ public:
{
ThreadCounter count(*this);
while (running) {
- WorkItem* i = 0;
+ std::unique_ptr<WorkItem> i;
{
boost::unique_lock<boost::mutex> lock(cs);
while (running && queue.empty())
cond.wait(lock);
if (!running)
break;
- i = queue.front();
+ i = std::move(queue.front());
queue.pop_front();
}
(*i)();
- delete i;
}
}
/** Interrupt and exit loops */
@@ -288,12 +281,14 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
// Dispatch to worker thread
if (i != iend) {
- std::unique_ptr<HTTPWorkItem> item(new HTTPWorkItem(hreq.release(), path, i->handler));
+ std::unique_ptr<HTTPWorkItem> item(new HTTPWorkItem(std::move(hreq), path, i->handler));
assert(workQueue);
if (workQueue->Enqueue(item.get()))
item.release(); /* if true, queue took ownership */
- else
+ else {
+ LogPrintf("WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\n");
item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded");
+ }
} else {
hreq->WriteReply(HTTP_NOTFOUND);
}
diff --git a/src/init.cpp b/src/init.cpp
index b06f448a00..8688381ecf 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -37,9 +37,7 @@
#include "utilmoneystr.h"
#include "validationinterface.h"
#ifdef ENABLE_WALLET
-#include "wallet/db.h"
#include "wallet/wallet.h"
-#include "wallet/walletdb.h"
#endif
#include <stdint.h>
#include <stdio.h>
@@ -125,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()
{
@@ -329,7 +327,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
@@ -406,7 +405,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) + ". " +
@@ -556,9 +555,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);
@@ -583,7 +583,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);
@@ -597,7 +596,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 {
@@ -605,6 +603,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();
@@ -986,9 +991,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (fPrintToDebugLog)
OpenDebugLog();
-#ifdef ENABLE_WALLET
- LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
-#endif
if (!fLogTimestamps)
LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()));
LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
@@ -1163,6 +1165,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";
@@ -1224,7 +1227,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);
@@ -1253,7 +1256,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;
}
@@ -1363,12 +1366,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"))
{
diff --git a/src/main.cpp b/src/main.cpp
index 11ccab253e..9ba90b4ead 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1005,7 +1005,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 +1170,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 +1418,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);
@@ -1468,7 +1465,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
int nHeight = -1;
{
- CCoinsViewCache &view = *pcoinsTip;
+ const CCoinsViewCache& view = *pcoinsTip;
const CCoins* coins = view.AccessCoins(hash);
if (coins)
nHeight = coins->nHeight;
@@ -1593,7 +1590,7 @@ bool fLargeWorkForkFound = false;
bool fLargeWorkInvalidChainFound = false;
CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL;
-static void AlertNotify(const std::string& strMessage, bool fThread)
+static void AlertNotify(const std::string& strMessage)
{
uiInterface.NotifyAlertChanged();
std::string strCmd = GetArg("-alertnotify", "");
@@ -1607,10 +1604,7 @@ static void AlertNotify(const std::string& strMessage, bool fThread)
safeStatus = singleQuote+safeStatus+singleQuote;
boost::replace_all(strCmd, "%s", safeStatus);
- if (fThread)
- boost::thread t(runCommand, strCmd); // thread runs free
- else
- runCommand(strCmd);
+ boost::thread t(runCommand, strCmd); // thread runs free
}
void CheckForkWarningConditions()
@@ -1632,7 +1626,7 @@ void CheckForkWarningConditions()
{
std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
pindexBestForkBase->phashBlock->ToString() + std::string("'");
- AlertNotify(warning, true);
+ AlertNotify(warning);
}
if (pindexBestForkTip && pindexBestForkBase)
{
@@ -1744,7 +1738,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state
}
}
-void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight)
+void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight)
{
// mark inputs spent
if (!tx.IsCoinBase()) {
@@ -1770,10 +1764,10 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
inputs.ModifyNewCoins(tx.GetHash(), tx.IsCoinBase())->FromTx(tx, nHeight);
}
-void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight)
+void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
{
CTxUndo txundo;
- UpdateCoins(tx, state, inputs, txundo, nHeight);
+ UpdateCoins(tx, inputs, txundo, nHeight);
}
bool CScriptCheck::operator()() {
@@ -2163,7 +2157,7 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const
if (!strWarning.empty())
{
strMiscWarning = strWarning;
- AlertNotify(strWarning, true);
+ AlertNotify(strWarning);
lastAlertTime = now;
}
}
@@ -2385,7 +2379,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (i > 0) {
blockundo.vtxundo.push_back(CTxUndo());
}
- UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
+ UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
vPos.push_back(std::make_pair(tx.GetHash(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
@@ -2598,7 +2592,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
if (state == THRESHOLD_ACTIVE) {
strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
if (!fWarned) {
- AlertNotify(strMiscWarning, true);
+ AlertNotify(strMiscWarning);
fWarned = true;
}
} else {
@@ -2620,7 +2614,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect");
if (!fWarned) {
- AlertNotify(strMiscWarning, true);
+ AlertNotify(strMiscWarning);
fWarned = true;
}
}
@@ -2654,7 +2648,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());
@@ -2817,10 +2811,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);
@@ -2890,6 +2883,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
@@ -2908,15 +2923,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();
@@ -3011,7 +3033,7 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
return true;
}
-bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) {
+bool ResetBlockFailureFlags(CBlockIndex *pindex) {
AssertLockHeld(cs_main);
int nHeight = pindex->nHeight;
@@ -3404,11 +3426,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;
@@ -3480,7 +3503,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);
@@ -3498,6 +3521,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__);
@@ -3705,7 +3730,7 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
bool static LoadBlockIndexDB()
{
const CChainParams& chainparams = Params();
- if (!pblocktree->LoadBlockIndexGuts())
+ if (!pblocktree->LoadBlockIndexGuts(InsertBlockIndex))
return false;
boost::this_thread::interruption_point();
@@ -4043,15 +4068,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);
@@ -4063,10 +4099,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());
@@ -4074,6 +4111,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
}
range.first++;
mapBlocksUnknownParent.erase(it);
+ NotifyHeaderTip();
}
}
} catch (const std::exception& e) {
@@ -4556,12 +4594,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH);
pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer);
}
- if (!vRecv.empty())
+ if (!vRecv.empty()) {
vRecv >> pfrom->nStartingHeight;
- if (!vRecv.empty())
- vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message
- else
- pfrom->fRelayTxes = true;
+ }
+ {
+ LOCK(pfrom->cs_filter);
+ if (!vRecv.empty())
+ vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message
+ else
+ pfrom->fRelayTxes = true;
+ }
// Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1)
@@ -4700,25 +4742,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);
}
}
@@ -4955,10 +4995,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",
@@ -4989,10 +5028,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);
}
@@ -5045,7 +5083,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));
}
@@ -5083,6 +5121,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) {
@@ -5090,6 +5129,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;
@@ -5110,7 +5156,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.
@@ -5166,6 +5212,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
@@ -5234,34 +5283,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->fDisconnect = true;
return true;
}
- LOCK2(cs_main, pfrom->cs_filter);
- std::vector<uint256> vtxid;
- mempool.queryHashes(vtxid);
- vector<CInv> vInv;
- BOOST_FOREACH(uint256& hash, vtxid) {
- CInv inv(MSG_TX, hash);
- if (pfrom->pfilter) {
- CTransaction tx;
- bool fInMemPool = mempool.lookup(hash, tx);
- if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
- if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue;
- }
- if (pfrom->minFeeFilter) {
- CFeeRate feeRate;
- mempool.lookupFeeRate(hash, feeRate);
- LOCK(pfrom->cs_feeFilter);
- if (feeRate.GetFeePerK() < pfrom->minFeeFilter)
- continue;
- }
- vInv.push_back(inv);
- if (vInv.size() == MAX_INV_SZ) {
- pfrom->PushMessage(NetMsgType::INV, vInv);
- vInv.clear();
- }
- }
- if (vInv.size() > 0)
- pfrom->PushMessage(NetMsgType::INV, vInv);
+ LOCK(pfrom->cs_inventory);
+ pfrom->fSendMempool = true;
}
@@ -5349,12 +5373,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CBloomFilter filter;
vRecv >> filter;
+ LOCK(pfrom->cs_filter);
+
if (!filter.IsWithinSizeConstraints())
// There is no excuse for sending a too-large filter
Misbehaving(pfrom->GetId(), 100);
else
{
- LOCK(pfrom->cs_filter);
delete pfrom->pfilter;
pfrom->pfilter = new CBloomFilter(filter);
pfrom->pfilter->UpdateEmptyFull();
@@ -5559,6 +5584,22 @@ bool ProcessMessages(CNode* pfrom)
return fOk;
}
+class CompareInvMempoolOrder
+{
+ CTxMemPool *mp;
+public:
+ CompareInvMempoolOrder(CTxMemPool *mempool)
+ {
+ mp = mempool;
+ }
+
+ bool operator()(std::set<uint256>::iterator a, std::set<uint256>::iterator b)
+ {
+ /* As std::make_heap produces a max-heap, we want the entries with the
+ * fewest ancestors/highest fee to sort later. */
+ return mp->CompareDepthAndScore(*b, *a);
+ }
+};
bool SendMessages(CNode* pto)
{
@@ -5798,49 +5839,127 @@ bool SendMessages(CNode* pto)
// Message: inventory
//
vector<CInv> vInv;
- vector<CInv> vInvWait;
{
+ LOCK(pto->cs_inventory);
+ vInv.reserve(std::max<size_t>(pto->vInventoryBlockToSend.size(), INVENTORY_BROADCAST_MAX));
+
+ // Add blocks
+ BOOST_FOREACH(const uint256& hash, pto->vInventoryBlockToSend) {
+ vInv.push_back(CInv(MSG_BLOCK, hash));
+ if (vInv.size() == MAX_INV_SZ) {
+ pto->PushMessage(NetMsgType::INV, vInv);
+ vInv.clear();
+ }
+ }
+ pto->vInventoryBlockToSend.clear();
+
+ // Check whether periodic sends should happen
bool fSendTrickle = pto->fWhitelisted;
if (pto->nNextInvSend < nNow) {
fSendTrickle = true;
- pto->nNextInvSend = PoissonNextSend(nNow, AVG_INVENTORY_BROADCAST_INTERVAL);
+ // Use half the delay for outbound peers, as there is less privacy concern for them.
+ pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> !pto->fInbound);
}
- LOCK(pto->cs_inventory);
- vInv.reserve(std::min<size_t>(1000, pto->vInventoryToSend.size()));
- vInvWait.reserve(pto->vInventoryToSend.size());
- BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
- {
- if (inv.type == MSG_TX && pto->filterInventoryKnown.contains(inv.hash))
- continue;
- // trickle out tx inv to protect privacy
- if (inv.type == MSG_TX && !fSendTrickle)
+ // Time to send but the peer has requested we not relay transactions.
+ if (fSendTrickle) {
+ LOCK(pto->cs_filter);
+ if (!pto->fRelayTxes) pto->setInventoryTxToSend.clear();
+ }
+
+ // Respond to BIP35 mempool requests
+ if (fSendTrickle && pto->fSendMempool) {
+ std::vector<uint256> vtxid;
+ mempool.queryHashes(vtxid);
+ pto->fSendMempool = false;
+ CAmount filterrate = 0;
{
- // 1/4 of tx invs blast to all immediately
- static uint256 hashSalt;
- if (hashSalt.IsNull())
- hashSalt = GetRandHash();
- uint256 hashRand = ArithToUint256(UintToArith256(inv.hash) ^ UintToArith256(hashSalt));
- hashRand = Hash(BEGIN(hashRand), END(hashRand));
- bool fTrickleWait = ((UintToArith256(hashRand) & 3) != 0);
-
- if (fTrickleWait)
- {
- vInvWait.push_back(inv);
- continue;
- }
+ LOCK(pto->cs_feeFilter);
+ filterrate = pto->minFeeFilter;
}
- pto->filterInventoryKnown.insert(inv.hash);
+ LOCK(pto->cs_filter);
- vInv.push_back(inv);
- if (vInv.size() >= 1000)
+ BOOST_FOREACH(const uint256& hash, vtxid) {
+ CInv inv(MSG_TX, hash);
+ pto->setInventoryTxToSend.erase(hash);
+ if (filterrate) {
+ CFeeRate feeRate;
+ mempool.lookupFeeRate(hash, feeRate);
+ if (feeRate.GetFeePerK() < filterrate)
+ continue;
+ }
+ if (pto->pfilter) {
+ CTransaction tx;
+ bool fInMemPool = mempool.lookup(hash, tx);
+ if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
+ if (!pto->pfilter->IsRelevantAndUpdate(tx)) continue;
+ }
+ pto->filterInventoryKnown.insert(hash);
+ vInv.push_back(inv);
+ if (vInv.size() == MAX_INV_SZ) {
+ pto->PushMessage(NetMsgType::INV, vInv);
+ vInv.clear();
+ }
+ }
+ }
+
+ // Determine transactions to relay
+ if (fSendTrickle) {
+ // Produce a vector with all candidates for sending
+ vector<std::set<uint256>::iterator> vInvTx;
+ vInvTx.reserve(pto->setInventoryTxToSend.size());
+ for (std::set<uint256>::iterator it = pto->setInventoryTxToSend.begin(); it != pto->setInventoryTxToSend.end(); it++) {
+ vInvTx.push_back(it);
+ }
+ CAmount filterrate = 0;
{
- pto->PushMessage(NetMsgType::INV, vInv);
- vInv.clear();
+ LOCK(pto->cs_feeFilter);
+ filterrate = pto->minFeeFilter;
+ }
+ // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
+ // A heap is used so that not all items need sorting if only a few are being sent.
+ CompareInvMempoolOrder compareInvMempoolOrder(&mempool);
+ std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
+ // No reason to drain out at many times the network's capacity,
+ // especially since we have many peers and some will draw much shorter delays.
+ unsigned int nRelayedTransactions = 0;
+ LOCK(pto->cs_filter);
+ while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
+ // Fetch the top element from the heap
+ std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
+ std::set<uint256>::iterator it = vInvTx.back();
+ vInvTx.pop_back();
+ uint256 hash = *it;
+ // Remove it from the to-be-sent set
+ pto->setInventoryTxToSend.erase(it);
+ // Check if not in the filter already
+ if (pto->filterInventoryKnown.contains(hash)) {
+ continue;
+ }
+ // Not in the mempool anymore? don't bother sending it.
+ CFeeRate feeRate;
+ if (!mempool.lookupFeeRate(hash, feeRate)) {
+ continue;
+ }
+ if (filterrate && feeRate.GetFeePerK() < filterrate) {
+ continue;
+ }
+ if (pto->pfilter) {
+ CTransaction tx;
+ if (!mempool.lookup(hash, tx)) continue;
+ if (!pto->pfilter->IsRelevantAndUpdate(tx)) continue;
+ }
+ // Send
+ vInv.push_back(CInv(MSG_TX, hash));
+ nRelayedTransactions++;
+ if (vInv.size() == MAX_INV_SZ) {
+ pto->PushMessage(NetMsgType::INV, vInv);
+ vInv.clear();
+ }
+ pto->filterInventoryKnown.insert(hash);
}
}
- pto->vInventoryToSend = vInvWait;
}
if (!vInv.empty())
pto->PushMessage(NetMsgType::INV, vInv);
diff --git a/src/main.h b/src/main.h
index 2c9635bcf2..f287171f14 100644
--- a/src/main.h
+++ b/src/main.h
@@ -99,9 +99,12 @@ static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
static const unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 24 * 60;
/** Average delay between peer address broadcasts in seconds. */
static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;
-/** Average delay between trickled inventory broadcasts in seconds.
- * Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */
-static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5;
+/** Average delay between trickled inventory transmissions in seconds.
+ * Blocks and whitelisted receivers bypass this, outbound peers get half this delay. */
+static const unsigned int INVENTORY_BROADCAST_INTERVAL = 5;
+/** Maximum number of inventory items to send per transmission.
+ * Limits the impact of low-fee transaction floods. */
+static const unsigned int INVENTORY_BROADCAST_MAX = 7 * INVENTORY_BROADCAST_INTERVAL;
/** Average delay between feefilter broadcasts in seconds. */
static const unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;
/** Maximum feefilter broadcast delay after significant change. */
@@ -209,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) */
@@ -292,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);
@@ -307,30 +310,6 @@ struct CNodeStateStats {
std::vector<int> vHeightInFlight;
};
-struct CDiskTxPos : public CDiskBlockPos
-{
- unsigned int nTxOffset; // after header
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(*(CDiskBlockPos*)this);
- READWRITE(VARINT(nTxOffset));
- }
-
- CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) {
- }
-
- CDiskTxPos() {
- SetNull();
- }
-
- void SetNull() {
- CDiskBlockPos::SetNull();
- nTxOffset = 0;
- }
-};
/**
@@ -359,7 +338,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks = NULL);
/** Apply the effects of this transaction on the UTXO set represented by view */
-void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight);
+void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
/** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
@@ -470,61 +449,6 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
-
-class CBlockFileInfo
-{
-public:
- unsigned int nBlocks; //!< number of blocks stored in file
- unsigned int nSize; //!< number of used bytes of block file
- unsigned int nUndoSize; //!< number of used bytes in the undo file
- unsigned int nHeightFirst; //!< lowest height of block in file
- unsigned int nHeightLast; //!< highest height of block in file
- uint64_t nTimeFirst; //!< earliest time of block in file
- uint64_t nTimeLast; //!< latest time of block in file
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(VARINT(nBlocks));
- READWRITE(VARINT(nSize));
- READWRITE(VARINT(nUndoSize));
- READWRITE(VARINT(nHeightFirst));
- READWRITE(VARINT(nHeightLast));
- READWRITE(VARINT(nTimeFirst));
- READWRITE(VARINT(nTimeLast));
- }
-
- void SetNull() {
- nBlocks = 0;
- nSize = 0;
- nUndoSize = 0;
- nHeightFirst = 0;
- nHeightLast = 0;
- nTimeFirst = 0;
- nTimeLast = 0;
- }
-
- CBlockFileInfo() {
- SetNull();
- }
-
- std::string ToString() const;
-
- /** update statistics (does not update nSize) */
- void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) {
- if (nBlocks==0 || nHeightFirst > nHeightIn)
- nHeightFirst = nHeightIn;
- if (nBlocks==0 || nTimeFirst > nTimeIn)
- nTimeFirst = nTimeIn;
- nBlocks++;
- if (nHeightIn > nHeightLast)
- nHeightLast = nHeightIn;
- if (nTimeIn > nTimeLast)
- nTimeLast = nTimeIn;
- }
-};
-
/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */
class CVerifyDB {
public:
@@ -540,7 +464,7 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex);
/** Remove invalidity status from a block and its descendants. */
-bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex);
+bool ResetBlockFailureFlags(CBlockIndex *pindex);
/** The currently-connected chain of blocks (protected by cs_main). */
extern CChain chainActive;
diff --git a/src/net.cpp b/src/net.cpp
index 1afe087be4..bbd23d292a 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;
@@ -78,7 +77,7 @@ bool fDiscover = true;
bool fListen = true;
uint64_t nLocalServices = NODE_NETWORK;
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 +87,17 @@ 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;
+std::map<uint256, CTransaction> mapRelay;
+std::deque<std::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 +131,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 +422,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 +459,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)));
@@ -467,9 +483,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 +540,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 +567,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 +832,24 @@ void SocketSendData(CNode *pnode)
pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it);
}
-static list<CNode*> vNodesDisconnected;
-
-class CNodeRef {
-public:
- CNodeRef(CNode *pnode) : _pnode(pnode) {
- LOCK(cs_vNodes);
- _pnode->AddRef();
- }
-
- ~CNodeRef() {
- LOCK(cs_vNodes);
- _pnode->Release();
- }
+static std::list<CNode*> vNodesDisconnected;
- 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 +862,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 +893,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 +904,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 +940,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 +964,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 +1059,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 +1083,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 +1134,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 +1145,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 +1212,7 @@ void ThreadSocketHandler()
//
// Service each socket
//
- vector<CNode*> vNodesCopy;
+ std::vector<CNode*> vNodesCopy;
{
LOCK(cs_vNodes);
vNodesCopy = vNodes;
@@ -1355,7 +1369,7 @@ void ThreadMapPort()
}
}
- string strDesc = "Bitcoin " + FormatFullVersion();
+ std::string strDesc = "Bitcoin " + FormatFullVersion();
try {
while (true) {
@@ -1441,7 +1455,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 +1464,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 +1522,7 @@ void DumpData()
void static ProcessOneShot()
{
- string strDest;
+ std::string strDest;
{
LOCK(cs_vOneShots);
if (vOneShots.empty())
@@ -1574,7 +1588,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 +1646,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 +1664,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 +1691,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);
@@ -1729,10 +1736,9 @@ void ThreadMessageHandler()
boost::mutex condition_mutex;
boost::unique_lock<boost::mutex> lock(condition_mutex);
- SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
while (true)
{
- vector<CNode*> vNodesCopy;
+ std::vector<CNode*> vNodesCopy;
{
LOCK(cs_vNodes);
vNodesCopy = vNodes;
@@ -1753,7 +1759,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())
@@ -1771,7 +1777,7 @@ void ThreadMessageHandler()
{
TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend)
- g_signals.SendMessages(pnode);
+ GetNodeSignals().SendMessages(pnode);
}
boost::this_thread::interruption_point();
}
@@ -1792,7 +1798,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;
@@ -1900,7 +1906,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)
@@ -1951,6 +1957,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();
}
@@ -2070,7 +2077,7 @@ public:
instance_of_cnetcleanup;
-void RelayTransaction(const CTransaction& tx, CFeeRate feerate)
+void RelayTransaction(const CTransaction& tx)
{
CInv inv(MSG_TX, tx.GetHash());
{
@@ -2088,20 +2095,7 @@ void RelayTransaction(const CTransaction& tx, CFeeRate feerate)
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
- if(!pnode->fRelayTxes)
- continue;
- {
- LOCK(pnode->cs_feeFilter);
- if (feerate.GetFeePerK() < pnode->minFeeFilter)
- continue;
- }
- LOCK(pnode->cs_filter);
- if (pnode->pfilter)
- {
- if (pnode->pfilter->IsRelevantAndUpdate(tx))
- pnode->PushInventory(inv);
- } else
- pnode->PushInventory(inv);
+ pnode->PushInventory(inv);
}
}
@@ -2313,7 +2307,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;
@@ -2334,6 +2328,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 ..
@@ -2347,6 +2346,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());
}
@@ -2387,6 +2388,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
hashContinue = uint256();
nStartingHeight = -1;
filterInventoryKnown.reset();
+ fSendMempool = false;
fGetAddr = false;
nNextLocalAddrSend = 0;
nNextAddrSend = 0;
@@ -2592,7 +2594,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;
@@ -2632,26 +2634,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 bf367684f6..998ee49260 100644
--- a/src/net.h
+++ b/src/net.h
@@ -83,7 +83,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();
@@ -357,7 +356,7 @@ public:
// a) it allows us to not relay tx invs before receiving the peer's version message
// b) the peer may tell us in its version message that we should not relay tx invs
// unless it loads a bloom filter.
- bool fRelayTxes;
+ bool fRelayTxes; //protected by cs_filter
bool fSentAddr;
CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter;
@@ -397,7 +396,13 @@ public:
// inventory based relay
CRollingBloomFilter filterInventoryKnown;
- std::vector<CInv> vInventoryToSend;
+ // Set of transaction ids we still have to announce.
+ // They are sorted by the mempool before relay, so the order is not important.
+ std::set<uint256> setInventoryTxToSend;
+ // List of block ids we still have announce.
+ // There is no final sorting before sending, as they are always sent immediately
+ // and in the order requested.
+ std::vector<uint256> vInventoryBlockToSend;
CCriticalSection cs_inventory;
std::set<uint256> setAskFor;
std::multimap<int64_t, CInv> mapAskFor;
@@ -405,6 +410,8 @@ public:
// Used for headers announcements - unfiltered blocks to relay
// Also protected by cs_inventory
std::vector<uint256> vBlockHashesToAnnounce;
+ // Used for BIP35 mempool sending, also protected by cs_inventory
+ bool fSendMempool;
// Ping time measurement:
// The pong reply we're expecting, or 0 if no pong expected.
@@ -517,11 +524,13 @@ public:
void PushInventory(const CInv& inv)
{
- {
- LOCK(cs_inventory);
- if (inv.type == MSG_TX && filterInventoryKnown.contains(inv.hash))
- return;
- vInventoryToSend.push_back(inv);
+ LOCK(cs_inventory);
+ if (inv.type == MSG_TX) {
+ if (!filterInventoryKnown.contains(inv.hash)) {
+ setInventoryTxToSend.insert(inv.hash);
+ }
+ } else if (inv.type == MSG_BLOCK) {
+ vInventoryBlockToSend.push_back(inv.hash);
}
}
@@ -773,7 +782,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
@@ -784,6 +793,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) */
@@ -797,8 +807,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/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/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 780a6c9709..6d50be56ec 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -26,6 +26,9 @@
#include <QScrollBar>
#include <QSettings>
#include <QTextDocument>
+#include <QTimer>
+
+#define SEND_CONFIRM_DELAY 3
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
@@ -121,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()));
}
}
@@ -311,10 +314,10 @@ void SendCoinsDialog::on_sendButton_clicked()
questionString.append(QString("<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span>")
.arg(alternativeUnits.join(" " + tr("or") + "<br />")));
- QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
- questionString.arg(formatted.join("<br />")),
- QMessageBox::Yes | QMessageBox::Cancel,
- QMessageBox::Cancel);
+ SendConfirmationDialog confirmationDialog(tr("Confirm send coins"),
+ questionString.arg(formatted.join("<br />")), SEND_CONFIRM_DELAY, this);
+ confirmationDialog.exec();
+ QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result();
if(retval != QMessageBox::Yes)
{
@@ -828,3 +831,45 @@ void SendCoinsDialog::coinControlUpdateLabels()
ui->labelCoinControlInsuffFunds->hide();
}
}
+
+SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int secDelay,
+ QWidget *parent) :
+ QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(secDelay)
+{
+ setDefaultButton(QMessageBox::Cancel);
+ yesButton = button(QMessageBox::Yes);
+ updateYesButton();
+ connect(&countDownTimer, SIGNAL(timeout()), this, SLOT(countDown()));
+}
+
+int SendConfirmationDialog::exec()
+{
+ updateYesButton();
+ countDownTimer.start(1000);
+ return QMessageBox::exec();
+}
+
+void SendConfirmationDialog::countDown()
+{
+ secDelay--;
+ updateYesButton();
+
+ if(secDelay <= 0)
+ {
+ countDownTimer.stop();
+ }
+}
+
+void SendConfirmationDialog::updateYesButton()
+{
+ if(secDelay > 0)
+ {
+ yesButton->setEnabled(false);
+ yesButton->setText(tr("Yes") + " (" + QString::number(secDelay) + ")");
+ }
+ else
+ {
+ yesButton->setEnabled(true);
+ yesButton->setText(tr("Yes"));
+ }
+}
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index ec171734fa..be4f2ee44b 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -8,7 +8,9 @@
#include "walletmodel.h"
#include <QDialog>
+#include <QMessageBox>
#include <QString>
+#include <QTimer>
class ClientModel;
class OptionsModel;
@@ -100,4 +102,24 @@ Q_SIGNALS:
void message(const QString &title, const QString &message, unsigned int style);
};
+
+
+class SendConfirmationDialog : public QMessageBox
+{
+ Q_OBJECT
+
+public:
+ SendConfirmationDialog(const QString &title, const QString &text, int secDelay = 0, QWidget *parent = 0);
+ int exec();
+
+private Q_SLOTS:
+ void countDown();
+ void updateYesButton();
+
+private:
+ QAbstractButton *yesButton;
+ QTimer countDownTimer;
+ int secDelay;
+};
+
#endif // BITCOIN_QT_SENDCOINSDIALOG_H
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 6960415e2e..cf3c73c4df 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -973,7 +973,6 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
std::string strHash = params[0].get_str();
uint256 hash(uint256S(strHash));
- CValidationState state;
{
LOCK(cs_main);
@@ -981,12 +980,11 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
CBlockIndex* pblockindex = mapBlockIndex[hash];
- ReconsiderBlock(state, pblockindex);
+ ResetBlockFailureFlags(pblockindex);
}
- if (state.IsValid()) {
- ActivateBestChain(state, Params());
- }
+ CValidationState state;
+ ActivateBestChain(state, Params());
if (!state.IsValid()) {
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index e8a099b445..09f5185781 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -366,6 +366,48 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
return (pubkey.GetID() == keyID);
}
+UniValue signmessagewithprivkey(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 2)
+ throw runtime_error(
+ "signmessagewithprivkey \"privkey\" \"message\"\n"
+ "\nSign a message with the private key of an address\n"
+ "\nArguments:\n"
+ "1. \"privkey\" (string, required) The private key to sign the message with.\n"
+ "2. \"message\" (string, required) The message to create a signature of.\n"
+ "\nResult:\n"
+ "\"signature\" (string) The signature of the message encoded in base 64\n"
+ "\nExamples:\n"
+ "\nCreate the signature\n"
+ + HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
+ "\nVerify the signature\n"
+ + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
+ "\nAs json rpc\n"
+ + HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
+ );
+
+ string strPrivkey = params[0].get_str();
+ string strMessage = params[1].get_str();
+
+ CBitcoinSecret vchSecret;
+ bool fGood = vchSecret.SetString(strPrivkey);
+ if (!fGood)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
+ CKey key = vchSecret.GetKey();
+ if (!key.IsValid())
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
+
+ CHashWriter ss(SER_GETHASH, 0);
+ ss << strMessageMagic;
+ ss << strMessage;
+
+ vector<unsigned char> vchSig;
+ if (!key.SignCompact(ss.GetHash(), vchSig))
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
+
+ return EncodeBase64(&vchSig[0], vchSig.size());
+}
+
UniValue setmocktime(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
@@ -404,6 +446,7 @@ static const CRPCCommand commands[] =
{ "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */
{ "util", "createmultisig", &createmultisig, true },
{ "util", "verifymessage", &verifymessage, true },
+ { "util", "signmessagewithprivkey", &signmessagewithprivkey, true },
/* Not shown in help */
{ "hidden", "setmocktime", &setmocktime, true },
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 320091b9c4..e09af89656 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -565,20 +565,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 +616,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..bec7ebe55f 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -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/scheduler.cpp b/src/scheduler.cpp
index 184ddc28ab..52777b61f9 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -79,6 +79,7 @@ void CScheduler::serviceQueue()
}
}
--nThreadsServicingQueue;
+ newTaskScheduled.notify_one();
}
void CScheduler::stop(bool drain)
diff --git a/src/script/script.h b/src/script/script.h
index 2a338d6f5c..a2941ce901 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -573,17 +573,26 @@ public:
int nFound = 0;
if (b.empty())
return nFound;
- iterator pc = begin();
+ CScript result;
+ iterator pc = begin(), pc2 = begin();
opcodetype opcode;
do
{
- while (end() - pc >= (long)b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
+ result.insert(result.end(), pc2, pc);
+ while (static_cast<size_t>(end() - pc) >= b.size() && std::equal(b.begin(), b.end(), pc))
{
- pc = erase(pc, pc + b.size());
+ pc = pc + b.size();
++nFound;
}
+ pc2 = pc;
}
while (GetOp(pc, opcode));
+
+ if (nFound > 0) {
+ result.insert(result.end(), pc2, end());
+ *this = result;
+ }
+
return nFound;
}
int Find(opcodetype op) const
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 9557000ddc..042fad42da 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -514,11 +514,14 @@ BOOST_AUTO_TEST_CASE(rolling_bloom)
if (i >= 100)
BOOST_CHECK(rb1.contains(data[i-100]));
rb1.insert(data[i]);
+ BOOST_CHECK(rb1.contains(data[i]));
}
// Insert 999 more random entries:
for (int i = 0; i < 999; i++) {
- rb1.insert(RandomData());
+ std::vector<unsigned char> d = RandomData();
+ rb1.insert(d);
+ BOOST_CHECK(rb1.contains(d));
}
// Sanity check to make sure the filter isn't just filling up:
nHits = 0;
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 129ce04e0b..e692326559 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -297,8 +297,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
CCoins &coins = result[tx.GetHash()];
coins.FromTx(tx, height);
- CValidationState dummy;
- UpdateCoins(tx, dummy, *(stack.back()), height);
+ UpdateCoins(tx, *(stack.back()), height);
}
// Once every 1000 iterations and at the end, verify the full cache.
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
index e75b7825ed..757d94b526 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"],
@@ -1820,5 +1822,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/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 9acd0e2430..aa12dfbd54 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -40,7 +40,6 @@ static void MicroSleep(uint64_t n)
#endif
}
-#if 0 /* Disabled for now because there is a race condition issue in this test - see #6540 */
BOOST_AUTO_TEST_CASE(manythreads)
{
seed_insecure_rand(false);
@@ -116,6 +115,5 @@ BOOST_AUTO_TEST_CASE(manythreads)
}
BOOST_CHECK_EQUAL(counterSum, 200);
}
-#endif
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index d42187f912..5e9711a4a7 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1051,4 +1051,121 @@ BOOST_AUTO_TEST_CASE(script_GetScriptAsm)
BOOST_CHECK_EQUAL(derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey));
}
+static CScript
+ScriptFromHex(const char* hex)
+{
+ std::vector<unsigned char> data = ParseHex(hex);
+ return CScript(data.begin(), data.end());
+}
+
+
+BOOST_AUTO_TEST_CASE(script_FindAndDelete)
+{
+ // Exercise the FindAndDelete functionality
+ CScript s;
+ CScript d;
+ CScript expect;
+
+ s = CScript() << OP_1 << OP_2;
+ d = CScript(); // delete nothing should be a no-op
+ expect = s;
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
+ BOOST_CHECK(s == expect);
+
+ s = CScript() << OP_1 << OP_2 << OP_3;
+ d = CScript() << OP_2;
+ expect = CScript() << OP_1 << OP_3;
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+
+ s = CScript() << OP_3 << OP_1 << OP_3 << OP_3 << OP_4 << OP_3;
+ d = CScript() << OP_3;
+ expect = CScript() << OP_1 << OP_4;
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 4);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("0302ff03"); // PUSH 0x02ff03 onto stack
+ d = ScriptFromHex("0302ff03");
+ expect = CScript();
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("0302ff030302ff03"); // PUSH 0x2ff03 PUSH 0x2ff03
+ d = ScriptFromHex("0302ff03");
+ expect = CScript();
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("0302ff030302ff03");
+ d = ScriptFromHex("02");
+ expect = s; // FindAndDelete matches entire opcodes
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("0302ff030302ff03");
+ d = ScriptFromHex("ff");
+ expect = s;
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
+ BOOST_CHECK(s == expect);
+
+ // This is an odd edge case: strip of the push-three-bytes
+ // prefix, leaving 02ff03 which is push-two-bytes:
+ s = ScriptFromHex("0302ff030302ff03");
+ d = ScriptFromHex("03");
+ expect = CScript() << ParseHex("ff03") << ParseHex("ff03");
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);
+ BOOST_CHECK(s == expect);
+
+ // Byte sequence that spans multiple opcodes:
+ s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY
+ d = ScriptFromHex("feed51");
+ expect = s;
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); // doesn't match 'inside' opcodes
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY
+ d = ScriptFromHex("02feed51");
+ expect = ScriptFromHex("69");
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("516902feed5169");
+ d = ScriptFromHex("feed51");
+ expect = s;
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("516902feed5169");
+ d = ScriptFromHex("02feed51");
+ expect = ScriptFromHex("516969");
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+
+ s = CScript() << OP_0 << OP_0 << OP_1 << OP_1;
+ d = CScript() << OP_0 << OP_1;
+ expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+
+ s = CScript() << OP_0 << OP_0 << OP_1 << OP_0 << OP_1 << OP_1;
+ d = CScript() << OP_0 << OP_1;
+ expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);
+ BOOST_CHECK(s == expect);
+
+ // Another weird edge case:
+ // End with invalid push (not enough data)...
+ s = ScriptFromHex("0003feed");
+ d = ScriptFromHex("03feed"); // ... can remove the invalid push
+ expect = ScriptFromHex("00");
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("0003feed");
+ d = ScriptFromHex("00");
+ expect = ScriptFromHex("03feed");
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+}
+
BOOST_AUTO_TEST_SUITE_END()
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/txdb.cpp b/src/txdb.cpp
index 5fbaeb608a..078c29def3 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -5,10 +5,8 @@
#include "txdb.h"
-#include "chain.h"
#include "chainparams.h"
#include "hash.h"
-#include "main.h"
#include "pow.h"
#include "uint256.h"
@@ -173,7 +171,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
return true;
}
-bool CBlockTreeDB::LoadBlockIndexGuts()
+bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex)
{
boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
@@ -187,8 +185,8 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
CDiskBlockIndex diskindex;
if (pcursor->GetValue(diskindex)) {
// Construct block index object
- CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
- pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
+ CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHash());
+ pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
pindexNew->nHeight = diskindex.nHeight;
pindexNew->nFile = diskindex.nFile;
pindexNew->nDataPos = diskindex.nDataPos;
diff --git a/src/txdb.h b/src/txdb.h
index 749802f0e5..ce3c39d7fe 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -8,15 +8,17 @@
#include "coins.h"
#include "dbwrapper.h"
+#include "chain.h"
#include <map>
#include <string>
#include <utility>
#include <vector>
-class CBlockFileInfo;
+#include <boost/function.hpp>
+
class CBlockIndex;
-struct CDiskTxPos;
+class CCoinsViewDBCursor;
class uint256;
//! -dbcache default (MiB)
@@ -26,7 +28,30 @@ static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024;
//! min. -dbcache in (MiB)
static const int64_t nMinDbCache = 4;
-class CCoinsViewDBCursor;
+struct CDiskTxPos : public CDiskBlockPos
+{
+ unsigned int nTxOffset; // after header
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(*(CDiskBlockPos*)this);
+ READWRITE(VARINT(nTxOffset));
+ }
+
+ CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) {
+ }
+
+ CDiskTxPos() {
+ SetNull();
+ }
+
+ void SetNull() {
+ CDiskBlockPos::SetNull();
+ nTxOffset = 0;
+ }
+};
/** CCoinsView backed by the coin database (chainstate/) */
class CCoinsViewDB : public CCoinsView
@@ -83,7 +108,7 @@ public:
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
bool WriteFlag(const std::string &name, bool fValue);
bool ReadFlag(const std::string &name, bool &fValue);
- bool LoadBlockIndexGuts();
+ bool LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex);
};
#endif // BITCOIN_TXDB_H
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 52c7793118..aa5df6ca4e 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -720,7 +720,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
else {
CValidationState state;
assert(CheckInputs(tx, state, mempoolDuplicate, false, 0, false, NULL));
- UpdateCoins(tx, state, mempoolDuplicate, 1000000);
+ UpdateCoins(tx, mempoolDuplicate, 1000000);
}
}
unsigned int stepsSinceLastRemove = 0;
@@ -734,7 +734,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
assert(stepsSinceLastRemove < waitingOnDependants.size());
} else {
assert(CheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, NULL));
- UpdateCoins(entry->GetTx(), state, mempoolDuplicate, 1000000);
+ UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000);
stepsSinceLastRemove = 0;
}
}
@@ -752,6 +752,31 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
assert(innerUsage == cachedInnerUsage);
}
+bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb)
+{
+ LOCK(cs);
+ indexed_transaction_set::const_iterator i = mapTx.find(hasha);
+ if (i == mapTx.end()) return false;
+ indexed_transaction_set::const_iterator j = mapTx.find(hashb);
+ if (j == mapTx.end()) return true;
+ uint64_t counta = i->GetCountWithAncestors();
+ uint64_t countb = j->GetCountWithAncestors();
+ if (counta == countb) {
+ return CompareTxMemPoolEntryByScore()(*i, *j);
+ }
+ return counta < countb;
+}
+
+namespace {
+class DepthAndScoreComparator
+{
+ CTxMemPool *mp;
+public:
+ DepthAndScoreComparator(CTxMemPool *mempool) : mp(mempool) {}
+ bool operator()(const uint256& a, const uint256& b) { return mp->CompareDepthAndScore(a, b); }
+};
+}
+
void CTxMemPool::queryHashes(vector<uint256>& vtxid)
{
vtxid.clear();
@@ -760,6 +785,8 @@ void CTxMemPool::queryHashes(vector<uint256>& vtxid)
vtxid.reserve(mapTx.size());
for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
vtxid.push_back(mi->GetTx().GetHash());
+
+ std::sort(vtxid.begin(), vtxid.end(), DepthAndScoreComparator(this));
}
bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
@@ -885,7 +912,7 @@ bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
return true;
}
-CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
+CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
// If an entry in the mempool exists, always return that one, as it's guaranteed to never
diff --git a/src/txmempool.h b/src/txmempool.h
index de4ba0b371..3e1d387975 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>,
@@ -511,6 +512,7 @@ public:
std::list<CTransaction>& conflicts, bool fCurrentEstimate = true);
void clear();
void _clear(); //lock free
+ bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);
void queryHashes(std::vector<uint256>& vtxid);
void pruneSpent(const uint256& hash, CCoins &coins);
unsigned int GetTransactionsUpdated() const;
@@ -672,10 +674,10 @@ private:
class CCoinsViewMemPool : public CCoinsViewBacked
{
protected:
- CTxMemPool &mempool;
+ const CTxMemPool& mempool;
public:
- CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn);
+ CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn);
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
};
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 00b75fbdbe..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 */
@@ -790,19 +790,6 @@ bool SetupNetworking()
return true;
}
-void SetThreadPriority(int nPriority)
-{
-#ifdef WIN32
- SetThreadPriority(GetCurrentThread(), nPriority);
-#else // WIN32
-#ifdef PRIO_THREAD
- setpriority(PRIO_THREAD, 0, nPriority);
-#else // PRIO_THREAD
- setpriority(PRIO_PROCESS, 0, nPriority);
-#endif // PRIO_THREAD
-#endif // WIN32
-}
-
int GetNumCores()
{
#if BOOST_VERSION >= 105600
diff --git a/src/util.h b/src/util.h
index 25c9b733e8..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;
@@ -208,7 +212,6 @@ std::string HelpMessageOpt(const std::string& option, const std::string& message
*/
int GetNumCores();
-void SetThreadPriority(int nPriority);
void RenameThread(const char* name);
/**
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 623037e766..27596929f1 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -2233,7 +2233,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 +2328,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 29d7138547..6b942e29d7 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -368,6 +368,7 @@ void CWallet::Flush(bool shutdown)
bool CWallet::Verify()
{
+ LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
LogPrintf("Using wallet %s\n", walletFile);
@@ -729,7 +730,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
// Write to disk
if (fInsertedNew || fUpdated)
- if (!wtx.WriteToDisk(pwalletdb))
+ if (!pwalletdb->WriteTx(wtx))
return false;
// Break debit/credit balance caches:
@@ -829,7 +830,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
wtx.nIndex = -1;
wtx.setAbandoned();
wtx.MarkDirty();
- wtx.WriteToDisk(&walletdb);
+ walletdb.WriteTx(wtx);
NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED);
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(hashTx, 0));
@@ -891,7 +892,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
wtx.nIndex = -1;
wtx.hashBlock = hashBlock;
wtx.MarkDirty();
- wtx.WriteToDisk(&walletdb);
+ walletdb.WriteTx(wtx);
// Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
while (iter != mapTxSpends.end() && iter->first.hash == now) {
@@ -1186,12 +1187,6 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived,
}
}
-
-bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb)
-{
- return pwalletdb->WriteTx(GetHash(), *this);
-}
-
/**
* Scan the block chain (starting in pindexStart) for transactions
* from or to us. If fUpdate is true, found transactions that already
@@ -1277,9 +1272,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;
}
}
@@ -3194,7 +3187,7 @@ bool CWallet::InitLoadWallet()
copyTo->fFromMe = copyFrom->fFromMe;
copyTo->strFromAccount = copyFrom->strFromAccount;
copyTo->nOrderPos = copyFrom->nOrderPos;
- copyTo->WriteToDisk(&walletdb);
+ walletdb.WriteTx(*copyTo);
}
}
}
@@ -3336,5 +3329,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 c3bd343edd..cc568c3749 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -394,8 +394,6 @@ public:
bool InMempool() const;
bool IsTrusted() const;
- bool WriteToDisk(CWalletDB *pwalletdb);
-
int64_t GetTxTime() const;
int GetRequestCount() const;
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index f2b5408e92..48579b2821 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -55,10 +55,10 @@ bool CWalletDB::ErasePurpose(const string& strPurpose)
return Erase(make_pair(string("purpose"), strPurpose));
}
-bool CWalletDB::WriteTx(uint256 hash, const CWalletTx& wtx)
+bool CWalletDB::WriteTx(const CWalletTx& wtx)
{
nWalletDBUpdated++;
- return Write(std::make_pair(std::string("tx"), hash), wtx);
+ return Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
}
bool CWalletDB::EraseTx(uint256 hash)
@@ -291,7 +291,7 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet)
if (pwtx)
{
- if (!WriteTx(pwtx->GetHash(), *pwtx))
+ if (!WriteTx(*pwtx))
return DB_LOAD_FAIL;
}
else
@@ -315,7 +315,7 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet)
// Since we're changing the order, write it back
if (pwtx)
{
- if (!WriteTx(pwtx->GetHash(), *pwtx))
+ if (!WriteTx(*pwtx))
return DB_LOAD_FAIL;
}
else
@@ -698,7 +698,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade)
- WriteTx(hash, pwallet->mapWallet[hash]);
+ WriteTx(pwallet->mapWallet[hash]);
// Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index fe6c366343..5345c0907e 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -87,7 +87,7 @@ public:
bool WritePurpose(const std::string& strAddress, const std::string& purpose);
bool ErasePurpose(const std::string& strAddress);
- bool WriteTx(uint256 hash, const CWalletTx& wtx);
+ bool WriteTx(const CWalletTx& wtx);
bool EraseTx(uint256 hash);
bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta);