aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.clang-format1
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.leveldb.include2
-rw-r--r--src/base58.cpp12
-rw-r--r--src/base58.h2
-rw-r--r--src/bench/base58.cpp27
-rw-r--r--src/bench/coin_selection.cpp1
-rw-r--r--src/bench/verify_script.cpp10
-rw-r--r--src/bitcoin-cli.cpp10
-rw-r--r--src/bitcoin-tx.cpp6
-rw-r--r--src/blockencodings.cpp4
-rw-r--r--src/bloom.cpp1
-rw-r--r--src/checkpoints.cpp4
-rw-r--r--src/checkqueue.h1
-rw-r--r--src/coins.cpp3
-rw-r--r--src/compressor.cpp8
-rw-r--r--src/consensus/consensus.h14
-rw-r--r--src/consensus/tx_verify.cpp2
-rw-r--r--src/consensus/validation.h18
-rw-r--r--src/core_memusage.h2
-rw-r--r--src/core_read.cpp2
-rw-r--r--src/core_write.cpp5
-rw-r--r--src/hash.cpp43
-rw-r--r--src/httprpc.cpp1
-rw-r--r--src/httpserver.cpp1
-rw-r--r--src/init.cpp20
-rw-r--r--src/key.cpp10
-rw-r--r--src/memusage.h1
-rw-r--r--src/merkleblock.cpp2
-rw-r--r--src/net.cpp2
-rw-r--r--src/net.h1
-rw-r--r--src/net_processing.cpp5
-rw-r--r--src/netaddress.cpp2
-rw-r--r--src/netbase.cpp21
-rw-r--r--src/netbase.h1
-rw-r--r--src/policy/feerate.h1
-rw-r--r--src/policy/fees.cpp159
-rw-r--r--src/policy/fees.h16
-rw-r--r--src/policy/policy.cpp2
-rw-r--r--src/prevector.h4
-rw-r--r--src/primitives/block.cpp9
-rw-r--r--src/primitives/block.h3
-rw-r--r--src/primitives/transaction.cpp5
-rw-r--r--src/primitives/transaction.h10
-rw-r--r--src/protocol.h2
-rw-r--r--src/pubkey.cpp7
-rw-r--r--src/qt/addresstablemodel.cpp1
-rw-r--r--src/qt/bitcoinstrings.cpp50
-rw-r--r--src/qt/coincontroldialog.cpp10
-rw-r--r--src/qt/forms/sendcoinsdialog.ui64
-rw-r--r--src/qt/locale/bitcoin_en.ts593
-rw-r--r--src/qt/recentrequeststablemodel.cpp1
-rw-r--r--src/qt/sendcoinsdialog.cpp117
-rw-r--r--src/qt/sendcoinsdialog.h3
-rw-r--r--src/qt/test/rpcnestedtests.cpp22
-rw-r--r--src/qt/transactionrecord.cpp1
-rw-r--r--src/qt/walletmodel.cpp11
-rw-r--r--src/qt/walletmodel.h2
-rw-r--r--src/random.cpp19
-rw-r--r--src/reverse_iterator.h39
-rw-r--r--src/rpc/blockchain.cpp2
-rw-r--r--src/rpc/client.cpp8
-rw-r--r--src/rpc/mining.cpp185
-rw-r--r--src/rpc/mining.h18
-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/interpreter.cpp4
-rw-r--r--src/script/ismine.cpp1
-rw-r--r--src/script/script.h8
-rw-r--r--src/script/sign.cpp1
-rw-r--r--src/script/standard.cpp1
-rw-r--r--src/serialize.h12
-rw-r--r--src/streams.h2
-rw-r--r--src/sync.cpp1
-rw-r--r--src/test/data/script_tests.json6
-rw-r--r--src/test/dbwrapper_tests.cpp29
-rw-r--r--src/test/getarg_tests.cpp1
-rw-r--r--src/test/multisig_tests.cpp1
-rw-r--r--src/test/netbase_tests.cpp1
-rw-r--r--src/test/policyestimator_tests.cpp10
-rw-r--r--src/test/prevector_tests.cpp5
-rw-r--r--src/test/script_tests.cpp1
-rw-r--r--src/test/sigopcount_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/test/txvalidationcache_tests.cpp2
-rw-r--r--src/timedata.cpp1
-rw-r--r--src/torcontrol.cpp3
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/txmempool.cpp3
-rw-r--r--src/undo.h3
-rw-r--r--src/util.h6
-rw-r--r--src/utilstrencodings.cpp23
-rw-r--r--src/utilstrencodings.h1
-rw-r--r--src/validation.cpp31
-rw-r--r--src/validationinterface.cpp134
-rw-r--r--src/validationinterface.h72
-rw-r--r--src/wallet/coincontrol.h20
-rw-r--r--src/wallet/crypter.cpp1
-rw-r--r--src/wallet/db.cpp1
-rw-r--r--src/wallet/db.h4
-rw-r--r--src/wallet/feebumper.cpp7
-rw-r--r--src/wallet/feebumper.h4
-rw-r--r--src/wallet/rpcdump.cpp3
-rw-r--r--src/wallet/rpcwallet.cpp185
-rw-r--r--src/wallet/rpcwallet.h2
-rw-r--r--src/wallet/test/accounting_tests.cpp1
-rw-r--r--src/wallet/test/wallet_tests.cpp4
-rw-r--r--src/wallet/wallet.cpp422
-rw-r--r--src/wallet/wallet.h27
-rw-r--r--src/wallet/walletdb.cpp19
116 files changed, 1711 insertions, 1100 deletions
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/Makefile.leveldb.include b/src/Makefile.leveldb.include
index ac38141f43..833f3d2a10 100644
--- a/src/Makefile.leveldb.include
+++ b/src/Makefile.leveldb.include
@@ -142,7 +142,7 @@ leveldb_libmemenv_a_SOURCES += leveldb/helpers/memenv/memenv.h
leveldb_libleveldb_sse42_a_CPPFLAGS = $(leveldb_libleveldb_a_CPPFLAGS)
leveldb_libleveldb_sse42_a_CXXFLAGS = $(leveldb_libleveldb_a_CXXFLAGS)
-if ENABLE_SSE42
+if ENABLE_HWCRC32
leveldb_libleveldb_sse42_a_CPPFLAGS += -DLEVELDB_PLATFORM_POSIX_SSE
leveldb_libleveldb_sse42_a_CXXFLAGS += $(SSE42_CXXFLAGS)
endif
diff --git a/src/base58.cpp b/src/base58.cpp
index efa1beb1e4..17022a6bc1 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -110,7 +110,7 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
std::string EncodeBase58(const std::vector<unsigned char>& vch)
{
- return EncodeBase58(&vch[0], &vch[0] + vch.size());
+ return EncodeBase58(vch.data(), vch.data() + vch.size());
}
bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
@@ -160,7 +160,7 @@ void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const
vchVersion = vchVersionIn;
vchData.resize(nSize);
if (!vchData.empty())
- memcpy(&vchData[0], pdata, nSize);
+ memcpy(vchData.data(), pdata, nSize);
}
void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)
@@ -180,8 +180,8 @@ bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
vchData.resize(vchTemp.size() - nVersionBytes);
if (!vchData.empty())
- memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size());
- memory_cleanse(&vchTemp[0], vchTemp.size());
+ memcpy(vchData.data(), vchTemp.data() + nVersionBytes, vchData.size());
+ memory_cleanse(vchTemp.data(), vchTemp.size());
return true;
}
@@ -262,7 +262,7 @@ CTxDestination CBitcoinAddress::Get() const
if (!IsValid())
return CNoDestination();
uint160 id;
- memcpy(&id, &vchData[0], 20);
+ memcpy(&id, vchData.data(), 20);
if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
return CKeyID(id);
else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
@@ -276,7 +276,7 @@ bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
return false;
uint160 id;
- memcpy(&id, &vchData[0], 20);
+ memcpy(&id, vchData.data(), 20);
keyID = CKeyID(id);
return true;
}
diff --git a/src/base58.h b/src/base58.h
index 3998283bb1..4de5cc6ce5 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -148,7 +148,7 @@ public:
K ret;
if (vchData.size() == Size) {
// If base58 encoded data does not hold an ext key, return a !IsValid() key
- ret.Decode(&vchData[0]);
+ ret.Decode(vchData.data());
}
return ret;
}
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index 3319c179bf..65e27a615d 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -7,34 +7,37 @@
#include "validation.h"
#include "base58.h"
+#include <array>
#include <vector>
#include <string>
static void Base58Encode(benchmark::State& state)
{
- unsigned char buff[32] = {
- 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
- 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
- 200, 24
+ static const std::array<unsigned char, 32> buff = {
+ {
+ 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
+ 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
+ 200, 24
+ }
};
- unsigned char* b = buff;
while (state.KeepRunning()) {
- EncodeBase58(b, b + 32);
+ EncodeBase58(buff.begin(), buff.end());
}
}
static void Base58CheckEncode(benchmark::State& state)
{
- unsigned char buff[32] = {
- 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
- 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
- 200, 24
+ static const std::array<unsigned char, 32> buff = {
+ {
+ 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
+ 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
+ 200, 24
+ }
};
- unsigned char* b = buff;
std::vector<unsigned char> vch;
- vch.assign(b, b + 32);
+ vch.assign(buff.begin(), buff.end());
while (state.KeepRunning()) {
EncodeBase58Check(vch);
}
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/bench/verify_script.cpp b/src/bench/verify_script.cpp
index 23bbadc88d..ef7381c120 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -11,6 +11,8 @@
#include "script/sign.h"
#include "streams.h"
+#include <array>
+
// FIXME: Dedup with BuildCreditingTransaction in test/script_tests.cpp.
static CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey)
{
@@ -55,8 +57,12 @@ static void VerifyScriptBench(benchmark::State& state)
// Keypair.
CKey key;
- const unsigned char vchKey[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
- key.Set(vchKey, vchKey + 32, false);
+ static const std::array<unsigned char, 32> vchKey = {
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+ }
+ };
+ key.Set(vchKey.begin(), vchKey.end(), false);
CPubKey pubkey = key.GetPubKey();
uint160 pubkeyHash;
CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(pubkeyHash.begin());
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 885b787b4d..8b48c7f8e4 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -191,8 +191,14 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx)
UniValue CallRPC(const std::string& strMethod, const UniValue& params)
{
- std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT);
- int port = GetArg("-rpcport", BaseParams().RPCPort());
+ std::string host;
+ // In preference order, we choose the following for the port:
+ // 1. -rpcport
+ // 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6)
+ // 3. default port for chain
+ int port = BaseParams().RPCPort();
+ SplitHostPort(GetArg("-rpcconnect", DEFAULT_RPCCONNECT), port, host);
+ port = GetArg("-rpcport", port);
// Obtain event base
raii_event_base base = obtain_event_base();
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 6093f78fb1..9acb3fd30e 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") + ". " +
@@ -239,7 +239,7 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
uint256 txid(uint256S(strTxid));
static const unsigned int minTxOutSz = 9;
- static const unsigned int maxVout = MAX_BLOCK_BASE_SIZE / minTxOutSz;
+ static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz);
// extract and validate vout
std::string strVout = vStrInputParts[1];
@@ -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/blockencodings.cpp b/src/blockencodings.cpp
index 9cac10d2b8..6f27b7b9dc 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -15,8 +15,6 @@
#include <unordered_map>
-#define MIN_TRANSACTION_BASE_SIZE (::GetSerializeSize(CTransaction(), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS))
-
CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID) :
nonce(GetRand(std::numeric_limits<uint64_t>::max())),
shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) {
@@ -50,7 +48,7 @@ uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const uint256& txhash) const {
ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<uint256, CTransactionRef>>& extra_txn) {
if (cmpctblock.header.IsNull() || (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty()))
return READ_STATUS_INVALID;
- if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_BASE_SIZE / MIN_TRANSACTION_BASE_SIZE)
+ if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_WEIGHT / MIN_SERIALIZABLE_TRANSACTION_WEIGHT)
return READ_STATUS_INVALID;
assert(header.IsNull() && txn_available.empty());
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/coins.cpp b/src/coins.cpp
index b5dc6197bd..e30bda930a 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -245,7 +245,8 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
return true;
}
-static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE / ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); // TODO: merge with similar definition in undo.h.
+static const size_t MIN_TRANSACTION_OUTPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION);
+static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_OUTPUT_WEIGHT;
const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
{
diff --git a/src/compressor.cpp b/src/compressor.cpp
index 20c154fc1e..f4c12f38d2 100644
--- a/src/compressor.cpp
+++ b/src/compressor.cpp
@@ -93,7 +93,7 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne
script[0] = OP_DUP;
script[1] = OP_HASH160;
script[2] = 20;
- memcpy(&script[3], &in[0], 20);
+ memcpy(&script[3], in.data(), 20);
script[23] = OP_EQUALVERIFY;
script[24] = OP_CHECKSIG;
return true;
@@ -101,7 +101,7 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne
script.resize(23);
script[0] = OP_HASH160;
script[1] = 20;
- memcpy(&script[2], &in[0], 20);
+ memcpy(&script[2], in.data(), 20);
script[22] = OP_EQUAL;
return true;
case 0x02:
@@ -109,14 +109,14 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne
script.resize(35);
script[0] = 33;
script[1] = nSize;
- memcpy(&script[2], &in[0], 32);
+ memcpy(&script[2], in.data(), 32);
script[34] = OP_CHECKSIG;
return true;
case 0x04:
case 0x05:
unsigned char vch[33] = {};
vch[0] = nSize - 2;
- memcpy(&vch[1], &in[0], 32);
+ memcpy(&vch[1], in.data(), 32);
CPubKey pubkey(&vch[0], &vch[33]);
if (!pubkey.Decompress())
return false;
diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h
index 58b2ed4b3e..ddd4ee9fab 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -6,25 +6,23 @@
#ifndef BITCOIN_CONSENSUS_CONSENSUS_H
#define BITCOIN_CONSENSUS_CONSENSUS_H
+#include <stdlib.h>
#include <stdint.h>
/** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 4000000;
/** The maximum allowed weight for a block, see BIP 141 (network rule) */
static const unsigned int MAX_BLOCK_WEIGHT = 4000000;
-/**
- * The maximum allowed size for a block excluding witness data, in bytes (network rule).
- * This parameter is largely superfluous because it is directly implied by the above block
- * weight limit, even when BIP 141 is not active. It continues to exist for use in
- * various early tests that run before the witness data has been checked.
- * All tests related to it could be removed without breaking consensus compatibility.
- */
-static const unsigned int MAX_BLOCK_BASE_SIZE = 1000000;
/** The maximum allowed number of signature check operations in a block (network rule) */
static const int64_t MAX_BLOCK_SIGOPS_COST = 80000;
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;
+static const int WITNESS_SCALE_FACTOR = 4;
+
+static const size_t MIN_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 60; // 60 is the lower bound for the size of a valid serialized CTransaction
+static const size_t MIN_SERIALIZABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 10; // 10 is the lower bound for the size of a serialized CTransaction
+
/** Flags for nSequence and nLockTime locks */
enum {
/* Interpret sequence numbers as relative lock-time constraints. */
diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp
index 0671cbc132..0a71915d1d 100644
--- a/src/consensus/tx_verify.cpp
+++ b/src/consensus/tx_verify.cpp
@@ -164,7 +164,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
if (tx.vout.empty())
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
// Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)
- if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) > MAX_BLOCK_BASE_SIZE)
+ if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");
// Check for negative or overflow output values
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 8fc3ef1b66..5494ce40ea 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -7,6 +7,10 @@
#define BITCOIN_CONSENSUS_VALIDATION_H
#include <string>
+#include "version.h"
+#include "consensus/consensus.h"
+#include "primitives/transaction.h"
+#include "primitives/block.h"
/** "reject" message codes */
static const unsigned char REJECT_MALFORMED = 0x01;
@@ -85,4 +89,18 @@ public:
std::string GetDebugMessage() const { return strDebugMessage; }
};
+static inline int64_t GetTransactionWeight(const CTransaction& tx)
+{
+ return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR -1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
+}
+
+static inline int64_t GetBlockWeight(const CBlock& block)
+{
+ // This implements the weight = (stripped_size * 4) + witness_size formula,
+ // using only serialization with and without witness data. As witness_size
+ // is equal to total_size - stripped_size, this formula is identical to:
+ // weight = (stripped_size * 3) + total_size.
+ return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION);
+}
+
#endif // BITCOIN_CONSENSUS_VALIDATION_H
diff --git a/src/core_memusage.h b/src/core_memusage.h
index e4ccd54c42..f038e7b154 100644
--- a/src/core_memusage.h
+++ b/src/core_memusage.h
@@ -10,7 +10,7 @@
#include "memusage.h"
static inline size_t RecursiveDynamicUsage(const CScript& script) {
- return memusage::DynamicUsage(*static_cast<const CScriptBase*>(&script));
+ return memusage::DynamicUsage(script);
}
static inline size_t RecursiveDynamicUsage(const COutPoint& out) {
diff --git a/src/core_read.cpp b/src/core_read.cpp
index dd9b5726a3..7018131a13 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 (unsigned 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..a366ef933c 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -5,7 +5,8 @@
#include "core_io.h"
#include "base58.h"
-#include "primitives/transaction.h"
+#include "consensus/consensus.h"
+#include "consensus/validation.h"
#include "script/script.h"
#include "script/standard.h"
#include "serialize.h"
@@ -15,8 +16,6 @@
#include "utilmoneystr.h"
#include "utilstrencodings.h"
-#include <boost/foreach.hpp>
-
std::string FormatScript(const CScript& script)
{
std::string ret;
diff --git a/src/hash.cpp b/src/hash.cpp
index b361c90d16..5a15600be5 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -17,36 +17,34 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char
{
// The following is MurmurHash3 (x86_32), see http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
uint32_t h1 = nHashSeed;
- if (vDataToHash.size() > 0)
- {
- const uint32_t c1 = 0xcc9e2d51;
- const uint32_t c2 = 0x1b873593;
+ const uint32_t c1 = 0xcc9e2d51;
+ const uint32_t c2 = 0x1b873593;
- const int nblocks = vDataToHash.size() / 4;
+ const int nblocks = vDataToHash.size() / 4;
- //----------
- // body
- const uint8_t* blocks = &vDataToHash[0] + nblocks * 4;
+ //----------
+ // body
+ const uint8_t* blocks = vDataToHash.data();
- for (int i = -nblocks; i; i++) {
- uint32_t k1 = ReadLE32(blocks + i*4);
+ for (int i = 0; i < nblocks; ++i) {
+ uint32_t k1 = ReadLE32(blocks + i*4);
- k1 *= c1;
- k1 = ROTL32(k1, 15);
- k1 *= c2;
+ k1 *= c1;
+ k1 = ROTL32(k1, 15);
+ k1 *= c2;
- h1 ^= k1;
- h1 = ROTL32(h1, 13);
- h1 = h1 * 5 + 0xe6546b64;
- }
+ h1 ^= k1;
+ h1 = ROTL32(h1, 13);
+ h1 = h1 * 5 + 0xe6546b64;
+ }
- //----------
- // tail
- const uint8_t* tail = (const uint8_t*)(&vDataToHash[0] + nblocks * 4);
+ //----------
+ // tail
+ const uint8_t* tail = vDataToHash.data() + nblocks * 4;
- uint32_t k1 = 0;
+ uint32_t k1 = 0;
- switch (vDataToHash.size() & 3) {
+ switch (vDataToHash.size() & 3) {
case 3:
k1 ^= tail[2] << 16;
case 2:
@@ -57,7 +55,6 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char
k1 = ROTL32(k1, 15);
k1 *= c2;
h1 ^= k1;
- }
}
//----------
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/httpserver.cpp b/src/httpserver.cpp
index 1c53d8d49d..290a2efca2 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -7,6 +7,7 @@
#include "chainparamsbase.h"
#include "compat.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "netbase.h"
#include "rpc/protocol.h" // For HTTP status codes
#include "sync.h"
diff --git a/src/init.cpp b/src/init.cpp
index 672ef77e80..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
@@ -1496,7 +1512,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("Shutdown requested. Exiting.\n");
return false;
}
- LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart);
+ if (fLoaded) {
+ LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart);
+ }
fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION);
diff --git a/src/key.cpp b/src/key.cpp
index 5a75647f1a..5a991fc1d2 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -138,7 +138,7 @@ CPrivKey CKey::GetPrivKey() const {
size_t privkeylen;
privkey.resize(279);
privkeylen = 279;
- ret = ec_privkey_export_der(secp256k1_context_sign, (unsigned char*)&privkey[0], &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
+ ret = ec_privkey_export_der(secp256k1_context_sign, (unsigned char*) privkey.data(), &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
assert(ret);
privkey.resize(privkeylen);
return privkey;
@@ -167,7 +167,7 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_
secp256k1_ecdsa_signature sig;
int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL);
assert(ret);
- secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, (unsigned char*)&vchSig[0], &nSigLen, &sig);
+ secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, (unsigned char*)vchSig.data(), &nSigLen, &sig);
vchSig.resize(nSigLen);
return true;
}
@@ -202,7 +202,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
}
bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
- if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size()))
+ if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), privkey.data(), privkey.size()))
return false;
fCompressed = vchPubKey.IsCompressed();
fValid = true;
@@ -245,8 +245,8 @@ void CExtKey::SetMaster(const unsigned char *seed, unsigned int nSeedLen) {
static const unsigned char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'};
std::vector<unsigned char, secure_allocator<unsigned char>> vout(64);
CHMAC_SHA512(hashkey, sizeof(hashkey)).Write(seed, nSeedLen).Finalize(vout.data());
- key.Set(&vout[0], &vout[32], true);
- memcpy(chaincode.begin(), &vout[32], 32);
+ key.Set(vout.data(), vout.data() + 32, true);
+ memcpy(chaincode.begin(), vout.data() + 32, 32);
nDepth = 0;
nChild = 0;
memset(vchFingerprint, 0, sizeof(vchFingerprint));
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/merkleblock.cpp b/src/merkleblock.cpp
index 78d7cd6001..ba5f7b400c 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -153,7 +153,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch, std::ve
if (nTransactions == 0)
return uint256();
// check for excessively high numbers of transactions
- if (nTransactions > MAX_BLOCK_BASE_SIZE / 60) // 60 is the lower bound for the size of a serialized CTransaction
+ if (nTransactions > MAX_BLOCK_WEIGHT / MIN_TRANSACTION_WEIGHT)
return uint256();
// there can never be more hashes provided than one for every txid
if (vHash.size() > nTransactions)
diff --git a/src/net.cpp b/src/net.cpp
index 301cf58b87..5bf3af7ea3 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2876,5 +2876,5 @@ uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const
{
std::vector<unsigned char> vchNetGroup(ad.GetGroup());
- return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize();
+ return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup.data(), vchNetGroup.size()).Finalize();
}
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/netaddress.cpp b/src/netaddress.cpp
index 89f257c642..110e778fbd 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -573,7 +573,7 @@ std::vector<unsigned char> CService::GetKey() const
{
std::vector<unsigned char> vKey;
vKey.resize(18);
- memcpy(&vKey[0], ip, 16);
+ memcpy(vKey.data(), ip, 16);
vKey[16] = port / 0x100;
vKey[17] = port & 0x0FF;
return vKey;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index a23f92e1ed..1f668a5d4c 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -58,25 +58,6 @@ std::string GetNetworkName(enum Network net) {
}
}
-void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
- size_t colon = in.find_last_of(':');
- // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
- bool fHaveColon = colon != in.npos;
- bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
- bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos);
- if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) {
- int32_t n;
- if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) {
- in = in.substr(0, colon);
- portOut = n;
- }
- }
- if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']')
- hostOut = in.substr(1, in.size()-2);
- else
- hostOut = in;
-}
-
bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
{
vIP.clear();
@@ -563,7 +544,7 @@ static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDe
// do socks negotiation
if (proxy.randomize_credentials) {
ProxyCredentials random_auth;
- static std::atomic_int counter;
+ static std::atomic_int counter(0);
random_auth.username = random_auth.password = strprintf("%i", counter++);
if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket))
return false;
diff --git a/src/netbase.h b/src/netbase.h
index c9d108aadd..fd4b34c8f1 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -39,7 +39,6 @@ public:
enum Network ParseNetwork(std::string net);
std::string GetNetworkName(enum Network net);
-void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
bool SetProxy(enum Network net, const proxyType &addrProxy);
bool GetProxy(enum Network net, proxyType &proxyInfoOut);
bool IsProxy(const CNetAddr &addr);
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..0f186fa845 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
@@ -90,7 +117,7 @@ public:
* Create new TxConfirmStats. This is called by BlockPolicyEstimator's
* constructor with default values.
* @param defaultBuckets contains the upper limits for the bucket boundaries
- * @param maxConfirms max number of confirms to track
+ * @param maxPeriods max number of periods to track
* @param decay how much to decay the historical moving average per block
*/
TxConfirmStats(const std::vector<double>& defaultBuckets, const std::map<double, unsigned int>& defaultBucketMap,
@@ -671,7 +698,7 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
break;
}
default: {
- return CFeeRate(0);
+ throw std::out_of_range("CBlockPolicyEstimator::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("CBlockPolicyEstimator::HighestTargetTracked unknown FeeEstimateHorizon");
+ }
+ }
+}
+
unsigned int CBlockPolicyEstimator::BlockSpan() const
{
if (firstRecordedHeight == 0) return 0;
@@ -781,8 +826,10 @@ double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget,
* estimates, however, required the 95% threshold at 2 * target be met for any
* longer time horizons also.
*/
-CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, const CTxMemPool& pool, bool conservative) const
+CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
{
+ LOCK(cs_feeEstimator);
+
if (feeCalc) {
feeCalc->desiredTarget = confTarget;
feeCalc->returnedTarget = confTarget;
@@ -790,80 +837,70 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
double median = -1;
EstimationResult tempResult;
- {
- LOCK(cs_feeEstimator);
- // Return failure if trying to analyze a target we're not tracking
- if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms())
- return CFeeRate(0);
+ // Return failure if trying to analyze a target we're not tracking
+ if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms())
+ return CFeeRate(0);
- // It's not possible to get reasonable estimates for confTarget of 1
- if (confTarget == 1)
- confTarget = 2;
+ // It's not possible to get reasonable estimates for confTarget of 1
+ if (confTarget == 1)
+ confTarget = 2;
- unsigned int maxUsableEstimate = MaxUsableEstimate();
- if (maxUsableEstimate <= 1)
- return CFeeRate(0);
+ unsigned int maxUsableEstimate = MaxUsableEstimate();
+ if (maxUsableEstimate <= 1)
+ return CFeeRate(0);
- if ((unsigned int)confTarget > maxUsableEstimate) {
- confTarget = maxUsableEstimate;
- }
+ if ((unsigned int)confTarget > maxUsableEstimate) {
+ confTarget = maxUsableEstimate;
+ }
- assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
- /** true is passed to estimateCombined fee for target/2 and target so
- * that we check the max confirms for shorter time horizons as well.
- * This is necessary to preserve monotonically increasing estimates.
- * For non-conservative estimates we do the same thing for 2*target, but
- * for conservative estimates we want to skip these shorter horizons
- * checks for 2*target because we are taking the max over all time
- * horizons so we already have monotonically increasing estimates and
- * the purpose of conservative estimates is not to let short term
- * fluctuations lower our estimates by too much.
- */
- double halfEst = estimateCombinedFee(confTarget/2, HALF_SUCCESS_PCT, true, &tempResult);
+ assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
+ /** true is passed to estimateCombined fee for target/2 and target so
+ * that we check the max confirms for shorter time horizons as well.
+ * This is necessary to preserve monotonically increasing estimates.
+ * For non-conservative estimates we do the same thing for 2*target, but
+ * for conservative estimates we want to skip these shorter horizons
+ * checks for 2*target because we are taking the max over all time
+ * horizons so we already have monotonically increasing estimates and
+ * the purpose of conservative estimates is not to let short term
+ * fluctuations lower our estimates by too much.
+ */
+ double halfEst = estimateCombinedFee(confTarget/2, HALF_SUCCESS_PCT, true, &tempResult);
+ if (feeCalc) {
+ feeCalc->est = tempResult;
+ feeCalc->reason = FeeReason::HALF_ESTIMATE;
+ }
+ median = halfEst;
+ double actualEst = estimateCombinedFee(confTarget, SUCCESS_PCT, true, &tempResult);
+ if (actualEst > median) {
+ median = actualEst;
if (feeCalc) {
feeCalc->est = tempResult;
- feeCalc->reason = FeeReason::HALF_ESTIMATE;
+ feeCalc->reason = FeeReason::FULL_ESTIMATE;
}
- median = halfEst;
- double actualEst = estimateCombinedFee(confTarget, SUCCESS_PCT, true, &tempResult);
- if (actualEst > median) {
- median = actualEst;
- if (feeCalc) {
- feeCalc->est = tempResult;
- feeCalc->reason = FeeReason::FULL_ESTIMATE;
- }
+ }
+ double doubleEst = estimateCombinedFee(2 * confTarget, DOUBLE_SUCCESS_PCT, !conservative, &tempResult);
+ if (doubleEst > median) {
+ median = doubleEst;
+ if (feeCalc) {
+ feeCalc->est = tempResult;
+ feeCalc->reason = FeeReason::DOUBLE_ESTIMATE;
}
- double doubleEst = estimateCombinedFee(2 * confTarget, DOUBLE_SUCCESS_PCT, !conservative, &tempResult);
- if (doubleEst > median) {
- median = doubleEst;
+ }
+
+ if (conservative || median == -1) {
+ double consEst = estimateConservativeFee(2 * confTarget, &tempResult);
+ if (consEst > median) {
+ median = consEst;
if (feeCalc) {
feeCalc->est = tempResult;
- feeCalc->reason = FeeReason::DOUBLE_ESTIMATE;
+ feeCalc->reason = FeeReason::CONSERVATIVE;
}
}
-
- if (conservative || median == -1) {
- double consEst = estimateConservativeFee(2 * confTarget, &tempResult);
- if (consEst > median) {
- median = consEst;
- if (feeCalc) {
- feeCalc->est = tempResult;
- feeCalc->reason = FeeReason::CONSERVATIVE;
- }
- }
- }
- } // Must unlock cs_feeEstimator before taking mempool locks
+ }
if (feeCalc) feeCalc->returnedTarget = confTarget;
- // If mempool is limiting txs , return at least the min feerate from the mempool
- CAmount minPoolFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
- if (minPoolFee > 0 && minPoolFee > median) {
- if (feeCalc) feeCalc->reason = FeeReason::MEMPOOL_MIN;
- return CFeeRate(minPoolFee);
- }
-
if (median < 0)
return CFeeRate(0);
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 2029ce3744..f4ef793643 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, 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..9f2d623e76 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -7,13 +7,13 @@
#include "policy/policy.h"
+#include "consensus/validation.h"
#include "validation.h"
#include "coins.h"
#include "tinyformat.h"
#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..46640d6fff 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; }
@@ -220,7 +220,7 @@ public:
}
}
- prevector() : _size(0) {}
+ prevector() : _size(0), _union{{}} {}
explicit prevector(size_type n) : _size(0) {
resize(n);
diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp
index 9a979094cc..24be67c84f 100644
--- a/src/primitives/block.cpp
+++ b/src/primitives/block.cpp
@@ -31,12 +31,3 @@ std::string CBlock::ToString() const
}
return s.str();
}
-
-int64_t GetBlockWeight(const CBlock& block)
-{
- // This implements the weight = (stripped_size * 4) + witness_size formula,
- // using only serialization with and without witness data. As witness_size
- // is equal to total_size - stripped_size, this formula is identical to:
- // weight = (stripped_size * 3) + total_size.
- return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION);
-}
diff --git a/src/primitives/block.h b/src/primitives/block.h
index f03cf48504..c90a1dfa64 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -152,7 +152,4 @@ struct CBlockLocator
}
};
-/** Compute the consensus-critical block weight (see BIP 141). */
-int64_t GetBlockWeight(const CBlock& tx);
-
#endif // BITCOIN_PRIMITIVES_BLOCK_H
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index a0d7793f97..f87934d586 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -114,8 +114,3 @@ std::string CTransaction::ToString() const
str += " " + vout[i].ToString() + "\n";
return str;
}
-
-int64_t GetTransactionWeight(const CTransaction& tx)
-{
- return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR -1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
-}
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 00ac0b92b5..041034bb8b 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -6,6 +6,7 @@
#ifndef BITCOIN_PRIMITIVES_TRANSACTION_H
#define BITCOIN_PRIMITIVES_TRANSACTION_H
+#include <stdint.h>
#include "amount.h"
#include "script/script.h"
#include "serialize.h"
@@ -13,8 +14,6 @@
static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000;
-static const int WITNESS_SCALE_FACTOR = 4;
-
/** An outpoint - a combination of a transaction hash and an index n into its vout */
class COutPoint
{
@@ -107,7 +106,7 @@ public:
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(prevout);
- READWRITE(*(CScriptBase*)(&scriptSig));
+ READWRITE(scriptSig);
READWRITE(nSequence);
}
@@ -147,7 +146,7 @@ public:
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(nValue);
- READWRITE(*(CScriptBase*)(&scriptPubKey));
+ READWRITE(scriptPubKey);
}
void SetNull()
@@ -411,7 +410,4 @@ typedef std::shared_ptr<const CTransaction> CTransactionRef;
static inline CTransactionRef MakeTransactionRef() { return std::make_shared<const CTransaction>(); }
template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }
-/** Compute the weight of a transaction, as defined by BIP 141 */
-int64_t GetTransactionWeight(const CTransaction &tx);
-
#endif // BITCOIN_PRIMITIVES_TRANSACTION_H
diff --git a/src/protocol.h b/src/protocol.h
index eba39ab1e5..7890bb627d 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -163,7 +163,7 @@ extern const char *PONG;
/**
* The notfound message is a reply to a getdata message which requested an
* object the receiving node does not have available for relay.
- * @ince protocol version 70001.
+ * @since protocol version 70001.
* @see https://bitcoin.org/en/developer-reference#notfound
*/
extern const char *NOTFOUND;
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index a16457ea4e..91af4e56f2 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -172,10 +172,7 @@ bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchS
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
return false;
}
- if (vchSig.size() == 0) {
- return false;
- }
- if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {
+ if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) {
return false;
}
/* libsecp256k1's ECDSA verification requires lower-S signatures, which have
@@ -274,7 +271,7 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
secp256k1_ecdsa_signature sig;
- if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {
+ if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) {
return false;
}
return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, NULL, &sig));
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..f3ee0fbe39 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -510,7 +510,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes -= 34;
// Fee
- nPayFee = CWallet::GetMinimumFee(nBytes, coinControl->nConfirmTarget, ::mempool, ::feeEstimator);
+ nPayFee = CWallet::GetMinimumFee(nBytes, *coinControl, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */);
if (nPayAmount > 0)
{
@@ -581,12 +581,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
QString toolTipDust = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
// how many satoshis the estimated fee can vary per byte we guess wrong
- double dFeeVary;
- 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;
- }
+ double dFeeVary = (double)nPayFee / nBytes;
+
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
l3->setToolTip(toolTip4);
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index 89f9c25d14..e82a3c1533 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -1068,44 +1068,15 @@
<number>30</number>
</property>
<item>
- <widget class="QSlider" name="sliderSmartFee">
- <property name="minimum">
+ <layout class="QHBoxLayout" name="horizontalLayoutConfTarget">
+ <property name="bottomMargin">
<number>0</number>
</property>
- <property name="maximum">
- <number>23</number>
- </property>
- <property name="pageStep">
- <number>1</number>
- </property>
- <property name="value">
- <number>0</number>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="invertedAppearance">
- <bool>false</bool>
- </property>
- <property name="invertedControls">
- <bool>false</bool>
- </property>
- <property name="tickPosition">
- <enum>QSlider::NoTicks</enum>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayoutFee10">
<item>
- <widget class="QLabel" name="labelSmartFeeNormal">
- <property name="text">
- <string>normal</string>
- </property>
- </widget>
+ <widget class="QComboBox" name="confTargetSelector"/>
</item>
<item>
- <spacer name="horizontalSpacer_7">
+ <spacer name="horizontalSpacerConfTarget">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -1117,33 +1088,6 @@
</property>
</spacer>
</item>
- <item>
- <widget class="QLabel" name="confirmationTargetLabel">
- <property name="text">
- <string notr="true">(count)</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QLabel" name="labelSmartFeeFast">
- <property name="text">
- <string>fast</string>
- </property>
- </widget>
- </item>
</layout>
</item>
</layout>
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..a01886c3ea 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -31,6 +31,25 @@
#include <QTextDocument>
#include <QTimer>
+static const std::array<int, 9> confTargets = { {2, 4, 6, 12, 24, 48, 144, 504, 1008} };
+int getConfTargetForIndex(int index) {
+ if (index+1 > static_cast<int>(confTargets.size())) {
+ return confTargets.back();
+ }
+ if (index < 0) {
+ return confTargets[0];
+ }
+ return confTargets[index];
+}
+int getIndexForConfTarget(int target) {
+ for (unsigned int i = 0; i < confTargets.size(); i++) {
+ if (confTargets[i] >= target) {
+ return i;
+ }
+ }
+ return confTargets.size() - 1;
+}
+
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::SendCoinsDialog),
@@ -152,35 +171,41 @@ void SendCoinsDialog::setModel(WalletModel *_model)
coinControlUpdateLabels();
// fee section
- connect(ui->sliderSmartFee, SIGNAL(valueChanged(int)), this, SLOT(updateSmartFeeLabel()));
- connect(ui->sliderSmartFee, SIGNAL(valueChanged(int)), this, SLOT(updateGlobalFeeVariables()));
- connect(ui->sliderSmartFee, SIGNAL(valueChanged(int)), this, SLOT(coinControlUpdateLabels()));
+ for (const int &n : confTargets) {
+ ui->confTargetSelector->addItem(tr("%1 (%2 blocks)").arg(GUIUtil::formatNiceTimeOffset(n*Params().GetConsensus().nPowTargetSpacing)).arg(n));
+ }
+ connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSmartFeeLabel()));
+ connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateFeeSectionControls()));
- connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels()));
- connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels()));
- connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(updateGlobalFeeVariables()));
connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(coinControlUpdateLabels()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(setMinimumFee()));
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();
updateSmartFeeLabel();
- updateGlobalFeeVariables();
// set default rbf checkbox state
ui->optInRBF->setCheckState(model->getDefaultWalletRbf() ? Qt::Checked : Qt::Unchecked);
// set the smartfee-sliders default value (wallets default conf.target or last stored value)
QSettings settings;
- if (settings.value("nSmartFeeSliderPosition").toInt() == 0)
- ui->sliderSmartFee->setValue(ui->sliderSmartFee->maximum() - model->getDefaultConfirmTarget() + 2);
+ if (settings.value("nSmartFeeSliderPosition").toInt() != 0) {
+ // migrate nSmartFeeSliderPosition to nConfTarget
+ // nConfTarget is available since 0.15 (replaced nSmartFeeSliderPosition)
+ int nConfirmTarget = 25 - settings.value("nSmartFeeSliderPosition").toInt(); // 25 == old slider range
+ settings.setValue("nConfTarget", nConfirmTarget);
+ settings.remove("nSmartFeeSliderPosition");
+ }
+ if (settings.value("nConfTarget").toInt() == 0)
+ ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(model->getDefaultConfirmTarget()));
else
- ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt());
+ ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(settings.value("nConfTarget").toInt()));
}
}
@@ -190,7 +215,7 @@ SendCoinsDialog::~SendCoinsDialog()
settings.setValue("fFeeSectionMinimized", fFeeMinimized);
settings.setValue("nFeeRadio", ui->groupFee->checkedId());
settings.setValue("nCustomFeeRadio", ui->groupCustomFee->checkedId());
- settings.setValue("nSmartFeeSliderPosition", ui->sliderSmartFee->value());
+ settings.setValue("nConfTarget", getConfTargetForIndex(ui->confTargetSelector->currentIndex()));
settings.setValue("nTransactionFee", (qint64)ui->customFee->value());
settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked());
@@ -243,14 +268,10 @@ void SendCoinsDialog::on_sendButton_clicked()
CCoinControl ctrl;
if (model->getOptionsModel()->getCoinControlFeatures())
ctrl = *CoinControlDialog::coinControl;
- if (ui->radioSmartFee->isChecked())
- ctrl.nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
- else
- ctrl.nConfirmTarget = 0;
- ctrl.signalRbf = ui->optInRBF->isChecked();
+ updateCoinControlState(ctrl);
- prepareStatus = model->prepareTransaction(currentTransaction, &ctrl);
+ prepareStatus = model->prepareTransaction(currentTransaction, ctrl);
// process prepareStatus and on error generate message shown to user
processSendCoinsReturn(prepareStatus,
@@ -594,36 +615,17 @@ void SendCoinsDialog::setMinimumFee()
void SendCoinsDialog::updateFeeSectionControls()
{
- ui->sliderSmartFee ->setEnabled(ui->radioSmartFee->isChecked());
+ ui->confTargetSelector ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelSmartFee ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelSmartFee2 ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelSmartFee3 ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelFeeEstimation ->setEnabled(ui->radioSmartFee->isChecked());
- ui->labelSmartFeeNormal ->setEnabled(ui->radioSmartFee->isChecked());
- ui->labelSmartFeeFast ->setEnabled(ui->radioSmartFee->isChecked());
- ui->confirmationTargetLabel ->setEnabled(ui->radioSmartFee->isChecked());
ui->checkBoxMinimumFee ->setEnabled(ui->radioCustomFee->isChecked());
ui->labelMinFeeWarning ->setEnabled(ui->radioCustomFee->isChecked());
ui->radioCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
}
-void SendCoinsDialog::updateGlobalFeeVariables()
-{
- if (ui->radioSmartFee->isChecked())
- {
- int nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
- payTxFee = CFeeRate(0);
-
- // show the estimated required time for confirmation
- ui->confirmationTargetLabel->setText(GUIUtil::formatDurationStr(nConfirmTarget * Params().GetConsensus().nPowTargetSpacing) + " / " + tr("%n block(s)", "", nConfirmTarget));
- }
- else
- {
- payTxFee = CFeeRate(ui->customFee->value());
- }
-}
-
void SendCoinsDialog::updateFeeMinimizedLabel()
{
if(!model || !model->getOptionsModel())
@@ -645,18 +647,32 @@ void SendCoinsDialog::updateMinFeeLabel()
);
}
+void SendCoinsDialog::updateCoinControlState(CCoinControl& ctrl)
+{
+ if (ui->radioCustomFee->isChecked()) {
+ ctrl.m_feerate = CFeeRate(ui->customFee->value());
+ } else {
+ ctrl.m_feerate.reset();
+ }
+ // Avoid using global defaults when sending money from the GUI
+ // Either custom fee will be used or if not selected, the confirmation target from dropdown box
+ ctrl.m_confirm_target = getConfTargetForIndex(ui->confTargetSelector->currentIndex());
+ ctrl.signalRbf = ui->optInRBF->isChecked();
+}
+
void SendCoinsDialog::updateSmartFeeLabel()
{
if(!model || !model->getOptionsModel())
return;
-
- int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
+ CCoinControl coin_control;
+ updateCoinControlState(coin_control);
+ coin_control.m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
FeeCalculation feeCalc;
- CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &feeCalc, ::mempool);
- if (feeRate <= CFeeRate(0)) // not enough data => minfee
- {
- ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
- std::max(CWallet::fallbackFee.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
+ CFeeRate feeRate = CFeeRate(CWallet::GetMinimumFee(1000, coin_control, ::mempool, ::feeEstimator, &feeCalc));
+
+ ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB");
+
+ if (feeCalc.reason == FeeReason::FALLBACK) {
ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
ui->labelFeeEstimation->setText("");
ui->fallbackFeeWarningLabel->setVisible(true);
@@ -667,8 +683,6 @@ void SendCoinsDialog::updateSmartFeeLabel()
}
else
{
- ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
- std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
ui->labelSmartFee2->hide();
ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", feeCalc.returnedTarget));
ui->fallbackFeeWarningLabel->setVisible(false);
@@ -727,8 +741,6 @@ void SendCoinsDialog::coinControlFeatureChanged(bool checked)
if (!checked && model) // coin control features disabled
CoinControlDialog::coinControl->SetNull();
- // make sure we set back the confirmation target
- updateGlobalFeeVariables();
coinControlUpdateLabels();
}
@@ -819,14 +831,11 @@ void SendCoinsDialog::coinControlUpdateLabels()
if (!model || !model->getOptionsModel())
return;
+ updateCoinControlState(*CoinControlDialog::coinControl);
+
// set pay amounts
CoinControlDialog::payAmounts.clear();
CoinControlDialog::fSubtractFeeFromAmount = false;
- if (ui->radioSmartFee->isChecked()) {
- CoinControlDialog::coinControl->nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
- } else {
- CoinControlDialog::coinControl->nConfirmTarget = model->getDefaultConfirmTarget();
- }
for(int i = 0; i < ui->entries->count(); ++i)
{
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index ff7040ac5b..70b4aa5a03 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -68,6 +68,8 @@ private:
void processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg = QString());
void minimizeFeeSection(bool fMinimize);
void updateFeeMinimizedLabel();
+ // Update the passed in CCoinControl with state from the GUI
+ void updateCoinControlState(CCoinControl& ctrl);
private Q_SLOTS:
void on_sendButton_clicked();
@@ -91,7 +93,6 @@ private Q_SLOTS:
void updateFeeSectionControls();
void updateMinFeeLabel();
void updateSmartFeeLabel();
- void updateGlobalFeeVariables();
Q_SIGNALS:
// Fired when a message should be reported to the user
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..ba0e1da0c7 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -19,10 +19,12 @@
#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"
#include "util.h" // for GetBoolArg
+#include "wallet/coincontrol.h"
#include "wallet/feebumper.h"
#include "wallet/wallet.h"
#include "wallet/walletdb.h" // for BackupWallet
@@ -34,7 +36,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),
@@ -191,7 +192,7 @@ bool WalletModel::validateAddress(const QString &address)
return addressParsed.IsValid();
}
-WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl)
+WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
{
CAmount total = 0;
bool fSubtractFeeFromAmount = false;
@@ -258,7 +259,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return DuplicateAddress;
}
- CAmount nBalance = getBalance(coinControl);
+ CAmount nBalance = getBalance(&coinControl);
if(total > nBalance)
{
@@ -667,8 +668,10 @@ bool WalletModel::bumpFee(uint256 hash)
{
std::unique_ptr<CFeeBumper> feeBump;
{
+ CCoinControl coin_control;
+ coin_control.signalRbf = true;
LOCK2(cs_main, wallet->cs_wallet);
- feeBump.reset(new CFeeBumper(wallet, hash, nTxConfirmTarget, false, 0, true));
+ feeBump.reset(new CFeeBumper(wallet, hash, coin_control, 0));
}
if (feeBump->getResult() != BumpFeeResult::OK)
{
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 16b0caed4e..5258dc6699 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -154,7 +154,7 @@ public:
};
// prepare transaction for getting txfee before sending coins
- SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl = NULL);
+ SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl);
// Send coins to a list of recipients
SendCoinsReturn sendCoins(WalletModelTransaction &transaction);
diff --git a/src/random.cpp b/src/random.cpp
index 67efc7d945..1ee6158e4b 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -36,6 +36,10 @@
#include <mutex>
+#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
+#include <cpuid.h>
+#endif
+
#include <openssl/err.h>
#include <openssl/rand.h>
@@ -72,18 +76,9 @@ static bool rdrand_supported = false;
static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
static void RDRandInit()
{
- uint32_t eax, ecx, edx;
-#if defined(__i386__) && ( defined(__PIC__) || defined(__PIE__))
- // Avoid clobbering ebx, as that is used for PIC on x86.
- uint32_t tmp;
- __asm__ ("mov %%ebx, %1; cpuid; mov %1, %%ebx": "=a"(eax), "=g"(tmp), "=c"(ecx), "=d"(edx) : "a"(1));
-#else
- uint32_t ebx;
- __asm__ ("cpuid": "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1));
-#endif
- //! When calling cpuid function #1, ecx register will have this set if RDRAND is available.
- if (ecx & CPUID_F1_ECX_RDRAND) {
- LogPrintf("Using RdRand as entropy source\n");
+ uint32_t eax, ebx, ecx, edx;
+ if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & CPUID_F1_ECX_RDRAND)) {
+ LogPrintf("Using RdRand as an additional entropy source\n");
rdrand_supported = true;
}
hwrand_initialized.store(true);
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/blockchain.cpp b/src/rpc/blockchain.cpp
index c17ca2fa3a..6178a1c7ab 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -798,7 +798,7 @@ static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash,
stats.nTransactions++;
for (const auto output : outputs) {
ss << VARINT(output.first + 1);
- ss << *(const CScriptBase*)(&output.second.out.scriptPubKey);
+ ss << output.second.out.scriptPubKey;
ss << VARINT(output.second.out.nValue);
stats.nTransactionOutputs++;
stats.nTotalAmount += output.second.out.nValue;
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..b8c94d32ec 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"
@@ -29,6 +30,16 @@
#include <univalue.h>
+unsigned int ParseConfirmTarget(const UniValue& value)
+{
+ int target = value.get_int();
+ unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
+ if (target < 1 || (unsigned int)target > max_target) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u - %u", 1, max_target));
+ }
+ return (unsigned int)target;
+}
+
/**
* Return average network hashes per second based on the last 'lookup' blocks,
* or from the last difficulty change if 'lookup' is nonpositive.
@@ -141,42 +152,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)
@@ -680,15 +655,16 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
result.push_back(Pair("mutable", aMutable));
result.push_back(Pair("noncerange", "00000000ffffffff"));
int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST;
+ int64_t nSizeLimit = MAX_BLOCK_SERIALIZED_SIZE;
if (fPreSegWit) {
assert(nSigOpLimit % WITNESS_SCALE_FACTOR == 0);
nSigOpLimit /= WITNESS_SCALE_FACTOR;
+ assert(nSizeLimit % WITNESS_SCALE_FACTOR == 0);
+ nSizeLimit /= WITNESS_SCALE_FACTOR;
}
result.push_back(Pair("sigoplimit", nSigOpLimit));
- if (fPreSegWit) {
- result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_BASE_SIZE));
- } else {
- result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SERIALIZED_SIZE));
+ result.push_back(Pair("sizelimit", nSizeLimit));
+ if (!fPreSegWit) {
result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT));
}
result.push_back(Pair("curtime", pblock->GetBlockTime()));
@@ -849,7 +825,6 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
"\n"
"A negative value is returned if not enough transactions and blocks\n"
"have been observed to make an estimate for any number of blocks.\n"
- "However it will not return a value below the mempool reject fee.\n"
"\nExample:\n"
+ HelpExampleCli("estimatesmartfee", "6")
);
@@ -865,7 +840,7 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
UniValue result(UniValue::VOBJ);
FeeCalculation feeCalc;
- CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &feeCalc, ::mempool, conservative);
+ CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &feeCalc, conservative);
result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
result.push_back(Pair("blocks", feeCalc.returnedTarget));
return result;
@@ -873,9 +848,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 +859,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 +960,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..868d7002b5
--- /dev/null
+++ b/src/rpc/mining.h
@@ -0,0 +1,18 @@
+// 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);
+
+/** Check bounds on a command line confirm target */
+unsigned int ParseConfirmTarget(const UniValue& value);
+
+#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/interpreter.cpp b/src/script/interpreter.cpp
index 7149c938fc..8a121774a0 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1099,7 +1099,7 @@ public:
// Serialize the script
if (nInput != nIn)
// Blank out other inputs' signatures
- ::Serialize(s, CScriptBase());
+ ::Serialize(s, CScript());
else
SerializeScriptCode(s);
// Serialize the nSequence
@@ -1207,7 +1207,7 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
// The prevout may already be contained in hashPrevout, and the nSequence
// may already be contain in hashSequence.
ss << txTo.vin[nIn].prevout;
- ss << static_cast<const CScriptBase&>(scriptCode);
+ ss << scriptCode;
ss << amount;
ss << txTo.vin[nIn].nSequence;
// Outputs (none/one/all, depending on flags)
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/script.h b/src/script/script.h
index bbb37f049e..d16bfd0e00 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -8,6 +8,7 @@
#include "crypto/common.h"
#include "prevector.h"
+#include "serialize.h"
#include <assert.h>
#include <climits>
@@ -404,6 +405,13 @@ public:
CScript(std::vector<unsigned char>::const_iterator pbegin, std::vector<unsigned char>::const_iterator pend) : CScriptBase(pbegin, pend) { }
CScript(const unsigned char* pbegin, const unsigned char* pend) : CScriptBase(pbegin, pend) { }
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITE(static_cast<CScriptBase&>(*this));
+ }
+
CScript& operator+=(const CScript& b)
{
insert(end(), b.begin(), b.end());
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/serialize.h b/src/serialize.h
index e82ddf2c5a..8b86a07a76 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -450,7 +450,7 @@ public:
}
string.resize(size);
if (size != 0)
- s.read((char*)&string[0], size);
+ s.read((char*)string.data(), size);
}
template<typename Stream>
@@ -458,7 +458,7 @@ public:
{
WriteCompactSize(s, string.size());
if (!string.empty())
- s.write((char*)&string[0], string.size());
+ s.write((char*)string.data(), string.size());
}
};
@@ -556,7 +556,7 @@ void Serialize(Stream& os, const std::basic_string<C>& str)
{
WriteCompactSize(os, str.size());
if (!str.empty())
- os.write((char*)&str[0], str.size() * sizeof(str[0]));
+ os.write((char*)str.data(), str.size() * sizeof(C));
}
template<typename Stream, typename C>
@@ -565,7 +565,7 @@ void Unserialize(Stream& is, std::basic_string<C>& str)
unsigned int nSize = ReadCompactSize(is);
str.resize(nSize);
if (nSize != 0)
- is.read((char*)&str[0], nSize * sizeof(str[0]));
+ is.read((char*)str.data(), nSize * sizeof(C));
}
@@ -578,7 +578,7 @@ void Serialize_impl(Stream& os, const prevector<N, T>& v, const unsigned char&)
{
WriteCompactSize(os, v.size());
if (!v.empty())
- os.write((char*)&v[0], v.size() * sizeof(T));
+ os.write((char*)v.data(), v.size() * sizeof(T));
}
template<typename Stream, unsigned int N, typename T, typename V>
@@ -646,7 +646,7 @@ void Serialize_impl(Stream& os, const std::vector<T, A>& v, const unsigned char&
{
WriteCompactSize(os, v.size());
if (!v.empty())
- os.write((char*)&v[0], v.size() * sizeof(T));
+ os.write((char*)v.data(), v.size() * sizeof(T));
}
template<typename Stream, typename T, typename A, typename V>
diff --git a/src/streams.h b/src/streams.h
index 8dc5a19ead..245fb9cd8f 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -389,7 +389,7 @@ public:
{
// Special case: stream << stream concatenates like stream += stream
if (!vch.empty())
- s.write((char*)&vch[0], vch.size() * sizeof(vch[0]));
+ s.write((char*)vch.data(), vch.size() * sizeof(value_type));
}
template<typename T>
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/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index be631ce7a6..6ed6e7744e 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -24,8 +24,7 @@ BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(dbwrapper)
{
// Perform tests both obfuscated and non-obfuscated.
- for (int i = 0; i < 2; i++) {
- bool obfuscate = (bool)i;
+ for (bool obfuscate : {false, true}) {
fs::path ph = fs::temp_directory_path() / fs::unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'k';
@@ -45,8 +44,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
BOOST_AUTO_TEST_CASE(dbwrapper_batch)
{
// Perform tests both obfuscated and non-obfuscated.
- for (int i = 0; i < 2; i++) {
- bool obfuscate = (bool)i;
+ for (bool obfuscate : {false, true}) {
fs::path ph = fs::temp_directory_path() / fs::unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
@@ -82,8 +80,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch)
BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
{
// Perform tests both obfuscated and non-obfuscated.
- for (int i = 0; i < 2; i++) {
- bool obfuscate = (bool)i;
+ for (bool obfuscate : {false, true}) {
fs::path ph = fs::temp_directory_path() / fs::unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
@@ -95,7 +92,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
uint256 in2 = InsecureRand256();
BOOST_CHECK(dbw.Write(key2, in2));
- std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
// Be sure to seek past the obfuscation key (if it exists)
it->Seek(key);
@@ -210,13 +207,8 @@ BOOST_AUTO_TEST_CASE(iterator_ordering)
BOOST_CHECK(dbw.Write(key, value));
}
- std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
- for (int c=0; c<2; ++c) {
- int seek_start;
- if (c == 0)
- seek_start = 0x00;
- else
- seek_start = 0x80;
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
+ for (int seek_start : {0x00, 0x80}) {
it->Seek((uint8_t)seek_start);
for (int x=seek_start; x<256; ++x) {
uint8_t key;
@@ -286,13 +278,8 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
}
}
- std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
- for (int c=0; c<2; ++c) {
- int seek_start;
- if (c == 0)
- seek_start = 0;
- else
- seek_start = 5;
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
+ for (int seek_start : {0, 5}) {
snprintf(buf, sizeof(buf), "%d", seek_start);
StringContentsSerializer seek_key(buf);
it->Seek(seek_key);
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/netbase_tests.cpp b/src/test/netbase_tests.cpp
index b45a7fcc57..1baf7643e5 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -4,6 +4,7 @@
#include "netbase.h"
#include "test/test_bitcoin.h"
+#include "utilstrencodings.h"
#include <string>
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 6bfd315647..fd8f7191f4 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -177,16 +177,6 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int i = 2; i < 9; i++) { // At 9, the original estimate was already at the bottom (b/c scale = 2)
BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
}
-
- // Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
- mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Height(blocknum).FromTx(tx));
- // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5]
- 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_AUTO_TEST_SUITE_END()
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/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
index eddb80aed5..d3b8b07228 100644
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "consensus/tx_verify.h"
+#include "consensus/validation.h"
#include "pubkey.h"
#include "key.h"
#include "script/script.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/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index a74f40251a..f609cb1af4 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -196,8 +196,8 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
// Test that invalidity under a set of flags doesn't preclude validity
// under other (eg consensus) flags.
// spend_tx is invalid according to DERSIG
- CValidationState state;
{
+ CValidationState state;
PrecomputedTransactionData ptd_spend_tx(spend_tx);
BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
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..ac13f73e70 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>
@@ -663,7 +662,7 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro
// _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, _1, _2));
cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end());
clientNonce = std::vector<uint8_t>(TOR_NONCE_SIZE, 0);
- GetRandBytes(&clientNonce[0], TOR_NONCE_SIZE);
+ GetRandBytes(clientNonce.data(), TOR_NONCE_SIZE);
_conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2));
} else {
if (status_cookie.first) {
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 002f6550bc..aa0b73a417 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -172,7 +172,7 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
CCoinsViewCursor *CCoinsViewDB::Cursor() const
{
- CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper*>(&db)->NewIterator(), GetBestBlock());
+ CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper&>(db).NewIterator(), GetBestBlock());
/* It seems that there are no "const iterators" for LevelDB. Since we
only need read operations on it, use a const-cast to get around
that restriction. */
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/undo.h b/src/undo.h
index 3749d5d7a8..0f9d041bbd 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -60,7 +60,8 @@ public:
TxInUndoDeserializer(Coin* coin) : txout(coin) {}
};
-static const size_t MAX_INPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE / ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION);
+static const size_t MIN_TRANSACTION_INPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION);
+static const size_t MAX_INPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_INPUT_WEIGHT;
/** Undo information for a CTransaction */
class CTxUndo
diff --git a/src/util.h b/src/util.h
index 824ad51ac4..e1bdfb1988 100644
--- a/src/util.h
+++ b/src/util.h
@@ -215,7 +215,7 @@ public:
* Return string argument or default value
*
* @param strArg Argument to get (e.g. "-foo")
- * @param default (e.g. "1")
+ * @param strDefault (e.g. "1")
* @return command-line argument or default value
*/
std::string GetArg(const std::string& strArg, const std::string& strDefault);
@@ -224,7 +224,7 @@ public:
* Return integer argument or default value
*
* @param strArg Argument to get (e.g. "-foo")
- * @param default (e.g. 1)
+ * @param nDefault (e.g. 1)
* @return command-line argument (0 if invalid number) or default value
*/
int64_t GetArg(const std::string& strArg, int64_t nDefault);
@@ -233,7 +233,7 @@ public:
* Return boolean argument or default value
*
* @param strArg Argument to get (e.g. "-foo")
- * @param default (true or false)
+ * @param fDefault (true or false)
* @return command-line argument or default value
*/
bool GetBoolArg(const std::string& strArg, bool fDefault);
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index 93abaec04b..9ee14070a2 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -91,6 +91,25 @@ std::vector<unsigned char> ParseHex(const std::string& str)
return ParseHex(str.c_str());
}
+void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
+ size_t colon = in.find_last_of(':');
+ // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
+ bool fHaveColon = colon != in.npos;
+ bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
+ bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos);
+ if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) {
+ int32_t n;
+ if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) {
+ in = in.substr(0, colon);
+ portOut = n;
+ }
+ }
+ if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']')
+ hostOut = in.substr(1, in.size()-2);
+ else
+ hostOut = in;
+}
+
std::string EncodeBase64(const unsigned char* pch, size_t len)
{
static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -228,7 +247,7 @@ std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
std::string DecodeBase64(const std::string& str)
{
std::vector<unsigned char> vchRet = DecodeBase64(str.c_str());
- return (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size());
+ return std::string((const char*)vchRet.data(), vchRet.size());
}
std::string EncodeBase32(const unsigned char* pch, size_t len)
@@ -415,7 +434,7 @@ std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
std::string DecodeBase32(const std::string& str)
{
std::vector<unsigned char> vchRet = DecodeBase32(str.c_str());
- return (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size());
+ return std::string((const char*)vchRet.data(), vchRet.size());
}
static bool ParsePrechecks(const std::string& str)
diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h
index 8b37fe12e0..707fdaad16 100644
--- a/src/utilstrencodings.h
+++ b/src/utilstrencodings.h
@@ -48,6 +48,7 @@ std::string DecodeBase32(const std::string& str);
std::string EncodeBase32(const unsigned char* pch, size_t len);
std::string EncodeBase32(const std::string& str);
+void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
std::string i64tostr(int64_t n);
std::string itostr(int n);
int64_t atoi64(const char* psz);
diff --git a/src/validation.cpp b/src/validation.cpp
index 975cbcc79f..d7d880d24f 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"
@@ -454,7 +455,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// Reject transactions with witness before segregated witness activates (override with -prematurewitness)
bool witnessEnabled = IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus());
- if (!GetBoolArg("-prematurewitness",false) && tx.HasWitness() && !witnessEnabled) {
+ if (!GetBoolArg("-prematurewitness", false) && tx.HasWitness() && !witnessEnabled) {
return state.DoS(0, false, REJECT_NONSTANDARD, "no-witness-yet", true);
}
@@ -531,24 +532,20 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
view.SetBackend(viewMemPool);
- // do we already have it?
- for (size_t out = 0; out < tx.vout.size(); out++) {
- COutPoint outpoint(hash, out);
- bool had_coin_in_cache = pcoinsTip->HaveCoinInCache(outpoint);
- if (view.HaveCoin(outpoint)) {
- if (!had_coin_in_cache) {
- coins_to_uncache.push_back(outpoint);
- }
- return state.Invalid(false, REJECT_DUPLICATE, "txn-already-known");
- }
- }
-
// do all inputs exist?
for (const CTxIn txin : tx.vin) {
if (!pcoinsTip->HaveCoinInCache(txin.prevout)) {
coins_to_uncache.push_back(txin.prevout);
}
if (!view.HaveCoin(txin.prevout)) {
+ // Are inputs missing because we already have the tx?
+ for (size_t out = 0; out < tx.vout.size(); out++) {
+ // Optimistically just do efficient check of cache for outputs
+ if (pcoinsTip->HaveCoinInCache(COutPoint(hash, out))) {
+ return state.Invalid(false, REJECT_DUPLICATE, "txn-already-known");
+ }
+ }
+ // Otherwise assume this might be an orphan tx for which we just haven't seen parents yet
if (pfMissingInputs) {
*pfMissingInputs = true;
}
@@ -1140,7 +1137,7 @@ static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
// or a chain that is entirely longer than ours and invalid (note that this should be detected by both)
// We define it this way because it allows us to only store the highest fork tip (+ base) which meets
// the 7-block condition and from this always have the most-likely-to-cause-warning fork
- if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) &&
+ if (pfork && (!pindexBestForkTip || pindexNewForkTip->nHeight > pindexBestForkTip->nHeight) &&
pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) &&
chainActive.Height() - pindexNewForkTip->nHeight < 72)
{
@@ -2340,7 +2337,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.
@@ -2802,7 +2799,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
// checks that use witness data may be performed here.
// Size limits
- if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_BASE_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) > MAX_BLOCK_BASE_SIZE)
+ if (block.vtx.empty() || block.vtx.size() * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed");
// First transaction must be coinbase, the rest must not be
@@ -2889,7 +2886,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
if (consensusParams.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) {
if (commitpos == -1) {
uint256 witnessroot = BlockWitnessMerkleRoot(block, NULL);
- CHash256().Write(witnessroot.begin(), 32).Write(&ret[0], 32).Finalize(witnessroot.begin());
+ CHash256().Write(witnessroot.begin(), 32).Write(ret.data(), 32).Finalize(witnessroot.begin());
CTxOut out;
out.nValue = 0;
out.scriptPubKey.resize(38);
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..fc0e7c519e 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -6,9 +6,12 @@
#define BITCOIN_WALLET_COINCONTROL_H
#include "policy/feerate.h"
+#include "policy/fees.h"
#include "primitives/transaction.h"
#include "wallet/wallet.h"
+#include <boost/optional.hpp>
+
/** Coin Control Features. */
class CCoinControl
{
@@ -18,14 +21,16 @@ public:
bool fAllowOtherInputs;
//! Includes watch only addresses which match the ISMINE_WATCH_SOLVABLE criteria
bool fAllowWatchOnly;
- //! Override estimated feerate
+ //! Override automatic min/max checks on fee, m_feerate must be set if true
bool fOverrideFeeRate;
- //! Feerate to use if overrideFeeRate is true
- CFeeRate nFeeRate;
- //! Override the default confirmation target, 0 = use default
- int nConfirmTarget;
+ //! Override the default payTxFee if set
+ boost::optional<CFeeRate> m_feerate;
+ //! Override the default confirmation target if set
+ boost::optional<unsigned int> m_confirm_target;
//! Signal BIP-125 replace by fee.
bool signalRbf;
+ //! Fee estimation mode to control arguments to estimateSmartFee
+ FeeEstimateMode m_fee_mode;
CCoinControl()
{
@@ -38,10 +43,11 @@ public:
fAllowOtherInputs = false;
fAllowWatchOnly = false;
setSelected.clear();
- nFeeRate = CFeeRate(0);
+ m_feerate.reset();
fOverrideFeeRate = false;
- nConfirmTarget = 0;
+ m_confirm_target.reset();
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/db.h b/src/wallet/db.h
index 7cccc65660..4f3ad0c42d 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -95,13 +95,13 @@ class CWalletDBWrapper
friend class CDB;
public:
/** Create dummy DB handle */
- CWalletDBWrapper() : nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(nullptr)
+ CWalletDBWrapper() : nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(nullptr)
{
}
/** Create DB handle to real database */
CWalletDBWrapper(CDBEnv *env_in, const std::string &strFile_in) :
- nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(env_in), strFile(strFile_in)
+ nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(env_in), strFile(strFile_in)
{
}
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 6a9e6cf9ff..4bfd8726a5 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "consensus/validation.h"
+#include "wallet/coincontrol.h"
#include "wallet/feebumper.h"
#include "wallet/wallet.h"
#include "policy/fees.h"
@@ -66,7 +67,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, const CCoinControl& coin_control, CAmount totalFee)
:
txid(std::move(txidIn)),
nOldFee(0),
@@ -165,7 +166,7 @@ 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);
+ nNewFee = CWallet::GetMinimumFee(maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */);
nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
// New fee rate must be at least old rate + minimum incremental relay rate
@@ -220,7 +221,7 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConf
}
// Mark new tx not replaceable, if requested.
- if (!newTxReplaceable) {
+ if (!coin_control.signalRbf) {
for (auto& input : mtx.vin) {
if (input.nSequence < 0xfffffffe) input.nSequence = 0xfffffffe;
}
diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h
index fc32316704..3d64e53c15 100644
--- a/src/wallet/feebumper.h
+++ b/src/wallet/feebumper.h
@@ -10,6 +10,8 @@
class CWallet;
class CWalletTx;
class uint256;
+class CCoinControl;
+enum class FeeEstimateMode;
enum class BumpFeeResult
{
@@ -24,7 +26,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, const CCoinControl& coin_control, CAmount totalFee);
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..ee8c7548fc 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, const CCoinControl& coin_control)
{
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.m_confirm_target = ParseConfirmTarget(request.params[6]);
+ }
+
+ 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();
}
@@ -716,9 +740,9 @@ UniValue getbalance(const JSONRPCRequest& request)
"\nResult:\n"
"amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
"\nExamples:\n"
- "\nThe total amount in the wallet\n"
+ "\nThe total amount in the wallet with 1 or more confirmations\n"
+ HelpExampleCli("getbalance", "") +
- "\nThe total amount in the wallet at least 5 blocks confirmed\n"
+ "\nThe total amount in the wallet at least 6 blocks confirmed\n"
+ HelpExampleCli("getbalance", "\"*\" 6") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("getbalance", "\"*\", 6")
@@ -874,7 +898,8 @@ UniValue sendfrom(const JSONRPCRequest& request)
if (nAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
- SendMoney(pwallet, address.Get(), nAmount, false, wtx);
+ CCoinControl no_coin_control; // This is a deprecated API
+ SendMoney(pwallet, address.Get(), nAmount, false, wtx, no_coin_control);
return wtx.GetHash().GetHex();
}
@@ -887,9 +912,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 +934,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 +972,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.m_confirm_target = ParseConfirmTarget(request.params[6]);
+ }
+
+ 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 +1034,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 +2701,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"
@@ -2678,13 +2730,9 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
RPCTypeCheck(request.params, {UniValue::VSTR});
CCoinControl coinControl;
- coinControl.destChange = CNoDestination();
int changePosition = -1;
- coinControl.fAllowWatchOnly = false; // include watching
bool lockUnspents = false;
bool reserveChangeKey = true;
- coinControl.nFeeRate = CFeeRate(0);
- coinControl.fOverrideFeeRate = false;
UniValue subtractFeeFromOutputs;
std::set<int> setSubtractFeeFromOutputs;
@@ -2707,7 +2755,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);
@@ -2734,15 +2784,23 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
if (options.exists("feeRate"))
{
- coinControl.nFeeRate = CFeeRate(AmountFromValue(options["feeRate"]));
+ coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
coinControl.fOverrideFeeRate = true;
}
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.m_confirm_target = ParseConfirmTarget(options["conf_target"]);
+ }
+ 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 +2879,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"
@@ -2839,10 +2901,9 @@ UniValue bumpfee(const JSONRPCRequest& request)
hash.SetHex(request.params[0].get_str());
// optional parameters
- bool ignoreGlobalPayTxFee = false;
- int newConfirmTarget = nTxConfirmTarget;
CAmount totalFee = 0;
- bool replaceable = true;
+ CCoinControl coin_control;
+ coin_control.signalRbf = true;
if (request.params.size() > 1) {
UniValue options = request.params[1];
RPCTypeCheckObj(options,
@@ -2850,20 +2911,14 @@ UniValue bumpfee(const JSONRPCRequest& request)
{"confTarget", UniValueType(UniValue::VNUM)},
{"totalFee", UniValueType(UniValue::VNUM)},
{"replaceable", UniValueType(UniValue::VBOOL)},
+ {"estimate_mode", UniValueType(UniValue::VSTR)},
},
true, true);
if (options.exists("confTarget") && options.exists("totalFee")) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget and totalFee options should not both be set. Please provide either a confirmation target for fee estimation or an explicit total fee for the transaction.");
- } else if (options.exists("confTarget")) {
- // If the user has explicitly set a confTarget in this rpc call,
- // then override the default logic that uses the global payTxFee
- // instead of the confirmation target.
- ignoreGlobalPayTxFee = true;
- newConfirmTarget = options["confTarget"].get_int();
- if (newConfirmTarget <= 0) { // upper-bound will be checked by estimatefee/smartfee
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid confTarget (cannot be <= 0)");
- }
+ } else if (options.exists("confTarget")) { // TODO: alias this to conf_target
+ coin_control.m_confirm_target = ParseConfirmTarget(options["confTarget"]);
} else if (options.exists("totalFee")) {
totalFee = options["totalFee"].get_int64();
if (totalFee <= 0) {
@@ -2872,14 +2927,19 @@ UniValue bumpfee(const JSONRPCRequest& request)
}
if (options.exists("replaceable")) {
- replaceable = options["replaceable"].get_bool();
+ coin_control.signalRbf = options["replaceable"].get_bool();
+ }
+ if (options.exists("estimate_mode")) {
+ if (!FeeModeFromString(options["estimate_mode"].get_str(), coin_control.m_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, coin_control, totalFee);
BumpFeeResult res = feeBump.getResult();
if (res != BumpFeeResult::OK)
{
@@ -2922,6 +2982,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 +3081,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 +3090,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/rpcwallet.h b/src/wallet/rpcwallet.h
index bd5dad18ca..31e2f6a699 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -16,7 +16,7 @@ void RegisterWalletRPCCommands(CRPCTable &t);
* @param[in] request JSONRPCRequest that wishes to access a wallet
* @return NULL if no wallet should be used, or a pointer to the CWallet
*/
-CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest&);
+CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
std::string HelpRequiringPassphrase(CWallet *);
void EnsureWalletIsUnlocked(CWallet *);
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/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 96a1b14b60..8176a0017c 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -13,6 +13,7 @@
#include "rpc/server.h"
#include "test/test_bitcoin.h"
#include "validation.h"
+#include "wallet/coincontrol.h"
#include "wallet/test/wallet_test_fixture.h"
#include <boost/test/unit_test.hpp>
@@ -617,7 +618,8 @@ public:
CAmount fee;
int changePos = -1;
std::string error;
- BOOST_CHECK(wallet->CreateTransaction({recipient}, wtx, reservekey, fee, changePos, error));
+ CCoinControl dummy;
+ BOOST_CHECK(wallet->CreateTransaction({recipient}, wtx, reservekey, fee, changePos, error, dummy));
CValidationState state;
BOOST_CHECK(wallet->CommitTransaction(wtx, reservekey, nullptr, state));
auto it = wallet->mapWallet.find(wtx.GetHash());
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 0d1a86dd24..13da7bb2c2 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");
}
}
@@ -2469,9 +2469,9 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
CReserveKey reservekey(this);
CWalletTx wtx;
- if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, &coinControl, false))
+ if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) {
return false;
-
+ }
if (nChangePosInOut != -1)
tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.tx->vout[nChangePosInOut]);
@@ -2502,7 +2502,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
}
bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
- int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign)
+ int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign)
{
CAmount nValue = 0;
int nChangePosRequest = nChangePosInOut;
@@ -2567,9 +2567,42 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
LOCK2(cs_main, cs_wallet);
{
std::vector<COutput> vAvailableCoins;
- AvailableCoins(vAvailableCoins, true, coinControl);
+ AvailableCoins(vAvailableCoins, true, &coin_control);
+
+ // 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 (!boost::get<CNoDestination>(&coin_control.destChange)) {
+ scriptChange = GetScriptForDestination(coin_control.destChange);
+ } else { // no coin control: send change to newly generated address
+ // 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 +2648,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, &coin_control))
+ {
+ 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 +2671,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
{
nChangePosInOut = -1;
nFeeRet += nChange;
- reservekey.ReturnKey();
}
else
{
@@ -2685,7 +2689,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
txNew.vout.insert(position, newTxOut);
}
} else {
- reservekey.ReturnKey();
nChangePosInOut = -1;
}
@@ -2699,8 +2702,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
// to avoid conflicting with other possible uses of nSequence,
// and in the spirit of "smallest possible change from prior
// behavior."
- bool rbf = coinControl ? coinControl->signalRbf : fWalletRbf;
- const uint32_t nSequence = rbf ? MAX_BIP125_RBF_SEQUENCE : (std::numeric_limits<unsigned int>::max() - 1);
+ const uint32_t nSequence = coin_control.signalRbf ? MAX_BIP125_RBF_SEQUENCE : (std::numeric_limits<unsigned int>::max() - 1);
for (const auto& coin : setCoins)
txNew.vin.push_back(CTxIn(coin.outpoint,CScript(),
nSequence));
@@ -2719,14 +2721,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
vin.scriptWitness.SetNull();
}
- // Allow to override the default confirmation target over the CoinControl instance
- int currentConfirmationTarget = nTxConfirmTarget;
- if (coinControl && coinControl->nConfirmTarget > 0)
- currentConfirmationTarget = coinControl->nConfirmTarget;
-
- CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator, &feeCalc);
- if (coinControl && coinControl->fOverrideFeeRate)
- nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes);
+ CAmount nFeeNeeded = GetMinimumFee(nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc);
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.
@@ -2737,16 +2732,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, coin_control, ::mempool, ::feeEstimator, nullptr);
+ 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 +2764,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 +2789,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,33 +2922,61 @@ 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, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc)
{
- // 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);
- // ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
- if (nFeeNeeded == 0) {
- nFeeNeeded = fallbackFee.GetFee(nTxBytes);
+ /* User control of how to calculate fee uses the following parameter precedence:
+ 1. coin_control.m_feerate
+ 2. coin_control.m_confirm_target
+ 3. payTxFee (user-set global variable)
+ 4. nTxConfirmTarget (user-set global variable)
+ The first parameter that is set is used.
+ */
+ CAmount fee_needed;
+ if (coin_control.m_feerate) { // 1.
+ fee_needed = coin_control.m_feerate->GetFee(nTxBytes);
+ if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
+ // Allow to override automatic min/max check over coin control instance
+ if (coin_control.fOverrideFeeRate) return fee_needed;
+ }
+ else if (!coin_control.m_confirm_target && ::payTxFee != CFeeRate(0)) { // 3. TODO: remove magic value of 0 for global payTxFee
+ fee_needed = ::payTxFee.GetFee(nTxBytes);
+ if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
+ }
+ else { // 2. or 4.
+ // We will use smart fee estimation
+ unsigned int target = coin_control.m_confirm_target ? *coin_control.m_confirm_target : ::nTxConfirmTarget;
+ // By default estimates are economical iff we are signaling opt-in-RBF
+ bool conservative_estimate = !coin_control.signalRbf;
+ // Allow to override the default fee estimate mode over the CoinControl instance
+ if (coin_control.m_fee_mode == FeeEstimateMode::CONSERVATIVE) conservative_estimate = true;
+ else if (coin_control.m_fee_mode == FeeEstimateMode::ECONOMICAL) conservative_estimate = false;
+
+ fee_needed = estimator.estimateSmartFee(target, feeCalc, conservative_estimate).GetFee(nTxBytes);
+ if (fee_needed == 0) {
+ // if we don't have enough data for estimateSmartFee, then use fallbackFee
+ fee_needed = fallbackFee.GetFee(nTxBytes);
if (feeCalc) feeCalc->reason = FeeReason::FALLBACK;
}
- } else {
- if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
+ // Obey mempool min fee when using smart fee estimation
+ CAmount min_mempool_fee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nTxBytes);
+ if (fee_needed < min_mempool_fee) {
+ fee_needed = min_mempool_fee;
+ if (feeCalc) feeCalc->reason = FeeReason::MEMPOOL_MIN;
+ }
}
+
// prevent user from paying a fee below minRelayTxFee or minTxFee
- CAmount requiredFee = GetRequiredFee(nTxBytes);
- if (requiredFee > nFeeNeeded) {
- nFeeNeeded = requiredFee;
+ CAmount required_fee = GetRequiredFee(nTxBytes);
+ if (required_fee > fee_needed) {
+ fee_needed = required_fee;
if (feeCalc) feeCalc->reason = FeeReason::REQUIRED;
}
// But always obey the maximum
- if (nFeeNeeded > maxTxFee) {
- nFeeNeeded = maxTxFee;
+ if (fee_needed > maxTxFee) {
+ fee_needed = maxTxFee;
if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
}
- return nFeeNeeded;
+ return fee_needed;
}
@@ -2946,7 +2991,8 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
if (dbw->Rewrite("\x04pool"))
{
LOCK(cs_wallet);
- setKeyPool.clear();
+ setInternalKeyPool.clear();
+ setExternalKeyPool.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
@@ -2974,7 +3020,8 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
{
if (dbw->Rewrite("\x04pool"))
{
- setKeyPool.clear();
+ setInternalKeyPool.clear();
+ setExternalKeyPool.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
@@ -2999,7 +3046,8 @@ DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
if (dbw->Rewrite("\x04pool"))
{
LOCK(cs_wallet);
- setKeyPool.clear();
+ setInternalKeyPool.clear();
+ setExternalKeyPool.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
@@ -3083,9 +3131,16 @@ bool CWallet::NewKeyPool()
{
LOCK(cs_wallet);
CWalletDB walletdb(*dbw);
- for (int64_t nIndex : setKeyPool)
+
+ for (int64_t nIndex : setInternalKeyPool) {
walletdb.ErasePool(nIndex);
- setKeyPool.clear();
+ }
+ setInternalKeyPool.clear();
+
+ for (int64_t nIndex : setExternalKeyPool) {
+ walletdb.ErasePool(nIndex);
+ }
+ setExternalKeyPool.clear();
if (!TopUpKeyPool()) {
return false;
@@ -3097,25 +3152,8 @@ bool CWallet::NewKeyPool()
size_t CWallet::KeypoolCountExternalKeys()
{
- AssertLockHeld(cs_wallet); // setKeyPool
-
- // immediately return setKeyPool's size if HD or HD_SPLIT is disabled or not supported
- if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT))
- return setKeyPool.size();
-
- CWalletDB walletdb(*dbw);
-
- // count amount of external keys
- size_t amountE = 0;
- for(const int64_t& id : setKeyPool)
- {
- CKeyPool tmpKeypool;
- if (!walletdb.ReadPool(id, tmpKeypool))
- throw std::runtime_error(std::string(__func__) + ": read failed");
- amountE += !tmpKeypool.fInternal;
- }
-
- return amountE;
+ AssertLockHeld(cs_wallet); // setExternalKeyPool
+ return setExternalKeyPool.size();
}
bool CWallet::TopUpKeyPool(unsigned int kpSize)
@@ -3135,10 +3173,8 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
// count amount of available keys (internal, external)
// make sure the keypool of external and internal keys fits the user selected target (-keypool)
- int64_t amountExternal = KeypoolCountExternalKeys();
- int64_t amountInternal = setKeyPool.size() - amountExternal;
- int64_t missingExternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - amountExternal, (int64_t) 0);
- int64_t missingInternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - amountInternal, (int64_t) 0);
+ int64_t missingExternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setExternalKeyPool.size(), (int64_t) 0);
+ int64_t missingInternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setInternalKeyPool.size(), (int64_t) 0);
if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT))
{
@@ -3150,20 +3186,32 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
for (int64_t i = missingInternal + missingExternal; i--;)
{
int64_t nEnd = 1;
- if (i < missingInternal)
+ if (i < missingInternal) {
internal = true;
- if (!setKeyPool.empty())
- nEnd = *(--setKeyPool.end()) + 1;
+ }
+
+ if (!setInternalKeyPool.empty()) {
+ nEnd = *(setInternalKeyPool.rbegin()) + 1;
+ }
+ if (!setExternalKeyPool.empty()) {
+ nEnd = std::max(nEnd, *(setExternalKeyPool.rbegin()) + 1);
+ }
+
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey(internal), internal)))
throw std::runtime_error(std::string(__func__) + ": writing generated key failed");
- setKeyPool.insert(nEnd);
- LogPrintf("keypool added key %d, size=%u, internal=%d\n", nEnd, setKeyPool.size(), internal);
+
+ if (internal) {
+ setInternalKeyPool.insert(nEnd);
+ } else {
+ setExternalKeyPool.insert(nEnd);
+ }
+ LogPrintf("keypool added key %d, size=%u (%u internal), new key is %s\n", nEnd, setInternalKeyPool.size() + setExternalKeyPool.size(), setInternalKeyPool.size(), internal ? "internal" : "external");
}
}
return true;
}
-void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool internal)
+void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal)
{
nIndex = -1;
keypool.vchPubKey = CPubKey();
@@ -3173,30 +3221,30 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool int
if (!IsLocked())
TopUpKeyPool();
+ bool fReturningInternal = IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT) && fRequestedInternal;
+ std::set<int64_t>& setKeyPool = fReturningInternal ? setInternalKeyPool : setExternalKeyPool;
+
// Get the oldest key
if(setKeyPool.empty())
return;
CWalletDB walletdb(*dbw);
- // try to find a key that matches the internal/external filter
- for(const int64_t& id : setKeyPool)
- {
- CKeyPool tmpKeypool;
- if (!walletdb.ReadPool(id, tmpKeypool))
- throw std::runtime_error(std::string(__func__) + ": read failed");
- if (!HaveKey(tmpKeypool.vchPubKey.GetID()))
- throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
- if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT) || tmpKeypool.fInternal == internal)
- {
- nIndex = id;
- keypool = tmpKeypool;
- setKeyPool.erase(id);
- assert(keypool.vchPubKey.IsValid());
- LogPrintf("keypool reserve %d\n", nIndex);
- return;
- }
+ auto it = setKeyPool.begin();
+ nIndex = *it;
+ setKeyPool.erase(it);
+ if (!walletdb.ReadPool(nIndex, keypool)) {
+ throw std::runtime_error(std::string(__func__) + ": read failed");
+ }
+ if (!HaveKey(keypool.vchPubKey.GetID())) {
+ throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
+ }
+ if (keypool.fInternal != fReturningInternal) {
+ throw std::runtime_error(std::string(__func__) + ": keypool entry misclassified");
}
+
+ assert(keypool.vchPubKey.IsValid());
+ LogPrintf("keypool reserve %d\n", nIndex);
}
}
@@ -3208,12 +3256,16 @@ void CWallet::KeepKey(int64_t nIndex)
LogPrintf("keypool keep %d\n", nIndex);
}
-void CWallet::ReturnKey(int64_t nIndex)
+void CWallet::ReturnKey(int64_t nIndex, bool fInternal)
{
// Return to key pool
{
LOCK(cs_wallet);
- setKeyPool.insert(nIndex);
+ if (fInternal) {
+ setInternalKeyPool.insert(nIndex);
+ } else {
+ setExternalKeyPool.insert(nIndex);
+ }
}
LogPrintf("keypool return %d\n", nIndex);
}
@@ -3237,48 +3289,35 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
return true;
}
-int64_t CWallet::GetOldestKeyPoolTime()
-{
- LOCK(cs_wallet);
-
- // if the keypool is empty, return <NOW>
- if (setKeyPool.empty())
+static int64_t GetOldestKeyTimeInPool(const std::set<int64_t>& setKeyPool, CWalletDB& walletdb) {
+ if (setKeyPool.empty()) {
return GetTime();
+ }
CKeyPool keypool;
- CWalletDB walletdb(*dbw);
-
- if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT))
- {
- // if HD & HD Chain Split is enabled, response max(oldest-internal-key, oldest-external-key)
- int64_t now = GetTime();
- int64_t oldest_external = now, oldest_internal = now;
-
- for(const int64_t& id : setKeyPool)
- {
- if (!walletdb.ReadPool(id, keypool)) {
- throw std::runtime_error(std::string(__func__) + ": read failed");
- }
- if (keypool.fInternal && keypool.nTime < oldest_internal) {
- oldest_internal = keypool.nTime;
- }
- else if (!keypool.fInternal && keypool.nTime < oldest_external) {
- oldest_external = keypool.nTime;
- }
- if (oldest_internal != now && oldest_external != now) {
- break;
- }
- }
- return std::max(oldest_internal, oldest_external);
- }
- // load oldest key from keypool, get time and return
int64_t nIndex = *(setKeyPool.begin());
- if (!walletdb.ReadPool(nIndex, keypool))
+ if (!walletdb.ReadPool(nIndex, keypool)) {
throw std::runtime_error(std::string(__func__) + ": read oldest key in keypool failed");
+ }
assert(keypool.vchPubKey.IsValid());
return keypool.nTime;
}
+int64_t CWallet::GetOldestKeyPoolTime()
+{
+ LOCK(cs_wallet);
+
+ CWalletDB walletdb(*dbw);
+
+ // load oldest key from keypool, get time and return
+ int64_t oldestKey = GetOldestKeyTimeInPool(setExternalKeyPool, walletdb);
+ if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) {
+ oldestKey = std::max(GetOldestKeyTimeInPool(setInternalKeyPool, walletdb), oldestKey);
+ }
+
+ return oldestKey;
+}
+
std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
std::map<CTxDestination, CAmount> balances;
@@ -3437,6 +3476,7 @@ bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
else {
return false;
}
+ fInternal = keypool.fInternal;
}
assert(vchPubKey.IsValid());
pubkey = vchPubKey;
@@ -3453,19 +3493,14 @@ void CReserveKey::KeepKey()
void CReserveKey::ReturnKey()
{
- if (nIndex != -1)
- pwallet->ReturnKey(nIndex);
+ if (nIndex != -1) {
+ pwallet->ReturnKey(nIndex, fInternal);
+ }
nIndex = -1;
vchPubKey = CPubKey();
}
-void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const
-{
- setAddress.clear();
-
- CWalletDB walletdb(*dbw);
-
- LOCK2(cs_main, cs_wallet);
+static void LoadReserveKeysToSet(std::set<CKeyID>& setAddress, const std::set<int64_t>& setKeyPool, CWalletDB& walletdb) {
for (const int64_t& id : setKeyPool)
{
CKeyPool keypool;
@@ -3473,12 +3508,27 @@ void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const
throw std::runtime_error(std::string(__func__) + ": read failed");
assert(keypool.vchPubKey.IsValid());
CKeyID keyID = keypool.vchPubKey.GetID();
- if (!HaveKey(keyID))
- throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
setAddress.insert(keyID);
}
}
+void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const
+{
+ setAddress.clear();
+
+ CWalletDB walletdb(*dbw);
+
+ LOCK2(cs_main, cs_wallet);
+ LoadReserveKeysToSet(setAddress, setInternalKeyPool, walletdb);
+ LoadReserveKeysToSet(setAddress, setExternalKeyPool, walletdb);
+
+ for (const CKeyID& keyID : setAddress) {
+ if (!HaveKey(keyID)) {
+ throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
+ }
+ }
+}
+
void CWallet::GetScriptForMining(std::shared_ptr<CReserveScript> &script)
{
std::shared_ptr<CReserveKey> rKey = std::make_shared<CReserveKey>(this);
@@ -4002,20 +4052,30 @@ bool CWallet::ParameterInteraction()
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
}
- if (GetBoolArg("-salvagewallet", false) && SoftSetBoolArg("-rescan", true)) {
+ if (GetBoolArg("-salvagewallet", false)) {
if (is_multiwallet) {
return InitError(strprintf("%s is only allowed with a single wallet file", "-salvagewallet"));
}
// Rewrite just private keys: rescan to find transactions
- LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
+ if (SoftSetBoolArg("-rescan", true)) {
+ LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
+ }
+ }
+
+ int zapwallettxes = GetArg("-zapwallettxes", 0);
+ // -zapwallettxes implies dropping the mempool on startup
+ if (zapwallettxes != 0 && SoftSetBoolArg("-persistmempool", false)) {
+ LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes);
}
- // -zapwallettx implies a rescan
- if (GetBoolArg("-zapwallettxes", false) && SoftSetBoolArg("-rescan", true)) {
+ // -zapwallettxes implies a rescan
+ if (zapwallettxes != 0) {
if (is_multiwallet) {
return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
}
- LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
+ if (SoftSetBoolArg("-rescan", true)) {
+ LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -rescan=1\n", __func__, zapwallettxes);
+ }
}
if (is_multiwallet) {
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index a3fd7408a0..b716e46a7d 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
@@ -698,7 +699,8 @@ private:
/* HD derive new child key (on internal or external chain) */
void DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret, bool internal = false);
- std::set<int64_t> setKeyPool;
+ std::set<int64_t> setInternalKeyPool;
+ std::set<int64_t> setExternalKeyPool;
int64_t nTimeFirstKey;
@@ -743,7 +745,11 @@ public:
void LoadKeyPool(int nIndex, const CKeyPool &keypool)
{
- setKeyPool.insert(nIndex);
+ if (keypool.fInternal) {
+ setInternalKeyPool.insert(nIndex);
+ } else {
+ setExternalKeyPool.insert(nIndex);
+ }
// If no metadata exists yet, create a default with the pool key's
// creation time. Note that this may be overwritten by actually
@@ -948,7 +954,7 @@ public:
* @note passing nChangePosInOut as -1 will result in setting a random position
*/
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut,
- std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
+ std::string& strFailReason, const CCoinControl& coin_control, bool sign = true);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries);
@@ -963,7 +969,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, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc);
/**
* Return the minimum required fee taking into account the
* floating relay fee and user set minimum transaction fee
@@ -973,9 +979,9 @@ public:
bool NewKeyPool();
size_t KeypoolCountExternalKeys();
bool TopUpKeyPool(unsigned int kpSize = 0);
- void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool internal);
+ void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
void KeepKey(int64_t nIndex);
- void ReturnKey(int64_t nIndex);
+ void ReturnKey(int64_t nIndex, bool fInternal);
bool GetKeyFromPool(CPubKey &key, bool internal = false);
int64_t GetOldestKeyPoolTime();
void GetAllReserveKeys(std::set<CKeyID>& setAddress) const;
@@ -1025,12 +1031,12 @@ public:
}
}
- void GetScriptForMining(std::shared_ptr<CReserveScript> &script) override;
+ void GetScriptForMining(std::shared_ptr<CReserveScript> &script);
unsigned int GetKeyPoolSize()
{
- AssertLockHeld(cs_wallet); // setKeyPool
- return setKeyPool.size();
+ AssertLockHeld(cs_wallet); // set{Ex,In}ternalKeyPool
+ return setInternalKeyPool.size() + setExternalKeyPool.size();
}
bool SetDefaultKey(const CPubKey &vchPubKey);
@@ -1134,11 +1140,13 @@ protected:
CWallet* pwallet;
int64_t nIndex;
CPubKey vchPubKey;
+ bool fInternal;
public:
CReserveKey(CWallet* pwalletIn)
{
nIndex = -1;
pwallet = pwalletIn;
+ fInternal = false;
}
CReserveKey() = default;
@@ -1211,4 +1219,5 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const ContainerType &coins
}
return true;
}
+
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 8321719b56..65a28af46d 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>
//
@@ -95,23 +94,23 @@ bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
{
- return WriteIC(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false);
+ return WriteIC(std::make_pair(std::string("cscript"), hash), redeemScript, false);
}
bool CWalletDB::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
{
- if (!WriteIC(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest)), keyMeta)) {
+ if (!WriteIC(std::make_pair(std::string("watchmeta"), dest), keyMeta)) {
return false;
}
- return WriteIC(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1');
+ return WriteIC(std::make_pair(std::string("watchs"), dest), '1');
}
bool CWalletDB::EraseWatchOnly(const CScript &dest)
{
- if (!EraseIC(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest)))) {
+ if (!EraseIC(std::make_pair(std::string("watchmeta"), dest))) {
return false;
}
- return EraseIC(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)));
+ return EraseIC(std::make_pair(std::string("watchs"), dest));
}
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
@@ -324,7 +323,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
{
wss.nWatchKeys++;
CScript script;
- ssKey >> *(CScriptBase*)(&script);
+ ssKey >> script;
char fYes;
ssValue >> fYes;
if (fYes == '1')
@@ -441,7 +440,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
else if (strType == "watchmeta")
{
CScript script;
- ssKey >> *(CScriptBase*)(&script);
+ ssKey >> script;
keyID = CScriptID(script);
}
@@ -475,7 +474,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
uint160 hash;
ssKey >> hash;
CScript script;
- ssValue >> *(CScriptBase*)(&script);
+ ssValue >> script;
if (!pwallet->LoadCScript(script))
{
strErr = "Error reading wallet database: LoadCScript failed";
@@ -748,7 +747,7 @@ DBErrors CWalletDB::ZapWalletTx(std::vector<CWalletTx>& vWtx)
void MaybeCompactWalletDB()
{
- static std::atomic<bool> fOneThread;
+ static std::atomic<bool> fOneThread(false);
if (fOneThread.exchange(true)) {
return;
}