Skip to content

Commit 0175dd7

Browse files
committed
Catch up the consequences of Number changes
- Change the Number::maxIntValue to all 9's. - Add integral() to Asset (copied from Lending) - Add toNumber() functions to STAmount, MPTAmount, XRPAmount to allow explicit conversions with enforcement options. - Add optional Number::EnforceInteger options to STAmount and STNumber ctors, conversions, etc. IOUs are never checked. - Update Vault transactors, and helper functions, to check restrictions. - Fix and add Vault tests.
1 parent cb6df19 commit 0175dd7

File tree

15 files changed

+274
-24
lines changed

15 files changed

+274
-24
lines changed

include/xrpl/basics/Number.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ class Number
5353
constexpr static rep maxMantissa = minMantissa * 10 - 1;
5454
static_assert(maxMantissa == 9'999'999'999'999'999LL);
5555

56-
constexpr static rep maxIntValue = minMantissa / 10;
56+
constexpr static rep maxIntValue = maxMantissa / 10;
57+
static_assert(maxIntValue == 999'999'999'999'999LL);
5758

5859
// The range for the exponent when normalized
5960
constexpr static int minExponent = -32768;

include/xrpl/protocol/Asset.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ class Asset
8484
return holds<Issue>() && get<Issue>().native();
8585
}
8686

87+
bool
88+
integral() const
89+
{
90+
return !holds<Issue>() || get<Issue>().native();
91+
}
92+
8793
friend constexpr bool
8894
operator==(Asset const& lhs, Asset const& rhs);
8995

include/xrpl/protocol/MPTAmount.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,17 @@ class MPTAmount : private boost::totally_ordered<MPTAmount>,
6262
explicit constexpr
6363
operator bool() const noexcept;
6464

65-
operator Number() const noexcept
65+
operator Number() const
6666
{
6767
return {value(), Number::strong};
6868
}
6969

70+
Number
71+
toNumber(Number::EnforceInteger enforce) const
72+
{
73+
return {value(), enforce};
74+
}
75+
7076
/** Return the sign of the amount */
7177
constexpr int
7278
signum() const noexcept;

include/xrpl/protocol/STAmount.h

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ class STAmount final : public STBase, public CountedObject<STAmount>
4040
exponent_type mOffset;
4141
bool mIsNegative;
4242

43+
// The Enforce integer setting is not stored or serialized. If set, it is
44+
// used during automatic conversions to Number. If not set, the default
45+
// behavior is used. It can also be overridden when coverting by using
46+
// toNumber().
47+
std::optional<Number::EnforceInteger> enforceConversion_;
48+
4349
public:
4450
using value_type = STAmount;
4551

@@ -135,16 +141,46 @@ class STAmount final : public STBase, public CountedObject<STAmount>
135141
STAmount(A const& asset, int mantissa, int exponent = 0);
136142

137143
template <AssetType A>
138-
STAmount(A const& asset, Number const& number)
144+
STAmount(
145+
A const& asset,
146+
Number const& number,
147+
std::optional<Number::EnforceInteger> enforce = std::nullopt)
139148
: STAmount(asset, number.mantissa(), number.exponent())
140149
{
150+
enforceConversion_ = enforce;
151+
if (!enforce)
152+
{
153+
// Use the default conversion behavior
154+
[[maybe_unused]]
155+
Number const n = *this;
156+
}
157+
else if (enforce == Number::strong)
158+
{
159+
// Throw if it's not valid
160+
if (!validNumber())
161+
{
162+
Throw<std::overflow_error>(
163+
"STAmount::STAmount integer Number lost precision");
164+
}
165+
}
141166
}
142167

143168
// Legacy support for new-style amounts
144169
STAmount(IOUAmount const& amount, Issue const& issue);
145170
STAmount(XRPAmount const& amount);
146171
STAmount(MPTAmount const& amount, MPTIssue const& mptIssue);
147172
operator Number() const;
173+
Number
174+
toNumber(Number::EnforceInteger enforce) const;
175+
176+
void
177+
setIntegerEnforcement(std::optional<Number::EnforceInteger> enforce);
178+
179+
std::optional<Number::EnforceInteger>
180+
integerEnforcement() const noexcept;
181+
182+
bool
183+
validNumber() const noexcept;
148184

