From 54e052d8bb937ac4bcb7625854cf6119eaec53d7 Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Wed, 29 Jul 2026 13:11:51 +0100 Subject: [PATCH] refactor: extract IOUAmount exponent bounds check into a helper The exponent bounds check appeared verbatim in both normalize() and IOUAmount(Number const&). Extract it into a private enforceExponentBounds() and call it from both. Named "enforce" rather than "check" because the function acts on the value as well as inspecting it: it throws above the range and truncates to zero below it. That matches the codebase precedent of requireAuth (a pure predicate) versus enforceMPTokenAuthorization (which mutates). Defined out of line because a header inline would need STAmount's offset constants, and STAmount.h already includes IOUAmount.h. No behavior change: the extracted body is identical to both original blocks, and the Number constructor still applies it after delegating construction completes. --- include/xrpl/protocol/IOUAmount.h | 14 ++++++++++++ src/libxrpl/protocol/IOUAmount.cpp | 34 ++++++++++++++---------------- 2 files changed, 30 insertions(+), 18 deletions(-) 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&