diff options
Diffstat (limited to 'src')
55 files changed, 411 insertions, 175 deletions
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 13c27299f8..748c5b7887 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -27,7 +27,7 @@ bench_bench_bitcoin_SOURCES = \ bench/lockedpool.cpp \ bench/perf.cpp \ bench/perf.h \ - bench/prevector_destructor.cpp + bench/prevector.cpp nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES) diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp index 06d2abeac6..6f438b60e9 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -37,11 +37,6 @@ static void CoinSelection(benchmark::State& state) LOCK(wallet.cs_wallet); while (state.KeepRunning()) { - // Empty wallet. - for (COutput output : vCoins) - delete output.tx; - vCoins.clear(); - // Add coins. for (int i = 0; i < 1000; i++) addCoin(1000 * COIN, wallet, vCoins); @@ -53,6 +48,12 @@ static void CoinSelection(benchmark::State& state) assert(success); assert(nValueRet == 1003 * COIN); assert(setCoinsRet.size() == 2); + + // Empty wallet. + for (COutput& output : vCoins) { + delete output.tx; + } + vCoins.clear(); } } diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp new file mode 100644 index 0000000000..d0f28d1a3e --- /dev/null +++ b/src/bench/prevector.cpp @@ -0,0 +1,77 @@ +// Copyright (c) 2015-2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <compat.h> +#include <prevector.h> + +#include <bench/bench.h> + +struct nontrivial_t { + int x; + nontrivial_t() :x(-1) {} +}; +static_assert(!IS_TRIVIALLY_CONSTRUCTIBLE<nontrivial_t>::value, + "expected nontrivial_t to not be trivially constructible"); + +typedef unsigned char trivial_t; +static_assert(IS_TRIVIALLY_CONSTRUCTIBLE<trivial_t>::value, + "expected trivial_t to be trivially constructible"); + +template <typename T> +static void PrevectorDestructor(benchmark::State& state) +{ + while (state.KeepRunning()) { + for (auto x = 0; x < 1000; ++x) { + prevector<28, T> t0; + prevector<28, T> t1; + t0.resize(28); + t1.resize(29); + } + } +} + +template <typename T> +static void PrevectorClear(benchmark::State& state) +{ + + while (state.KeepRunning()) { + for (auto x = 0; x < 1000; ++x) { + prevector<28, T> t0; + prevector<28, T> t1; + t0.resize(28); + t0.clear(); + t1.resize(29); + t0.clear(); + } + } +} + +template <typename T> +void PrevectorResize(benchmark::State& state) +{ + while (state.KeepRunning()) { + prevector<28, T> t0; + prevector<28, T> t1; + for (auto x = 0; x < 1000; ++x) { + t0.resize(28); + t0.resize(0); + t1.resize(29); + t1.resize(0); + } + } +} + +#define PREVECTOR_TEST(name, nontrivops, trivops) \ + static void Prevector ## name ## Nontrivial(benchmark::State& state) { \ + PrevectorResize<nontrivial_t>(state); \ + } \ + BENCHMARK(Prevector ## name ## Nontrivial, nontrivops); \ + static void Prevector ## name ## Trivial(benchmark::State& state) { \ + PrevectorResize<trivial_t>(state); \ + } \ + BENCHMARK(Prevector ## name ## Trivial, trivops); + +PREVECTOR_TEST(Clear, 28300, 88600) +PREVECTOR_TEST(Destructor, 28800, 88900) +PREVECTOR_TEST(Resize, 28900, 90300) diff --git a/src/bench/prevector_destructor.cpp b/src/bench/prevector_destructor.cpp deleted file mode 100644 index 39d0ee5eb1..0000000000 --- a/src/bench/prevector_destructor.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2015-2017 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include <bench/bench.h> -#include <prevector.h> - -static void PrevectorDestructor(benchmark::State& state) -{ - while (state.KeepRunning()) { - for (auto x = 0; x < 1000; ++x) { - prevector<28, unsigned char> t0; - prevector<28, unsigned char> t1; - t0.resize(28); - t1.resize(29); - } - } -} - -static void PrevectorClear(benchmark::State& state) -{ - - while (state.KeepRunning()) { - for (auto x = 0; x < 1000; ++x) { - prevector<28, unsigned char> t0; - prevector<28, unsigned char> t1; - t0.resize(28); - t0.clear(); - t1.resize(29); - t0.clear(); - } - } -} - -BENCHMARK(PrevectorDestructor, 5700); -BENCHMARK(PrevectorClear, 5600); diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 6eb223171f..c2b3480f9d 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -175,6 +175,9 @@ public: // (the tx=... number in the SetBestChain debug.log lines) 3.5 // * estimated number of transactions per second after that timestamp }; + + /* disable fallback fee on mainnet */ + m_fallback_fee_enabled = false; } }; @@ -266,6 +269,8 @@ public: 0.09 }; + /* enable fallback fee on testnet */ + m_fallback_fee_enabled = true; } }; @@ -343,6 +348,9 @@ public: base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94}; bech32_hrp = "bcrt"; + + /* enable fallback fee on regtest */ + m_fallback_fee_enabled = true; } }; diff --git a/src/chainparams.h b/src/chainparams.h index d478da9891..6b1f813afb 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -65,6 +65,8 @@ public: bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } /** Return the BIP70 network string (main, test or regtest) */ std::string NetworkIDString() const { return strNetworkID; } + /** Return true if the fallback fee is by default enabled for this network */ + bool IsFallbackFeeEnabled() const { return m_fallback_fee_enabled; } /** Return the list of hostnames to look up for DNS seeds */ const std::vector<std::string>& DNSSeeds() const { return vSeeds; } const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } @@ -91,6 +93,7 @@ protected: bool fMineBlocksOnDemand; CCheckpointData checkpointData; ChainTxData chainTxData; + bool m_fallback_fee_enabled; }; /** diff --git a/src/compat.h b/src/compat.h index aae84b1181..8a0f901304 100644 --- a/src/compat.h +++ b/src/compat.h @@ -10,6 +10,16 @@ #include <config/bitcoin-config.h> #endif +#include <type_traits> + +// GCC 4.8 is missing some C++11 type_traits, +// https://www.gnu.org/software/gcc/gcc-5/changes.html +#if defined(__GNUC__) && __GNUC__ < 5 +#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivial +#else +#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivially_constructible +#endif + #ifdef WIN32 #ifdef _WIN32_WINNT #undef _WIN32_WINNT diff --git a/src/crypto/common.h b/src/crypto/common.h index 825b430978..6e9d6dc82a 100644 --- a/src/crypto/common.h +++ b/src/crypto/common.h @@ -82,12 +82,12 @@ void static inline WriteBE64(unsigned char* ptr, uint64_t x) /** Return the smallest number n such that (x >> n) == 0 (or 64 if the highest bit in x is set. */ uint64_t static inline CountBits(uint64_t x) { -#ifdef HAVE_DECL___BUILTIN_CLZL +#if HAVE_DECL___BUILTIN_CLZL if (sizeof(unsigned long) >= sizeof(uint64_t)) { return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0; } #endif -#ifdef HAVE_DECL___BUILTIN_CLZLL +#if HAVE_DECL___BUILTIN_CLZLL if (sizeof(unsigned long long) >= sizeof(uint64_t)) { return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0; } diff --git a/src/init.cpp b/src/init.cpp index 5c5d1ee792..47bcdf2294 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -448,6 +448,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)); strUsage += HelpMessageOpt("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)"); + strUsage += HelpMessageOpt("-addrmantest", "Allows to test address relay on localhost"); } strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " + _("If <category> is not supplied or if <category> = 1, output all debugging information.") + " " + _("<category> can be:") + " " + ListLogCategories() + "."); @@ -490,7 +491,8 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY)); strUsage += HelpMessageGroup(_("Block creation options:")); - strUsage += HelpMessageOpt("-blockmaxsize=<n>", _("Set maximum BIP141 block weight to this * 4. Deprecated, use blockmaxweight")); + if (showDebug) + strUsage += HelpMessageOpt("-blockmaxsize=<n>", "Set maximum BIP141 block weight to this * 4. Deprecated, use blockmaxweight"); strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT)); strUsage += HelpMessageOpt("-blockmintxfee=<amt>", strprintf(_("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE))); if (showDebug) diff --git a/src/leveldb/db/db_impl.cc b/src/leveldb/db/db_impl.cc index f43ad76794..3bb58e560a 100644 --- a/src/leveldb/db/db_impl.cc +++ b/src/leveldb/db/db_impl.cc @@ -414,7 +414,7 @@ Status DBImpl::RecoverLogFile(uint64_t log_number, bool last_log, status.ok()) { if (record.size() < 12) { reporter.Corruption( - record.size(), Status::Corruption("log record too small")); + record.size(), Status::Corruption("log record too small", fname)); continue; } WriteBatchInternal::SetContents(&batch, record); diff --git a/src/leveldb/db/leveldbutil.cc b/src/leveldb/db/leveldbutil.cc index 9f4b7dd70c..d06d64d640 100644 --- a/src/leveldb/db/leveldbutil.cc +++ b/src/leveldb/db/leveldbutil.cc @@ -19,6 +19,7 @@ class StdoutPrinter : public WritableFile { virtual Status Close() { return Status::OK(); } virtual Status Flush() { return Status::OK(); } virtual Status Sync() { return Status::OK(); } + virtual std::string GetName() const { return "[stdout]"; } }; bool HandleDumpCommand(Env* env, char** files, int num) { diff --git a/src/leveldb/db/log_reader.cc b/src/leveldb/db/log_reader.cc index a6d304545d..8b6ad136d7 100644 --- a/src/leveldb/db/log_reader.cc +++ b/src/leveldb/db/log_reader.cc @@ -186,7 +186,7 @@ uint64_t Reader::LastRecordOffset() { } void Reader::ReportCorruption(uint64_t bytes, const char* reason) { - ReportDrop(bytes, Status::Corruption(reason)); + ReportDrop(bytes, Status::Corruption(reason, file_->GetName())); } void Reader::ReportDrop(uint64_t bytes, const Status& reason) { diff --git a/src/leveldb/db/repair.cc b/src/leveldb/db/repair.cc index 4cd4bb047f..7281e3d345 100644 --- a/src/leveldb/db/repair.cc +++ b/src/leveldb/db/repair.cc @@ -203,7 +203,7 @@ class Repairer { while (reader.ReadRecord(&record, &scratch)) { if (record.size() < 12) { reporter.Corruption( - record.size(), Status::Corruption("log record too small")); + record.size(), Status::Corruption("log record too small", logname)); continue; } WriteBatchInternal::SetContents(&batch, record); diff --git a/src/leveldb/helpers/memenv/memenv.cc b/src/leveldb/helpers/memenv/memenv.cc index 9a98884daf..68c0614a59 100644 --- a/src/leveldb/helpers/memenv/memenv.cc +++ b/src/leveldb/helpers/memenv/memenv.cc @@ -176,6 +176,7 @@ class SequentialFileImpl : public SequentialFile { return Status::OK(); } + virtual std::string GetName() const { return "[memenv]"; } private: FileState* file_; uint64_t pos_; @@ -196,6 +197,7 @@ class RandomAccessFileImpl : public RandomAccessFile { return file_->Read(offset, n, result, scratch); } + virtual std::string GetName() const { return "[memenv]"; } private: FileState* file_; }; @@ -218,6 +220,7 @@ class WritableFileImpl : public WritableFile { virtual Status Flush() { return Status::OK(); } virtual Status Sync() { return Status::OK(); } + virtual std::string GetName() const { return "[memenv]"; } private: FileState* file_; }; diff --git a/src/leveldb/include/leveldb/env.h b/src/leveldb/include/leveldb/env.h index 99b6c21414..275d441eae 100644 --- a/src/leveldb/include/leveldb/env.h +++ b/src/leveldb/include/leveldb/env.h @@ -191,6 +191,9 @@ class SequentialFile { // REQUIRES: External synchronization virtual Status Skip(uint64_t n) = 0; + // Get a name for the file, only for error reporting + virtual std::string GetName() const = 0; + private: // No copying allowed SequentialFile(const SequentialFile&); @@ -215,6 +218,9 @@ class RandomAccessFile { virtual Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const = 0; + // Get a name for the file, only for error reporting + virtual std::string GetName() const = 0; + private: // No copying allowed RandomAccessFile(const RandomAccessFile&); @@ -234,6 +240,9 @@ class WritableFile { virtual Status Flush() = 0; virtual Status Sync() = 0; + // Get a name for the file, only for error reporting + virtual std::string GetName() const = 0; + private: // No copying allowed WritableFile(const WritableFile&); diff --git a/src/leveldb/table/format.cc b/src/leveldb/table/format.cc index 24e4e02445..285e1c0de3 100644 --- a/src/leveldb/table/format.cc +++ b/src/leveldb/table/format.cc @@ -82,7 +82,7 @@ Status ReadBlock(RandomAccessFile* file, } if (contents.size() != n + kBlockTrailerSize) { delete[] buf; - return Status::Corruption("truncated block read"); + return Status::Corruption("truncated block read", file->GetName()); } // Check the crc of the type and the block contents @@ -92,7 +92,7 @@ Status ReadBlock(RandomAccessFile* file, const uint32_t actual = crc32c::Value(data, n + 1); if (actual != crc) { delete[] buf; - s = Status::Corruption("block checksum mismatch"); + s = Status::Corruption("block checksum mismatch", file->GetName()); return s; } } @@ -119,13 +119,13 @@ Status ReadBlock(RandomAccessFile* file, size_t ulength = 0; if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) { delete[] buf; - return Status::Corruption("corrupted compressed block contents"); + return Status::Corruption("corrupted compressed block contents", file->GetName()); } char* ubuf = new char[ulength]; if (!port::Snappy_Uncompress(data, n, ubuf)) { delete[] buf; delete[] ubuf; - return Status::Corruption("corrupted compressed block contents"); + return Status::Corruption("corrupted compressed block contents", file->GetName()); } delete[] buf; result->data = Slice(ubuf, ulength); @@ -135,7 +135,7 @@ Status ReadBlock(RandomAccessFile* file, } default: delete[] buf; - return Status::Corruption("bad block type"); + return Status::Corruption("bad block type", file->GetName()); } return Status::OK(); diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc index dd852af354..4676bc2240 100644 --- a/src/leveldb/util/env_posix.cc +++ b/src/leveldb/util/env_posix.cc @@ -121,6 +121,8 @@ class PosixSequentialFile: public SequentialFile { } return Status::OK(); } + + virtual std::string GetName() const { return filename_; } }; // pread() based random-access @@ -172,6 +174,8 @@ class PosixRandomAccessFile: public RandomAccessFile { } return s; } + + virtual std::string GetName() const { return filename_; } }; // mmap() based random-access @@ -206,6 +210,8 @@ class PosixMmapReadableFile: public RandomAccessFile { } return s; } + + virtual std::string GetName() const { return filename_; } }; class PosixWritableFile : public WritableFile { @@ -287,6 +293,8 @@ class PosixWritableFile : public WritableFile { } return s; } + + virtual std::string GetName() const { return filename_; } }; static int LockOrUnlock(int fd, bool lock) { diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc index d32c4e676c..81380216bb 100644 --- a/src/leveldb/util/env_win.cc +++ b/src/leveldb/util/env_win.cc @@ -78,6 +78,7 @@ public: virtual Status Read(size_t n, Slice* result, char* scratch); virtual Status Skip(uint64_t n); BOOL isEnable(); + virtual std::string GetName() const { return _filename; } private: BOOL _Init(); void _CleanUp(); @@ -94,6 +95,7 @@ public: virtual ~Win32RandomAccessFile(); virtual Status Read(uint64_t offset, size_t n, Slice* result,char* scratch) const; BOOL isEnable(); + virtual std::string GetName() const { return _filename; } private: BOOL _Init(LPCWSTR path); void _CleanUp(); @@ -114,6 +116,7 @@ public: virtual Status Flush(); virtual Status Sync(); BOOL isEnable(); + virtual std::string GetName() const { return filename_; } private: std::string filename_; ::HANDLE _hFile; diff --git a/src/miner.cpp b/src/miner.cpp index dda52790c6..fcb376c6cb 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -30,12 +30,6 @@ #include <queue> #include <utility> -////////////////////////////////////////////////////////////////////////////// -// -// BitcoinMiner -// - -// // Unconfirmed transactions in the memory pool often depend on other // transactions in the memory pool. When we select transactions from the // pool, we select by highest fee rate of a transaction combined with all diff --git a/src/net.cpp b/src/net.cpp index 201914685c..c7c19f83a1 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -181,6 +181,10 @@ void AdvertiseLocal(CNode *pnode) if (fListen && pnode->fSuccessfullyConnected) { CAddress addrLocal = GetLocalAddress(&pnode->addr, pnode->GetLocalServices()); + if (gArgs.GetBoolArg("-addrmantest", false)) { + // use IPv4 loopback during addrmantest + addrLocal = CAddress(CService(LookupNumeric("127.0.0.1", GetListenPort())), pnode->GetLocalServices()); + } // If discovery is enabled, sometimes give our peer the address it // tells us that it sees us as in case it has a better idea of our // address than we do. @@ -189,7 +193,7 @@ void AdvertiseLocal(CNode *pnode) { addrLocal.SetIP(pnode->GetAddrLocal()); } - if (addrLocal.IsRoutable()) + if (addrLocal.IsRoutable() || gArgs.GetBoolArg("-addrmantest", false)) { LogPrint(BCLog::NET, "AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); FastRandomContext insecure_rand; @@ -2718,6 +2722,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn fOneShot = false; m_manual_connection = false; fClient = false; // set by version message + m_limited_node = false; // set by version message fFeeler = false; fSuccessfullyConnected = false; fDisconnect = false; @@ -641,6 +641,7 @@ public: bool fOneShot; bool m_manual_connection; bool fClient; + bool m_limited_node; //after BIP159 const bool fInbound; std::atomic_bool fSuccessfullyConnected; std::atomic_bool fDisconnect; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index bf9307727a..ddf0dbbbea 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -892,6 +892,7 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB const int nNewHeight = pindexNew->nHeight; connman->SetBestHeight(nNewHeight); + SetServiceFlagsIBDCache(!fInitialDownload); if (!fInitialDownload) { // Find the hashes of all blocks that weren't previously in the best chain. std::vector<uint256> vHashes; @@ -1642,7 +1643,13 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->cleanSubVer = cleanSubVer; } pfrom->nStartingHeight = nStartingHeight; - pfrom->fClient = !(nServices & NODE_NETWORK); + + // set nodes not relaying blocks and tx and not serving (parts) of the historical blockchain as "clients" + pfrom->fClient = (!(nServices & NODE_NETWORK) && !(nServices & NODE_NETWORK_LIMITED)); + + // set nodes not capable of serving the complete blockchain history as "limited nodes" + pfrom->m_limited_node = (!(nServices & NODE_NETWORK) && (nServices & NODE_NETWORK_LIMITED)); + { LOCK(pfrom->cs_filter); pfrom->fRelayTxes = fRelay; // set to true after we get the first filter* message @@ -1801,7 +1808,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // We only bother storing full nodes, though this may include // things which we would not make an outbound connection to, in // part because we may make feeler connections to them. - if (!MayHaveUsefulAddressDB(addr.nServices)) + if (!MayHaveUsefulAddressDB(addr.nServices) && !HasAllDesirableServiceFlags(addr.nServices)) continue; if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) @@ -3611,7 +3618,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic<bool>& interruptM // Message: getdata (blocks) // std::vector<CInv> vGetData; - if (!pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + if (!pto->fClient && ((fFetch && !pto->m_limited_node) || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { std::vector<const CBlockIndex*> vToDownload; NodeId staller = -1; FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams); diff --git a/src/netbase.cpp b/src/netbase.cpp index 5be3fe34f8..3ea3141d5e 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -139,7 +139,7 @@ bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, if (pszName[0] == 0) return false; int port = portDefault; - std::string hostname = ""; + std::string hostname; SplitHostPort(std::string(pszName), port, hostname); std::vector<CNetAddr> vIP; diff --git a/src/prevector.h b/src/prevector.h index f8d6a09145..103ead82cc 100644 --- a/src/prevector.h +++ b/src/prevector.h @@ -10,9 +10,12 @@ #include <stdint.h> #include <string.h> +#include <cstddef> #include <iterator> #include <type_traits> +#include <compat.h> + #pragma pack(push, 1) /** Implements a drop-in replacement for std::vector<T> which stores up to N * elements directly (without heap allocation). The types Size and Diff are @@ -194,16 +197,42 @@ private: T* item_ptr(difference_type pos) { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } + void fill(T* dst, ptrdiff_t count) { + if (IS_TRIVIALLY_CONSTRUCTIBLE<T>::value) { + // The most common use of prevector is where T=unsigned char. For + // trivially constructible types, we can use memset() to avoid + // looping. + ::memset(dst, 0, count * sizeof(T)); + } else { + for (auto i = 0; i < count; ++i) { + new(static_cast<void*>(dst + i)) T(); + } + } + } + + void fill(T* dst, ptrdiff_t count, const T& value) { + for (auto i = 0; i < count; ++i) { + new(static_cast<void*>(dst + i)) T(value); + } + } + + template<typename InputIterator> + void fill(T* dst, InputIterator first, InputIterator last) { + while (first != last) { + new(static_cast<void*>(dst)) T(*first); + ++dst; + ++first; + } + } + public: void assign(size_type n, const T& val) { clear(); if (capacity() < n) { change_capacity(n); } - while (size() < n) { - _size++; - new(static_cast<void*>(item_ptr(size() - 1))) T(val); - } + _size += n; + fill(item_ptr(0), n, val); } template<typename InputIterator> @@ -213,11 +242,8 @@ public: if (capacity() < n) { change_capacity(n); } - while (first != last) { - _size++; - new(static_cast<void*>(item_ptr(size() - 1))) T(*first); - ++first; - } + _size += n; + fill(item_ptr(0), first, last); } prevector() : _size(0), _union{{}} {} @@ -228,31 +254,23 @@ public: explicit prevector(size_type n, const T& val = T()) : _size(0) { change_capacity(n); - while (size() < n) { - _size++; - new(static_cast<void*>(item_ptr(size() - 1))) T(val); - } + _size += n; + fill(item_ptr(0), n, val); } template<typename InputIterator> prevector(InputIterator first, InputIterator last) : _size(0) { size_type n = last - first; change_capacity(n); - while (first != last) { - _size++; - new(static_cast<void*>(item_ptr(size() - 1))) T(*first); - ++first; - } + _size += n; + fill(item_ptr(0), first, last); } prevector(const prevector<N, T, Size, Diff>& other) : _size(0) { - change_capacity(other.size()); - const_iterator it = other.begin(); - while (it != other.end()) { - _size++; - new(static_cast<void*>(item_ptr(size() - 1))) T(*it); - ++it; - } + size_type n = other.size(); + change_capacity(n); + _size += n; + fill(item_ptr(0), other.begin(), other.end()); } prevector(prevector<N, T, Size, Diff>&& other) : _size(0) { @@ -263,14 +281,7 @@ public: if (&other == this) { return *this; } - resize(0); - change_capacity(other.size()); - const_iterator it = other.begin(); - while (it != other.end()) { - _size++; - new(static_cast<void*>(item_ptr(size() - 1))) T(*it); - ++it; - } + assign(other.begin(), other.end()); return *this; } @@ -314,16 +325,20 @@ public: } void resize(size_type new_size) { - if (size() > new_size) { + size_type cur_size = size(); + if (cur_size == new_size) { + return; + } + if (cur_size > new_size) { erase(item_ptr(new_size), end()); + return; } if (new_size > capacity()) { change_capacity(new_size); } - while (size() < new_size) { - _size++; - new(static_cast<void*>(item_ptr(size() - 1))) T(); - } + ptrdiff_t increase = new_size - cur_size; + fill(item_ptr(cur_size), increase); + _size += increase; } void reserve(size_type new_capacity) { @@ -346,10 +361,11 @@ public: if (capacity() < new_size) { change_capacity(new_size + (new_size >> 1)); } - memmove(item_ptr(p + 1), item_ptr(p), (size() - p) * sizeof(T)); + T* ptr = item_ptr(p); + memmove(ptr + 1, ptr, (size() - p) * sizeof(T)); _size++; - new(static_cast<void*>(item_ptr(p))) T(value); - return iterator(item_ptr(p)); + new(static_cast<void*>(ptr)) T(value); + return iterator(ptr); } void insert(iterator pos, size_type count, const T& value) { @@ -358,11 +374,10 @@ public: if (capacity() < new_size) { change_capacity(new_size + (new_size >> 1)); } - memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T)); + T* ptr = item_ptr(p); + memmove(ptr + count, ptr, (size() - p) * sizeof(T)); _size += count; - for (size_type i = 0; i < count; i++) { - new(static_cast<void*>(item_ptr(p + i))) T(value); - } + fill(item_ptr(p), count, value); } template<typename InputIterator> @@ -373,13 +388,10 @@ public: if (capacity() < new_size) { change_capacity(new_size + (new_size >> 1)); } - memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T)); + T* ptr = item_ptr(p); + memmove(ptr + count, ptr, (size() - p) * sizeof(T)); _size += count; - while (first != last) { - new(static_cast<void*>(item_ptr(p))) T(*first); - ++p; - ++first; - } + fill(ptr, first, last); } iterator erase(iterator pos) { diff --git a/src/protocol.cpp b/src/protocol.cpp index c412ad9ffe..2ec26fbd3e 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -12,6 +12,8 @@ # include <arpa/inet.h> #endif +static std::atomic<bool> g_initial_block_download_completed(false); + namespace NetMsgType { const char *VERSION="version"; const char *VERACK="verack"; @@ -127,6 +129,17 @@ bool CMessageHeader::IsValid(const MessageStartChars& pchMessageStartIn) const } +ServiceFlags GetDesirableServiceFlags(ServiceFlags services) { + if ((services & NODE_NETWORK_LIMITED) && g_initial_block_download_completed) { + return ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS); + } + return ServiceFlags(NODE_NETWORK | NODE_WITNESS); +} + +void SetServiceFlagsIBDCache(bool state) { + g_initial_block_download_completed = state; +} + CAddress::CAddress() : CService() { diff --git a/src/protocol.h b/src/protocol.h index 42eb57e4f0..e518d11944 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -15,6 +15,7 @@ #include <uint256.h> #include <version.h> +#include <atomic> #include <stdint.h> #include <string> @@ -301,9 +302,10 @@ enum ServiceFlags : uint64_t { * If the NODE_NONE return value is changed, contrib/seeds/makeseeds.py * should be updated appropriately to filter for the same nodes. */ -static ServiceFlags GetDesirableServiceFlags(ServiceFlags services) { - return ServiceFlags(NODE_NETWORK | NODE_WITNESS); -} +ServiceFlags GetDesirableServiceFlags(ServiceFlags services); + +/** Set the current IBD status in order to figure out the desirable service flags */ +void SetServiceFlagsIBDCache(bool status); /** * A shortcut for (services & GetDesirableServiceFlags(services)) @@ -316,10 +318,10 @@ static inline bool HasAllDesirableServiceFlags(ServiceFlags services) { /** * Checks if a peer with the given service flags may be capable of having a - * robust address-storage DB. Currently an alias for checking NODE_NETWORK. + * robust address-storage DB. */ static inline bool MayHaveUsefulAddressDB(ServiceFlags services) { - return services & NODE_NETWORK; + return (services & NODE_NETWORK) || (services & NODE_NETWORK_LIMITED); } /** A CService with information about it as peer */ diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 06e1f1a37c..ab381bfb5d 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -29,6 +29,7 @@ #include <init.h> #include <rpc/server.h> #include <ui_interface.h> +#include <uint256.h> #include <util.h> #include <warnings.h> @@ -80,6 +81,7 @@ Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); // Declare meta types used for QMetaObject::invokeMethod Q_DECLARE_METATYPE(bool*) Q_DECLARE_METATYPE(CAmount) +Q_DECLARE_METATYPE(uint256) static void InitMessage(const std::string &message) { diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 3642e5d4d4..eaf2896bc3 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -138,9 +138,9 @@ size_t ClientModel::getMempoolDynamicUsage() const double ClientModel::getVerificationProgress(const CBlockIndex *tipIn) const { CBlockIndex *tip = const_cast<CBlockIndex *>(tipIn); + LOCK(cs_main); if (!tip) { - LOCK(cs_main); tip = chainActive.Tip(); } return GuessVerificationProgress(Params().TxData(), tip); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 871822ccb4..ef36aab1a4 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -369,6 +369,7 @@ void SendCoinsDialog::on_sendButton_clicked() accept(); CoinControlDialog::coinControl()->UnSelectAll(); coinControlUpdateLabels(); + Q_EMIT coinsSent(currentTransaction.getTransaction()->GetHash()); } fNewRecipientAllowed = true; } diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 7c27785d12..48885bbcad 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -54,6 +54,9 @@ public Q_SLOTS: void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); +Q_SIGNALS: + void coinsSent(const uint256& txid); + private: Ui::SendCoinsDialog *ui; ClientModel *clientModel; diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index c1d28be0ab..6f30e56327 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -17,6 +17,7 @@ #include <util.h> #include <wallet/db.h> #include <wallet/wallet.h> +#include <policy/policy.h> #include <stdint.h> #include <string> @@ -241,6 +242,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxID() + "<br>"; strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.tx->GetTotalSize()) + " bytes<br>"; + strHTML += "<b>" + tr("Transaction virtual size") + ":</b> " + QString::number(GetVirtualTransactionSize(*wtx.tx)) + " bytes<br>"; strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>"; // Message from normal bitcoin:URI (bitcoin:123...?message=example) diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 88f8f463bc..006f9fe443 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -263,8 +263,7 @@ void TransactionView::setModel(WalletModel *_model) void TransactionView::chooseDate(int idx) { - if(!transactionProxyModel) - return; + if (!transactionProxyModel) return; QDate current = QDate::currentDate(); dateRangeWidget->setVisible(false); switch(dateWidget->itemData(idx).toInt()) @@ -592,6 +591,32 @@ void TransactionView::focusTransaction(const QModelIndex &idx) transactionView->setFocus(); } +void TransactionView::focusTransaction(const uint256& txid) +{ + if (!transactionProxyModel) + return; + + const QModelIndexList results = this->model->getTransactionTableModel()->match( + this->model->getTransactionTableModel()->index(0,0), + TransactionTableModel::TxHashRole, + QString::fromStdString(txid.ToString()), -1); + + transactionView->setFocus(); + transactionView->selectionModel()->clearSelection(); + for (const QModelIndex& index : results) { + const QModelIndex targetIndex = transactionProxyModel->mapFromSource(index); + transactionView->selectionModel()->select( + targetIndex, + QItemSelectionModel::Rows | QItemSelectionModel::Select); + // Called once per destination to ensure all results are in view, unless + // transactions are not ordered by (ascending or descending) date. + transactionView->scrollTo(targetIndex); + // scrollTo() does not scroll far enough the first time when transactions + // are ordered by ascending date. + if (index == results[0]) transactionView->scrollTo(targetIndex); + } +} + // We override the virtual resizeEvent of the QWidget to adjust tables column // sizes as the tables width is proportional to the dialogs width. void TransactionView::resizeEvent(QResizeEvent* event) diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 82e929b53f..66dc5bc86b 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -7,6 +7,8 @@ #include <qt/guiutil.h> +#include <uint256.h> + #include <QWidget> #include <QKeyEvent> @@ -116,7 +118,7 @@ public Q_SLOTS: void changedSearch(); void exportClicked(); void focusTransaction(const QModelIndex&); - + void focusTransaction(const uint256& txid); }; #endif // BITCOIN_QT_TRANSACTIONVIEW_H diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 7eced9289d..64497a3431 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -68,6 +68,9 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent): connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex))); connect(overviewPage, SIGNAL(outOfSyncWarningClicked()), this, SLOT(requestedSyncWarningInfo())); + // Highlight transaction after send + connect(sendCoinsPage, SIGNAL(coinsSent(uint256)), transactionView, SLOT(focusTransaction(uint256))); + // Double-clicking on a transaction on the transaction history page shows details connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); @@ -91,6 +94,9 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui) // Clicking on a transaction on the overview page simply sends you to transaction history page connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), gui, SLOT(gotoHistoryPage())); + // Navigate to transaction history page after send + connect(sendCoinsPage, SIGNAL(coinsSent(uint256)), gui, SLOT(gotoHistoryPage())); + // Receive and report messages connect(this, SIGNAL(message(QString,QString,unsigned int)), gui, SLOT(message(QString,QString,unsigned int))); diff --git a/src/rest.cpp b/src/rest.cpp index eeeb3f5141..8cba59dbbc 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -90,7 +90,7 @@ static enum RetFormat ParseDataFormat(std::string& param, const std::string& str static std::string AvailableDataFormatsString() { - std::string formats = ""; + std::string formats; for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++) if (strlen(rf_names[i].name) > 0) { formats.append("."); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index f1352a13cf..8007cebc37 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1542,25 +1542,19 @@ UniValue getchaintxstats(const JSONRPCRequest& request) const CBlockIndex* pindex; int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month - bool havehash = !request.params[1].isNull(); - uint256 hash; - if (havehash) { - hash = uint256S(request.params[1].get_str()); - } - - { + if (request.params[1].isNull()) { LOCK(cs_main); - if (havehash) { - auto it = mapBlockIndex.find(hash); - if (it == mapBlockIndex.end()) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - } - pindex = it->second; - if (!chainActive.Contains(pindex)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain"); - } - } else { - pindex = chainActive.Tip(); + pindex = chainActive.Tip(); + } else { + uint256 hash = uint256S(request.params[1].get_str()); + LOCK(cs_main); + auto it = mapBlockIndex.find(hash); + if (it == mapBlockIndex.end()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + } + pindex = it->second; + if (!chainActive.Contains(pindex)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain"); } } diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 61bd59e9ed..f573c7dbeb 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -98,7 +98,7 @@ UniValue createmultisig(const JSONRPCRequest& request) "\nCreates a multi-signature address with n signature of m keys required.\n" "It returns a json object with the address and redeemScript.\n" "\nArguments:\n" - "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" + "1. nrequired (numeric, required) The number of required signatures out of the n keys.\n" "2. \"keys\" (string, required) A json array of hex-encoded public keys\n" " [\n" " \"key\" (string) The hex-encoded public key\n" diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 7a0225ff0d..fee2b765ba 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -89,7 +89,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request) " \"pingtime\": n, (numeric) ping time (if available)\n" " \"minping\": n, (numeric) minimum observed ping time (if any at all)\n" " \"pingwait\": n, (numeric) ping wait (if non-zero)\n" - " \"version\": v, (numeric) The peer version, such as 7001\n" + " \"version\": v, (numeric) The peer version, such as 70001\n" " \"subver\": \"/Satoshi:0.8.5/\", (string) The string version\n" " \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n" " \"addnode\": true|false, (boolean) Whether connection was due to addnode/-connect or if it was an automatic/inbound connection\n" diff --git a/src/rpc/rawtransaction.h b/src/rpc/rawtransaction.h index 2186c1d5e7..ec9d1f2cf0 100644 --- a/src/rpc/rawtransaction.h +++ b/src/rpc/rawtransaction.h @@ -6,7 +6,7 @@ #define BITCOIN_RPC_RAWTRANSACTION_H class CBasicKeyStore; -class CMutableTransaction; +struct CMutableTransaction; class UniValue; /** Sign a transaction with the given keystore and previous transactions */ diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 838e502a0a..aaba5e5926 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -140,10 +140,9 @@ static CScript PushAll(const std::vector<valtype>& values) bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata) { - CScript script = fromPubKey; std::vector<valtype> result; txnouttype whichType; - bool solved = SignStep(creator, script, result, whichType, SIGVERSION_BASE); + bool solved = SignStep(creator, fromPubKey, result, whichType, SIGVERSION_BASE); bool P2SH = false; CScript subscript; sigdata.scriptWitness.stack.clear(); @@ -153,8 +152,8 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu // Solver returns the subscript that needs to be evaluated; // the final scriptSig is the signatures from that // and then the serialized subscript: - script = subscript = CScript(result[0].begin(), result[0].end()); - solved = solved && SignStep(creator, script, result, whichType, SIGVERSION_BASE) && whichType != TX_SCRIPTHASH; + subscript = CScript(result[0].begin(), result[0].end()); + solved = solved && SignStep(creator, subscript, result, whichType, SIGVERSION_BASE) && whichType != TX_SCRIPTHASH; P2SH = true; } diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp index 42f9dd0600..8e0ec5243b 100644 --- a/src/test/checkqueue_tests.cpp +++ b/src/test/checkqueue_tests.cpp @@ -406,11 +406,11 @@ BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks) boost::thread_group tg; std::mutex m; std::condition_variable cv; + bool has_lock{false}; + bool has_tried{false}; + bool done{false}; + bool done_ack{false}; { - bool has_lock {false}; - bool has_tried {false}; - bool done {false}; - bool done_ack {false}; std::unique_lock<std::mutex> l(m); tg.create_thread([&]{ CCheckQueueControl<FakeCheck> control(queue.get()); diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index ca57f58905..e03234060d 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -171,7 +171,7 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) ipv4Addr.s_addr = 0xa0b0c001; CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK); - std::string pszDest = ""; + std::string pszDest; bool fInboundIn = false; // Test that fFeeler is false by default. diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp index db9162c0db..01c3a6cedd 100644 --- a/src/test/prevector_tests.cpp +++ b/src/test/prevector_tests.cpp @@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt) test.erase(InsecureRandRange(test.size())); } if (InsecureRandBits(3) == 2) { - int new_size = std::max<int>(0, std::min<int>(30, test.size() + (InsecureRandRange(5)) - 2)); + int new_size = std::max(0, std::min(30, (int)test.size() + (int)InsecureRandRange(5) - 2)); test.resize(new_size); } if (InsecureRandBits(3) == 3) { diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index 760f933abc..179df7dd38 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -56,8 +56,8 @@ BOOST_AUTO_TEST_CASE(manythreads) int counter[10] = { 0 }; FastRandomContext rng(42); auto zeroToNine = [](FastRandomContext& rc) -> int { return rc.randrange(10); }; // [0, 9] - auto randomMsec = [](FastRandomContext& rc) -> int { return -11 + rc.randrange(1012); }; // [-11, 1000] - auto randomDelta = [](FastRandomContext& rc) -> int { return -1000 + rc.randrange(2001); }; // [-1000, 1000] + auto randomMsec = [](FastRandomContext& rc) -> int { return -11 + (int)rc.randrange(1012); }; // [-11, 1000] + auto randomDelta = [](FastRandomContext& rc) -> int { return -1000 + (int)rc.randrange(2001); }; // [-1000, 1000] boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now(); boost::chrono::system_clock::time_point now = start; diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index bdd44489f4..95c4825b84 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -28,6 +28,9 @@ void CConnmanTest::AddNode(CNode& node) void CConnmanTest::ClearNodes() { LOCK(g_connman->cs_vNodes); + for (CNode* node : g_connman->vNodes) { + delete node; + } g_connman->vNodes.clear(); } diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 463bed5957..58f033cd89 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -82,6 +82,20 @@ BOOST_AUTO_TEST_CASE(util_HexStr) "04 67 8a fd b0"); BOOST_CHECK_EQUAL( + HexStr(ParseHex_expected + sizeof(ParseHex_expected), + ParseHex_expected + sizeof(ParseHex_expected)), + ""); + + BOOST_CHECK_EQUAL( + HexStr(ParseHex_expected + sizeof(ParseHex_expected), + ParseHex_expected + sizeof(ParseHex_expected), true), + ""); + + BOOST_CHECK_EQUAL( + HexStr(ParseHex_expected, ParseHex_expected), + ""); + + BOOST_CHECK_EQUAL( HexStr(ParseHex_expected, ParseHex_expected, true), ""); @@ -90,6 +104,58 @@ BOOST_AUTO_TEST_CASE(util_HexStr) BOOST_CHECK_EQUAL( HexStr(ParseHex_vec, true), "04 67 8a fd b0"); + + BOOST_CHECK_EQUAL( + HexStr(ParseHex_vec.rbegin(), ParseHex_vec.rend()), + "b0fd8a6704" + ); + + BOOST_CHECK_EQUAL( + HexStr(ParseHex_vec.rbegin(), ParseHex_vec.rend(), true), + "b0 fd 8a 67 04" + ); + + BOOST_CHECK_EQUAL( + HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected), + std::reverse_iterator<const uint8_t *>(ParseHex_expected)), + "" + ); + + BOOST_CHECK_EQUAL( + HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected), + std::reverse_iterator<const uint8_t *>(ParseHex_expected), true), + "" + ); + + BOOST_CHECK_EQUAL( + HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected + 1), + std::reverse_iterator<const uint8_t *>(ParseHex_expected)), + "04" + ); + + BOOST_CHECK_EQUAL( + HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected + 1), + std::reverse_iterator<const uint8_t *>(ParseHex_expected), true), + "04" + ); + + BOOST_CHECK_EQUAL( + HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected + 5), + std::reverse_iterator<const uint8_t *>(ParseHex_expected)), + "b0fd8a6704" + ); + + BOOST_CHECK_EQUAL( + HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected + 5), + std::reverse_iterator<const uint8_t *>(ParseHex_expected), true), + "b0 fd 8a 67 04" + ); + + BOOST_CHECK_EQUAL( + HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected + 65), + std::reverse_iterator<const uint8_t *>(ParseHex_expected)), + "5f1df16b2b704c8a578d0bbaf74d385cde12c11ee50455f3c438ef4c3fbcf649b6de611feae06279a60939e028a8d65c10b73071a6f16719274855feb0fd8a6704" + ); } @@ -688,7 +754,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory) thr.join(); BOOST_CHECK_EQUAL(threadresult, true); #ifndef WIN32 - // Try to aquire lock in child process while we're holding it, this should fail. + // Try to acquire lock in child process while we're holding it, this should fail. char ch; BOOST_CHECK_EQUAL(write(fd[1], &LockCommand, 1), 1); BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1); @@ -699,7 +765,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory) // Probing lock from our side now should succeed, but not hold on to the lock. BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true); - // Try to acquire the lock in the child process, this should be succesful. + // Try to acquire the lock in the child process, this should be successful. BOOST_CHECK_EQUAL(write(fd[1], &LockCommand, 1), 1); BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1); BOOST_CHECK_EQUAL((bool)ch, true); diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 52158e9804..ebafe078f4 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -127,7 +127,7 @@ std::string EncodeBase64(const unsigned char* pch, size_t len) { static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - std::string strRet = ""; + std::string strRet; strRet.reserve((len+2)/3*4); int mode=0, left=0; @@ -267,7 +267,7 @@ std::string EncodeBase32(const unsigned char* pch, size_t len) { static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; - std::string strRet=""; + std::string strRet; strRet.reserve((len+4)/5*8); int mode=0, left=0; diff --git a/src/validation.cpp b/src/validation.cpp index e809f66e25..d2438b0609 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -4658,6 +4658,7 @@ bool DumpMempool(void) } //! Guess how far we are in the verification process at the given block index +//! require cs_main if pindex has not been validated yet (because nChainTx might be unset) double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pindex) { if (pindex == nullptr) return 0.0; diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp index 73985dcf25..385fdc963a 100644 --- a/src/wallet/fees.cpp +++ b/src/wallet/fees.cpp @@ -53,6 +53,9 @@ CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, c // if we don't have enough data for estimateSmartFee, then use fallbackFee fee_needed = CWallet::fallbackFee.GetFee(nTxBytes); if (feeCalc) feeCalc->reason = FeeReason::FALLBACK; + + // directly return if fallback fee is disabled (feerate 0 == disabled) + if (CWallet::fallbackFee.GetFee(1000) == 0) return fee_needed; } // Obey mempool min fee when using smart fee estimation CAmount min_mempool_fee = pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nTxBytes); diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 74036f4f0f..9ac48bff77 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -5,6 +5,7 @@ #include <wallet/init.h> +#include <chainparams.h> #include <net.h> #include <util.h> #include <utilmoneystr.h> @@ -123,6 +124,8 @@ bool WalletParameterInteraction() _("This is the minimum transaction fee you pay on every transaction.")); CWallet::minTxFee = CFeeRate(n); } + + g_wallet_allow_fallback_fee = Params().IsFallbackFeeEnabled(); if (gArgs.IsArgSet("-fallbackfee")) { CAmount nFeePerK = 0; @@ -132,6 +135,7 @@ bool WalletParameterInteraction() InitWarning(AmountHighWarn("-fallbackfee") + " " + _("This is the transaction fee you may pay when fee estimates are not available.")); CWallet::fallbackFee = CFeeRate(nFeePerK); + g_wallet_allow_fallback_fee = nFeePerK != 0; //disable fallback fee in case value was set to 0, enable if non-null value } if (gArgs.IsArgSet("-discardfee")) { diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 741ea25340..930e8bbbb4 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -279,7 +279,7 @@ UniValue importaddress(const JSONRPCRequest& request) ); - std::string strLabel = ""; + std::string strLabel; if (!request.params[1].isNull()) strLabel = request.params[1].get_str(); @@ -452,7 +452,7 @@ UniValue importpubkey(const JSONRPCRequest& request) ); - std::string strLabel = ""; + std::string strLabel; if (!request.params[1].isNull()) strLabel = request.params[1].get_str(); diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp index cafd69d075..e6510cc214 100644 --- a/src/wallet/test/accounting_tests.cpp +++ b/src/wallet/test/accounting_tests.cpp @@ -82,7 +82,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) wtx.mapValue["comment"] = "y"; { CMutableTransaction tx(*wtx.tx); - --tx.nLockTime; // Just to change the hash :) + ++tx.nLockTime; // Just to change the hash :) wtx.SetTx(MakeTransactionRef(std::move(tx))); } pwalletMain->AddToWallet(wtx); @@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) wtx.mapValue["comment"] = "x"; { CMutableTransaction tx(*wtx.tx); - --tx.nLockTime; // Just to change the hash :) + ++tx.nLockTime; // Just to change the hash :) wtx.SetTx(MakeTransactionRef(std::move(tx))); } pwalletMain->AddToWallet(wtx); diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp index 7797f85f07..18abf9a9db 100644 --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -11,7 +11,6 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName): TestingSetup(chainName) { bitdb.MakeMock(); - bool fFirstRun; g_address_type = OUTPUT_TYPE_DEFAULT; g_change_type = OUTPUT_TYPE_DEFAULT; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 408a01c50b..bb7be2df33 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -43,6 +43,7 @@ bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE; bool fWalletRbf = DEFAULT_WALLET_RBF; OutputType g_address_type = OUTPUT_TYPE_NONE; OutputType g_change_type = OUTPUT_TYPE_NONE; +bool g_wallet_allow_fallback_fee = true; //<! will be defined via chainparams const char * DEFAULT_WALLET_DAT = "wallet.dat"; const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; @@ -1668,20 +1669,15 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock dProgressStart = GuessVerificationProgress(chainParams.TxData(), pindex); dProgressTip = GuessVerificationProgress(chainParams.TxData(), tip); } + double gvp = dProgressStart; while (pindex && !fAbortRescan) { if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) { - double gvp = 0; - { - LOCK(cs_main); - gvp = GuessVerificationProgress(chainParams.TxData(), pindex); - } ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((gvp - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); } if (GetTime() >= nNow + 60) { nNow = GetTime(); - LOCK(cs_main); - LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex)); + LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, gvp); } CBlock block; @@ -1705,6 +1701,7 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock { LOCK(cs_main); pindex = chainActive.Next(pindex); + gvp = GuessVerificationProgress(chainParams.TxData(), pindex); if (tip != chainActive.Tip()) { tip = chainActive.Tip(); // in case the tip has changed, update progress max @@ -1713,7 +1710,7 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock } } if (pindex && fAbortRescan) { - LogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex)); + LogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, gvp); } ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI } @@ -2922,6 +2919,11 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT } nFeeNeeded = GetMinimumFee(nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc); + if (feeCalc.reason == FeeReason::FALLBACK && !g_wallet_allow_fallback_fee) { + // eventually allow a fallback fee + strFailReason = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee."); + return false; + } // If we made it here and we aren't even able to meet the relay fee on the next pass, give up // because we must be at the maximum allowed fee. diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index fefe415bb1..4db45f16ef 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -39,6 +39,7 @@ extern CFeeRate payTxFee; extern unsigned int nTxConfirmTarget; extern bool bSpendZeroConfChange; extern bool fWalletRbf; +extern bool g_wallet_allow_fallback_fee; static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000; //! -paytxfee default |