20 #include <ripple/basics/Log.h>
21 #include <ripple/basics/contract.h>
22 #include <ripple/basics/safe_cast.h>
23 #include <ripple/beast/core/LexicalCast.h>
24 #include <ripple/protocol/STAmount.h>
25 #include <ripple/protocol/SystemParameters.h>
26 #include <ripple/protocol/UintTypes.h>
27 #include <ripple/protocol/jss.h>
28 #include <boost/algorithm/string.hpp>
29 #include <boost/multiprecision/cpp_int.hpp>
30 #include <boost/regex.hpp>
41 getStaticSTAmountCanonicalizeSwitchover()
43 static LocalValue<bool> r{
true};
51 return *getStaticSTAmountCanonicalizeSwitchover();
57 *getStaticSTAmountCanonicalizeSwitchover() = v;
69 Throw<std::runtime_error>(
"amount is not native!");
107 Throw<std::runtime_error>(
"negative zero is not canonical");
120 Throw<std::runtime_error>(
"invalid native currency");
125 Throw<std::runtime_error>(
"invalid native account");
128 int offset =
static_cast<int>(
value >> (64 - 10));
130 value &= ~(1023ull << (64 - 10));
134 bool isNegative = (offset & 256) == 0;
135 offset = (offset & 255) - 97;
140 Throw<std::runtime_error>(
"invalid currency value");
152 Throw<std::runtime_error>(
"invalid currency value");
174 , mIsNegative(negative)
189 , mIsNegative(negative)
205 , mIsNegative(negative)
211 :
STBase(name), mOffset(0), mIsNative(true)
221 , mIsNegative(negative)
236 , mIsNegative(negative)
244 , mIssue(from.mIssue)
245 , mValue(from.mValue)
246 , mOffset(from.mOffset)
247 , mIsNegative(from.mIsNegative)
259 , mIsNegative(mantissa != 0 && negative)
269 : mIssue(issue), mValue(mantissa), mOffset(exponent), mIsNegative(negative)
275 : mIssue(issue), mOffset(exponent)
298 , mOffset(amount.exponent())
300 , mIsNegative(amount <
beast::zero)
311 : mOffset(0), mIsNative(true), mIsNegative(amount <
beast::zero)
314 mValue = unsafe_cast<std::uint64_t>(-amount.
drops());
316 mValue = unsafe_cast<std::uint64_t>(amount.
drops());
324 return std::make_unique<STAmount>(sit, name);
336 return emplace(n, buf, std::move(*
this));
348 Throw<std::logic_error>(
349 "Cannot return non-native STAmount as XRPAmount");
363 Throw<std::logic_error>(
"Cannot return native STAmount as IOUAmount");
411 Throw<std::runtime_error>(
"Can't add amounts that are't comparable!");
413 if (v2 == beast::zero)
416 if (v1 == beast::zero)
464 if ((fv >= -10) && (fv <= 10))
508 if (offerOut == beast::zero)
513 if (r == beast::zero)
517 return (ret << (64 - 8)) | r.
mantissa();
572 if (*
this == beast::zero)
581 bool const scientific(
599 size_t const pad_prefix = 27;
600 size_t const pad_suffix = 23;
604 val.
append(pad_prefix,
'0');
606 val.
append(pad_suffix,
'0');
608 size_t const offset(
mOffset + 43);
610 auto pre_from(val.
begin());
611 auto const pre_to(val.
begin() + offset);
613 auto const post_from(val.
begin() + offset);
614 auto post_to(val.
end());
619 pre_from += pad_prefix;
621 assert(post_to >= post_from);
623 pre_from =
std::find_if(pre_from, pre_to, [](
char c) {
return c !=
'0'; });
628 post_to -= pad_suffix;
630 assert(post_to >= post_from);
635 [](
char c) {
return c !=
'0'; })
639 if (pre_from == pre_to)
642 ret.
append(pre_from, pre_to);
644 if (post_to != post_from)
647 ret.
append(post_from, post_to);
674 if (*
this == beast::zero)
695 return v && (*v == *
this);
743 Throw<std::runtime_error>(
744 "Native currency amount out of range");
771 Throw<std::runtime_error>(
772 "Native currency amount out of range");
780 Throw<std::runtime_error>(
"Native currency amount out of range");
809 Throw<std::runtime_error>(
"value overflow");
824 Throw<std::runtime_error>(
"value overflow");
856 int exponent =
static_cast<int>(rate >> (64 - 8)) - 100;
864 static boost::regex
const reNumber(
869 "([eE]([+-]?)([0-9]+))?"
871 boost::regex_constants::optimize);
875 if (!boost::regex_match(amount, match, reNumber))
876 Throw<std::runtime_error>(
"Number '" + amount +
"' is not valid");
889 if ((match[2].length() + match[4].length()) > 32)
890 Throw<std::runtime_error>(
"Number '" + amount +
"' is overlong");
892 bool negative = (match[1].matched && (match[1] ==
"-"));
895 if (
isXRP(issue) && match[3].matched)
896 Throw<std::runtime_error>(
"XRP must be specified in integral drops.");
901 if (!match[4].matched)
904 beast::lexicalCastThrow<std::uint64_t>(
std::string(match[2]));
910 mantissa = beast::lexicalCastThrow<std::uint64_t>(match[2] + match[4]);
911 exponent = -(match[4].length());
914 if (match[5].matched)
917 if (match[6].matched && (match[6] ==
"-"))
918 exponent -= beast::lexicalCastThrow<int>(
std::string(match[7]));
920 exponent += beast::lexicalCastThrow<int>(
std::string(match[7]));
923 return {issue, mantissa, exponent, negative};
931 bool negative =
false;
940 Throw<std::runtime_error>(
941 "XRP may not be specified with a null Json value");
945 value = v[jss::value];
946 currency = v[jss::currency];
947 issuer = v[jss::issuer];
959 boost::split(elements, val, boost::is_any_of(
"\t\n\r ,/"));
961 if (elements.
size() > 3)
962 Throw<std::runtime_error>(
"invalid amount string");
966 if (elements.
size() > 1)
967 currency = elements[1];
969 if (elements.
size() > 2)
970 issuer = elements[2];
983 Throw<std::runtime_error>(
"XRP may not be specified as an object");
990 Throw<std::runtime_error>(
"invalid currency");
993 Throw<std::runtime_error>(
"invalid issuer");
996 Throw<std::runtime_error>(
"invalid issuer");
1001 if (value.
asInt() >= 0)
1003 mantissa = value.
asInt();
1007 mantissa = -value.
asInt();
1019 mantissa = ret.mantissa();
1020 exponent = ret.exponent();
1021 negative = ret.negative();
1025 Throw<std::runtime_error>(
"invalid amount type");
1028 return {name, issue, mantissa, exponent, native, negative};
1042 <<
"amountFromJsonNoThrow: caught: " << e.
what();
1064 Throw<std::runtime_error>(
1065 "Can't compare amounts that are't comparable!");
1124 boost::multiprecision::uint128_t ret;
1126 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1131 Throw<std::overflow_error>(
1136 return static_cast<uint64_t
>(ret);
1146 boost::multiprecision::uint128_t ret;
1148 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1154 Throw<std::overflow_error>(
1160 return static_cast<uint64_t
>(ret);
1166 if (den == beast::zero)
1167 Throw<std::runtime_error>(
"division by zero");
1169 if (num == beast::zero)
1204 numOffset - denOffset - 17,
1211 if (v1 == beast::zero || v2 == beast::zero)
1221 if (minV > 3000000000ull)
1222 Throw<std::runtime_error>(
"Native value overflow");
1224 if (((maxV >> 32) * minV) > 2095475792ull)
1225 Throw<std::runtime_error>(
"Native value overflow");
1263 offset1 + offset2 + 14,
1303 value += (loops >= 2) ? 9 : 10;
1337 bool hadRemainder =
false;
1345 hadRemainder |= (value != (newValue * 10));
1350 (hadRemainder && roundUp) ? 10 : 9;
1374 class NumberRoundModeGuard
1376 saveNumberRoundMode saved_;
1384 NumberRoundModeGuard(NumberRoundModeGuard
const&) =
delete;
1386 NumberRoundModeGuard&
1387 operator=(NumberRoundModeGuard
const&) =
delete;
1392 class DontAffectNumberRoundMode
1399 DontAffectNumberRoundMode(DontAffectNumberRoundMode
const&) =
delete;
1401 DontAffectNumberRoundMode&
1402 operator=(DontAffectNumberRoundMode
const&) =
delete;
1413 typename MightSaveRound>
1421 if (v1 == beast::zero || v2 == beast::zero)
1424 bool const xrp =
isXRP(issue);
1433 if (minV > 3000000000ull)
1434 Throw<std::runtime_error>(
"Native value overflow");
1436 if (((maxV >> 32) * minV) > 2095475792ull)
1437 Throw<std::runtime_error>(
"Native value overflow");
1476 int offset = offset1 + offset2 + 14;
1477 if (resultNegative != roundUp)
1479 CanonicalizeFunc(xrp, amount, offset, roundUp);
1485 return STAmount(issue, amount, offset, resultNegative);
1488 if (roundUp && !resultNegative && !result)
1502 return STAmount(issue, amount, offset, resultNegative);
1514 return mulRoundImpl<canonicalizeRound, DontAffectNumberRoundMode>(
1515 v1, v2, issue, roundUp);
1525 return mulRoundImpl<canonicalizeRoundStrict, NumberRoundModeGuard>(
1526 v1, v2, issue, roundUp);
1531 template <
typename MightSaveRound>
1539 if (den == beast::zero)
1540 Throw<std::runtime_error>(
"division by zero");
1542 if (num == beast::zero)
1577 numVal,
tenTo17, denVal, (resultNegative != roundUp) ? denVal - 1 : 0);
1579 int offset = numOffset - denOffset - 17;
1581 if (resultNegative != roundUp)
1589 MightSaveRound
const savedRound(
1590 roundUp ^ resultNegative ? upward : downward);
1591 return STAmount(issue, amount, offset, resultNegative);
1594 if (roundUp && !resultNegative && !result)
1608 return STAmount(issue, amount, offset, resultNegative);
1620 return divRoundImpl<DontAffectNumberRoundMode>(num, den, issue, roundUp);
1630 return divRoundImpl<NumberRoundModeGuard>(num, den, issue, roundUp);