aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--configure.ac4
-rw-r--r--doc/build-unix.md6
-rw-r--r--doc/release-notes/release-notes-0.14.1.md143
-rw-r--r--src/Makefile.am8
-rw-r--r--src/checkqueue.h2
-rw-r--r--src/coins.h1
-rw-r--r--src/init.cpp5
-rw-r--r--src/merkleblock.h2
-rw-r--r--src/net.h2
-rw-r--r--src/policy/fees.cpp209
-rw-r--r--src/policy/fees.h129
-rw-r--r--src/policy/policy.cpp1
-rw-r--r--src/qt/clientmodel.cpp1
-rw-r--r--src/qt/coincontroldialog.cpp5
-rw-r--r--src/qt/sendcoinsdialog.cpp7
-rw-r--r--src/qt/walletmodel.cpp1
-rw-r--r--src/rpc/mining.cpp5
-rw-r--r--src/rpc/misc.cpp1
-rw-r--r--src/streams.h8
-rw-r--r--src/test/policyestimator_tests.cpp45
-rw-r--r--src/txmempool.cpp64
-rw-r--r--src/txmempool.h16
-rw-r--r--src/validation.cpp12
-rw-r--r--src/validation.h3
-rw-r--r--src/wallet/feebumper.cpp5
-rw-r--r--src/wallet/rpcwallet.cpp2
-rw-r--r--src/wallet/wallet.cpp11
-rw-r--r--src/wallet/wallet.h5
-rw-r--r--src/zmq/zmqpublishnotifier.cpp1
-rw-r--r--test/functional/README.md2
-rwxr-xr-xtest/functional/blockchain.py14
-rwxr-xr-xtest/functional/maxblocksinflight.py93
-rwxr-xr-xtest/functional/net.py21
-rwxr-xr-xtest/functional/p2p-segwit.py13
-rw-r--r--test/functional/test_framework/blocktools.py11
-rwxr-xr-xtest/functional/test_framework/mininode.py3
-rwxr-xr-xtest/functional/test_runner.py1
38 files changed, 475 insertions, 390 deletions
diff --git a/Makefile.am b/Makefile.am
index e82704dbdf..3a56eea0c0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -76,9 +76,6 @@ $(BITCOIN_WIN_INSTALLER): all-recursive
echo error: could not build $@
@echo built $@
-$(if $(findstring src/,$(MAKECMDGOALS)),$(MAKECMDGOALS), none): FORCE
- $(MAKE) -C src $(patsubst src/%,%,$@)
-
$(OSX_APP)/Contents/PkgInfo:
$(MKDIR_P) $(@D)
@echo "APPL????" > $@
diff --git a/configure.ac b/configure.ac
index 1e1ed49f91..496a6bcf9f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -676,6 +676,10 @@ AX_BOOST_PROGRAM_OPTIONS
AX_BOOST_THREAD
AX_BOOST_CHRONO
+dnl Boost 1.56 through 1.62 allow using std::atomic instead of its own atomic
+dnl counter implementations. In 1.63 and later the std::atomic approach is default.
+m4_pattern_allow(DBOOST_AC_USE_STD_ATOMIC) dnl otherwise it's treated like a macro
+BOOST_CPPFLAGS="-DBOOST_SP_USE_STD_ATOMIC -DBOOST_AC_USE_STD_ATOMIC $BOOST_CPPFLAGS"
if test x$use_reduce_exports = xyes; then
AC_MSG_CHECKING([for working boost reduced exports])
diff --git a/doc/build-unix.md b/doc/build-unix.md
index 31a88a1b18..b7eae2a630 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -321,8 +321,10 @@ Clang is installed by default as `cc` compiler, this makes it easier to get
started than on [OpenBSD](build-openbsd.md). Installing dependencies:
pkg install autoconf automake libtool pkgconf
- pkg install boost-libs openssl libevent2
+ pkg install boost-libs openssl libevent
+ pkg install gmake
+You need to use GNU make (`gmake`) instead of `make`.
(`libressl` instead of `openssl` will also work)
For the wallet (optional):
@@ -338,7 +340,7 @@ Then build using:
./autogen.sh
./configure --with-incompatible-bdb BDB_CFLAGS="-I/usr/local/include/db5" BDB_LIBS="-L/usr/local/lib -ldb_cxx-5"
- make
+ gmake
*Note on debugging*: The version of `gdb` installed by default is [ancient and considered harmful](https://wiki.freebsd.org/GdbRetirement).
It is not suitable for debugging a multi-threaded C++ program, not even for getting backtraces. Please install the package `gdb` and
diff --git a/doc/release-notes/release-notes-0.14.1.md b/doc/release-notes/release-notes-0.14.1.md
new file mode 100644
index 0000000000..ef072afd4d
--- /dev/null
+++ b/doc/release-notes/release-notes-0.14.1.md
@@ -0,0 +1,143 @@
+Bitcoin Core version 0.14.1 is now available from:
+
+ <https://bitcoin.org/bin/bitcoin-core-0.14.1/>
+
+This is a new minor version release, including various bugfixes and
+performance improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at github:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+Compatibility
+==============
+
+Bitcoin Core is extensively tested on multiple operating systems using
+the Linux kernel, macOS 10.8+, and Windows Vista and later.
+
+Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support),
+No attempt is made to prevent installing or running the software on Windows XP, you
+can still do so at your own risk but be aware that there are known instabilities and issues.
+Please do not report issues about Windows XP to the issue tracker.
+
+Bitcoin Core should also work on most other Unix-like systems but is not
+frequently tested on them.
+
+Notable changes
+===============
+
+RPC changes
+-----------
+
+- The first positional argument of `createrawtransaction` was renamed from
+ `transactions` to `inputs`.
+
+- The argument of `disconnectnode` was renamed from `node` to `address`.
+
+These interface changes break compatibility with 0.14.0, when the named
+arguments functionality, introduced in 0.14.0, is used. Client software
+using these calls with named arguments needs to be updated.
+
+Mining
+------
+
+In previous versions, getblocktemplate required segwit support from downstream
+clients/miners once the feature activated on the network. In this version, it
+now supports non-segwit clients even after activation, by removing all segwit
+transactions from the returned block template. This allows non-segwit miners to
+continue functioning correctly even after segwit has activated.
+
+Due to the limitations in previous versions, getblocktemplate also recommended
+non-segwit clients to not signal for the segwit version-bit. Since this is no
+longer an issue, getblocktemplate now always recommends signalling segwit for
+all miners. This is safe because ability to enforce the rule is the only
+required criteria for safe activation, not actually producing segwit-enabled
+blocks.
+
+UTXO memory accounting
+----------------------
+
+Memory usage for the UTXO cache is being calculated more accurately, so that
+the configured limit (`-dbcache`) will be respected when memory usage peaks
+during cache flushes. The memory accounting in prior releases is estimated to
+only account for half the actual peak utilization.
+
+The default `-dbcache` has also been changed in this release to 450MiB. Users
+who currently set `-dbcache` to a high value (e.g. to keep the UTXO more fully
+cached in memory) should consider increasing this setting in order to achieve
+the same cache performance as prior releases. Users on low-memory systems
+(such as systems with 1GB or less) should consider specifying a lower value for
+this parameter.
+
+Additional information relating to running on low-memory systems can be found
+here:
+[reducing-bitcoind-memory-usage.md](https://gist.github.com/laanwj/efe29c7661ce9b6620a7).
+
+0.14.1 Change log
+=================
+
+Detailed release notes follow. This overview includes changes that affect
+behavior, not code moves, refactors and string updates. For convenience in locating
+the code changes and accompanying discussion, both the pull request and
+git merge commit are mentioned.
+
+### RPC and other APIs
+- #10084 `142fbb2` Rename first named arg of createrawtransaction (MarcoFalke)
+- #10139 `f15268d` Remove auth cookie on shutdown (practicalswift)
+- #10146 `2fea10a` Better error handling for submitblock (rawodb, gmaxwell)
+- #10144 `d947afc` Prioritisetransaction wasn't always updating ancestor fee (sdaftuar)
+- #10204 `3c79602` Rename disconnectnode argument (jnewbery)
+
+### Block and transaction handling
+- #10126 `0b5e162` Compensate for memory peak at flush time (sipa)
+- #9912 `fc3d7db` Optimize GetWitnessHash() for non-segwit transactions (sdaftuar)
+- #10133 `ab864d3` Clean up calculations of pcoinsTip memory usage (morcos)
+
+### P2P protocol and network code
+- #9953/#10013 `d2548a4` Fix shutdown hang with >= 8 -addnodes set (TheBlueMatt)
+- #10176 `30fa231` net: gracefully handle NodeId wrapping (theuni)
+
+### Build system
+- #9973 `e9611d1` depends: fix zlib build on osx (theuni)
+
+### GUI
+- #10060 `ddc2dd1` Ensure an item exists on the rpcconsole stack before adding (achow101)
+
+### Mining
+- #9955/#10006 `569596c` Don't require segwit in getblocktemplate for segwit signalling or mining (sdaftuar)
+- #9959/#10127 `b5c3440` Prevent slowdown in CreateNewBlock on large mempools (sdaftuar)
+
+### Tests and QA
+- #10157 `55f641c` Fix the `mempool_packages.py` test (sdaftuar)
+
+### Miscellaneous
+- #10037 `4d8e660` Trivial: Fix typo in help getrawtransaction RPC (keystrike)
+- #10120 `e4c9a90` util: Work around (virtual) memory exhaustion on 32-bit w/ glibc (laanwj)
+- #10130 `ecc5232` bitcoin-tx input verification (awemany, jnewbery)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Alex Morcos
+- Andrew Chow
+- Awemany
+- Cory Fields
+- Gregory Maxwell
+- James Evans
+- John Newbery
+- MarcoFalke
+- Matt Corallo
+- Pieter Wuille
+- practicalswift
+- rawodb
+- Suhas Daftuar
+- Wladimir J. van der Laan
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 69b5bb48ad..96b9a27f7b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -462,6 +462,14 @@ DISTCLEANFILES = obj/build.h
EXTRA_DIST = $(CTAES_DIST)
+
+config/bitcoin-config.h: config/stamp-h1
+ @$(MAKE) -C $(top_builddir) $(subdir)/$(@)
+config/stamp-h1: $(top_srcdir)/$(subdir)/config/bitcoin-config.h.in $(top_builddir)/config.status
+ $(AM_V_at)$(MAKE) -C $(top_builddir) $(subdir)/$(@)
+$(top_srcdir)/$(subdir)/config/bitcoin-config.h.in: $(am__configure_deps)
+ $(AM_V_at)$(MAKE) -C $(top_srcdir) $(subdir)/config/bitcoin-config.h.in
+
clean-local:
-$(MAKE) -C secp256k1 clean
-$(MAKE) -C univalue clean
diff --git a/src/checkqueue.h b/src/checkqueue.h
index ea12df66dd..63c104c02a 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_CHECKQUEUE_H
#define BITCOIN_CHECKQUEUE_H
+#include "sync.h"
+
#include <algorithm>
#include <vector>
diff --git a/src/coins.h b/src/coins.h
index 8ee49b33ae..0cb8519df8 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -6,6 +6,7 @@
#ifndef BITCOIN_COINS_H
#define BITCOIN_COINS_H
+#include "primitives/transaction.h"
#include "compressor.h"
#include "core_memusage.h"
#include "hash.h"
diff --git a/src/init.cpp b/src/init.cpp
index 1e7e388a52..f06c9e1100 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -25,6 +25,7 @@
#include "netbase.h"
#include "net.h"
#include "net_processing.h"
+#include "policy/fees.h"
#include "policy/policy.h"
#include "rpc/server.h"
#include "rpc/register.h"
@@ -215,7 +216,7 @@ void Shutdown()
fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
CAutoFile est_fileout(fsbridge::fopen(est_path, "wb"), SER_DISK, CLIENT_VERSION);
if (!est_fileout.IsNull())
- mempool.WriteFeeEstimates(est_fileout);
+ ::feeEstimator.Write(est_fileout);
else
LogPrintf("%s: Failed to write fee estimates to %s\n", __func__, est_path.string());
fFeeEstimatesInitialized = false;
@@ -1550,7 +1551,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION);
// Allowed to fail as this file IS missing on first startup.
if (!est_filein.IsNull())
- mempool.ReadFeeEstimates(est_filein);
+ ::feeEstimator.Read(est_filein);
fFeeEstimatesInitialized = true;
// ********************************************************* Step 8: load wallet
diff --git a/src/merkleblock.h b/src/merkleblock.h
index 73cbf670ee..de4c5c8d29 100644
--- a/src/merkleblock.h
+++ b/src/merkleblock.h
@@ -23,7 +23,7 @@
* storing a bit for each traversed node, signifying whether the node is the
* parent of at least one matched leaf txid (or a matched txid itself). In
* case we are at the leaf level, or this bit is 0, its merkle node hash is
- * stored, and its children are not explorer further. Otherwise, no hash is
+ * stored, and its children are not explored further. Otherwise, no hash is
* stored, but we recurse into both (or the only) child branch. During
* decoding, the same depth-first traversal is performed, consuming bits and
* hashes as they written during encoding.
diff --git a/src/net.h b/src/net.h
index 91b2685e48..faeb5a927e 100644
--- a/src/net.h
+++ b/src/net.h
@@ -11,7 +11,6 @@
#include "amount.h"
#include "bloom.h"
#include "compat.h"
-#include "fs.h"
#include "hash.h"
#include "limitedmap.h"
#include "netaddress.h"
@@ -36,7 +35,6 @@
#include <boost/foreach.hpp>
#include <boost/signals2/signal.hpp>
-class CAddrMan;
class CScheduler;
class CNode;
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 38e07dc345..f3f7f8378e 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -7,14 +7,121 @@
#include "policy/policy.h"
#include "amount.h"
+#include "clientversion.h"
#include "primitives/transaction.h"
#include "random.h"
#include "streams.h"
#include "txmempool.h"
#include "util.h"
-void TxConfirmStats::Initialize(std::vector<double>& defaultBuckets,
- unsigned int maxConfirms, double _decay)
+/**
+ * We will instantiate an instance of this class to track transactions that were
+ * included in a block. We will lump transactions into a bucket according to their
+ * approximate feerate and then track how long it took for those txs to be included in a block
+ *
+ * The tracking of unconfirmed (mempool) transactions is completely independent of the
+ * historical tracking of transactions that have been confirmed in a block.
+ */
+class TxConfirmStats
+{
+private:
+ //Define the buckets we will group transactions into
+ std::vector<double> buckets; // The upper-bound of the range for the bucket (inclusive)
+ std::map<double, unsigned int> bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
+
+ // For each bucket X:
+ // Count the total # of txs in each bucket
+ // Track the historical moving average of this total over blocks
+ std::vector<double> txCtAvg;
+ // and calculate the total for the current block to update the moving average
+ std::vector<int> curBlockTxCt;
+
+ // Count the total # of txs confirmed within Y blocks in each bucket
+ // Track the historical moving average of theses totals over blocks
+ std::vector<std::vector<double> > confAvg; // confAvg[Y][X]
+ // and calculate the totals for the current block to update the moving averages
+ std::vector<std::vector<int> > curBlockConf; // curBlockConf[Y][X]
+
+ // Sum the total feerate of all tx's in each bucket
+ // Track the historical moving average of this total over blocks
+ std::vector<double> avg;
+ // and calculate the total for the current block to update the moving average
+ std::vector<double> curBlockVal;
+
+ // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
+ // Combine the total value with the tx counts to calculate the avg feerate per bucket
+
+ double decay;
+
+ // Mempool counts of outstanding transactions
+ // For each bucket X, track the number of transactions in the mempool
+ // that are unconfirmed for each possible confirmation value Y
+ std::vector<std::vector<int> > unconfTxs; //unconfTxs[Y][X]
+ // transactions still unconfirmed after MAX_CONFIRMS for each bucket
+ std::vector<int> oldUnconfTxs;
+
+public:
+ /**
+ * Create new TxConfirmStats. This is called by BlockPolicyEstimator's
+ * constructor with default values.
+ * @param defaultBuckets contains the upper limits for the bucket boundaries
+ * @param maxConfirms max number of confirms to track
+ * @param decay how much to decay the historical moving average per block
+ */
+ TxConfirmStats(const std::vector<double>& defaultBuckets, unsigned int maxConfirms, double decay);
+
+ /** Clear the state of the curBlock variables to start counting for the new block */
+ void ClearCurrent(unsigned int nBlockHeight);
+
+ /**
+ * Record a new transaction data point in the current block stats
+ * @param blocksToConfirm the number of blocks it took this transaction to confirm
+ * @param val the feerate of the transaction
+ * @warning blocksToConfirm is 1-based and has to be >= 1
+ */
+ void Record(int blocksToConfirm, double val);
+
+ /** Record a new transaction entering the mempool*/
+ unsigned int NewTx(unsigned int nBlockHeight, double val);
+
+ /** Remove a transaction from mempool tracking stats*/
+ void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight,
+ unsigned int bucketIndex);
+
+ /** Update our estimates by decaying our historical moving average and updating
+ with the data gathered from the current block */
+ void UpdateMovingAverages();
+
+ /**
+ * Calculate a feerate estimate. Find the lowest value bucket (or range of buckets
+ * to make sure we have enough data points) whose transactions still have sufficient likelihood
+ * of being confirmed within the target number of confirmations
+ * @param confTarget target number of confirmations
+ * @param sufficientTxVal required average number of transactions per block in a bucket range
+ * @param minSuccess the success probability we require
+ * @param requireGreater return the lowest feerate such that all higher values pass minSuccess OR
+ * return the highest feerate such that all lower values fail minSuccess
+ * @param nBlockHeight the current block height
+ */
+ double EstimateMedianVal(int confTarget, double sufficientTxVal,
+ double minSuccess, bool requireGreater, unsigned int nBlockHeight) const;
+
+ /** Return the max number of confirms we're tracking */
+ unsigned int GetMaxConfirms() const { return confAvg.size(); }
+
+ /** Write state of estimation data to a file*/
+ void Write(CAutoFile& fileout) const;
+
+ /**
+ * Read saved state of estimation data from a file and replace all internal data structures and
+ * variables with this state.
+ */
+ void Read(CAutoFile& filein);
+};
+
+
+TxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,
+ unsigned int maxConfirms, double _decay)
{
decay = _decay;
for (unsigned int i = 0; i < defaultBuckets.size(); i++) {
@@ -77,7 +184,7 @@ void TxConfirmStats::UpdateMovingAverages()
// returns -1 on error conditions
double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
double successBreakPoint, bool requireGreater,
- unsigned int nBlockHeight)
+ unsigned int nBlockHeight) const
{
// Counters for a bucket (or range of buckets)
double nConf = 0; // Number of tx's confirmed within the confTarget
@@ -173,7 +280,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
return median;
}
-void TxConfirmStats::Write(CAutoFile& fileout)
+void TxConfirmStats::Write(CAutoFile& fileout) const
{
fileout << decay;
fileout << buckets;
@@ -290,9 +397,10 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe
// of no harm to try to remove them again.
bool CBlockPolicyEstimator::removeTx(uint256 hash)
{
+ LOCK(cs_feeEstimator);
std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
if (pos != mapMemPoolTxs.end()) {
- feeStats.removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex);
+ feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex);
mapMemPoolTxs.erase(hash);
return true;
} else {
@@ -310,11 +418,17 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
vfeelist.push_back(bucketBoundary);
}
vfeelist.push_back(INF_FEERATE);
- feeStats.Initialize(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY);
+ feeStats = new TxConfirmStats(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY);
+}
+
+CBlockPolicyEstimator::~CBlockPolicyEstimator()
+{
+ delete feeStats;
}
void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
{
+ LOCK(cs_feeEstimator);
unsigned int txHeight = entry.GetHeight();
uint256 hash = entry.GetTx().GetHash();
if (mapMemPoolTxs.count(hash)) {
@@ -343,7 +457,7 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
mapMemPoolTxs[hash].blockHeight = txHeight;
- mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK());
+ mapMemPoolTxs[hash].bucketIndex = feeStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
}
bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry)
@@ -367,13 +481,14 @@ bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxM
// Feerates are stored and reported as BTC-per-kb:
CFeeRate feeRate(entry->GetFee(), entry->GetTxSize());
- feeStats.Record(blocksToConfirm, (double)feeRate.GetFeePerK());
+ feeStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
return true;
}
void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
std::vector<const CTxMemPoolEntry*>& entries)
{
+ LOCK(cs_feeEstimator);
if (nBlockHeight <= nBestSeenHeight) {
// Ignore side chains and re-orgs; assuming they are random
// they don't affect the estimate.
@@ -389,7 +504,7 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
nBestSeenHeight = nBlockHeight;
// Clear the current block state and update unconfirmed circular buffer
- feeStats.ClearCurrent(nBlockHeight);
+ feeStats->ClearCurrent(nBlockHeight);
unsigned int countedTxs = 0;
// Repopulate the current block states
@@ -399,7 +514,7 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
}
// Update all exponential averages with the current block state
- feeStats.UpdateMovingAverages();
+ feeStats->UpdateMovingAverages();
LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy after updating estimates for %u of %u txs in block, since last block %u of %u tracked, new mempool map size %u\n",
countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size());
@@ -408,14 +523,15 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
untrackedTxs = 0;
}
-CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget)
+CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) const
{
+ LOCK(cs_feeEstimator);
// Return failure if trying to analyze a target we're not tracking
// It's not possible to get reasonable estimates for confTarget of 1
- if (confTarget <= 1 || (unsigned int)confTarget > feeStats.GetMaxConfirms())
+ if (confTarget <= 1 || (unsigned int)confTarget > feeStats->GetMaxConfirms())
return CFeeRate(0);
- double median = feeStats.EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
+ double median = feeStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
if (median < 0)
return CFeeRate(0);
@@ -423,22 +539,28 @@ CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget)
return CFeeRate(median);
}
-CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool)
+CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool) const
{
if (answerFoundAtTarget)
*answerFoundAtTarget = confTarget;
- // Return failure if trying to analyze a target we're not tracking
- if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms())
- return CFeeRate(0);
-
- // It's not possible to get reasonable estimates for confTarget of 1
- if (confTarget == 1)
- confTarget = 2;
double median = -1;
- while (median < 0 && (unsigned int)confTarget <= feeStats.GetMaxConfirms()) {
- median = feeStats.EstimateMedianVal(confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
- }
+
+ {
+ LOCK(cs_feeEstimator);
+
+ // Return failure if trying to analyze a target we're not tracking
+ if (confTarget <= 0 || (unsigned int)confTarget > feeStats->GetMaxConfirms())
+ return CFeeRate(0);
+
+ // It's not possible to get reasonable estimates for confTarget of 1
+ if (confTarget == 1)
+ confTarget = 2;
+
+ while (median < 0 && (unsigned int)confTarget <= feeStats->GetMaxConfirms()) {
+ median = feeStats->EstimateMedianVal(confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
+ }
+ } // Must unlock cs_feeEstimator before taking mempool locks
if (answerFoundAtTarget)
*answerFoundAtTarget = confTarget - 1;
@@ -454,19 +576,40 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
return CFeeRate(median);
}
-void CBlockPolicyEstimator::Write(CAutoFile& fileout)
+bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
{
- fileout << nBestSeenHeight;
- feeStats.Write(fileout);
+ try {
+ LOCK(cs_feeEstimator);
+ fileout << 139900; // version required to read: 0.13.99 or later
+ fileout << CLIENT_VERSION; // version that wrote the file
+ fileout << nBestSeenHeight;
+ feeStats->Write(fileout);
+ }
+ catch (const std::exception&) {
+ LogPrintf("CBlockPolicyEstimator::Write(): unable to read policy estimator data (non-fatal)\n");
+ return false;
+ }
+ return true;
}
-void CBlockPolicyEstimator::Read(CAutoFile& filein, int nFileVersion)
+bool CBlockPolicyEstimator::Read(CAutoFile& filein)
{
- int nFileBestSeenHeight;
- filein >> nFileBestSeenHeight;
- feeStats.Read(filein);
- nBestSeenHeight = nFileBestSeenHeight;
- // if nVersionThatWrote < 139900 then another TxConfirmStats (for priority) follows but can be ignored.
+ try {
+ LOCK(cs_feeEstimator);
+ int nVersionRequired, nVersionThatWrote, nFileBestSeenHeight;
+ filein >> nVersionRequired >> nVersionThatWrote;
+ if (nVersionRequired > CLIENT_VERSION)
+ return error("CBlockPolicyEstimator::Read(): up-version (%d) fee estimate file", nVersionRequired);
+ filein >> nFileBestSeenHeight;
+ feeStats->Read(filein);
+ nBestSeenHeight = nFileBestSeenHeight;
+ // if nVersionThatWrote < 139900 then another TxConfirmStats (for priority) follows but can be ignored.
+ }
+ catch (const std::exception&) {
+ LogPrintf("CBlockPolicyEstimator::Read(): unable to read policy estimator data (non-fatal)\n");
+ return false;
+ }
+ return true;
}
FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
diff --git a/src/policy/fees.h b/src/policy/fees.h
index dd01c90c45..34f07c7270 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -8,6 +8,7 @@
#include "amount.h"
#include "uint256.h"
#include "random.h"
+#include "sync.h"
#include <map>
#include <string>
@@ -17,6 +18,7 @@ class CAutoFile;
class CFeeRate;
class CTxMemPoolEntry;
class CTxMemPool;
+class TxConfirmStats;
/** \class CBlockPolicyEstimator
* The BlockPolicyEstimator is used for estimating the feerate needed
@@ -59,113 +61,6 @@ class CTxMemPool;
* they've been outstanding.
*/
-/**
- * We will instantiate an instance of this class to track transactions that were
- * included in a block. We will lump transactions into a bucket according to their
- * approximate feerate and then track how long it took for those txs to be included in a block
- *
- * The tracking of unconfirmed (mempool) transactions is completely independent of the
- * historical tracking of transactions that have been confirmed in a block.
- */
-class TxConfirmStats
-{
-private:
- //Define the buckets we will group transactions into
- std::vector<double> buckets; // The upper-bound of the range for the bucket (inclusive)
- std::map<double, unsigned int> bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
-
- // For each bucket X:
- // Count the total # of txs in each bucket
- // Track the historical moving average of this total over blocks
- std::vector<double> txCtAvg;
- // and calculate the total for the current block to update the moving average
- std::vector<int> curBlockTxCt;
-
- // Count the total # of txs confirmed within Y blocks in each bucket
- // Track the historical moving average of theses totals over blocks
- std::vector<std::vector<double> > confAvg; // confAvg[Y][X]
- // and calculate the totals for the current block to update the moving averages
- std::vector<std::vector<int> > curBlockConf; // curBlockConf[Y][X]
-
- // Sum the total feerate of all tx's in each bucket
- // Track the historical moving average of this total over blocks
- std::vector<double> avg;
- // and calculate the total for the current block to update the moving average
- std::vector<double> curBlockVal;
-
- // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
- // Combine the total value with the tx counts to calculate the avg feerate per bucket
-
- double decay;
-
- // Mempool counts of outstanding transactions
- // For each bucket X, track the number of transactions in the mempool
- // that are unconfirmed for each possible confirmation value Y
- std::vector<std::vector<int> > unconfTxs; //unconfTxs[Y][X]
- // transactions still unconfirmed after MAX_CONFIRMS for each bucket
- std::vector<int> oldUnconfTxs;
-
-public:
- /**
- * Initialize the data structures. This is called by BlockPolicyEstimator's
- * constructor with default values.
- * @param defaultBuckets contains the upper limits for the bucket boundaries
- * @param maxConfirms max number of confirms to track
- * @param decay how much to decay the historical moving average per block
- */
- void Initialize(std::vector<double>& defaultBuckets, unsigned int maxConfirms, double decay);
-
- /** Clear the state of the curBlock variables to start counting for the new block */
- void ClearCurrent(unsigned int nBlockHeight);
-
- /**
- * Record a new transaction data point in the current block stats
- * @param blocksToConfirm the number of blocks it took this transaction to confirm
- * @param val the feerate of the transaction
- * @warning blocksToConfirm is 1-based and has to be >= 1
- */
- void Record(int blocksToConfirm, double val);
-
- /** Record a new transaction entering the mempool*/
- unsigned int NewTx(unsigned int nBlockHeight, double val);
-
- /** Remove a transaction from mempool tracking stats*/
- void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight,
- unsigned int bucketIndex);
-
- /** Update our estimates by decaying our historical moving average and updating
- with the data gathered from the current block */
- void UpdateMovingAverages();
-
- /**
- * Calculate a feerate estimate. Find the lowest value bucket (or range of buckets
- * to make sure we have enough data points) whose transactions still have sufficient likelihood
- * of being confirmed within the target number of confirmations
- * @param confTarget target number of confirmations
- * @param sufficientTxVal required average number of transactions per block in a bucket range
- * @param minSuccess the success probability we require
- * @param requireGreater return the lowest feerate such that all higher values pass minSuccess OR
- * return the highest feerate such that all lower values fail minSuccess
- * @param nBlockHeight the current block height
- */
- double EstimateMedianVal(int confTarget, double sufficientTxVal,
- double minSuccess, bool requireGreater, unsigned int nBlockHeight);
-
- /** Return the max number of confirms we're tracking */
- unsigned int GetMaxConfirms() { return confAvg.size(); }
-
- /** Write state of estimation data to a file*/
- void Write(CAutoFile& fileout);
-
- /**
- * Read saved state of estimation data from a file and replace all internal data structures and
- * variables with this state.
- */
- void Read(CAutoFile& filein);
-};
-
-
-
/** Track confirm delays up to 25 blocks, can't estimate beyond that */
static const unsigned int MAX_BLOCK_CONFIRMS = 25;
@@ -204,14 +99,12 @@ class CBlockPolicyEstimator
public:
/** Create new BlockPolicyEstimator and initialize stats tracking classes with default values */
CBlockPolicyEstimator();
+ ~CBlockPolicyEstimator();
/** Process all the transactions that have been included in a block */
void processBlock(unsigned int nBlockHeight,
std::vector<const CTxMemPoolEntry*>& entries);
- /** Process a transaction confirmed in a block*/
- bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry);
-
/** Process a transaction accepted to the mempool*/
void processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate);
@@ -219,19 +112,19 @@ public:
bool removeTx(uint256 hash);
/** Return a feerate estimate */
- CFeeRate estimateFee(int confTarget);
+ CFeeRate estimateFee(int confTarget) const;
/** Estimate feerate needed to get be included in a block within
* confTarget blocks. If no answer can be given at confTarget, return an
* estimate at the lowest target where one can be given.
*/
- CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool);
+ CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool) const;
/** Write estimation data to a file */
- void Write(CAutoFile& fileout);
+ bool Write(CAutoFile& fileout) const;
/** Read estimation data from a file */
- void Read(CAutoFile& filein, int nFileVersion);
+ bool Read(CAutoFile& filein);
private:
CFeeRate minTrackedFee; //!< Passed to constructor to avoid dependency on main
@@ -247,10 +140,16 @@ private:
std::map<uint256, TxStatsInfo> mapMemPoolTxs;
/** Classes to track historical data on transaction confirmations */
- TxConfirmStats feeStats;
+ TxConfirmStats* feeStats;
unsigned int trackedTxs;
unsigned int untrackedTxs;
+
+ mutable CCriticalSection cs_feeEstimator;
+
+ /** Process a transaction confirmed in a block*/
+ bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry);
+
};
class FeeFilterRounder
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index ec398f6627..6f8b6c2953 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -8,6 +8,7 @@
#include "policy/policy.h"
#include "validation.h"
+#include "coins.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 20d4687971..de00eacdb9 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -9,6 +9,7 @@
#include "guiutil.h"
#include "peertablemodel.h"
+#include "chain.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "clientversion.h"
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 1d19c65753..38ad6e9aab 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -15,6 +15,7 @@
#include "wallet/coincontrol.h"
#include "init.h"
+#include "policy/fees.h"
#include "policy/policy.h"
#include "validation.h" // For mempool
#include "wallet/wallet.h"
@@ -512,7 +513,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes -= 34;
// Fee
- nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
+ nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, ::mempool, ::feeEstimator);
if (nPayFee > 0 && coinControl->nMinimumTotalFee > nPayFee)
nPayFee = coinControl->nMinimumTotalFee;
@@ -592,7 +593,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
if (payTxFee.GetFeePerK() > 0)
dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), payTxFee.GetFeePerK()) / 1000;
else {
- dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), mempool.estimateSmartFee(nTxConfirmTarget).GetFeePerK()) / 1000;
+ dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), ::feeEstimator.estimateSmartFee(nTxConfirmTarget, NULL, ::mempool).GetFeePerK()) / 1000;
}
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index ed7eab03f3..098cda6d32 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -21,6 +21,7 @@
#include "validation.h" // mempool and minRelayTxFee
#include "ui_interface.h"
#include "txmempool.h"
+#include "policy/fees.h"
#include "wallet/wallet.h"
#include <QFontMetrics>
@@ -114,7 +115,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p
ui->groupCustomFee->button((int)std::max(0, std::min(1, settings.value("nCustomFeeRadio").toInt())))->setChecked(true);
ui->customFee->setValue(settings.value("nTransactionFee").toLongLong());
ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool());
- ui->optInRBF->setCheckState(model->getDefaultWalletRbf() ? Qt::Checked : Qt::Unchecked);
minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());
}
@@ -175,6 +175,9 @@ void SendCoinsDialog::setModel(WalletModel *_model)
updateSmartFeeLabel();
updateGlobalFeeVariables();
+ // set default rbf checkbox state
+ ui->optInRBF->setCheckState(model->getDefaultWalletRbf() ? Qt::Checked : Qt::Unchecked);
+
// set the smartfee-sliders default value (wallets default conf.target or last stored value)
QSettings settings;
if (settings.value("nSmartFeeSliderPosition").toInt() == 0)
@@ -660,7 +663,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
int estimateFoundAtBlocks = nBlocksToConfirm;
- CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks);
+ CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks, ::mempool);
if (feeRate <= CFeeRate(0)) // not enough data => minfee
{
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index ebcac53c25..a2a9271904 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -13,6 +13,7 @@
#include "transactiontablemodel.h"
#include "base58.h"
+#include "chain.h"
#include "keystore.h"
#include "validation.h"
#include "net.h" // for g_connman
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index d234bb69ae..4ce52a6c7f 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -15,6 +15,7 @@
#include "validation.h"
#include "miner.h"
#include "net.h"
+#include "policy/fees.h"
#include "pow.h"
#include "rpc/blockchain.h"
#include "rpc/server.h"
@@ -818,7 +819,7 @@ UniValue estimatefee(const JSONRPCRequest& request)
if (nBlocks < 1)
nBlocks = 1;
- CFeeRate feeRate = mempool.estimateFee(nBlocks);
+ CFeeRate feeRate = ::feeEstimator.estimateFee(nBlocks);
if (feeRate == CFeeRate(0))
return -1.0;
@@ -856,7 +857,7 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
UniValue result(UniValue::VOBJ);
int answerFound;
- CFeeRate feeRate = mempool.estimateSmartFee(nBlocks, &answerFound);
+ CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &answerFound, ::mempool);
result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
result.push_back(Pair("blocks", answerFound));
return result;
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 7b8aa572d7..1f973a0c18 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
+#include "chain.h"
#include "clientversion.h"
#include "init.h"
#include "validation.h"
diff --git a/src/streams.h b/src/streams.h
index 1387b9cf54..8dc5a19ead 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -248,7 +248,8 @@ public:
void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
{
- assert(last - first >= 0);
+ if (last == first) return;
+ assert(last - first > 0);
if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
{
// special case for inserting at the front when there's room
@@ -261,7 +262,8 @@ public:
void insert(iterator it, const char* first, const char* last)
{
- assert(last - first >= 0);
+ if (last == first) return;
+ assert(last - first > 0);
if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
{
// special case for inserting at the front when there's room
@@ -339,6 +341,8 @@ public:
void read(char* pch, size_t nSize)
{
+ if (nSize == 0) return;
+
// Read from the beginning of the buffer
unsigned int nReadPosNext = nReadPos + nSize;
if (nReadPosNext >= vch.size())
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index bc2f49ef3f..ed6782ea34 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -16,7 +16,8 @@ BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
{
- CTxMemPool mpool;
+ CBlockPolicyEstimator feeEst;
+ CTxMemPool mpool(&feeEst);
TestMemPoolEntryHelper entry;
CAmount basefee(2000);
CAmount deltaFee(100);
@@ -78,16 +79,16 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
// At this point we should need to combine 5 buckets to get enough data points
// So estimateFee(1,2,3) should fail and estimateFee(4) should return somewhere around
// 8*baserate. estimateFee(4) %'s are 100,100,100,100,90 = average 98%
- BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
- BOOST_CHECK(mpool.estimateFee(2) == CFeeRate(0));
- BOOST_CHECK(mpool.estimateFee(3) == CFeeRate(0));
- BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee);
- BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee);
+ BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
+ BOOST_CHECK(feeEst.estimateFee(2) == CFeeRate(0));
+ BOOST_CHECK(feeEst.estimateFee(3) == CFeeRate(0));
+ BOOST_CHECK(feeEst.estimateFee(4).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee);
+ BOOST_CHECK(feeEst.estimateFee(4).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee);
int answerFound;
- BOOST_CHECK(mpool.estimateSmartFee(1, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
- BOOST_CHECK(mpool.estimateSmartFee(3, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
- BOOST_CHECK(mpool.estimateSmartFee(4, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
- BOOST_CHECK(mpool.estimateSmartFee(8, &answerFound) == mpool.estimateFee(8) && answerFound == 8);
+ BOOST_CHECK(feeEst.estimateSmartFee(1, &answerFound, mpool) == feeEst.estimateFee(4) && answerFound == 4);
+ BOOST_CHECK(feeEst.estimateSmartFee(3, &answerFound, mpool) == feeEst.estimateFee(4) && answerFound == 4);
+ BOOST_CHECK(feeEst.estimateSmartFee(4, &answerFound, mpool) == feeEst.estimateFee(4) && answerFound == 4);
+ BOOST_CHECK(feeEst.estimateSmartFee(8, &answerFound, mpool) == feeEst.estimateFee(8) && answerFound == 8);
}
}
@@ -99,7 +100,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
// Second highest feerate has 100% chance of being included by 2 blocks,
// so estimateFee(2) should return 9*baseRate etc...
for (int i = 1; i < 10;i++) {
- origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK());
+ origFeeEst.push_back(feeEst.estimateFee(i).GetFeePerK());
if (i > 2) { // Fee estimates should be monotonically decreasing
BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);
}
@@ -118,10 +119,10 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
while (blocknum < 250)
mpool.removeForBlock(block, ++blocknum);
- BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
+ BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
for (int i = 2; i < 10;i++) {
- BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
- BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
+ BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
}
@@ -141,8 +142,8 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
int answerFound;
for (int i = 1; i < 10;i++) {
- BOOST_CHECK(mpool.estimateFee(i) == CFeeRate(0) || mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
- BOOST_CHECK(mpool.estimateSmartFee(i, &answerFound).GetFeePerK() > origFeeEst[answerFound-1] - deltaFee);
+ BOOST_CHECK(feeEst.estimateFee(i) == CFeeRate(0) || feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(feeEst.estimateSmartFee(i, &answerFound, mpool).GetFeePerK() > origFeeEst[answerFound-1] - deltaFee);
}
// Mine all those transactions
@@ -157,9 +158,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
}
mpool.removeForBlock(block, 265);
block.clear();
- BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
+ BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
for (int i = 2; i < 10;i++) {
- BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
}
// Mine 200 more blocks where everything is mined every block
@@ -179,9 +180,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
mpool.removeForBlock(block, ++blocknum);
block.clear();
}
- BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
+ BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
for (int i = 2; i < 10; i++) {
- BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
}
// Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
@@ -190,8 +191,8 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
mpool.TrimToSize(1);
BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]);
for (int i = 1; i < 10; i++) {
- BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.estimateFee(i).GetFeePerK());
- BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
+ BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool).GetFeePerK() >= feeEst.estimateFee(i).GetFeePerK());
+ BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
}
}
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 0794a3902f..ac842da6bf 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -5,7 +5,6 @@
#include "txmempool.h"
-#include "clientversion.h"
#include "consensus/consensus.h"
#include "consensus/validation.h"
#include "validation.h"
@@ -16,7 +15,6 @@
#include "util.h"
#include "utilmoneystr.h"
#include "utiltime.h"
-#include "version.h"
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
int64_t _nTime, unsigned int _entryHeight,
@@ -333,8 +331,8 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee,
assert(int(nSigOpCostWithAncestors) >= 0);
}
-CTxMemPool::CTxMemPool() :
- nTransactionsUpdated(0)
+CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator) :
+ nTransactionsUpdated(0), minerPolicyEstimator(estimator)
{
_clear(); //lock free clear
@@ -342,13 +340,6 @@ CTxMemPool::CTxMemPool() :
// accepting transactions becomes O(N^2) where N is the number
// of transactions in the pool
nCheckFrequency = 0;
-
- minerPolicyEstimator = new CBlockPolicyEstimator();
-}
-
-CTxMemPool::~CTxMemPool()
-{
- delete minerPolicyEstimator;
}
void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
@@ -427,7 +418,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
nTransactionsUpdated++;
totalTxSize += entry.GetTxSize();
- minerPolicyEstimator->processTransaction(entry, validFeeEstimate);
+ if (minerPolicyEstimator) {minerPolicyEstimator->processTransaction(entry, validFeeEstimate);}
vTxHashes.emplace_back(tx.GetWitnessHash(), newit);
newit->vTxHashesIdx = vTxHashes.size() - 1;
@@ -457,7 +448,7 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
mapLinks.erase(it);
mapTx.erase(it);
nTransactionsUpdated++;
- minerPolicyEstimator->removeTx(hash);
+ if (minerPolicyEstimator) {minerPolicyEstimator->removeTx(hash);}
}
// Calculates descendants of entry that are not already in setDescendants, and adds to
@@ -591,7 +582,7 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
entries.push_back(&*i);
}
// Before the txs in the new block have been removed from the mempool, update policy estimates
- minerPolicyEstimator->processBlock(nBlockHeight, entries);
+ if (minerPolicyEstimator) {minerPolicyEstimator->processBlock(nBlockHeight, entries);}
for (const auto& tx : vtx)
{
txiter it = mapTx.find(tx->GetHash());
@@ -850,51 +841,6 @@ TxMempoolInfo CTxMemPool::info(const uint256& hash) const
return GetInfo(i);
}
-CFeeRate CTxMemPool::estimateFee(int nBlocks) const
-{
- LOCK(cs);
- return minerPolicyEstimator->estimateFee(nBlocks);
-}
-CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, int *answerFoundAtBlocks) const
-{
- LOCK(cs);
- return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks, *this);
-}
-
-bool
-CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
-{
- try {
- LOCK(cs);
- fileout << 139900; // version required to read: 0.13.99 or later
- fileout << CLIENT_VERSION; // version that wrote the file
- minerPolicyEstimator->Write(fileout);
- }
- catch (const std::exception&) {
- LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)\n");
- return false;
- }
- return true;
-}
-
-bool
-CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
-{
- try {
- int nVersionRequired, nVersionThatWrote;
- filein >> nVersionRequired >> nVersionThatWrote;
- if (nVersionRequired > CLIENT_VERSION)
- return error("CTxMemPool::ReadFeeEstimates(): up-version (%d) fee estimate file", nVersionRequired);
- LOCK(cs);
- minerPolicyEstimator->Read(filein, nVersionThatWrote);
- }
- catch (const std::exception&) {
- LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)\n");
- return false;
- }
- return true;
-}
-
void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta)
{
{
diff --git a/src/txmempool.h b/src/txmempool.h
index 4222789510..92c4d9f9d4 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -496,8 +496,7 @@ public:
/** Create a new CTxMemPool.
*/
- CTxMemPool();
- ~CTxMemPool();
+ CTxMemPool(CBlockPolicyEstimator* estimator = nullptr);
/**
* If sanity-checking is turned on, check makes sure the pool is
@@ -618,19 +617,6 @@ public:
TxMempoolInfo info(const uint256& hash) const;
std::vector<TxMempoolInfo> infoAll() const;
- /** Estimate fee rate needed to get into the next nBlocks
- * If no answer can be given at nBlocks, return an estimate
- * at the lowest number of blocks where one can be given
- */
- CFeeRate estimateSmartFee(int nBlocks, int *answerFoundAtBlocks = NULL) const;
-
- /** Estimate fee rate needed to get into the next nBlocks */
- CFeeRate estimateFee(int nBlocks) const;
-
- /** Write/Read estimates to disk */
- bool WriteFeeEstimates(CAutoFile& fileout) const;
- bool ReadFeeEstimates(CAutoFile& filein);
-
size_t DynamicMemoryUsage() const;
boost::signals2::signal<void (CTransactionRef)> NotifyEntryAdded;
diff --git a/src/validation.cpp b/src/validation.cpp
index 6ae87c683e..6c60be45a1 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -6,6 +6,7 @@
#include "validation.h"
#include "arith_uint256.h"
+#include "chain.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
@@ -80,7 +81,8 @@ uint256 hashAssumeValid;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
-CTxMemPool mempool;
+CBlockPolicyEstimator feeEstimator;
+CTxMemPool mempool(&feeEstimator);
static void CheckBlockIndex(const Consensus::Params& consensusParams);
@@ -2677,7 +2679,7 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
}
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
-bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos)
+static bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
{
pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0;
@@ -2685,7 +2687,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
pindexNew->nDataPos = pos.nPos;
pindexNew->nUndoPos = 0;
pindexNew->nStatus |= BLOCK_HAVE_DATA;
- if (IsWitnessEnabled(pindexNew->pprev, Params().GetConsensus())) {
+ if (IsWitnessEnabled(pindexNew->pprev, consensusParams)) {
pindexNew->nStatus |= BLOCK_OPT_WITNESS;
}
pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS);
@@ -3207,7 +3209,7 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
if (dbp == NULL)
if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
AbortNode(state, "Failed to write block");
- if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
+ if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
return error("AcceptBlock(): ReceivedBlockTransactions failed");
} catch (const std::runtime_error& e) {
return AbortNode(state, std::string("System error: ") + e.what());
@@ -3838,7 +3840,7 @@ bool InitBlockIndex(const CChainParams& chainparams)
if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
return error("LoadBlockIndex(): writing genesis block to disk failed");
CBlockIndex *pindex = AddToBlockIndex(block);
- if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
+ if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
return error("LoadBlockIndex(): genesis block not accepted");
// Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data
return FlushStateToDisk(state, FLUSH_STATE_ALWAYS);
diff --git a/src/validation.h b/src/validation.h
index 51ea18722c..c0f9b6d513 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -11,7 +11,6 @@
#endif
#include "amount.h"
-#include "chain.h"
#include "coins.h"
#include "fs.h"
#include "protocol.h" // For CMessageHeader::MessageStartChars
@@ -39,6 +38,7 @@ class CChainParams;
class CInv;
class CConnman;
class CScriptCheck;
+class CBlockPolicyEstimator;
class CTxMemPool;
class CValidationInterface;
class CValidationState;
@@ -152,6 +152,7 @@ struct BlockHasher
extern CScript COINBASE_FLAGS;
extern CCriticalSection cs_main;
+extern CBlockPolicyEstimator feeEstimator;
extern CTxMemPool mempool;
typedef boost::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
extern BlockMap mapBlockIndex;
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 6b030935f3..82e5974065 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -5,6 +5,7 @@
#include "consensus/validation.h"
#include "wallet/feebumper.h"
#include "wallet/wallet.h"
+#include "policy/fees.h"
#include "policy/policy.h"
#include "policy/rbf.h"
#include "validation.h" //for mempool access
@@ -159,11 +160,11 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConf
} else {
// if user specified a confirm target then don't consider any global payTxFee
if (specifiedConfirmTarget) {
- nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, CAmount(0));
+ nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, CAmount(0));
}
// otherwise use the regular wallet logic to select payTxFee or default confirm target
else {
- nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool);
+ nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator);
}
nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 665d856df5..5cbeeab4eb 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -9,8 +9,10 @@
#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
+#include "wallet/coincontrol.h"
#include "validation.h"
#include "net.h"
+#include "policy/fees.h"
#include "policy/policy.h"
#include "policy/rbf.h"
#include "rpc/server.h"
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index b5e26e26d3..33dd30a795 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -16,6 +16,7 @@
#include "keystore.h"
#include "validation.h"
#include "net.h"
+#include "policy/fees.h"
#include "policy/policy.h"
#include "policy/rbf.h"
#include "primitives/block.h"
@@ -2612,7 +2613,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
if (coinControl && coinControl->nConfirmTarget > 0)
currentConfirmationTarget = coinControl->nConfirmTarget;
- CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, mempool);
+ CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator);
if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) {
nFeeNeeded = coinControl->nMinimumTotalFee;
}
@@ -2786,19 +2787,19 @@ CAmount CWallet::GetRequiredFee(unsigned int nTxBytes)
return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
}
-CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool)
+CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator)
{
// payTxFee is the user-set global for desired feerate
- return GetMinimumFee(nTxBytes, nConfirmTarget, pool, payTxFee.GetFee(nTxBytes));
+ return GetMinimumFee(nTxBytes, nConfirmTarget, pool, estimator, payTxFee.GetFee(nTxBytes));
}
-CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, CAmount targetFee)
+CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, CAmount targetFee)
{
CAmount nFeeNeeded = targetFee;
// User didn't set: use -txconfirmtarget to estimate...
if (nFeeNeeded == 0) {
int estimateFoundTarget = nConfirmTarget;
- nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes);
+ nFeeNeeded = estimator.estimateSmartFee(nConfirmTarget, &estimateFoundTarget, pool).GetFee(nTxBytes);
// ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
if (nFeeNeeded == 0)
nFeeNeeded = fallbackFee.GetFee(nTxBytes);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 06e7e14990..c0ed44377f 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -73,6 +73,7 @@ class CReserveKey;
class CScript;
class CScheduler;
class CTxMemPool;
+class CBlockPolicyEstimator;
class CWalletTx;
/** (client) version numbers for particular wallet features */
@@ -932,12 +933,12 @@ public:
* Estimate the minimum fee considering user set parameters
* and the required fee
*/
- static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool);
+ static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator);
/**
* Estimate the minimum fee considering required fee and targetFee or if 0
* then fee estimation for nConfirmTarget
*/
- static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, CAmount targetFee);
+ static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, CAmount targetFee);
/**
* Return the minimum required fee taking into account the
* floating relay fee and user set minimum transaction fee
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index b2963e9bde..700c39f66e 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "chain.h"
#include "chainparams.h"
#include "streams.h"
#include "zmqpublishnotifier.h"
diff --git a/test/functional/README.md b/test/functional/README.md
index 651b01f18a..e6c4849702 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -59,7 +59,7 @@ thread.)
* RPC calls are available in p2p tests.
* Can be used to write free-form tests, where specific p2p-protocol behavior
-is tested. Examples: ```p2p-accept-block.py```, ```maxblocksinflight.py```.
+is tested. Examples: ```p2p-accept-block.py```, ```p2p-compactblocks.py```.
## Comptool
diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py
index 596aed50ec..de5e01c2e3 100755
--- a/test/functional/blockchain.py
+++ b/test/functional/blockchain.py
@@ -6,6 +6,10 @@
Test the following RPCs:
- gettxoutsetinfo
+ - getdifficulty
+ - getbestblockhash
+ - getblockhash
+ - getblockheader
- verifychain
Tests correspond to code in rpc/blockchain.cpp.
@@ -40,6 +44,7 @@ class BlockchainTest(BitcoinTestFramework):
def run_test(self):
self._test_gettxoutsetinfo()
self._test_getblockheader()
+ self._test_getdifficulty()
self.nodes[0].verifychain(4, 0)
def _test_gettxoutsetinfo(self):
@@ -57,7 +62,8 @@ class BlockchainTest(BitcoinTestFramework):
def _test_getblockheader(self):
node = self.nodes[0]
- assert_raises_jsonrpc(-5, "Block not found", node.getblockheader, "nonsense")
+ assert_raises_jsonrpc(-5, "Block not found",
+ node.getblockheader, "nonsense")
besthash = node.getbestblockhash()
secondbesthash = node.getblockhash(199)
@@ -79,5 +85,11 @@ class BlockchainTest(BitcoinTestFramework):
assert isinstance(int(header['versionHex'], 16), int)
assert isinstance(header['difficulty'], Decimal)
+ def _test_getdifficulty(self):
+ difficulty = self.nodes[0].getdifficulty()
+ # 1 hash in 2 should be valid, so difficulty should be 1/2**31
+ # binary => decimal => binary math is why we do this check
+ assert abs(difficulty * 2**31 - 1) < 0.0001
+
if __name__ == '__main__':
BlockchainTest().main()
diff --git a/test/functional/maxblocksinflight.py b/test/functional/maxblocksinflight.py
deleted file mode 100755
index 4ef2a35a44..0000000000
--- a/test/functional/maxblocksinflight.py
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2015-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.
-"""Test nodes responses to having many blocks in flight.
-
-In this test we connect to one node over p2p, send it numerous inv's, and
-compare the resulting number of getdata requests to a max allowed value. We
-test for exceeding 128 blocks in flight, which was the limit an 0.9 client will
-reach. [0.10 clients shouldn't request more than 16 from a single peer.]
-"""
-
-from test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-
-MAX_REQUESTS = 128
-
-class TestManager(NodeConnCB):
- def on_getdata(self, conn, message):
- self.log.debug("got getdata %s" % repr(message))
- # Log the requests
- for inv in message.inv:
- if inv.hash not in self.blockReqCounts:
- self.blockReqCounts[inv.hash] = 0
- self.blockReqCounts[inv.hash] += 1
-
- def on_close(self, conn):
- if not self.disconnectOkay:
- raise EarlyDisconnectError(0)
-
- def add_new_connection(self, connection):
- super().add_connection(connection)
- self.blockReqCounts = {}
- self.disconnectOkay = False
-
- def run(self):
- self.connection.rpc.generate(1) # Leave IBD
-
- numBlocksToGenerate = [8, 16, 128, 1024]
- for count in range(len(numBlocksToGenerate)):
- current_invs = []
- for i in range(numBlocksToGenerate[count]):
- current_invs.append(CInv(2, random.randrange(0, 1 << 256)))
- if len(current_invs) >= 50000:
- self.connection.send_message(msg_inv(current_invs))
- current_invs = []
- if len(current_invs) > 0:
- self.connection.send_message(msg_inv(current_invs))
-
- # Wait and see how many blocks were requested
- time.sleep(2)
-
- total_requests = 0
- with mininode_lock:
- for key in self.blockReqCounts:
- total_requests += self.blockReqCounts[key]
- if self.blockReqCounts[key] > 1:
- raise AssertionError("Error, test failed: block %064x requested more than once" % key)
- if total_requests > MAX_REQUESTS:
- raise AssertionError("Error, too many blocks (%d) requested" % total_requests)
- self.log.info("Round %d: success (total requests: %d)" % (count, total_requests))
-
- self.disconnectOkay = True
- self.connection.disconnect_node()
-
-
-class MaxBlocksInFlightTest(BitcoinTestFramework):
- def add_options(self, parser):
- parser.add_option("--testbinary", dest="testbinary",
- default=os.getenv("BITCOIND", "bitcoind"),
- help="Binary to test max block requests behavior")
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = True
- self.num_nodes = 1
-
- def setup_network(self):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-whitelist=127.0.0.1']],
- binary=[self.options.testbinary])
-
- def run_test(self):
- test = TestManager()
- # pass log handler through to the test manager object
- test.log = self.log
- test.add_new_connection(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test))
- NetworkThread().start() # Start up network handling in another thread
- test.run()
-
-if __name__ == '__main__':
- MaxBlocksInFlightTest().main()
diff --git a/test/functional/net.py b/test/functional/net.py
index e9463c7dc7..a82cdabf52 100755
--- a/test/functional/net.py
+++ b/test/functional/net.py
@@ -7,15 +7,15 @@
Tests correspond to code in rpc/net.cpp.
"""
-from decimal import Decimal
import time
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.authproxy import JSONRPCException
from test_framework.util import (
assert_equal,
- start_nodes,
+ assert_raises_jsonrpc,
connect_nodes_bi,
+ p2p_port,
+ start_nodes,
)
@@ -33,7 +33,7 @@ class NetTest(BitcoinTestFramework):
def run_test(self):
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)
- assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2) # bilateral connection
+ assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)
self.nodes[0].setnetworkactive(False)
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False)
@@ -49,6 +49,19 @@ class NetTest(BitcoinTestFramework):
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)
assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)
+ # test getaddednodeinfo
+ assert_equal(self.nodes[0].getaddednodeinfo(), [])
+ # add a node (node2) to node0
+ ip_port = "127.0.0.1:{}".format(p2p_port(2))
+ self.nodes[0].addnode(ip_port, 'add')
+ # check that the node has indeed been added
+ added_nodes = self.nodes[0].getaddednodeinfo(ip_port)
+ assert_equal(len(added_nodes), 1)
+ assert_equal(added_nodes[0]['addednode'], ip_port)
+ # check that a non-existant node returns an error
+ assert_raises_jsonrpc(-24, "Node has not been added",
+ self.nodes[0].getaddednodeinfo, '1.1.1.1')
+
if __name__ == '__main__':
NetTest().main()
diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py
index cd7b788eb4..3dd78c8b7d 100755
--- a/test/functional/p2p-segwit.py
+++ b/test/functional/p2p-segwit.py
@@ -8,7 +8,7 @@ from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from test_framework.script import *
-from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, WITNESS_COMMITMENT_HEADER
+from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, get_witness_script, WITNESS_COMMITMENT_HEADER
from test_framework.key import CECKey, CPubKey
import time
import random
@@ -1721,15 +1721,10 @@ class SegWitTest(BitcoinTestFramework):
assert('default_witness_commitment' in gbt_results)
witness_commitment = gbt_results['default_witness_commitment']
- # TODO: this duplicates some code from blocktools.py, would be nice
- # to refactor.
# Check that default_witness_commitment is present.
- block = CBlock()
- witness_root = block.get_merkle_root([ser_uint256(0), ser_uint256(txid)])
- check_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(0)))
- from test_framework.blocktools import WITNESS_COMMITMENT_HEADER
- output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(check_commitment)
- script = CScript([OP_RETURN, output_data])
+ witness_root = CBlock.get_merkle_root([ser_uint256(0),
+ ser_uint256(txid)])
+ script = get_witness_script(witness_root, 0)
assert_equal(witness_commitment, bytes_to_hex_str(script))
# undo mocktime
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 2c9a0857df..5dcf516dc6 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -25,6 +25,13 @@ def create_block(hashprev, coinbase, nTime=None):
# From BIP141
WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
+
+def get_witness_script(witness_root, witness_nonce):
+ witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(witness_nonce)))
+ output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(witness_commitment)
+ return CScript([OP_RETURN, output_data])
+
+
# According to BIP141, blocks with witness rules active must commit to the
# hash of all in-block transactions including witness.
def add_witness_commitment(block, nonce=0):
@@ -32,14 +39,12 @@ def add_witness_commitment(block, nonce=0):
# transactions, with witnesses.
witness_nonce = nonce
witness_root = block.calc_witness_merkle_root()
- witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(witness_nonce)))
# witness_nonce should go to coinbase witness.
block.vtx[0].wit.vtxinwit = [CTxInWitness()]
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(witness_nonce)]
# witness commitment is the last OP_RETURN output in coinbase
- output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(witness_commitment)
- block.vtx[0].vout.append(CTxOut(0, CScript([OP_RETURN, output_data])))
+ block.vtx[0].vout.append(CTxOut(0, get_witness_script(witness_root, witness_nonce)))
block.vtx[0].rehash()
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index d57d46f2ff..2383cca58e 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -610,7 +610,8 @@ class CBlock(CBlockHeader):
return r
# Calculate the merkle root given a vector of transaction hashes
- def get_merkle_root(self, hashes):
+ @classmethod
+ def get_merkle_root(cls, hashes):
while len(hashes) > 1:
newhashes = []
for i in range(0, len(hashes), 2):
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 44c049dca8..2932f82970 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -139,7 +139,6 @@ EXTENDED_SCRIPTS = [
'txn_clone.py --mineblock',
'forknotify.py',
'invalidateblock.py',
- 'maxblocksinflight.py',
'p2p-acceptblock.py',
'replace-by-fee.py',
]