Add RPC options for RBF, confirmation target, and conservative fee estimation.
Add support for setting each of these attributes on a per RPC call basis to sendtoaddress, sendmany, fundrawtransaction (already had RBF), and bumpfee (already had RBF and conf target).
This commit is contained in:
parent
f0bf33da83
commit
f135923ee2
7 changed files with 109 additions and 18 deletions
|
@ -36,6 +36,20 @@ std::string StringForFeeReason(FeeReason reason) {
|
||||||
return reason_string->second;
|
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
|
* 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
|
* included in a block. We will lump transactions into a bucket according to their
|
||||||
|
|
|
@ -97,6 +97,8 @@ enum class FeeEstimateMode {
|
||||||
CONSERVATIVE, //! Force estimateSmartFee to use 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 */
|
/* Used to return detailed information about a feerate bucket */
|
||||||
struct EstimatorBucket
|
struct EstimatorBucket
|
||||||
{
|
{
|
||||||
|
|
|
@ -668,7 +668,7 @@ bool WalletModel::bumpFee(uint256 hash)
|
||||||
std::unique_ptr<CFeeBumper> feeBump;
|
std::unique_ptr<CFeeBumper> feeBump;
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
LOCK2(cs_main, wallet->cs_wallet);
|
||||||
feeBump.reset(new CFeeBumper(wallet, hash, nTxConfirmTarget, false, 0, true));
|
feeBump.reset(new CFeeBumper(wallet, hash, nTxConfirmTarget, false, 0, true, FeeEstimateMode::UNSET));
|
||||||
}
|
}
|
||||||
if (feeBump->getResult() != BumpFeeResult::OK)
|
if (feeBump->getResult() != BumpFeeResult::OK)
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,6 +37,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||||
{ "getnetworkhashps", 1, "height" },
|
{ "getnetworkhashps", 1, "height" },
|
||||||
{ "sendtoaddress", 1, "amount" },
|
{ "sendtoaddress", 1, "amount" },
|
||||||
{ "sendtoaddress", 4, "subtractfeefromamount" },
|
{ "sendtoaddress", 4, "subtractfeefromamount" },
|
||||||
|
{ "sendtoaddress", 5 , "replaceable" },
|
||||||
|
{ "sendtoaddress", 6 , "conf_target" },
|
||||||
{ "settxfee", 0, "amount" },
|
{ "settxfee", 0, "amount" },
|
||||||
{ "getreceivedbyaddress", 1, "minconf" },
|
{ "getreceivedbyaddress", 1, "minconf" },
|
||||||
{ "getreceivedbyaccount", 1, "minconf" },
|
{ "getreceivedbyaccount", 1, "minconf" },
|
||||||
|
@ -69,6 +71,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||||
{ "sendmany", 1, "amounts" },
|
{ "sendmany", 1, "amounts" },
|
||||||
{ "sendmany", 2, "minconf" },
|
{ "sendmany", 2, "minconf" },
|
||||||
{ "sendmany", 4, "subtractfeefrom" },
|
{ "sendmany", 4, "subtractfeefrom" },
|
||||||
|
{ "sendmany", 5 , "replaceable" },
|
||||||
|
{ "sendmany", 6 , "conf_target" },
|
||||||
{ "addmultisigaddress", 0, "nrequired" },
|
{ "addmultisigaddress", 0, "nrequired" },
|
||||||
{ "addmultisigaddress", 1, "keys" },
|
{ "addmultisigaddress", 1, "keys" },
|
||||||
{ "createmultisig", 0, "nrequired" },
|
{ "createmultisig", 0, "nrequired" },
|
||||||
|
|
|
@ -66,7 +66,7 @@ bool CFeeBumper::preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable)
|
CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable, FeeEstimateMode fee_mode)
|
||||||
:
|
:
|
||||||
txid(std::move(txidIn)),
|
txid(std::move(txidIn)),
|
||||||
nOldFee(0),
|
nOldFee(0),
|
||||||
|
@ -165,7 +165,7 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConf
|
||||||
nNewFee = totalFee;
|
nNewFee = totalFee;
|
||||||
nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
|
nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
|
||||||
} else {
|
} else {
|
||||||
bool conservative_estimate = CalculateEstimateType(FeeEstimateMode::UNSET, newTxReplaceable);
|
bool conservative_estimate = CalculateEstimateType(fee_mode, newTxReplaceable);
|
||||||
nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, nullptr /* FeeCalculation */, ignoreGlobalPayTxFee, conservative_estimate);
|
nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, nullptr /* FeeCalculation */, ignoreGlobalPayTxFee, conservative_estimate);
|
||||||
nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
|
nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
class CWallet;
|
class CWallet;
|
||||||
class CWalletTx;
|
class CWalletTx;
|
||||||
class uint256;
|
class uint256;
|
||||||
|
enum class FeeEstimateMode;
|
||||||
|
|
||||||
enum class BumpFeeResult
|
enum class BumpFeeResult
|
||||||
{
|
{
|
||||||
|
@ -24,7 +25,7 @@ enum class BumpFeeResult
|
||||||
class CFeeBumper
|
class CFeeBumper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CFeeBumper(const CWallet *pWalletIn, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable);
|
CFeeBumper(const CWallet *pWalletIn, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable, FeeEstimateMode fee_mode);
|
||||||
BumpFeeResult getResult() const { return currentResult; }
|
BumpFeeResult getResult() const { return currentResult; }
|
||||||
const std::vector<std::string>& getErrors() const { return vErrors; }
|
const std::vector<std::string>& getErrors() const { return vErrors; }
|
||||||
CAmount getOldFee() const { return nOldFee; }
|
CAmount getOldFee() const { return nOldFee; }
|
||||||
|
|
|
@ -356,7 +356,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
|
static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew, CCoinControl *coin_control = nullptr)
|
||||||
{
|
{
|
||||||
CAmount curBalance = pwallet->GetBalance();
|
CAmount curBalance = pwallet->GetBalance();
|
||||||
|
|
||||||
|
@ -382,7 +382,7 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA
|
||||||
int nChangePosRet = -1;
|
int nChangePosRet = -1;
|
||||||
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
|
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
|
||||||
vecSend.push_back(recipient);
|
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)
|
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
|
||||||
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
|
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, strError);
|
throw JSONRPCError(RPC_WALLET_ERROR, strError);
|
||||||
|
@ -401,9 +401,9 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
|
||||||
return NullUniValue;
|
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(
|
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"
|
"\nSend an amount to a given address.\n"
|
||||||
+ HelpRequiringPassphrase(pwallet) +
|
+ HelpRequiringPassphrase(pwallet) +
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
|
@ -416,6 +416,12 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
|
||||||
" transaction, just kept in your wallet.\n"
|
" transaction, just kept in your wallet.\n"
|
||||||
"5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\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"
|
" 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"
|
"\nResult:\n"
|
||||||
"\"txid\" (string) The transaction id.\n"
|
"\"txid\" (string) The transaction id.\n"
|
||||||
"\nExamples:\n"
|
"\nExamples:\n"
|
||||||
|
@ -444,12 +450,29 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
|
||||||
wtx.mapValue["to"] = request.params[3].get_str();
|
wtx.mapValue["to"] = request.params[3].get_str();
|
||||||
|
|
||||||
bool fSubtractFeeFromAmount = false;
|
bool fSubtractFeeFromAmount = false;
|
||||||
if (request.params.size() > 4)
|
if (request.params.size() > 4 && !request.params[4].isNull()) {
|
||||||
fSubtractFeeFromAmount = request.params[4].get_bool();
|
fSubtractFeeFromAmount = request.params[4].get_bool();
|
||||||
|
}
|
||||||
|
|
||||||
|
CCoinControl coin_control;
|
||||||
|
if (request.params.size() > 5 && !request.params[5].isNull()) {
|
||||||
|
coin_control.signalRbf = request.params[5].get_bool();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.params.size() > 6 && !request.params[6].isNull()) {
|
||||||
|
coin_control.nConfirmTarget = request.params[6].get_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.params.size() > 7 && !request.params[7].isNull()) {
|
||||||
|
if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
EnsureWalletIsUnlocked(pwallet);
|
EnsureWalletIsUnlocked(pwallet);
|
||||||
|
|
||||||
SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
|
SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, &coin_control);
|
||||||
|
|
||||||
return wtx.GetHash().GetHex();
|
return wtx.GetHash().GetHex();
|
||||||
}
|
}
|
||||||
|
@ -888,9 +911,9 @@ UniValue sendmany(const JSONRPCRequest& request)
|
||||||
return NullUniValue;
|
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(
|
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."
|
"\nSend multiple times. Amounts are double-precision floating point numbers."
|
||||||
+ HelpRequiringPassphrase(pwallet) + "\n"
|
+ HelpRequiringPassphrase(pwallet) + "\n"
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
|
@ -910,7 +933,13 @@ UniValue sendmany(const JSONRPCRequest& request)
|
||||||
" \"address\" (string) Subtract fee from this address\n"
|
" \"address\" (string) Subtract fee from this address\n"
|
||||||
" ,...\n"
|
" ,...\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"
|
"\"txid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
|
||||||
" the number of addresses.\n"
|
" the number of addresses.\n"
|
||||||
"\nExamples:\n"
|
"\nExamples:\n"
|
||||||
|
@ -942,9 +971,24 @@ UniValue sendmany(const JSONRPCRequest& request)
|
||||||
wtx.mapValue["comment"] = request.params[3].get_str();
|
wtx.mapValue["comment"] = request.params[3].get_str();
|
||||||
|
|
||||||
UniValue subtractFeeFromAmount(UniValue::VARR);
|
UniValue subtractFeeFromAmount(UniValue::VARR);
|
||||||
if (request.params.size() > 4)
|
if (request.params.size() > 4 && !request.params[4].isNull())
|
||||||
subtractFeeFromAmount = request.params[4].get_array();
|
subtractFeeFromAmount = request.params[4].get_array();
|
||||||
|
|
||||||
|
CCoinControl coin_control;
|
||||||
|
if (request.params.size() > 5 && !request.params[5].isNull()) {
|
||||||
|
coin_control.signalRbf = request.params[5].get_bool();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.params.size() > 6 && !request.params[6].isNull()) {
|
||||||
|
coin_control.nConfirmTarget = request.params[6].get_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.params.size() > 7 && !request.params[7].isNull()) {
|
||||||
|
if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::set<CBitcoinAddress> setAddress;
|
std::set<CBitcoinAddress> setAddress;
|
||||||
std::vector<CRecipient> vecSend;
|
std::vector<CRecipient> vecSend;
|
||||||
|
|
||||||
|
@ -989,7 +1033,7 @@ UniValue sendmany(const JSONRPCRequest& request)
|
||||||
CAmount nFeeRequired = 0;
|
CAmount nFeeRequired = 0;
|
||||||
int nChangePosRet = -1;
|
int nChangePosRet = -1;
|
||||||
std::string strFailReason;
|
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)
|
if (!fCreated)
|
||||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
|
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
|
@ -2658,6 +2702,11 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
|
||||||
" [vout_index,...]\n"
|
" [vout_index,...]\n"
|
||||||
" \"replaceable\" (boolean, optional) Marks this transaction as BIP125 replaceable.\n"
|
" \"replaceable\" (boolean, optional) Marks this transaction as BIP125 replaceable.\n"
|
||||||
" Allows this transaction to be replaced by a transaction with higher fees\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"
|
" }\n"
|
||||||
" for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n"
|
" for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n"
|
||||||
"\nResult:\n"
|
"\nResult:\n"
|
||||||
|
@ -2710,6 +2759,8 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
|
||||||
{"feeRate", UniValueType()}, // will be checked below
|
{"feeRate", UniValueType()}, // will be checked below
|
||||||
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
|
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
|
||||||
{"replaceable", UniValueType(UniValue::VBOOL)},
|
{"replaceable", UniValueType(UniValue::VBOOL)},
|
||||||
|
{"conf_target", UniValueType(UniValue::VNUM)},
|
||||||
|
{"estimate_mode", UniValueType(UniValue::VSTR)},
|
||||||
},
|
},
|
||||||
true, true);
|
true, true);
|
||||||
|
|
||||||
|
@ -2746,6 +2797,14 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
|
||||||
if (options.exists("replaceable")) {
|
if (options.exists("replaceable")) {
|
||||||
coinControl.signalRbf = options["replaceable"].get_bool();
|
coinControl.signalRbf = options["replaceable"].get_bool();
|
||||||
}
|
}
|
||||||
|
if (options.exists("conf_target")) {
|
||||||
|
coinControl.nConfirmTarget = options["conf_target"].get_int();
|
||||||
|
}
|
||||||
|
if (options.exists("estimate_mode")) {
|
||||||
|
if (!FeeModeFromString(options["estimate_mode"].get_str(), coinControl.m_fee_mode)) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2823,6 +2882,10 @@ UniValue bumpfee(const JSONRPCRequest& request)
|
||||||
" so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
|
" 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"
|
" still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
|
||||||
" are replaceable).\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"
|
" }\n"
|
||||||
"\nResult:\n"
|
"\nResult:\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
@ -2845,6 +2908,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
|
||||||
int newConfirmTarget = nTxConfirmTarget;
|
int newConfirmTarget = nTxConfirmTarget;
|
||||||
CAmount totalFee = 0;
|
CAmount totalFee = 0;
|
||||||
bool replaceable = true;
|
bool replaceable = true;
|
||||||
|
FeeEstimateMode fee_mode = FeeEstimateMode::UNSET;
|
||||||
if (request.params.size() > 1) {
|
if (request.params.size() > 1) {
|
||||||
UniValue options = request.params[1];
|
UniValue options = request.params[1];
|
||||||
RPCTypeCheckObj(options,
|
RPCTypeCheckObj(options,
|
||||||
|
@ -2852,6 +2916,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
|
||||||
{"confTarget", UniValueType(UniValue::VNUM)},
|
{"confTarget", UniValueType(UniValue::VNUM)},
|
||||||
{"totalFee", UniValueType(UniValue::VNUM)},
|
{"totalFee", UniValueType(UniValue::VNUM)},
|
||||||
{"replaceable", UniValueType(UniValue::VBOOL)},
|
{"replaceable", UniValueType(UniValue::VBOOL)},
|
||||||
|
{"estimate_mode", UniValueType(UniValue::VSTR)},
|
||||||
},
|
},
|
||||||
true, true);
|
true, true);
|
||||||
|
|
||||||
|
@ -2876,12 +2941,17 @@ UniValue bumpfee(const JSONRPCRequest& request)
|
||||||
if (options.exists("replaceable")) {
|
if (options.exists("replaceable")) {
|
||||||
replaceable = options["replaceable"].get_bool();
|
replaceable = options["replaceable"].get_bool();
|
||||||
}
|
}
|
||||||
|
if (options.exists("estimate_mode")) {
|
||||||
|
if (!FeeModeFromString(options["estimate_mode"].get_str(), fee_mode)) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCK2(cs_main, pwallet->cs_wallet);
|
LOCK2(cs_main, pwallet->cs_wallet);
|
||||||
EnsureWalletIsUnlocked(pwallet);
|
EnsureWalletIsUnlocked(pwallet);
|
||||||
|
|
||||||
CFeeBumper feeBump(pwallet, hash, newConfirmTarget, ignoreGlobalPayTxFee, totalFee, replaceable);
|
CFeeBumper feeBump(pwallet, hash, newConfirmTarget, ignoreGlobalPayTxFee, totalFee, replaceable, fee_mode);
|
||||||
BumpFeeResult res = feeBump.getResult();
|
BumpFeeResult res = feeBump.getResult();
|
||||||
if (res != BumpFeeResult::OK)
|
if (res != BumpFeeResult::OK)
|
||||||
{
|
{
|
||||||
|
@ -3023,8 +3093,8 @@ static const CRPCCommand commands[] =
|
||||||
{ "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} },
|
{ "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} },
|
||||||
{ "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} },
|
{ "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} },
|
||||||
{ "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
|
{ "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
|
||||||
{ "wallet", "sendmany", &sendmany, false, {"fromaccount","amounts","minconf","comment","subtractfeefrom"} },
|
{ "wallet", "sendmany", &sendmany, false, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
|
||||||
{ "wallet", "sendtoaddress", &sendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount"} },
|
{ "wallet", "sendtoaddress", &sendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
|
||||||
{ "wallet", "setaccount", &setaccount, true, {"address","account"} },
|
{ "wallet", "setaccount", &setaccount, true, {"address","account"} },
|
||||||
{ "wallet", "settxfee", &settxfee, true, {"amount"} },
|
{ "wallet", "settxfee", &settxfee, true, {"amount"} },
|
||||||
{ "wallet", "signmessage", &signmessage, true, {"address","message"} },
|
{ "wallet", "signmessage", &signmessage, true, {"address","message"} },
|
||||||
|
|
Loading…
Reference in a new issue