aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rwxr-xr-xcontrib/devtools/github-merge.py2
-rwxr-xr-xcontrib/verifybinaries/verify.sh31
-rw-r--r--doc/REST-interface.md28
-rw-r--r--src/.clang-format1
-rw-r--r--src/Makefile.am2
-rw-r--r--src/bench/coin_selection.cpp1
-rw-r--r--src/bitcoin-tx.cpp4
-rw-r--r--src/bloom.cpp1
-rw-r--r--src/checkpoints.cpp4
-rw-r--r--src/checkqueue.h1
-rw-r--r--src/core_read.cpp2
-rw-r--r--src/core_write.cpp1
-rw-r--r--src/httprpc.cpp1
-rw-r--r--src/init.cpp16
-rw-r--r--src/memusage.h1
-rw-r--r--src/net.h1
-rw-r--r--src/net_processing.cpp5
-rw-r--r--src/policy/feerate.h1
-rw-r--r--src/policy/fees.cpp47
-rw-r--r--src/policy/fees.h16
-rw-r--r--src/policy/policy.cpp1
-rw-r--r--src/prevector.h2
-rw-r--r--src/qt/addresstablemodel.cpp1
-rw-r--r--src/qt/bitcoinstrings.cpp50
-rw-r--r--src/qt/coincontroldialog.cpp6
-rw-r--r--src/qt/locale/bitcoin_en.ts593
-rw-r--r--src/qt/recentrequeststablemodel.cpp1
-rw-r--r--src/qt/sendcoinsdialog.cpp6
-rw-r--r--src/qt/test/rpcnestedtests.cpp22
-rw-r--r--src/qt/transactionrecord.cpp1
-rw-r--r--src/qt/walletmodel.cpp4
-rw-r--r--src/reverse_iterator.h39
-rw-r--r--src/rpc/client.cpp8
-rw-r--r--src/rpc/mining.cpp163
-rw-r--r--src/rpc/mining.h15
-rw-r--r--src/rpc/misc.cpp8
-rw-r--r--src/rpc/net.cpp6
-rw-r--r--src/rpc/rawtransaction.cpp9
-rw-r--r--src/rpc/server.cpp1
-rw-r--r--src/scheduler.cpp66
-rw-r--r--src/scheduler.h33
-rw-r--r--src/script/ismine.cpp1
-rw-r--r--src/script/sign.cpp1
-rw-r--r--src/script/standard.cpp1
-rw-r--r--src/sync.cpp1
-rw-r--r--src/test/data/script_tests.json6
-rw-r--r--src/test/getarg_tests.cpp1
-rw-r--r--src/test/multisig_tests.cpp1
-rw-r--r--src/test/policyestimator_tests.cpp4
-rw-r--r--src/test/prevector_tests.cpp5
-rw-r--r--src/test/script_tests.cpp1
-rw-r--r--src/test/test_bitcoin.cpp8
-rw-r--r--src/test/test_bitcoin.h2
-rw-r--r--src/test/transaction_tests.cpp1
-rw-r--r--src/timedata.cpp1
-rw-r--r--src/torcontrol.cpp1
-rw-r--r--src/txmempool.cpp3
-rw-r--r--src/validation.cpp3
-rw-r--r--src/validationinterface.cpp134
-rw-r--r--src/validationinterface.h72
-rw-r--r--src/wallet/coincontrol.h4
-rw-r--r--src/wallet/crypter.cpp1
-rw-r--r--src/wallet/db.cpp1
-rw-r--r--src/wallet/feebumper.cpp5
-rw-r--r--src/wallet/feebumper.h3
-rw-r--r--src/wallet/rpcdump.cpp3
-rw-r--r--src/wallet/rpcwallet.cpp155
-rw-r--r--src/wallet/test/accounting_tests.cpp1
-rw-r--r--src/wallet/wallet.cpp145
-rw-r--r--src/wallet/wallet.h8
-rw-r--r--src/wallet/walletdb.cpp1
-rwxr-xr-xtest/functional/dbcrash.py109
-rwxr-xr-xtest/functional/getblocktemplate_proposals.py157
-rwxr-xr-xtest/functional/mining.py124
-rwxr-xr-xtest/functional/replace-by-fee.py4
-rw-r--r--test/functional/test_framework/util.py7
-rwxr-xr-xtest/functional/test_runner.py2
78 files changed, 1423 insertions, 757 deletions
diff --git a/.travis.yml b/.travis.yml
index fcf4b082f1..a79428fc17 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -68,7 +68,7 @@ script:
- make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false )
- export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib
- if [ "$RUN_TESTS" = "true" ]; then travis_wait 30 make $MAKEJOBS check VERBOSE=1; fi
- - if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then extended="--extended --exclude pruning"; fi
+ - if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then extended="--extended --exclude pruning,dbcrash"; fi
- if [ "$RUN_TESTS" = "true" ]; then test/functional/test_runner.py --coverage --quiet ${extended}; fi
after_script:
- echo $TRAVIS_COMMIT_RANGE
diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py
index e9816f7d19..c664cf81fa 100755
--- a/contrib/devtools/github-merge.py
+++ b/contrib/devtools/github-merge.py
@@ -175,6 +175,7 @@ def main():
if info is None:
exit(1)
title = info['title'].strip()
+ body = info['body'].strip()
# precedence order for destination branch argument:
# - command line argument
# - githubmerge.branch setting
@@ -229,6 +230,7 @@ def main():
firstline = 'Merge #%s' % (pull,)
message = firstline + '\n\n'
message += subprocess.check_output([GIT,'log','--no-merges','--topo-order','--pretty=format:%h %s (%an)',base_branch+'..'+head_branch]).decode('utf-8')
+ message += '\n\nPull request description:\n\n ' + body.replace('\n', '\n ') + '\n'
try:
subprocess.check_call([GIT,'merge','-q','--commit','--no-edit','--no-ff','-m',message.encode('utf-8'),head_branch])
except subprocess.CalledProcessError as e:
diff --git a/contrib/verifybinaries/verify.sh b/contrib/verifybinaries/verify.sh
index c2cc2b7013..409f517c9f 100755
--- a/contrib/verifybinaries/verify.sh
+++ b/contrib/verifybinaries/verify.sh
@@ -3,7 +3,8 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-### This script attempts to download the signature file SHA256SUMS.asc from bitcoin.org
+### This script attempts to download the signature file SHA256SUMS.asc from
+### bitcoincore.org and bitcoin.org and compares them.
### It first checks if the signature passes, and then downloads the files specified in
### the file, and checks if the hashes of these files match those that are specified
### in the signature file.
@@ -22,7 +23,9 @@ TMPFILE="hashes.tmp"
SIGNATUREFILENAME="SHA256SUMS.asc"
RCSUBDIR="test"
-BASEDIR="https://bitcoin.org/bin/"
+HOST1="https://bitcoincore.org"
+HOST2="https://bitcoin.org"
+BASEDIR="/bin/"
VERSIONPREFIX="bitcoin-core-"
RCVERSIONSTRING="rc"
@@ -81,7 +84,7 @@ else
fi
#first we fetch the file containing the signature
-WGETOUT=$(wget -N "$BASEDIR$SIGNATUREFILENAME" 2>&1)
+WGETOUT=$(wget -N "$HOST1$BASEDIR$SIGNATUREFILENAME" 2>&1)
#and then see if wget completed successfully
if [ $? -ne 0 ]; then
@@ -92,6 +95,22 @@ if [ $? -ne 0 ]; then
exit 2
fi
+WGETOUT=$(wget -N -O "$SIGNATUREFILENAME.2" "$HOST2$BASEDIR$SIGNATUREFILENAME" 2>&1)
+if [ $? -ne 0 ]; then
+ echo "bitcoin.org failed to provide signature file, but bitcoincore.org did?"
+ echo "wget output:"
+ echo "$WGETOUT"|sed 's/^/\t/g'
+ clean_up $SIGNATUREFILENAME
+ exit 3
+fi
+
+SIGFILEDIFFS="$(diff $SIGNATUREFILENAME $SIGNATUREFILENAME.2)"
+if [ "$SIGFILEDIFFS" != "" ]; then
+ echo "bitcoin.org and bitcoincore.org signature files were not equal?"
+ clean_up $SIGNATUREFILENAME $SIGNATUREFILENAME.2
+ exit 4
+fi
+
#then we check it
GPGOUT=$(gpg --yes --decrypt --output "$TMPFILE" "$SIGNATUREFILENAME" 2>&1)
@@ -111,7 +130,7 @@ if [ $RET -ne 0 ]; then
echo "gpg output:"
echo "$GPGOUT"|sed 's/^/\t/g'
- clean_up $SIGNATUREFILENAME $TMPFILE
+ clean_up $SIGNATUREFILENAME $SIGNATUREFILENAME.2 $TMPFILE
exit "$RET"
fi
@@ -131,7 +150,7 @@ FILES=$(awk '{print $2}' "$TMPFILE")
for file in $FILES
do
echo "Downloading $file"
- wget --quiet -N "$BASEDIR$file"
+ wget --quiet -N "$HOST1$BASEDIR$file"
done
#check hashes
@@ -149,7 +168,7 @@ fi
if [ -n "$2" ]; then
echo "Clean up the binaries"
- clean_up $FILES $SIGNATUREFILENAME $TMPFILE
+ clean_up $FILES $SIGNATUREFILENAME $SIGNATUREFILENAME.2 $TMPFILE
else
echo "Keep the binaries in $WORKINGDIR"
clean_up $TMPFILE
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index 7fbb174030..caf6782886 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -40,11 +40,13 @@ Only supports JSON as output format.
* headers : (numeric) the current number of headers we have validated
* bestblockhash : (string) the hash of the currently best block
* difficulty : (numeric) the current difficulty
+* mediantime : (numeric) the median time of the 11 blocks before the most recent block on the blockchain
* verificationprogress : (numeric) estimate of verification progress [0..1]
* chainwork : (string) total amount of work in active chain, in hexadecimal
* pruned : (boolean) if the blocks are subject to pruning
* pruneheight : (numeric) heighest block available
* softforks : (array) status of softforks in progress
+* bip9_softforks : (object) status of BIP9 softforks in progress
####Query UTXO set
`GET /rest/getutxos/<checkmempool>/<txid>-<n>/<txid>-<n>/.../<txid>-<n>.<bin|hex|json>`
@@ -57,25 +59,25 @@ Example:
```
$ curl localhost:18332/rest/getutxos/checkmempool/b2cdfd7b89def827ff8af7cd9bff7627ff72e5e8b0f71210f92ea7a4000c5d75-0.json 2>/dev/null | json_pp
{
- "chaintipHash" : "00000000fb01a7f3745a717f8caebee056c484e6e0bfe4a9591c235bb70506fb",
"chainHeight" : 325347,
+ "chaintipHash" : "00000000fb01a7f3745a717f8caebee056c484e6e0bfe4a9591c235bb70506fb",
+ "bitmap": "1",
"utxos" : [
{
+ "txvers" : 1
+ "height" : 2147483647,
+ "value" : 8.8687,
"scriptPubKey" : {
- "addresses" : [
- "mi7as51dvLJsizWnTMurtRmrP8hG2m1XvD"
- ],
- "type" : "pubkeyhash",
+ "asm" : "OP_DUP OP_HASH160 1c7cebb529b86a04c683dfa87be49de35bcf589e OP_EQUALVERIFY OP_CHECKSIG",
"hex" : "76a9141c7cebb529b86a04c683dfa87be49de35bcf589e88ac",
"reqSigs" : 1,
- "asm" : "OP_DUP OP_HASH160 1c7cebb529b86a04c683dfa87be49de35bcf589e OP_EQUALVERIFY OP_CHECKSIG"
- },
- "value" : 8.8687,
- "height" : 2147483647,
- "txvers" : 1
+ "type" : "pubkeyhash",
+ "addresses" : [
+ "mi7as51dvLJsizWnTMurtRmrP8hG2m1XvD"
+ ]
+ }
}
- ],
- "bitmap" : "1"
+ ]
}
```
@@ -87,6 +89,8 @@ Only supports JSON as output format.
* size : (numeric) the number of transactions in the TX mempool
* bytes : (numeric) size of the TX mempool in bytes
* usage : (numeric) total TX mempool memory usage
+* maxmempool : (numeric) maximum memory usage for the mempool in bytes
+* mempoolminfee : (numeric) minimum feerate (BTC per KB) for tx to be accepted
`GET /rest/mempool/contents.json`
diff --git a/src/.clang-format b/src/.clang-format
index 5918819d13..2d2ee67035 100644
--- a/src/.clang-format
+++ b/src/.clang-format
@@ -23,7 +23,6 @@ ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
-ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, BOOST_REVERSE_FOREACH ]
IndentCaseLabels: false
IndentFunctionDeclarationAfterType: false
IndentWidth: 4
diff --git a/src/Makefile.am b/src/Makefile.am
index 9b9dd89f68..06b09404a7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -124,9 +124,11 @@ BITCOIN_CORE_H = \
pow.h \
protocol.h \
random.h \
+ reverse_iterator.h \
reverselock.h \
rpc/blockchain.h \
rpc/client.h \
+ rpc/mining.h \
rpc/protocol.h \
rpc/server.h \
rpc/register.h \
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 942942c299..f8956508f6 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -5,7 +5,6 @@
#include "bench.h"
#include "wallet/wallet.h"
-#include <boost/foreach.hpp>
#include <set>
static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<COutput>& vCoins)
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 6093f78fb1..c6d5db786e 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -77,7 +77,7 @@ static int AppInitRawTx(int argc, char* argv[])
strUsage += HelpMessageOpt("in=TXID:VOUT(:SEQUENCE_NUMBER)", _("Add input to TX"));
strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N"));
strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
- strUsage += HelpMessageOpt("rbfoptin(=N)", _("Set RBF opt-in sequence number for input N (if not provided, opt-in all available inputs)"));
+ strUsage += HelpMessageOpt("replaceable(=N)", _("Set RBF opt-in sequence number for input N (if not provided, opt-in all available inputs)"));
strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
strUsage += HelpMessageOpt("outpubkey=VALUE:PUBKEY[:FLAGS]", _("Add pay-to-pubkey output to TX") + ". " +
_("Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output") + ". " +
@@ -673,7 +673,7 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
MutateTxVersion(tx, commandVal);
else if (command == "locktime")
MutateTxLocktime(tx, commandVal);
- else if (command == "rbfoptin") {
+ else if (command == "replaceable") {
MutateTxRBFOptIn(tx, commandVal);
}
diff --git a/src/bloom.cpp b/src/bloom.cpp
index cc3baa9185..fa884f0bf3 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -14,7 +14,6 @@
#include <math.h>
#include <stdlib.h>
-#include <boost/foreach.hpp>
#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
#define LN2 0.6931471805599453094172321214581765680755001343602552
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 13b5876530..e6b5fb72a7 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -6,12 +6,12 @@
#include "chain.h"
#include "chainparams.h"
+#include "reverse_iterator.h"
#include "validation.h"
#include "uint256.h"
#include <stdint.h>
-#include <boost/foreach.hpp>
namespace Checkpoints {
@@ -19,7 +19,7 @@ namespace Checkpoints {
{
const MapCheckpoints& checkpoints = data.mapCheckpoints;
- BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
+ for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints))
{
const uint256& hash = i.second;
BlockMap::const_iterator t = mapBlockIndex.find(hash);
diff --git a/src/checkqueue.h b/src/checkqueue.h
index d7b7b836dc..408e278d21 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -10,7 +10,6 @@
#include <algorithm>
#include <vector>
-#include <boost/foreach.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
diff --git a/src/core_read.cpp b/src/core_read.cpp
index dd9b5726a3..18d02fb913 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -27,7 +27,7 @@ CScript ParseScript(const std::string& s)
if (mapOpNames.empty())
{
- for (int op = 0; op <= OP_NOP10; op++)
+ for (int op = 0; op <= MAX_OPCODE; op++)
{
// Allow OP_RESERVED to get into mapOpNames
if (op < OP_NOP && op != OP_RESERVED)
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 553ef44874..7f38e9e565 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -15,7 +15,6 @@
#include "utilmoneystr.h"
#include "utilstrencodings.h"
-#include <boost/foreach.hpp>
std::string FormatScript(const CScript& script)
{
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 8c2e0da32f..a207d5ece4 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -18,7 +18,6 @@
#include <stdio.h>
#include <boost/algorithm/string.hpp> // boost::trim
-#include <boost/foreach.hpp>
/** WWW-Authenticate to present with 401 Unauthorized response */
static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";
diff --git a/src/init.cpp b/src/init.cpp
index 61b26d3618..1e85642019 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -215,6 +215,19 @@ void Shutdown()
fFeeEstimatesInitialized = false;
}
+ // FlushStateToDisk generates a SetBestChain callback, which we should avoid missing
+ FlushStateToDisk();
+
+ // After there are no more peers/RPC left to give us new data which may generate
+ // CValidationInterface callbacks, flush them...
+ GetMainSignals().FlushBackgroundCallbacks();
+
+ // Any future callbacks will be dropped. This should absolutely be safe - if
+ // missing a callback results in an unrecoverable situation, unclean shutdown
+ // would too. The only reason to do the above flushes is to let the wallet catch
+ // up with our current chain to avoid any strange pruning edge cases and make
+ // next startup faster by avoiding rescan.
+
{
LOCK(cs_main);
if (pcoinsTip != NULL) {
@@ -251,6 +264,7 @@ void Shutdown()
}
#endif
UnregisterAllValidationInterfaces();
+ GetMainSignals().UnregisterBackgroundSignalScheduler();
#ifdef ENABLE_WALLET
for (CWalletRef pwallet : vpwallets) {
delete pwallet;
@@ -1203,6 +1217,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler);
threadGroup.create_thread(boost::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
+ GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
+
/* Start the RPC server already. It will be started in "warmup" mode
* and not really process calls already (but it will signify connections
* that the server is there and will be ready later). Warmup mode will
diff --git a/src/memusage.h b/src/memusage.h
index 710120d285..93fd6a0eb5 100644
--- a/src/memusage.h
+++ b/src/memusage.h
@@ -15,7 +15,6 @@
#include <unordered_map>
#include <unordered_set>
-#include <boost/foreach.hpp>
namespace memusage
{
diff --git a/src/net.h b/src/net.h
index dc25e7a5dd..b9a11c62f2 100644
--- a/src/net.h
+++ b/src/net.h
@@ -33,7 +33,6 @@
#include <arpa/inet.h>
#endif
-#include <boost/foreach.hpp>
#include <boost/signals2/signal.hpp>
class CScheduler;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 4d832f3711..a743f04dd1 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -22,6 +22,7 @@
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "random.h"
+#include "reverse_iterator.h"
#include "tinyformat.h"
#include "txmempool.h"
#include "ui_interface.h"
@@ -827,7 +828,7 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
// Relay inventory, but don't relay old inventory during initial block download.
connman->ForEachNode([nNewHeight, &vHashes](CNode* pnode) {
if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 0)) {
- BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
+ for (const uint256& hash : reverse_iterate(vHashes)) {
pnode->PushBlockHash(hash);
}
}
@@ -2338,7 +2339,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
} else {
std::vector<CInv> vGetData;
// Download as much as possible, from earliest to latest.
- BOOST_REVERSE_FOREACH(const CBlockIndex *pindex, vToFetch) {
+ for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) {
if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
// Can't download any more from this peer
break;
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index e82268b095..565da6c154 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -40,6 +40,7 @@ public:
friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; }
friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; }
+ friend bool operator!=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK != b.nSatoshisPerK; }
CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }
std::string ToString() const;
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 771491770e..03fe11a0d8 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -16,6 +16,19 @@
static constexpr double INF_FEERATE = 1e99;
+std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon) {
+ static const std::map<FeeEstimateHorizon, std::string> horizon_strings = {
+ {FeeEstimateHorizon::SHORT_HALFLIFE, "short"},
+ {FeeEstimateHorizon::MED_HALFLIFE, "medium"},
+ {FeeEstimateHorizon::LONG_HALFLIFE, "long"},
+ };
+ auto horizon_string = horizon_strings.find(horizon);
+
+ if (horizon_string == horizon_strings.end()) return "unknown";
+
+ return horizon_string->second;
+}
+
std::string StringForFeeReason(FeeReason reason) {
static const std::map<FeeReason, std::string> fee_reason_strings = {
{FeeReason::NONE, "None"},
@@ -36,6 +49,20 @@ std::string StringForFeeReason(FeeReason reason) {
return reason_string->second;
}
+bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode) {
+ static const std::map<std::string, FeeEstimateMode> fee_modes = {
+ {"UNSET", FeeEstimateMode::UNSET},
+ {"ECONOMICAL", FeeEstimateMode::ECONOMICAL},
+ {"CONSERVATIVE", FeeEstimateMode::CONSERVATIVE},
+ };
+ auto mode = fee_modes.find(mode_string);
+
+ if (mode == fee_modes.end()) return false;
+
+ fee_estimate_mode = mode->second;
+ return true;
+}
+
/**
* 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
@@ -671,7 +698,7 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
break;
}
default: {
- return CFeeRate(0);
+ throw std::out_of_range("CBlockPoicyEstimator::estimateRawFee unknown FeeEstimateHorizon");
}
}
@@ -690,6 +717,24 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
return CFeeRate(median);
}
+unsigned int CBlockPolicyEstimator::HighestTargetTracked(FeeEstimateHorizon horizon) const
+{
+ switch (horizon) {
+ case FeeEstimateHorizon::SHORT_HALFLIFE: {
+ return shortStats->GetMaxConfirms();
+ }
+ case FeeEstimateHorizon::MED_HALFLIFE: {
+ return feeStats->GetMaxConfirms();
+ }
+ case FeeEstimateHorizon::LONG_HALFLIFE: {
+ return longStats->GetMaxConfirms();
+ }
+ default: {
+ throw std::out_of_range("CBlockPoicyEstimator::HighestTargetTracked unknown FeeEstimateHorizon");
+ }
+ }
+}
+
unsigned int CBlockPolicyEstimator::BlockSpan() const
{
if (firstRecordedHeight == 0) return 0;
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 2029ce3744..4c80371c5c 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -74,6 +74,8 @@ enum FeeEstimateHorizon {
LONG_HALFLIFE = 2
};
+std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon);
+
/* Enumeration of reason for returned fee estimate */
enum class FeeReason {
NONE,
@@ -90,6 +92,15 @@ enum class FeeReason {
std::string StringForFeeReason(FeeReason reason);
+/* Used to determine type of fee estimation requested */
+enum class FeeEstimateMode {
+ UNSET, //! Use default settings based on other criteria
+ ECONOMICAL, //! Force estimateSmartFee to use non-conservative estimates
+ CONSERVATIVE, //! Force estimateSmartFee to use conservative estimates
+};
+
+bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode);
+
/* Used to return detailed information about a feerate bucket */
struct EstimatorBucket
{
@@ -197,7 +208,7 @@ public:
* the closest target where one can be given. 'conservative' estimates are
* valid over longer time horizons also.
*/
- CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, const CTxMemPool& pool, bool conservative = true) const;
+ CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, const CTxMemPool& pool, bool conservative) const;
/** Return a specific fee estimate calculation with a given success
* threshold and time horizon, and optionally return detailed data about
@@ -214,6 +225,9 @@ public:
/** Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool */
void FlushUnconfirmed(CTxMemPool& pool);
+ /** Calculation of highest target that estimates are tracked for */
+ unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const;
+
private:
unsigned int nBestSeenHeight;
unsigned int firstRecordedHeight;
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 5f68c09a86..2f78d2f347 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -13,7 +13,6 @@
#include "util.h"
#include "utilstrencodings.h"
-#include <boost/foreach.hpp>
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
{
diff --git a/src/prevector.h b/src/prevector.h
index dc17e7ce4b..02d860bb00 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -132,7 +132,7 @@ public:
typedef const T* pointer;
typedef const T& reference;
typedef std::bidirectional_iterator_tag iterator_category;
- const_reverse_iterator(T* ptr_) : ptr(ptr_) {}
+ const_reverse_iterator(const T* ptr_) : ptr(ptr_) {}
const_reverse_iterator(reverse_iterator x) : ptr(&(*x)) {}
const T& operator*() const { return *ptr; }
const T* operator->() const { return ptr; }
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index d3ad24da01..2fa032abdc 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -10,7 +10,6 @@
#include "base58.h"
#include "wallet/wallet.h"
-#include <boost/foreach.hpp>
#include <QFont>
#include <QDebug>
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index a1e5cccc0b..b3d2cf1d55 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -21,9 +21,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"A fee rate (in %s/kB) that will be used when fee estimation has insufficient "
"data (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Accept connections from outside (default: 1 if no -proxy or -connect/-"
-"noconnect)"),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"Accept relayed transactions received from whitelisted peers even when not "
"relaying transactions (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -37,14 +34,16 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Bind to given address and whitelist peers connecting to it. Use [host]:port "
"notation for IPv6"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Bind to given address to listen for JSON-RPC connections. Use [host]:port "
-"notation for IPv6. This option can be specified multiple times (default: "
-"bind to all interfaces)"),
+"Bind to given address to listen for JSON-RPC connections. This option is "
+"ignored unless -rpcallowip is also passed. Port is optional and overrides -"
+"rpcport. Use [host]:port notation for IPv6. This option can be specified "
+"multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -"
+"rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot obtain a lock on data directory %s. %s is probably already running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Connect only to the specified node(s); -noconnect or -connect=0 alone to "
-"disable automatic connections"),
+"Connect only to the specified node(s); -connect=0 disables automatic "
+"connections"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Create new files with system default permissions, instead of umask 077 (only "
"effective with disabled wallet functionality)"),
@@ -62,13 +61,17 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Equivalent bytes per sigop in transactions for relay and mining (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Error loading %s: You can't enable HD on a already existing non-HD wallet"),
+"Error loading %s: You can't enable HD on an already existing non-HD wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error reading %s! All keys read correctly, but transaction data or address "
"book entries might be missing or incorrect."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error: Listening for incoming connections failed (listen returned error %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Exclude debugging information for a category. Can be used in conjunction "
+"with -debug=1 to output debug logs for all categories except one or more "
+"specified categories."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when a relevant alert is received or we see a really long "
"fork (%s in cmd is replaced by message)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -134,7 +137,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"reindex (download the whole blockchain again in case of pruned node)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Query for peer addresses via DNS lookup, if low on addresses (default: 1 "
-"unless -connect/-noconnect)"),
+"unless -connect used)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Randomize credentials for every proxy connection. This enables Tor stream "
"isolation (default: %u)"),
@@ -154,8 +157,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Set lowest fee rate (in %s/kB) for transactions to be included in block "
"creation. (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"Set the number of script verification threads (%u to %d, 0 = auto, <0 = "
"leave that many cores free, default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -186,6 +187,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = "
"no limit (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Unable to replay blocks. You will need to rebuild the database using -"
+"reindex-chainstate."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to rewind the database to a pre-fork state. You will need to "
"redownload the blockchain"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -225,6 +229,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: We do not appear to fully agree with our peers! You may need to "
"upgrade, or other nodes may need to upgrade."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Whether to save the mempool on shutdown and load on restart (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR "
"notated network (e.g. 1.2.3.0/24). Can be specified multiple times."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -235,13 +241,17 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"mode. This will redownload the entire blockchain"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"You need to rebuild the database using -reindex-chainstate to change -txindex"),
+QT_TRANSLATE_NOOP("bitcoin-core", "%d of last 100 blocks have unexpected version"),
QT_TRANSLATE_NOOP("bitcoin-core", "%s corrupt, salvage failed"),
QT_TRANSLATE_NOOP("bitcoin-core", "%s is set very high!"),
QT_TRANSLATE_NOOP("bitcoin-core", "(default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "(default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "(press q to shutdown and continue later)"),
QT_TRANSLATE_NOOP("bitcoin-core", "-maxmempool must be at least %d MB"),
+QT_TRANSLATE_NOOP("bitcoin-core", "-wallet parameter must only specify a filename (not a path)"),
QT_TRANSLATE_NOOP("bitcoin-core", "<category> can be:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept command line and JSON-RPC commands"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Accept connections from outside (default: 1 if no -proxy or -connect)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept public REST requests (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"),
@@ -274,10 +284,11 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing wallet database environmen
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet corrupted"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet requires newer version of %s"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: You can't disable HD on a already existing HD wallet"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: You can't disable HD on an already existing HD wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error upgrading chainstate database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: A fatal internal error occurred, see debug.log for details"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"),
@@ -291,18 +302,19 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong da
QT_TRANSLATE_NOOP("bitcoin-core", "Information"),
QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. %s is shutting down."),
QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address: '%s'"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address or hostname: '%s'"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address or hostname: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -%s=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -fallbackfee=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Invalid characters in -wallet filename"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Keep at most <n> unconnectable transactions in memory (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Keep the transaction memory pool below <n> megabytes (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Keypool ran out, please call keypoolrefill first"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on <port> (default: %u or testnet: %u)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Loading P2P addresses..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading banlist..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."),
@@ -329,12 +341,12 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Rebuild chain state from the currently indexe
QT_TRANSLATE_NOOP("bitcoin-core", "Reducing -maxconnections from %d to %d, because of system limitations."),
QT_TRANSLATE_NOOP("bitcoin-core", "Relay and mine data carrier transactions (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Relay non-P2SH multisig (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Replaying blocks..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions on startup"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Rewinding blocks..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of debug.log file"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Send transactions as zero-fee transactions if possible (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send transactions with full-RBF opt-in enabled (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set database cache size in megabytes (%d to %d, default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to <n> (default: %u)"),
@@ -374,13 +386,15 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'")
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -benchmark ignored, use -debug=bench."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -debugnet ignored, use -debug=net."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -tor found, use -onion."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported logging category %s=%s."),
QT_TRANSLATE_NOOP("bitcoin-core", "Upgrade wallet to latest format on startup"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Upgrading UTXO database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use the test chain"),
QT_TRANSLATE_NOOP("bitcoin-core", "User Agent comment (%s) contains unsafe characters."),
QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks..."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet..."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet(s)..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet %s resides outside data directory %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet debugging/testing options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart %s to complete"),
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index af9a888d94..c19420beb5 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -490,6 +490,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
else nBytesInputs += 148;
}
+ bool conservative_estimate = CalculateEstimateType(FeeEstimateMode::UNSET, coinControl->signalRbf);
+
// calculation
if (nQuantity > 0)
{
@@ -510,7 +512,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes -= 34;
// Fee
- nPayFee = CWallet::GetMinimumFee(nBytes, coinControl->nConfirmTarget, ::mempool, ::feeEstimator);
+ nPayFee = CWallet::GetMinimumFee(nBytes, coinControl->nConfirmTarget, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */, false /* ignoreGlobalPayTxFee */, conservative_estimate);
if (nPayAmount > 0)
{
@@ -585,7 +587,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), ::feeEstimator.estimateSmartFee(coinControl->nConfirmTarget, NULL, ::mempool).GetFeePerK()) / 1000;
+ dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), ::feeEstimator.estimateSmartFee(coinControl->nConfirmTarget, NULL, ::mempool, conservative_estimate).GetFeePerK()) / 1000;
}
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index f62f1e4a73..9183075067 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -127,7 +127,7 @@
<context>
<name>AddressTableModel</name>
<message>
- <location filename="../addresstablemodel.cpp" line="+170"/>
+ <location filename="../addresstablemodel.cpp" line="+169"/>
<source>Label</source>
<translation type="unfinished"></translation>
</message>
@@ -304,12 +304,12 @@
<translation>Sign &amp;message...</translation>
</message>
<message>
- <location line="+427"/>
+ <location line="+429"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
- <location line="-505"/>
+ <location line="-507"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
@@ -404,7 +404,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+357"/>
+ <location line="+359"/>
<source>Click to disable network activity.</source>
<translation type="unfinished"></translation>
</message>
@@ -429,7 +429,7 @@
<translation>Reindexing blocks on disk...</translation>
</message>
<message>
- <location line="-508"/>
+ <location line="-510"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -459,12 +459,12 @@
<translation>&amp;Verify message...</translation>
</message>
<message>
- <location line="+514"/>
+ <location line="+516"/>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
<message>
- <location line="-739"/>
+ <location line="-741"/>
<source>Wallet</source>
<translation>Wallet</translation>
</message>
@@ -549,7 +549,7 @@
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+354"/>
+ <location line="+356"/>
<source>%n active connection(s) to Bitcoin network</source>
<translation>
<numerusform>%n active connection to Bitcoin network</numerusform>
@@ -610,12 +610,12 @@
<translation>Up to date</translation>
</message>
<message>
- <location line="-438"/>
+ <location line="-440"/>
<source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+197"/>
+ <location line="+199"/>
<source>%1 client</source>
<translation type="unfinished"></translation>
</message>
@@ -690,7 +690,7 @@
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="+518"/>
+ <location filename="../bitcoin.cpp" line="+524"/>
<source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
<translation type="unfinished"></translation>
</message>
@@ -783,7 +783,7 @@
<translation type="unfinished">Confirmed</translation>
</message>
<message>
- <location filename="../coincontroldialog.cpp" line="+55"/>
+ <location filename="../coincontroldialog.cpp" line="+54"/>
<source>Copy address</source>
<translation type="unfinished"></translation>
</message>
@@ -849,7 +849,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+183"/>
+ <location line="+155"/>
<source>yes</source>
<translation type="unfinished"></translation>
</message>
@@ -956,7 +956,7 @@
<context>
<name>FreespaceChecker</name>
<message>
- <location filename="../intro.cpp" line="+78"/>
+ <location filename="../intro.cpp" line="+76"/>
<source>A new data directory will be created.</source>
<translation>A new data directory will be created.</translation>
</message>
@@ -1068,12 +1068,22 @@
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+157"/>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+10"/>
- <source>%1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source>
+ <source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
+ <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-160"/>
<source>Use the default data directory</source>
<translation>Use the default data directory</translation>
</message>
@@ -1083,7 +1093,32 @@
<translation>Use a custom data directory:</translation>
</message>
<message>
- <location filename="../intro.cpp" line="+94"/>
+ <location filename="../intro.cpp" line="+20"/>
+ <source>Bitcoin</source>
+ <translation type="unfinished">Bitcoin</translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Approximately %1 GB of data will be stored in this directory.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <source>%1 will download and store a copy of the Bitcoin block chain.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+70"/>
<source>Error: Specified data directory &quot;%1&quot; cannot be created.</source>
<translation type="unfinished"></translation>
</message>
@@ -1257,7 +1292,14 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+94"/>
+ <location line="-118"/>
+ <location line="+23"/>
+ <location line="+23"/>
+ <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+166"/>
<source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
<translation type="unfinished"></translation>
</message>
@@ -1278,7 +1320,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+43"/>
+ <location line="+45"/>
+ <source>Open the %1 configuration file from the working directory.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Open Configuration File</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
<source>Reset all client options to default.</source>
<translation>Reset all client options to default.</translation>
</message>
@@ -1288,7 +1340,7 @@
<translation>&amp;Reset Options</translation>
</message>
<message>
- <location line="-514"/>
+ <location line="-529"/>
<source>&amp;Network</source>
<translation>&amp;Network</translation>
</message>
@@ -1366,14 +1418,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
<location line="+23"/>
- <location line="+23"/>
- <source>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="-36"/>
<source>IPv4</source>
<translation type="unfinished"></translation>
</message>
@@ -1458,7 +1503,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+612"/>
+ <location line="+646"/>
<source>&amp;OK</source>
<translation>&amp;OK</translation>
</message>
@@ -1468,7 +1513,7 @@
<translation>&amp;Cancel</translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="+86"/>
+ <location filename="../optionsdialog.cpp" line="+84"/>
<source>default</source>
<translation>default</translation>
</message>
@@ -1484,22 +1529,42 @@
</message>
<message>
<location line="+1"/>
- <location line="+43"/>
+ <location line="+55"/>
<source>Client restart required to activate changes.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-43"/>
+ <location line="-55"/>
<source>Client will be shut down. Do you want to proceed?</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+47"/>
+ <location line="+15"/>
+ <source>Configuration options</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Error</source>
+ <translation type="unfinished">Error</translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>The configuration file could not be opened.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+38"/>
<source>This change would require a client restart.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+25"/>
+ <location line="+28"/>
<source>The supplied proxy address is invalid.</source>
<translation>The supplied proxy address is invalid.</translation>
</message>
@@ -1755,12 +1820,12 @@
<translation type="unfinished">Amount</translation>
</message>
<message>
- <location filename="../guiutil.cpp" line="+136"/>
+ <location filename="../guiutil.cpp" line="+130"/>
<source>Enter a Bitcoin address (e.g. %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+759"/>
+ <location line="+766"/>
<source>%1 d</source>
<translation type="unfinished"></translation>
</message>
@@ -1850,7 +1915,7 @@
</translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="+172"/>
+ <location filename="../bitcoin.cpp" line="+173"/>
<source>%1 didn&apos;t yet exit safely...</source>
<translation type="unfinished"></translation>
</message>
@@ -2007,7 +2072,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+404"/>
+ <location line="+324"/>
+ <source>&amp;Reset</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+80"/>
<location line="+558"/>
<source>Received</source>
<translation type="unfinished"></translation>
@@ -2030,8 +2100,8 @@
</message>
<message>
<location line="+60"/>
- <location filename="../rpcconsole.cpp" line="+456"/>
- <location line="+719"/>
+ <location filename="../rpcconsole.cpp" line="+458"/>
+ <location line="+728"/>
<source>Select a peer to view detailed information.</source>
<translation type="unfinished"></translation>
</message>
@@ -2157,12 +2227,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+52"/>
- <source>&amp;Clear</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+16"/>
+ <location line="+68"/>
<source>Totals</source>
<translation type="unfinished"></translation>
</message>
@@ -2187,7 +2252,7 @@
<translation>Clear console</translation>
</message>
<message>
- <location filename="../rpcconsole.cpp" line="-214"/>
+ <location filename="../rpcconsole.cpp" line="-223"/>
<source>1 &amp;hour</source>
<translation type="unfinished"></translation>
</message>
@@ -2225,23 +2290,23 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+126"/>
+ <location line="+135"/>
<source>Welcome to the %1 RPC console.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
- <translation>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Type &lt;b&gt;help&lt;/b&gt; for an overview of available commands.</source>
<translation>Type &lt;b&gt;help&lt;/b&gt; for an overview of available commands.</translation>
</message>
<message>
- <location line="+2"/>
- <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.</source>
+ <location line="-1"/>
+ <source>Use up and down arrows to navigate history, and %1 to clear screen.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -2494,7 +2559,7 @@
<context>
<name>RecentRequestsTableModel</name>
<message>
- <location filename="../recentrequeststablemodel.cpp" line="+29"/>
+ <location filename="../recentrequeststablemodel.cpp" line="+28"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -2509,7 +2574,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+40"/>
+ <location line="+39"/>
<source>(no label)</source>
<translation type="unfinished"></translation>
</message>
@@ -2533,7 +2598,7 @@
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
- <location filename="../sendcoinsdialog.cpp" line="+554"/>
+ <location filename="../sendcoinsdialog.cpp" line="+565"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
@@ -2608,7 +2673,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+37"/>
+ <location line="+24"/>
+ <source>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until your have validated the complete chain.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <source>Warning: Fee estimation is currently not possible.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+26"/>
<source>collapse fee-settings</source>
<translation type="unfinished"></translation>
</message>
@@ -2619,22 +2694,16 @@
</message>
<message>
<location line="-3"/>
- <location line="+16"/>
<source>If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then &quot;per kilobyte&quot; only pays 250 satoshis in fee, while &quot;total at least&quot; pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-64"/>
+ <location line="-48"/>
<source>Hide</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+67"/>
- <source>total at least</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+30"/>
+ <location line="+84"/>
<location line="+13"/>
<source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
<translation type="unfinished"></translation>
@@ -2670,7 +2739,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+102"/>
+ <location line="+30"/>
+ <source>Request Replace-By-Fee</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Indicates that the sender may wish to replace this transaction with a new one paying higher fees (prior to being confirmed).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+79"/>
<source>Send to multiple recipients at once</source>
<translation>Send to multiple recipients at once</translation>
</message>
@@ -2685,17 +2764,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-876"/>
+ <location line="-895"/>
<source>Dust:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+691"/>
+ <location line="+700"/>
<source>Confirmation time target:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+188"/>
+ <location line="+198"/>
<source>Clear &amp;All</source>
<translation>Clear &amp;All</translation>
</message>
@@ -2715,7 +2794,7 @@
<translation>S&amp;end</translation>
</message>
<message>
- <location filename="../sendcoinsdialog.cpp" line="-486"/>
+ <location filename="../sendcoinsdialog.cpp" line="-497"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
@@ -2750,7 +2829,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+205"/>
+ <location line="+209"/>
<location line="+5"/>
<location line="+5"/>
<location line="+4"/>
@@ -2778,7 +2857,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+5"/>
+ <source>This transaction signals replaceability (optin-RBF).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
<source>Confirm send coins</source>
<translation type="unfinished"></translation>
</message>
@@ -2828,7 +2912,7 @@
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+67"/>
+ <location line="+63"/>
<source>%n block(s)</source>
<translation>
<numerusform>%n block</numerusform>
@@ -2836,12 +2920,12 @@
</translation>
</message>
<message>
- <location line="+28"/>
+ <location line="+24"/>
<source>Pay only the required fee of %1</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+25"/>
+ <location line="+30"/>
<source>Estimated to begin confirmation within %n block(s).</source>
<translation>
<numerusform>Estimated to begin confirmation within %n block.</numerusform>
@@ -2849,7 +2933,7 @@
</translation>
</message>
<message>
- <location line="+102"/>
+ <location line="+103"/>
<source>Warning: Invalid Bitcoin address</source>
<translation type="unfinished"></translation>
</message>
@@ -2986,7 +3070,7 @@
<context>
<name>SendConfirmationDialog</name>
<message>
- <location filename="../sendcoinsdialog.cpp" line="+95"/>
+ <location filename="../sendcoinsdialog.cpp" line="+86"/>
<location line="+5"/>
<source>Yes</source>
<translation type="unfinished"></translation>
@@ -3198,7 +3282,7 @@
<context>
<name>TrafficGraphWidget</name>
<message>
- <location filename="../trafficgraphwidget.cpp" line="+79"/>
+ <location filename="../trafficgraphwidget.cpp" line="+80"/>
<source>KB/s</source>
<translation type="unfinished"></translation>
</message>
@@ -3427,7 +3511,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+21"/>
+ <location line="+20"/>
<source>Amount</source>
<translation type="unfinished">Amount</translation>
</message>
@@ -3460,7 +3544,7 @@
<context>
<name>TransactionTableModel</name>
<message>
- <location filename="../transactiontablemodel.cpp" line="+246"/>
+ <location filename="../transactiontablemodel.cpp" line="+248"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -3606,7 +3690,7 @@
<context>
<name>TransactionView</name>
<message>
- <location filename="../transactionview.cpp" line="+69"/>
+ <location filename="../transactionview.cpp" line="+70"/>
<location line="+16"/>
<source>All</source>
<translation type="unfinished"></translation>
@@ -3677,12 +3761,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+36"/>
+ <location line="+37"/>
<source>Abandon transaction</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
+ <source>Increase transaction fee</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
<source>Copy address</source>
<translation type="unfinished"></translation>
</message>
@@ -3722,7 +3811,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+186"/>
+ <location line="+193"/>
<source>Export Transaction History</source>
<translation type="unfinished"></translation>
</message>
@@ -3787,7 +3876,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+147"/>
+ <location line="+166"/>
<source>Range:</source>
<translation type="unfinished"></translation>
</message>
@@ -3816,10 +3905,57 @@
<context>
<name>WalletModel</name>
<message>
- <location filename="../walletmodel.cpp" line="+291"/>
+ <location filename="../walletmodel.cpp" line="+289"/>
<source>Send Coins</source>
<translation type="unfinished">Send Coins</translation>
</message>
+ <message>
+ <location line="+385"/>
+ <location line="+46"/>
+ <location line="+9"/>
+ <source>Fee bump error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-55"/>
+ <source>Increasing transaction fee failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Do you want to increase the fee?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Current fee:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Increase:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>New fee:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Confirm fee bump</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+22"/>
+ <source>Can&apos;t sign transaction.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <source>Could not commit transaction</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>WalletView</name>
@@ -3867,7 +4003,7 @@
<context>
<name>bitcoin-core</name>
<message>
- <location filename="../bitcoinstrings.cpp" line="+318"/>
+ <location filename="../bitcoinstrings.cpp" line="+330"/>
<source>Options:</source>
<translation>Options:</translation>
</message>
@@ -3877,37 +4013,27 @@
<translation>Specify data directory</translation>
</message>
<message>
- <location line="-90"/>
+ <location line="-92"/>
<source>Connect to a node to retrieve peer addresses, and disconnect</source>
<translation>Connect to a node to retrieve peer addresses, and disconnect</translation>
</message>
<message>
- <location line="+93"/>
+ <location line="+95"/>
<source>Specify your own public address</source>
<translation>Specify your own public address</translation>
</message>
<message>
- <location line="-108"/>
+ <location line="-111"/>
<source>Accept command line and JSON-RPC commands</source>
<translation>Accept command line and JSON-RPC commands</translation>
</message>
<message>
- <location line="-221"/>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+22"/>
- <source>Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+12"/>
+ <location line="-197"/>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+37"/>
+ <location line="+41"/>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
<translation type="unfinished"></translation>
</message>
@@ -3927,7 +4053,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+132"/>
+ <location line="+140"/>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
<translation type="unfinished"></translation>
</message>
@@ -3937,22 +4063,22 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+40"/>
+ <location line="+41"/>
<source>Pruning blockstore...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+11"/>
<source>Run in the background as a daemon and accept commands</source>
<translation>Run in the background as a daemon and accept commands</translation>
</message>
<message>
- <location line="+37"/>
+ <location line="+36"/>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-360"/>
+ <location line="-372"/>
<source>Bitcoin Core</source>
<translation type="unfinished">Bitcoin Core</translation>
</message>
@@ -3967,7 +4093,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+3"/>
<source>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</source>
<translation type="unfinished"></translation>
</message>
@@ -3977,7 +4103,7 @@
<translation>Bind to given address and always listen on it. Use [host]:port notation for IPv6</translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+12"/>
<source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
<translation type="unfinished"></translation>
</message>
@@ -3987,17 +4113,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
- <source>Error loading %s: You can&apos;t enable HD on a already existing non-HD wallet</source>
+ <location line="+15"/>
+ <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
- <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
+ <location line="+5"/>
+ <source>Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+7"/>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</translation>
</message>
@@ -4032,7 +4158,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+8"/>
+ <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
<translation type="unfinished"></translation>
</message>
@@ -4042,7 +4173,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+3"/>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation type="unfinished"></translation>
</message>
@@ -4058,6 +4189,11 @@
</message>
<message>
<location line="+15"/>
+ <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
<translation type="unfinished"></translation>
</message>
@@ -4087,27 +4223,52 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+12"/>
+ <location line="+3"/>
+ <source>Whether to save the mempool on shutdown and load on restart (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+11"/>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
+ <source>%d of last 100 blocks have unexpected version</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>%s corrupt, salvage failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
+ <source>(press q to shutdown and continue later)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>-maxmempool must be at least %d MB</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
+ <source>-wallet parameter must only specify a filename (not a path)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>&lt;category&gt; can be:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+2"/>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
<source>Append comment to the user agent string</source>
<translation type="unfinished"></translation>
</message>
@@ -4217,12 +4378,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>Error loading %s: You can&apos;t disable HD on a already existing HD wallet</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Error loading block database</source>
<translation>Error loading block database</translation>
</message>
@@ -4232,7 +4388,7 @@
<translation>Error opening block database</translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+5"/>
<source>Error: Disk space is low!</source>
<translation>Error: Disk space is low!</translation>
</message>
@@ -4257,27 +4413,32 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
- <source>Invalid -onion address: &apos;%s&apos;</source>
+ <location line="+4"/>
+ <source>Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Invalid amount for -fallbackfee=&lt;amount&gt;: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
- <source>Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
+ <source>Invalid characters in -wallet filename</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>Invalid amount for -fallbackfee=&lt;amount&gt;: &apos;%s&apos;</source>
+ <location line="+3"/>
+ <source>Keep the transaction memory pool below &lt;n&gt; megabytes (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
- <source>Keep the transaction memory pool below &lt;n&gt; megabytes (default: %u)</source>
+ <source>Loading P2P addresses...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+1"/>
<source>Loading banlist...</source>
<translation type="unfinished"></translation>
</message>
@@ -4327,12 +4488,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+4"/>
+ <source>Replaying blocks...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Rewinding blocks...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+4"/>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation type="unfinished"></translation>
</message>
@@ -4372,7 +4538,17 @@
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+1"/>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+2"/>
+ <source>Upgrading UTXO database</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Use UPnP to map the listening port (default: %u)</source>
<translation type="unfinished"></translation>
</message>
@@ -4392,12 +4568,7 @@
<translation>Verifying blocks...</translation>
</message>
<message>
- <location line="+1"/>
- <source>Verifying wallet...</source>
- <translation>Verifying wallet...</translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Wallet %s resides outside data directory %s</source>
<translation>Wallet %s resides outside data directory %s</translation>
</message>
@@ -4417,7 +4588,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-358"/>
+ <location line="-375"/>
<source>Allow JSON-RPC connections from specified source. Valid for &lt;ip&gt; are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times</source>
<translation type="unfinished"></translation>
</message>
@@ -4427,12 +4598,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+9"/>
+ <location line="+14"/>
<source>Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)</source>
<translation type="unfinished"></translation>
</message>
@@ -4447,7 +4613,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+6"/>
<source>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</source>
<translation>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</translation>
</message>
@@ -4477,22 +4643,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+18"/>
- <source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+15"/>
+ <location line="+31"/>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+28"/>
+ <location line="+31"/>
<source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+31"/>
+ <location line="+33"/>
<source>Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway</source>
<translation type="unfinished"></translation>
</message>
@@ -4502,12 +4663,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+9"/>
<source>(default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+7"/>
<source>Accept public REST requests (default: %u)</source>
<translation type="unfinished"></translation>
</message>
@@ -4522,11 +4683,21 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+22"/>
+ <location line="+19"/>
+ <source>Error loading %s: You can&apos;t disable HD on an already existing HD wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Error reading from database, shutting down.</source>
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+1"/>
+ <source>Error upgrading chainstate database</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+8"/>
<source>Imports blocks from external blk000??.dat file on startup</source>
<translation type="unfinished"></translation>
@@ -4537,12 +4708,22 @@
<translation>Information</translation>
</message>
<message>
- <location line="+7"/>
- <source>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least %s)</source>
+ <location line="+3"/>
+ <source>Invalid -onion address or hostname: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
+ <source>Invalid -proxy address or hostname: &apos;%s&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least %s)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
<source>Invalid netmask specified in -whitelist: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
@@ -4572,7 +4753,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+4"/>
<source>Rescan the block chain for missing wallet transactions on startup</source>
<translation type="unfinished"></translation>
</message>
@@ -4582,11 +4763,6 @@
<translation>Send trace/debug info to console instead of debug.log file</translation>
</message>
<message>
- <location line="+1"/>
- <source>Send transactions as zero-fee transactions if possible (default: %u)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<location line="+7"/>
<source>Show all debugging options (usage: --help -help-debug)</source>
<translation type="unfinished"></translation>
@@ -4642,17 +4818,22 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+8"/>
<source>Upgrade wallet to latest format on startup</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+5"/>
<source>Username for JSON-RPC connections</source>
<translation>Username for JSON-RPC connections</translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+2"/>
+ <source>Verifying wallet(s)...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
<source>Warning</source>
<translation>Warning</translation>
</message>
@@ -4677,27 +4858,22 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-73"/>
+ <location line="-75"/>
<source>Password for JSON-RPC connections</source>
<translation>Password for JSON-RPC connections</translation>
</message>
<message>
- <location line="-242"/>
+ <location line="-251"/>
<source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
<translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation>
</message>
<message>
- <location line="+170"/>
+ <location line="+177"/>
<source>Allow DNS lookups for -addnode, -seednode and -connect</source>
<translation>Allow DNS lookups for -addnode, -seednode and -connect</translation>
</message>
<message>
- <location line="+58"/>
- <source>Loading addresses...</source>
- <translation>Loading addresses...</translation>
- </message>
- <message>
- <location line="-291"/>
+ <location line="-243"/>
<source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source>
<translation type="unfinished"></translation>
</message>
@@ -4707,7 +4883,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+43"/>
+ <location line="+19"/>
+ <source>Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <source>Connect only to the specified node(s); -connect=0 disables automatic connections</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+15"/>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation type="unfinished"></translation>
</message>
@@ -4717,7 +4903,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+24"/>
+ <location line="+2"/>
+ <source>Error loading %s: You can&apos;t enable HD on an already existing non-HD wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+26"/>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -4747,12 +4938,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+26"/>
+ <location line="+37"/>
<source>Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)</source>
<translation type="unfinished"></translation>
</message>
@@ -4782,7 +4968,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+9"/>
<source>Unsupported argument -socks found. Setting SOCKS version isn&apos;t possible anymore, only SOCKS5 proxies are supported.</source>
<translation type="unfinished"></translation>
</message>
@@ -4807,12 +4993,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+9"/>
<source>Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+12"/>
+ <location line="+13"/>
<source>%s is set very high!</source>
<translation type="unfinished"></translation>
</message>
@@ -4822,12 +5008,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+11"/>
<source>Always query for peer addresses via DNS lookup (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+38"/>
+ <location line="+39"/>
<source>How many blocks to check at startup (default: %u, 0 = all)</source>
<translation type="unfinished"></translation>
</message>
@@ -4837,12 +5023,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
- <source>Invalid -proxy address: &apos;%s&apos;</source>
- <translation>Invalid -proxy address: &apos;%s&apos;</translation>
- </message>
- <message>
- <location line="+7"/>
+ <location line="+14"/>
<source>Keypool ran out, please call keypoolrefill first</source>
<translation type="unfinished"></translation>
</message>
@@ -4977,27 +5158,27 @@
<translation>Unknown network specified in -onlynet: &apos;%s&apos;</translation>
</message>
<message>
- <location line="-80"/>
+ <location line="-81"/>
<source>Insufficient funds</source>
<translation>Insufficient funds</translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+15"/>
<source>Loading block index...</source>
<translation>Loading block index...</translation>
</message>
<message>
- <location line="-61"/>
+ <location line="-63"/>
<source>Add a node to connect to and attempt to keep the connection open</source>
<translation>Add a node to connect to and attempt to keep the connection open</translation>
</message>
<message>
- <location line="+62"/>
+ <location line="+64"/>
<source>Loading wallet...</source>
<translation>Loading wallet...</translation>
</message>
<message>
- <location line="-55"/>
+ <location line="-57"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
@@ -5007,17 +5188,17 @@
<translation>Cannot write default address</translation>
</message>
<message>
- <location line="+78"/>
+ <location line="+81"/>
<source>Rescanning...</source>
<translation>Rescanning...</translation>
</message>
<message>
- <location line="-67"/>
+ <location line="-70"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>
<message>
- <location line="+15"/>
+ <location line="+16"/>
<source>Error</source>
<translation>Error</translation>
</message>
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 470fb6b377..4e88c8802c 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -11,7 +11,6 @@
#include "clientversion.h"
#include "streams.h"
-#include <boost/foreach.hpp>
RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel *parent) :
QAbstractTableModel(parent), walletModel(parent)
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 12d2d0f31c..27634eb179 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -166,6 +166,8 @@ void SendCoinsDialog::setModel(WalletModel *_model)
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
+ connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel()));
+ connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000));
updateFeeSectionControls();
updateMinFeeLabel();
@@ -652,7 +654,8 @@ void SendCoinsDialog::updateSmartFeeLabel()
int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
FeeCalculation feeCalc;
- CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &feeCalc, ::mempool);
+ bool conservative_estimate = CalculateEstimateType(FeeEstimateMode::UNSET, ui->optInRBF->isChecked());
+ CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &feeCalc, ::mempool, conservative_estimate);
if (feeRate <= CFeeRate(0)) // not enough data => minfee
{
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
@@ -827,6 +830,7 @@ void SendCoinsDialog::coinControlUpdateLabels()
} else {
CoinControlDialog::coinControl->nConfirmTarget = model->getDefaultConfirmTarget();
}
+ CoinControlDialog::coinControl->signalRbf = ui->optInRBF->isChecked();
for(int i = 0; i < ui->entries->count(); ++i)
{
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index 26dec3c610..fbad9e544a 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -12,6 +12,7 @@
#include "rpc/server.h"
#include "rpcconsole.h"
#include "test/testutil.h"
+#include "test/test_bitcoin.h"
#include "univalue.h"
#include "util.h"
@@ -35,8 +36,6 @@ void RPCNestedTests::rpcNestedTests()
{
// do some test setup
// could be moved to a more generic place when we add more tests on QT level
- const CChainParams& chainparams = Params();
- RegisterAllCoreRPCCommands(tableRPC);
tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
ClearDatadirCache();
std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_bitcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
@@ -44,15 +43,8 @@ void RPCNestedTests::rpcNestedTests()
dir.mkpath(".");
ForceSetArg("-datadir", path);
//mempool.setSanityCheck(1.0);
- pblocktree = new CBlockTreeDB(1 << 20, true);
- pcoinsdbview = new CCoinsViewDB(1 << 23, true);
- pcoinsTip = new CCoinsViewCache(pcoinsdbview);
- InitBlockIndex(chainparams);
- {
- CValidationState state;
- bool ok = ActivateBestChain(state, chainparams);
- QVERIFY(ok);
- }
+
+ TestingSetup test;
SetRPCWarmupFinished();
@@ -145,13 +137,5 @@ void RPCNestedTests::rpcNestedTests()
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
#endif
- UnloadBlockIndex();
- delete pcoinsTip;
- pcoinsTip = nullptr;
- delete pcoinsdbview;
- pcoinsdbview = nullptr;
- delete pblocktree;
- pblocktree = nullptr;
-
fs::remove_all(fs::path(path));
}
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index da070da084..03fd734e92 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -12,7 +12,6 @@
#include <stdint.h>
-#include <boost/foreach.hpp>
/* Return positive answer if transaction should be shown in list.
*/
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 6538a80233..60b55da3e7 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -19,6 +19,7 @@
#include "keystore.h"
#include "validation.h"
#include "net.h" // for g_connman
+#include "policy/fees.h"
#include "policy/rbf.h"
#include "sync.h"
#include "ui_interface.h"
@@ -34,7 +35,6 @@
#include <QSet>
#include <QTimer>
-#include <boost/foreach.hpp>
WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *_wallet, OptionsModel *_optionsModel, QObject *parent) :
QObject(parent), wallet(_wallet), optionsModel(_optionsModel), addressTableModel(0),
@@ -668,7 +668,7 @@ bool WalletModel::bumpFee(uint256 hash)
std::unique_ptr<CFeeBumper> feeBump;
{
LOCK2(cs_main, wallet->cs_wallet);
- feeBump.reset(new CFeeBumper(wallet, hash, nTxConfirmTarget, false, 0, true));
+ feeBump.reset(new CFeeBumper(wallet, hash, nTxConfirmTarget, false, 0, true, FeeEstimateMode::UNSET));
}
if (feeBump->getResult() != BumpFeeResult::OK)
{
diff --git a/src/reverse_iterator.h b/src/reverse_iterator.h
new file mode 100644
index 0000000000..409f895ce0
--- /dev/null
+++ b/src/reverse_iterator.h
@@ -0,0 +1,39 @@
+// Taken from https://gist.github.com/arvidsson/7231973
+
+#ifndef BITCOIN_REVERSE_ITERATOR_HPP
+#define BITCOIN_REVERSE_ITERATOR_HPP
+
+/**
+ * Template used for reverse iteration in C++11 range-based for loops.
+ *
+ * std::vector<int> v = {1, 2, 3, 4, 5};
+ * for (auto x : reverse_iterate(v))
+ * std::cout << x << " ";
+ */
+
+template <typename T>
+class reverse_range
+{
+ T &x;
+
+public:
+ reverse_range(T &x) : x(x) {}
+
+ auto begin() const -> decltype(this->x.rbegin())
+ {
+ return x.rbegin();
+ }
+
+ auto end() const -> decltype(this->x.rend())
+ {
+ return x.rend();
+ }
+};
+
+template <typename T>
+reverse_range<T> reverse_iterate(T &x)
+{
+ return reverse_range<T>(x);
+}
+
+#endif // BITCOIN_REVERSE_ITERATOR_HPP
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index cb1539dce5..775ad4b6c9 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -37,6 +37,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getnetworkhashps", 1, "height" },
{ "sendtoaddress", 1, "amount" },
{ "sendtoaddress", 4, "subtractfeefromamount" },
+ { "sendtoaddress", 5 , "replaceable" },
+ { "sendtoaddress", 6 , "conf_target" },
{ "settxfee", 0, "amount" },
{ "getreceivedbyaddress", 1, "minconf" },
{ "getreceivedbyaccount", 1, "minconf" },
@@ -69,6 +71,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendmany", 1, "amounts" },
{ "sendmany", 2, "minconf" },
{ "sendmany", 4, "subtractfeefrom" },
+ { "sendmany", 5 , "replaceable" },
+ { "sendmany", 6 , "conf_target" },
{ "addmultisigaddress", 0, "nrequired" },
{ "addmultisigaddress", 1, "keys" },
{ "createmultisig", 0, "nrequired" },
@@ -79,6 +83,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "listunspent", 3, "include_unsafe" },
{ "listunspent", 4, "query_options" },
{ "getblock", 1, "verbosity" },
+ { "getblock", 1, "verbose" },
{ "getblockheader", 1, "verbose" },
{ "getchaintxstats", 0, "nblocks" },
{ "gettransaction", 1, "include_watchonly" },
@@ -86,7 +91,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "createrawtransaction", 0, "inputs" },
{ "createrawtransaction", 1, "outputs" },
{ "createrawtransaction", 2, "locktime" },
- { "createrawtransaction", 3, "optintorbf" },
+ { "createrawtransaction", 3, "replaceable" },
{ "signrawtransaction", 1, "prevtxs" },
{ "signrawtransaction", 2, "privkeys" },
{ "sendrawtransaction", 1, "allowhighfees" },
@@ -112,7 +117,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "estimatesmartfee", 1, "conservative" },
{ "estimaterawfee", 0, "nblocks" },
{ "estimaterawfee", 1, "threshold" },
- { "estimaterawfee", 2, "horizon" },
{ "prioritisetransaction", 1, "dummy" },
{ "prioritisetransaction", 2, "fee_delta" },
{ "setban", 2, "bantime" },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 8c682592c5..046c85a76e 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -18,6 +18,7 @@
#include "policy/fees.h"
#include "pow.h"
#include "rpc/blockchain.h"
+#include "rpc/mining.h"
#include "rpc/server.h"
#include "txmempool.h"
#include "util.h"
@@ -141,42 +142,6 @@ UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGen
return blockHashes;
}
-UniValue generate(const JSONRPCRequest& request)
-{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
- "generate nblocks ( maxtries )\n"
- "\nMine up to nblocks blocks immediately (before the RPC call returns)\n"
- "\nArguments:\n"
- "1. nblocks (numeric, required) How many blocks are generated immediately.\n"
- "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
- "\nResult:\n"
- "[ blockhashes ] (array) hashes of blocks generated\n"
- "\nExamples:\n"
- "\nGenerate 11 blocks\n"
- + HelpExampleCli("generate", "11")
- );
-
- int nGenerate = request.params[0].get_int();
- uint64_t nMaxTries = 1000000;
- if (request.params.size() > 1) {
- nMaxTries = request.params[1].get_int();
- }
-
- std::shared_ptr<CReserveScript> coinbaseScript;
- GetMainSignals().ScriptForMining(coinbaseScript);
-
- // If the keypool is exhausted, no script is returned at all. Catch this.
- if (!coinbaseScript)
- throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
-
- //throw an error if no script was provided
- if (coinbaseScript->reserveScript.empty())
- throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)");
-
- return generateBlocks(coinbaseScript, nGenerate, nMaxTries, true);
-}
-
UniValue generatetoaddress(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
@@ -873,9 +838,9 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
UniValue estimaterawfee(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1|| request.params.size() > 3)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
- "estimaterawfee nblocks (threshold horizon)\n"
+ "estimaterawfee nblocks (threshold)\n"
"\nWARNING: This interface is unstable and may disappear or change!\n"
"\nWARNING: This is an advanced API call that is tightly coupled to the specific\n"
" implementation of fee estimation. The parameters it can be called with\n"
@@ -884,72 +849,95 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
"confirmation within nblocks blocks if possible. Uses virtual transaction size as defined\n"
"in BIP 141 (witness data is discounted).\n"
"\nArguments:\n"
- "1. nblocks (numeric)\n"
+ "1. nblocks (numeric) Confirmation target in blocks (1 - 1008)\n"
"2. threshold (numeric, optional) The proportion of transactions in a given feerate range that must have been\n"
" confirmed within nblocks in order to consider those feerates as high enough and proceed to check\n"
" lower buckets. Default: 0.95\n"
- "3. horizon (numeric, optional) How long a history of estimates to consider. 0=short, 1=medium, 2=long.\n"
- " Default: 1\n"
"\nResult:\n"
"{\n"
- " \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in BTC)\n"
- " \"decay\" : x.x, (numeric) exponential decay (per block) for historical moving average of confirmation data\n"
- " \"scale\" : x, (numeric) The resolution of confirmation targets at this time horizon\n"
- " \"pass\" : { (json object) information about the lowest range of feerates to succeed in meeting the threshold\n"
- " \"startrange\" : x.x, (numeric) start of feerate range\n"
- " \"endrange\" : x.x, (numeric) end of feerate range\n"
- " \"withintarget\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed within target\n"
- " \"totalconfirmed\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed at any point\n"
- " \"inmempool\" : x.x, (numeric) current number of txs in mempool in the feerate range unconfirmed for at least target blocks\n"
- " \"leftmempool\" : x.x, (numeric) number of txs over history horizon in the feerate range that left mempool unconfirmed after target\n"
- " }\n"
- " \"fail\" : { ... } (json object) information about the highest range of feerates to fail to meet the threshold\n"
+ " \"short\" : { (json object, optional) estimate for short time horizon\n"
+ " \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\n"
+ " \"decay\" : x.x, (numeric) exponential decay (per block) for historical moving average of confirmation data\n"
+ " \"scale\" : x, (numeric) The resolution of confirmation targets at this time horizon\n"
+ " \"pass\" : { (json object, optional) information about the lowest range of feerates to succeed in meeting the threshold\n"
+ " \"startrange\" : x.x, (numeric) start of feerate range\n"
+ " \"endrange\" : x.x, (numeric) end of feerate range\n"
+ " \"withintarget\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed within target\n"
+ " \"totalconfirmed\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed at any point\n"
+ " \"inmempool\" : x.x, (numeric) current number of txs in mempool in the feerate range unconfirmed for at least target blocks\n"
+ " \"leftmempool\" : x.x, (numeric) number of txs over history horizon in the feerate range that left mempool unconfirmed after target\n"
+ " },\n"
+ " \"fail\" : { ... }, (json object, optional) information about the highest range of feerates to fail to meet the threshold\n"
+ " \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
+ " },\n"
+ " \"medium\" : { ... }, (json object, optional) estimate for medium time horizon\n"
+ " \"long\" : { ... } (json object) estimate for long time horizon\n"
"}\n"
"\n"
- "A negative feerate is returned if no answer can be given.\n"
+ "Results are returned for any horizon which tracks blocks up to the confirmation target.\n"
"\nExample:\n"
- + HelpExampleCli("estimaterawfee", "6 0.9 1")
+ + HelpExampleCli("estimaterawfee", "6 0.9")
);
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM, UniValue::VNUM}, true);
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
int nBlocks = request.params[0].get_int();
+ if (nBlocks < 1 || (unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid nblocks");
+ }
double threshold = 0.95;
- if (!request.params[1].isNull())
+ if (!request.params[1].isNull()) {
threshold = request.params[1].get_real();
- FeeEstimateHorizon horizon = FeeEstimateHorizon::MED_HALFLIFE;
- if (!request.params[2].isNull()) {
- int horizonInt = request.params[2].get_int();
- if (horizonInt < 0 || horizonInt > 2) {
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid horizon for fee estimates");
- } else {
- horizon = (FeeEstimateHorizon)horizonInt;
- }
}
+ if (threshold < 0 || threshold > 1) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid threshold");
+ }
+
UniValue result(UniValue::VOBJ);
- CFeeRate feeRate;
- EstimationResult buckets;
- feeRate = ::feeEstimator.estimateRawFee(nBlocks, threshold, horizon, &buckets);
- result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
- result.push_back(Pair("decay", buckets.decay));
- result.push_back(Pair("scale", (int)buckets.scale));
- UniValue passbucket(UniValue::VOBJ);
- passbucket.push_back(Pair("startrange", round(buckets.pass.start)));
- passbucket.push_back(Pair("endrange", round(buckets.pass.end)));
- passbucket.push_back(Pair("withintarget", round(buckets.pass.withinTarget * 100.0) / 100.0));
- passbucket.push_back(Pair("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0));
- passbucket.push_back(Pair("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0));
- passbucket.push_back(Pair("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0));
- result.push_back(Pair("pass", passbucket));
- UniValue failbucket(UniValue::VOBJ);
- failbucket.push_back(Pair("startrange", round(buckets.fail.start)));
- failbucket.push_back(Pair("endrange", round(buckets.fail.end)));
- failbucket.push_back(Pair("withintarget", round(buckets.fail.withinTarget * 100.0) / 100.0));
- failbucket.push_back(Pair("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0));
- failbucket.push_back(Pair("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0));
- failbucket.push_back(Pair("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0));
- result.push_back(Pair("fail", failbucket));
+ for (FeeEstimateHorizon horizon : {FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}) {
+ CFeeRate feeRate;
+ EstimationResult buckets;
+
+ // Only output results for horizons which track the target
+ if ((unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(horizon)) continue;
+
+ feeRate = ::feeEstimator.estimateRawFee(nBlocks, threshold, horizon, &buckets);
+ UniValue horizon_result(UniValue::VOBJ);
+ UniValue errors(UniValue::VARR);
+ UniValue passbucket(UniValue::VOBJ);
+ passbucket.push_back(Pair("startrange", round(buckets.pass.start)));
+ passbucket.push_back(Pair("endrange", round(buckets.pass.end)));
+ passbucket.push_back(Pair("withintarget", round(buckets.pass.withinTarget * 100.0) / 100.0));
+ passbucket.push_back(Pair("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0));
+ passbucket.push_back(Pair("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0));
+ passbucket.push_back(Pair("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0));
+ UniValue failbucket(UniValue::VOBJ);
+ failbucket.push_back(Pair("startrange", round(buckets.fail.start)));
+ failbucket.push_back(Pair("endrange", round(buckets.fail.end)));
+ failbucket.push_back(Pair("withintarget", round(buckets.fail.withinTarget * 100.0) / 100.0));
+ failbucket.push_back(Pair("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0));
+ failbucket.push_back(Pair("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0));
+ failbucket.push_back(Pair("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0));
+
+ // CFeeRate(0) is used to indicate error as a return value from estimateRawFee
+ if (feeRate != CFeeRate(0)) {
+ horizon_result.push_back(Pair("feerate", ValueFromAmount(feeRate.GetFeePerK())));
+ horizon_result.push_back(Pair("decay", buckets.decay));
+ horizon_result.push_back(Pair("scale", (int)buckets.scale));
+ horizon_result.push_back(Pair("pass", passbucket));
+ // buckets.fail.start == -1 indicates that all buckets passed, there is no fail bucket to output
+ if (buckets.fail.start != -1) horizon_result.push_back(Pair("fail", failbucket));
+ } else {
+ // Output only information that is still meaningful in the event of error
+ horizon_result.push_back(Pair("decay", buckets.decay));
+ horizon_result.push_back(Pair("scale", (int)buckets.scale));
+ horizon_result.push_back(Pair("fail", failbucket));
+ errors.push_back("Insufficient data or no feerate found which meets threshold");
+ horizon_result.push_back(Pair("errors",errors));
+ }
+ result.push_back(Pair(StringForFeeEstimateHorizon(horizon), horizon_result));
+ }
return result;
}
@@ -962,13 +950,12 @@ static const CRPCCommand commands[] =
{ "mining", "getblocktemplate", &getblocktemplate, true, {"template_request"} },
{ "mining", "submitblock", &submitblock, true, {"hexdata","dummy"} },
- { "generating", "generate", &generate, true, {"nblocks","maxtries"} },
{ "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
{ "util", "estimatefee", &estimatefee, true, {"nblocks"} },
{ "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks", "conservative"} },
- { "hidden", "estimaterawfee", &estimaterawfee, true, {"nblocks", "threshold", "horizon"} },
+ { "hidden", "estimaterawfee", &estimaterawfee, true, {"nblocks", "threshold"} },
};
void RegisterMiningRPCCommands(CRPCTable &t)
diff --git a/src/rpc/mining.h b/src/rpc/mining.h
new file mode 100644
index 0000000000..a148d851da
--- /dev/null
+++ b/src/rpc/mining.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_RPC_MINING_H
+#define BITCOIN_RPC_MINING_H
+
+#include "script/script.h"
+
+#include <univalue.h>
+
+/** Generate blocks (mine) */
+UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript);
+
+#endif
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index ef19e481c2..fcbbe1ceed 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -174,6 +174,14 @@ UniValue validateaddress(const JSONRPCRequest& request)
" \"ismine\" : true|false, (boolean) If the address is yours or not\n"
" \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n"
" \"isscript\" : true|false, (boolean) If the key is a script\n"
+ " \"script\" : \"type\" (string, optional) The output script type. Possible types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash, witness_v0_scripthash\n"
+ " \"hex\" : \"hex\", (string, optional) The redeemscript for the p2sh address\n"
+ " \"addresses\" (string, optional) Array of addresses associated with the known redeemscript\n"
+ " [\n"
+ " \"address\"\n"
+ " ,...\n"
+ " ]\n"
+ " \"sigsrequired\" : xxxxx (numeric, optional) Number of signatures required to spend multisig output\n"
" \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n"
" \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
" \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n"
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 5cab0ad5bd..ed452fcb02 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -19,7 +19,6 @@
#include "utilstrencodings.h"
#include "version.h"
-#include <boost/foreach.hpp>
#include <univalue.h>
@@ -302,9 +301,8 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)
" ,...\n"
"]\n"
"\nExamples:\n"
- + HelpExampleCli("getaddednodeinfo", "true")
- + HelpExampleCli("getaddednodeinfo", "true \"192.168.0.201\"")
- + HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"")
+ + HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"")
+ + HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"")
);
if(!g_connman)
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 527a4d6974..b878624df8 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -294,7 +294,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
throw std::runtime_error(
- "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime ) ( optintorbf )\n"
+ "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime ) ( replaceable )\n"
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
"Outputs can be addresses or data.\n"
"Returns hex-encoded raw transaction.\n"
@@ -318,7 +318,8 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
" ,...\n"
" }\n"
"3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
- "4. optintorbf (boolean, optional, default=false) Allow this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible.\n"
+ "4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125 replaceable.\n"
+ " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible.\n"
"\nResult:\n"
"\"transaction\" (string) hex string of the transaction\n"
@@ -412,7 +413,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
}
if (request.params.size() > 3 && rbfOptIn != SignalsOptInRBF(rawTx)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict optintorbf option");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
}
return EncodeHexTx(rawTx);
@@ -900,7 +901,7 @@ static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
{ "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} },
- { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"inputs","outputs","locktime"} },
+ { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"inputs","outputs","locktime","replaceable"} },
{ "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} },
{ "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} },
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} },
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index c320d20453..63e4e9c630 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -17,7 +17,6 @@
#include <univalue.h>
#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/algorithm/string/case_conv.hpp> // for to_upper()
#include <boost/algorithm/string/classification.hpp>
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index 923ba2c231..36a6d5110d 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -139,3 +139,69 @@ size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first,
}
return result;
}
+
+bool CScheduler::AreThreadsServicingQueue() const {
+ return nThreadsServicingQueue;
+}
+
+
+void SingleThreadedSchedulerClient::MaybeScheduleProcessQueue() {
+ {
+ LOCK(m_cs_callbacks_pending);
+ // Try to avoid scheduling too many copies here, but if we
+ // accidentally have two ProcessQueue's scheduled at once its
+ // not a big deal.
+ if (m_are_callbacks_running) return;
+ if (m_callbacks_pending.empty()) return;
+ }
+ m_pscheduler->schedule(std::bind(&SingleThreadedSchedulerClient::ProcessQueue, this));
+}
+
+void SingleThreadedSchedulerClient::ProcessQueue() {
+ std::function<void (void)> callback;
+ {
+ LOCK(m_cs_callbacks_pending);
+ if (m_are_callbacks_running) return;
+ if (m_callbacks_pending.empty()) return;
+ m_are_callbacks_running = true;
+
+ callback = std::move(m_callbacks_pending.front());
+ m_callbacks_pending.pop_front();
+ }
+
+ // RAII the setting of fCallbacksRunning and calling MaybeScheduleProcessQueue
+ // to ensure both happen safely even if callback() throws.
+ struct RAIICallbacksRunning {
+ SingleThreadedSchedulerClient* instance;
+ RAIICallbacksRunning(SingleThreadedSchedulerClient* _instance) : instance(_instance) {}
+ ~RAIICallbacksRunning() {
+ {
+ LOCK(instance->m_cs_callbacks_pending);
+ instance->m_are_callbacks_running = false;
+ }
+ instance->MaybeScheduleProcessQueue();
+ }
+ } raiicallbacksrunning(this);
+
+ callback();
+}
+
+void SingleThreadedSchedulerClient::AddToProcessQueue(std::function<void (void)> func) {
+ assert(m_pscheduler);
+
+ {
+ LOCK(m_cs_callbacks_pending);
+ m_callbacks_pending.emplace_back(std::move(func));
+ }
+ MaybeScheduleProcessQueue();
+}
+
+void SingleThreadedSchedulerClient::EmptyQueue() {
+ assert(!m_pscheduler->AreThreadsServicingQueue());
+ bool should_continue = true;
+ while (should_continue) {
+ ProcessQueue();
+ LOCK(m_cs_callbacks_pending);
+ should_continue = !m_callbacks_pending.empty();
+ }
+}
diff --git a/src/scheduler.h b/src/scheduler.h
index 27412a15b4..0365d668b2 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -14,6 +14,8 @@
#include <boost/thread.hpp>
#include <map>
+#include "sync.h"
+
//
// Simple class for background tasks that should be run
// periodically or once "after a while"
@@ -41,7 +43,7 @@ public:
typedef std::function<void(void)> Function;
// Call func at/after time t
- void schedule(Function f, boost::chrono::system_clock::time_point t);
+ void schedule(Function f, boost::chrono::system_clock::time_point t=boost::chrono::system_clock::now());
// Convenience method: call f once deltaSeconds from now
void scheduleFromNow(Function f, int64_t deltaMilliSeconds);
@@ -69,6 +71,9 @@ public:
size_t getQueueInfo(boost::chrono::system_clock::time_point &first,
boost::chrono::system_clock::time_point &last) const;
+ // Returns true if there are threads actively running in serviceQueue()
+ bool AreThreadsServicingQueue() const;
+
private:
std::multimap<boost::chrono::system_clock::time_point, Function> taskQueue;
boost::condition_variable newTaskScheduled;
@@ -79,4 +84,30 @@ private:
bool shouldStop() { return stopRequested || (stopWhenEmpty && taskQueue.empty()); }
};
+/**
+ * Class used by CScheduler clients which may schedule multiple jobs
+ * which are required to be run serially. Does not require such jobs
+ * to be executed on the same thread, but no two jobs will be executed
+ * at the same time.
+ */
+class SingleThreadedSchedulerClient {
+private:
+ CScheduler *m_pscheduler;
+
+ CCriticalSection m_cs_callbacks_pending;
+ std::list<std::function<void (void)>> m_callbacks_pending;
+ bool m_are_callbacks_running = false;
+
+ void MaybeScheduleProcessQueue();
+ void ProcessQueue();
+
+public:
+ SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {}
+ void AddToProcessQueue(std::function<void (void)> func);
+
+ // Processes all remaining queue members on the calling thread, blocking until queue is empty
+ // Must be called after the CScheduler has no remaining processing threads!
+ void EmptyQueue();
+};
+
#endif
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 35b534344e..0a39619734 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -11,7 +11,6 @@
#include "script/standard.h"
#include "script/sign.h"
-#include <boost/foreach.hpp>
typedef std::vector<unsigned char> valtype;
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index ec93c5451b..dc50467d3f 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -12,7 +12,6 @@
#include "script/standard.h"
#include "uint256.h"
-#include <boost/foreach.hpp>
typedef std::vector<unsigned char> valtype;
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 8e08acf0c6..760a5305e5 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -10,7 +10,6 @@
#include "util.h"
#include "utilstrencodings.h"
-#include <boost/foreach.hpp>
typedef std::vector<unsigned char> valtype;
diff --git a/src/sync.cpp b/src/sync.cpp
index 94f2cafa98..c359e8220b 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -9,7 +9,6 @@
#include <stdio.h>
-#include <boost/foreach.hpp>
#include <boost/thread.hpp>
#ifdef DEBUG_LOCKCONTENTION
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
index 0390d6806d..698e898231 100644
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -240,7 +240,7 @@
["0", "IF NOP10 ENDIF 1", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "OK",
"Discouraged NOPs are allowed if not executed"],
-["0", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "opcodes above NOP10 invalid if executed"],
+["0", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "opcodes above MAX_OPCODE invalid if executed"],
["0", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
["0", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
@@ -878,7 +878,7 @@
"P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript"],
["0x50","1", "P2SH,STRICTENC", "BAD_OPCODE", "opcode 0x50 is reserved"],
-["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "opcodes above NOP10 invalid if executed"],
+["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "opcodes above MAX_OPCODE invalid if executed"],
["1", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],
["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],
["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],
@@ -1001,7 +1001,7 @@
["1","RESERVED", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED is reserved"],
["1","RESERVED1", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED1 is reserved"],
["1","RESERVED2", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED2 is reserved"],
-["1","0xba", "P2SH,STRICTENC", "BAD_OPCODE", "0xba == OP_NOP10 + 1"],
+["1","0xba", "P2SH,STRICTENC", "BAD_OPCODE", "0xba == MAX_OPCODE + 1"],
["2147483648", "1ADD 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"],
["2147483648", "NEGATE 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"],
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 01cc5ed831..c79675f5a6 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -9,7 +9,6 @@
#include <vector>
#include <boost/algorithm/string.hpp>
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(getarg_tests, BasicTestingSetup)
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 6d8aab887b..c686f679c2 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -14,7 +14,6 @@
#include "test/test_bitcoin.h"
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
typedef std::vector<unsigned char> valtype;
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 6bfd315647..8cdd392109 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -184,8 +184,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(feeEst.estimateSmartFee(i, NULL, mpool).GetFeePerK() >= feeEst.estimateRawFee(i, 0.85, FeeEstimateHorizon::MED_HALFLIFE).GetFeePerK());
- BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
+ BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool, true).GetFeePerK() >= feeEst.estimateRawFee(i, 0.85, FeeEstimateHorizon::MED_HALFLIFE).GetFeePerK());
+ BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool, true).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
}
}
diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp
index 11bb11d1e9..345c4a2148 100644
--- a/src/test/prevector_tests.cpp
+++ b/src/test/prevector_tests.cpp
@@ -5,6 +5,7 @@
#include <vector>
#include "prevector.h"
+#include "reverse_iterator.h"
#include "serialize.h"
#include "streams.h"
@@ -56,13 +57,13 @@ class prevector_tester {
for (const T& v : pre_vector) {
local_check(v == real_vector[pos++]);
}
- BOOST_REVERSE_FOREACH(const T& v, pre_vector) {
+ for (const T& v : reverse_iterate(pre_vector)) {
local_check(v == real_vector[--pos]);
}
for (const T& v : const_pre_vector) {
local_check(v == real_vector[pos++]);
}
- BOOST_REVERSE_FOREACH(const T& v, const_pre_vector) {
+ for (const T& v : reverse_iterate(const_pre_vector)) {
local_check(v == real_vector[--pos]);
}
CDataStream ss1(SER_DISK, 0);
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 1bb191c73d..a18471588a 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -24,7 +24,6 @@
#include <string>
#include <vector>
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
#include <univalue.h>
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 579e96524c..3ba81ed17b 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -62,6 +62,12 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000)));
fs::create_directories(pathTemp);
ForceSetArg("-datadir", pathTemp.string());
+
+ // Note that because we don't bother running a scheduler thread here,
+ // callbacks via CValidationInterface are unreliable, but that's OK,
+ // our unit tests aren't testing multiple parts of the code at once.
+ GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
+
mempool.setSanityCheck(1.0);
pblocktree = new CBlockTreeDB(1 << 20, true);
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
@@ -88,6 +94,8 @@ TestingSetup::~TestingSetup()
UnregisterNodeSignals(GetNodeSignals());
threadGroup.interrupt_all();
threadGroup.join_all();
+ GetMainSignals().FlushBackgroundCallbacks();
+ GetMainSignals().UnregisterBackgroundSignalScheduler();
UnloadBlockIndex();
delete pcoinsTip;
delete pcoinsdbview;
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index c9e4a3427f..dd3b13c8c8 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -10,6 +10,7 @@
#include "key.h"
#include "pubkey.h"
#include "random.h"
+#include "scheduler.h"
#include "txdb.h"
#include "txmempool.h"
@@ -53,6 +54,7 @@ struct TestingSetup: public BasicTestingSetup {
fs::path pathTemp;
boost::thread_group threadGroup;
CConnman* connman;
+ CScheduler scheduler;
TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~TestingSetup();
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 778d2fd742..39f9f58604 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -27,7 +27,6 @@
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/test/unit_test.hpp>
-#include <boost/foreach.hpp>
#include <univalue.h>
diff --git a/src/timedata.cpp b/src/timedata.cpp
index d736baa213..099ed7f042 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -15,7 +15,6 @@
#include "utilstrencodings.h"
#include "warnings.h"
-#include <boost/foreach.hpp>
static CCriticalSection cs_nTimeOffset;
static int64_t nTimeOffset = 0;
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 4cd64bf028..3665e7e770 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -17,7 +17,6 @@
#include <boost/bind.hpp>
#include <boost/signals2/signal.hpp>
-#include <boost/foreach.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index dcfc5ffde0..4a81055231 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -11,6 +11,7 @@
#include "validation.h"
#include "policy/policy.h"
#include "policy/fees.h"
+#include "reverse_iterator.h"
#include "streams.h"
#include "timedata.h"
#include "util.h"
@@ -127,7 +128,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes
// This maximizes the benefit of the descendant cache and guarantees that
// setMemPoolChildren will be updated, an assumption made in
// UpdateForDescendants.
- BOOST_REVERSE_FOREACH(const uint256 &hash, vHashesToUpdate) {
+ for (const uint256 &hash : reverse_iterate(vHashesToUpdate)) {
// we cache the in-mempool children to avoid duplicate updates
setEntries setChildren;
// calculate children from mapNextTx
diff --git a/src/validation.cpp b/src/validation.cpp
index 975cbcc79f..09288be1ca 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -24,6 +24,7 @@
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "random.h"
+#include "reverse_iterator.h"
#include "script/script.h"
#include "script/sigcache.h"
#include "script/standard.h"
@@ -2340,7 +2341,7 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
nHeight = nTargetHeight;
// Connect new blocks.
- BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {
+ for (CBlockIndex *pindexConnect : reverse_iterate(vpindexToConnect)) {
if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace, disconnectpool)) {
if (state.IsInvalid()) {
// The block violates a consensus rule.
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 46d7c9b329..bf20d606f8 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -4,49 +4,123 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "validationinterface.h"
+#include "init.h"
+#include "scheduler.h"
+#include "sync.h"
+#include "util.h"
+
+#include <list>
+#include <atomic>
+
+#include <boost/signals2/signal.hpp>
+
+struct MainSignalsInstance {
+ boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
+ boost::signals2::signal<void (const CTransactionRef &)> TransactionAddedToMempool;
+ boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef>&)> BlockConnected;
+ boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
+ boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
+ boost::signals2::signal<void (const uint256 &)> Inventory;
+ boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
+ boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
+ boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
+
+ // We are not allowed to assume the scheduler only runs in one thread,
+ // but must ensure all callbacks happen in-order, so we end up creating
+ // our own queue here :(
+ SingleThreadedSchedulerClient m_schedulerClient;
+
+ MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
+};
static CMainSignals g_signals;
+void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler) {
+ assert(!m_internals);
+ m_internals.reset(new MainSignalsInstance(&scheduler));
+}
+
+void CMainSignals::UnregisterBackgroundSignalScheduler() {
+ m_internals.reset(nullptr);
+}
+
+void CMainSignals::FlushBackgroundCallbacks() {
+ m_internals->m_schedulerClient.EmptyQueue();
+}
+
CMainSignals& GetMainSignals()
{
return g_signals;
}
void RegisterValidationInterface(CValidationInterface* pwalletIn) {
- g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
- g_signals.TransactionAddedToMempool.connect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
- g_signals.BlockConnected.connect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
- g_signals.BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
- g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
- g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
- g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
- g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
- g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
- g_signals.NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
+ g_signals.m_internals->UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
+ g_signals.m_internals->TransactionAddedToMempool.connect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
+ g_signals.m_internals->BlockConnected.connect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
+ g_signals.m_internals->BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
+ g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
+ g_signals.m_internals->Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
+ g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
+ g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
+ g_signals.m_internals->NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
}
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
- g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
- g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
- g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
- g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
- g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
- g_signals.TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
- g_signals.BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
- g_signals.BlockDisconnected.disconnect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
- g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
- g_signals.NewPoWValidBlock.disconnect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
+ g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
+ g_signals.m_internals->Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
+ g_signals.m_internals->Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
+ g_signals.m_internals->SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
+ g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
+ g_signals.m_internals->BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
+ g_signals.m_internals->BlockDisconnected.disconnect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
+ g_signals.m_internals->UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
+ g_signals.m_internals->NewPoWValidBlock.disconnect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
}
void UnregisterAllValidationInterfaces() {
- g_signals.ScriptForMining.disconnect_all_slots();
- g_signals.BlockChecked.disconnect_all_slots();
- g_signals.Broadcast.disconnect_all_slots();
- g_signals.Inventory.disconnect_all_slots();
- g_signals.SetBestChain.disconnect_all_slots();
- g_signals.TransactionAddedToMempool.disconnect_all_slots();
- g_signals.BlockConnected.disconnect_all_slots();
- g_signals.BlockDisconnected.disconnect_all_slots();
- g_signals.UpdatedBlockTip.disconnect_all_slots();
- g_signals.NewPoWValidBlock.disconnect_all_slots();
+ g_signals.m_internals->BlockChecked.disconnect_all_slots();
+ g_signals.m_internals->Broadcast.disconnect_all_slots();
+ g_signals.m_internals->Inventory.disconnect_all_slots();
+ g_signals.m_internals->SetBestChain.disconnect_all_slots();
+ g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
+ g_signals.m_internals->BlockConnected.disconnect_all_slots();
+ g_signals.m_internals->BlockDisconnected.disconnect_all_slots();
+ g_signals.m_internals->UpdatedBlockTip.disconnect_all_slots();
+ g_signals.m_internals->NewPoWValidBlock.disconnect_all_slots();
+}
+
+void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
+ m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
+}
+
+void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx) {
+ m_internals->TransactionAddedToMempool(ptx);
+}
+
+void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {
+ m_internals->BlockConnected(pblock, pindex, vtxConflicted);
+}
+
+void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock) {
+ m_internals->BlockDisconnected(pblock);
+}
+
+void CMainSignals::SetBestChain(const CBlockLocator &locator) {
+ m_internals->SetBestChain(locator);
+}
+
+void CMainSignals::Inventory(const uint256 &hash) {
+ m_internals->Inventory(hash);
+}
+
+void CMainSignals::Broadcast(int64_t nBestBlockTime, CConnman* connman) {
+ m_internals->Broadcast(nBestBlockTime, connman);
+}
+
+void CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) {
+ m_internals->BlockChecked(block, state);
+}
+
+void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
+ m_internals->NewPoWValidBlock(pindex, block);
}
diff --git a/src/validationinterface.h b/src/validationinterface.h
index 460aecf243..568da66df2 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -6,7 +6,6 @@
#ifndef BITCOIN_VALIDATIONINTERFACE_H
#define BITCOIN_VALIDATIONINTERFACE_H
-#include <boost/signals2/signal.hpp>
#include <memory>
#include "primitives/transaction.h" // CTransaction(Ref)
@@ -20,6 +19,7 @@ class CReserveScript;
class CValidationInterface;
class CValidationState;
class uint256;
+class CScheduler;
// These functions dispatch to one or all registered wallets
@@ -32,52 +32,66 @@ void UnregisterAllValidationInterfaces();
class CValidationInterface {
protected:
- virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {}
- virtual void TransactionAddedToMempool(const CTransactionRef &ptxn) {}
- virtual void BlockConnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex, const std::vector<CTransactionRef> &txnConflicted) {}
- virtual void BlockDisconnected(const std::shared_ptr<const CBlock> &block) {}
- virtual void SetBestChain(const CBlockLocator &locator) {}
- virtual void Inventory(const uint256 &hash) {}
- virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
- virtual void BlockChecked(const CBlock&, const CValidationState&) {}
- virtual void GetScriptForMining(std::shared_ptr<CReserveScript>&) {};
- virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) {};
- friend void ::RegisterValidationInterface(CValidationInterface*);
- friend void ::UnregisterValidationInterface(CValidationInterface*);
- friend void ::UnregisterAllValidationInterfaces();
-};
-
-struct CMainSignals {
/** Notifies listeners of updated block chain tip */
- boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
+ virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {}
/** Notifies listeners of a transaction having been added to mempool. */
- boost::signals2::signal<void (const CTransactionRef &)> TransactionAddedToMempool;
+ virtual void TransactionAddedToMempool(const CTransactionRef &ptxn) {}
/**
* Notifies listeners of a block being connected.
* Provides a vector of transactions evicted from the mempool as a result.
*/
- boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef> &)> BlockConnected;
+ virtual void BlockConnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex, const std::vector<CTransactionRef> &txnConflicted) {}
/** Notifies listeners of a block being disconnected */
- boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
- /** Notifies listeners of a new active block chain. */
- boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
+ virtual void BlockDisconnected(const std::shared_ptr<const CBlock> &block) {}
+ /** Notifies listeners of the new active block chain on-disk. */
+ virtual void SetBestChain(const CBlockLocator &locator) {}
/** Notifies listeners about an inventory item being seen on the network. */
- boost::signals2::signal<void (const uint256 &)> Inventory;
+ virtual void Inventory(const uint256 &hash) {}
/** Tells listeners to broadcast their data. */
- boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
+ virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
/**
* Notifies listeners of a block validation result.
* If the provided CValidationState IsValid, the provided block
* is guaranteed to be the current best block at the time the
* callback was generated (not necessarily now)
*/
- boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
- /** Notifies listeners that a key for mining is required (coinbase) */
- boost::signals2::signal<void (std::shared_ptr<CReserveScript>&)> ScriptForMining;
+ virtual void BlockChecked(const CBlock&, const CValidationState&) {}
/**
* Notifies listeners that a block which builds directly on our current tip
* has been received and connected to the headers tree, though not validated yet */
- boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
+ virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) {};
+ friend void ::RegisterValidationInterface(CValidationInterface*);
+ friend void ::UnregisterValidationInterface(CValidationInterface*);
+ friend void ::UnregisterAllValidationInterfaces();
+};
+
+struct MainSignalsInstance;
+class CMainSignals {
+private:
+ std::unique_ptr<MainSignalsInstance> m_internals;
+
+ friend void ::RegisterValidationInterface(CValidationInterface*);
+ friend void ::UnregisterValidationInterface(CValidationInterface*);
+ friend void ::UnregisterAllValidationInterfaces();
+
+public:
+ /** Register a CScheduler to give callbacks which should run in the background (may only be called once) */
+ void RegisterBackgroundSignalScheduler(CScheduler& scheduler);
+ /** Unregister a CScheduler to give callbacks which should run in the background - these callbacks will now be dropped! */
+ void UnregisterBackgroundSignalScheduler();
+ /** Call any remaining callbacks on the calling thread */
+ void FlushBackgroundCallbacks();
+
+ void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
+ void TransactionAddedToMempool(const CTransactionRef &);
+ void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef> &);
+ void BlockDisconnected(const std::shared_ptr<const CBlock> &);
+ void UpdatedTransaction(const uint256 &);
+ void SetBestChain(const CBlockLocator &);
+ void Inventory(const uint256 &);
+ void Broadcast(int64_t nBestBlockTime, CConnman* connman);
+ void BlockChecked(const CBlock&, const CValidationState&);
+ void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
};
CMainSignals& GetMainSignals();
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index cb4719ae90..bdd01bec12 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -6,6 +6,7 @@
#define BITCOIN_WALLET_COINCONTROL_H
#include "policy/feerate.h"
+#include "policy/fees.h"
#include "primitives/transaction.h"
#include "wallet/wallet.h"
@@ -26,6 +27,8 @@ public:
int nConfirmTarget;
//! Signal BIP-125 replace by fee.
bool signalRbf;
+ //! Fee estimation mode to control arguments to estimateSmartFee
+ FeeEstimateMode m_fee_mode;
CCoinControl()
{
@@ -42,6 +45,7 @@ public:
fOverrideFeeRate = false;
nConfirmTarget = 0;
signalRbf = fWalletRbf;
+ m_fee_mode = FeeEstimateMode::UNSET;
}
bool HasSelected() const
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index 6fa685628f..dcce88cedc 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -12,7 +12,6 @@
#include <string>
#include <vector>
-#include <boost/foreach.hpp>
int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const
{
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index c8928a3b66..da2d180756 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -18,7 +18,6 @@
#include <sys/stat.h>
#endif
-#include <boost/foreach.hpp>
#include <boost/thread.hpp>
//
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 6a9e6cf9ff..607ecf4182 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -66,7 +66,7 @@ bool CFeeBumper::preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx
return true;
}
-CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable)
+CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable, FeeEstimateMode fee_mode)
:
txid(std::move(txidIn)),
nOldFee(0),
@@ -165,7 +165,8 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConf
nNewFee = totalFee;
nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
} else {
- nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, nullptr, ignoreGlobalPayTxFee);
+ bool conservative_estimate = CalculateEstimateType(fee_mode, newTxReplaceable);
+ nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, nullptr /* FeeCalculation */, ignoreGlobalPayTxFee, conservative_estimate);
nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
// New fee rate must be at least old rate + minimum incremental relay rate
diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h
index fc32316704..11e2f5f953 100644
--- a/src/wallet/feebumper.h
+++ b/src/wallet/feebumper.h
@@ -10,6 +10,7 @@
class CWallet;
class CWalletTx;
class uint256;
+enum class FeeEstimateMode;
enum class BumpFeeResult
{
@@ -24,7 +25,7 @@ enum class BumpFeeResult
class CFeeBumper
{
public:
- CFeeBumper(const CWallet *pWalletIn, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable);
+ CFeeBumper(const CWallet *pWalletIn, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable, FeeEstimateMode fee_mode);
BumpFeeResult getResult() const { return currentResult; }
const std::vector<std::string>& getErrors() const { return vErrors; }
CAmount getOldFee() const { return nOldFee; }
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 0fe2412352..9f42b1f266 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -26,7 +26,6 @@
#include <univalue.h>
-#include <boost/foreach.hpp>
std::string static EncodeDumpTime(int64_t nTime) {
return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
@@ -362,7 +361,7 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
"\nExamples:\n"
+ HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") +
"\nAs a JSON-RPC call\n"
- + HelpExampleRpc("removprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
+ + HelpExampleRpc("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
);
LOCK2(cs_main, pwallet->cs_wallet);
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 5bbb5088e2..5f72e3b6f5 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -15,6 +15,7 @@
#include "policy/fees.h"
#include "policy/policy.h"
#include "policy/rbf.h"
+#include "rpc/mining.h"
#include "rpc/server.h"
#include "script/sign.h"
#include "timedata.h"
@@ -355,7 +356,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
return ret;
}
-static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
+static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew, CCoinControl *coin_control = nullptr)
{
CAmount curBalance = pwallet->GetBalance();
@@ -381,7 +382,7 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA
int nChangePosRet = -1;
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
vecSend.push_back(recipient);
- if (!pwallet->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
+ if (!pwallet->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) {
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
@@ -400,9 +401,9 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 8)
throw std::runtime_error(
- "sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" subtractfeefromamount )\n"
+ "sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" subtractfeefromamount replaceable conf_target \"estimate_mode\")\n"
"\nSend an amount to a given address.\n"
+ HelpRequiringPassphrase(pwallet) +
"\nArguments:\n"
@@ -415,6 +416,12 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
" transaction, just kept in your wallet.\n"
"5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
" The recipient will receive less bitcoins than you enter in the amount field.\n"
+ "6. replaceable (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees via BIP 125\n"
+ "7. conf_target (numeric, optional) Confirmation target (in blocks)\n"
+ "8. \"estimate_mode\" (string, optional, default=UNSET) The fee estimate mode, must be one of:\n"
+ " \"UNSET\"\n"
+ " \"ECONOMICAL\"\n"
+ " \"CONSERVATIVE\"\n"
"\nResult:\n"
"\"txid\" (string) The transaction id.\n"
"\nExamples:\n"
@@ -443,12 +450,29 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
wtx.mapValue["to"] = request.params[3].get_str();
bool fSubtractFeeFromAmount = false;
- if (request.params.size() > 4)
+ if (request.params.size() > 4 && !request.params[4].isNull()) {
fSubtractFeeFromAmount = request.params[4].get_bool();
+ }
+
+ CCoinControl coin_control;
+ if (request.params.size() > 5 && !request.params[5].isNull()) {
+ coin_control.signalRbf = request.params[5].get_bool();
+ }
+
+ if (request.params.size() > 6 && !request.params[6].isNull()) {
+ coin_control.nConfirmTarget = request.params[6].get_int();
+ }
+
+ if (request.params.size() > 7 && !request.params[7].isNull()) {
+ if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
+ }
+ }
+
EnsureWalletIsUnlocked(pwallet);
- SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
+ SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, &coin_control);
return wtx.GetHash().GetHex();
}
@@ -887,9 +911,9 @@ UniValue sendmany(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 8)
throw std::runtime_error(
- "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
+ "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] replaceable conf_target \"estimate_mode\")\n"
"\nSend multiple times. Amounts are double-precision floating point numbers."
+ HelpRequiringPassphrase(pwallet) + "\n"
"\nArguments:\n"
@@ -909,7 +933,13 @@ UniValue sendmany(const JSONRPCRequest& request)
" \"address\" (string) Subtract fee from this address\n"
" ,...\n"
" ]\n"
- "\nResult:\n"
+ "6. replaceable (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees via BIP 125\n"
+ "7. conf_target (numeric, optional) Confirmation target (in blocks)\n"
+ "8. \"estimate_mode\" (string, optional, default=UNSET) The fee estimate mode, must be one of:\n"
+ " \"UNSET\"\n"
+ " \"ECONOMICAL\"\n"
+ " \"CONSERVATIVE\"\n"
+ "\nResult:\n"
"\"txid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
" the number of addresses.\n"
"\nExamples:\n"
@@ -941,9 +971,24 @@ UniValue sendmany(const JSONRPCRequest& request)
wtx.mapValue["comment"] = request.params[3].get_str();
UniValue subtractFeeFromAmount(UniValue::VARR);
- if (request.params.size() > 4)
+ if (request.params.size() > 4 && !request.params[4].isNull())
subtractFeeFromAmount = request.params[4].get_array();
+ CCoinControl coin_control;
+ if (request.params.size() > 5 && !request.params[5].isNull()) {
+ coin_control.signalRbf = request.params[5].get_bool();
+ }
+
+ if (request.params.size() > 6 && !request.params[6].isNull()) {
+ coin_control.nConfirmTarget = request.params[6].get_int();
+ }
+
+ if (request.params.size() > 7 && !request.params[7].isNull()) {
+ if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
+ }
+ }
+
std::set<CBitcoinAddress> setAddress;
std::vector<CRecipient> vecSend;
@@ -988,7 +1033,7 @@ UniValue sendmany(const JSONRPCRequest& request)
CAmount nFeeRequired = 0;
int nChangePosRet = -1;
std::string strFailReason;
- bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
+ bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason, &coin_control);
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
CValidationState state;
@@ -2655,7 +2700,13 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
" Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
" If no outputs are specified here, the sender pays the fee.\n"
" [vout_index,...]\n"
- " \"optIntoRbf\" (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees\n"
+ " \"replaceable\" (boolean, optional) Marks this transaction as BIP125 replaceable.\n"
+ " Allows this transaction to be replaced by a transaction with higher fees\n"
+ " \"conf_target\" (numeric, optional) Confirmation target (in blocks)\n"
+ " \"estimate_mode\" (string, optional, default=UNSET) The fee estimate mode, must be one of:\n"
+ " \"UNSET\"\n"
+ " \"ECONOMICAL\"\n"
+ " \"CONSERVATIVE\"\n"
" }\n"
" for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n"
"\nResult:\n"
@@ -2707,7 +2758,9 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
{"reserveChangeKey", UniValueType(UniValue::VBOOL)},
{"feeRate", UniValueType()}, // will be checked below
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
- {"optIntoRbf", UniValueType(UniValue::VBOOL)},
+ {"replaceable", UniValueType(UniValue::VBOOL)},
+ {"conf_target", UniValueType(UniValue::VNUM)},
+ {"estimate_mode", UniValueType(UniValue::VSTR)},
},
true, true);
@@ -2741,8 +2794,16 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
if (options.exists("subtractFeeFromOutputs"))
subtractFeeFromOutputs = options["subtractFeeFromOutputs"].get_array();
- if (options.exists("optIntoRbf")) {
- coinControl.signalRbf = options["optIntoRbf"].get_bool();
+ if (options.exists("replaceable")) {
+ coinControl.signalRbf = options["replaceable"].get_bool();
+ }
+ if (options.exists("conf_target")) {
+ coinControl.nConfirmTarget = options["conf_target"].get_int();
+ }
+ if (options.exists("estimate_mode")) {
+ if (!FeeModeFromString(options["estimate_mode"].get_str(), coinControl.m_fee_mode)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
+ }
}
}
}
@@ -2821,6 +2882,10 @@ UniValue bumpfee(const JSONRPCRequest& request)
" so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
" still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
" are replaceable).\n"
+ " \"estimate_mode\" (string, optional, default=UNSET) The fee estimate mode, must be one of:\n"
+ " \"UNSET\"\n"
+ " \"ECONOMICAL\"\n"
+ " \"CONSERVATIVE\"\n"
" }\n"
"\nResult:\n"
"{\n"
@@ -2843,6 +2908,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
int newConfirmTarget = nTxConfirmTarget;
CAmount totalFee = 0;
bool replaceable = true;
+ FeeEstimateMode fee_mode = FeeEstimateMode::UNSET;
if (request.params.size() > 1) {
UniValue options = request.params[1];
RPCTypeCheckObj(options,
@@ -2850,6 +2916,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
{"confTarget", UniValueType(UniValue::VNUM)},
{"totalFee", UniValueType(UniValue::VNUM)},
{"replaceable", UniValueType(UniValue::VBOOL)},
+ {"estimate_mode", UniValueType(UniValue::VSTR)},
},
true, true);
@@ -2874,12 +2941,17 @@ UniValue bumpfee(const JSONRPCRequest& request)
if (options.exists("replaceable")) {
replaceable = options["replaceable"].get_bool();
}
+ if (options.exists("estimate_mode")) {
+ if (!FeeModeFromString(options["estimate_mode"].get_str(), fee_mode)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
+ }
+ }
}
LOCK2(cs_main, pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
- CFeeBumper feeBump(pwallet, hash, newConfirmTarget, ignoreGlobalPayTxFee, totalFee, replaceable);
+ CFeeBumper feeBump(pwallet, hash, newConfirmTarget, ignoreGlobalPayTxFee, totalFee, replaceable, fee_mode);
BumpFeeResult res = feeBump.getResult();
if (res != BumpFeeResult::OK)
{
@@ -2922,6 +2994,51 @@ UniValue bumpfee(const JSONRPCRequest& request)
return result;
}
+UniValue generate(const JSONRPCRequest& request)
+{
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ throw std::runtime_error(
+ "generate nblocks ( maxtries )\n"
+ "\nMine up to nblocks blocks immediately (before the RPC call returns) to an address in the wallet.\n"
+ "\nArguments:\n"
+ "1. nblocks (numeric, required) How many blocks are generated immediately.\n"
+ "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
+ "\nResult:\n"
+ "[ blockhashes ] (array) hashes of blocks generated\n"
+ "\nExamples:\n"
+ "\nGenerate 11 blocks\n"
+ + HelpExampleCli("generate", "11")
+ );
+ }
+
+ int num_generate = request.params[0].get_int();
+ uint64_t max_tries = 1000000;
+ if (request.params.size() > 1 && !request.params[1].isNull()) {
+ max_tries = request.params[1].get_int();
+ }
+
+ std::shared_ptr<CReserveScript> coinbase_script;
+ pwallet->GetScriptForMining(coinbase_script);
+
+ // If the keypool is exhausted, no script is returned at all. Catch this.
+ if (!coinbase_script) {
+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
+ }
+
+ //throw an error if no script was provided
+ if (coinbase_script->reserveScript.empty()) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available");
+ }
+
+ return generateBlocks(coinbase_script, num_generate, max_tries, true);
+}
+
extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue importprivkey(const JSONRPCRequest& request);
@@ -2976,8 +3093,8 @@ static const CRPCCommand commands[] =
{ "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} },
{ "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} },
{ "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
- { "wallet", "sendmany", &sendmany, false, {"fromaccount","amounts","minconf","comment","subtractfeefrom"} },
- { "wallet", "sendtoaddress", &sendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount"} },
+ { "wallet", "sendmany", &sendmany, false, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "sendtoaddress", &sendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
{ "wallet", "setaccount", &setaccount, true, {"address","account"} },
{ "wallet", "settxfee", &settxfee, true, {"amount"} },
{ "wallet", "signmessage", &signmessage, true, {"address","message"} },
@@ -2985,6 +3102,8 @@ static const CRPCCommand commands[] =
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, true, {"oldpassphrase","newpassphrase"} },
{ "wallet", "walletpassphrase", &walletpassphrase, true, {"passphrase","timeout"} },
{ "wallet", "removeprunedfunds", &removeprunedfunds, true, {"txid"} },
+
+ { "generating", "generate", &generate, true, {"nblocks","maxtries"} },
};
void RegisterWalletRPCCommands(CRPCTable &t)
diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp
index 12d9f2e995..330878ceb5 100644
--- a/src/wallet/test/accounting_tests.cpp
+++ b/src/wallet/test/accounting_tests.cpp
@@ -8,7 +8,6 @@
#include <stdint.h>
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
extern CWallet* pwalletMain;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 0d1a86dd24..5e9701c71c 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1718,7 +1718,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
const CTxOut &txout = tx->vout[i];
nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);
if (!MoneyRange(nCredit))
- throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
+ throw std::runtime_error(std::string(__func__) + " : value out of range");
}
}
@@ -1761,7 +1761,7 @@ CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const
const CTxOut &txout = tx->vout[i];
nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY);
if (!MoneyRange(nCredit))
- throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
}
@@ -2569,7 +2569,43 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
std::vector<COutput> vAvailableCoins;
AvailableCoins(vAvailableCoins, true, coinControl);
+ // Create change script that will be used if we need change
+ // TODO: pass in scriptChange instead of reservekey so
+ // change transaction isn't always pay-to-bitcoin-address
+ CScript scriptChange;
+
+ // coin control: send change to custom address
+ if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange))
+ scriptChange = GetScriptForDestination(coinControl->destChange);
+
+ // no coin control: send change to newly generated address
+ else
+ {
+ // Note: We use a new key here to keep it from being obvious which side is the change.
+ // The drawback is that by not reusing a previous key, the change may be lost if a
+ // backup is restored, if the backup doesn't have the new private key for the change.
+ // If we reused the old key, it would be possible to add code to look for and
+ // rediscover unknown transactions that were written with keys of ours to recover
+ // post-backup change.
+
+ // Reserve a new key pair from key pool
+ CPubKey vchPubKey;
+ bool ret;
+ ret = reservekey.GetReservedKey(vchPubKey, true);
+ if (!ret)
+ {
+ strFailReason = _("Keypool ran out, please call keypoolrefill first");
+ return false;
+ }
+
+ scriptChange = GetScriptForDestination(vchPubKey.GetID());
+ }
+ CTxOut change_prototype_txout(0, scriptChange);
+ size_t change_prototype_size = GetSerializeSize(change_prototype_txout, SER_DISK, 0);
+
nFeeRet = 0;
+ bool pick_new_inputs = true;
+ CAmount nValueIn = 0;
// Start with no fee and loop until there is enough fee
while (true)
{
@@ -2615,49 +2651,21 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
}
// Choose coins to use
- CAmount nValueIn = 0;
- setCoins.clear();
- if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))
- {
- strFailReason = _("Insufficient funds");
- return false;
+ if (pick_new_inputs) {
+ nValueIn = 0;
+ setCoins.clear();
+ if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))
+ {
+ strFailReason = _("Insufficient funds");
+ return false;
+ }
}
const CAmount nChange = nValueIn - nValueToSelect;
+
if (nChange > 0)
{
// Fill a vout to ourself
- // TODO: pass in scriptChange instead of reservekey so
- // change transaction isn't always pay-to-bitcoin-address
- CScript scriptChange;
-
- // coin control: send change to custom address
- if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange))
- scriptChange = GetScriptForDestination(coinControl->destChange);
-
- // no coin control: send change to newly generated address
- else
- {
- // Note: We use a new key here to keep it from being obvious which side is the change.
- // The drawback is that by not reusing a previous key, the change may be lost if a
- // backup is restored, if the backup doesn't have the new private key for the change.
- // If we reused the old key, it would be possible to add code to look for and
- // rediscover unknown transactions that were written with keys of ours to recover
- // post-backup change.
-
- // Reserve a new key pair from key pool
- CPubKey vchPubKey;
- bool ret;
- ret = reservekey.GetReservedKey(vchPubKey, true);
- if (!ret)
- {
- strFailReason = _("Keypool ran out, please call keypoolrefill first");
- return false;
- }
-
- scriptChange = GetScriptForDestination(vchPubKey.GetID());
- }
-
CTxOut newTxOut(nChange, scriptChange);
// Never create dust outputs; if we would, just
@@ -2666,7 +2674,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
{
nChangePosInOut = -1;
nFeeRet += nChange;
- reservekey.ReturnKey();
}
else
{
@@ -2685,7 +2692,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
txNew.vout.insert(position, newTxOut);
}
} else {
- reservekey.ReturnKey();
nChangePosInOut = -1;
}
@@ -2724,7 +2730,10 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
if (coinControl && coinControl->nConfirmTarget > 0)
currentConfirmationTarget = coinControl->nConfirmTarget;
- CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator, &feeCalc);
+ // Allow to override the default fee estimate mode over the CoinControl instance
+ bool conservative_estimate = CalculateEstimateType(coinControl ? coinControl->m_fee_mode : FeeEstimateMode::UNSET, rbf);
+
+ CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator, &feeCalc, false /* ignoreGlobalPayTxFee */, conservative_estimate);
if (coinControl && coinControl->fOverrideFeeRate)
nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes);
@@ -2737,16 +2746,30 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
}
if (nFeeRet >= nFeeNeeded) {
- // Reduce fee to only the needed amount if we have change
- // output to increase. This prevents potential overpayment
- // in fees if the coins selected to meet nFeeNeeded result
- // in a transaction that requires less fee than the prior
- // iteration.
+ // Reduce fee to only the needed amount if possible. This
+ // prevents potential overpayment in fees if the coins
+ // selected to meet nFeeNeeded result in a transaction that
+ // requires less fee than the prior iteration.
+
// TODO: The case where nSubtractFeeFromAmount > 0 remains
// to be addressed because it requires returning the fee to
// the payees and not the change output.
- // TODO: The case where there is no change output remains
- // to be addressed so we avoid creating too small an output.
+
+ // If we have no change and a big enough excess fee, then
+ // try to construct transaction again only without picking
+ // new inputs. We now know we only need the smaller fee
+ // (because of reduced tx size) and so we should add a
+ // change output. Only try this once.
+ CAmount fee_needed_for_change = GetMinimumFee(change_prototype_size, currentConfirmationTarget, ::mempool, ::feeEstimator, nullptr, false /* ignoreGlobalPayTxFee */, conservative_estimate);
+ CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, ::dustRelayFee);
+ CAmount max_excess_fee = fee_needed_for_change + minimum_value_for_change;
+ if (nFeeRet > nFeeNeeded + max_excess_fee && nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) {
+ pick_new_inputs = false;
+ nFeeRet = nFeeNeeded + fee_needed_for_change;
+ continue;
+ }
+
+ // If we have change output already, just increase it
if (nFeeRet > nFeeNeeded && nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) {
CAmount extraFeePaid = nFeeRet - nFeeNeeded;
std::vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;
@@ -2755,6 +2778,12 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
}
break; // Done, enough fee included.
}
+ else if (!pick_new_inputs) {
+ // This shouldn't happen, we should have had enough excess
+ // fee to pay for the new output and still meet nFeeNeeded
+ strFailReason = _("Transaction fee and change calculation failed");
+ return false;
+ }
// Try to reduce change to include necessary fee
if (nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) {
@@ -2774,6 +2803,8 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
}
}
+ if (nChangePosInOut == -1) reservekey.ReturnKey(); // Return any reserved key if we don't have change
+
if (sign)
{
CTransaction txNewConst(txNew);
@@ -2905,13 +2936,13 @@ 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, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc, bool ignoreGlobalPayTxFee)
+CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc, bool ignoreGlobalPayTxFee, bool conservative_estimate)
{
// payTxFee is the user-set global for desired feerate
CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
// User didn't set: use -txconfirmtarget to estimate...
if (nFeeNeeded == 0 || ignoreGlobalPayTxFee) {
- nFeeNeeded = estimator.estimateSmartFee(nConfirmTarget, feeCalc, pool, true).GetFee(nTxBytes);
+ nFeeNeeded = estimator.estimateSmartFee(nConfirmTarget, feeCalc, pool, conservative_estimate).GetFee(nTxBytes);
// ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
if (nFeeNeeded == 0) {
nFeeNeeded = fallbackFee.GetFee(nTxBytes);
@@ -4154,3 +4185,15 @@ bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState&
{
return ::AcceptToMemoryPool(mempool, state, tx, true, NULL, NULL, false, nAbsurdFee);
}
+
+bool CalculateEstimateType(FeeEstimateMode mode, bool opt_in_rbf) {
+ switch (mode) {
+ case FeeEstimateMode::UNSET:
+ return !opt_in_rbf; // Allow for lower fees if RBF is an option
+ case FeeEstimateMode::CONSERVATIVE:
+ return true;
+ case FeeEstimateMode::ECONOMICAL:
+ return false;
+ }
+ return true;
+}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index a3fd7408a0..e3715cdf37 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -80,6 +80,7 @@ class CTxMemPool;
class CBlockPolicyEstimator;
class CWalletTx;
struct FeeCalculation;
+enum class FeeEstimateMode;
/** (client) version numbers for particular wallet features */
enum WalletFeature
@@ -963,7 +964,7 @@ 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, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc = nullptr, bool ignoreGlobalPayTxFee = false);
+ static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc, bool ignoreGlobalPayTxFee, bool conservative_estimate);
/**
* Return the minimum required fee taking into account the
* floating relay fee and user set minimum transaction fee
@@ -1025,7 +1026,7 @@ public:
}
}
- void GetScriptForMining(std::shared_ptr<CReserveScript> &script) override;
+ void GetScriptForMining(std::shared_ptr<CReserveScript> &script);
unsigned int GetKeyPoolSize()
{
@@ -1211,4 +1212,7 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const ContainerType &coins
}
return true;
}
+
+bool CalculateEstimateType(FeeEstimateMode mode, bool opt_in_rbf);
+
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 8321719b56..deb09a4771 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -18,7 +18,6 @@
#include <atomic>
-#include <boost/foreach.hpp>
#include <boost/thread.hpp>
//
diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py
index 6f877f8362..8339305f5e 100755
--- a/test/functional/dbcrash.py
+++ b/test/functional/dbcrash.py
@@ -2,21 +2,7 @@
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Test recovery from a crash during chainstate writing."""
-
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.script import *
-from test_framework.mininode import *
-import random
-try:
- import http.client as httplib
-except ImportError:
- import httplib
-import errno
-
-'''
-Test structure:
+"""Test recovery from a crash during chainstate writing.
- 4 nodes
* node0, node1, and node2 will have different dbcrash ratios, and different
@@ -37,11 +23,26 @@ Test structure:
* submit block to node
* if node crashed on/after submitting:
- restart until recovery succeeds
- - check that utxo matches node3 using gettxoutsetinfo
-'''
+ - check that utxo matches node3 using gettxoutsetinfo"""
-class ChainstateWriteCrashTest(BitcoinTestFramework):
+import errno
+import http.client
+import random
+import sys
+import time
+
+from test_framework.mininode import *
+from test_framework.script import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+HTTP_DISCONNECT_ERRORS = [http.client.CannotSendRequest]
+try:
+ HTTP_DISCONNECT_ERRORS.append(http.client.RemoteDisconnected)
+except AttributeError:
+ pass
+class ChainstateWriteCrashTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 4
@@ -50,32 +51,28 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
# Set -maxmempool=0 to turn off mempool memory sharing with dbcache
# Set -rpcservertimeout=900 to reduce socket disconnects in this
# long-running test
- self.base_args = ["-limitdescendantsize=0", "-maxmempool=0", "-rpcservertimeout=900"]
+ self.base_args = ["-limitdescendantsize=0", "-maxmempool=0", "-rpcservertimeout=900", "-dbbatchsize=200000"]
# Set different crash ratios and cache sizes. Note that not all of
# -dbcache goes to pcoinsTip.
- self.node0_args = ["-dbcrashratio=8", "-dbcache=4", "-dbbatchsize=200000"] + self.base_args
- self.node1_args = ["-dbcrashratio=16", "-dbcache=8", "-dbbatchsize=200000"] + self.base_args
- self.node2_args = ["-dbcrashratio=24", "-dbcache=16", "-dbbatchsize=200000"] + self.base_args
+ self.node0_args = ["-dbcrashratio=8", "-dbcache=4"] + self.base_args
+ self.node1_args = ["-dbcrashratio=16", "-dbcache=8"] + self.base_args
+ self.node2_args = ["-dbcrashratio=24", "-dbcache=16"] + self.base_args
# Node3 is a normal node with default args, except will mine full blocks
self.node3_args = ["-blockmaxweight=4000000"]
self.extra_args = [self.node0_args, self.node1_args, self.node2_args, self.node3_args]
- # We'll track some test coverage statistics
- self.restart_counts = [0, 0, 0] # Track the restarts for nodes 0-2
- self.crashed_on_restart = 0 # Track count of crashes during recovery
-
def setup_network(self):
self.setup_nodes()
# Leave them unconnected, we'll use submitblock directly in this test
- # Starts up a given node id, waits for the tip to reach the given block
- # hash, and calculates the utxo hash. Exceptions on startup should
- # indicate node crash (due to -dbcrashratio), in which case we try again.
- # Give up after 60 seconds.
- # Returns the utxo hash of the given node.
def restart_node(self, node_index, expected_tip):
+ """Start up a given node id, wait for the tip to reach the given block hash, and calculate the utxo hash.
+
+ Exceptions on startup should indicate node crash (due to -dbcrashratio), in which case we try again. Give up
+ after 60 seconds. Returns the utxo hash of the given node."""
+
time_start = time.time()
while time.time() - time_start < 60:
try:
@@ -99,14 +96,23 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
# and make sure that recovery happens.
raise AssertionError("Unable to successfully restart node %d in allotted time", node_index)
- # Try submitting a block to the given node.
- # Catch any exceptions that indicate the node has crashed.
- # Returns true if the block was submitted successfully; false otherwise.
def submit_block_catch_error(self, node_index, block):
+ """Try submitting a block to the given node.
+
+ Catch any exceptions that indicate the node has crashed.
+ Returns true if the block was submitted successfully; false otherwise."""
+
try:
self.nodes[node_index].submitblock(block)
return True
- except (httplib.CannotSendRequest, httplib.RemoteDisconnected) as e:
+ except http.client.BadStatusLine as e:
+ # Prior to 3.5 BadStatusLine('') was raised for a remote disconnect error.
+ if sys.version_info[0] == 3 and sys.version_info[1] < 5 and e.line == "''":
+ self.log.debug("node %d submitblock raised exception: %s", node_index, e)
+ return False
+ else:
+ raise
+ except tuple(HTTP_DISCONNECT_ERRORS) as e:
self.log.debug("node %d submitblock raised exception: %s", node_index, e)
return False
except OSError as e:
@@ -118,11 +124,13 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
# Unexpected exception, raise
raise
- # Use submitblock to sync node3's chain with the other nodes
- # If submitblock fails, restart the node and get the new utxo hash.
def sync_node3blocks(self, block_hashes):
- # If any nodes crash while updating, we'll compare utxo hashes to
- # ensure recovery was successful.
+ """Use submitblock to sync node3's chain with the other nodes
+
+ If submitblock fails, restart the node and get the new utxo hash.
+ If any nodes crash while updating, we'll compare utxo hashes to
+ ensure recovery was successful."""
+
node3_utxo_hash = self.nodes[3].gettxoutsetinfo()['hash_serialized_2']
# Retrieve all the blocks from node3
@@ -161,9 +169,10 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
self.log.debug("Checking txoutsetinfo matches for node %d", i)
assert_equal(nodei_utxo_hash, node3_utxo_hash)
- # Verify that the utxo hash of each node matches node3.
- # Restart any nodes that crash while querying.
def verify_utxo_hash(self):
+ """Verify that the utxo hash of each node matches node3.
+
+ Restart any nodes that crash while querying."""
node3_utxo_hash = self.nodes[3].gettxoutsetinfo()['hash_serialized_2']
self.log.info("Verifying utxo hash matches for all nodes")
@@ -175,9 +184,8 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
nodei_utxo_hash = self.restart_node(i, self.nodes[3].getbestblockhash())
assert_equal(nodei_utxo_hash, node3_utxo_hash)
-
def generate_small_transactions(self, node, count, utxo_list):
- FEE = 1000 # TODO: replace this with node relay fee based calculation
+ FEE = 1000 # TODO: replace this with node relay fee based calculation
num_transactions = 0
random.shuffle(utxo_list)
while len(utxo_list) >= 2 and num_transactions < count:
@@ -186,8 +194,8 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
for i in range(2):
utxo = utxo_list.pop()
tx.vin.append(CTxIn(COutPoint(int(utxo['txid'], 16), utxo['vout'])))
- input_amount += int(utxo['amount']*COIN)
- output_amount = (input_amount - FEE)//3
+ input_amount += int(utxo['amount'] * COIN)
+ output_amount = (input_amount - FEE) // 3
if output_amount <= 0:
# Sanity check -- if we chose inputs that are too small, skip
@@ -202,6 +210,9 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
num_transactions += 1
def run_test(self):
+ # Track test coverage statistics
+ self.restart_counts = [0, 0, 0] # Track the restarts for nodes 0-2
+ self.crashed_on_restart = 0 # Track count of crashes during recovery
# Start by creating a lot of utxos on node3
initial_height = self.nodes[3].getblockcount()
@@ -210,7 +221,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
# Sync these blocks with the other nodes
block_hashes_to_sync = []
- for height in range(initial_height+1, self.nodes[3].getblockcount()+1):
+ for height in range(initial_height + 1, self.nodes[3].getblockcount() + 1):
block_hashes_to_sync.append(self.nodes[3].getblockhash(height))
self.log.debug("Syncing %d blocks with other nodes", len(block_hashes_to_sync))
@@ -233,13 +244,15 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
if random_height > starting_tip_height:
# Randomly reorg from this point with some probability (1/4 for
# tip, 1/5 for tip-1, ...)
- if random.random() < 1.0/(current_height + 4 - random_height):
+ if random.random() < 1.0 / (current_height + 4 - random_height):
self.log.debug("Invalidating block at height %d", random_height)
self.nodes[3].invalidateblock(self.nodes[3].getblockhash(random_height))
# Now generate new blocks until we pass the old tip height
self.log.debug("Mining longer tip")
- block_hashes = self.nodes[3].generate(current_height+1-self.nodes[3].getblockcount())
+ block_hashes = []
+ while current_height + 1 > self.nodes[3].getblockcount():
+ block_hashes.extend(self.nodes[3].generate(min(10, current_height + 1 - self.nodes[3].getblockcount())))
self.log.debug("Syncing %d new blocks...", len(block_hashes))
self.sync_node3blocks(block_hashes)
utxo_list = self.nodes[3].listunspent()
diff --git a/test/functional/getblocktemplate_proposals.py b/test/functional/getblocktemplate_proposals.py
deleted file mode 100755
index fca99c7df5..0000000000
--- a/test/functional/getblocktemplate_proposals.py
+++ /dev/null
@@ -1,157 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2014-2016 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Test block proposals with getblocktemplate."""
-
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-
-from binascii import a2b_hex, b2a_hex
-from hashlib import sha256
-from struct import pack
-
-def b2x(b):
- return b2a_hex(b).decode('ascii')
-
-# NOTE: This does not work for signed numbers (set the high bit) or zero (use b'\0')
-def encodeUNum(n):
- s = bytearray(b'\1')
- while n > 127:
- s[0] += 1
- s.append(n % 256)
- n //= 256
- s.append(n)
- return bytes(s)
-
-def varlenEncode(n):
- if n < 0xfd:
- return pack('<B', n)
- if n <= 0xffff:
- return b'\xfd' + pack('<H', n)
- if n <= 0xffffffff:
- return b'\xfe' + pack('<L', n)
- return b'\xff' + pack('<Q', n)
-
-def dblsha(b):
- return sha256(sha256(b).digest()).digest()
-
-def genmrklroot(leaflist):
- cur = leaflist
- while len(cur) > 1:
- n = []
- if len(cur) & 1:
- cur.append(cur[-1])
- for i in range(0, len(cur), 2):
- n.append(dblsha(cur[i] + cur[i+1]))
- cur = n
- return cur[0]
-
-def template_to_bytearray(tmpl, txlist):
- blkver = pack('<L', tmpl['version'])
- mrklroot = genmrklroot(list(dblsha(a) for a in txlist))
- timestamp = pack('<L', tmpl['curtime'])
- nonce = b'\0\0\0\0'
- blk = blkver + a2b_hex(tmpl['previousblockhash'])[::-1] + mrklroot + timestamp + a2b_hex(tmpl['bits'])[::-1] + nonce
- blk += varlenEncode(len(txlist))
- for tx in txlist:
- blk += tx
- return bytearray(blk)
-
-def template_to_hex(tmpl, txlist):
- return b2x(template_to_bytearray(tmpl, txlist))
-
-def assert_template(node, tmpl, txlist, expect):
- rsp = node.getblocktemplate({'data':template_to_hex(tmpl, txlist),'mode':'proposal'})
- if rsp != expect:
- raise AssertionError('unexpected: %s' % (rsp,))
-
-class GetBlockTemplateProposalTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.num_nodes = 2
- self.setup_clean_chain = False
-
- def run_test(self):
- node = self.nodes[0]
- node.generate(1) # Mine a block to leave initial block download
- tmpl = node.getblocktemplate()
- if 'coinbasetxn' not in tmpl:
- rawcoinbase = encodeUNum(tmpl['height'])
- rawcoinbase += b'\x01-'
- hexcoinbase = b2x(rawcoinbase)
- hexoutval = b2x(pack('<Q', tmpl['coinbasevalue']))
- tmpl['coinbasetxn'] = {'data': '01000000' + '01' + '0000000000000000000000000000000000000000000000000000000000000000ffffffff' + ('%02x' % (len(rawcoinbase),)) + hexcoinbase + 'fffffffe' + '01' + hexoutval + '00' + '00000000'}
- txlist = list(bytearray(a2b_hex(a['data'])) for a in (tmpl['coinbasetxn'],) + tuple(tmpl['transactions']))
-
- # Test 0: Capability advertised
- assert('proposal' in tmpl['capabilities'])
-
- # NOTE: This test currently FAILS (regtest mode doesn't enforce block height in coinbase)
- ## Test 1: Bad height in coinbase
- #txlist[0][4+1+36+1+1] += 1
- #assert_template(node, tmpl, txlist, 'FIXME')
- #txlist[0][4+1+36+1+1] -= 1
-
- # Test 2: Bad input hash for gen tx
- txlist[0][4+1] += 1
- assert_template(node, tmpl, txlist, 'bad-cb-missing')
- txlist[0][4+1] -= 1
-
- # Test 3: Truncated final tx
- lastbyte = txlist[-1].pop()
- assert_raises_jsonrpc(-22, "Block decode failed", assert_template, node, tmpl, txlist, 'n/a')
- txlist[-1].append(lastbyte)
-
- # Test 4: Add an invalid tx to the end (duplicate of gen tx)
- txlist.append(txlist[0])
- assert_template(node, tmpl, txlist, 'bad-txns-duplicate')
- txlist.pop()
-
- # Test 5: Add an invalid tx to the end (non-duplicate)
- txlist.append(bytearray(txlist[0]))
- txlist[-1][4+1] = 0xff
- assert_template(node, tmpl, txlist, 'bad-txns-inputs-missingorspent')
- txlist.pop()
-
- # Test 6: Future tx lock time
- txlist[0][-4:] = b'\xff\xff\xff\xff'
- assert_template(node, tmpl, txlist, 'bad-txns-nonfinal')
- txlist[0][-4:] = b'\0\0\0\0'
-
- # Test 7: Bad tx count
- txlist.append(b'')
- assert_raises_jsonrpc(-22, 'Block decode failed', assert_template, node, tmpl, txlist, 'n/a')
- txlist.pop()
-
- # Test 8: Bad bits
- realbits = tmpl['bits']
- tmpl['bits'] = '1c0000ff' # impossible in the real world
- assert_template(node, tmpl, txlist, 'bad-diffbits')
- tmpl['bits'] = realbits
-
- # Test 9: Bad merkle root
- rawtmpl = template_to_bytearray(tmpl, txlist)
- rawtmpl[4+32] = (rawtmpl[4+32] + 1) % 0x100
- rsp = node.getblocktemplate({'data':b2x(rawtmpl),'mode':'proposal'})
- if rsp != 'bad-txnmrklroot':
- raise AssertionError('unexpected: %s' % (rsp,))
-
- # Test 10: Bad timestamps
- realtime = tmpl['curtime']
- tmpl['curtime'] = 0x7fffffff
- assert_template(node, tmpl, txlist, 'time-too-new')
- tmpl['curtime'] = 0
- assert_template(node, tmpl, txlist, 'time-too-old')
- tmpl['curtime'] = realtime
-
- # Test 11: Valid block
- assert_template(node, tmpl, txlist, None)
-
- # Test 12: Orphan block
- tmpl['previousblockhash'] = 'ff00' * 16
- assert_template(node, tmpl, txlist, 'inconclusive-not-best-prevblk')
-
-if __name__ == '__main__':
- GetBlockTemplateProposalTest().main()
diff --git a/test/functional/mining.py b/test/functional/mining.py
new file mode 100755
index 0000000000..dbd4e29eca
--- /dev/null
+++ b/test/functional/mining.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test mining RPCs
+
+- getblocktemplate proposal mode
+- submitblock"""
+
+from binascii import b2a_hex
+import copy
+
+from test_framework.blocktools import create_coinbase
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.mininode import CBlock
+from test_framework.util import *
+
+def b2x(b):
+ return b2a_hex(b).decode('ascii')
+
+def assert_template(node, block, expect, rehash=True):
+ if rehash:
+ block.hashMerkleRoot = block.calc_merkle_root()
+ rsp = node.getblocktemplate({'data': b2x(block.serialize()), 'mode': 'proposal'})
+ assert_equal(rsp, expect)
+
+class MiningTest(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
+
+ def run_test(self):
+ node = self.nodes[0]
+ # Mine a block to leave initial block download
+ node.generate(1)
+ tmpl = node.getblocktemplate()
+ self.log.info("getblocktemplate: Test capability advertised")
+ assert 'proposal' in tmpl['capabilities']
+ assert 'coinbasetxn' not in tmpl
+
+ coinbase_tx = create_coinbase(height=int(tmpl["height"]) + 1)
+ # sequence numbers must not be max for nLockTime to have effect
+ coinbase_tx.vin[0].nSequence = 2 ** 32 - 2
+ coinbase_tx.rehash()
+
+ block = CBlock()
+ block.nVersion = tmpl["version"]
+ block.hashPrevBlock = int(tmpl["previousblockhash"], 16)
+ block.nTime = tmpl["curtime"]
+ block.nBits = int(tmpl["bits"], 16)
+ block.nNonce = 0
+ block.vtx = [coinbase_tx]
+
+ self.log.info("getblocktemplate: Test valid block")
+ assert_template(node, block, None)
+
+ self.log.info("submitblock: Test block decode failure")
+ assert_raises_jsonrpc(-22, "Block decode failed", node.submitblock, b2x(block.serialize()[:-15]))
+
+ self.log.info("getblocktemplate: Test bad input hash for coinbase transaction")
+ bad_block = copy.deepcopy(block)
+ bad_block.vtx[0].vin[0].prevout.hash += 1
+ bad_block.vtx[0].rehash()
+ assert_template(node, bad_block, 'bad-cb-missing')
+
+ self.log.info("submitblock: Test invalid coinbase transaction")
+ assert_raises_jsonrpc(-22, "Block does not start with a coinbase", node.submitblock, b2x(bad_block.serialize()))
+
+ self.log.info("getblocktemplate: Test truncated final transaction")
+ assert_raises_jsonrpc(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(block.serialize()[:-1]), 'mode': 'proposal'})
+
+ self.log.info("getblocktemplate: Test duplicate transaction")
+ bad_block = copy.deepcopy(block)
+ bad_block.vtx.append(bad_block.vtx[0])
+ assert_template(node, bad_block, 'bad-txns-duplicate')
+
+ self.log.info("getblocktemplate: Test invalid transaction")
+ bad_block = copy.deepcopy(block)
+ bad_tx = copy.deepcopy(bad_block.vtx[0])
+ bad_tx.vin[0].prevout.hash = 255
+ bad_tx.rehash()
+ bad_block.vtx.append(bad_tx)
+ assert_template(node, bad_block, 'bad-txns-inputs-missingorspent')
+
+ self.log.info("getblocktemplate: Test nonfinal transaction")
+ bad_block = copy.deepcopy(block)
+ bad_block.vtx[0].nLockTime = 2 ** 32 - 1
+ bad_block.vtx[0].rehash()
+ assert_template(node, bad_block, 'bad-txns-nonfinal')
+
+ self.log.info("getblocktemplate: Test bad tx count")
+ # The tx count is immediately after the block header
+ TX_COUNT_OFFSET = 80
+ bad_block_sn = bytearray(block.serialize())
+ assert_equal(bad_block_sn[TX_COUNT_OFFSET], 1)
+ bad_block_sn[TX_COUNT_OFFSET] += 1
+ assert_raises_jsonrpc(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(bad_block_sn), 'mode': 'proposal'})
+
+ self.log.info("getblocktemplate: Test bad bits")
+ bad_block = copy.deepcopy(block)
+ bad_block.nBits = 469762303 # impossible in the real world
+ assert_template(node, bad_block, 'bad-diffbits')
+
+ self.log.info("getblocktemplate: Test bad merkle root")
+ bad_block = copy.deepcopy(block)
+ bad_block.hashMerkleRoot += 1
+ assert_template(node, bad_block, 'bad-txnmrklroot', False)
+
+ self.log.info("getblocktemplate: Test bad timestamps")
+ bad_block = copy.deepcopy(block)
+ bad_block.nTime = 2 ** 31 - 1
+ assert_template(node, bad_block, 'time-too-new')
+ bad_block.nTime = 0
+ assert_template(node, bad_block, 'time-too-old')
+
+ self.log.info("getblocktemplate: Test not best block")
+ bad_block = copy.deepcopy(block)
+ bad_block.hashPrevBlock = 123
+ assert_template(node, bad_block, 'inconclusive-not-best-prevblk')
+
+if __name__ == '__main__':
+ MiningTest().main()
diff --git a/test/functional/replace-by-fee.py b/test/functional/replace-by-fee.py
index d6bf3ea59f..bc67654987 100755
--- a/test/functional/replace-by-fee.py
+++ b/test/functional/replace-by-fee.py
@@ -531,8 +531,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert_equal(json1["vin"][0]["sequence"], 4294967295)
rawtx2 = self.nodes[0].createrawtransaction([], outs)
- frawtx2a = self.nodes[0].fundrawtransaction(rawtx2, {"optIntoRbf": True})
- frawtx2b = self.nodes[0].fundrawtransaction(rawtx2, {"optIntoRbf": False})
+ frawtx2a = self.nodes[0].fundrawtransaction(rawtx2, {"replaceable": True})
+ frawtx2b = self.nodes[0].fundrawtransaction(rawtx2, {"replaceable": False})
json0 = self.nodes[0].decoderawtransaction(frawtx2a['hex'])
json1 = self.nodes[0].decoderawtransaction(frawtx2b['hex'])
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 3c918b48fb..acca72aa86 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -236,7 +236,7 @@ def get_auth_cookie(datadir, n):
user = None
password = None
if os.path.isfile(os.path.join(datadir, "bitcoin.conf")):
- with open(os.path.join(datadir, "bitcoin.conf"), 'r') as f:
+ with open(os.path.join(datadir, "bitcoin.conf"), 'r', encoding='utf8') as f:
for line in f:
if line.startswith("rpcuser="):
assert user is None # Ensure that there is only one rpcuser line
@@ -412,7 +412,10 @@ def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
# Helper to create at least "count" utxos
# Pass in a fee that is sufficient for relay and mining new transactions.
def create_confirmed_utxos(fee, node, count):
- node.generate(int(0.5 * count) + 101)
+ to_generate = int(0.5 * count) + 101
+ while to_generate > 0:
+ node.generate(min(25, to_generate))
+ to_generate -= 25
utxos = node.listunspent()
iterations = count - len(utxos)
addr1 = node.getnewaddress()
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 54f625514b..b7bc6e841b 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -108,6 +108,7 @@ BASE_SCRIPTS= [
'signmessages.py',
'nulldummy.py',
'import-rescan.py',
+ 'mining.py',
'bumpfee.py',
'rpcnamedargs.py',
'listsinceblock.py',
@@ -141,7 +142,6 @@ EXTENDED_SCRIPTS = [
'bipdersig-p2p.py',
'bipdersig.py',
'example_test.py',
- 'getblocktemplate_proposals.py',
'txn_doublespend.py',
'txn_clone.py --mineblock',
'forknotify.py',