mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-21 19:45:53 +00:00
Include rounding mode in XRPAmount to STAmount conversion.
This commit is contained in:
committed by
Elliot Lee
parent
6fcd654bee
commit
e354497f63
@@ -186,10 +186,6 @@ mulRatio(
|
||||
std::uint32_t den,
|
||||
bool roundUp);
|
||||
|
||||
// Since IOUAmount and STAmount do not have access to a ledger, this
|
||||
// is needed to put low-level routines on an amendment switch. Only
|
||||
// transactions need to use this switchover. Outside of a transaction
|
||||
// it's safe to unconditionally use the new behavior.
|
||||
extern LocalValue<bool> stNumberSwitchover;
|
||||
|
||||
/** RAII class to set and restore the Number switchover.
|
||||
|
||||
@@ -337,6 +337,24 @@ squelch(Number const& x, Number const& limit) noexcept
|
||||
return x;
|
||||
}
|
||||
|
||||
class saveNumberRoundMode
|
||||
{
|
||||
Number::rounding_mode mode_;
|
||||
|
||||
public:
|
||||
~saveNumberRoundMode()
|
||||
{
|
||||
Number::setround(mode_);
|
||||
}
|
||||
explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept
|
||||
: mode_{mode}
|
||||
{
|
||||
}
|
||||
saveNumberRoundMode(saveNumberRoundMode const&) = delete;
|
||||
saveNumberRoundMode&
|
||||
operator=(saveNumberRoundMode const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_BASICS_NUMBER_H_INCLUDED
|
||||
|
||||
@@ -725,24 +725,36 @@ STAmount::canonicalize()
|
||||
"Native currency amount out of range");
|
||||
}
|
||||
|
||||
while (mOffset < 0)
|
||||
if (*stNumberSwitchover && *stAmountCanonicalizeSwitchover)
|
||||
{
|
||||
mValue /= 10;
|
||||
++mOffset;
|
||||
Number num(
|
||||
mIsNegative ? -mValue : mValue, mOffset, Number::unchecked{});
|
||||
XRPAmount xrp{num};
|
||||
mIsNegative = xrp.drops() < 0;
|
||||
mValue = mIsNegative ? -xrp.drops() : xrp.drops();
|
||||
mOffset = 0;
|
||||
}
|
||||
|
||||
while (mOffset > 0)
|
||||
else
|
||||
{
|
||||
if (*stAmountCanonicalizeSwitchover)
|
||||
while (mOffset < 0)
|
||||
{
|
||||
// N.B. do not move the overflow check to after the
|
||||
// multiplication
|
||||
if (mValue > cMaxNativeN)
|
||||
Throw<std::runtime_error>(
|
||||
"Native currency amount out of range");
|
||||
mValue /= 10;
|
||||
++mOffset;
|
||||
}
|
||||
|
||||
while (mOffset > 0)
|
||||
{
|
||||
if (*stAmountCanonicalizeSwitchover)
|
||||
{
|
||||
// N.B. do not move the overflow check to after the
|
||||
// multiplication
|
||||
if (mValue > cMaxNativeN)
|
||||
Throw<std::runtime_error>(
|
||||
"Native currency amount out of range");
|
||||
}
|
||||
mValue *= 10;
|
||||
--mOffset;
|
||||
}
|
||||
mValue *= 10;
|
||||
--mOffset;
|
||||
}
|
||||
|
||||
if (mValue > cMaxNativeN)
|
||||
|
||||
@@ -2349,7 +2349,13 @@ class NFToken_test : public beast::unit_test::suite
|
||||
|
||||
// See the impact of rounding when the nft is sold for small amounts
|
||||
// of drops.
|
||||
for (auto NumberSwitchOver : {true})
|
||||
{
|
||||
if (NumberSwitchOver)
|
||||
env.enableFeature(fixUniversalNumber);
|
||||
else
|
||||
env.disableFeature(fixUniversalNumber);
|
||||
|
||||
// An nft with a transfer fee of 1 basis point.
|
||||
uint256 const nftID =
|
||||
token::getNextID(env, alice, 0u, tfTransferable, 1);
|
||||
@@ -2374,16 +2380,16 @@ class NFToken_test : public beast::unit_test::suite
|
||||
|
||||
// minter sells to carol. The payment is just small enough that
|
||||
// alice does not get any transfer fee.
|
||||
auto pmt = NumberSwitchOver ? drops(50000) : drops(99999);
|
||||
STAmount carolBalance = env.balance(carol);
|
||||
uint256 const minterSellOfferIndex =
|
||||
keylet::nftoffer(minter, env.seq(minter)).key;
|
||||
env(token::createOffer(minter, nftID, drops(99999)),
|
||||
txflags(tfSellNFToken));
|
||||
env(token::createOffer(minter, nftID, pmt), txflags(tfSellNFToken));
|
||||
env.close();
|
||||
env(token::acceptSellOffer(carol, minterSellOfferIndex));
|
||||
env.close();
|
||||
minterBalance += drops(99999) - fee;
|
||||
carolBalance -= drops(99999) + fee;
|
||||
minterBalance += pmt - fee;
|
||||
carolBalance -= pmt + fee;
|
||||
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
||||
BEAST_EXPECT(env.balance(minter) == minterBalance);
|
||||
BEAST_EXPECT(env.balance(carol) == carolBalance);
|
||||
@@ -2393,13 +2399,13 @@ class NFToken_test : public beast::unit_test::suite
|
||||
STAmount beckyBalance = env.balance(becky);
|
||||
uint256 const beckyBuyOfferIndex =
|
||||
keylet::nftoffer(becky, env.seq(becky)).key;
|
||||
env(token::createOffer(becky, nftID, drops(100000)),
|
||||
token::owner(carol));
|
||||
pmt = NumberSwitchOver ? drops(50001) : drops(100000);
|
||||
env(token::createOffer(becky, nftID, pmt), token::owner(carol));
|
||||
env.close();
|
||||
env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
|
||||
env.close();
|
||||
carolBalance += drops(99999) - fee;
|
||||
beckyBalance -= drops(100000) + fee;
|
||||
carolBalance += pmt - drops(1) - fee;
|
||||
beckyBalance -= pmt + fee;
|
||||
aliceBalance += drops(1);
|
||||
|
||||
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,24 +26,6 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class saveNumberRoundMode
|
||||
{
|
||||
Number::rounding_mode mode_;
|
||||
|
||||
public:
|
||||
~saveNumberRoundMode()
|
||||
{
|
||||
Number::setround(mode_);
|
||||
}
|
||||
explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept
|
||||
: mode_{mode}
|
||||
{
|
||||
}
|
||||
saveNumberRoundMode(saveNumberRoundMode const&) = delete;
|
||||
saveNumberRoundMode&
|
||||
operator=(saveNumberRoundMode const&) = delete;
|
||||
};
|
||||
|
||||
class Number_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
@@ -580,6 +562,29 @@ public:
|
||||
BEAST_EXPECT(x == y);
|
||||
}
|
||||
|
||||
void
|
||||
test_toSTAmount()
|
||||
{
|
||||
NumberSO stNumberSO{true};
|
||||
Issue const issue;
|
||||
Number const n{7'518'783'80596, -5};
|
||||
saveNumberRoundMode const save{Number::setround(Number::to_nearest)};
|
||||
auto res2 = STAmount{issue, n.mantissa(), n.exponent()};
|
||||
BEAST_EXPECT(res2 == STAmount{7518784});
|
||||
|
||||
Number::setround(Number::towards_zero);
|
||||
res2 = STAmount{issue, n.mantissa(), n.exponent()};
|
||||
BEAST_EXPECT(res2 == STAmount{7518783});
|
||||
|
||||
Number::setround(Number::downward);
|
||||
res2 = STAmount{issue, n.mantissa(), n.exponent()};
|
||||
BEAST_EXPECT(res2 == STAmount{7518783});
|
||||
|
||||
Number::setround(Number::upward);
|
||||
res2 = STAmount{issue, n.mantissa(), n.exponent()};
|
||||
BEAST_EXPECT(res2 == STAmount{7518784});
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@@ -599,6 +604,7 @@ public:
|
||||
test_relationals();
|
||||
test_stream();
|
||||
test_inc_dec();
|
||||
test_toSTAmount();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user