mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-13 11:25:02 -05:00
Merge bitcoin/bitcoin#22220: util: make ParseMoney return a std::optional<CAmount>
f7752adba5
util: check MoneyRange() inside ParseMoney() (fanquake)5ef2738089
util: make ParseMoney return a std::optional<CAmount> (fanquake) Pull request description: Related discussion in #22193. ACKs for top commit: MarcoFalke: review ACKf7752adba5
📄 Tree-SHA512: 88453f9e28f668deff4290d4bc0b2468cbd54699a3be1bfeac63a512276d309354672e7ea7deefa01466c3d9d826e837cc1ea244d4d74b4fa9c11c56f074e098
This commit is contained in:
commit
61a843e43b
9 changed files with 123 additions and 140 deletions
|
@ -188,10 +188,11 @@ static void RegisterLoad(const std::string& strInput)
|
||||||
|
|
||||||
static CAmount ExtractAndValidateValue(const std::string& strValue)
|
static CAmount ExtractAndValidateValue(const std::string& strValue)
|
||||||
{
|
{
|
||||||
CAmount value;
|
if (std::optional<CAmount> parsed = ParseMoney(strValue)) {
|
||||||
if (!ParseMoney(strValue, value))
|
return parsed.value();
|
||||||
|
} else {
|
||||||
throw std::runtime_error("invalid TX output value");
|
throw std::runtime_error("invalid TX output value");
|
||||||
return value;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
|
static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
|
||||||
|
|
26
src/init.cpp
26
src/init.cpp
|
@ -921,10 +921,11 @@ bool AppInitParameterInteraction(const ArgsManager& args)
|
||||||
// incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
|
// incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
|
||||||
// and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
|
// and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
|
||||||
if (args.IsArgSet("-incrementalrelayfee")) {
|
if (args.IsArgSet("-incrementalrelayfee")) {
|
||||||
CAmount n = 0;
|
if (std::optional<CAmount> inc_relay_fee = ParseMoney(args.GetArg("-incrementalrelayfee", ""))) {
|
||||||
if (!ParseMoney(args.GetArg("-incrementalrelayfee", ""), n))
|
::incrementalRelayFee = CFeeRate{inc_relay_fee.value()};
|
||||||
|
} else {
|
||||||
return InitError(AmountErrMsg("incrementalrelayfee", args.GetArg("-incrementalrelayfee", "")));
|
return InitError(AmountErrMsg("incrementalrelayfee", args.GetArg("-incrementalrelayfee", "")));
|
||||||
incrementalRelayFee = CFeeRate(n);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// block pruning; get the amount of disk space (in MiB) to allot for block & undo files
|
// block pruning; get the amount of disk space (in MiB) to allot for block & undo files
|
||||||
|
@ -956,12 +957,12 @@ bool AppInitParameterInteraction(const ArgsManager& args)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.IsArgSet("-minrelaytxfee")) {
|
if (args.IsArgSet("-minrelaytxfee")) {
|
||||||
CAmount n = 0;
|
if (std::optional<CAmount> min_relay_fee = ParseMoney(args.GetArg("-minrelaytxfee", ""))) {
|
||||||
if (!ParseMoney(args.GetArg("-minrelaytxfee", ""), n)) {
|
// High fee check is done afterward in CWallet::Create()
|
||||||
|
::minRelayTxFee = CFeeRate{min_relay_fee.value()};
|
||||||
|
} else {
|
||||||
return InitError(AmountErrMsg("minrelaytxfee", args.GetArg("-minrelaytxfee", "")));
|
return InitError(AmountErrMsg("minrelaytxfee", args.GetArg("-minrelaytxfee", "")));
|
||||||
}
|
}
|
||||||
// High fee check is done afterward in CWallet::Create()
|
|
||||||
::minRelayTxFee = CFeeRate(n);
|
|
||||||
} else if (incrementalRelayFee > ::minRelayTxFee) {
|
} else if (incrementalRelayFee > ::minRelayTxFee) {
|
||||||
// Allow only setting incrementalRelayFee to control both
|
// Allow only setting incrementalRelayFee to control both
|
||||||
::minRelayTxFee = incrementalRelayFee;
|
::minRelayTxFee = incrementalRelayFee;
|
||||||
|
@ -971,18 +972,19 @@ bool AppInitParameterInteraction(const ArgsManager& args)
|
||||||
// Sanity check argument for min fee for including tx in block
|
// Sanity check argument for min fee for including tx in block
|
||||||
// TODO: Harmonize which arguments need sanity checking and where that happens
|
// TODO: Harmonize which arguments need sanity checking and where that happens
|
||||||
if (args.IsArgSet("-blockmintxfee")) {
|
if (args.IsArgSet("-blockmintxfee")) {
|
||||||
CAmount n = 0;
|
if (!ParseMoney(args.GetArg("-blockmintxfee", ""))) {
|
||||||
if (!ParseMoney(args.GetArg("-blockmintxfee", ""), n))
|
|
||||||
return InitError(AmountErrMsg("blockmintxfee", args.GetArg("-blockmintxfee", "")));
|
return InitError(AmountErrMsg("blockmintxfee", args.GetArg("-blockmintxfee", "")));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Feerate used to define dust. Shouldn't be changed lightly as old
|
// Feerate used to define dust. Shouldn't be changed lightly as old
|
||||||
// implementations may inadvertently create non-standard transactions
|
// implementations may inadvertently create non-standard transactions
|
||||||
if (args.IsArgSet("-dustrelayfee")) {
|
if (args.IsArgSet("-dustrelayfee")) {
|
||||||
CAmount n = 0;
|
if (std::optional<CAmount> parsed = ParseMoney(args.GetArg("-dustrelayfee", ""))) {
|
||||||
if (!ParseMoney(args.GetArg("-dustrelayfee", ""), n))
|
dustRelayFee = CFeeRate{parsed.value()};
|
||||||
|
} else {
|
||||||
return InitError(AmountErrMsg("dustrelayfee", args.GetArg("-dustrelayfee", "")));
|
return InitError(AmountErrMsg("dustrelayfee", args.GetArg("-dustrelayfee", "")));
|
||||||
dustRelayFee = CFeeRate(n);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fRequireStandard = !args.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
|
fRequireStandard = !args.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
|
||||||
|
|
|
@ -73,11 +73,11 @@ static BlockAssembler::Options DefaultOptions()
|
||||||
// If -blockmaxweight is not given, limit to DEFAULT_BLOCK_MAX_WEIGHT
|
// If -blockmaxweight is not given, limit to DEFAULT_BLOCK_MAX_WEIGHT
|
||||||
BlockAssembler::Options options;
|
BlockAssembler::Options options;
|
||||||
options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
|
options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
|
||||||
CAmount n = 0;
|
if (gArgs.IsArgSet("-blockmintxfee")) {
|
||||||
if (gArgs.IsArgSet("-blockmintxfee") && ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) {
|
std::optional<CAmount> parsed = ParseMoney(gArgs.GetArg("-blockmintxfee", ""));
|
||||||
options.blockMinFeeRate = CFeeRate(n);
|
options.blockMinFeeRate = CFeeRate{parsed.value_or(DEFAULT_BLOCK_MIN_TX_FEE)};
|
||||||
} else {
|
} else {
|
||||||
options.blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
|
options.blockMinFeeRate = CFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,9 +83,8 @@ FUZZ_TARGET_INIT(integer, initialize_integer)
|
||||||
(void)FormatISO8601Date(i64);
|
(void)FormatISO8601Date(i64);
|
||||||
(void)FormatISO8601DateTime(i64);
|
(void)FormatISO8601DateTime(i64);
|
||||||
{
|
{
|
||||||
int64_t parsed_money;
|
if (std::optional<CAmount> parsed = ParseMoney(FormatMoney(i64))) {
|
||||||
if (ParseMoney(FormatMoney(i64), parsed_money)) {
|
assert(parsed.value() == i64);
|
||||||
assert(parsed_money == i64);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(void)GetSizeOfCompactSize(u64);
|
(void)GetSizeOfCompactSize(u64);
|
||||||
|
@ -126,9 +125,8 @@ FUZZ_TARGET_INIT(integer, initialize_integer)
|
||||||
(void)ToLower(ch);
|
(void)ToLower(ch);
|
||||||
(void)ToUpper(ch);
|
(void)ToUpper(ch);
|
||||||
{
|
{
|
||||||
int64_t parsed_money;
|
if (std::optional<CAmount> parsed = ParseMoney(ValueFromAmount(i64).getValStr())) {
|
||||||
if (ParseMoney(ValueFromAmount(i64).getValStr(), parsed_money)) {
|
assert(parsed.value() == i64);
|
||||||
assert(parsed_money == i64);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i32 >= 0 && i32 <= 16) {
|
if (i32 >= 0 && i32 <= 16) {
|
||||||
|
|
|
@ -12,8 +12,7 @@ FUZZ_TARGET(parse_numbers)
|
||||||
{
|
{
|
||||||
const std::string random_string(buffer.begin(), buffer.end());
|
const std::string random_string(buffer.begin(), buffer.end());
|
||||||
|
|
||||||
CAmount amount;
|
(void)ParseMoney(random_string);
|
||||||
(void)ParseMoney(random_string, amount);
|
|
||||||
|
|
||||||
double d;
|
double d;
|
||||||
(void)ParseDouble(random_string, &d);
|
(void)ParseDouble(random_string, &d);
|
||||||
|
|
|
@ -1222,86 +1222,59 @@ BOOST_AUTO_TEST_CASE(util_FormatMoney)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(util_ParseMoney)
|
BOOST_AUTO_TEST_CASE(util_ParseMoney)
|
||||||
{
|
{
|
||||||
CAmount ret = 0;
|
BOOST_CHECK_EQUAL(ParseMoney("0.0").value(), 0);
|
||||||
BOOST_CHECK(ParseMoney("0.0", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, 0);
|
|
||||||
|
|
||||||
BOOST_CHECK(ParseMoney("12345.6789", ret));
|
BOOST_CHECK_EQUAL(ParseMoney("12345.6789").value(), (COIN/10000)*123456789);
|
||||||
BOOST_CHECK_EQUAL(ret, (COIN/10000)*123456789);
|
|
||||||
|
|
||||||
BOOST_CHECK(ParseMoney("100000000.00", ret));
|
BOOST_CHECK_EQUAL(ParseMoney("10000000.00").value(), COIN*10000000);
|
||||||
BOOST_CHECK_EQUAL(ret, COIN*100000000);
|
BOOST_CHECK_EQUAL(ParseMoney("1000000.00").value(), COIN*1000000);
|
||||||
BOOST_CHECK(ParseMoney("10000000.00", ret));
|
BOOST_CHECK_EQUAL(ParseMoney("100000.00").value(), COIN*100000);
|
||||||
BOOST_CHECK_EQUAL(ret, COIN*10000000);
|
BOOST_CHECK_EQUAL(ParseMoney("10000.00").value(), COIN*10000);
|
||||||
BOOST_CHECK(ParseMoney("1000000.00", ret));
|
BOOST_CHECK_EQUAL(ParseMoney("1000.00").value(), COIN*1000);
|
||||||
BOOST_CHECK_EQUAL(ret, COIN*1000000);
|
BOOST_CHECK_EQUAL(ParseMoney("100.00").value(), COIN*100);
|
||||||
BOOST_CHECK(ParseMoney("100000.00", ret));
|
BOOST_CHECK_EQUAL(ParseMoney("10.00").value(), COIN*10);
|
||||||
BOOST_CHECK_EQUAL(ret, COIN*100000);
|
BOOST_CHECK_EQUAL(ParseMoney("1.00").value(), COIN);
|
||||||
BOOST_CHECK(ParseMoney("10000.00", ret));
|
BOOST_CHECK_EQUAL(ParseMoney("1").value(), COIN);
|
||||||
BOOST_CHECK_EQUAL(ret, COIN*10000);
|
BOOST_CHECK_EQUAL(ParseMoney(" 1").value(), COIN);
|
||||||
BOOST_CHECK(ParseMoney("1000.00", ret));
|
BOOST_CHECK_EQUAL(ParseMoney("1 ").value(), COIN);
|
||||||
BOOST_CHECK_EQUAL(ret, COIN*1000);
|
BOOST_CHECK_EQUAL(ParseMoney(" 1 ").value(), COIN);
|
||||||
BOOST_CHECK(ParseMoney("100.00", ret));
|
BOOST_CHECK_EQUAL(ParseMoney("0.1").value(), COIN/10);
|
||||||
BOOST_CHECK_EQUAL(ret, COIN*100);
|
BOOST_CHECK_EQUAL(ParseMoney("0.01").value(), COIN/100);
|
||||||
BOOST_CHECK(ParseMoney("10.00", ret));
|
BOOST_CHECK_EQUAL(ParseMoney("0.001").value(), COIN/1000);
|
||||||
BOOST_CHECK_EQUAL(ret, COIN*10);
|
BOOST_CHECK_EQUAL(ParseMoney("0.0001").value(), COIN/10000);
|
||||||
BOOST_CHECK(ParseMoney("1.00", ret));
|
BOOST_CHECK_EQUAL(ParseMoney("0.00001").value(), COIN/100000);
|
||||||
BOOST_CHECK_EQUAL(ret, COIN);
|
BOOST_CHECK_EQUAL(ParseMoney("0.000001").value(), COIN/1000000);
|
||||||
BOOST_CHECK(ParseMoney("1", ret));
|
BOOST_CHECK_EQUAL(ParseMoney("0.0000001").value(), COIN/10000000);
|
||||||
BOOST_CHECK_EQUAL(ret, COIN);
|
BOOST_CHECK_EQUAL(ParseMoney("0.00000001").value(), COIN/100000000);
|
||||||
BOOST_CHECK(ParseMoney(" 1", ret));
|
BOOST_CHECK_EQUAL(ParseMoney(" 0.00000001 ").value(), COIN/100000000);
|
||||||
BOOST_CHECK_EQUAL(ret, COIN);
|
BOOST_CHECK_EQUAL(ParseMoney("0.00000001 ").value(), COIN/100000000);
|
||||||
BOOST_CHECK(ParseMoney("1 ", ret));
|
BOOST_CHECK_EQUAL(ParseMoney(" 0.00000001").value(), COIN/100000000);
|
||||||
BOOST_CHECK_EQUAL(ret, COIN);
|
|
||||||
BOOST_CHECK(ParseMoney(" 1 ", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, COIN);
|
|
||||||
BOOST_CHECK(ParseMoney("0.1", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, COIN/10);
|
|
||||||
BOOST_CHECK(ParseMoney("0.01", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, COIN/100);
|
|
||||||
BOOST_CHECK(ParseMoney("0.001", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, COIN/1000);
|
|
||||||
BOOST_CHECK(ParseMoney("0.0001", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, COIN/10000);
|
|
||||||
BOOST_CHECK(ParseMoney("0.00001", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, COIN/100000);
|
|
||||||
BOOST_CHECK(ParseMoney("0.000001", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, COIN/1000000);
|
|
||||||
BOOST_CHECK(ParseMoney("0.0000001", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, COIN/10000000);
|
|
||||||
BOOST_CHECK(ParseMoney("0.00000001", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, COIN/100000000);
|
|
||||||
BOOST_CHECK(ParseMoney(" 0.00000001 ", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, COIN/100000000);
|
|
||||||
BOOST_CHECK(ParseMoney("0.00000001 ", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, COIN/100000000);
|
|
||||||
BOOST_CHECK(ParseMoney(" 0.00000001", ret));
|
|
||||||
BOOST_CHECK_EQUAL(ret, COIN/100000000);
|
|
||||||
|
|
||||||
// Parsing amount that can not be represented in ret should fail
|
// Parsing amount that can not be represented should fail
|
||||||
BOOST_CHECK(!ParseMoney("0.000000001", ret));
|
BOOST_CHECK(!ParseMoney("100000000.00"));
|
||||||
|
BOOST_CHECK(!ParseMoney("0.000000001"));
|
||||||
|
|
||||||
// Parsing empty string should fail
|
// Parsing empty string should fail
|
||||||
BOOST_CHECK(!ParseMoney("", ret));
|
BOOST_CHECK(!ParseMoney(""));
|
||||||
BOOST_CHECK(!ParseMoney(" ", ret));
|
BOOST_CHECK(!ParseMoney(" "));
|
||||||
BOOST_CHECK(!ParseMoney(" ", ret));
|
BOOST_CHECK(!ParseMoney(" "));
|
||||||
|
|
||||||
// Parsing two numbers should fail
|
// Parsing two numbers should fail
|
||||||
BOOST_CHECK(!ParseMoney("1 2", ret));
|
BOOST_CHECK(!ParseMoney("1 2"));
|
||||||
BOOST_CHECK(!ParseMoney(" 1 2 ", ret));
|
BOOST_CHECK(!ParseMoney(" 1 2 "));
|
||||||
BOOST_CHECK(!ParseMoney(" 1.2 3 ", ret));
|
BOOST_CHECK(!ParseMoney(" 1.2 3 "));
|
||||||
BOOST_CHECK(!ParseMoney(" 1 2.3 ", ret));
|
BOOST_CHECK(!ParseMoney(" 1 2.3 "));
|
||||||
|
|
||||||
// Attempted 63 bit overflow should fail
|
// Attempted 63 bit overflow should fail
|
||||||
BOOST_CHECK(!ParseMoney("92233720368.54775808", ret));
|
BOOST_CHECK(!ParseMoney("92233720368.54775808"));
|
||||||
|
|
||||||
// Parsing negative amounts must fail
|
// Parsing negative amounts must fail
|
||||||
BOOST_CHECK(!ParseMoney("-1", ret));
|
BOOST_CHECK(!ParseMoney("-1"));
|
||||||
|
|
||||||
// Parsing strings with embedded NUL characters should fail
|
// Parsing strings with embedded NUL characters should fail
|
||||||
BOOST_CHECK(!ParseMoney("\0-1"s, ret));
|
BOOST_CHECK(!ParseMoney("\0-1"s));
|
||||||
BOOST_CHECK(!ParseMoney(STRING_WITH_EMBEDDED_NULL_CHAR, ret));
|
BOOST_CHECK(!ParseMoney(STRING_WITH_EMBEDDED_NULL_CHAR));
|
||||||
BOOST_CHECK(!ParseMoney("1\0"s, ret));
|
BOOST_CHECK(!ParseMoney("1\0"s));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(util_IsHex)
|
BOOST_AUTO_TEST_CASE(util_IsHex)
|
||||||
|
|
|
@ -5,10 +5,13 @@
|
||||||
|
|
||||||
#include <util/moneystr.h>
|
#include <util/moneystr.h>
|
||||||
|
|
||||||
|
#include <amount.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
std::string FormatMoney(const CAmount n)
|
std::string FormatMoney(const CAmount n)
|
||||||
{
|
{
|
||||||
// Note: not using straight sprintf here because we do NOT want
|
// Note: not using straight sprintf here because we do NOT want
|
||||||
|
@ -35,14 +38,14 @@ std::string FormatMoney(const CAmount n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ParseMoney(const std::string& money_string, CAmount& nRet)
|
std::optional<CAmount> ParseMoney(const std::string& money_string)
|
||||||
{
|
{
|
||||||
if (!ValidAsCString(money_string)) {
|
if (!ValidAsCString(money_string)) {
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
const std::string str = TrimString(money_string);
|
const std::string str = TrimString(money_string);
|
||||||
if (str.empty()) {
|
if (str.empty()) {
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string strWhole;
|
std::string strWhole;
|
||||||
|
@ -62,21 +65,25 @@ bool ParseMoney(const std::string& money_string, CAmount& nRet)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (IsSpace(*p))
|
if (IsSpace(*p))
|
||||||
return false;
|
return std::nullopt;
|
||||||
if (!IsDigit(*p))
|
if (!IsDigit(*p))
|
||||||
return false;
|
return std::nullopt;
|
||||||
strWhole.insert(strWhole.end(), *p);
|
strWhole.insert(strWhole.end(), *p);
|
||||||
}
|
}
|
||||||
if (*p) {
|
if (*p) {
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
if (strWhole.size() > 10) // guard against 63 bit overflow
|
if (strWhole.size() > 10) // guard against 63 bit overflow
|
||||||
return false;
|
return std::nullopt;
|
||||||
if (nUnits < 0 || nUnits > COIN)
|
if (nUnits < 0 || nUnits > COIN)
|
||||||
return false;
|
return std::nullopt;
|
||||||
int64_t nWhole = atoi64(strWhole);
|
int64_t nWhole = atoi64(strWhole);
|
||||||
CAmount nValue = nWhole*COIN + nUnits;
|
|
||||||
|
|
||||||
nRet = nValue;
|
CAmount value = nWhole * COIN + nUnits;
|
||||||
return true;
|
|
||||||
|
if (!MoneyRange(value)) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <amount.h>
|
#include <amount.h>
|
||||||
#include <attributes.h>
|
#include <attributes.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
/* Do not use these functions to represent or parse monetary amounts to or from
|
/* Do not use these functions to represent or parse monetary amounts to or from
|
||||||
|
@ -19,6 +20,6 @@
|
||||||
*/
|
*/
|
||||||
std::string FormatMoney(const CAmount n);
|
std::string FormatMoney(const CAmount n);
|
||||||
/** Parse an amount denoted in full coins. E.g. "0.0034" supplied on the command line. **/
|
/** Parse an amount denoted in full coins. E.g. "0.0034" supplied on the command line. **/
|
||||||
[[nodiscard]] bool ParseMoney(const std::string& str, CAmount& nRet);
|
std::optional<CAmount> ParseMoney(const std::string& str);
|
||||||
|
|
||||||
#endif // BITCOIN_UTIL_MONEYSTR_H
|
#endif // BITCOIN_UTIL_MONEYSTR_H
|
||||||
|
|
|
@ -2609,72 +2609,73 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gArgs.IsArgSet("-mintxfee")) {
|
if (gArgs.IsArgSet("-mintxfee")) {
|
||||||
CAmount n = 0;
|
std::optional<CAmount> min_tx_fee = ParseMoney(gArgs.GetArg("-mintxfee", ""));
|
||||||
if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n) {
|
if (!min_tx_fee || min_tx_fee.value() == 0) {
|
||||||
error = AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", ""));
|
error = AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", ""));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
} else if (min_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
|
||||||
if (n > HIGH_TX_FEE_PER_KB) {
|
|
||||||
warnings.push_back(AmountHighWarn("-mintxfee") + Untranslated(" ") +
|
warnings.push_back(AmountHighWarn("-mintxfee") + Untranslated(" ") +
|
||||||
_("This is the minimum transaction fee you pay on every transaction."));
|
_("This is the minimum transaction fee you pay on every transaction."));
|
||||||
}
|
}
|
||||||
walletInstance->m_min_fee = CFeeRate(n);
|
|
||||||
|
walletInstance->m_min_fee = CFeeRate{min_tx_fee.value()};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gArgs.IsArgSet("-maxapsfee")) {
|
if (gArgs.IsArgSet("-maxapsfee")) {
|
||||||
const std::string max_aps_fee{gArgs.GetArg("-maxapsfee", "")};
|
const std::string max_aps_fee{gArgs.GetArg("-maxapsfee", "")};
|
||||||
CAmount n = 0;
|
|
||||||
if (max_aps_fee == "-1") {
|
if (max_aps_fee == "-1") {
|
||||||
n = -1;
|
walletInstance->m_max_aps_fee = -1;
|
||||||
} else if (!ParseMoney(max_aps_fee, n)) {
|
} else if (std::optional<CAmount> max_fee = ParseMoney(max_aps_fee)) {
|
||||||
error = AmountErrMsg("maxapsfee", max_aps_fee);
|
if (max_fee.value() > HIGH_APS_FEE) {
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (n > HIGH_APS_FEE) {
|
|
||||||
warnings.push_back(AmountHighWarn("-maxapsfee") + Untranslated(" ") +
|
warnings.push_back(AmountHighWarn("-maxapsfee") + Untranslated(" ") +
|
||||||
_("This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
|
_("This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
|
||||||
}
|
}
|
||||||
walletInstance->m_max_aps_fee = n;
|
walletInstance->m_max_aps_fee = max_fee.value();
|
||||||
|
} else {
|
||||||
|
error = AmountErrMsg("maxapsfee", max_aps_fee);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gArgs.IsArgSet("-fallbackfee")) {
|
if (gArgs.IsArgSet("-fallbackfee")) {
|
||||||
CAmount nFeePerK = 0;
|
std::optional<CAmount> fallback_fee = ParseMoney(gArgs.GetArg("-fallbackfee", ""));
|
||||||
if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK)) {
|
if (!fallback_fee) {
|
||||||
error = strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", ""));
|
error = strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", ""));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
} else if (fallback_fee.value() > HIGH_TX_FEE_PER_KB) {
|
||||||
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
|
|
||||||
warnings.push_back(AmountHighWarn("-fallbackfee") + Untranslated(" ") +
|
warnings.push_back(AmountHighWarn("-fallbackfee") + Untranslated(" ") +
|
||||||
_("This is the transaction fee you may pay when fee estimates are not available."));
|
_("This is the transaction fee you may pay when fee estimates are not available."));
|
||||||
}
|
}
|
||||||
walletInstance->m_fallback_fee = CFeeRate(nFeePerK);
|
walletInstance->m_fallback_fee = CFeeRate{fallback_fee.value()};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable fallback fee in case value was set to 0, enable if non-null value
|
// Disable fallback fee in case value was set to 0, enable if non-null value
|
||||||
walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.GetFeePerK() != 0;
|
walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.GetFeePerK() != 0;
|
||||||
|
|
||||||
if (gArgs.IsArgSet("-discardfee")) {
|
if (gArgs.IsArgSet("-discardfee")) {
|
||||||
CAmount nFeePerK = 0;
|
std::optional<CAmount> discard_fee = ParseMoney(gArgs.GetArg("-discardfee", ""));
|
||||||
if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK)) {
|
if (!discard_fee) {
|
||||||
error = strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", ""));
|
error = strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", ""));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
} else if (discard_fee.value() > HIGH_TX_FEE_PER_KB) {
|
||||||
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
|
|
||||||
warnings.push_back(AmountHighWarn("-discardfee") + Untranslated(" ") +
|
warnings.push_back(AmountHighWarn("-discardfee") + Untranslated(" ") +
|
||||||
_("This is the transaction fee you may discard if change is smaller than dust at this level"));
|
_("This is the transaction fee you may discard if change is smaller than dust at this level"));
|
||||||
}
|
}
|
||||||
walletInstance->m_discard_rate = CFeeRate(nFeePerK);
|
walletInstance->m_discard_rate = CFeeRate{discard_fee.value()};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gArgs.IsArgSet("-paytxfee")) {
|
if (gArgs.IsArgSet("-paytxfee")) {
|
||||||
CAmount nFeePerK = 0;
|
std::optional<CAmount> pay_tx_fee = ParseMoney(gArgs.GetArg("-paytxfee", ""));
|
||||||
if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK)) {
|
if (!pay_tx_fee) {
|
||||||
error = AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", ""));
|
error = AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", ""));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
} else if (pay_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
|
||||||
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
|
|
||||||
warnings.push_back(AmountHighWarn("-paytxfee") + Untranslated(" ") +
|
warnings.push_back(AmountHighWarn("-paytxfee") + Untranslated(" ") +
|
||||||
_("This is the transaction fee you will pay if you send a transaction."));
|
_("This is the transaction fee you will pay if you send a transaction."));
|
||||||
}
|
}
|
||||||
walletInstance->m_pay_tx_fee = CFeeRate(nFeePerK, 1000);
|
|
||||||
|
walletInstance->m_pay_tx_fee = CFeeRate{pay_tx_fee.value(), 1000};
|
||||||
|
|
||||||
if (chain && walletInstance->m_pay_tx_fee < chain->relayMinFee()) {
|
if (chain && walletInstance->m_pay_tx_fee < chain->relayMinFee()) {
|
||||||
error = strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
|
error = strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
|
||||||
gArgs.GetArg("-paytxfee", ""), chain->relayMinFee().ToString());
|
gArgs.GetArg("-paytxfee", ""), chain->relayMinFee().ToString());
|
||||||
|
@ -2683,20 +2684,21 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gArgs.IsArgSet("-maxtxfee")) {
|
if (gArgs.IsArgSet("-maxtxfee")) {
|
||||||
CAmount nMaxFee = 0;
|
std::optional<CAmount> max_fee = ParseMoney(gArgs.GetArg("-maxtxfee", ""));
|
||||||
if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee)) {
|
if (!max_fee) {
|
||||||
error = AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", ""));
|
error = AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", ""));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
} else if (max_fee.value() > HIGH_MAX_TX_FEE) {
|
||||||
if (nMaxFee > HIGH_MAX_TX_FEE) {
|
|
||||||
warnings.push_back(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
|
warnings.push_back(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
|
||||||
}
|
}
|
||||||
if (chain && CFeeRate(nMaxFee, 1000) < chain->relayMinFee()) {
|
|
||||||
|
if (chain && CFeeRate{max_fee.value(), 1000} < chain->relayMinFee()) {
|
||||||
error = strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
|
error = strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
|
||||||
gArgs.GetArg("-maxtxfee", ""), chain->relayMinFee().ToString());
|
gArgs.GetArg("-maxtxfee", ""), chain->relayMinFee().ToString());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
walletInstance->m_default_max_tx_fee = nMaxFee;
|
|
||||||
|
walletInstance->m_default_max_tx_fee = max_fee.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chain && chain->relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) {
|
if (chain && chain->relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue