mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Add units to all fee calculations:
* Uses existing XRPAmount with units for drops, and a new TaggedFee for fee units (LoadFeeTrack), and fee levels (TxQ). * Resolves #2451
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <ripple/app/misc/LoadFeeTrack.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/FeeUnits.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/safe_cast.h>
|
||||
#include <ripple/core/Config.h>
|
||||
@@ -83,27 +84,32 @@ LoadFeeTrack::lowerLocalFee ()
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class T1, class T2,
|
||||
class = std::enable_if_t<
|
||||
std::is_integral_v<T1> &&
|
||||
std::is_integral_v<T2>>
|
||||
>
|
||||
void lowestTerms(T1& a, T2& b)
|
||||
{
|
||||
if (auto const gcd = std::gcd(a, b))
|
||||
{
|
||||
a /= gcd;
|
||||
b /= gcd;
|
||||
}
|
||||
}
|
||||
|
||||
// Scale using load as well as base rate
|
||||
std::uint64_t
|
||||
scaleFeeLoad(std::uint64_t fee, LoadFeeTrack const& feeTrack,
|
||||
XRPAmount
|
||||
scaleFeeLoad(FeeUnit64 fee, LoadFeeTrack const& feeTrack,
|
||||
Fees const& fees, bool bUnlimited)
|
||||
{
|
||||
if (fee == 0)
|
||||
return fee;
|
||||
return XRPAmount{0};
|
||||
|
||||
// Normally, types with different units wouldn't be mathematically
|
||||
// compatible. This function is an exception.
|
||||
auto lowestTerms = [](auto& a, auto& b)
|
||||
{
|
||||
auto value = [](auto val)
|
||||
{
|
||||
if constexpr(std::is_arithmetic_v<decltype(val)>)
|
||||
return val;
|
||||
else
|
||||
return val.value();
|
||||
};
|
||||
|
||||
if (auto const g = std::gcd(value(a), value(b)))
|
||||
{
|
||||
a = value(a) / g;
|
||||
b = value(b) / g;
|
||||
}
|
||||
};
|
||||
|
||||
// Collect the fee rates
|
||||
auto [feeFactor, uRemFee] = feeTrack.getScalingFactors();
|
||||
@@ -113,7 +119,7 @@ scaleFeeLoad(std::uint64_t fee, LoadFeeTrack const& feeTrack,
|
||||
if (bUnlimited && (feeFactor > uRemFee) && (feeFactor < (4 * uRemFee)))
|
||||
feeFactor = uRemFee;
|
||||
|
||||
auto baseFee = fees.base;
|
||||
XRPAmount baseFee{fees.base};
|
||||
// Compute:
|
||||
// fee = fee * baseFee * feeFactor / (fees.units * lftNormalFee);
|
||||
// without overflow, and as accurately as possible
|
||||
@@ -121,7 +127,7 @@ scaleFeeLoad(std::uint64_t fee, LoadFeeTrack const& feeTrack,
|
||||
// The denominator of the fraction we're trying to compute.
|
||||
// fees.units and lftNormalFee are both 32 bit,
|
||||
// so the multiplication can't overflow.
|
||||
auto den = safe_cast<std::uint64_t>(fees.units)
|
||||
auto den = FeeUnit64{ fees.units }
|
||||
* safe_cast<std::uint64_t>(feeTrack.getLoadBase());
|
||||
// Reduce fee * baseFee * feeFactor / (fees.units * lftNormalFee)
|
||||
// to lowest terms.
|
||||
@@ -131,33 +137,30 @@ scaleFeeLoad(std::uint64_t fee, LoadFeeTrack const& feeTrack,
|
||||
|
||||
// fee and baseFee are 64 bit, feeFactor is 32 bit
|
||||
// Order fee and baseFee largest first
|
||||
if (fee < baseFee)
|
||||
std::swap(fee, baseFee);
|
||||
// Normally, these types wouldn't be comparable or swappable.
|
||||
// This function is an exception.
|
||||
if (fee.value() < baseFee.value())
|
||||
{
|
||||
auto tmp = fee.value();
|
||||
fee = baseFee.value();
|
||||
baseFee = tmp;
|
||||
}
|
||||
// double check
|
||||
assert(fee.value() >= baseFee.value());
|
||||
|
||||
// If baseFee * feeFactor overflows, the final result will overflow
|
||||
const auto max = std::numeric_limits<std::uint64_t>::max();
|
||||
if (baseFee > max / feeFactor)
|
||||
Throw<std::overflow_error> ("scaleFeeLoad");
|
||||
XRPAmount const baseFeeOverflow{
|
||||
std::numeric_limits<XRPAmount::value_type>::max() / feeFactor};
|
||||
if (baseFee > baseFeeOverflow)
|
||||
{
|
||||
Throw<std::overflow_error>("scaleFeeLoad");
|
||||
}
|
||||
baseFee *= feeFactor;
|
||||
// Reorder fee and baseFee
|
||||
if (fee < baseFee)
|
||||
std::swap(fee, baseFee);
|
||||
// If fee * baseFee / den might overflow...
|
||||
if (fee > max / baseFee)
|
||||
{
|
||||
// Do the division first, on the larger of fee and baseFee
|
||||
fee /= den;
|
||||
if (fee > max / baseFee)
|
||||
Throw<std::overflow_error> ("scaleFeeLoad");
|
||||
fee *= baseFee;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise fee * baseFee won't overflow,
|
||||
// so do it prior to the division.
|
||||
fee *= baseFee;
|
||||
fee /= den;
|
||||
}
|
||||
return fee;
|
||||
|
||||
auto const result = mulDiv(fee, baseFee, den);
|
||||
if (!result.first)
|
||||
Throw<std::overflow_error> ("scaleFeeLoad");
|
||||
return result.second;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
Reference in New Issue
Block a user