diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e8c3ae888d0da..ef3f42394bf5b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -207,8 +207,36 @@ static std::string LabelFromValue(const UniValue& value) * verify only that fee_rate is greater than 0 * @throws a JSONRPCError if conf_target, estimate_mode, or fee_rate contain invalid values or are in conflict */ -static void SetFeeEstimateMode(const CWallet& wallet, CCoinControl& cc, const UniValue& conf_target, const UniValue& estimate_mode, const UniValue& fee_rate, bool override_min_fee) +static void SetFeeEstimateMode(const CWallet& wallet, CCoinControl& cc, UniValue conf_target, UniValue estimate_mode, UniValue fee_rate, bool override_min_fee) { + if (estimate_mode.isStr()) { + const auto estimate_mode_str = ToUpper(estimate_mode.get_str()); + if (estimate_mode_str == "EXPLICIT" || + estimate_mode_str == ToUpper(CURRENCY_UNIT + "/kB") || + estimate_mode_str == ToUpper(CURRENCY_ATOM + "/B")) { + if (!fee_rate.isNull()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and fee_rate. For explicit fees, please use fee_rate."); + } + if (conf_target.isNull()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Selected estimate_mode is deprecated and requires a fee rate in conf_target. Better to upgrade to fee_rate."); + } + if (estimate_mode_str.at(estimate_mode_str.size() - 2) == '/') { + // "sat/B": pretty straightforward + fee_rate = conf_target; + } else { + // "BTC/kB" or "EXPLICIT": Need to convert to sat/vB + CAmount fee_rate_amount = AmountFromValue(conf_target); + // NOTE: AmountFromValue never allows negative + // AmountFromValue gives us satoshis per kvB, so to get sat/vB we just divide out the kilo + const int64_t quotient = fee_rate_amount / 1000; + const int64_t remainder = fee_rate_amount % 1000; + fee_rate.setNumStr(strprintf("%d.%03d", quotient, remainder)); + } + estimate_mode.setNull(); + conf_target.setNull(); + override_min_fee = false; + } + } if (!fee_rate.isNull()) { if (!conf_target.isNull()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate."); diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 3cbddaf6dacd1..ad71d09350807 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -273,7 +273,7 @@ def run_test(self): for target, mode in product([-1, 0, 1009], ["economical", "conservative"]): assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008", # max value of 1008 per src/policy/fees.h self.nodes[2].sendmany, amounts={address: 1}, conf_target=target, estimate_mode=mode) - for target, mode in product([-1, 0], ["btc/kb", "sat/b"]): + for target, mode in product([-1, 0], ["btc/kvb", "sat/vb"]): assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"', self.nodes[2].sendmany, amounts={address: 1}, conf_target=target, estimate_mode=mode) @@ -456,7 +456,7 @@ def run_test(self): for target, mode in product([-1, 0, 1009], ["economical", "conservative"]): assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008", # max value of 1008 per src/policy/fees.h self.nodes[2].sendtoaddress, address=address, amount=1, conf_target=target, estimate_mode=mode) - for target, mode in product([-1, 0], ["btc/kb", "sat/b"]): + for target, mode in product([-1, 0], ["btc/kvb", "sat/vb"]): assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"', self.nodes[2].sendtoaddress, address=address, amount=1, conf_target=target, estimate_mode=mode) diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index c8c1f2e37493a..58c185927619c 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -135,7 +135,7 @@ def test_invalid_parameters(self, rbf_node, peer_node, dest_address): for k, v in {"number": 42, "object": {"foo": "bar"}}.items(): assert_raises_rpc_error(-3, "Expected type string for estimate_mode, got {}".format(k), rbf_node.bumpfee, rbfid, {"estimate_mode": v}) - for mode in ["foo", Decimal("3.1415"), "sat/B", "BTC/kB"]: + for mode in ["foo", Decimal("3.1415"), "sat/vB", "BTC/kvB"]: assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"', rbf_node.bumpfee, rbfid, {"estimate_mode": mode}) diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py index 9835c5a2af47d..38abba9e9e060 100755 --- a/test/functional/wallet_send.py +++ b/test/functional/wallet_send.py @@ -289,7 +289,7 @@ def run_test(self): self.test_send(from_wallet=w0, to_wallet=w1, amount=1, conf_target=target, estimate_mode=mode, expect_error=(-8, "Invalid conf_target, must be between 1 and 1008")) # max value of 1008 per src/policy/fees.h msg = 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"' - for target, mode in product([-1, 0], ["btc/kb", "sat/b"]): + for target, mode in product([-1, 0], ["btc/kvb", "sat/vb"]): self.test_send(from_wallet=w0, to_wallet=w1, amount=1, conf_target=target, estimate_mode=mode, expect_error=(-8, msg)) for mode in ["", "foo", Decimal("3.141592")]: self.test_send(from_wallet=w0, to_wallet=w1, amount=1, conf_target=0.1, estimate_mode=mode, expect_error=(-8, msg))