diff --git a/include/xrpl/protocol/IOUAmount.h b/include/xrpl/protocol/IOUAmount.h index 060ad3d828..41ade77e62 100644 --- a/include/xrpl/protocol/IOUAmount.h +++ b/include/xrpl/protocol/IOUAmount.h @@ -40,6 +40,20 @@ private: void normalize(); + /** + * Constrains the exponent to IOUAmount's range, which is narrower than + * the one Number normalization enforces. + * + * The two ends are deliberately asymmetric, matching the class contract: + * an exponent above the range is unrepresentable and throws, while one + * below it is a silent underflow that truncates the amount to zero. + * + * @throws std::overflow_error if the exponent exceeds the largest + * representable IOU exponent. + */ + void + enforceExponentBounds(); + static IOUAmount fromNumber(Number const& number); diff --git a/src/libxrpl/protocol/IOUAmount.cpp b/src/libxrpl/protocol/IOUAmount.cpp index 1b3e5b3737..3c7ce14e76 100644 --- a/src/libxrpl/protocol/IOUAmount.cpp +++ b/src/libxrpl/protocol/IOUAmount.cpp @@ -43,19 +43,8 @@ IOUAmount::minPositiveAmount() } void -IOUAmount::normalize() +IOUAmount::enforceExponentBounds() { - if (mantissa_ == 0) - { - *this = beast::kZero; - return; - } - std::tie(mantissa_, exponent_) = - Number::normalizeToRange(mantissa_, exponent_); - - // normalizeToRange only enforces Number's much wider exponent bounds. - // Re-apply IOUAmount's narrower range here, matching the check - // IOUAmount(Number const&) applies on its own construction path. if (exponent_ > kMaxExponent) { Throw("value overflow"); @@ -66,16 +55,25 @@ IOUAmount::normalize() } } -IOUAmount::IOUAmount(Number const& other) : IOUAmount(fromNumber(other)) +void +IOUAmount::normalize() { - if (exponent_ > kMaxExponent) - { - Throw("value overflow"); - } - if (exponent_ < kMinExponent) + if (mantissa_ == 0) { *this = beast::kZero; + return; } + std::tie(mantissa_, exponent_) = + Number::normalizeToRange(mantissa_, exponent_); + + // normalizeToRange only enforces Number's much wider exponent bounds, so + // IOUAmount's narrower range still has to be applied on top. + enforceExponentBounds(); +} + +IOUAmount::IOUAmount(Number const& other) : IOUAmount(fromNumber(other)) +{ + enforceExponentBounds(); } IOUAmount&