aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bench/base58.cpp27
-rw-r--r--src/bench/verify_script.cpp10
-rw-r--r--src/bitcoin-cli.cpp10
-rw-r--r--src/blockencodings.cpp2
-rw-r--r--src/consensus/consensus.h2
-rw-r--r--src/core_memusage.h2
-rw-r--r--src/httpserver.cpp1
-rw-r--r--src/netbase.cpp19
-rw-r--r--src/netbase.h1
-rw-r--r--src/policy/fees.cpp116
-rw-r--r--src/policy/fees.h2
-rw-r--r--src/primitives/transaction.h4
-rw-r--r--src/protocol.h2
-rw-r--r--src/qt/coincontroldialog.cpp12
-rw-r--r--src/qt/sendcoinsdialog.cpp67
-rw-r--r--src/qt/sendcoinsdialog.h3
-rw-r--r--src/qt/walletmodel.cpp9
-rw-r--r--src/qt/walletmodel.h2
-rw-r--r--src/random.cpp20
-rw-r--r--src/rpc/blockchain.cpp2
-rw-r--r--src/rpc/mining.cpp13
-rw-r--r--src/rpc/mining.h3
-rw-r--r--src/script/interpreter.cpp4
-rw-r--r--src/script/script.h8
-rw-r--r--src/test/dbwrapper_tests.cpp29
-rw-r--r--src/test/netbase_tests.cpp1
-rw-r--r--src/test/policyestimator_tests.cpp10
-rw-r--r--src/test/txvalidationcache_tests.cpp2
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/util.h6
-rw-r--r--src/utilstrencodings.cpp19
-rw-r--r--src/utilstrencodings.h1
-rw-r--r--src/wallet/coincontrol.h16
-rw-r--r--src/wallet/feebumper.cpp8
-rw-r--r--src/wallet/feebumper.h3
-rw-r--r--src/wallet/rpcwallet.cpp48
-rw-r--r--src/wallet/rpcwallet.h2
-rw-r--r--src/wallet/test/wallet_tests.cpp4
-rw-r--r--src/wallet/wallet.cpp321
-rw-r--r--src/wallet/wallet.h25
-rw-r--r--src/wallet/walletdb.cpp16
41 files changed, 424 insertions, 430 deletions
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/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/blockencodings.cpp b/src/blockencodings.cpp
index 7adab586e8..6f27b7b9dc 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -48,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_WEIGHT / MIN_SERIALIZEABLE_TRANSACTION_WEIGHT)
+ 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/consensus/consensus.h b/src/consensus/consensus.h
index a1bb99a802..ddd4ee9fab 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -21,7 +21,7 @@ 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_SERIALIZEABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 10; // 10 is the lower bound for the size of a 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 {
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/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/netbase.cpp b/src/netbase.cpp
index 3fb1c18f03..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();
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/fees.cpp b/src/policy/fees.cpp
index 03fe11a0d8..0f186fa845 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -117,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,
@@ -698,7 +698,7 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
break;
}
default: {
- throw std::out_of_range("CBlockPoicyEstimator::estimateRawFee unknown FeeEstimateHorizon");
+ throw std::out_of_range("CBlockPolicyEstimator::estimateRawFee unknown FeeEstimateHorizon");
}
}
@@ -730,7 +730,7 @@ unsigned int CBlockPolicyEstimator::HighestTargetTracked(FeeEstimateHorizon hori
return longStats->GetMaxConfirms();
}
default: {
- throw std::out_of_range("CBlockPoicyEstimator::HighestTargetTracked unknown FeeEstimateHorizon");
+ throw std::out_of_range("CBlockPolicyEstimator::HighestTargetTracked unknown FeeEstimateHorizon");
}
}
}
@@ -826,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;
@@ -835,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 4c80371c5c..f4ef793643 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -208,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) 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
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index f1dd51b9fd..041034bb8b 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -106,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);
}
@@ -146,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()
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/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index c19420beb5..f3ee0fbe39 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -490,8 +490,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
else nBytesInputs += 148;
}
- bool conservative_estimate = CalculateEstimateType(FeeEstimateMode::UNSET, coinControl->signalRbf);
-
// calculation
if (nQuantity > 0)
{
@@ -512,7 +510,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes -= 34;
// Fee
- nPayFee = CWallet::GetMinimumFee(nBytes, coinControl->nConfirmTarget, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */, false /* ignoreGlobalPayTxFee */, conservative_estimate);
+ nPayFee = CWallet::GetMinimumFee(nBytes, *coinControl, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */);
if (nPayAmount > 0)
{
@@ -583,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, conservative_estimate).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/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 86401d3bb4..a01886c3ea 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -175,18 +175,13 @@ void SendCoinsDialog::setModel(WalletModel *_model)
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(updateGlobalFeeVariables()));
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()));
@@ -194,7 +189,6 @@ void SendCoinsDialog::setModel(WalletModel *_model)
updateFeeSectionControls();
updateMinFeeLabel();
updateSmartFeeLabel();
- updateGlobalFeeVariables();
// set default rbf checkbox state
ui->optInRBF->setCheckState(model->getDefaultWalletRbf() ? Qt::Checked : Qt::Unchecked);
@@ -274,14 +268,10 @@ void SendCoinsDialog::on_sendButton_clicked()
CCoinControl ctrl;
if (model->getOptionsModel()->getCoinControlFeatures())
ctrl = *CoinControlDialog::coinControl;
- if (ui->radioSmartFee->isChecked())
- ctrl.nConfirmTarget = getConfTargetForIndex(ui->confTargetSelector->currentIndex());
- 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,
@@ -636,18 +626,6 @@ void SendCoinsDialog::updateFeeSectionControls()
ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
}
-void SendCoinsDialog::updateGlobalFeeVariables()
-{
- if (ui->radioSmartFee->isChecked())
- {
- payTxFee = CFeeRate(0);
- }
- else
- {
- payTxFee = CFeeRate(ui->customFee->value());
- }
-}
-
void SendCoinsDialog::updateFeeMinimizedLabel()
{
if(!model || !model->getOptionsModel())
@@ -669,19 +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 = getConfTargetForIndex(ui->confTargetSelector->currentIndex());
+ CCoinControl coin_control;
+ updateCoinControlState(coin_control);
+ coin_control.m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
FeeCalculation feeCalc;
- bool conservative_estimate = CalculateEstimateType(FeeEstimateMode::UNSET, ui->optInRBF->isChecked());
- CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &feeCalc, ::mempool, conservative_estimate);
- if (feeRate <= CFeeRate(0)) // not enough data => minfee
- {
- ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
- 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);
@@ -692,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);
@@ -752,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();
}
@@ -844,15 +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 = getConfTargetForIndex(ui->confTargetSelector->currentIndex());
- } else {
- CoinControlDialog::coinControl->nConfirmTarget = model->getDefaultConfirmTarget();
- }
- CoinControlDialog::coinControl->signalRbf = ui->optInRBF->isChecked();
for(int i = 0; i < ui->entries->count(); ++i)
{
diff --git a/src/qt/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/walletmodel.cpp b/src/qt/walletmodel.cpp
index 60b55da3e7..ba0e1da0c7 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -24,6 +24,7 @@
#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
@@ -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, FeeEstimateMode::UNSET));
+ 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..3226abb69e 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);
@@ -191,6 +186,7 @@ void GetDevURandom(unsigned char *ent32)
do {
ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
+ close(f);
RandFailure();
}
have += n;
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/mining.cpp b/src/rpc/mining.cpp
index 10bb341e54..b8c94d32ec 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -30,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.
@@ -815,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")
);
@@ -831,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;
diff --git a/src/rpc/mining.h b/src/rpc/mining.h
index a148d851da..868d7002b5 100644
--- a/src/rpc/mining.h
+++ b/src/rpc/mining.h
@@ -12,4 +12,7 @@
/** 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/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/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/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/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 8cdd392109..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, true).GetFeePerK() >= feeEst.estimateRawFee(i, 0.85, FeeEstimateHorizon::MED_HALFLIFE).GetFeePerK());
- BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool, true).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
- }
}
BOOST_AUTO_TEST_SUITE_END()
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/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/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 2fabb8cf7a..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+/";
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/wallet/coincontrol.h b/src/wallet/coincontrol.h
index bdd01bec12..fc0e7c519e 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -10,6 +10,8 @@
#include "primitives/transaction.h"
#include "wallet/wallet.h"
+#include <boost/optional.hpp>
+
/** Coin Control Features. */
class CCoinControl
{
@@ -19,12 +21,12 @@ 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
@@ -41,9 +43,9 @@ 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;
}
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 607ecf4182..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, FeeEstimateMode fee_mode)
+CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoinControl& coin_control, CAmount totalFee)
:
txid(std::move(txidIn)),
nOldFee(0),
@@ -165,8 +166,7 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConf
nNewFee = totalFee;
nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
} else {
- bool conservative_estimate = CalculateEstimateType(fee_mode, newTxReplaceable);
- nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, nullptr /* FeeCalculation */, ignoreGlobalPayTxFee, conservative_estimate);
+ 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
@@ -221,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 11e2f5f953..3d64e53c15 100644
--- a/src/wallet/feebumper.h
+++ b/src/wallet/feebumper.h
@@ -10,6 +10,7 @@
class CWallet;
class CWalletTx;
class uint256;
+class CCoinControl;
enum class FeeEstimateMode;
enum class BumpFeeResult
@@ -25,7 +26,7 @@ enum class BumpFeeResult
class CFeeBumper
{
public:
- CFeeBumper(const CWallet *pWalletIn, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable, FeeEstimateMode fee_mode);
+ 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/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 5f72e3b6f5..ee8c7548fc 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -356,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, CCoinControl *coin_control = nullptr)
+static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew, const CCoinControl& coin_control)
{
CAmount curBalance = pwallet->GetBalance();
@@ -460,7 +460,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
}
if (request.params.size() > 6 && !request.params[6].isNull()) {
- coin_control.nConfirmTarget = request.params[6].get_int();
+ coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
}
if (request.params.size() > 7 && !request.params[7].isNull()) {
@@ -472,7 +472,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, &coin_control);
+ SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, coin_control);
return wtx.GetHash().GetHex();
}
@@ -740,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")
@@ -898,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();
}
@@ -980,7 +981,7 @@ UniValue sendmany(const JSONRPCRequest& request)
}
if (request.params.size() > 6 && !request.params[6].isNull()) {
- coin_control.nConfirmTarget = request.params[6].get_int();
+ coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
}
if (request.params.size() > 7 && !request.params[7].isNull()) {
@@ -1033,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, &coin_control);
+ bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control);
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
CValidationState state;
@@ -2729,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;
@@ -2787,7 +2784,7 @@ 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;
}
@@ -2798,7 +2795,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
coinControl.signalRbf = options["replaceable"].get_bool();
}
if (options.exists("conf_target")) {
- coinControl.nConfirmTarget = options["conf_target"].get_int();
+ coinControl.m_confirm_target = ParseConfirmTarget(options["conf_target"]);
}
if (options.exists("estimate_mode")) {
if (!FeeModeFromString(options["estimate_mode"].get_str(), coinControl.m_fee_mode)) {
@@ -2904,11 +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;
- FeeEstimateMode fee_mode = FeeEstimateMode::UNSET;
+ CCoinControl coin_control;
+ coin_control.signalRbf = true;
if (request.params.size() > 1) {
UniValue options = request.params[1];
RPCTypeCheckObj(options,
@@ -2922,15 +2917,8 @@ UniValue bumpfee(const JSONRPCRequest& request)
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) {
@@ -2939,10 +2927,10 @@ 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(), fee_mode)) {
+ if (!FeeModeFromString(options["estimate_mode"].get_str(), coin_control.m_fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
}
}
@@ -2951,7 +2939,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
- CFeeBumper feeBump(pwallet, hash, newConfirmTarget, ignoreGlobalPayTxFee, totalFee, replaceable, fee_mode);
+ CFeeBumper feeBump(pwallet, hash, coin_control, totalFee);
BumpFeeResult res = feeBump.getResult();
if (res != BumpFeeResult::OK)
{
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/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 07b7f58a64..13da7bb2c2 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -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,7 +2567,7 @@ 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
@@ -2575,12 +2575,9 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
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
- {
+ 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.
@@ -2654,7 +2651,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
if (pick_new_inputs) {
nValueIn = 0;
setCoins.clear();
- if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))
+ if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, &coin_control))
{
strFailReason = _("Insufficient funds");
return false;
@@ -2705,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));
@@ -2725,17 +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;
-
- // Allow to override the default fee estimate mode over the CoinControl instance
- bool conservative_estimate = CalculateEstimateType(coinControl ? coinControl->m_fee_mode : FeeEstimateMode::UNSET, rbf);
-
- CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator, &feeCalc, false /* ignoreGlobalPayTxFee */, conservative_estimate);
- if (coinControl && coinControl->fOverrideFeeRate)
- nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes);
+ 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.
@@ -2760,7 +2746,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
// new inputs. We now know we only need the smaller fee
// (because of reduced tx size) and so we should add a
// change output. Only try this once.
- CAmount fee_needed_for_change = GetMinimumFee(change_prototype_size, currentConfirmationTarget, ::mempool, ::feeEstimator, nullptr, false /* ignoreGlobalPayTxFee */, conservative_estimate);
+ CAmount 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) {
@@ -2936,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, bool conservative_estimate)
+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, conservative_estimate).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;
}
@@ -2977,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.
@@ -3005,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.
@@ -3030,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.
@@ -3114,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;
@@ -3128,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)
@@ -3166,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))
{
@@ -3181,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();
@@ -3204,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);
}
}
@@ -3239,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);
}
@@ -3268,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;
@@ -3468,6 +3476,7 @@ bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
else {
return false;
}
+ fInternal = keypool.fInternal;
}
assert(vchPubKey.IsValid());
pubkey = vchPubKey;
@@ -3484,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;
@@ -3504,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);
@@ -4043,13 +4062,19 @@ bool CWallet::ParameterInteraction()
}
}
- // -zapwallettx implies a rescan
- if (GetBoolArg("-zapwallettxes", false)) {
+ 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);
+ }
+
+ // -zapwallettxes implies a rescan
+ if (zapwallettxes != 0) {
if (is_multiwallet) {
return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
}
if (SoftSetBoolArg("-rescan", true)) {
- LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
+ LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -rescan=1\n", __func__, zapwallettxes);
}
}
@@ -4189,15 +4214,3 @@ bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState&
{
return ::AcceptToMemoryPool(mempool, state, tx, true, NULL, NULL, false, nAbsurdFee);
}
-
-bool CalculateEstimateType(FeeEstimateMode mode, bool opt_in_rbf) {
- switch (mode) {
- case FeeEstimateMode::UNSET:
- return !opt_in_rbf; // Allow for lower fees if RBF is an option
- case FeeEstimateMode::CONSERVATIVE:
- return true;
- case FeeEstimateMode::ECONOMICAL:
- return false;
- }
- return true;
-}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index e3715cdf37..b716e46a7d 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -699,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;
@@ -744,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
@@ -949,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);
@@ -964,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, bool ignoreGlobalPayTxFee, bool conservative_estimate);
+ 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
@@ -974,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;
@@ -1030,8 +1035,8 @@ public:
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);
@@ -1135,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;
@@ -1213,6 +1220,4 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const ContainerType &coins
return true;
}
-bool CalculateEstimateType(FeeEstimateMode mode, bool opt_in_rbf);
-
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 2a33dca240..65a28af46d 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -94,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)
@@ -323,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')
@@ -440,7 +440,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
else if (strType == "watchmeta")
{
CScript script;
- ssKey >> *(CScriptBase*)(&script);
+ ssKey >> script;
keyID = CScriptID(script);
}
@@ -474,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";