mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Refactor STAmount:
* Remove unused functions * Remove unused constructor * Use delegating constructors * Mark some observers deprecated * Clean up declaration parameter names * Add checked and unchecked constructors * De-inline unnecessary inlined functions * Reorder and regroup members into sections * Move globals from the unity file to the .cpp * Change some member functions to be free functions * Put implementation in one .cpp and the test in another .cpp Remove unused STAmount constructor and delegate two others No change in functionality.
This commit is contained in:
@@ -2598,7 +2598,7 @@
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\module\data\protocol\STAmount.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\data\protocol\STAmountRound.cpp">
|
||||
<ClCompile Include="..\..\src\ripple\module\data\protocol\STAmount.test.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\module\data\protocol\STArray.cpp">
|
||||
|
||||
@@ -3738,7 +3738,7 @@
|
||||
<ClInclude Include="..\..\src\ripple\module\data\protocol\STAmount.h">
|
||||
<Filter>ripple\module\data\protocol</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\data\protocol\STAmountRound.cpp">
|
||||
<ClCompile Include="..\..\src\ripple\module\data\protocol\STAmount.test.cpp">
|
||||
<Filter>ripple\module\data\protocol</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\module\data\protocol\STArray.cpp">
|
||||
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
Amount
|
||||
rate () const
|
||||
{
|
||||
return Amount::setRate (m_value);
|
||||
return amountFromQuality (m_value);
|
||||
}
|
||||
|
||||
/** Returns the scaled amount with in capped.
|
||||
|
||||
@@ -31,7 +31,7 @@ Quality::Quality (std::uint64_t value)
|
||||
}
|
||||
|
||||
Quality::Quality (Amounts const& amount)
|
||||
: m_value (Amount::getRate (amount.out, amount.in))
|
||||
: m_value (getRate (amount.out, amount.in))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ Quality::ceil_in (Amounts const& amount, Amount const& limit) const
|
||||
{
|
||||
if (amount.in > limit)
|
||||
{
|
||||
Amounts result (limit, Amount::divRound (
|
||||
Amounts result (limit, divRound (
|
||||
limit, rate(), amount.out, true));
|
||||
// Clamp out
|
||||
if (result.out > amount.out)
|
||||
@@ -89,7 +89,7 @@ Quality::ceil_out (Amounts const& amount, Amount const& limit) const
|
||||
{
|
||||
if (amount.out > limit)
|
||||
{
|
||||
Amounts result (Amount::mulRound (
|
||||
Amounts result (mulRound (
|
||||
limit, rate(), amount.in, true), limit);
|
||||
// Clamp in
|
||||
if (result.in > amount.in)
|
||||
@@ -110,10 +110,10 @@ composed_quality (Quality const& lhs, Quality const& rhs)
|
||||
Amount const rhs_rate (rhs.rate ());
|
||||
assert (rhs_rate != zero);
|
||||
|
||||
Amount const rate (Amount::mulRound (lhs_rate, rhs_rate, true));
|
||||
Amount const rate (mulRound (lhs_rate, rhs_rate, true));
|
||||
|
||||
std::uint64_t const stored_exponent (rate.getExponent () + 100);
|
||||
std::uint64_t const stored_mantissa (rate.getMantissa ());
|
||||
std::uint64_t const stored_exponent (rate.exponent () + 100);
|
||||
std::uint64_t const stored_mantissa (rate.mantissa());
|
||||
|
||||
assert ((stored_exponent > 0) && (stored_exponent <= 255));
|
||||
|
||||
|
||||
@@ -57,14 +57,14 @@ Taker::remaining_offer () const
|
||||
assert (m_remain.in > zero);
|
||||
|
||||
// We scale the output based on the remaining input:
|
||||
return Amounts (m_remain.in, Amount::divRound (
|
||||
return Amounts (m_remain.in, divRound (
|
||||
m_remain.in, m_quality.rate (), m_remain.out, true));
|
||||
}
|
||||
|
||||
assert (m_remain.out > zero);
|
||||
|
||||
// We scale the input based on the remaining output:
|
||||
return Amounts (Amount::mulRound (
|
||||
return Amounts (mulRound (
|
||||
m_remain.out, m_quality.rate (), m_remain.in, true), m_remain.out);
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ Taker::flow (Amounts amount, Offer const& offer, Account const& taker)
|
||||
{
|
||||
Amount const taker_charge (Amount::saFromRate (taker_charge_rate));
|
||||
amount = offer.quality ().ceil_in (amount,
|
||||
Amount::divide (taker_funds, taker_charge));
|
||||
divide (taker_funds, taker_charge));
|
||||
}
|
||||
|
||||
// Best flow the owner can get.
|
||||
@@ -118,7 +118,7 @@ Taker::flow (Amounts amount, Offer const& offer, Account const& taker)
|
||||
{
|
||||
Amount const owner_charge (Amount::saFromRate (owner_charge_rate));
|
||||
owner_amount = offer.quality ().ceil_out (owner_amount,
|
||||
Amount::divide (owner_funds, owner_charge));
|
||||
divide (owner_funds, owner_charge));
|
||||
}
|
||||
|
||||
// Calculate the amount that will flow through the offer
|
||||
|
||||
@@ -1278,7 +1278,7 @@ STAmount LedgerEntrySet::rippleTransferFee (
|
||||
STAmount saTransitRate (
|
||||
noIssue(), static_cast<std::uint64_t> (uTransitRate), -9);
|
||||
|
||||
STAmount saTransferTotal = STAmount::multiply (
|
||||
STAmount saTransferTotal = multiply (
|
||||
saAmount, saTransitRate, saAmount.issue ());
|
||||
STAmount saTransferFee = saTransferTotal - saAmount;
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
*/
|
||||
STAmount getCurrentRate () const
|
||||
{
|
||||
return STAmount::setRate (getCurrentQuality());
|
||||
return amountFromQuality (getCurrentQuality());
|
||||
}
|
||||
|
||||
/** Get the current quality
|
||||
|
||||
@@ -3140,7 +3140,7 @@ void NetworkOPsImp::getBookPage (
|
||||
else
|
||||
{
|
||||
uTipIndex = sleOfferDir->getIndex ();
|
||||
saDirRate = STAmount::setRate (Ledger::getQuality (uTipIndex));
|
||||
saDirRate = amountFromQuality (Ledger::getQuality (uTipIndex));
|
||||
|
||||
lesActive.dirFirst (
|
||||
uTipIndex, sleOfferDir, uBookEntry, offerIndex);
|
||||
@@ -3220,7 +3220,7 @@ void NetworkOPsImp::getBookPage (
|
||||
{
|
||||
// Need to charge a transfer fee to offer owner.
|
||||
uOfferRate = uTransferRate;
|
||||
saOwnerFundsLimit = STAmount::divide (
|
||||
saOwnerFundsLimit = divide (
|
||||
saOwnerFunds, STAmount (noIssue(), uOfferRate, -9));
|
||||
// TODO(tom): why -9?
|
||||
}
|
||||
@@ -3243,7 +3243,7 @@ void NetworkOPsImp::getBookPage (
|
||||
|
||||
saTakerGetsFunded.setJson (jvOffer[jss::taker_gets_funded]);
|
||||
std::min (
|
||||
saTakerPays, STAmount::multiply (
|
||||
saTakerPays, multiply (
|
||||
saTakerGetsFunded, saDirRate, saTakerPays)).setJson
|
||||
(jvOffer[jss::taker_pays_funded]);
|
||||
}
|
||||
@@ -3252,7 +3252,7 @@ void NetworkOPsImp::getBookPage (
|
||||
? saTakerGetsFunded
|
||||
: std::min (
|
||||
saOwnerFunds,
|
||||
STAmount::multiply (
|
||||
multiply (
|
||||
saTakerGetsFunded,
|
||||
STAmount (noIssue(),
|
||||
uOfferRate, -9)));
|
||||
@@ -3388,7 +3388,7 @@ void NetworkOPsImp::getBookPage (
|
||||
uOfferRate = uTransferRate;
|
||||
// TODO(tom): where does -9 come from?!
|
||||
STAmount amount (noIssue(), uOfferRate, -9);
|
||||
saOwnerFundsLimit = STAmount::divide (saOwnerFunds, amount);
|
||||
saOwnerFundsLimit = divide (saOwnerFunds, amount);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3410,7 +3410,7 @@ void NetworkOPsImp::getBookPage (
|
||||
|
||||
// TOOD(tom): The result of this expression is not used - what's
|
||||
// going on here?
|
||||
std::min (saTakerPays, STAmount::multiply (
|
||||
std::min (saTakerPays, multiply (
|
||||
saTakerGetsFunded, saDirRate, saTakerPays)).setJson (
|
||||
jvOffer[jss::taker_pays_funded]);
|
||||
}
|
||||
@@ -3418,7 +3418,7 @@ void NetworkOPsImp::getBookPage (
|
||||
STAmount saOwnerPays = (uOfferRate == QUALITY_ONE)
|
||||
? saTakerGetsFunded
|
||||
: std::min (saOwnerFunds,
|
||||
STAmount::multiply (
|
||||
multiply (
|
||||
saTakerGetsFunded, STAmount (
|
||||
noIssue(), uOfferRate,
|
||||
-9)));
|
||||
|
||||
@@ -268,7 +268,7 @@ int PathRequest::parseJson (Json::Value const& jvParams, bool complete)
|
||||
|
||||
if (jvParams.isMember ("destination_amount"))
|
||||
{
|
||||
if (!saDstAmount.bSetJson (jvParams["destination_amount"]) ||
|
||||
if (! amountFromJsonNoThrow (saDstAmount, jvParams["destination_amount"]) ||
|
||||
(saDstAmount.getCurrency ().isZero () && saDstAmount.getIssuer ().isNonZero ()) ||
|
||||
(saDstAmount.getCurrency () == badCurrency()) ||
|
||||
saDstAmount <= zero)
|
||||
|
||||
@@ -302,7 +302,7 @@ STPathSet Pathfinder::filterPaths(int iMaxPaths, STPath& extraPath)
|
||||
std::vector<path_LQ_t> vMap;
|
||||
|
||||
// Ignore paths that move only very small amounts
|
||||
auto saMinDstAmount = STAmount::divide(
|
||||
auto saMinDstAmount = divide(
|
||||
mDstAmount, STAmount(iMaxPaths + 2), mDstAmount);
|
||||
|
||||
// Build map of quality to entry.
|
||||
@@ -348,7 +348,7 @@ STPathSet Pathfinder::filterPaths(int iMaxPaths, STPath& extraPath)
|
||||
else
|
||||
{
|
||||
std::uint64_t uQuality (
|
||||
STAmount::getRate (rc.actualAmountOut, rc.actualAmountIn));
|
||||
getRate (rc.actualAmountOut, rc.actualAmountIn));
|
||||
|
||||
WriteLog (lsDEBUG, Pathfinder) <<
|
||||
"findPaths: quality: " << uQuality <<
|
||||
|
||||
@@ -193,7 +193,7 @@ TER RippleCalc::rippleCalculate ()
|
||||
// When processing, we don't want to complicate directory walking with
|
||||
// deletion.
|
||||
const std::uint64_t uQualityLimit = inputFlags.limitQuality ?
|
||||
STAmount::getRate (saDstAmountReq_, saMaxAmountReq_) : 0;
|
||||
getRate (saDstAmountReq_, saMaxAmountReq_) : 0;
|
||||
|
||||
// Offers that became unfunded.
|
||||
OfferSet unfundedOffersFromBestPaths;
|
||||
|
||||
@@ -103,7 +103,7 @@ TER PathCursor::advanceNode (bool const bReverse) const
|
||||
{
|
||||
// Our quality changed since last iteration.
|
||||
// Use the rate from the directory.
|
||||
node().saOfrRate = STAmount::setRate (
|
||||
node().saOfrRate = amountFromQuality (
|
||||
Ledger::getQuality (node().directory.current));
|
||||
// For correct ratio
|
||||
node().uEntry = 0;
|
||||
|
||||
@@ -97,14 +97,14 @@ TER PathCursor::deliverNodeForward (
|
||||
node().saRevDeliver - node().saFwdDeliver);
|
||||
|
||||
// Offer maximum in - Limited by by payout.
|
||||
auto saInFunded = STAmount::mulRound (
|
||||
auto saInFunded = mulRound (
|
||||
saOutPassFunded,
|
||||
node().saOfrRate,
|
||||
node().saTakerPays,
|
||||
true);
|
||||
|
||||
// Offer maximum in with fees.
|
||||
auto saInTotal = STAmount::mulRound (saInFunded, saInFeeRate, true);
|
||||
auto saInTotal = mulRound (saInFunded, saInFeeRate, true);
|
||||
auto saInRemaining = saInReq - saInAct - saInFees;
|
||||
|
||||
if (saInRemaining < zero)
|
||||
@@ -115,11 +115,11 @@ TER PathCursor::deliverNodeForward (
|
||||
|
||||
// In without fees.
|
||||
auto saInPassAct = std::min (
|
||||
node().saTakerPays, STAmount::divRound (
|
||||
node().saTakerPays, divRound (
|
||||
saInSum, saInFeeRate, true));
|
||||
|
||||
// Out limited by in remaining.
|
||||
auto outPass = STAmount::divRound (
|
||||
auto outPass = divRound (
|
||||
saInPassAct, node().saOfrRate, node().saTakerGets, true);
|
||||
STAmount saOutPassMax = std::min (saOutPassFunded, outPass);
|
||||
|
||||
@@ -235,10 +235,10 @@ TER PathCursor::deliverNodeForward (
|
||||
// previous.
|
||||
|
||||
assert (saOutPassAct < saOutPassMax);
|
||||
auto inPassAct = STAmount::mulRound (
|
||||
auto inPassAct = mulRound (
|
||||
saOutPassAct, node().saOfrRate, saInReq, true);
|
||||
saInPassAct = std::min (node().saTakerPays, inPassAct);
|
||||
auto inPassFees = STAmount::mulRound (
|
||||
auto inPassFees = mulRound (
|
||||
saInPassAct, saInFeeRate, true);
|
||||
saInPassFees = std::min (saInPassFeesMax, inPassFees);
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ TER PathCursor::deliverNodeReverse (
|
||||
// as a cost to taker.
|
||||
//
|
||||
// Round down: prefer liquidity rather than microscopic fees.
|
||||
STAmount saOutPlusFees = STAmount::mulRound (
|
||||
STAmount saOutPlusFees = mulRound (
|
||||
saOutPassAct, saOutFeeRate, false);
|
||||
// Offer out with fees.
|
||||
|
||||
@@ -172,7 +172,7 @@ TER PathCursor::deliverNodeReverse (
|
||||
|
||||
// Round up: prefer liquidity rather than microscopic fees. But,
|
||||
// limit by requested.
|
||||
auto fee = STAmount::divRound (saOutPlusFees, saOutFeeRate, true);
|
||||
auto fee = divRound (saOutPlusFees, saOutFeeRate, true);
|
||||
saOutPassAct = std::min (saOutPassReq, fee);
|
||||
|
||||
WriteLog (lsTRACE, RippleCalc)
|
||||
@@ -183,7 +183,7 @@ TER PathCursor::deliverNodeReverse (
|
||||
}
|
||||
|
||||
// Compute portion of input needed to cover actual output.
|
||||
auto outputFee = STAmount::mulRound (
|
||||
auto outputFee = mulRound (
|
||||
saOutPassAct, node().saOfrRate, node().saTakerPays, true);
|
||||
STAmount saInPassReq = std::min (node().saTakerPays, outputFee);
|
||||
STAmount saInPassAct;
|
||||
@@ -248,10 +248,10 @@ TER PathCursor::deliverNodeReverse (
|
||||
if (saInPassAct < saInPassReq)
|
||||
{
|
||||
// Adjust output to conform to limited input.
|
||||
auto outputRequirements = STAmount::divRound (
|
||||
auto outputRequirements = divRound (
|
||||
saInPassAct, node().saOfrRate, node().saTakerGets, true);
|
||||
saOutPassAct = std::min (saOutPassReq, outputRequirements);
|
||||
auto outputFees = STAmount::mulRound (
|
||||
auto outputFees = mulRound (
|
||||
saOutPassAct, saOutFeeRate, true);
|
||||
saOutPlusFees = std::min (node().saOfferFunds, outputFees);
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ TER PathCursor::forwardLiquidityForAccount () const
|
||||
auto& saCurReceive = pathState_.outPass();
|
||||
STAmount saIssueCrd = uQualityIn >= QUALITY_ONE
|
||||
? previousNode().saFwdIssue // No fee.
|
||||
: STAmount::mulRound (
|
||||
: mulRound (
|
||||
previousNode().saFwdIssue,
|
||||
STAmount (noIssue(), uQualityIn, -9),
|
||||
true); // Amount to credit.
|
||||
|
||||
@@ -54,7 +54,7 @@ void PathCursor::nextIncrement (LedgerEntrySet const& lesCheckpoint) const
|
||||
throw std::runtime_error ("Made no progress.");
|
||||
|
||||
// Calculate relative quality.
|
||||
pathState_.setQuality(STAmount::getRate (
|
||||
pathState_.setQuality(getRate (
|
||||
pathState_.outPass(), pathState_.inPass()));
|
||||
|
||||
WriteLog (lsTRACE, RippleCalc)
|
||||
|
||||
@@ -126,7 +126,7 @@ void rippleLiquidity (
|
||||
// If the quality is worse than the previous
|
||||
WriteLog (lsTRACE, RippleCalc) << "rippleLiquidity: Fee";
|
||||
|
||||
std::uint64_t uRate = STAmount::getRate (
|
||||
std::uint64_t uRate = getRate (
|
||||
STAmount (uQualityOut), STAmount (uQualityIn));
|
||||
|
||||
// If the next rate is at least as good as the current rate, process.
|
||||
@@ -136,11 +136,11 @@ void rippleLiquidity (
|
||||
auto uCurIssuerID = saCur.getIssuer ();
|
||||
|
||||
// current actual = current request * (quality out / quality in).
|
||||
auto numerator = STAmount::mulRound (
|
||||
auto numerator = mulRound (
|
||||
saCur, uQualityOut, {currency, uCurIssuerID}, true);
|
||||
// True means "round up" to get best flow.
|
||||
|
||||
STAmount saCurIn = STAmount::divRound (
|
||||
STAmount saCurIn = divRound (
|
||||
numerator, uQualityIn, {currency, uCurIssuerID}, true);
|
||||
|
||||
WriteLog (lsTRACE, RippleCalc)
|
||||
@@ -169,11 +169,11 @@ void rippleLiquidity (
|
||||
// going the other way
|
||||
|
||||
Issue issue{currency, uCurIssuerID};
|
||||
auto numerator = STAmount::mulRound (
|
||||
auto numerator = mulRound (
|
||||
saPrv, uQualityIn, issue, true);
|
||||
// A part of current. All of previous. (Cur is the driver
|
||||
// variable.)
|
||||
STAmount saCurOut = STAmount::divRound (
|
||||
STAmount saCurOut = divRound (
|
||||
numerator, uQualityOut, issue, true);
|
||||
|
||||
WriteLog (lsTRACE, RippleCalc)
|
||||
|
||||
@@ -153,7 +153,7 @@ public:
|
||||
STAmount saTakerPays = mTxn.getFieldAmount (sfTakerPays);
|
||||
STAmount saTakerGets = mTxn.getFieldAmount (sfTakerGets);
|
||||
|
||||
if (!saTakerPays.isLegalNet () || !saTakerGets.isLegalNet ())
|
||||
if (!isLegalNet (saTakerPays) || !isLegalNet (saTakerGets))
|
||||
return temBAD_AMOUNT;
|
||||
|
||||
auto const& uPaysIssuerID = saTakerPays.getIssuer ();
|
||||
@@ -192,7 +192,7 @@ public:
|
||||
|
||||
// This is the original rate of this offer, and is the rate at which it will
|
||||
// be placed, even if crossing offers change the amounts.
|
||||
std::uint64_t const uRate = STAmount::getRate (saTakerGets, saTakerPays);
|
||||
std::uint64_t const uRate = getRate (saTakerGets, saTakerPays);
|
||||
|
||||
TER terResult (tesSUCCESS);
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
else
|
||||
maxSourceAmount = STAmount (
|
||||
{saDstAmount.getCurrency (), mTxnAccountID},
|
||||
saDstAmount.getMantissa (), saDstAmount.getExponent (),
|
||||
saDstAmount.mantissa(), saDstAmount.exponent (),
|
||||
saDstAmount < zero);
|
||||
auto const& uSrcCurrency = maxSourceAmount.getCurrency ();
|
||||
auto const& uDstCurrency = saDstAmount.getCurrency ();
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
"maxSourceAmount=" << maxSourceAmount.getFullText () <<
|
||||
" saDstAmount=" << saDstAmount.getFullText ();
|
||||
|
||||
if (!saDstAmount.isLegalNet () || !maxSourceAmount.isLegalNet ())
|
||||
if (!isLegalNet (saDstAmount) || !isLegalNet (maxSourceAmount))
|
||||
return temBAD_AMOUNT;
|
||||
|
||||
if (uTxFlags & tfPaymentMask)
|
||||
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
std::uint32_t uQualityIn (bQualityIn ? mTxn.getFieldU32 (sfQualityIn) : 0);
|
||||
std::uint32_t uQualityOut (bQualityOut ? mTxn.getFieldU32 (sfQualityOut) : 0);
|
||||
|
||||
if (!saLimitAmount.isLegalNet ())
|
||||
if (!isLegalNet (saLimitAmount))
|
||||
return temBAD_AMOUNT;
|
||||
|
||||
if (bQualityOut && QUALITY_ONE == uQualityOut)
|
||||
|
||||
@@ -106,7 +106,7 @@ TER Transactor::payFee ()
|
||||
{
|
||||
STAmount saPaid = mTxn.getTransactionFee ();
|
||||
|
||||
if (!saPaid.isLegalNet ())
|
||||
if (!isLegalNet (saPaid))
|
||||
return temBAD_AMOUNT;
|
||||
|
||||
// Only check fee is sufficient when the ledger is open.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,18 @@ namespace ripple {
|
||||
// Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive
|
||||
class STAmount : public SerializedType
|
||||
{
|
||||
public:
|
||||
typedef std::uint64_t mantissa_type;
|
||||
typedef int exponent_type;
|
||||
typedef std::pair <mantissa_type, exponent_type> rep;
|
||||
|
||||
private:
|
||||
Issue mIssue;
|
||||
mantissa_type mValue;
|
||||
exponent_type mOffset;
|
||||
bool mIsNative; // A shorthand for isXRP(mIssue).
|
||||
bool mIsNegative;
|
||||
|
||||
public:
|
||||
static const int cMinOffset = -96;
|
||||
static const int cMaxOffset = 80;
|
||||
@@ -55,164 +67,168 @@ public:
|
||||
|
||||
static std::uint64_t uRateOne;
|
||||
|
||||
STAmount (std::uint64_t v = 0, bool negative = false)
|
||||
: mValue (v), mOffset (0), mIsNative (true), mIsNegative (negative)
|
||||
{
|
||||
if (v == 0) mIsNegative = false;
|
||||
}
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
STAmount (SField::ref n, std::uint64_t v = 0, bool negative = false)
|
||||
: SerializedType (n), mValue (v), mOffset (0), mIsNative (true),
|
||||
mIsNegative (negative)
|
||||
{
|
||||
}
|
||||
struct unchecked { };
|
||||
|
||||
STAmount (SField::ref n, std::int64_t v)
|
||||
: SerializedType (n), mOffset (0), mIsNative (true)
|
||||
{
|
||||
set (v);
|
||||
}
|
||||
// Calls canonicalize
|
||||
STAmount (SField::ref name, Issue const& issue,
|
||||
mantissa_type mantissa, exponent_type exponent,
|
||||
bool native, bool negative);
|
||||
|
||||
// Does not call canonicalize
|
||||
STAmount (SField::ref name, Issue const& issue,
|
||||
mantissa_type mantissa, exponent_type exponent,
|
||||
bool native, bool negative, unchecked);
|
||||
|
||||
STAmount (SField::ref name, std::int64_t mantissa);
|
||||
|
||||
STAmount (SField::ref name,
|
||||
std::uint64_t mantissa = 0, bool negative = false);
|
||||
|
||||
STAmount (SField::ref name, Issue const& issue,
|
||||
std::uint64_t mantissa = 0, int exponent = 0, bool negative = false);
|
||||
|
||||
STAmount (std::uint64_t mantissa = 0, bool negative = false);
|
||||
|
||||
STAmount (Issue const& issue,
|
||||
std::uint64_t uV = 0, int iOff = 0, bool negative = false)
|
||||
: mIssue(issue), mValue (uV), mOffset (iOff), mIsNegative (negative)
|
||||
{
|
||||
canonicalize ();
|
||||
}
|
||||
std::uint64_t mantissa = 0, int exponent = 0, bool negative = false);
|
||||
|
||||
// VFALCO Is this needed when we have the previous signature?
|
||||
STAmount (Issue const& issue,
|
||||
std::uint32_t uV, int iOff = 0, bool negative = false)
|
||||
: mIssue(issue), mValue (uV), mOffset (iOff), mIsNegative (negative)
|
||||
{
|
||||
canonicalize ();
|
||||
}
|
||||
std::uint32_t mantissa, int exponent = 0, bool negative = false);
|
||||
|
||||
STAmount (SField::ref n, Issue const& issue,
|
||||
std::uint64_t v = 0, int off = 0, bool negative = false) :
|
||||
SerializedType (n), mIssue(issue), mValue (v), mOffset (off),
|
||||
mIsNegative (negative)
|
||||
{
|
||||
canonicalize ();
|
||||
}
|
||||
STAmount (Issue const& issue, std::int64_t mantissa, int exponent = 0);
|
||||
|
||||
STAmount (Issue const& issue, std::int64_t v, int iOff = 0)
|
||||
: mIssue(issue), mOffset (iOff)
|
||||
{
|
||||
set (v);
|
||||
canonicalize ();
|
||||
}
|
||||
STAmount (Issue const& issue, int mantissa, int exponent = 0);
|
||||
|
||||
STAmount (SField::ref n, Issue const& issue, std::int64_t v, int off = 0)
|
||||
: SerializedType (n), mIssue(issue), mOffset (off)
|
||||
{
|
||||
set (v);
|
||||
canonicalize ();
|
||||
}
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
STAmount (Issue const& issue, int v, int iOff = 0)
|
||||
: mIssue(issue), mOffset (iOff)
|
||||
{
|
||||
set (v);
|
||||
canonicalize ();
|
||||
}
|
||||
private:
|
||||
static
|
||||
std::unique_ptr<STAmount>
|
||||
construct (SerializerIterator&, SField::ref name);
|
||||
|
||||
STAmount (SField::ref n, Issue const& issue, int v, int off = 0)
|
||||
: SerializedType (n), mIssue(issue), mOffset (off)
|
||||
{
|
||||
set (v);
|
||||
canonicalize ();
|
||||
}
|
||||
public:
|
||||
static
|
||||
STAmount
|
||||
createFromInt64 (SField::ref n, std::int64_t v);
|
||||
|
||||
STAmount (SField::ref, Json::Value const&);
|
||||
|
||||
static STAmount createFromInt64 (SField::ref n, std::int64_t v);
|
||||
|
||||
static std::unique_ptr<SerializedType> deserialize (
|
||||
static
|
||||
std::unique_ptr <SerializedType>
|
||||
deserialize (
|
||||
SerializerIterator& sit, SField::ref name)
|
||||
{
|
||||
return construct (sit, name);
|
||||
}
|
||||
|
||||
bool bSetJson (Json::Value const& jvSource);
|
||||
|
||||
static STAmount saFromRate (std::uint64_t uRate = 0)
|
||||
static
|
||||
STAmount
|
||||
saFromRate (std::uint64_t uRate = 0)
|
||||
{
|
||||
return STAmount (noIssue(), uRate, -9, false);
|
||||
}
|
||||
|
||||
SerializedTypeID getSType () const
|
||||
{
|
||||
return STI_AMOUNT;
|
||||
}
|
||||
std::string getText () const;
|
||||
std::string getFullText () const;
|
||||
void add (Serializer& s) const;
|
||||
static
|
||||
STAmount
|
||||
deserialize (SerializerIterator&);
|
||||
|
||||
int getExponent () const
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
std::uint64_t getMantissa () const
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Observers
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
int signum () const
|
||||
int exponent() const noexcept { return mOffset; }
|
||||
bool native() const noexcept { return mIsNative; }
|
||||
bool negative() const noexcept { return mIsNegative; }
|
||||
std::uint64_t mantissa() const noexcept { return mValue; }
|
||||
Issue const& issue() const { return mIssue; }
|
||||
|
||||
// These three are deprecated
|
||||
Currency const& getCurrency() const { return mIssue.currency; }
|
||||
Account const& getIssuer() const { return mIssue.account; }
|
||||
bool isNative() const { return mIsNative; }
|
||||
|
||||
int
|
||||
signum() const noexcept
|
||||
{
|
||||
return mValue ? (mIsNegative ? -1 : 1) : 0;
|
||||
}
|
||||
|
||||
// When the currency is XRP, the value in raw units. S=signed
|
||||
std::uint64_t getNValue () const
|
||||
{
|
||||
if (!mIsNative)
|
||||
throw std::runtime_error ("not native");
|
||||
|
||||
return mValue;
|
||||
}
|
||||
void setNValue (std::uint64_t v)
|
||||
{
|
||||
if (!mIsNative)
|
||||
throw std::runtime_error ("not native");
|
||||
|
||||
mValue = v;
|
||||
}
|
||||
std::int64_t getSNValue () const;
|
||||
void setSNValue (std::int64_t);
|
||||
|
||||
std::string getHumanCurrency () const;
|
||||
|
||||
bool isNative () const
|
||||
{
|
||||
return mIsNative;
|
||||
}
|
||||
bool isLegalNet () const
|
||||
{
|
||||
return !mIsNative || (mValue <= cMaxNativeN);
|
||||
}
|
||||
|
||||
explicit
|
||||
operator bool () const noexcept
|
||||
{
|
||||
return *this != zero;
|
||||
}
|
||||
|
||||
void negate ()
|
||||
{
|
||||
if (*this != zero)
|
||||
mIsNegative = !mIsNegative;
|
||||
}
|
||||
|
||||
/** @return a copy of amount with the same Issuer and Currency but zero
|
||||
value. */
|
||||
STAmount zeroed() const
|
||||
|
||||
/** Returns a zero value with the same issuer and currency. */
|
||||
STAmount
|
||||
zeroed() const
|
||||
{
|
||||
// TODO(tom): what does this next comment mean here?
|
||||
// See https://ripplelabs.atlassian.net/browse/WC-1847?jql=
|
||||
return STAmount (mIssue);
|
||||
}
|
||||
|
||||
void clear ()
|
||||
// When the currency is XRP, the value in raw unsigned units.
|
||||
std::uint64_t
|
||||
getNValue() const;
|
||||
|
||||
// When the currency is XRP, the value in raw signed units.
|
||||
std::int64_t
|
||||
getSNValue() const;
|
||||
|
||||
// VFALCO TODO This can be a free function or just call the
|
||||
// member on the issue.
|
||||
std::string
|
||||
getHumanCurrency() const;
|
||||
|
||||
void
|
||||
setJson (Json::Value&) const;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Operators
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return *this != zero;
|
||||
}
|
||||
|
||||
bool isComparable (STAmount const&) const;
|
||||
void throwComparable (STAmount const&) const;
|
||||
|
||||
STAmount& operator+= (STAmount const&);
|
||||
STAmount& operator-= (STAmount const&);
|
||||
STAmount& operator+= (std::uint64_t);
|
||||
STAmount& operator-= (std::uint64_t);
|
||||
|
||||
STAmount& operator= (std::uint64_t);
|
||||
STAmount& operator= (beast::Zero)
|
||||
{
|
||||
clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend STAmount operator+ (STAmount const& v1, STAmount const& v2);
|
||||
friend STAmount operator- (STAmount const& v1, STAmount const& v2);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Modification
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// VFALCO TODO Remove this, it is only called from the unit test
|
||||
void roundSelf();
|
||||
|
||||
void setNValue (std::uint64_t v);
|
||||
void setSNValue (std::int64_t);
|
||||
|
||||
void negate()
|
||||
{
|
||||
if (*this != zero)
|
||||
mIsNegative = !mIsNegative;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
// VFALCO: Why -100?
|
||||
mOffset = mIsNative ? 0 : -100;
|
||||
@@ -223,26 +239,13 @@ public:
|
||||
// Zero while copying currency and issuer.
|
||||
void clear (STAmount const& saTmpl)
|
||||
{
|
||||
clear(saTmpl.mIssue);
|
||||
clear (saTmpl.mIssue);
|
||||
}
|
||||
|
||||
void clear (Issue const& issue)
|
||||
{
|
||||
setIssue(issue);
|
||||
clear ();
|
||||
}
|
||||
|
||||
STAmount& operator=(beast::Zero)
|
||||
{
|
||||
clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
int compare (STAmount const&) const;
|
||||
|
||||
Account const& getIssuer () const
|
||||
{
|
||||
return mIssue.account;
|
||||
clear();
|
||||
}
|
||||
|
||||
void setIssuer (Account const& uIssuer)
|
||||
@@ -254,201 +257,208 @@ public:
|
||||
/** Set the Issue for this amount and update mIsNative. */
|
||||
void setIssue (Issue const& issue);
|
||||
|
||||
Currency const& getCurrency () const
|
||||
{
|
||||
return mIssue.currency;
|
||||
}
|
||||
|
||||
Issue const& issue () const
|
||||
{
|
||||
return mIssue;
|
||||
}
|
||||
|
||||
// VFALCO TODO Rename to setValueOnly (it only sets mantissa and exponent)
|
||||
// Make this private
|
||||
bool setValue (std::string const& sAmount);
|
||||
bool setFullValue (
|
||||
std::string const& sAmount, std::string const& sCurrency = "",
|
||||
std::string const& sIssuer = "");
|
||||
void setValue (STAmount const&);
|
||||
|
||||
virtual bool isEquivalent (const SerializedType& t) const;
|
||||
virtual bool isDefault () const
|
||||
bool setFullValue (std::string const& sAmount,
|
||||
std::string const& sCurrency = "", std::string const& sIssuer = "");
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// SerializedType
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
SerializedTypeID
|
||||
getSType() const override
|
||||
{
|
||||
return STI_AMOUNT;
|
||||
}
|
||||
|
||||
std::string
|
||||
getFullText() const override;
|
||||
|
||||
std::string
|
||||
getText() const override;
|
||||
|
||||
Json::Value
|
||||
getJson (int) const override;
|
||||
|
||||
void
|
||||
add (Serializer& s) const override;
|
||||
|
||||
bool
|
||||
isEquivalent (const SerializedType& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override
|
||||
{
|
||||
return (mValue == 0) && mIsNative;
|
||||
}
|
||||
|
||||
bool operator== (STAmount const&) const;
|
||||
bool operator!= (STAmount const&) const;
|
||||
bool operator< (STAmount const&) const;
|
||||
bool operator> (STAmount const&) const;
|
||||
bool operator<= (STAmount const&) const;
|
||||
bool operator>= (STAmount const&) const;
|
||||
bool isComparable (STAmount const&) const;
|
||||
void throwComparable (STAmount const&) const;
|
||||
|
||||
// native currency only
|
||||
bool operator< (std::uint64_t) const;
|
||||
bool operator> (std::uint64_t) const;
|
||||
bool operator<= (std::uint64_t) const;
|
||||
bool operator>= (std::uint64_t) const;
|
||||
STAmount operator+ (std::uint64_t) const;
|
||||
STAmount operator- (std::uint64_t) const;
|
||||
STAmount operator- (void) const;
|
||||
|
||||
STAmount& operator+= (STAmount const&);
|
||||
STAmount& operator-= (STAmount const&);
|
||||
STAmount& operator+= (std::uint64_t);
|
||||
STAmount& operator-= (std::uint64_t);
|
||||
STAmount& operator= (std::uint64_t);
|
||||
|
||||
operator double () const;
|
||||
|
||||
friend STAmount operator+ (STAmount const& v1, STAmount const& v2);
|
||||
friend STAmount operator- (STAmount const& v1, STAmount const& v2);
|
||||
|
||||
static STAmount divide (
|
||||
STAmount const& v1, STAmount const& v2, Issue const& issue);
|
||||
|
||||
static STAmount divide (
|
||||
STAmount const& v1, STAmount const& v2, STAmount const& saUnit)
|
||||
{
|
||||
return divide (v1, v2, saUnit.issue ());
|
||||
}
|
||||
static STAmount divide (STAmount const& v1, STAmount const& v2)
|
||||
{
|
||||
return divide (v1, v2, v1);
|
||||
}
|
||||
|
||||
static STAmount multiply (
|
||||
STAmount const& v1, STAmount const& v2, Issue const& issue);
|
||||
|
||||
static STAmount multiply (
|
||||
STAmount const& v1, STAmount const& v2, STAmount const& saUnit)
|
||||
{
|
||||
return multiply (v1, v2, saUnit.issue());
|
||||
}
|
||||
static STAmount multiply (STAmount const& v1, STAmount const& v2)
|
||||
{
|
||||
return multiply (v1, v2, v1);
|
||||
}
|
||||
|
||||
/* addRound, subRound can end up rounding if the amount subtracted is too small
|
||||
to make a change. Consder (X-d) where d is very small relative to X.
|
||||
If you ask to round down, then (X-d) should not be X unless d is zero.
|
||||
If you ask to round up, (X+d) should never be X unless d is zero. (Assuming X and d are positive).
|
||||
*/
|
||||
// Add, subtract, multiply, or divide rounding result in specified direction
|
||||
static STAmount addRound (
|
||||
STAmount const& v1, STAmount const& v2, bool roundUp);
|
||||
static STAmount subRound (
|
||||
STAmount const& v1, STAmount const& v2, bool roundUp);
|
||||
static STAmount mulRound (
|
||||
STAmount const& v1, STAmount const& v2, Issue const& issue,
|
||||
bool roundUp);
|
||||
static STAmount divRound (
|
||||
STAmount const& v1, STAmount const& v2, Issue const& issue,
|
||||
bool roundUp);
|
||||
|
||||
static STAmount mulRound (
|
||||
STAmount const& v1, STAmount const& v2, STAmount const& saUnit,
|
||||
bool roundUp)
|
||||
{
|
||||
return mulRound (v1, v2, saUnit.issue (), roundUp);
|
||||
}
|
||||
static STAmount mulRound (
|
||||
STAmount const& v1, STAmount const& v2, bool roundUp)
|
||||
{
|
||||
return mulRound (v1, v2, v1.issue (), roundUp);
|
||||
}
|
||||
static STAmount divRound (
|
||||
STAmount const& v1, STAmount const& v2, STAmount const& saUnit,
|
||||
bool roundUp)
|
||||
{
|
||||
return divRound (v1, v2, saUnit.issue (), roundUp);
|
||||
}
|
||||
static STAmount divRound (
|
||||
STAmount const& v1, STAmount const& v2, bool roundUp)
|
||||
{
|
||||
return divRound (v1, v2, v1.issue (), roundUp);
|
||||
}
|
||||
|
||||
// Someone is offering X for Y, what is the rate?
|
||||
// Rate: smaller is better, the taker wants the most out: in/out
|
||||
static std::uint64_t getRate (
|
||||
STAmount const& offerOut, STAmount const& offerIn);
|
||||
static STAmount setRate (std::uint64_t rate);
|
||||
|
||||
// Someone is offering X for Y, I need Z, how much do I pay
|
||||
|
||||
// WARNING: most methods in rippled have parameters ordered "in, out" - this
|
||||
// one is ordered "out, in".
|
||||
static STAmount getPay (
|
||||
STAmount const& out, STAmount const& in, STAmount const& needed);
|
||||
|
||||
static STAmount deserialize (SerializerIterator&);
|
||||
|
||||
Json::Value getJson (int) const;
|
||||
void setJson (Json::Value&) const;
|
||||
|
||||
STAmount getRound () const;
|
||||
void roundSelf ();
|
||||
|
||||
static void canonicalizeRound (
|
||||
bool isNative, std::uint64_t& value, int& offset, bool roundUp);
|
||||
|
||||
private:
|
||||
Issue mIssue;
|
||||
STAmount*
|
||||
duplicate() const override;
|
||||
|
||||
std::uint64_t mValue;
|
||||
int mOffset;
|
||||
bool mIsNative; // A shorthand for isXRP(mIssue).
|
||||
bool mIsNegative;
|
||||
|
||||
void canonicalize ();
|
||||
STAmount* duplicate () const
|
||||
{
|
||||
return new STAmount (*this);
|
||||
}
|
||||
|
||||
static
|
||||
std::unique_ptr<STAmount>
|
||||
construct (SerializerIterator&, SField::ref name);
|
||||
|
||||
STAmount (SField::ref name, Issue const& issue,
|
||||
std::uint64_t val, int off, bool isNat, bool negative)
|
||||
: SerializedType (name), mIssue(issue), mValue (val),
|
||||
mOffset (off), mIsNative (isNat), mIsNegative (negative)
|
||||
{
|
||||
}
|
||||
|
||||
void set (std::int64_t v)
|
||||
{
|
||||
if (v < 0)
|
||||
{
|
||||
mIsNegative = true;
|
||||
mValue = static_cast<std::uint64_t> (-v);
|
||||
}
|
||||
else
|
||||
{
|
||||
mIsNegative = false;
|
||||
mValue = static_cast<std::uint64_t> (v);
|
||||
}
|
||||
}
|
||||
|
||||
void set (int v)
|
||||
{
|
||||
if (v < 0)
|
||||
{
|
||||
mIsNegative = true;
|
||||
mValue = static_cast<std::uint64_t> (-v);
|
||||
}
|
||||
else
|
||||
{
|
||||
mIsNegative = false;
|
||||
mValue = static_cast<std::uint64_t> (v);
|
||||
}
|
||||
}
|
||||
void canonicalize();
|
||||
void set (std::int64_t v);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Creation
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// VFALCO TODO The parameter type should be Quality not uint64_t
|
||||
STAmount
|
||||
amountFromQuality (std::uint64_t rate);
|
||||
|
||||
STAmount
|
||||
amountFromJson (SField::ref name, Json::Value const& v);
|
||||
|
||||
bool
|
||||
amountFromJsonNoThrow (STAmount& result, Json::Value const& jvSource);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Observers
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline
|
||||
bool
|
||||
isLegalNet (STAmount const& value)
|
||||
{
|
||||
return ! value.native() || (value.mantissa() <= STAmount::cMaxNativeN);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Operators
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool operator== (STAmount const& lhs, STAmount const& rhs);
|
||||
bool operator!= (STAmount const& lhs, STAmount const& rhs);
|
||||
bool operator< (STAmount const& lhs, STAmount const& rhs);
|
||||
bool operator> (STAmount const& lhs, STAmount const& rhs);
|
||||
bool operator<= (STAmount const& lhs, STAmount const& rhs);
|
||||
bool operator>= (STAmount const& lhs, STAmount const& rhs);
|
||||
|
||||
// native currency only
|
||||
bool operator< (STAmount const& lhs, std::uint64_t rhs);
|
||||
bool operator> (STAmount const& lhs, std::uint64_t rhs);
|
||||
bool operator<= (STAmount const& lhs, std::uint64_t rhs);
|
||||
bool operator>= (STAmount const& lhs, std::uint64_t rhs);
|
||||
|
||||
STAmount operator+ (STAmount const& lhs, std::uint64_t rhs);
|
||||
STAmount operator- (STAmount const& lhs, std::uint64_t rhs);
|
||||
STAmount operator- (STAmount const& value);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Arithmetic
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
STAmount
|
||||
divide (STAmount const& v1, STAmount const& v2, Issue const& issue);
|
||||
|
||||
inline
|
||||
STAmount
|
||||
divide (STAmount const& v1, STAmount const& v2, STAmount const& saUnit)
|
||||
{
|
||||
return divide (v1, v2, saUnit.issue());
|
||||
}
|
||||
|
||||
inline
|
||||
STAmount
|
||||
divide (STAmount const& v1, STAmount const& v2)
|
||||
{
|
||||
return divide (v1, v2, v1);
|
||||
}
|
||||
|
||||
STAmount
|
||||
multiply (STAmount const& v1, STAmount const& v2, Issue const& issue);
|
||||
|
||||
inline
|
||||
STAmount
|
||||
multiply (STAmount const& v1, STAmount const& v2, STAmount const& saUnit)
|
||||
{
|
||||
return multiply (v1, v2, saUnit.issue());
|
||||
}
|
||||
|
||||
inline
|
||||
STAmount
|
||||
multiply (STAmount const& v1, STAmount const& v2)
|
||||
{
|
||||
return multiply (v1, v2, v1);
|
||||
}
|
||||
|
||||
void
|
||||
canonicalizeRound (bool native, std::uint64_t& mantissa,
|
||||
int& exponent, bool roundUp);
|
||||
|
||||
/* addRound, subRound can end up rounding if the amount subtracted is too small
|
||||
to make a change. Consder (X-d) where d is very small relative to X.
|
||||
If you ask to round down, then (X-d) should not be X unless d is zero.
|
||||
If you ask to round up, (X+d) should never be X unless d is zero. (Assuming X and d are positive).
|
||||
*/
|
||||
// Add, subtract, multiply, or divide rounding result in specified direction
|
||||
STAmount
|
||||
addRound (STAmount const& v1, STAmount const& v2, bool roundUp);
|
||||
|
||||
STAmount
|
||||
subRound (STAmount const& v1, STAmount const& v2, bool roundUp);
|
||||
|
||||
STAmount
|
||||
mulRound (STAmount const& v1, STAmount const& v2,
|
||||
Issue const& issue, bool roundUp);
|
||||
|
||||
inline
|
||||
STAmount
|
||||
mulRound (STAmount const& v1, STAmount const& v2,
|
||||
STAmount const& saUnit, bool roundUp)
|
||||
{
|
||||
return mulRound (v1, v2, saUnit.issue(), roundUp);
|
||||
}
|
||||
|
||||
inline
|
||||
STAmount
|
||||
mulRound (STAmount const& v1, STAmount const& v2, bool roundUp)
|
||||
{
|
||||
return mulRound (v1, v2, v1.issue(), roundUp);
|
||||
}
|
||||
|
||||
STAmount
|
||||
divRound (STAmount const& v1, STAmount const& v2,
|
||||
Issue const& issue, bool roundUp);
|
||||
|
||||
inline
|
||||
STAmount
|
||||
divRound (STAmount const& v1, STAmount const& v2,
|
||||
STAmount const& saUnit, bool roundUp)
|
||||
{
|
||||
return divRound (v1, v2, saUnit.issue(), roundUp);
|
||||
}
|
||||
|
||||
inline
|
||||
STAmount
|
||||
divRound (STAmount const& v1, STAmount const& v2, bool roundUp)
|
||||
{
|
||||
return divRound (v1, v2, v1.issue(), roundUp);
|
||||
}
|
||||
|
||||
// Someone is offering X for Y, what is the rate?
|
||||
// Rate: smaller is better, the taker wants the most out: in/out
|
||||
// VFALCO TODO Return a Quality object
|
||||
std::uint64_t
|
||||
getRate (STAmount const& offerOut, STAmount const& offerIn);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline bool isXRP(STAmount const& amount)
|
||||
{
|
||||
return isXRP (amount.issue().currency);
|
||||
|
||||
528
src/ripple/module/data/protocol/STAmount.test.cpp
Normal file
528
src/ripple/module/data/protocol/STAmount.test.cpp
Normal file
@@ -0,0 +1,528 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/module/data/protocol/STAmount.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class STAmount_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
static STAmount serializeAndDeserialize (STAmount const& s)
|
||||
{
|
||||
Serializer ser;
|
||||
s.add (ser);
|
||||
|
||||
SerializerIterator sit (ser);
|
||||
return STAmount::deserialize (sit);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
bool roundTest (int n, int d, int m)
|
||||
{
|
||||
// check STAmount rounding
|
||||
STAmount num (noIssue(), n);
|
||||
STAmount den (noIssue(), d);
|
||||
STAmount mul (noIssue(), m);
|
||||
STAmount quot = divide (n, d, noIssue());
|
||||
STAmount res = multiply (quot, mul, noIssue());
|
||||
|
||||
expect (! res.isNative (), "Product should not be native");
|
||||
|
||||
res.roundSelf ();
|
||||
|
||||
STAmount cmp (noIssue(), (n * m) / d);
|
||||
|
||||
expect (! cmp.isNative (), "Comparison amount should not be native");
|
||||
|
||||
if (res != cmp)
|
||||
{
|
||||
cmp.throwComparable (res);
|
||||
|
||||
WriteLog (lsWARNING, STAmount) << "(" << num.getText () << "/" << den.getText () << ") X " << mul.getText () << " = "
|
||||
<< res.getText () << " not " << cmp.getText ();
|
||||
|
||||
fail ("Rounding");
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
pass ();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mulTest (int a, int b)
|
||||
{
|
||||
STAmount aa (noIssue(), a);
|
||||
STAmount bb (noIssue(), b);
|
||||
STAmount prod1 (multiply (aa, bb, noIssue()));
|
||||
|
||||
expect (! prod1.isNative ());
|
||||
|
||||
STAmount prod2 (noIssue(), static_cast<std::uint64_t> (a) * static_cast<std::uint64_t> (b));
|
||||
|
||||
if (prod1 != prod2)
|
||||
{
|
||||
WriteLog (lsWARNING, STAmount) << "nn(" << aa.getFullText () << " * " << bb.getFullText () << ") = " << prod1.getFullText ()
|
||||
<< " not " << prod2.getFullText ();
|
||||
|
||||
fail ("Multiplication result is not exact");
|
||||
}
|
||||
else
|
||||
{
|
||||
pass ();
|
||||
}
|
||||
|
||||
aa = a;
|
||||
prod1 = multiply (aa, bb, noIssue());
|
||||
|
||||
if (prod1 != prod2)
|
||||
{
|
||||
WriteLog (lsWARNING, STAmount) << "n(" << aa.getFullText () << " * " << bb.getFullText () << ") = " << prod1.getFullText ()
|
||||
<< " not " << prod2.getFullText ();
|
||||
fail ("Multiplication result is not exact");
|
||||
}
|
||||
else
|
||||
{
|
||||
pass ();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void testSetValue ()
|
||||
{
|
||||
testcase ("set value");
|
||||
|
||||
STAmount saTmp;
|
||||
|
||||
#if 0
|
||||
// Check native floats
|
||||
saTmp.setFullValue ("1^0");
|
||||
BOOST_CHECK_MESSAGE (SYSTEM_CURRENCY_PARTS == saTmp.getNValue (), "float integer failed");
|
||||
saTmp.setFullValue ("0^1");
|
||||
BOOST_CHECK_MESSAGE (SYSTEM_CURRENCY_PARTS / 10 == saTmp.getNValue (), "float fraction failed");
|
||||
saTmp.setFullValue ("0^12");
|
||||
BOOST_CHECK_MESSAGE (12 * SYSTEM_CURRENCY_PARTS / 100 == saTmp.getNValue (), "float fraction failed");
|
||||
saTmp.setFullValue ("1^2");
|
||||
BOOST_CHECK_MESSAGE (SYSTEM_CURRENCY_PARTS + (2 * SYSTEM_CURRENCY_PARTS / 10) == saTmp.getNValue (), "float combined failed");
|
||||
#endif
|
||||
|
||||
// Check native integer
|
||||
saTmp.setFullValue ("1");
|
||||
expect (1 == saTmp.getNValue (), "should be equal");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void testNativeCurrency ()
|
||||
{
|
||||
testcase ("native currency");
|
||||
STAmount zeroSt, one (1), hundred (100);
|
||||
// VFALCO NOTE Why repeat "STAmount fail" so many times??
|
||||
unexpected (serializeAndDeserialize (zeroSt) != zeroSt, "STAmount fail");
|
||||
unexpected (serializeAndDeserialize (one) != one, "STAmount fail");
|
||||
unexpected (serializeAndDeserialize (hundred) != hundred, "STAmount fail");
|
||||
unexpected (!zeroSt.isNative (), "STAmount fail");
|
||||
unexpected (!hundred.isNative (), "STAmount fail");
|
||||
unexpected (zeroSt != zero, "STAmount fail");
|
||||
unexpected (one == zero, "STAmount fail");
|
||||
unexpected (hundred == zero, "STAmount fail");
|
||||
unexpected ((zeroSt < zeroSt), "STAmount fail");
|
||||
unexpected (! (zeroSt < one), "STAmount fail");
|
||||
unexpected (! (zeroSt < hundred), "STAmount fail");
|
||||
unexpected ((one < zeroSt), "STAmount fail");
|
||||
unexpected ((one < one), "STAmount fail");
|
||||
unexpected (! (one < hundred), "STAmount fail");
|
||||
unexpected ((hundred < zeroSt), "STAmount fail");
|
||||
unexpected ((hundred < one), "STAmount fail");
|
||||
unexpected ((hundred < hundred), "STAmount fail");
|
||||
unexpected ((zeroSt > zeroSt), "STAmount fail");
|
||||
unexpected ((zeroSt > one), "STAmount fail");
|
||||
unexpected ((zeroSt > hundred), "STAmount fail");
|
||||
unexpected (! (one > zeroSt), "STAmount fail");
|
||||
unexpected ((one > one), "STAmount fail");
|
||||
unexpected ((one > hundred), "STAmount fail");
|
||||
unexpected (! (hundred > zeroSt), "STAmount fail");
|
||||
unexpected (! (hundred > one), "STAmount fail");
|
||||
unexpected ((hundred > hundred), "STAmount fail");
|
||||
unexpected (! (zeroSt <= zeroSt), "STAmount fail");
|
||||
unexpected (! (zeroSt <= one), "STAmount fail");
|
||||
unexpected (! (zeroSt <= hundred), "STAmount fail");
|
||||
unexpected ((one <= zeroSt), "STAmount fail");
|
||||
unexpected (! (one <= one), "STAmount fail");
|
||||
unexpected (! (one <= hundred), "STAmount fail");
|
||||
unexpected ((hundred <= zeroSt), "STAmount fail");
|
||||
unexpected ((hundred <= one), "STAmount fail");
|
||||
unexpected (! (hundred <= hundred), "STAmount fail");
|
||||
unexpected (! (zeroSt >= zeroSt), "STAmount fail");
|
||||
unexpected ((zeroSt >= one), "STAmount fail");
|
||||
unexpected ((zeroSt >= hundred), "STAmount fail");
|
||||
unexpected (! (one >= zeroSt), "STAmount fail");
|
||||
unexpected (! (one >= one), "STAmount fail");
|
||||
unexpected ((one >= hundred), "STAmount fail");
|
||||
unexpected (! (hundred >= zeroSt), "STAmount fail");
|
||||
unexpected (! (hundred >= one), "STAmount fail");
|
||||
unexpected (! (hundred >= hundred), "STAmount fail");
|
||||
unexpected (! (zeroSt == zeroSt), "STAmount fail");
|
||||
unexpected ((zeroSt == one), "STAmount fail");
|
||||
unexpected ((zeroSt == hundred), "STAmount fail");
|
||||
unexpected ((one == zeroSt), "STAmount fail");
|
||||
unexpected (! (one == one), "STAmount fail");
|
||||
unexpected ((one == hundred), "STAmount fail");
|
||||
unexpected ((hundred == zeroSt), "STAmount fail");
|
||||
unexpected ((hundred == one), "STAmount fail");
|
||||
unexpected (! (hundred == hundred), "STAmount fail");
|
||||
unexpected ((zeroSt != zeroSt), "STAmount fail");
|
||||
unexpected (! (zeroSt != one), "STAmount fail");
|
||||
unexpected (! (zeroSt != hundred), "STAmount fail");
|
||||
unexpected (! (one != zeroSt), "STAmount fail");
|
||||
unexpected ((one != one), "STAmount fail");
|
||||
unexpected (! (one != hundred), "STAmount fail");
|
||||
unexpected (! (hundred != zeroSt), "STAmount fail");
|
||||
unexpected (! (hundred != one), "STAmount fail");
|
||||
unexpected ((hundred != hundred), "STAmount fail");
|
||||
unexpected (STAmount ().getText () != "0", "STAmount fail");
|
||||
unexpected (STAmount (31).getText () != "31", "STAmount fail");
|
||||
unexpected (STAmount (310).getText () != "310", "STAmount fail");
|
||||
unexpected (to_string (Currency ()) != "XRP", "cHC(XRP)");
|
||||
Currency c;
|
||||
unexpected (!to_currency (c, "USD"), "create USD currency");
|
||||
unexpected (to_string (c) != "USD", "check USD currency");
|
||||
|
||||
const std::string cur = "015841551A748AD2C1F76FF6ECB0CCCD00000000";
|
||||
unexpected (!to_currency (c, cur), "create custom currency");
|
||||
unexpected (to_string (c) != cur, "check custom currency");
|
||||
unexpected (c != Currency (cur), "check custom currency");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void testCustomCurrency ()
|
||||
{
|
||||
testcase ("custom currency");
|
||||
STAmount zeroSt (noIssue()), one (noIssue(), 1), hundred (noIssue(), 100);
|
||||
unexpected (serializeAndDeserialize (zeroSt) != zeroSt, "STAmount fail");
|
||||
unexpected (serializeAndDeserialize (one) != one, "STAmount fail");
|
||||
unexpected (serializeAndDeserialize (hundred) != hundred, "STAmount fail");
|
||||
unexpected (zeroSt.isNative (), "STAmount fail");
|
||||
unexpected (hundred.isNative (), "STAmount fail");
|
||||
unexpected (zeroSt != zero, "STAmount fail");
|
||||
unexpected (one == zero, "STAmount fail");
|
||||
unexpected (hundred == zero, "STAmount fail");
|
||||
unexpected ((zeroSt < zeroSt), "STAmount fail");
|
||||
unexpected (! (zeroSt < one), "STAmount fail");
|
||||
unexpected (! (zeroSt < hundred), "STAmount fail");
|
||||
unexpected ((one < zeroSt), "STAmount fail");
|
||||
unexpected ((one < one), "STAmount fail");
|
||||
unexpected (! (one < hundred), "STAmount fail");
|
||||
unexpected ((hundred < zeroSt), "STAmount fail");
|
||||
unexpected ((hundred < one), "STAmount fail");
|
||||
unexpected ((hundred < hundred), "STAmount fail");
|
||||
unexpected ((zeroSt > zeroSt), "STAmount fail");
|
||||
unexpected ((zeroSt > one), "STAmount fail");
|
||||
unexpected ((zeroSt > hundred), "STAmount fail");
|
||||
unexpected (! (one > zeroSt), "STAmount fail");
|
||||
unexpected ((one > one), "STAmount fail");
|
||||
unexpected ((one > hundred), "STAmount fail");
|
||||
unexpected (! (hundred > zeroSt), "STAmount fail");
|
||||
unexpected (! (hundred > one), "STAmount fail");
|
||||
unexpected ((hundred > hundred), "STAmount fail");
|
||||
unexpected (! (zeroSt <= zeroSt), "STAmount fail");
|
||||
unexpected (! (zeroSt <= one), "STAmount fail");
|
||||
unexpected (! (zeroSt <= hundred), "STAmount fail");
|
||||
unexpected ((one <= zeroSt), "STAmount fail");
|
||||
unexpected (! (one <= one), "STAmount fail");
|
||||
unexpected (! (one <= hundred), "STAmount fail");
|
||||
unexpected ((hundred <= zeroSt), "STAmount fail");
|
||||
unexpected ((hundred <= one), "STAmount fail");
|
||||
unexpected (! (hundred <= hundred), "STAmount fail");
|
||||
unexpected (! (zeroSt >= zeroSt), "STAmount fail");
|
||||
unexpected ((zeroSt >= one), "STAmount fail");
|
||||
unexpected ((zeroSt >= hundred), "STAmount fail");
|
||||
unexpected (! (one >= zeroSt), "STAmount fail");
|
||||
unexpected (! (one >= one), "STAmount fail");
|
||||
unexpected ((one >= hundred), "STAmount fail");
|
||||
unexpected (! (hundred >= zeroSt), "STAmount fail");
|
||||
unexpected (! (hundred >= one), "STAmount fail");
|
||||
unexpected (! (hundred >= hundred), "STAmount fail");
|
||||
unexpected (! (zeroSt == zeroSt), "STAmount fail");
|
||||
unexpected ((zeroSt == one), "STAmount fail");
|
||||
unexpected ((zeroSt == hundred), "STAmount fail");
|
||||
unexpected ((one == zeroSt), "STAmount fail");
|
||||
unexpected (! (one == one), "STAmount fail");
|
||||
unexpected ((one == hundred), "STAmount fail");
|
||||
unexpected ((hundred == zeroSt), "STAmount fail");
|
||||
unexpected ((hundred == one), "STAmount fail");
|
||||
unexpected (! (hundred == hundred), "STAmount fail");
|
||||
unexpected ((zeroSt != zeroSt), "STAmount fail");
|
||||
unexpected (! (zeroSt != one), "STAmount fail");
|
||||
unexpected (! (zeroSt != hundred), "STAmount fail");
|
||||
unexpected (! (one != zeroSt), "STAmount fail");
|
||||
unexpected ((one != one), "STAmount fail");
|
||||
unexpected (! (one != hundred), "STAmount fail");
|
||||
unexpected (! (hundred != zeroSt), "STAmount fail");
|
||||
unexpected (! (hundred != one), "STAmount fail");
|
||||
unexpected ((hundred != hundred), "STAmount fail");
|
||||
unexpected (STAmount (noIssue()).getText () != "0", "STAmount fail");
|
||||
unexpected (STAmount (noIssue(), 31).getText () != "31", "STAmount fail");
|
||||
unexpected (STAmount (noIssue(), 31, 1).getText () != "310", "STAmount fail");
|
||||
unexpected (STAmount (noIssue(), 31, -1).getText () != "3.1", "STAmount fail");
|
||||
unexpected (STAmount (noIssue(), 31, -2).getText () != "0.31", "STAmount fail");
|
||||
unexpected (multiply (STAmount (noIssue(), 20), STAmount (3), noIssue()).getText () != "60",
|
||||
"STAmount multiply fail 1");
|
||||
unexpected (multiply (STAmount (noIssue(), 20), STAmount (3), xrpIssue ()).getText () != "60",
|
||||
"STAmount multiply fail 2");
|
||||
unexpected (multiply (STAmount (20), STAmount (3), noIssue()).getText () != "60",
|
||||
"STAmount multiply fail 3");
|
||||
unexpected (multiply (STAmount (20), STAmount (3), xrpIssue ()).getText () != "60",
|
||||
"STAmount multiply fail 4");
|
||||
|
||||
if (divide (STAmount (noIssue(), 60), STAmount (3), noIssue()).getText () != "20")
|
||||
{
|
||||
WriteLog (lsFATAL, STAmount) << "60/3 = " <<
|
||||
divide (STAmount (noIssue(), 60),
|
||||
STAmount (3), noIssue()).getText ();
|
||||
fail ("STAmount divide fail");
|
||||
}
|
||||
else
|
||||
{
|
||||
pass ();
|
||||
}
|
||||
|
||||
unexpected (divide (STAmount (noIssue(), 60), STAmount (3), xrpIssue ()).getText () != "20",
|
||||
"STAmount divide fail");
|
||||
|
||||
unexpected (divide (STAmount (noIssue(), 60), STAmount (noIssue(), 3), noIssue()).getText () != "20",
|
||||
"STAmount divide fail");
|
||||
|
||||
unexpected (divide (STAmount (noIssue(), 60), STAmount (noIssue(), 3), xrpIssue ()).getText () != "20",
|
||||
"STAmount divide fail");
|
||||
|
||||
STAmount a1 (noIssue(), 60), a2 (noIssue(), 10, -1);
|
||||
|
||||
unexpected (divide (a2, a1, noIssue()) != amountFromQuality (getRate (a1, a2)),
|
||||
"STAmount setRate(getRate) fail");
|
||||
|
||||
unexpected (divide (a1, a2, noIssue()) != amountFromQuality (getRate (a2, a1)),
|
||||
"STAmount setRate(getRate) fail");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void testArithmetic ()
|
||||
{
|
||||
testcase ("arithmetic");
|
||||
|
||||
CBigNum b;
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
std::uint64_t r = rand ();
|
||||
r <<= 32;
|
||||
r |= rand ();
|
||||
b.setuint64 (r);
|
||||
|
||||
if (b.getuint64 () != r)
|
||||
{
|
||||
WriteLog (lsFATAL, STAmount) << r << " != " << b.getuint64 () << " " << b.ToString (16);
|
||||
fail ("setull64/getull64 failure");
|
||||
}
|
||||
else
|
||||
{
|
||||
pass ();
|
||||
}
|
||||
}
|
||||
|
||||
// Test currency multiplication and division operations such as
|
||||
// convertToDisplayAmount, convertToInternalAmount, getRate, getClaimed, and getNeeded
|
||||
|
||||
unexpected (getRate (STAmount (1), STAmount (10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 1");
|
||||
|
||||
unexpected (getRate (STAmount (10), STAmount (1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 2");
|
||||
|
||||
unexpected (getRate (STAmount (noIssue(), 1), STAmount (noIssue(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 3");
|
||||
|
||||
unexpected (getRate (STAmount (noIssue(), 10), STAmount (noIssue(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 4");
|
||||
|
||||
unexpected (getRate (STAmount (noIssue(), 1), STAmount (10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 5");
|
||||
|
||||
unexpected (getRate (STAmount (noIssue(), 10), STAmount (1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 6");
|
||||
|
||||
unexpected (getRate (STAmount (1), STAmount (noIssue(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 7");
|
||||
|
||||
unexpected (getRate (STAmount (10), STAmount (noIssue(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 8");
|
||||
|
||||
roundTest (1, 3, 3);
|
||||
roundTest (2, 3, 9);
|
||||
roundTest (1, 7, 21);
|
||||
roundTest (1, 2, 4);
|
||||
roundTest (3, 9, 18);
|
||||
roundTest (7, 11, 44);
|
||||
|
||||
for (int i = 0; i <= 100000; ++i)
|
||||
mulTest (rand () % 10000000, rand () % 10000000);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template <class Cond>
|
||||
bool
|
||||
expect (Cond cond, beast::String const& s)
|
||||
{
|
||||
return suite::expect (cond, s.toStdString());
|
||||
}
|
||||
|
||||
template <class Cond>
|
||||
bool
|
||||
expect (Cond cond)
|
||||
{
|
||||
return suite::expect (cond);
|
||||
}
|
||||
|
||||
void testUnderflow ()
|
||||
{
|
||||
testcase ("underflow");
|
||||
|
||||
STAmount bigNative (STAmount::cMaxNative / 2);
|
||||
STAmount bigValue (noIssue(),
|
||||
(STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMaxOffset - 1);
|
||||
STAmount smallValue (noIssue(),
|
||||
(STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMinOffset + 1);
|
||||
STAmount zeroSt (noIssue(), 0);
|
||||
|
||||
STAmount smallXsmall = multiply (smallValue, smallValue, noIssue());
|
||||
|
||||
expect (smallXsmall == zero, "smallXsmall != 0");
|
||||
|
||||
STAmount bigDsmall = divide (smallValue, bigValue, noIssue());
|
||||
|
||||
expect (bigDsmall == zero, beast::String ("small/big != 0: ") + bigDsmall.getText ());
|
||||
|
||||
#if 0
|
||||
// TODO(tom): this test makes no sense - we should have no way to have
|
||||
// the currency not be XRP while the account is XRP.
|
||||
bigDsmall = divide (smallValue, bigNative, noCurrency(), xrpAccount ());
|
||||
#endif
|
||||
|
||||
expect (bigDsmall == zero, beast::String ("small/bigNative != 0: ") + bigDsmall.getText ());
|
||||
|
||||
bigDsmall = divide (smallValue, bigValue, xrpIssue ());
|
||||
|
||||
expect (bigDsmall == zero, beast::String ("(small/big)->N != 0: ") + bigDsmall.getText ());
|
||||
|
||||
bigDsmall = divide (smallValue, bigNative, xrpIssue ());
|
||||
|
||||
expect (bigDsmall == zero, beast::String ("(small/bigNative)->N != 0: ") + bigDsmall.getText ());
|
||||
|
||||
// very bad offer
|
||||
std::uint64_t r = getRate (smallValue, bigValue);
|
||||
|
||||
expect (r == 0, "getRate(smallOut/bigIn) != 0");
|
||||
|
||||
// very good offer
|
||||
r = getRate (bigValue, smallValue);
|
||||
|
||||
expect (r == 0, "getRate(smallIn/bigOUt) != 0");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void testRounding ()
|
||||
{
|
||||
// VFALCO TODO There are no actual tests here, just printed output?
|
||||
// Change this to actually do something.
|
||||
|
||||
#if 0
|
||||
beginTestCase ("rounding ");
|
||||
|
||||
std::uint64_t value = 25000000000000000ull;
|
||||
int offset = -14;
|
||||
canonicalizeRound (false, value, offset, true);
|
||||
|
||||
STAmount one (noIssue(), 1);
|
||||
STAmount two (noIssue(), 2);
|
||||
STAmount three (noIssue(), 3);
|
||||
|
||||
STAmount oneThird1 = divRound (one, three, noIssue(), false);
|
||||
STAmount oneThird2 = divide (one, three, noIssue());
|
||||
STAmount oneThird3 = divRound (one, three, noIssue(), true);
|
||||
WriteLog (lsINFO, STAmount) << oneThird1;
|
||||
WriteLog (lsINFO, STAmount) << oneThird2;
|
||||
WriteLog (lsINFO, STAmount) << oneThird3;
|
||||
|
||||
STAmount twoThird1 = divRound (two, three, noIssue(), false);
|
||||
STAmount twoThird2 = divide (two, three, noIssue());
|
||||
STAmount twoThird3 = divRound (two, three, noIssue(), true);
|
||||
WriteLog (lsINFO, STAmount) << twoThird1;
|
||||
WriteLog (lsINFO, STAmount) << twoThird2;
|
||||
WriteLog (lsINFO, STAmount) << twoThird3;
|
||||
|
||||
STAmount oneA = mulRound (oneThird1, three, noIssue(), false);
|
||||
STAmount oneB = multiply (oneThird2, three, noIssue());
|
||||
STAmount oneC = mulRound (oneThird3, three, noIssue(), true);
|
||||
WriteLog (lsINFO, STAmount) << oneA;
|
||||
WriteLog (lsINFO, STAmount) << oneB;
|
||||
WriteLog (lsINFO, STAmount) << oneC;
|
||||
|
||||
STAmount fourThirdsA = addRound (twoThird2, twoThird2, false);
|
||||
STAmount fourThirdsB = twoThird2 + twoThird2;
|
||||
STAmount fourThirdsC = addRound (twoThird2, twoThird2, true);
|
||||
WriteLog (lsINFO, STAmount) << fourThirdsA;
|
||||
WriteLog (lsINFO, STAmount) << fourThirdsB;
|
||||
WriteLog (lsINFO, STAmount) << fourThirdsC;
|
||||
|
||||
STAmount dripTest1 = mulRound (twoThird2, two, xrpIssue (), false);
|
||||
STAmount dripTest2 = multiply (twoThird2, two, xrpIssue ());
|
||||
STAmount dripTest3 = mulRound (twoThird2, two, xrpIssue (), true);
|
||||
WriteLog (lsINFO, STAmount) << dripTest1;
|
||||
WriteLog (lsINFO, STAmount) << dripTest2;
|
||||
WriteLog (lsINFO, STAmount) << dripTest3;
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void run ()
|
||||
{
|
||||
testSetValue ();
|
||||
testNativeCurrency ();
|
||||
testCustomCurrency ();
|
||||
testArithmetic ();
|
||||
testUnderflow ();
|
||||
testRounding ();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(STAmount,ripple_data,ripple);
|
||||
|
||||
} // ripple
|
||||
@@ -1,329 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ripple {
|
||||
|
||||
void STAmount::canonicalizeRound (
|
||||
bool isNative, std::uint64_t& value, int& offset, bool roundUp)
|
||||
{
|
||||
if (!roundUp) // canonicalize already rounds down
|
||||
return;
|
||||
|
||||
WriteLog (lsTRACE, STAmount)
|
||||
<< "canonicalizeRound< " << value << ":" << offset;
|
||||
|
||||
if (isNative)
|
||||
{
|
||||
if (offset < 0)
|
||||
{
|
||||
int loops = 0;
|
||||
|
||||
while (offset < -1)
|
||||
{
|
||||
value /= 10;
|
||||
++offset;
|
||||
++loops;
|
||||
}
|
||||
|
||||
value += (loops >= 2) ? 9 : 10; // add before last divide
|
||||
value /= 10;
|
||||
++offset;
|
||||
}
|
||||
}
|
||||
else if (value > STAmount::cMaxValue)
|
||||
{
|
||||
while (value > (10 * STAmount::cMaxValue))
|
||||
{
|
||||
value /= 10;
|
||||
++offset;
|
||||
}
|
||||
|
||||
value += 9; // add before last divide
|
||||
value /= 10;
|
||||
++offset;
|
||||
}
|
||||
|
||||
WriteLog (lsTRACE, STAmount)
|
||||
<< "canonicalizeRound> " << value << ":" << offset;
|
||||
}
|
||||
|
||||
STAmount STAmount::addRound (STAmount const& v1, STAmount const& v2, bool roundUp)
|
||||
{
|
||||
v1.throwComparable (v2);
|
||||
|
||||
if (v2.mValue == 0)
|
||||
return v1;
|
||||
|
||||
if (v1.mValue == 0)
|
||||
return STAmount (v1.getFName (), v1.mIssue, v2.mValue,
|
||||
v2.mOffset, v2.mIsNegative);
|
||||
|
||||
if (v1.mIsNative)
|
||||
return STAmount (v1.getFName (), v1.getSNValue () + v2.getSNValue ());
|
||||
|
||||
int ov1 = v1.mOffset, ov2 = v2.mOffset;
|
||||
auto vv1 = static_cast<std::int64_t> (v1.mValue);
|
||||
auto vv2 = static_cast<std::int64_t> (v2.mValue);
|
||||
|
||||
if (v1.mIsNegative)
|
||||
vv1 = -vv1;
|
||||
|
||||
if (v2.mIsNegative)
|
||||
vv2 = -vv2;
|
||||
|
||||
if (ov1 < ov2)
|
||||
{
|
||||
while (ov1 < (ov2 - 1))
|
||||
{
|
||||
vv1 /= 10;
|
||||
++ov1;
|
||||
}
|
||||
|
||||
if (roundUp)
|
||||
vv1 += 9;
|
||||
|
||||
vv1 /= 10;
|
||||
++ov1;
|
||||
}
|
||||
|
||||
if (ov2 < ov1)
|
||||
{
|
||||
while (ov2 < (ov1 - 1))
|
||||
{
|
||||
vv2 /= 10;
|
||||
++ov2;
|
||||
}
|
||||
|
||||
if (roundUp)
|
||||
vv2 += 9;
|
||||
|
||||
vv2 /= 10;
|
||||
++ov2;
|
||||
}
|
||||
|
||||
std::int64_t fv = vv1 + vv2;
|
||||
|
||||
if ((fv >= -10) && (fv <= 10))
|
||||
return STAmount (v1.getFName (), v1.mIssue);
|
||||
else if (fv >= 0)
|
||||
{
|
||||
std::uint64_t v = static_cast<std::uint64_t> (fv);
|
||||
canonicalizeRound (false, v, ov1, roundUp);
|
||||
return STAmount (v1.getFName (), v1.mIssue, v, ov1, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::uint64_t v = static_cast<std::uint64_t> (-fv);
|
||||
canonicalizeRound (false, v, ov1, !roundUp);
|
||||
return STAmount (v1.getFName (), v1.mIssue, v, ov1, true);
|
||||
}
|
||||
}
|
||||
|
||||
STAmount STAmount::subRound (STAmount const& v1, STAmount const& v2, bool roundUp)
|
||||
{
|
||||
v1.throwComparable (v2);
|
||||
|
||||
if (v2.mValue == 0)
|
||||
return v1;
|
||||
|
||||
if (v1.mValue == 0)
|
||||
return STAmount (v1.getFName (), v1.mIssue, v2.mValue,
|
||||
v2.mOffset, !v2.mIsNegative);
|
||||
|
||||
if (v1.mIsNative)
|
||||
return STAmount (v1.getFName (), v1.getSNValue () - v2.getSNValue ());
|
||||
|
||||
int ov1 = v1.mOffset, ov2 = v2.mOffset;
|
||||
auto vv1 = static_cast<std::int64_t> (v1.mValue);
|
||||
auto vv2 = static_cast<std::int64_t> (v2.mValue);
|
||||
|
||||
if (v1.mIsNegative)
|
||||
vv1 = -vv1;
|
||||
|
||||
if (!v2.mIsNegative)
|
||||
vv2 = -vv2;
|
||||
|
||||
if (ov1 < ov2)
|
||||
{
|
||||
while (ov1 < (ov2 - 1))
|
||||
{
|
||||
vv1 /= 10;
|
||||
++ov1;
|
||||
}
|
||||
|
||||
if (roundUp)
|
||||
vv1 += 9;
|
||||
|
||||
vv1 /= 10;
|
||||
++ov1;
|
||||
}
|
||||
|
||||
if (ov2 < ov1)
|
||||
{
|
||||
while (ov2 < (ov1 - 1))
|
||||
{
|
||||
vv2 /= 10;
|
||||
++ov2;
|
||||
}
|
||||
|
||||
if (roundUp)
|
||||
vv2 += 9;
|
||||
|
||||
vv2 /= 10;
|
||||
++ov2;
|
||||
}
|
||||
|
||||
std::int64_t fv = vv1 + vv2;
|
||||
|
||||
if ((fv >= -10) && (fv <= 10))
|
||||
return STAmount (v1.getFName (), v1.mIssue);
|
||||
|
||||
if (fv >= 0)
|
||||
{
|
||||
std::uint64_t v = static_cast<std::uint64_t> (fv);
|
||||
canonicalizeRound (false, v, ov1, roundUp);
|
||||
return STAmount (v1.getFName (), v1.mIssue, v, ov1, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::uint64_t v = static_cast<std::uint64_t> (-fv);
|
||||
canonicalizeRound (false, v, ov1, !roundUp);
|
||||
return STAmount (v1.getFName (), v1.mIssue, v, ov1, true);
|
||||
}
|
||||
}
|
||||
|
||||
STAmount STAmount::mulRound (
|
||||
STAmount const& v1, STAmount const& v2, Issue const& issue, bool roundUp)
|
||||
{
|
||||
if (v1 == zero || v2 == zero)
|
||||
return {issue};
|
||||
|
||||
if (v1.mIsNative && v2.mIsNative && isXRP (issue))
|
||||
{
|
||||
std::uint64_t minV = (v1.getSNValue () < v2.getSNValue ()) ?
|
||||
v1.getSNValue () : v2.getSNValue ();
|
||||
std::uint64_t maxV = (v1.getSNValue () < v2.getSNValue ()) ?
|
||||
v2.getSNValue () : v1.getSNValue ();
|
||||
|
||||
if (minV > 3000000000ull) // sqrt(cMaxNative)
|
||||
throw std::runtime_error ("Native value overflow");
|
||||
|
||||
if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
|
||||
throw std::runtime_error ("Native value overflow");
|
||||
|
||||
return STAmount (v1.getFName (), minV * maxV);
|
||||
}
|
||||
|
||||
std::uint64_t value1 = v1.mValue, value2 = v2.mValue;
|
||||
int offset1 = v1.mOffset, offset2 = v2.mOffset;
|
||||
|
||||
if (v1.mIsNative)
|
||||
{
|
||||
while (value1 < STAmount::cMinValue)
|
||||
{
|
||||
value1 *= 10;
|
||||
--offset1;
|
||||
}
|
||||
}
|
||||
|
||||
if (v2.mIsNative)
|
||||
{
|
||||
while (value2 < STAmount::cMinValue)
|
||||
{
|
||||
value2 *= 10;
|
||||
--offset2;
|
||||
}
|
||||
}
|
||||
|
||||
bool resultNegative = v1.mIsNegative != v2.mIsNegative;
|
||||
// Compute (numerator * denominator) / 10^14 with rounding
|
||||
// 10^16 <= result <= 10^18
|
||||
CBigNum v;
|
||||
|
||||
if ((BN_add_word64 (&v, value1) != 1) || (BN_mul_word64 (&v, value2) != 1))
|
||||
throw std::runtime_error ("internal bn error");
|
||||
|
||||
if (resultNegative != roundUp) // rounding down is automatic when we divide
|
||||
BN_add_word64 (&v, tenTo14m1);
|
||||
|
||||
if (BN_div_word64 (&v, tenTo14) == ((std::uint64_t) - 1))
|
||||
throw std::runtime_error ("internal bn error");
|
||||
|
||||
// 10^16 <= product <= 10^18
|
||||
assert (BN_num_bytes (&v) <= 64);
|
||||
|
||||
std::uint64_t amount = v.getuint64 ();
|
||||
int offset = offset1 + offset2 + 14;
|
||||
canonicalizeRound (
|
||||
isXRP (issue), amount, offset, resultNegative != roundUp);
|
||||
return STAmount (issue, amount, offset, resultNegative);
|
||||
}
|
||||
|
||||
STAmount STAmount::divRound (
|
||||
STAmount const& num, STAmount const& den,
|
||||
Issue const& issue, bool roundUp)
|
||||
{
|
||||
if (den == zero)
|
||||
throw std::runtime_error ("division by zero");
|
||||
|
||||
if (num == zero)
|
||||
return {issue};
|
||||
|
||||
std::uint64_t numVal = num.mValue, denVal = den.mValue;
|
||||
int numOffset = num.mOffset, denOffset = den.mOffset;
|
||||
|
||||
if (num.mIsNative)
|
||||
while (numVal < STAmount::cMinValue)
|
||||
{
|
||||
// Need to bring into range
|
||||
numVal *= 10;
|
||||
--numOffset;
|
||||
}
|
||||
|
||||
if (den.mIsNative)
|
||||
while (denVal < STAmount::cMinValue)
|
||||
{
|
||||
denVal *= 10;
|
||||
--denOffset;
|
||||
}
|
||||
|
||||
bool resultNegative = num.mIsNegative != den.mIsNegative;
|
||||
// Compute (numerator * 10^17) / denominator
|
||||
CBigNum v;
|
||||
|
||||
if ((BN_add_word64 (&v, numVal) != 1) || (BN_mul_word64 (&v, tenTo17) != 1))
|
||||
throw std::runtime_error ("internal bn error");
|
||||
|
||||
if (resultNegative != roundUp) // Rounding down is automatic when we divide
|
||||
BN_add_word64 (&v, denVal - 1);
|
||||
|
||||
if (BN_div_word64 (&v, denVal) == ((std::uint64_t) - 1))
|
||||
throw std::runtime_error ("internal bn error");
|
||||
|
||||
// 10^16 <= quotient <= 10^18
|
||||
assert (BN_num_bytes (&v) <= 64);
|
||||
|
||||
std::uint64_t amount = v.getuint64 ();
|
||||
int offset = numOffset - denOffset - 17;
|
||||
canonicalizeRound (
|
||||
isXRP (issue), amount, offset, resultNegative != roundUp);
|
||||
return STAmount (issue, amount, offset, resultNegative);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
@@ -416,7 +416,7 @@ bool STParsedJSON::parse (std::string const& json_name,
|
||||
case STI_AMOUNT:
|
||||
try
|
||||
{
|
||||
data.push_back (new STAmount (field, value));
|
||||
data.push_back (new STAmount (amountFromJson (field, value)));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
@@ -83,14 +83,78 @@ public:
|
||||
assert (fName);
|
||||
}
|
||||
|
||||
virtual ~SerializedType () { }
|
||||
virtual ~SerializedType () = default;
|
||||
|
||||
static std::unique_ptr<SerializedType> deserialize (SField::ref name)
|
||||
//
|
||||
// overridables
|
||||
//
|
||||
|
||||
virtual
|
||||
SerializedTypeID
|
||||
getSType () const
|
||||
{
|
||||
return STI_NOTPRESENT;
|
||||
}
|
||||
|
||||
virtual
|
||||
std::string
|
||||
getFullText() const;
|
||||
|
||||
// just the value
|
||||
virtual
|
||||
std::string
|
||||
getText() const
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
virtual
|
||||
Json::Value getJson (int /*options*/) const
|
||||
{
|
||||
return getText();
|
||||
}
|
||||
|
||||
virtual
|
||||
void
|
||||
add (Serializer& s) const
|
||||
{
|
||||
// VFALCO Why not just make this pure virtual?
|
||||
assert (false);
|
||||
}
|
||||
|
||||
virtual
|
||||
bool
|
||||
isEquivalent (SerializedType const& t) const;
|
||||
|
||||
virtual
|
||||
bool
|
||||
isDefault () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// VFALCO TODO Return std::unique_ptr <SerializedType>
|
||||
virtual
|
||||
SerializedType*
|
||||
duplicate () const
|
||||
{
|
||||
return new SerializedType (*fName);
|
||||
}
|
||||
|
||||
public:
|
||||
//
|
||||
// members
|
||||
//
|
||||
|
||||
static
|
||||
std::unique_ptr <SerializedType>
|
||||
deserialize (SField::ref name)
|
||||
{
|
||||
return std::unique_ptr<SerializedType> (new SerializedType (name));
|
||||
}
|
||||
|
||||
/** A SerializeType is a field.
|
||||
/** A SerializedType is a field.
|
||||
This sets the name.
|
||||
*/
|
||||
void setFName (SField::ref n)
|
||||
@@ -102,31 +166,11 @@ public:
|
||||
{
|
||||
return *fName;
|
||||
}
|
||||
virtual SerializedTypeID getSType () const
|
||||
{
|
||||
return STI_NOTPRESENT;
|
||||
}
|
||||
std::unique_ptr<SerializedType> clone () const
|
||||
{
|
||||
return std::unique_ptr<SerializedType> (duplicate ());
|
||||
}
|
||||
|
||||
virtual std::string getFullText () const;
|
||||
virtual std::string getText () const // just the value
|
||||
{
|
||||
return std::string ();
|
||||
}
|
||||
virtual Json::Value getJson (int /*options*/) const
|
||||
{
|
||||
return getText ();
|
||||
}
|
||||
|
||||
virtual void add (Serializer& s) const
|
||||
{
|
||||
assert (false);
|
||||
}
|
||||
|
||||
virtual bool isEquivalent (const SerializedType& t) const;
|
||||
|
||||
void addFieldID (Serializer& s) const
|
||||
{
|
||||
@@ -145,11 +189,6 @@ public:
|
||||
return (getSType () != t.getSType ()) || !isEquivalent (t);
|
||||
}
|
||||
|
||||
virtual bool isDefault () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class D>
|
||||
D& downcast()
|
||||
{
|
||||
@@ -171,12 +210,6 @@ public:
|
||||
protected:
|
||||
// VFALCO TODO make accessors for this
|
||||
SField::ptr fName;
|
||||
|
||||
private:
|
||||
virtual SerializedType* duplicate () const
|
||||
{
|
||||
return new SerializedType (*fName);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
const STAmount saZero (noIssue(), 0);
|
||||
const STAmount saOne (noIssue(), 1);
|
||||
const STAmount saZero (noIssue(), 0u);
|
||||
const STAmount saOne (noIssue(), 1u);
|
||||
|
||||
SerializedType& SerializedType::operator= (const SerializedType& t)
|
||||
{
|
||||
|
||||
@@ -72,7 +72,7 @@ Json::Value doRipplePathFind (RPC::Context& context)
|
||||
else if (
|
||||
// Parse saDstAmount.
|
||||
!context.params_.isMember ("destination_amount")
|
||||
|| !saDstAmount.bSetJson (context.params_["destination_amount"])
|
||||
|| ! amountFromJsonNoThrow(saDstAmount, context.params_["destination_amount"])
|
||||
|| saDstAmount <= zero
|
||||
|| (!isXRP(saDstAmount.getCurrency ())
|
||||
&& (!saDstAmount.getIssuer () ||
|
||||
|
||||
@@ -105,7 +105,7 @@ static Json::Value signPayment(
|
||||
|
||||
STAmount amount;
|
||||
|
||||
if (!amount.bSetJson (tx_json ["Amount"]))
|
||||
if (! amountFromJsonNoThrow (amount, tx_json ["Amount"]))
|
||||
return RPC::invalid_field_error ("tx_json.Amount");
|
||||
|
||||
if (!tx_json.isMember ("Destination"))
|
||||
@@ -131,7 +131,7 @@ static Json::Value signPayment(
|
||||
|
||||
if (tx_json.isMember ("SendMax"))
|
||||
{
|
||||
if (!saSendMax.bSetJson (tx_json ["SendMax"]))
|
||||
if (! amountFromJsonNoThrow (saSendMax, tx_json ["SendMax"]))
|
||||
return RPC::invalid_field_error ("tx_json.SendMax");
|
||||
}
|
||||
else
|
||||
|
||||
@@ -79,13 +79,8 @@
|
||||
#include <ripple/module/data/protocol/STArray.cpp>
|
||||
#include <ripple/module/data/protocol/TER.cpp>
|
||||
#include <ripple/module/data/protocol/TxFormats.cpp>
|
||||
|
||||
// These are for STAmount
|
||||
static const std::uint64_t tenTo14 = 100000000000000ull;
|
||||
static const std::uint64_t tenTo14m1 = tenTo14 - 1;
|
||||
static const std::uint64_t tenTo17 = tenTo14 * 1000;
|
||||
#include <ripple/module/data/protocol/STAmount.cpp>
|
||||
#include <ripple/module/data/protocol/STAmountRound.cpp>
|
||||
#include <ripple/module/data/protocol/STAmount.test.cpp>
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (pop)
|
||||
|
||||
Reference in New Issue
Block a user