aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarcoFalke <falke.marco@gmail.com>2021-05-10 09:02:42 +0200
committerMarcoFalke <falke.marco@gmail.com>2021-05-10 09:02:48 +0200
commitadf78434100204f2eb799bbb96a28b734fb084f0 (patch)
tree854453b481e39c31a9426667e67c85cbd059003c /src
parent2a22d903f3da54b31d21e74c3e084f5113f13789 (diff)
parent847288df07b45ca535c849e518b22818ab492896 (diff)
Merge bitcoin/bitcoin#21786: wallet: ensure sat/vB feerates are in range (mantissa of 3)
847288df07b45ca535c849e518b22818ab492896 test: fee rate values that cannot be represented as sat/vB (Jon Atack) 06a90fa0381c790f7bde2ab9bf47d2b22acef4a5 rpc: for sat/vB fee rates, limit ParseFixedPoint decimals to 3 (Jon Atack) 0742c7840f03505597fd2de87db97f12597ef667 rpc: enable passing decimals to AmountFromValue, add doxygen (Jon Atack) 8ce3ef57a3e9ad13c0aaa4648e8584241d53592d test: ParseFixedPoint with 3 decimals for sat/vB fee rates (Jon Atack) b5033275979a2a495b02b25f70cadbdcc8b6eb6a test: type error and out of range fee rates where missing (Jon Atack) c5fd4344f7fcc257062a610c8ff26ffcc9b53953 test: explicit fee rates with invalid amounts (Jon Atack) ea6f76b66ecc52360719053489e0ec9f9a673eab test: improve zero-value explicit fee rate coverage (Jon Atack) Pull request description: - Improve/close gaps in existing test coverage before making the change - Enable passing `decimals` to `ParseFixedPoint()` when calling `AmountFromValue()` - Limit explicit fee rates in sat/vB passed in by users to 3 decimals, and raise otherwise - Add regression test coverage Closes #20534. ACKs for top commit: MarcoFalke: review ACK 847288df07b45ca535c849e518b22818ab492896 🔷 Tree-SHA512: c539d07ae9b21c0d6c8ea460beb9c8dad5559445518aace560abc3c05c588907bae189b6fd7602b3b397de4a42356136c3ec6f960d3dcf2d5d16377aef4ab5a2
Diffstat (limited to 'src')
-rw-r--r--src/rpc/util.cpp4
-rw-r--r--src/rpc/util.h9
-rw-r--r--src/test/util_tests.cpp9
-rw-r--r--src/wallet/rpcwallet.cpp3
4 files changed, 21 insertions, 4 deletions
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 069669bb3b..7cf25e0c82 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -74,12 +74,12 @@ void RPCTypeCheckObj(const UniValue& o,
}
}
-CAmount AmountFromValue(const UniValue& value)
+CAmount AmountFromValue(const UniValue& value, int decimals)
{
if (!value.isNum() && !value.isStr())
throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
CAmount amount;
- if (!ParseFixedPoint(value.getValStr(), 8, &amount))
+ if (!ParseFixedPoint(value.getValStr(), decimals, &amount))
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
if (!MoneyRange(amount))
throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
diff --git a/src/rpc/util.h b/src/rpc/util.h
index 06381d504c..0120dbcc98 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -77,7 +77,14 @@ extern uint256 ParseHashO(const UniValue& o, std::string strKey);
extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
-extern CAmount AmountFromValue(const UniValue& value);
+/**
+ * Validate and return a CAmount from a UniValue number or string.
+ *
+ * @param[in] value UniValue number or string to parse.
+ * @param[in] decimals Number of significant digits (default: 8).
+ * @returns a CAmount if the various checks pass.
+ */
+extern CAmount AmountFromValue(const UniValue& value, int decimals = 8);
using RPCArgList = std::vector<std::pair<std::string, UniValue>>;
extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 04b908829b..534d28e5de 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1759,6 +1759,15 @@ BOOST_AUTO_TEST_CASE(test_ParseFixedPoint)
BOOST_CHECK(!ParseFixedPoint("1.1e", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("1.1e-", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("1.", 8, &amount));
+
+ // Test with 3 decimal places for fee rates in sat/vB.
+ BOOST_CHECK(ParseFixedPoint("0.001", 3, &amount));
+ BOOST_CHECK_EQUAL(amount, CAmount{1});
+ BOOST_CHECK(!ParseFixedPoint("0.0009", 3, &amount));
+ BOOST_CHECK(!ParseFixedPoint("31.00100001", 3, &amount));
+ BOOST_CHECK(!ParseFixedPoint("31.0011", 3, &amount));
+ BOOST_CHECK(!ParseFixedPoint("31.99999999", 3, &amount));
+ BOOST_CHECK(!ParseFixedPoint("31.999999999999999999999", 3, &amount));
}
static void TestOtherThread(fs::path dirname, std::string lockname, bool *result)
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index ae337055e2..7777543ece 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -216,7 +216,8 @@ static void SetFeeEstimateMode(const CWallet& wallet, CCoinControl& cc, const Un
if (!estimate_mode.isNull() && estimate_mode.get_str() != "unset") {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and fee_rate");
}
- cc.m_feerate = CFeeRate(AmountFromValue(fee_rate), COIN);
+ // Fee rates in sat/vB cannot represent more than 3 significant digits.
+ cc.m_feerate = CFeeRate{AmountFromValue(fee_rate, /* decimals */ 3)};
if (override_min_fee) cc.fOverrideFeeRate = true;
// Default RBF to true for explicit fee_rate, if unset.
if (!cc.m_signal_bip125_rbf) cc.m_signal_bip125_rbf = true;