mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Simplify fee handling during transaction submission:
Avoid custom overflow code; simply use 128-bit math to maintain precision and return a saturated 64-bit value as the final result. Disallow use of negative values in the `fee_mult_max` and `fee_div_max` fields. This change could potentially cause submissions with negative values that would have previously succeeded to now fail.
This commit is contained in:
@@ -20,46 +20,29 @@
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/basics/mulDiv.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple
|
||||
{
|
||||
|
||||
// compute (value)*(mul)/(div) - avoid overflow but keep precision
|
||||
std::pair<bool, std::uint64_t>
|
||||
mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div)
|
||||
{
|
||||
if ((value == 0 || mul == 0) && div != 0)
|
||||
return{ true, 0 };
|
||||
lowestTerms(value, div);
|
||||
lowestTerms(mul, div);
|
||||
using namespace boost::multiprecision;
|
||||
|
||||
if (value < mul)
|
||||
std::swap(value, mul);
|
||||
constexpr std::uint64_t max =
|
||||
std::numeric_limits<std::uint64_t>::max();
|
||||
const auto limit = max / mul;
|
||||
if (value > limit)
|
||||
{
|
||||
value /= div;
|
||||
if (value > limit)
|
||||
return{ false, max };
|
||||
return{ true, value * mul };
|
||||
}
|
||||
return{ true, value * mul / div };
|
||||
uint128_t result;
|
||||
result = multiply(result, value, mul);
|
||||
|
||||
result /= div;
|
||||
|
||||
auto const limit = std::numeric_limits<std::uint64_t>::max();
|
||||
|
||||
if (result > limit)
|
||||
return { false, limit };
|
||||
|
||||
return { true, static_cast<std::uint64_t>(result) };
|
||||
}
|
||||
|
||||
// compute (value)*(mul)/(div) - avoid overflow but keep precision
|
||||
std::uint64_t
|
||||
mulDivThrow(std::uint64_t value, std::uint64_t mul, std::uint64_t div)
|
||||
{
|
||||
auto const result = mulDiv(value, mul, div);
|
||||
if(!result.first)
|
||||
Throw<std::overflow_error>("mulDiv");
|
||||
return result.second;
|
||||
}
|
||||
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#define RIPPLE_BASICS_MULDIV_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple
|
||||
@@ -43,38 +42,6 @@ namespace ripple
|
||||
std::pair<bool, std::uint64_t>
|
||||
mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div);
|
||||
|
||||
/** Return value*mul/div accurately.
|
||||
Computes the result of the multiplication and division in
|
||||
a single step, avoiding overflow and retaining precision.
|
||||
Throws:
|
||||
std::overflow_error
|
||||
*/
|
||||
std::uint64_t
|
||||
mulDivThrow(std::uint64_t value, std::uint64_t mul, std::uint64_t div);
|
||||
|
||||
template <class T1, class T2,
|
||||
class = std::enable_if_t <
|
||||
std::is_integral<T1>::value &&
|
||||
std::is_unsigned<T1>::value &&
|
||||
sizeof(T1) <= sizeof(std::uint64_t) >,
|
||||
class = std::enable_if_t <
|
||||
std::is_integral<T2>::value &&
|
||||
std::is_unsigned<T2>::value &&
|
||||
sizeof(T2) <= sizeof(std::uint64_t) >
|
||||
>
|
||||
void lowestTerms(T1& a, T2& b)
|
||||
{
|
||||
std::uint64_t x = a, y = b;
|
||||
while (y != 0)
|
||||
{
|
||||
auto t = x % y;
|
||||
x = y;
|
||||
y = t;
|
||||
}
|
||||
a /= x;
|
||||
b /= x;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user