149185
//--------------------------------------------------------------------------
150186
//
@@ -155,6 +191,9 @@ class STAmount final : public STBase, public CountedObject<STAmount>
155191
int
156192
exponent() const noexcept;
157193

194+
bool
195+
integral() const noexcept;
196+
158197
bool
159198
native() const noexcept;
160199

@@ -435,6 +474,12 @@ STAmount::exponent() const noexcept
435474
return mOffset;
436475
}
437476

477+
inline bool
478+
STAmount::integral() const noexcept
479+
{
480+
return mAsset.integral();
481+
}
482+
438483
inline bool
439484
STAmount::native() const noexcept
440485
{
@@ -510,13 +555,26 @@ inline STAmount::operator bool() const noexcept
510555

511556
inline STAmount::operator Number() const
512557
{
558+
if (enforceConversion_)
559+
return toNumber(*enforceConversion_);
513560
if (native())
514561
return xrp();
515562
if (mAsset.holds<MPTIssue>())
516563
return mpt();
517564
return iou();
518565
}
519566

567+
inline Number
568+
STAmount::toNumber(Number::EnforceInteger enforce) const
569+
{
570+
if (native())
571+
return xrp().toNumber(enforce);
572+
if (mAsset.holds<MPTIssue>())
573+
return mpt().toNumber(enforce);
574+
// It doesn't make sense to enforce limits on IOUs
575+
return iou();
576+
}
577+
520578
inline STAmount&
521579
STAmount::operator=(beast::Zero)
522580
{
@@ -538,6 +596,11 @@ STAmount::operator=(Number const& number)
538596
mValue = mIsNegative ? -number.mantissa() : number.mantissa();
539597
mOffset = number.exponent();
540598
canonicalize();
599+
600+
// Convert it back to a Number to check that it's valid
601+
[[maybe_unused]]
602+
Number n = *this;
603+
541604
return *this;
542605
}
543606

@@ -553,7 +616,7 @@ STAmount::clear()
553616
{
554617
// The -100 is used to allow 0 to sort less than a small positive values
555618
// which have a negative exponent.
556-
mOffset = native() ? 0 : -100;
619+
mOffset = integral() ? 0 : -100;
557620
mValue = 0;
558621
mIsNegative = false;
559622
}

include/xrpl/protocol/STNumber.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ class STNumber : public STBase, public CountedObject<STNumber>
5656
bool
5757
isDefault() const override;
5858

59+
/// Sets the flag on the underlying number
60+
void
61+
setIntegerEnforcement(Number::EnforceInteger enforce);
62+
63+
/// Gets the flag value on the underlying number
64+
Number::EnforceInteger
65+
integerEnforcement() const noexcept;
66+
67+
/// Checks the underlying number
68+
bool
69+
valid() const noexcept;
70+
5971
operator Number() const
6072
{
6173
return value_;

include/xrpl/protocol/SystemParameters.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ systemName()
2323

2424
/** Number of drops in the genesis account. */
2525
constexpr XRPAmount INITIAL_XRP{100'000'000'000 * DROPS_PER_XRP};
26+
static_assert(INITIAL_XRP.drops() == 100'000'000'000'000'000);
2627

2728
/** Returns true if the amount does not exceed the initial XRP in existence. */
2829
inline bool

include/xrpl/protocol/XRPAmount.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ class XRPAmount : private boost::totally_ordered<XRPAmount>,
146146
return {drops(), Number::weak};
147147
}
148148

149+
Number
150+
toNumber(Number::EnforceInteger enforce) const
151+
{
152+
return {value(), enforce};
153+
}
154+
149155
/** Return the sign of the amount */
150156
constexpr int
151157
signum() const noexcept

src/libxrpl/ledger/View.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2878,13 +2878,17 @@ assetsToSharesDeposit(
28782878

28792879
Number const assetTotal = vault->at(sfAssetsTotal);
28802880
STAmount shares{vault->at(sfShareMPTID)};
2881+
shares.setIntegerEnforcement(Number::weak);
28812882
if (assetTotal == 0)
28822883
return STAmount{
28832884
shares.asset(),
28842885
Number(assets.mantissa(), assets.exponent() + vault->at(sfScale))
2885-
.truncate()};
2886+
.truncate(),
2887+
Number::weak};
28862888

2887-
Number const shareTotal = issuance->at(sfOutstandingAmount);
2889+
Number const shareTotal{
2890+
unsafe_cast<std::int64_t>(issuance->at(sfOutstandingAmount)),
2891+
Number::strong};
28882892
shares = (shareTotal * (assets / assetTotal)).truncate();
28892893
return shares;
28902894
}
@@ -2906,14 +2910,17 @@ sharesToAssetsDeposit(
29062910

29072911
Number const assetTotal = vault->at(sfAssetsTotal);
29082912
STAmount assets{vault->at(sfAsset)};
2913+
assets.setIntegerEnforcement(Number::weak);
29092914
if (assetTotal == 0)
29102915
return STAmount{
29112916
assets.asset(),
29122917
shares.mantissa(),
29132918
shares.exponent() - vault->at(sfScale),
29142919
false};
29152920

2916-
Number const shareTotal = issuance->at(sfOutstandingAmount);
2921+
Number const shareTotal{
2922+
unsafe_cast<std::int64_t>(issuance->at(sfOutstandingAmount)),
2923+
Number::strong};
29172924
assets = assetTotal * (shares / shareTotal);
29182925
return assets;
29192926
}
@@ -2937,9 +2944,12 @@ assetsToSharesWithdraw(
29372944
Number assetTotal = vault->at(sfAssetsTotal);
29382945
assetTotal -= vault->at(sfLossUnrealized);
29392946
STAmount shares{vault->at(sfShareMPTID)};
2947+
shares.setIntegerEnforcement(Number::weak);
29402948
if (assetTotal == 0)
29412949
return shares;
2942-
Number const shareTotal = issuance->at(sfOutstandingAmount);
2950+
Number const shareTotal{
2951+
unsafe_cast<std::int64_t>(issuance->at(sfOutstandingAmount)),
2952+
Number::strong};
29432953
Number result = shareTotal * (assets / assetTotal);
29442954
if (truncate == TruncateShares::yes)
29452955
result = result.truncate();
@@ -2965,9 +2975,12 @@ sharesToAssetsWithdraw(
29652975
Number assetTotal = vault->at(sfAssetsTotal);
29662976
assetTotal -= vault->at(sfLossUnrealized);
29672977
STAmount assets{vault->at(sfAsset)};
2978+
assets.setIntegerEnforcement(Number::weak);
29682979
if (assetTotal == 0)
29692980
return assets;
2970-
Number const shareTotal = issuance->at(sfOutstandingAmount);
2981+
Number const shareTotal{
2982+
unsafe_cast<std::int64_t>(issuance->at(sfOutstandingAmount)),
2983+
Number::strong};
29712984
assets = assetTotal * (shares / shareTotal);
29722985
return assets;
29732986
}

src/libxrpl/protocol/STAmount.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,25 @@ STAmount::move(std::size_t n, void* buf)
255255
return emplace(n, buf, std::move(*this));
256256
}
257257

258+
void
259+
STAmount::setIntegerEnforcement(std::optional<Number::EnforceInteger> enforce)
260+
{
261+
enforceConversion_ = enforce;
262+
}
263+
264+
std::optional<Number::EnforceInteger>
265+
STAmount::integerEnforcement() const noexcept
266+
{
267+
return enforceConversion_;
268+
}
269+
270+
bool
271+
STAmount::validNumber() const noexcept
272+
{
273+
Number n = toNumber(Number::EnforceInteger::weak);
274+
return n.valid();
275+
}
276+
258277
//------------------------------------------------------------------------------
259278
//
260279
// Conversion

src/libxrpl/protocol/STNumber.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,24 @@ STNumber::isDefault() const
9494
return value_ == Number();
9595
}
9696

97+
void
98+
STNumber::setIntegerEnforcement(Number::EnforceInteger enforce)
99+
{
100+
value_.setIntegerEnforcement(enforce);
101+
}
102+
103+
Number::EnforceInteger
104+
STNumber::integerEnforcement() const noexcept
105+
{
106+
return value_.integerEnforcement();
107+
}
108+
109+
bool
110+
STNumber::valid() const noexcept
111+
{
112+
return value_.valid();
113+
}
114+
97115
std::ostream&
98116
operator<<(std::ostream& out, STNumber const& rhs)
99117
{

0 commit comments

Comments
 (0)