diff --git a/src/avalanche/test/processor_tests.cpp b/src/avalanche/test/processor_tests.cpp --- a/src/avalanche/test/processor_tests.cpp +++ b/src/avalanche/test/processor_tests.cpp @@ -1299,7 +1299,8 @@ // Min stake is out of range {"-1", "0", false}, - {"21000000001", "0", false}, + {"-0.01", "0", false}, + {"21000000000000.01", "0", false}, // Min connected ratio is out of range {"0", "-1", false}, @@ -1307,10 +1308,12 @@ // Both parameters are valid {"0", "0", true}, + {"0.00", "0", true}, + {"0.01", "0", true}, {"1", "0.1", true}, {"10", "0.5", true}, {"10", "1", true}, - {ToString(MAX_MONEY / COIN), "0", true}, + {"21000000000000.00", "0", true}, }; // For each case set the parameters and check that making the processor diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1437,6 +1437,9 @@ BOOST_CHECK(ParseMoney("1234567.89", ret)); BOOST_CHECK_EQUAL(ret, 123456789 * SATOSHI); + BOOST_CHECK(ParseMoney("21000000000000.00", ret)); + BOOST_CHECK_EQUAL(ret, MAX_MONEY); + const auto XEC = Currency::get().baseunit; BOOST_CHECK(ParseMoney("100000000.00", ret)); BOOST_CHECK_EQUAL(ret, 100000000 * XEC); @@ -1474,14 +1477,14 @@ BOOST_CHECK_EQUAL(ret, XEC / 100); BOOST_CHECK(ParseMoney(" 0.01", ret)); BOOST_CHECK_EQUAL(ret, XEC / 100); + + // Parsing amount that can not be represented in ret should fail BOOST_CHECK(!ParseMoney("0.001", ret)); BOOST_CHECK(!ParseMoney("0.0001", ret)); BOOST_CHECK(!ParseMoney("0.00001", ret)); BOOST_CHECK(!ParseMoney("0.000001", ret)); BOOST_CHECK(!ParseMoney("0.0000001", ret)); BOOST_CHECK(!ParseMoney("0.00000001", ret)); - - // Parsing amount that can not be represented in ret should fail BOOST_CHECK(!ParseMoney("0.000000001", ret)); // Parsing empty string should fail @@ -1495,8 +1498,12 @@ BOOST_CHECK(!ParseMoney(" 1.2 3 ", ret)); BOOST_CHECK(!ParseMoney(" 1 2.3 ", ret)); + // Max possible value with the max number of digits + BOOST_CHECK(ParseMoney("9999999999999999.99", ret)); + BOOST_CHECK_EQUAL(ret, 999999999999999999 * SATOSHI); // Attempted 63 bit overflow should fail - BOOST_CHECK(!ParseMoney("92233720368.54775808", ret)); + BOOST_CHECK(!ParseMoney("10000000000000000.00", ret)); + BOOST_CHECK(!ParseMoney("92233720368547758.08", ret)); // Parsing negative amounts must fail BOOST_CHECK(!ParseMoney("-1", ret)); diff --git a/src/util/moneystr.cpp b/src/util/moneystr.cpp --- a/src/util/moneystr.cpp +++ b/src/util/moneystr.cpp @@ -42,7 +42,7 @@ return false; } - const auto currency = Currency::get(); + const auto ¤cy = Currency::get(); std::string strWhole; Amount nUnits = Amount::zero(); const char *p = str.c_str(); @@ -67,8 +67,14 @@ if (*p) { return false; } + + // Make sure the following overflow check is meaningful. It's fine to assert + // because it's on no critical path, and it's very unlikely to support a 19 + // decimal (or more) currency anyway. + assert(currency.decimals <= 18); + // guard against 63 bit overflow - if (strWhole.size() > 10) { + if (strWhole.size() > (size_t(18) - currency.decimals)) { return false; } if (nUnits < Amount::zero() || nUnits > currency.baseunit) {