From 58b22901cb12e8442fe7023a6a6c7bd866456f34 Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Sat, 9 Nov 2024 06:17:00 +0100 Subject: [PATCH] Fix: `float_divide` rounding error (#351) Co-authored-by: RichardAH --- src/ripple/app/hook/impl/applyHook.cpp | 21 ++++++++++++++++----- src/ripple/protocol/Feature.h | 3 ++- src/ripple/protocol/impl/Feature.cpp | 1 + 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/ripple/app/hook/impl/applyHook.cpp b/src/ripple/app/hook/impl/applyHook.cpp index 2afd018e8..abd7ef136 100644 --- a/src/ripple/app/hook/impl/applyHook.cpp +++ b/src/ripple/app/hook/impl/applyHook.cpp @@ -5404,7 +5404,7 @@ DEFINE_HOOK_FUNCTION( const int64_t float_one_internal = make_float(1000000000000000ull, -15, false); inline int64_t -float_divide_internal(int64_t float1, int64_t float2) +float_divide_internal(int64_t float1, int64_t float2, bool hasFix) { RETURN_IF_INVALID_FLOAT(float1); RETURN_IF_INVALID_FLOAT(float2); @@ -5457,8 +5457,16 @@ float_divide_internal(int64_t float1, int64_t float2) while (man2 > 0) { int i = 0; - for (; man1 > man2; man1 -= man2, ++i) - ; + if (hasFix) + { + for (; man1 >= man2; man1 -= man2, ++i) + ; + } + else + { + for (; man1 > man2; man1 -= man2, ++i) + ; + } man3 *= 10; man3 += i; @@ -5478,7 +5486,8 @@ DEFINE_HOOK_FUNCTION(int64_t, float_divide, int64_t float1, int64_t float2) HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx, // hookCtx on current stack - return float_divide_internal(float1, float2); + bool const hasFix = view.rules().enabled(fixFloatDivide); + return float_divide_internal(float1, float2, hasFix); HOOK_TEARDOWN(); } @@ -5497,7 +5506,9 @@ DEFINE_HOOK_FUNCTION(int64_t, float_invert, int64_t float1) return DIVISION_BY_ZERO; if (float1 == float_one_internal) return float_one_internal; - return float_divide_internal(float_one_internal, float1); + + bool const fixV3 = view.rules().enabled(fixFloatDivide); + return float_divide_internal(float_one_internal, float1, fixV3); HOOK_TEARDOWN(); } diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index 54628c9cd..43d510c63 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -74,7 +74,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 73; +static constexpr std::size_t numFeatures = 74; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -361,6 +361,7 @@ extern uint256 const fixNSDelete; extern uint256 const fix240819; extern uint256 const fixPageCap; extern uint256 const fix240911; +extern uint256 const fixFloatDivide; } // namespace ripple diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index 27ec16cb7..23cbe236d 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -467,6 +467,7 @@ REGISTER_FIX (fixNSDelete, Supported::yes, VoteBehavior::De REGISTER_FIX (fix240819, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FIX (fixPageCap, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FIX (fix240911, Supported::yes, VoteBehavior::DefaultYes); +REGISTER_FIX (fixFloatDivide, Supported::yes, VoteBehavior::DefaultYes); // The following amendments are obsolete, but must remain supported // because they could potentially get enabled.