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:
Nik Bougalis
2017-01-18 03:33:46 -08:00
parent c7de7950c4
commit 8345475bc3
8 changed files with 135 additions and 106 deletions

View File

@@ -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

View File

@@ -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