mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-01 00:15:51 +00:00
Merge remote-tracking branch 'mywork/ximinez/lending-number' into ximinez/lending-XLS-66
* mywork/ximinez/lending-number: Catch up the consequences of Number changes Fix build error - avoid copy Add integer enforcement when converting to XRP/MPTAmount to Number Make all STNumber fields "soeDEFAULT" Add optional enforcement of valid integer range to Number fix: domain order book insertion #5998 refactor: Retire fixTrustLinesToSelf amendment (#5989)
This commit is contained in:
@@ -24,17 +24,38 @@ isPowerOfTen(T value)
|
||||
|
||||
class Number
|
||||
{
|
||||
public:
|
||||
/** Describes whether and how to enforce this number as an integer.
|
||||
*
|
||||
* - none: No enforcement. The value may vary freely. This is the default.
|
||||
* - weak: If the absolute value is greater than maxIntValue, valid() will
|
||||
* return false.
|
||||
* - strong: Assignment operations will throw if the absolute value is above
|
||||
* maxIntValue.
|
||||
*/
|
||||
enum EnforceInteger { none, weak, strong };
|
||||
|
||||
private:
|
||||
using rep = std::int64_t;
|
||||
rep mantissa_{0};
|
||||
int exponent_{std::numeric_limits<int>::lowest()};
|
||||
|
||||
// The enforcement setting is not serialized, and does not affect the
|
||||
// ledger. If not "none", the value is checked to be within the valid
|
||||
// integer range. With "strong", the checks will be made as automatic as
|
||||
// possible.
|
||||
EnforceInteger enforceInteger_ = none;
|
||||
|
||||
public:
|
||||
// The range for the mantissa when normalized
|
||||
constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL;
|
||||
constexpr static rep minMantissa = 1'000'000'000'000'000LL;
|
||||
static_assert(isPowerOfTen(minMantissa));
|
||||
constexpr static std::int64_t maxMantissa = minMantissa * 10 - 1;
|
||||
constexpr static rep maxMantissa = minMantissa * 10 - 1;
|
||||
static_assert(maxMantissa == 9'999'999'999'999'999LL);
|
||||
|
||||
constexpr static rep maxIntValue = maxMantissa / 10;
|
||||
static_assert(maxIntValue == 999'999'999'999'999LL);
|
||||
|
||||
// The range for the exponent when normalized
|
||||
constexpr static int minExponent = -32768;
|
||||
constexpr static int maxExponent = 32768;
|
||||
@@ -46,15 +67,33 @@ public:
|
||||
|
||||
explicit constexpr Number() = default;
|
||||
|
||||
Number(rep mantissa);
|
||||
explicit Number(rep mantissa, int exponent);
|
||||
Number(rep mantissa, EnforceInteger enforce = none);
|
||||
explicit Number(rep mantissa, int exponent, EnforceInteger enforce = none);
|
||||
explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept;
|
||||
constexpr Number(Number const& other) = default;
|
||||
constexpr Number(Number&& other) = default;
|
||||
|
||||
~Number() = default;
|
||||
|
||||
constexpr Number&
|
||||
operator=(Number const& other);
|
||||
constexpr Number&
|
||||
operator=(Number&& other);
|
||||
|
||||
constexpr rep
|
||||
mantissa() const noexcept;
|
||||
constexpr int
|
||||
exponent() const noexcept;
|
||||
|
||||
void
|
||||
setIntegerEnforcement(EnforceInteger enforce);
|
||||
|
||||
EnforceInteger
|
||||
integerEnforcement() const noexcept;
|
||||
|
||||
bool
|
||||
valid() const noexcept;
|
||||
|
||||
constexpr Number
|
||||
operator+() const noexcept;
|
||||
constexpr Number
|
||||
@@ -180,6 +219,9 @@ public:
|
||||
private:
|
||||
static thread_local rounding_mode mode_;
|
||||
|
||||
void
|
||||
checkInteger(char const* what) const;
|
||||
|
||||
void
|
||||
normalize();
|
||||
constexpr bool
|
||||
@@ -195,16 +237,52 @@ inline constexpr Number::Number(rep mantissa, int exponent, unchecked) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
inline Number::Number(rep mantissa, int exponent)
|
||||
: mantissa_{mantissa}, exponent_{exponent}
|
||||
inline Number::Number(rep mantissa, int exponent, EnforceInteger enforce)
|
||||
: mantissa_{mantissa}, exponent_{exponent}, enforceInteger_(enforce)
|
||||
{
|
||||
normalize();
|
||||
|
||||
checkInteger("Number::Number integer overflow");
|
||||
}
|
||||
|
||||
inline Number::Number(rep mantissa) : Number{mantissa, 0}
|
||||
inline Number::Number(rep mantissa, EnforceInteger enforce)
|
||||
: Number{mantissa, 0, enforce}
|
||||
{
|
||||
}
|
||||
|
||||
constexpr Number&
|
||||
Number::operator=(Number const& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
mantissa_ = other.mantissa_;
|
||||
exponent_ = other.exponent_;
|
||||
enforceInteger_ = std::max(enforceInteger_, other.enforceInteger_);
|
||||
|
||||
checkInteger("Number::operator= integer overflow");
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Number&
|
||||
Number::operator=(Number&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
// std::move doesn't really do anything for these types, but
|
||||
// this is future-proof in case the types ever change
|
||||
mantissa_ = std::move(other.mantissa_);
|
||||
exponent_ = std::move(other.exponent_);
|
||||
if (other.enforceInteger_ > enforceInteger_)
|
||||
enforceInteger_ = std::move(other.enforceInteger_);
|
||||
|
||||
checkInteger("Number::operator= integer overflow");
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline constexpr Number::rep
|
||||
Number::mantissa() const noexcept
|
||||
{
|
||||
@@ -217,6 +295,20 @@ Number::exponent() const noexcept
|
||||
return exponent_;
|
||||
}
|
||||
|
||||
inline void
|
||||
Number::setIntegerEnforcement(EnforceInteger enforce)
|
||||
{
|
||||
enforceInteger_ = enforce;
|
||||
|
||||
checkInteger("Number::setIntegerEnforcement integer overflow");
|
||||
}
|
||||
|
||||
inline Number::EnforceInteger
|
||||
Number::integerEnforcement() const noexcept
|
||||
{
|
||||
return enforceInteger_;
|
||||
}
|
||||
|
||||
inline constexpr Number
|
||||
Number::operator+() const noexcept
|
||||
{
|
||||
|
||||
@@ -62,9 +62,15 @@ public:
|
||||
explicit constexpr
|
||||
operator bool() const noexcept;
|
||||
|
||||
operator Number() const noexcept
|
||||
operator Number() const
|
||||
{
|
||||
return value();
|
||||
return {value(), Number::strong};
|
||||
}
|
||||
|
||||
Number
|
||||
toNumber(Number::EnforceInteger enforce) const
|
||||
{
|
||||
return {value(), enforce};
|
||||
}
|
||||
|
||||
/** Return the sign of the amount */
|
||||
|
||||
@@ -40,6 +40,12 @@ private:
|
||||
exponent_type mOffset;
|
||||
bool mIsNegative;
|
||||
|
||||
// The Enforce integer setting is not stored or serialized. If set, it is
|
||||
// used during automatic conversions to Number. If not set, the default
|
||||
// behavior is used. It can also be overridden when coverting by using
|
||||
// toNumber().
|
||||
std::optional<Number::EnforceInteger> enforceConversion_;
|
||||
|
||||
public:
|
||||
using value_type = STAmount;
|
||||
|
||||
@@ -137,9 +143,28 @@ public:
|
||||
STAmount(A const& asset, int mantissa, int exponent = 0);
|
||||
|
||||
template <AssetType A>
|
||||
STAmount(A const& asset, Number const& number)
|
||||
STAmount(
|
||||
A const& asset,
|
||||
Number const& number,
|
||||
std::optional<Number::EnforceInteger> enforce = std::nullopt)
|
||||
: STAmount(asset, number.mantissa(), number.exponent())
|
||||
{
|
||||
enforceConversion_ = enforce;
|
||||
if (!enforce)
|
||||
{
|
||||
// Use the default conversion behavior
|
||||
[[maybe_unused]]
|
||||
Number const n = *this;
|
||||
}
|
||||
else if (enforce == Number::strong)
|
||||
{
|
||||
// Throw if it's not valid
|
||||
if (!validNumber())
|
||||
{
|
||||
Throw<std::overflow_error>(
|
||||
"STAmount::STAmount integer Number lost precision");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy support for new-style amounts
|
||||
@@ -147,6 +172,17 @@ public:
|
||||
STAmount(XRPAmount const& amount);
|
||||
STAmount(MPTAmount const& amount, MPTIssue const& mptIssue);
|
||||
operator Number() const;
|
||||
Number
|
||||
toNumber(Number::EnforceInteger enforce) const;
|
||||
|
||||
void
|
||||
setIntegerEnforcement(std::optional<Number::EnforceInteger> enforce);
|
||||
|
||||
std::optional<Number::EnforceInteger>
|
||||
integerEnforcement() const noexcept;
|
||||
|
||||
bool
|
||||
validNumber() const noexcept;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
@@ -521,6 +557,8 @@ inline STAmount::operator bool() const noexcept
|
||||
|
||||
inline STAmount::operator Number() const
|
||||
{
|
||||
if (enforceConversion_)
|
||||
return toNumber(*enforceConversion_);
|
||||
if (native())
|
||||
return xrp();
|
||||
if (mAsset.holds<MPTIssue>())
|
||||
@@ -528,6 +566,17 @@ inline STAmount::operator Number() const
|
||||
return iou();
|
||||
}
|
||||
|
||||
inline Number
|
||||
STAmount::toNumber(Number::EnforceInteger enforce) const
|
||||
{
|
||||
if (native())
|
||||
return xrp().toNumber(enforce);
|
||||
if (mAsset.holds<MPTIssue>())
|
||||
return mpt().toNumber(enforce);
|
||||
// It doesn't make sense to enforce limits on IOUs
|
||||
return iou();
|
||||
}
|
||||
|
||||
inline STAmount&
|
||||
STAmount::operator=(beast::Zero)
|
||||
{
|
||||
@@ -549,6 +598,11 @@ STAmount::operator=(Number const& number)
|
||||
mValue = mIsNegative ? -number.mantissa() : number.mantissa();
|
||||
mOffset = number.exponent();
|
||||
canonicalize();
|
||||
|
||||
// Convert it back to a Number to check that it's valid
|
||||
[[maybe_unused]]
|
||||
Number n = *this;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -564,7 +618,7 @@ STAmount::clear()
|
||||
{
|
||||
// The -100 is used to allow 0 to sort less than a small positive values
|
||||
// which have a negative exponent.
|
||||
mOffset = native() ? 0 : -100;
|
||||
mOffset = integral() ? 0 : -100;
|
||||
mValue = 0;
|
||||
mIsNegative = false;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,18 @@ public:
|
||||
bool
|
||||
isDefault() const override;
|
||||
|
||||
/// Sets the flag on the underlying number
|
||||
void
|
||||
setIntegerEnforcement(Number::EnforceInteger enforce);
|
||||
|
||||
/// Gets the flag value on the underlying number
|
||||
Number::EnforceInteger
|
||||
integerEnforcement() const noexcept;
|
||||
|
||||
/// Checks the underlying number
|
||||
bool
|
||||
valid() const noexcept;
|
||||
|
||||
operator Number() const
|
||||
{
|
||||
return value_;
|
||||
|
||||
@@ -23,6 +23,7 @@ systemName()
|
||||
|
||||
/** Number of drops in the genesis account. */
|
||||
constexpr XRPAmount INITIAL_XRP{100'000'000'000 * DROPS_PER_XRP};
|
||||
static_assert(INITIAL_XRP.drops() == 100'000'000'000'000'000);
|
||||
|
||||
/** Returns true if the amount does not exceed the initial XRP in existence. */
|
||||
inline bool
|
||||
|
||||
@@ -143,7 +143,13 @@ public:
|
||||
|
||||
operator Number() const noexcept
|
||||
{
|
||||
return drops();
|
||||
return {drops(), Number::weak};
|
||||
}
|
||||
|
||||
Number
|
||||
toNumber(Number::EnforceInteger enforce) const
|
||||
{
|
||||
return {value(), enforce};
|
||||
}
|
||||
|
||||
/** Return the sign of the amount */
|
||||
|
||||
@@ -65,7 +65,6 @@ XRPL_FIX (UniversalNumber, Supported::yes, VoteBehavior::DefaultNo
|
||||
XRPL_FEATURE(XRPFees, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(DisallowIncoming, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (TrustLinesToSelf, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(ExpandedSignerList, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(CheckCashMakesTrustLine, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(FlowSortStrands, Supported::yes, VoteBehavior::DefaultYes)
|
||||
@@ -122,6 +121,7 @@ XRPL_RETIRE(fixReducedOffersV1)
|
||||
XRPL_RETIRE(fixRmSmallIncreasedQOffers)
|
||||
XRPL_RETIRE(fixSTAmountCanonicalize)
|
||||
XRPL_RETIRE(fixTakerDryOfferRemoval)
|
||||
XRPL_RETIRE(fixTrustLinesToSelf)
|
||||
XRPL_RETIRE(CryptoConditions)
|
||||
XRPL_RETIRE(Escrow)
|
||||
XRPL_RETIRE(EnforceInvariants)
|
||||
|
||||
@@ -480,10 +480,10 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfData, soeOPTIONAL},
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAssetsTotal, soeREQUIRED},
|
||||
{sfAssetsAvailable, soeREQUIRED},
|
||||
{sfAssetsTotal, soeDEFAULT},
|
||||
{sfAssetsAvailable, soeDEFAULT},
|
||||
{sfAssetsMaximum, soeDEFAULT},
|
||||
{sfLossUnrealized, soeREQUIRED},
|
||||
{sfLossUnrealized, soeDEFAULT},
|
||||
{sfShareMPTID, soeREQUIRED},
|
||||
{sfWithdrawalPolicy, soeREQUIRED},
|
||||
{sfScale, soeDEFAULT},
|
||||
|
||||
Reference in New Issue
Block a user