Step 1: Convert Number to use 128-bit numbers internally

- Update the conversion points between Number and *Amount & STNumber.
- Tests probably don't pass.
This commit is contained in:
Ed Hennis
2025-11-12 00:26:13 -05:00
parent 33309480d4
commit d030fdaa2b
18 changed files with 419 additions and 88 deletions

View File

@@ -122,7 +122,7 @@ toAmount(
{
if (isXRP(issue))
return STAmount(issue, static_cast<std::int64_t>(n));
return STAmount(issue, n.mantissa(), n.exponent());
return STAmount(issue, n);
}
else
{

View File

@@ -84,6 +84,12 @@ public:
return holds<Issue>() && get<Issue>().native();
}
bool
integral() const
{
return !holds<Issue>() || get<Issue>().native();
}
friend constexpr bool
operator==(Asset const& lhs, Asset const& rhs);

View File

@@ -26,8 +26,10 @@ class IOUAmount : private boost::totally_ordered<IOUAmount>,
private boost::additive<IOUAmount>
{
private:
std::int64_t mantissa_;
int exponent_;
using mantissa_type = std::int64_t;
using exponent_type = int;
mantissa_type mantissa_;
exponent_type exponent_;
/** Adjusts the mantissa and exponent to the proper range.
@@ -38,11 +40,19 @@ private:
void
normalize();
IOUAmount(std::pair<mantissa_type, exponent_type> parts)
: IOUAmount(parts.first, parts.second)
{
}
static std::pair<mantissa_type, exponent_type>
scaleNumber(Number const& number);
public:
IOUAmount() = default;
explicit IOUAmount(Number const& other);
IOUAmount(beast::Zero);
IOUAmount(std::int64_t mantissa, int exponent);
IOUAmount(mantissa_type mantissa, exponent_type exponent);
IOUAmount& operator=(beast::Zero);
@@ -71,10 +81,10 @@ public:
int
signum() const noexcept;
int
exponent_type
exponent() const noexcept;
std::int64_t
mantissa_type
mantissa() const noexcept;
static IOUAmount
@@ -92,7 +102,7 @@ inline IOUAmount::IOUAmount(beast::Zero)
*this = beast::zero;
}
inline IOUAmount::IOUAmount(std::int64_t mantissa, int exponent)
inline IOUAmount::IOUAmount(mantissa_type mantissa, exponent_type exponent)
: mantissa_(mantissa), exponent_(exponent)
{
normalize();
@@ -149,13 +159,13 @@ IOUAmount::signum() const noexcept
return (mantissa_ < 0) ? -1 : (mantissa_ ? 1 : 0);
}
inline int
inline IOUAmount::exponent_type
IOUAmount::exponent() const noexcept
{
return exponent_;
}
inline std::int64_t
inline IOUAmount::mantissa_type
IOUAmount::mantissa() const noexcept
{
return mantissa_;

View File

@@ -37,6 +37,9 @@ public:
bool
native() const;
bool
integral() const;
friend constexpr std::weak_ordering
operator<=>(Issue const& lhs, Issue const& rhs);
};

View File

@@ -46,6 +46,12 @@ public:
{
return false;
}
bool
integral() const
{
return true;
}
};
constexpr bool

View File

@@ -47,9 +47,11 @@ public:
static int const cMaxOffset = 80;
// Maximum native value supported by the code
static std::uint64_t const cMinValue = 1000000000000000ull;
static std::uint64_t const cMaxValue = 9999999999999999ull;
static std::uint64_t const cMaxNative = 9000000000000000000ull;
constexpr static std::uint64_t cMinValue = 1'000'000'000'000'000ull;
static_assert(isPowerOfTen(cMinValue));
constexpr static std::uint64_t cMaxValue = cMinValue * 10 - 1;
static_assert(cMaxValue == 9'999'999'999'999'999ull);
static std::uint64_t const cMaxNative = 9'000'000'000'000'000'000ull;
// Max native value on network.
static std::uint64_t const cMaxNativeN = 100000000000000000ull;
@@ -136,7 +138,7 @@ public:
template <AssetType A>
STAmount(A const& asset, Number const& number)
: STAmount(asset, number.mantissa(), number.exponent())
: STAmount(asset, scaleNumber(asset, number))
{
}
@@ -155,6 +157,9 @@ public:
int
exponent() const noexcept;
bool
integral() const noexcept;
bool
native() const noexcept;
@@ -277,6 +282,22 @@ public:
mpt() const;
private:
template <AssetType A>
STAmount(
A const& asset,
std::tuple<mantissa_type, exponent_type, bool> parts)
: STAmount(
asset,
std::get<mantissa_type>(parts),
std::get<exponent_type>(parts),
std::get<bool>(parts))
{
}
template <AssetType A>
static std::tuple<mantissa_type, exponent_type, bool>
scaleNumber(A const& asset, Number const& number);
static std::unique_ptr<STAmount>
construct(SerialIter&, SField const& name);
@@ -435,6 +456,12 @@ STAmount::exponent() const noexcept
return mOffset;
}
inline bool
STAmount::integral() const noexcept
{
return mAsset.integral();
}
inline bool
STAmount::native() const noexcept
{
@@ -531,12 +558,29 @@ STAmount::operator=(XRPAmount const& amount)
return *this;
}
template <AssetType A>
inline std::tuple<STAmount::mantissa_type, STAmount::exponent_type, bool>
STAmount::scaleNumber(A const& asset, Number const& number)
{
bool const negative = number.mantissa() < 0;
if (asset.integral())
{
return std::make_tuple(std::int64_t(number), 0, negative);
}
else
{
Number const working{negative ? -number : number};
auto const [mantissa, exponent] =
working.normalizeToRange(cMinValue, cMaxValue);
return std::make_tuple(mantissa, exponent, negative);
}
}
inline STAmount&
STAmount::operator=(Number const& number)
{
mIsNegative = number.mantissa() < 0;
mValue = mIsNegative ? -number.mantissa() : number.mantissa();
mOffset = number.exponent();
std::tie(mValue, mOffset, mIsNegative) = scaleNumber(mAsset, number);
canonicalize();
return *this;
}
@@ -553,7 +597,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;
}

View File

@@ -482,6 +482,8 @@ public:
value_type
operator*() const;
/// Do not use operator->() unless the field is required, or you've checked
/// that it's set.
T const*
operator->() const;
@@ -718,6 +720,8 @@ STObject::Proxy<T>::operator*() const -> value_type
return this->value();
}
/// Do not use operator->() unless the field is required, or you've checked that
/// it's set.
template <class T>
T const*
STObject::Proxy<T>::operator->() const

View File

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

View File

@@ -479,10 +479,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},