mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-04 19:25:51 +00:00
Rename RippleAsset to Issue and RippleBook to Book:
* Split STAmount out of SerializedTypes.h * New concept of "Issue consistency": when either both or neither of its currency and account are XRP. * Stop checking for consistency of Issue in its constructor. * Clarification of mIsNative logic in STAmount. * Usual cleanups.
This commit is contained in:
committed by
Nik Bougalis
parent
a96dee85d2
commit
206efbf30d
@@ -191,7 +191,7 @@ public:
|
||||
|
||||
if (sig == 0)
|
||||
return os << "0";
|
||||
|
||||
|
||||
if (sig < 0)
|
||||
os << "-";
|
||||
if (m_integral)
|
||||
@@ -204,10 +204,11 @@ public:
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TODO(tom): remove this typedef and have exactly one name for STAmount.
|
||||
|
||||
typedef STAmount Amount;
|
||||
|
||||
}
|
||||
}
|
||||
} // core
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
#define RIPPLE_CORE_TYPES_H_INCLUDED
|
||||
|
||||
#include <ripple/module/app/ledger/LedgerEntrySet.h>
|
||||
#include <ripple/types/api/RippleAssets.h>
|
||||
#include <ripple/types/api/base_uint.h>
|
||||
#include <ripple/types/api/Book.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
@@ -33,14 +32,6 @@ namespace core {
|
||||
/** A mutable view that overlays an immutable ledger to track changes. */
|
||||
typedef LedgerEntrySet LedgerView;
|
||||
|
||||
/** Asset identifiers. */
|
||||
typedef RippleAsset Asset;
|
||||
typedef RippleAssetRef AssetRef;
|
||||
|
||||
/** Uniquely identifies an order book. */
|
||||
typedef RippleBook Book;
|
||||
typedef RippleBookRef BookRef;
|
||||
|
||||
/** A clock representing network time.
|
||||
This measures seconds since the Ripple epoch as seen
|
||||
by the ledger close clock.
|
||||
|
||||
@@ -26,8 +26,8 @@ BookTip::BookTip (LedgerView& view, BookRef book)
|
||||
: m_view (view)
|
||||
, m_valid (false)
|
||||
, m_book (Ledger::getBookBase (
|
||||
book.in.currency, book.in.issuer,
|
||||
book.out.currency, book.out.issuer))
|
||||
book.in.currency, book.in.account,
|
||||
book.out.currency, book.out.account))
|
||||
, m_end (Ledger::getQualityNext (m_book))
|
||||
{
|
||||
}
|
||||
@@ -65,7 +65,7 @@ BookTip::step ()
|
||||
m_book = page;
|
||||
|
||||
// The quality immediately before the next quality
|
||||
--m_book;
|
||||
--m_book;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -46,11 +46,7 @@ Taker::remaining_offer () const
|
||||
{
|
||||
// If the taker is done, then there's no offer to place.
|
||||
if (done ())
|
||||
{
|
||||
return Amounts (
|
||||
Amount (m_amount.in.getCurrency (), m_amount.in.getIssuer ()),
|
||||
Amount (m_amount.out.getCurrency (), m_amount.out.getIssuer ()));
|
||||
}
|
||||
return Amounts (m_amount.in.zeroed(), m_amount.out.zeroed());
|
||||
|
||||
// Avoid math altogether if we didn't cross.
|
||||
if (m_amount == m_remain)
|
||||
@@ -272,7 +268,7 @@ Taker::cross (Offer const& leg1, Offer const& leg2)
|
||||
Amounts flow1 (flow (amount1, leg1, m_account));
|
||||
|
||||
amount2 = leg2.quality().ceil_in (amount2, flow1.out);
|
||||
|
||||
|
||||
Amounts flow2 (flow (amount2, leg2, m_account));
|
||||
|
||||
m_remain.out -= amount2.out;
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
Amount
|
||||
static raw (std::uint64_t mantissa, int exponent)
|
||||
{
|
||||
return Amount (Currency(3), Account(3), mantissa, exponent);
|
||||
return Amount ({Currency(3), Account(3)}, mantissa, exponent);
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
@@ -241,9 +241,9 @@ public:
|
||||
{
|
||||
testcase ("comparisons");
|
||||
|
||||
Amount const amount1 (noCurrency (), noAccount (), 231);
|
||||
Amount const amount2 (noCurrency (), noAccount (), 462);
|
||||
Amount const amount3 (noCurrency (), noAccount (), 924);
|
||||
Amount const amount1 (noIssue(), 231);
|
||||
Amount const amount2 (noIssue(), 462);
|
||||
Amount const amount3 (noIssue(), 924);
|
||||
|
||||
Quality const q11 (core::Amounts (amount1, amount1));
|
||||
Quality const q12 (core::Amounts (amount1, amount2));
|
||||
@@ -264,9 +264,9 @@ public:
|
||||
{
|
||||
testcase ("composition");
|
||||
|
||||
Amount const amount1 (noCurrency (), noAccount (), 231);
|
||||
Amount const amount2 (noCurrency (), noAccount (), 462);
|
||||
Amount const amount3 (noCurrency (), noAccount (), 924);
|
||||
Amount const amount1 (noIssue(), 231);
|
||||
Amount const amount2 (noIssue(), 462);
|
||||
Amount const amount3 (noIssue(), 924);
|
||||
|
||||
Quality const q11 (core::Amounts (amount1, amount1));
|
||||
Quality const q12 (core::Amounts (amount1, amount2));
|
||||
@@ -289,8 +289,8 @@ public:
|
||||
testcase ("operations");
|
||||
|
||||
Quality const q11 (core::Amounts (
|
||||
Amount (noCurrency (), noAccount (), 731),
|
||||
Amount (noCurrency (), noAccount (), 731)));
|
||||
Amount (noIssue(), 731),
|
||||
Amount (noIssue(), 731)));
|
||||
|
||||
Quality qa (q11);
|
||||
Quality qb (q11);
|
||||
|
||||
@@ -1114,7 +1114,7 @@ STAmount LedgerEntrySet::rippleOwed (
|
||||
}
|
||||
else
|
||||
{
|
||||
saBalance.clear (currency, uToAccountID);
|
||||
saBalance.clear ({currency, uToAccountID});
|
||||
|
||||
WriteLog (lsDEBUG, LedgerEntrySet) << "rippleOwed:" <<
|
||||
" No credit line between " <<
|
||||
@@ -1146,7 +1146,7 @@ STAmount LedgerEntrySet::rippleLimit (
|
||||
}
|
||||
else
|
||||
{
|
||||
saLimit.clear (currency, uToAccountID);
|
||||
saLimit.clear ({currency, uToAccountID});
|
||||
}
|
||||
|
||||
return saLimit;
|
||||
@@ -1237,7 +1237,7 @@ STAmount LedgerEntrySet::rippleHolds (
|
||||
|
||||
if (!sleRippleState)
|
||||
{
|
||||
saBalance.clear (currency, issuer);
|
||||
saBalance.clear ({currency, issuer});
|
||||
}
|
||||
else if (account > issuer)
|
||||
{
|
||||
@@ -1351,12 +1351,10 @@ STAmount LedgerEntrySet::rippleTransferFee (
|
||||
{
|
||||
// NIKB use STAmount::saFromRate
|
||||
STAmount saTransitRate (
|
||||
noCurrency(), noAccount(),
|
||||
static_cast<std::uint64_t> (uTransitRate), -9);
|
||||
noIssue(), static_cast<std::uint64_t> (uTransitRate), -9);
|
||||
|
||||
STAmount saTransferTotal = STAmount::multiply (
|
||||
saAmount, saTransitRate,
|
||||
saAmount.getCurrency (), saAmount.getIssuer ());
|
||||
saAmount, saTransitRate, saAmount.issue ());
|
||||
STAmount saTransferFee = saTransferTotal - saAmount;
|
||||
|
||||
WriteLog (lsDEBUG, LedgerEntrySet) << "rippleTransferFee:" <<
|
||||
@@ -1366,7 +1364,7 @@ STAmount LedgerEntrySet::rippleTransferFee (
|
||||
}
|
||||
}
|
||||
|
||||
return STAmount (saAmount.getCurrency (), saAmount.getIssuer ());
|
||||
return saAmount.zeroed();
|
||||
}
|
||||
|
||||
TER LedgerEntrySet::trustCreate (
|
||||
@@ -1413,42 +1411,42 @@ TER LedgerEntrySet::trustCreate (
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
{
|
||||
const bool bSetDst = saLimit.getIssuer () == uDstAccountID;
|
||||
const bool bSetHigh = bSrcHigh ^ bSetDst;
|
||||
const bool bSetDst = saLimit.getIssuer () == uDstAccountID;
|
||||
const bool bSetHigh = bSrcHigh ^ bSetDst;
|
||||
|
||||
// Remember deletion hints.
|
||||
sleRippleState->setFieldU64 (sfLowNode, uLowNode);
|
||||
sleRippleState->setFieldU64 (sfHighNode, uHighNode);
|
||||
|
||||
sleRippleState->setFieldAmount (
|
||||
!bSetHigh ? sfLowLimit : sfHighLimit, saLimit);
|
||||
bSetHigh ? sfHighLimit : sfLowLimit, saLimit);
|
||||
sleRippleState->setFieldAmount (
|
||||
bSetHigh ? sfLowLimit : sfHighLimit,
|
||||
STAmount (saBalance.getCurrency (),
|
||||
bSetDst ? uSrcAccountID : uDstAccountID));
|
||||
STAmount ({saBalance.getCurrency (),
|
||||
bSetDst ? uSrcAccountID : uDstAccountID}));
|
||||
|
||||
if (uQualityIn)
|
||||
sleRippleState->setFieldU32 (
|
||||
!bSetHigh ? sfLowQualityIn : sfHighQualityIn, uQualityIn);
|
||||
bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn);
|
||||
|
||||
if (uQualityOut)
|
||||
sleRippleState->setFieldU32 (
|
||||
!bSetHigh ? sfLowQualityOut : sfHighQualityOut, uQualityOut);
|
||||
bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut);
|
||||
|
||||
std::uint32_t uFlags = !bSetHigh ? lsfLowReserve : lsfHighReserve;
|
||||
std::uint32_t uFlags = bSetHigh ? lsfHighReserve : lsfLowReserve;
|
||||
|
||||
if (bAuth)
|
||||
{
|
||||
uFlags |= (!bSetHigh ? lsfLowAuth : lsfHighAuth);
|
||||
uFlags |= (bSetHigh ? lsfHighAuth : lsfLowAuth);
|
||||
}
|
||||
if (bNoRipple)
|
||||
{
|
||||
uFlags |= (!bSetHigh ? lsfLowNoRipple : lsfHighNoRipple);
|
||||
uFlags |= (bSetHigh ? lsfHighNoRipple : lsfLowNoRipple);
|
||||
}
|
||||
|
||||
sleRippleState->setFieldU32 (sfFlags, uFlags);
|
||||
ownerCountAdjust (
|
||||
!bSetDst ? uSrcAccountID : uDstAccountID, 1, sleAccount);
|
||||
bSetDst ? uDstAccountID : uSrcAccountID, 1, sleAccount);
|
||||
|
||||
// ONLY: Create ripple balance.
|
||||
sleRippleState->setFieldAmount (
|
||||
@@ -1528,8 +1526,8 @@ TER LedgerEntrySet::rippleCredit (
|
||||
|
||||
if (!sleRippleState)
|
||||
{
|
||||
STAmount saReceiverLimit = STAmount (currency, uReceiverID);
|
||||
STAmount saBalance = saAmount;
|
||||
STAmount saReceiverLimit({currency, uReceiverID});
|
||||
STAmount saBalance = saAmount;
|
||||
|
||||
saBalance.setIssuer (noAccount());
|
||||
|
||||
|
||||
@@ -61,9 +61,9 @@ void OrderBookDB::setup (Ledger::ref ledger)
|
||||
|
||||
static void updateHelper (SLE::ref entry,
|
||||
ripple::unordered_set< uint256 >& seen,
|
||||
ripple::unordered_map< RippleAsset, std::vector<OrderBook::pointer> >& destMap,
|
||||
ripple::unordered_map< RippleAsset, std::vector<OrderBook::pointer> >& sourceMap,
|
||||
ripple::unordered_set< RippleAsset >& XRPBooks,
|
||||
ripple::unordered_map< Issue, std::vector<OrderBook::pointer> >& destMap,
|
||||
ripple::unordered_map< Issue, std::vector<OrderBook::pointer> >& sourceMap,
|
||||
ripple::unordered_set< Issue >& XRPBooks,
|
||||
int& books)
|
||||
{
|
||||
if ((entry->getType () == ltDIR_NODE) && (entry->isFieldPresent (sfExchangeRate)) &&
|
||||
@@ -85,10 +85,10 @@ static void updateHelper (SLE::ref entry,
|
||||
OrderBook::pointer book = std::make_shared<OrderBook> (std::cref (index),
|
||||
std::cref (ci), std::cref (co), std::cref (ii), std::cref (io));
|
||||
|
||||
sourceMap[RippleAssetRef (ci, ii)].push_back (book);
|
||||
destMap[RippleAssetRef (co, io)].push_back (book);
|
||||
sourceMap[IssueRef (ci, ii)].push_back (book);
|
||||
destMap[IssueRef (co, io)].push_back (book);
|
||||
if (co.isZero())
|
||||
XRPBooks.insert(RippleAssetRef (ci, ii));
|
||||
XRPBooks.insert(IssueRef (ci, ii));
|
||||
++books;
|
||||
}
|
||||
}
|
||||
@@ -97,9 +97,9 @@ static void updateHelper (SLE::ref entry,
|
||||
void OrderBookDB::update (Ledger::pointer ledger)
|
||||
{
|
||||
ripple::unordered_set< uint256 > seen;
|
||||
ripple::unordered_map< RippleAsset, std::vector<OrderBook::pointer> > destMap;
|
||||
ripple::unordered_map< RippleAsset, std::vector<OrderBook::pointer> > sourceMap;
|
||||
ripple::unordered_set< RippleAsset > XRPBooks;
|
||||
ripple::unordered_map< Issue, std::vector<OrderBook::pointer> > destMap;
|
||||
ripple::unordered_map< Issue, std::vector<OrderBook::pointer> > sourceMap;
|
||||
ripple::unordered_set< Issue > XRPBooks;
|
||||
|
||||
WriteLog (lsDEBUG, OrderBookDB) << "OrderBookDB::update>";
|
||||
|
||||
@@ -139,7 +139,7 @@ void OrderBookDB::addOrderBook(Currency const& ci, Currency const& co,
|
||||
|
||||
if (toXRP)
|
||||
{ // We don't want to search through all the to-XRP or from-XRP order books!
|
||||
for (auto ob : mSourceMap[RippleAssetRef(ci, ii)])
|
||||
for (auto ob : mSourceMap[{ci, ii}])
|
||||
{
|
||||
if (ob->getCurrencyOut().isZero ()) // also to XRP
|
||||
return;
|
||||
@@ -147,7 +147,7 @@ void OrderBookDB::addOrderBook(Currency const& ci, Currency const& co,
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto ob : mDestMap[RippleAssetRef(co, io)])
|
||||
for (auto ob : mDestMap[{co, io}])
|
||||
{
|
||||
if ((ob->getCurrencyIn() == ci) && (ob->getIssuerIn() == ii))
|
||||
return;
|
||||
@@ -157,10 +157,10 @@ void OrderBookDB::addOrderBook(Currency const& ci, Currency const& co,
|
||||
uint256 index = Ledger::getBookBase(ci, ii, co, io);
|
||||
auto book = std::make_shared<OrderBook> (index, ci, co, ii, io);
|
||||
|
||||
mSourceMap[RippleAssetRef (ci, ii)].push_back (book);
|
||||
mDestMap[RippleAssetRef (co, io)].push_back (book);
|
||||
mSourceMap[{ci, ii}].push_back (book);
|
||||
mDestMap[{co, io}].push_back (book);
|
||||
if (toXRP)
|
||||
mXRPBooks.insert(RippleAssetRef (ci, ii));
|
||||
mXRPBooks.insert({ci, ii});
|
||||
}
|
||||
|
||||
// return list of all orderbooks that want this issuerID and currencyID
|
||||
@@ -168,8 +168,7 @@ void OrderBookDB::getBooksByTakerPays (Account const& issuerID, Currency const&
|
||||
std::vector<OrderBook::pointer>& bookRet)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
auto it = mSourceMap.find (RippleAssetRef (currencyID, issuerID));
|
||||
|
||||
auto it = mSourceMap.find ({currencyID, issuerID});
|
||||
if (it != mSourceMap.end ())
|
||||
bookRet = it->second;
|
||||
else
|
||||
@@ -180,7 +179,7 @@ bool OrderBookDB::isBookToXRP(Account const& issuerID, Currency const& currencyI
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
|
||||
return mXRPBooks.count(RippleAssetRef(currencyID, issuerID)) > 0;
|
||||
return mXRPBooks.count({currencyID, issuerID}) > 0;
|
||||
}
|
||||
|
||||
// return list of all orderbooks that give this issuerID and currencyID
|
||||
@@ -188,7 +187,7 @@ void OrderBookDB::getBooksByTakerGets (Account const& issuerID, Currency const&
|
||||
std::vector<OrderBook::pointer>& bookRet)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
auto it = mDestMap.find (RippleAssetRef (currencyID, issuerID));
|
||||
auto it = mDestMap.find ({currencyID, issuerID});
|
||||
|
||||
if (it != mDestMap.end ())
|
||||
bookRet = it->second;
|
||||
@@ -206,9 +205,8 @@ BookListeners::pointer OrderBookDB::makeBookListeners (Currency const& currencyP
|
||||
{
|
||||
ret = std::make_shared<BookListeners> ();
|
||||
|
||||
mListeners [RippleBookRef (
|
||||
RippleAssetRef (currencyPays, issuerPays),
|
||||
RippleAssetRef (currencyGets, issuerGets))] = ret;
|
||||
mListeners [BookRef ({currencyPays, issuerPays},
|
||||
{currencyGets, issuerGets})] = ret;
|
||||
assert (getBookListeners (currencyPays, currencyGets, issuerPays, issuerGets) == ret);
|
||||
}
|
||||
|
||||
@@ -221,9 +219,8 @@ BookListeners::pointer OrderBookDB::getBookListeners (Currency const& currencyPa
|
||||
BookListeners::pointer ret;
|
||||
ScopedLockType sl (mLock);
|
||||
|
||||
auto it0 (mListeners.find (RippleBookRef (
|
||||
RippleAssetRef (currencyPays, issuerPays),
|
||||
RippleAssetRef (currencyGets, issuerGets))));
|
||||
auto it0 (mListeners.find (BookRef (
|
||||
{currencyPays, issuerPays}, {currencyGets, issuerGets})));
|
||||
|
||||
if (it0 != mListeners.end ())
|
||||
ret = it0->second;
|
||||
|
||||
@@ -79,7 +79,7 @@ public:
|
||||
void processTxn (Ledger::ref ledger, const AcceptedLedgerTx& alTx, Json::Value const& jvObj);
|
||||
|
||||
private:
|
||||
typedef ripple::unordered_map <RippleAsset, std::vector<OrderBook::pointer>>
|
||||
typedef ripple::unordered_map <Issue, std::vector<OrderBook::pointer>>
|
||||
AssetToOrderBook;
|
||||
|
||||
// by ci/ii
|
||||
@@ -89,13 +89,13 @@ private:
|
||||
AssetToOrderBook mDestMap;
|
||||
|
||||
// does an order book to XRP exist
|
||||
ripple::unordered_set <RippleAsset> mXRPBooks;
|
||||
ripple::unordered_set <Issue> mXRPBooks;
|
||||
|
||||
typedef RippleRecursiveMutex LockType;
|
||||
typedef std::lock_guard <LockType> ScopedLockType;
|
||||
LockType mLock;
|
||||
|
||||
typedef ripple::unordered_map <RippleBook, BookListeners::pointer>
|
||||
typedef ripple::unordered_map <Book, BookListeners::pointer>
|
||||
BookToListenersMap;
|
||||
|
||||
BookToListenersMap mListeners;
|
||||
|
||||
@@ -3004,8 +3004,7 @@ void NetworkOPsImp::getBookPage (
|
||||
// Need to charge a transfer fee to offer owner.
|
||||
uOfferRate = uTransferRate;
|
||||
saOwnerFundsLimit = STAmount::divide (
|
||||
saOwnerFunds, STAmount (noCurrency(), noAccount(),
|
||||
uOfferRate, -9));
|
||||
saOwnerFunds, STAmount (noIssue(), uOfferRate, -9));
|
||||
// TODO(tom): why -9?
|
||||
}
|
||||
else
|
||||
@@ -3038,7 +3037,7 @@ void NetworkOPsImp::getBookPage (
|
||||
saOwnerFunds,
|
||||
STAmount::multiply (
|
||||
saTakerGetsFunded,
|
||||
STAmount (noCurrency(), noAccount(),
|
||||
STAmount (noIssue(),
|
||||
uOfferRate, -9)));
|
||||
|
||||
umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
|
||||
@@ -3165,7 +3164,7 @@ void NetworkOPsImp::getBookPage (
|
||||
// Need to charge a transfer fee to offer owner.
|
||||
uOfferRate = uTransferRate;
|
||||
// TODO(tom): where does -9 come from?!
|
||||
STAmount amount (noCurrency(), noAccount(), uOfferRate, -9);
|
||||
STAmount amount (noIssue(), uOfferRate, -9);
|
||||
saOwnerFundsLimit = STAmount::divide (saOwnerFunds, amount);
|
||||
}
|
||||
else
|
||||
@@ -3198,7 +3197,7 @@ void NetworkOPsImp::getBookPage (
|
||||
: std::min (saOwnerFunds,
|
||||
STAmount::multiply (
|
||||
saTakerGetsFunded, STAmount (
|
||||
noCurrency(), noAccount(), uOfferRate,
|
||||
noIssue(), uOfferRate,
|
||||
-9)));
|
||||
|
||||
umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
@param issuerOut The destination issuer.
|
||||
*/
|
||||
// VFALCO NOTE what is the meaning of the index parameter?
|
||||
// VFALCO TODO Replace with RippleAsset
|
||||
// VFALCO TODO Replace with Issue
|
||||
OrderBook (uint256 const& index,
|
||||
Currency const& currencyIn,
|
||||
Currency const& currencyOut,
|
||||
|
||||
@@ -264,7 +264,7 @@ TER nodeDeliverFwd (
|
||||
// Do outbound debiting.
|
||||
// Send to issuer/limbo total amount including fees (issuer gets
|
||||
// fees).
|
||||
auto id = !!node.currency_ ? Account(node.issuer_) : xrpIssuer();
|
||||
auto id = !!node.currency_ ? Account(node.issuer_) : xrpAccount();
|
||||
auto outPassTotal = saOutPassAct + saOutPassFees;
|
||||
rippleCalc.mActiveLedger.accountSend (node.offerOwnerAccount_, id, outPassTotal);
|
||||
|
||||
@@ -296,7 +296,7 @@ TER nodeDeliverFwd (
|
||||
|| uInAccountID != node.offerOwnerAccount_)
|
||||
{
|
||||
auto id = !isXRP(previousNode.currency_) ?
|
||||
uInAccountID : xrpIssuer();
|
||||
uInAccountID : xrpAccount();
|
||||
resultCode = rippleCalc.mActiveLedger.accountSend (
|
||||
id, node.offerOwnerAccount_, saInPassAct);
|
||||
|
||||
|
||||
@@ -78,18 +78,11 @@ TER computeForwardLiquidityForAccount (
|
||||
// rev.
|
||||
|
||||
// For nextNodeIsAccount
|
||||
STAmount saPrvRedeemAct (
|
||||
previousNode.saFwdRedeem.getCurrency (),
|
||||
previousNode.saFwdRedeem.getIssuer ());
|
||||
|
||||
STAmount saPrvIssueAct (
|
||||
previousNode.saFwdIssue.getCurrency (),
|
||||
previousNode.saFwdIssue.getIssuer ());
|
||||
auto saPrvRedeemAct = previousNode.saFwdRedeem.zeroed();
|
||||
auto saPrvIssueAct = previousNode.saFwdIssue.zeroed();
|
||||
|
||||
// For !previousNodeIsAccount
|
||||
STAmount saPrvDeliverAct (
|
||||
previousNode.saFwdDeliver.getCurrency (),
|
||||
previousNode.saFwdDeliver.getIssuer ());
|
||||
auto saPrvDeliverAct = previousNode.saFwdDeliver.zeroed ();
|
||||
|
||||
WriteLog (lsTRACE, RippleCalc)
|
||||
<< "computeForwardLiquidityForAccount> "
|
||||
@@ -167,7 +160,7 @@ TER computeForwardLiquidityForAccount (
|
||||
? previousNode.saFwdIssue // No fee.
|
||||
: STAmount::mulRound (
|
||||
previousNode.saFwdIssue,
|
||||
STAmount (noCurrency(), noAccount(), uQualityIn, -9),
|
||||
STAmount (noIssue(), uQualityIn, -9),
|
||||
true); // Amount to credit.
|
||||
|
||||
// Amount to credit. Credit for less than received as a surcharge.
|
||||
@@ -329,7 +322,7 @@ TER computeForwardLiquidityForAccount (
|
||||
node.saFwdDeliver = std::min (
|
||||
node.saFwdDeliver,
|
||||
rippleCalc.mActiveLedger.accountHolds (
|
||||
node.account_, xrpCurrency(), xrpIssuer()));
|
||||
node.account_, xrpCurrency(), xrpAccount()));
|
||||
|
||||
}
|
||||
|
||||
@@ -360,7 +353,7 @@ TER computeForwardLiquidityForAccount (
|
||||
|
||||
// Deliver XRP to limbo.
|
||||
resultCode = rippleCalc.mActiveLedger.accountSend (
|
||||
node.account_, xrpIssuer(), node.saFwdDeliver);
|
||||
node.account_, xrpAccount(), node.saFwdDeliver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,19 +84,19 @@ TER computeReverseLiquidityForAccount (
|
||||
const STAmount saPrvOwed = (previousNodeIsAccount && nodeIndex != 0)
|
||||
? rippleCalc.mActiveLedger.rippleOwed (
|
||||
node.account_, previousAccountID, node.currency_)
|
||||
: STAmount (node.currency_, node.account_);
|
||||
: STAmount ({node.currency_, node.account_});
|
||||
|
||||
// The limit amount that the previous account may owe.
|
||||
const STAmount saPrvLimit = (previousNodeIsAccount && nodeIndex != 0)
|
||||
? rippleCalc.mActiveLedger.rippleLimit (
|
||||
node.account_, previousAccountID, node.currency_)
|
||||
: STAmount (node.currency_, node.account_);
|
||||
: STAmount ({node.currency_, node.account_});
|
||||
|
||||
// Next account is owed.
|
||||
const STAmount saNxtOwed = (nextNodeIsAccount && nodeIndex != lastNodeIndex)
|
||||
? rippleCalc.mActiveLedger.rippleOwed (
|
||||
node.account_, nextAccountID, node.currency_)
|
||||
: STAmount (node.currency_, node.account_);
|
||||
: STAmount ({node.currency_, node.account_});
|
||||
|
||||
WriteLog (lsTRACE, RippleCalc)
|
||||
<< "computeReverseLiquidityForAccount>"
|
||||
@@ -114,7 +114,7 @@ TER computeReverseLiquidityForAccount (
|
||||
// Previous can redeem the owed IOUs it holds.
|
||||
const STAmount saPrvRedeemReq = (saPrvOwed > zero)
|
||||
? saPrvOwed
|
||||
: STAmount (saPrvOwed.getCurrency (), saPrvOwed.getIssuer ());
|
||||
: STAmount (saPrvOwed.issue ());
|
||||
|
||||
// This is the amount we're actually going to be setting for the previous
|
||||
// node.
|
||||
@@ -129,27 +129,25 @@ TER computeReverseLiquidityForAccount (
|
||||
// Precompute these values in case we have an order book.
|
||||
auto deliverCurrency = previousNode.saRevDeliver.getCurrency ();
|
||||
const STAmount saPrvDeliverReq (
|
||||
deliverCurrency, previousNode.saRevDeliver.getIssuer (), -1);
|
||||
{deliverCurrency, previousNode.saRevDeliver.getIssuer ()}, -1);
|
||||
// Unlimited delivery.
|
||||
|
||||
STAmount& saPrvDeliverAct = previousNode.saRevDeliver;
|
||||
STAmount& saPrvDeliverAct = previousNode.saRevDeliver;
|
||||
|
||||
// For nextNodeIsAccount
|
||||
const STAmount& saCurRedeemReq = node.saRevRedeem;
|
||||
|
||||
// Set to zero, because we're trying to hit the previous node.
|
||||
STAmount saCurRedeemAct (
|
||||
saCurRedeemReq.getCurrency (), saCurRedeemReq.getIssuer ());
|
||||
auto saCurRedeemAct = saCurRedeemReq.zeroed();
|
||||
|
||||
const STAmount& saCurIssueReq = node.saRevIssue;
|
||||
|
||||
// Track the amount we actually redeem.
|
||||
STAmount saCurIssueAct (
|
||||
saCurIssueReq.getCurrency (), saCurIssueReq.getIssuer ());
|
||||
auto saCurIssueAct = saCurIssueReq.zeroed();
|
||||
|
||||
// For !nextNodeIsAccount
|
||||
const STAmount& saCurDeliverReq = node.saRevDeliver;
|
||||
STAmount saCurDeliverAct (
|
||||
saCurDeliverReq.getCurrency (), saCurDeliverReq.getIssuer ());
|
||||
auto saCurDeliverAct = saCurDeliverReq.zeroed();
|
||||
|
||||
WriteLog (lsTRACE, RippleCalc)
|
||||
<< "computeReverseLiquidityForAccount:"
|
||||
@@ -192,8 +190,7 @@ TER computeReverseLiquidityForAccount (
|
||||
const STAmount saCurWantedReq = std::min (
|
||||
pathState.outReq() - pathState.outAct(),
|
||||
saPrvLimit + saPrvOwed);
|
||||
STAmount saCurWantedAct (
|
||||
saCurWantedReq.getCurrency (), saCurWantedReq.getIssuer ());
|
||||
auto saCurWantedAct = saCurWantedReq.zeroed ();
|
||||
|
||||
WriteLog (lsTRACE, RippleCalc)
|
||||
<< "computeReverseLiquidityForAccount: account --> ACCOUNT --> $ :"
|
||||
|
||||
@@ -139,11 +139,11 @@ void computeRippleLiquidity (
|
||||
|
||||
// current actual = current request * (quality out / quality in).
|
||||
auto numerator = STAmount::mulRound (
|
||||
saCur, uQualityOut, currency, uCurIssuerID, true);
|
||||
saCur, uQualityOut, {currency, uCurIssuerID}, true);
|
||||
// True means "round up" to get best flow.
|
||||
|
||||
STAmount saCurIn = STAmount::divRound (
|
||||
numerator, uQualityIn, currency, uCurIssuerID, true);
|
||||
numerator, uQualityIn, {currency, uCurIssuerID}, true);
|
||||
|
||||
WriteLog (lsTRACE, RippleCalc)
|
||||
<< "computeRippleLiquidity:"
|
||||
@@ -170,12 +170,13 @@ void computeRippleLiquidity (
|
||||
// This is inverted compared to the code above because we're
|
||||
// going the other way
|
||||
|
||||
Issue issue{currency, uCurIssuerID};
|
||||
auto numerator = STAmount::mulRound (
|
||||
saPrv, uQualityIn, currency, uCurIssuerID, true);
|
||||
saPrv, uQualityIn, issue, true);
|
||||
// A part of current. All of previous. (Cur is the driver
|
||||
// variable.)
|
||||
STAmount saCurOut = STAmount::divRound (
|
||||
numerator, uQualityOut, currency, uCurIssuerID, true);
|
||||
numerator, uQualityOut, issue, true);
|
||||
|
||||
WriteLog (lsTRACE, RippleCalc)
|
||||
<< "computeRippleLiquidity:4: saCurReq=" << saCurReq;
|
||||
|
||||
@@ -361,7 +361,7 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
|
||||
if (!sameAccount || (c != saDstAmount.getCurrency ()))
|
||||
{
|
||||
if (c.isZero ())
|
||||
sourceCurrencies.insert (std::make_pair (c, xrpIssuer()));
|
||||
sourceCurrencies.insert (std::make_pair (c, xrpAccount()));
|
||||
else
|
||||
sourceCurrencies.insert (std::make_pair (c, raSrcAccount.getAccountID ()));
|
||||
}
|
||||
@@ -414,7 +414,7 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
|
||||
for (auto const& currIssuer: sourceCurrencies)
|
||||
{
|
||||
{
|
||||
STAmount test (currIssuer.first, currIssuer.second, 1);
|
||||
STAmount test ({currIssuer.first, currIssuer.second}, 1);
|
||||
if (m_journal.debug)
|
||||
{
|
||||
m_journal.debug
|
||||
@@ -436,11 +436,12 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
|
||||
PathState::List pathStateList;
|
||||
STAmount saMaxAmountAct;
|
||||
STAmount saDstAmountAct;
|
||||
STAmount saMaxAmount (
|
||||
currIssuer.first,
|
||||
currIssuer.second.isNonZero () ? Account(currIssuer.second) :
|
||||
(currIssuer.first.isZero () ? xrpIssuer() :
|
||||
raSrcAccount.getAccountID ()), 1);
|
||||
auto& account = currIssuer.second.isNonZero ()
|
||||
? Account(currIssuer.second)
|
||||
: isXRP (currIssuer.first)
|
||||
? xrpAccount()
|
||||
: raSrcAccount.getAccountID ();
|
||||
STAmount saMaxAmount ({currIssuer.first, account}, 1);
|
||||
|
||||
saMaxAmount.negate ();
|
||||
m_journal.debug << iIdentifier << " Paths found, calling rippleCalc";
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
typedef const pointer& ref;
|
||||
typedef const wptr& wref;
|
||||
|
||||
// TODO(tom): Use RippleAsset instead!
|
||||
// TODO(tom): Use Issue instead!
|
||||
typedef std::pair<Currency, Account> CurrencyIssuer;
|
||||
|
||||
public:
|
||||
|
||||
@@ -78,7 +78,7 @@ TER PathState::pushImpliedNodes (
|
||||
if (nodes_.back ().currency_ != currency)
|
||||
{
|
||||
// Currency is different, need to convert via an offer from an order
|
||||
// book. xrpIssuer() does double duty as signaling "this is an order
|
||||
// book. xrpAccount() does double duty as signaling "this is an order
|
||||
// book".
|
||||
|
||||
// Corresponds to "Implies an offer directory" in the diagram, currently
|
||||
@@ -88,8 +88,8 @@ TER PathState::pushImpliedNodes (
|
||||
: STPathElement::typeCurrency | STPathElement::typeIssuer;
|
||||
|
||||
// The offer's output is what is now wanted.
|
||||
// xrpIssuer() is a placeholder for offers.
|
||||
resultCode = pushNode (type, xrpIssuer(), currency, issuer);
|
||||
// xrpAccount() is a placeholder for offers.
|
||||
resultCode = pushNode (type, xrpAccount(), currency, issuer);
|
||||
}
|
||||
|
||||
|
||||
@@ -193,13 +193,13 @@ TER PathState::pushNode (
|
||||
? issuer
|
||||
: !!node.currency_ // Not XRP.
|
||||
? account
|
||||
: xrpIssuer();
|
||||
: xrpAccount();
|
||||
// Zero value - for accounts.
|
||||
node.saRevRedeem = STAmount (node.currency_, account);
|
||||
node.saRevRedeem = STAmount ({node.currency_, account});
|
||||
node.saRevIssue = node.saRevRedeem;
|
||||
|
||||
// For order books only - zero currency with the issuer ID.
|
||||
node.saRevDeliver = STAmount (node.currency_, node.issuer_);
|
||||
node.saRevDeliver = STAmount ({node.currency_, node.issuer_});
|
||||
node.saFwdDeliver = node.saRevDeliver;
|
||||
|
||||
if (pathIsEmpty)
|
||||
@@ -220,7 +220,7 @@ TER PathState::pushNode (
|
||||
|
||||
resultCode = pushImpliedNodes (
|
||||
node.account_, node.currency_,
|
||||
isXRP(node.currency_) ? xrpIssuer() : account);
|
||||
isXRP(node.currency_) ? xrpAccount() : account);
|
||||
|
||||
// Note: previousNode may no longer be the immediately previous node.
|
||||
}
|
||||
@@ -322,9 +322,9 @@ TER PathState::pushNode (
|
||||
? Account(previousNode.issuer_) // Default to previous issuer
|
||||
: Account(previousNode.account_)
|
||||
// Or previous account if no previous issuer.
|
||||
: xrpIssuer();
|
||||
: xrpAccount();
|
||||
node.saRateMax = saZero;
|
||||
node.saRevDeliver = STAmount (node.currency_, node.issuer_);
|
||||
node.saRevDeliver = STAmount({node.currency_, node.issuer_});
|
||||
node.saFwdDeliver = node.saRevDeliver;
|
||||
|
||||
if (node.currency_.isZero() != node.issuer_.isZero())
|
||||
@@ -345,7 +345,7 @@ TER PathState::pushNode (
|
||||
|
||||
// Insert intermediary issuer account if needed.
|
||||
resultCode = pushImpliedNodes (
|
||||
xrpIssuer(), // Rippling, but offers don't have an account.
|
||||
xrpAccount(), // Rippling, but offers don't have an account.
|
||||
previousNode.currency_,
|
||||
previousNode.issuer_);
|
||||
}
|
||||
@@ -389,7 +389,7 @@ void PathState::expandPath (
|
||||
const Currency currencyOutID = saOutReq.getCurrency ();
|
||||
const Account issuerOutID = saOutReq.getIssuer ();
|
||||
const Account uSenderIssuerID
|
||||
= isXRP(uMaxCurrencyID) ? xrpIssuer() : uSenderID;
|
||||
= isXRP(uMaxCurrencyID) ? xrpAccount() : uSenderID;
|
||||
// Sender is always issuer for non-XRP.
|
||||
|
||||
WriteLog (lsTRACE, RippleCalc)
|
||||
@@ -450,7 +450,7 @@ void PathState::expandPath (
|
||||
? (issuerOutID == uReceiverID)
|
||||
? Account(uReceiverID)
|
||||
: Account(issuerOutID) // Use implied node.
|
||||
: xrpIssuer();
|
||||
: xrpAccount();
|
||||
|
||||
WriteLog (lsDEBUG, RippleCalc)
|
||||
<< "expandPath: implied check:"
|
||||
|
||||
@@ -111,7 +111,7 @@ Pathfinder::Pathfinder (
|
||||
mDstAmount (saDstAmount),
|
||||
mSrcCurrencyID (uSrcCurrencyID),
|
||||
mSrcIssuerID (uSrcIssuerID),
|
||||
mSrcAmount (uSrcCurrencyID, uSrcIssuerID, 1u, 0, true),
|
||||
mSrcAmount ({uSrcCurrencyID, uSrcIssuerID}, 1u, 0, true),
|
||||
mLedger (cache->getLedger ()), mRLCache (cache)
|
||||
{
|
||||
|
||||
@@ -502,7 +502,7 @@ int Pathfinder::getPathsOut (
|
||||
Currency const& currencyID, Account const& accountID,
|
||||
bool isDstCurrency, Account const& dstAccount)
|
||||
{
|
||||
// VFALCO TODO Use RippleAsset here
|
||||
// VFALCO TODO Use Issue here
|
||||
auto currencyAccount = std::make_pair(currencyID, accountID);
|
||||
auto it = mPOMap.find (currencyAccount);
|
||||
|
||||
@@ -791,7 +791,7 @@ void Pathfinder::addLink(
|
||||
{
|
||||
STPathElement pathElement(
|
||||
STPathElement::typeCurrency,
|
||||
xrpIssuer(), xrpCurrency(), xrpIssuer());
|
||||
xrpAccount(), xrpCurrency(), xrpAccount());
|
||||
incompletePaths.assembleAdd(currentPath, pathElement);
|
||||
}
|
||||
}
|
||||
@@ -804,7 +804,7 @@ void Pathfinder::addLink(
|
||||
BOOST_FOREACH(OrderBook::ref book, books)
|
||||
{
|
||||
if (!currentPath.hasSeen (
|
||||
xrpIssuer(),
|
||||
xrpAccount(),
|
||||
book->getCurrencyOut(),
|
||||
book->getIssuerOut()) &&
|
||||
!matchesOrigin(
|
||||
@@ -821,7 +821,7 @@ void Pathfinder::addLink(
|
||||
// add the order book itself
|
||||
newPath.addElement(STPathElement(
|
||||
STPathElement::typeCurrency,
|
||||
xrpIssuer(), xrpCurrency(), xrpIssuer()));
|
||||
xrpAccount(), xrpCurrency(), xrpAccount()));
|
||||
|
||||
if (mDstAmount.getCurrency().isZero())
|
||||
{ // destination is XRP, add account and path is complete
|
||||
@@ -835,7 +835,7 @@ void Pathfinder::addLink(
|
||||
{ // Don't want the book if we've already seen the issuer
|
||||
// add the order book itself
|
||||
newPath.addElement(STPathElement(STPathElement::typeCurrency | STPathElement::typeIssuer,
|
||||
xrpIssuer(), book->getCurrencyOut(), book->getIssuerOut()));
|
||||
xrpAccount(), book->getCurrencyOut(), book->getIssuerOut()));
|
||||
|
||||
if ((book->getIssuerOut() == mDstAccountID) && book->getCurrencyOut() == mDstAmount.getCurrency())
|
||||
{ // with the destination account, this path is complete
|
||||
|
||||
@@ -55,13 +55,13 @@ TER rippleCalculate (
|
||||
PathState::List& pathStateList,
|
||||
|
||||
// Issuer:
|
||||
// XRP: xrpIssuer()
|
||||
// XRP: xrpAccount()
|
||||
// non-XRP: uSrcAccountID (for any issuer) or another account with trust
|
||||
// node.
|
||||
STAmount const& saMaxAmountReq, // --> -1 = no limit.
|
||||
|
||||
// Issuer:
|
||||
// XRP: xrpIssuer()
|
||||
// XRP: xrpAccount()
|
||||
// non-XRP: uDstAccountID (for any issuer) or another account with trust
|
||||
// node.
|
||||
STAmount const& saDstAmountReq,
|
||||
|
||||
@@ -40,19 +40,19 @@ CreateOffer::CreateOffer (
|
||||
}
|
||||
|
||||
TER
|
||||
CreateOffer::checkAcceptAsset(core::AssetRef asset) const
|
||||
CreateOffer::checkAcceptAsset(IssueRef issue) const
|
||||
{
|
||||
/* Only valid for custom currencies */
|
||||
assert (!asset.is_xrp ());
|
||||
assert (!isXRP (issue.currency));
|
||||
|
||||
SLE::pointer const issuerAccount = mEngine->entryCache (
|
||||
ltACCOUNT_ROOT, Ledger::getAccountRootIndex (asset.issuer));
|
||||
ltACCOUNT_ROOT, Ledger::getAccountRootIndex (issue.account));
|
||||
|
||||
if (!issuerAccount)
|
||||
{
|
||||
if (m_journal.warning) m_journal.warning <<
|
||||
"delay: can't receive IOUs from non-existent issuer: " <<
|
||||
to_string (asset.issuer);
|
||||
to_string (issue.account);
|
||||
|
||||
return (mParams & tapRETRY)
|
||||
? terNO_ACCOUNT
|
||||
@@ -63,7 +63,7 @@ CreateOffer::checkAcceptAsset(core::AssetRef asset) const
|
||||
{
|
||||
SLE::pointer const trustLine (mEngine->entryCache (
|
||||
ltRIPPLE_STATE, Ledger::getRippleStateIndex (
|
||||
mTxnAccountID, asset.issuer, asset.currency)));
|
||||
mTxnAccountID, issue.account, issue.currency)));
|
||||
|
||||
if (!trustLine)
|
||||
{
|
||||
@@ -75,7 +75,7 @@ CreateOffer::checkAcceptAsset(core::AssetRef asset) const
|
||||
// Entries have a canonical representation, determined by a
|
||||
// lexicographical "greater than" comparison employing strict weak
|
||||
// ordering. Determine which entry we need to access.
|
||||
bool const canonical_gt (mTxnAccountID > asset.issuer);
|
||||
bool const canonical_gt (mTxnAccountID > issue.account);
|
||||
|
||||
bool const need_auth (trustLine->getFieldU32 (sfFlags) &
|
||||
(canonical_gt ? lsfLowAuth : lsfHighAuth));
|
||||
@@ -279,7 +279,7 @@ CreateOffer::doApply ()
|
||||
|
||||
// Make sure that we are authorized to hold what the taker will pay us.
|
||||
if (terResult == tesSUCCESS && !saTakerPays.isNative ())
|
||||
terResult = checkAcceptAsset (core::Asset (uPaysCurrency, uPaysIssuerID));
|
||||
terResult = checkAcceptAsset (Issue (uPaysCurrency, uPaysIssuerID));
|
||||
|
||||
bool crossed = false;
|
||||
bool const bOpenLedger (mParams & tapOPEN_LEDGER);
|
||||
@@ -358,7 +358,7 @@ CreateOffer::doApply ()
|
||||
// Earlier, we verified that the amounts, as specified in the offer,
|
||||
// were not negative. That they are now suggests that something went
|
||||
// very wrong with offer crossing.
|
||||
m_journal.fatal << (crossed ? "Partially consumed" : "Full") <<
|
||||
m_journal.fatal << (crossed ? "Partially consumed" : "Full") <<
|
||||
" offer has negative component:" <<
|
||||
" pays=" << saTakerPays.getFullText () <<
|
||||
" gets=" << saTakerGets.getFullText ();
|
||||
|
||||
@@ -32,7 +32,7 @@ class CreateOffer
|
||||
{
|
||||
protected:
|
||||
/** Determine if we are authorized to hold the asset we want to get */
|
||||
TER checkAcceptAsset(core::AssetRef asset) const;
|
||||
TER checkAcceptAsset(IssueRef asset) const;
|
||||
|
||||
/** Fill offer as much as possible by consuming offers already on the books.
|
||||
We adjusts account balances and charges fees on top to taker.
|
||||
@@ -65,4 +65,3 @@ std::unique_ptr <Transactor> make_CreateOffer (
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -41,20 +41,17 @@ CreateOfferBridged::crossOffers (
|
||||
|
||||
core::LedgerView view_cancel (view.duplicate());
|
||||
|
||||
core::AssetRef const asset_in (
|
||||
taker_amount.in.getCurrency(), taker_amount.in.getIssuer());
|
||||
|
||||
core::AssetRef const asset_out (
|
||||
taker_amount.out.getCurrency(), taker_amount.out.getIssuer());
|
||||
auto& asset_in = taker_amount.in.issue();
|
||||
auto& asset_out = taker_amount.out.issue();
|
||||
|
||||
core::OfferStream offers_direct (view, view_cancel,
|
||||
core::Book (asset_in, asset_out), when, m_journal);
|
||||
Book (asset_in, asset_out), when, m_journal);
|
||||
|
||||
core::OfferStream offers_leg1 (view, view_cancel,
|
||||
core::Book (asset_in, xrp_asset ()), when, m_journal);
|
||||
Book (asset_in, xrpIssue ()), when, m_journal);
|
||||
|
||||
core::OfferStream offers_leg2 (view, view_cancel,
|
||||
core::Book (xrp_asset (), asset_out), when, m_journal);
|
||||
Book (xrpIssue (), asset_out), when, m_journal);
|
||||
|
||||
core::Taker taker (view, mTxnAccountID, taker_amount, options);
|
||||
|
||||
|
||||
@@ -45,16 +45,11 @@ CreateOfferDirect::crossOffers (
|
||||
mEngine->getLedger ()->getParentCloseTimeNC ());
|
||||
|
||||
core::LedgerView view_cancel (view.duplicate());
|
||||
core::OfferStream offers (view, view_cancel,
|
||||
core::Book (
|
||||
core::AssetRef (
|
||||
taker_amount.in.getCurrency(), taker_amount.in.getIssuer()),
|
||||
core::AssetRef (
|
||||
taker_amount.out.getCurrency(), taker_amount.out.getIssuer())),
|
||||
core::OfferStream offers (
|
||||
view, view_cancel,
|
||||
Book (taker_amount.in.issue(), taker_amount.out.issue()),
|
||||
when, m_journal);
|
||||
Account& account = mTxnAccountID;
|
||||
// TODO(tom): why is that last line needed?
|
||||
core::Taker taker (offers.view(), account, taker_amount, options);
|
||||
core::Taker taker (offers.view(), mTxnAccountID, taker_amount, options);
|
||||
|
||||
TER cross_result (tesSUCCESS);
|
||||
|
||||
|
||||
@@ -39,8 +39,9 @@ TER Payment::doApply ()
|
||||
maxSourceAmount = saDstAmount;
|
||||
else
|
||||
maxSourceAmount = STAmount (
|
||||
saDstAmount.getCurrency (), mTxnAccountID, saDstAmount.getMantissa (),
|
||||
saDstAmount.getExponent (), saDstAmount < zero);
|
||||
{saDstAmount.getCurrency (), mTxnAccountID},
|
||||
saDstAmount.getMantissa (), saDstAmount.getExponent (),
|
||||
saDstAmount < zero);
|
||||
auto const& uSrcCurrency = maxSourceAmount.getCurrency ();
|
||||
auto const& uDstCurrency = saDstAmount.getCurrency ();
|
||||
|
||||
|
||||
@@ -352,12 +352,12 @@ TER SetTrust::doApply ()
|
||||
}
|
||||
else if (badCurrency() == currency)
|
||||
{
|
||||
terResult = temBAD_CURRENCY;
|
||||
terResult = temBAD_CURRENCY;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Zero balance in currency.
|
||||
STAmount saBalance (STAmount (currency, noAccount()));
|
||||
STAmount saBalance ({currency, noAccount()});
|
||||
|
||||
uint256 index (Ledger::getRippleStateIndex (
|
||||
mTxnAccountID, uDstAccountID, currency));
|
||||
|
||||
@@ -28,7 +28,7 @@ std::uint64_t STAmount::uRateOne =
|
||||
|
||||
std::string STAmount::getHumanCurrency () const
|
||||
{
|
||||
return to_string (mCurrency);
|
||||
return to_string (mIssue.currency);
|
||||
}
|
||||
|
||||
bool STAmount::bSetJson (const Json::Value& jvSource)
|
||||
@@ -101,14 +101,14 @@ STAmount::STAmount (SField::ref n, const Json::Value& v)
|
||||
else
|
||||
{
|
||||
// non-XRP
|
||||
if (!to_currency (mCurrency, currency.asString ()))
|
||||
if (!to_currency (mIssue.currency, currency.asString ()))
|
||||
throw std::runtime_error ("invalid currency");
|
||||
|
||||
if (!issuer.isString ()
|
||||
|| !to_issuer (mIssuer, issuer.asString ()))
|
||||
|| !to_issuer (mIssue.account, issuer.asString ()))
|
||||
throw std::runtime_error ("invalid issuer");
|
||||
|
||||
if (mIssuer.isZero ())
|
||||
if (isXRP (*this))
|
||||
throw std::runtime_error ("invalid issuer");
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ STAmount::STAmount (SField::ref n, const Json::Value& v)
|
||||
|
||||
bool STAmount::setValue (const std::string& sAmount)
|
||||
{
|
||||
// Note: mIsNative and mCurrency must be set already!
|
||||
// Note: mIsNative and mIssue.currency must be set already!
|
||||
|
||||
static boost::regex reNumber (
|
||||
"\\`([+-]?)(\\d*)(\\.(\\d*))?([eE]([+-]?)(\\d+))?\\'");
|
||||
@@ -253,14 +253,14 @@ bool STAmount::setFullValue (const std::string& sAmount, const std::string& sCur
|
||||
//
|
||||
// Figure out the currency.
|
||||
//
|
||||
if (!to_currency (mCurrency, sCurrency))
|
||||
if (!to_currency (mIssue.currency, sCurrency))
|
||||
{
|
||||
WriteLog (lsINFO, STAmount) << "Currency malformed: " << sCurrency;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
mIsNative = !mCurrency;
|
||||
mIsNative = !mIssue.currency;
|
||||
|
||||
//
|
||||
// Figure out the issuer.
|
||||
@@ -275,10 +275,10 @@ bool STAmount::setFullValue (const std::string& sAmount, const std::string& sCur
|
||||
return false;
|
||||
}
|
||||
|
||||
mIssuer = naIssuerID.getAccountID ();
|
||||
mIssue.account = naIssuerID.getAccountID ();
|
||||
|
||||
// Stamps not must have an issuer.
|
||||
if (mIsNative && !mIssuer.isZero ())
|
||||
if (mIsNative && !isXRP (*this))
|
||||
{
|
||||
WriteLog (lsINFO, STAmount) << "Issuer specified for XRP: " << sIssuer;
|
||||
|
||||
@@ -289,13 +289,15 @@ bool STAmount::setFullValue (const std::string& sAmount, const std::string& sCur
|
||||
}
|
||||
|
||||
// amount = value * [10 ^ offset]
|
||||
// representation range is 10^80 - 10^(-80)
|
||||
// on the wire, high 8 bits are (offset+142), low 56 bits are value
|
||||
// value is zero if amount is zero, otherwise value is 10^15 to (10^16 - 1) inclusive
|
||||
// Representation range is 10^80 - 10^(-80).
|
||||
// On the wire, high 8 bits are (offset+142), low 56 bits are value.
|
||||
//
|
||||
// Value is zero if amount is zero, otherwise value is 10^15 to (10^16 - 1)
|
||||
// inclusive.
|
||||
|
||||
void STAmount::canonicalize ()
|
||||
{
|
||||
if (mCurrency.isZero ())
|
||||
if (isXRP (*this))
|
||||
{
|
||||
// native currency amounts should always have an offset of zero
|
||||
mIsNative = true;
|
||||
@@ -384,8 +386,8 @@ void STAmount::add (Serializer& s) const
|
||||
else // 256 = positive
|
||||
s.add64 (mValue | (static_cast<std::uint64_t> (mOffset + 512 + 256 + 97) << (64 - 10)));
|
||||
|
||||
s.add160 (mCurrency);
|
||||
s.add160 (mIssuer);
|
||||
s.add160 (mIssue.currency);
|
||||
s.add160 (mIssue.account);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,18 +400,23 @@ STAmount STAmount::createFromInt64 (SField::ref name, std::int64_t value)
|
||||
|
||||
void STAmount::setValue (const STAmount& a)
|
||||
{
|
||||
mCurrency = a.mCurrency;
|
||||
mIssuer = a.mIssuer;
|
||||
mIssue = a.mIssue;
|
||||
mValue = a.mValue;
|
||||
mOffset = a.mOffset;
|
||||
mIsNative = a.mIsNative;
|
||||
mIsNegative = a.mIsNegative;
|
||||
}
|
||||
|
||||
void STAmount::setIssue (Issue const& issue) {
|
||||
mIssue = std::move(issue);
|
||||
mIsNative = isXRP (*this);
|
||||
}
|
||||
|
||||
int STAmount::compare (const STAmount& a) const
|
||||
{
|
||||
// Compares the value of a to the value of this STAmount, amounts must be comparable
|
||||
if (mIsNegative != a.mIsNegative) return mIsNegative ? -1 : 1;
|
||||
if (mIsNegative != a.mIsNegative)
|
||||
return mIsNegative ? -1 : 1;
|
||||
|
||||
if (!mValue)
|
||||
{
|
||||
@@ -446,14 +453,16 @@ STAmount* STAmount::construct (SerializerIterator& sit, SField::ref name)
|
||||
return new STAmount (name, value, true); // negative
|
||||
}
|
||||
|
||||
Currency currency;
|
||||
currency.copyFrom (sit.get160 ());
|
||||
Issue issue;
|
||||
issue.currency.copyFrom (sit.get160 ());
|
||||
|
||||
if (!currency)
|
||||
throw std::runtime_error ("invalid non-native currency");
|
||||
if (isXRP (issue.currency))
|
||||
throw std::runtime_error ("invalid native currency");
|
||||
|
||||
Account issuer;
|
||||
issuer.copyFrom (sit.get160 ());
|
||||
issue.account.copyFrom (sit.get160 ());
|
||||
|
||||
if (isXRP (issue.account))
|
||||
throw std::runtime_error ("invalid native account");
|
||||
|
||||
// 10 bits for the offset, sign and "not native" flag
|
||||
int offset = static_cast<int> (value >> (64 - 10));
|
||||
@@ -473,21 +482,23 @@ STAmount* STAmount::construct (SerializerIterator& sit, SField::ref name)
|
||||
throw std::runtime_error ("invalid currency value");
|
||||
}
|
||||
|
||||
return new STAmount (name, currency, issuer, value, offset, isNegative);
|
||||
return new STAmount (name, issue, value, offset, isNegative);
|
||||
}
|
||||
|
||||
if (offset != 512)
|
||||
throw std::runtime_error ("invalid currency value");
|
||||
|
||||
return new STAmount (name, currency, issuer);
|
||||
return new STAmount (name, issue);
|
||||
}
|
||||
|
||||
std::int64_t STAmount::getSNValue () const
|
||||
{
|
||||
// signed native value
|
||||
if (!mIsNative) throw std::runtime_error ("not native");
|
||||
if (!mIsNative)
|
||||
throw std::runtime_error ("not native");
|
||||
|
||||
if (mIsNegative) return - static_cast<std::int64_t> (mValue);
|
||||
if (mIsNegative)
|
||||
return - static_cast<std::int64_t> (mValue);
|
||||
|
||||
return static_cast<std::int64_t> (mValue);
|
||||
}
|
||||
@@ -526,7 +537,7 @@ std::string STAmount::getText () const
|
||||
{
|
||||
ret.append (raw_value);
|
||||
|
||||
if(scientific)
|
||||
if (scientific)
|
||||
{
|
||||
ret.append (1, 'e');
|
||||
ret.append (std::to_string (mOffset));
|
||||
@@ -604,16 +615,13 @@ bool STAmount::isComparable (const STAmount& t) const
|
||||
|
||||
if (t.mIsNative) return false;
|
||||
|
||||
return mCurrency == t.mCurrency;
|
||||
return mIssue.currency == t.mIssue.currency;
|
||||
}
|
||||
|
||||
bool STAmount::isEquivalent (const SerializedType& t) const
|
||||
{
|
||||
const STAmount* v = dynamic_cast<const STAmount*> (&t);
|
||||
|
||||
if (!v) return false;
|
||||
|
||||
return isComparable (*v) && (mIsNegative == v->mIsNegative) && (mValue == v->mValue) && (mOffset == v->mOffset);
|
||||
return v && (*v == *this);
|
||||
}
|
||||
|
||||
void STAmount::throwComparable (const STAmount& t) const
|
||||
@@ -625,12 +633,18 @@ void STAmount::throwComparable (const STAmount& t) const
|
||||
|
||||
bool STAmount::operator== (const STAmount& a) const
|
||||
{
|
||||
return isComparable (a) && (mIsNegative == a.mIsNegative) && (mOffset == a.mOffset) && (mValue == a.mValue);
|
||||
return isComparable (a) &&
|
||||
mIsNegative == a.mIsNegative &&
|
||||
mOffset == a.mOffset &&
|
||||
mValue == a.mValue;
|
||||
}
|
||||
|
||||
bool STAmount::operator!= (const STAmount& a) const
|
||||
{
|
||||
return (mOffset != a.mOffset) || (mValue != a.mValue) || (mIsNegative != a.mIsNegative) || !isComparable (a);
|
||||
return mOffset != a.mOffset ||
|
||||
mValue != a.mValue ||
|
||||
mIsNegative != a.mIsNegative ||
|
||||
!isComparable (a);
|
||||
}
|
||||
|
||||
bool STAmount::operator< (const STAmount& a) const
|
||||
@@ -673,17 +687,19 @@ STAmount STAmount::operator- (void) const
|
||||
{
|
||||
if (mValue == 0) return *this;
|
||||
|
||||
return STAmount (getFName (), mCurrency, mIssuer, mValue, mOffset, mIsNative, !mIsNegative);
|
||||
return STAmount (
|
||||
getFName (), mIssue, mValue, mOffset, mIsNative, !mIsNegative);
|
||||
}
|
||||
|
||||
STAmount& STAmount::operator= (std::uint64_t v)
|
||||
{
|
||||
// does not copy name, does not change currency type
|
||||
// Does not copy name, does not change currency type.
|
||||
mOffset = 0;
|
||||
mValue = v;
|
||||
mIsNegative = false;
|
||||
|
||||
if (!mIsNative) canonicalize ();
|
||||
if (!mIsNative)
|
||||
canonicalize ();
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -732,12 +748,14 @@ bool STAmount::operator>= (std::uint64_t v) const
|
||||
|
||||
STAmount STAmount::operator+ (std::uint64_t v) const
|
||||
{
|
||||
return STAmount (getFName (), getSNValue () + static_cast<std::int64_t> (v));
|
||||
return STAmount (
|
||||
getFName (), getSNValue () + static_cast<std::int64_t> (v));
|
||||
}
|
||||
|
||||
STAmount STAmount::operator- (std::uint64_t v) const
|
||||
{
|
||||
return STAmount (getFName (), getSNValue () - static_cast<std::int64_t> (v));
|
||||
return STAmount (
|
||||
getFName (), getSNValue () - static_cast<std::int64_t> (v));
|
||||
}
|
||||
|
||||
STAmount::operator double () const
|
||||
@@ -746,7 +764,8 @@ STAmount::operator double () const
|
||||
if (!mValue)
|
||||
return 0.0;
|
||||
|
||||
if (mIsNegative) return -1.0 * static_cast<double> (mValue) * pow (10.0, mOffset);
|
||||
if (mIsNegative)
|
||||
return -1.0 * static_cast<double> (mValue) * pow (10.0, mOffset);
|
||||
|
||||
return static_cast<double> (mValue) * pow (10.0, mOffset);
|
||||
}
|
||||
@@ -761,18 +780,22 @@ STAmount operator+ (const STAmount& v1, const STAmount& v2)
|
||||
if (v1 == zero)
|
||||
{
|
||||
// Result must be in terms of v1 currency and issuer.
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v2.mValue, v2.mOffset, v2.mIsNegative);
|
||||
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;
|
||||
std::int64_t vv1 = static_cast<std::int64_t> (v1.mValue), vv2 = static_cast<std::int64_t> (v2.mValue);
|
||||
std::int64_t vv1 = static_cast<std::int64_t> (v1.mValue);
|
||||
std::int64_t vv2 = static_cast<std::int64_t> (v2.mValue);
|
||||
|
||||
if (v1.mIsNegative) vv1 = -vv1;
|
||||
if (v1.mIsNegative)
|
||||
vv1 = -vv1;
|
||||
|
||||
if (v2.mIsNegative) vv2 = -vv2;
|
||||
if (v2.mIsNegative)
|
||||
vv2 = -vv2;
|
||||
|
||||
while (ov1 < ov2)
|
||||
{
|
||||
@@ -786,16 +809,17 @@ STAmount operator+ (const STAmount& v1, const STAmount& v2)
|
||||
++ov2;
|
||||
}
|
||||
|
||||
// this addition cannot overflow an std::int64_t, it can overflow an STAmount and the constructor will throw
|
||||
// This addition cannot overflow an std::int64_t. It can overflow an
|
||||
// STAmount and the constructor will throw.
|
||||
|
||||
std::int64_t fv = vv1 + vv2;
|
||||
|
||||
if ((fv >= -10) && (fv <= 10))
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer);
|
||||
else if (fv >= 0)
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, fv, ov1, false);
|
||||
return STAmount (v1.getFName (), v1.mIssue);
|
||||
if (fv >= 0)
|
||||
return STAmount (v1.getFName (), v1.mIssue, fv, ov1, false);
|
||||
else
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, -fv, ov1, true);
|
||||
return STAmount (v1.getFName (), v1.mIssue, -fv, ov1, true);
|
||||
}
|
||||
|
||||
STAmount operator- (const STAmount& v1, const STAmount& v2)
|
||||
@@ -807,16 +831,21 @@ STAmount operator- (const STAmount& v1, const STAmount& v2)
|
||||
|
||||
if (v2.mIsNative)
|
||||
{
|
||||
// XXX This could be better, check for overflow and that maximum range is covered.
|
||||
return STAmount::createFromInt64 (v1.getFName (), v1.getSNValue () - v2.getSNValue ());
|
||||
// XXX This could be better, check for overflow and that maximum range
|
||||
// is covered.
|
||||
return STAmount::createFromInt64 (
|
||||
v1.getFName (), v1.getSNValue () - v2.getSNValue ());
|
||||
}
|
||||
|
||||
int ov1 = v1.mOffset, ov2 = v2.mOffset;
|
||||
std::int64_t vv1 = static_cast<std::int64_t> (v1.mValue), vv2 = static_cast<std::int64_t> (v2.mValue);
|
||||
auto vv1 = static_cast<std::int64_t> (v1.mValue);
|
||||
auto vv2 = static_cast<std::int64_t> (v2.mValue);
|
||||
|
||||
if (v1.mIsNegative) vv1 = -vv1;
|
||||
if (v1.mIsNegative)
|
||||
vv1 = -vv1;
|
||||
|
||||
if (v2.mIsNegative) vv2 = -vv2;
|
||||
if (v2.mIsNegative)
|
||||
vv2 = -vv2;
|
||||
|
||||
while (ov1 < ov2)
|
||||
{
|
||||
@@ -835,23 +864,22 @@ STAmount operator- (const STAmount& v1, const STAmount& v2)
|
||||
std::int64_t fv = vv1 - vv2;
|
||||
|
||||
if ((fv >= -10) && (fv <= 10))
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer);
|
||||
else if (fv >= 0)
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, fv, ov1, false);
|
||||
return STAmount (v1.getFName (), v1.mIssue);
|
||||
if (fv >= 0)
|
||||
return STAmount (v1.getFName (), v1.mIssue, fv, ov1, false);
|
||||
else
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, -fv, ov1, true);
|
||||
return STAmount (v1.getFName (), v1.mIssue, -fv, ov1, true);
|
||||
}
|
||||
|
||||
// NIKB TODO Make Amount::divide skip math if den == QUALITY_ONE
|
||||
STAmount STAmount::divide (
|
||||
const STAmount& num, const STAmount& den, Currency const& currency,
|
||||
Account const& issuer)
|
||||
const STAmount& num, const STAmount& den, Issue const& issue)
|
||||
{
|
||||
if (den == zero)
|
||||
throw std::runtime_error ("division by zero");
|
||||
|
||||
if (num == zero)
|
||||
return STAmount (currency, issuer);
|
||||
return {issue};
|
||||
|
||||
std::uint64_t numVal = num.mValue, denVal = den.mValue;
|
||||
int numOffset = num.mOffset, denOffset = den.mOffset;
|
||||
@@ -884,21 +912,24 @@ STAmount STAmount::divide (
|
||||
// 10^16 <= quotient <= 10^18
|
||||
assert (BN_num_bytes (&v) <= 64);
|
||||
|
||||
return STAmount (currency, issuer, v.getuint64 () + 5,
|
||||
numOffset - denOffset - 17, num.mIsNegative != den.mIsNegative);
|
||||
// TODO(tom): where do 5 and 17 come from?
|
||||
return STAmount (issue, v.getuint64 () + 5,
|
||||
numOffset - denOffset - 17,
|
||||
num.mIsNegative != den.mIsNegative);
|
||||
}
|
||||
|
||||
STAmount STAmount::multiply (
|
||||
const STAmount& v1, const STAmount& v2, Currency const& currency,
|
||||
Account const& issuer)
|
||||
const STAmount& v1, const STAmount& v2, Issue const& issue)
|
||||
{
|
||||
if (v1 == zero || v2 == zero)
|
||||
return STAmount (currency, issuer);
|
||||
return STAmount (issue);
|
||||
|
||||
if (v1.mIsNative && v2.mIsNative && currency.isZero ())
|
||||
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 ();
|
||||
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");
|
||||
@@ -944,8 +975,9 @@ STAmount STAmount::multiply (
|
||||
// 10^16 <= product <= 10^18
|
||||
assert (BN_num_bytes (&v) <= 64);
|
||||
|
||||
return STAmount (currency, issuer, v.getuint64 () + 7, offset1 + offset2 + 14,
|
||||
v1.mIsNegative != v2.mIsNegative);
|
||||
// TODO(tom): where do 7 and 14 come from?
|
||||
return STAmount (issue, v.getuint64 () + 7,
|
||||
offset1 + offset2 + 14, v1.mIsNegative != v2.mIsNegative);
|
||||
}
|
||||
|
||||
// Convert an offer into an index amount so they sort by rate.
|
||||
@@ -964,7 +996,7 @@ std::uint64_t STAmount::getRate (const STAmount& offerOut, const STAmount& offer
|
||||
|
||||
try
|
||||
{
|
||||
STAmount r = divide (offerIn, offerOut, noCurrency(), noAccount());
|
||||
STAmount r = divide (offerIn, offerOut, noIssue());
|
||||
|
||||
if (r == zero) // offer is too good
|
||||
return 0;
|
||||
@@ -985,34 +1017,39 @@ std::uint64_t STAmount::getRate (const STAmount& offerOut, const STAmount& offer
|
||||
STAmount STAmount::setRate (std::uint64_t rate)
|
||||
{
|
||||
if (rate == 0)
|
||||
return STAmount (noCurrency(), noAccount());
|
||||
return STAmount (noIssue());
|
||||
|
||||
std::uint64_t mantissa = rate & ~ (255ull << (64 - 8));
|
||||
int exponent = static_cast<int> (rate >> (64 - 8)) - 100;
|
||||
|
||||
return STAmount (noCurrency(), noAccount(), mantissa, exponent);
|
||||
return STAmount (noIssue(), mantissa, exponent);
|
||||
}
|
||||
|
||||
STAmount STAmount::getPay (const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed)
|
||||
STAmount STAmount::getPay (
|
||||
const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed)
|
||||
{
|
||||
// Someone wants to get (needed) out of the offer, how much should they pay in?
|
||||
// Someone wants to get (needed) out of the offer, how much should they pay
|
||||
// in?
|
||||
if (offerOut == zero)
|
||||
return STAmount (offerIn.getCurrency (), offerIn.getIssuer ());
|
||||
return STAmount (offerIn.issue ());
|
||||
|
||||
if (needed >= offerOut)
|
||||
{
|
||||
// They need more than offered, pay full amount.
|
||||
return needed;
|
||||
}
|
||||
|
||||
STAmount ret = divide (multiply (needed, offerIn, noCurrency(), noAccount()), offerOut, offerIn.getCurrency (), offerIn.getIssuer ());
|
||||
|
||||
STAmount ret = divide (multiply (needed, offerIn, noIssue()),
|
||||
offerOut, offerIn.issue());
|
||||
|
||||
return (ret > offerIn) ? offerIn : ret;
|
||||
}
|
||||
|
||||
STAmount STAmount::deserialize (SerializerIterator& it)
|
||||
{
|
||||
std::unique_ptr<STAmount> s (dynamic_cast<STAmount*> (construct (it, sfGeneric)));
|
||||
auto s = dynamic_cast<STAmount*> (construct (it, sfGeneric));
|
||||
if (!s)
|
||||
throw std::runtime_error("Deserialization error");
|
||||
|
||||
STAmount ret (*s);
|
||||
return ret;
|
||||
}
|
||||
@@ -1028,12 +1065,12 @@ std::string STAmount::getFullText () const
|
||||
{
|
||||
ret += "/";
|
||||
|
||||
if (!mIssuer)
|
||||
if (isXRP (*this))
|
||||
ret += "0";
|
||||
else if (mIssuer == noAccount())
|
||||
else if (mIssue.account == noAccount())
|
||||
ret += "1";
|
||||
else
|
||||
ret += to_string (mIssuer);
|
||||
ret += to_string (mIssue.account);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -1047,9 +1084,9 @@ STAmount STAmount::getRound () const
|
||||
std::uint64_t valueDigits = mValue % 1000000000ull;
|
||||
|
||||
if (valueDigits == 1)
|
||||
return STAmount (mCurrency, mIssuer, mValue - 1, mOffset, mIsNegative);
|
||||
return STAmount (mIssue, mValue - 1, mOffset, mIsNegative);
|
||||
else if (valueDigits == 999999999ull)
|
||||
return STAmount (mCurrency, mIssuer, mValue + 1, mOffset, mIsNegative);
|
||||
return STAmount (mIssue, mValue + 1, mOffset, mIsNegative);
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -1083,11 +1120,11 @@ void STAmount::setJson (Json::Value& elem) const
|
||||
|
||||
if (!mIsNative)
|
||||
{
|
||||
// It is an error for currency or issuer not to be specified for valid json.
|
||||
|
||||
// It is an error for currency or issuer not to be specified for valid
|
||||
// json.
|
||||
elem[jss::value] = getText ();
|
||||
elem[jss::currency] = getHumanCurrency ();
|
||||
elem[jss::issuer] = to_string (mIssuer);
|
||||
elem[jss::issuer] = to_string (mIssue.account);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1110,11 +1147,9 @@ public:
|
||||
static STAmount serializeAndDeserialize (const STAmount& s)
|
||||
{
|
||||
Serializer ser;
|
||||
|
||||
s.add (ser);
|
||||
|
||||
SerializerIterator sit (ser);
|
||||
|
||||
return STAmount::deserialize (sit);
|
||||
}
|
||||
|
||||
@@ -1123,17 +1158,17 @@ public:
|
||||
bool roundTest (int n, int d, int m)
|
||||
{
|
||||
// check STAmount rounding
|
||||
STAmount num (noCurrency(), noAccount(), n);
|
||||
STAmount den (noCurrency(), noAccount(), d);
|
||||
STAmount mul (noCurrency(), noAccount(), m);
|
||||
STAmount quot = STAmount::divide (n, d, noCurrency(), noAccount());
|
||||
STAmount res = STAmount::multiply (quot, mul, noCurrency(), noAccount());
|
||||
STAmount num (noIssue(), n);
|
||||
STAmount den (noIssue(), d);
|
||||
STAmount mul (noIssue(), m);
|
||||
STAmount quot = STAmount::divide (n, d, noIssue());
|
||||
STAmount res = STAmount::multiply (quot, mul, noIssue());
|
||||
|
||||
expect (! res.isNative (), "Product should not be native");
|
||||
|
||||
res.roundSelf ();
|
||||
|
||||
STAmount cmp (noCurrency(), noAccount(), (n * m) / d);
|
||||
STAmount cmp (noIssue(), (n * m) / d);
|
||||
|
||||
expect (! cmp.isNative (), "Comparison amount should not be native");
|
||||
|
||||
@@ -1158,13 +1193,13 @@ public:
|
||||
|
||||
void mulTest (int a, int b)
|
||||
{
|
||||
STAmount aa (noCurrency(), noAccount(), a);
|
||||
STAmount bb (noCurrency(), noAccount(), b);
|
||||
STAmount prod1 (STAmount::multiply (aa, bb, noCurrency(), noAccount()));
|
||||
STAmount aa (noIssue(), a);
|
||||
STAmount bb (noIssue(), b);
|
||||
STAmount prod1 (STAmount::multiply (aa, bb, noIssue()));
|
||||
|
||||
expect (! prod1.isNative ());
|
||||
|
||||
STAmount prod2 (noCurrency(), noAccount(), static_cast<std::uint64_t> (a) * static_cast<std::uint64_t> (b));
|
||||
STAmount prod2 (noIssue(), static_cast<std::uint64_t> (a) * static_cast<std::uint64_t> (b));
|
||||
|
||||
if (prod1 != prod2)
|
||||
{
|
||||
@@ -1179,7 +1214,7 @@ public:
|
||||
}
|
||||
|
||||
aa = a;
|
||||
prod1 = STAmount::multiply (aa, bb, noCurrency(), noAccount());
|
||||
prod1 = STAmount::multiply (aa, bb, noIssue());
|
||||
|
||||
if (prod1 != prod2)
|
||||
{
|
||||
@@ -1374,7 +1409,7 @@ public:
|
||||
{
|
||||
testcase ("custom currency");
|
||||
|
||||
STAmount zeroSt (noCurrency(), noAccount()), one (noCurrency(), noAccount(), 1), hundred (noCurrency(), noAccount(), 100);
|
||||
STAmount zeroSt (noIssue()), one (noIssue(), 1), hundred (noIssue(), 100);
|
||||
|
||||
unexpected (serializeAndDeserialize (zeroSt) != zeroSt, "STAmount fail");
|
||||
|
||||
@@ -1500,33 +1535,33 @@ public:
|
||||
|
||||
unexpected ((hundred != hundred), "STAmount fail");
|
||||
|
||||
unexpected (STAmount (noCurrency(), noAccount()).getText () != "0", "STAmount fail");
|
||||
unexpected (STAmount (noIssue()).getText () != "0", "STAmount fail");
|
||||
|
||||
unexpected (STAmount (noCurrency(), noAccount(), 31).getText () != "31", "STAmount fail");
|
||||
unexpected (STAmount (noIssue(), 31).getText () != "31", "STAmount fail");
|
||||
|
||||
unexpected (STAmount (noCurrency(), noAccount(), 31, 1).getText () != "310", "STAmount fail");
|
||||
unexpected (STAmount (noIssue(), 31, 1).getText () != "310", "STAmount fail");
|
||||
|
||||
unexpected (STAmount (noCurrency(), noAccount(), 31, -1).getText () != "3.1", "STAmount fail");
|
||||
unexpected (STAmount (noIssue(), 31, -1).getText () != "3.1", "STAmount fail");
|
||||
|
||||
unexpected (STAmount (noCurrency(), noAccount(), 31, -2).getText () != "0.31", "STAmount fail");
|
||||
unexpected (STAmount (noIssue(), 31, -2).getText () != "0.31", "STAmount fail");
|
||||
|
||||
unexpected (STAmount::multiply (STAmount (noCurrency(), noAccount(), 20), STAmount (3), noCurrency(), noAccount()).getText () != "60",
|
||||
unexpected (STAmount::multiply (STAmount (noIssue(), 20), STAmount (3), noIssue()).getText () != "60",
|
||||
"STAmount multiply fail 1");
|
||||
|
||||
unexpected (STAmount::multiply (STAmount (noCurrency(), noAccount(), 20), STAmount (3), xrpCurrency (), xrpIssuer()).getText () != "60",
|
||||
unexpected (STAmount::multiply (STAmount (noIssue(), 20), STAmount (3), xrpIssue ()).getText () != "60",
|
||||
"STAmount multiply fail 2");
|
||||
|
||||
unexpected (STAmount::multiply (STAmount (20), STAmount (3), noCurrency(), noAccount()).getText () != "60",
|
||||
unexpected (STAmount::multiply (STAmount (20), STAmount (3), noIssue()).getText () != "60",
|
||||
"STAmount multiply fail 3");
|
||||
|
||||
unexpected (STAmount::multiply (STAmount (20), STAmount (3), xrpCurrency (), xrpIssuer()).getText () != "60",
|
||||
unexpected (STAmount::multiply (STAmount (20), STAmount (3), xrpIssue ()).getText () != "60",
|
||||
"STAmount multiply fail 4");
|
||||
|
||||
if (STAmount::divide (STAmount (noCurrency(), noAccount(), 60), STAmount (3), noCurrency(), noAccount()).getText () != "20")
|
||||
if (STAmount::divide (STAmount (noIssue(), 60), STAmount (3), noIssue()).getText () != "20")
|
||||
{
|
||||
WriteLog (lsFATAL, STAmount) << "60/3 = " <<
|
||||
STAmount::divide (STAmount (noCurrency(), noAccount(), 60),
|
||||
STAmount (3), noCurrency(), noAccount()).getText ();
|
||||
STAmount::divide (STAmount (noIssue(), 60),
|
||||
STAmount (3), noIssue()).getText ();
|
||||
fail ("STAmount divide fail");
|
||||
}
|
||||
else
|
||||
@@ -1534,21 +1569,21 @@ public:
|
||||
pass ();
|
||||
}
|
||||
|
||||
unexpected (STAmount::divide (STAmount (noCurrency(), noAccount(), 60), STAmount (3), xrpCurrency (), xrpIssuer()).getText () != "20",
|
||||
unexpected (STAmount::divide (STAmount (noIssue(), 60), STAmount (3), xrpIssue ()).getText () != "20",
|
||||
"STAmount divide fail");
|
||||
|
||||
unexpected (STAmount::divide (STAmount (noCurrency(), noAccount(), 60), STAmount (noCurrency(), noAccount(), 3), noCurrency(), noAccount()).getText () != "20",
|
||||
unexpected (STAmount::divide (STAmount (noIssue(), 60), STAmount (noIssue(), 3), noIssue()).getText () != "20",
|
||||
"STAmount divide fail");
|
||||
|
||||
unexpected (STAmount::divide (STAmount (noCurrency(), noAccount(), 60), STAmount (noCurrency(), noAccount(), 3), xrpCurrency (), xrpIssuer()).getText () != "20",
|
||||
unexpected (STAmount::divide (STAmount (noIssue(), 60), STAmount (noIssue(), 3), xrpIssue ()).getText () != "20",
|
||||
"STAmount divide fail");
|
||||
|
||||
STAmount a1 (noCurrency(), noAccount(), 60), a2 (noCurrency(), noAccount(), 10, -1);
|
||||
STAmount a1 (noIssue(), 60), a2 (noIssue(), 10, -1);
|
||||
|
||||
unexpected (STAmount::divide (a2, a1, noCurrency(), noAccount()) != STAmount::setRate (STAmount::getRate (a1, a2)),
|
||||
unexpected (STAmount::divide (a2, a1, noIssue()) != STAmount::setRate (STAmount::getRate (a1, a2)),
|
||||
"STAmount setRate(getRate) fail");
|
||||
|
||||
unexpected (STAmount::divide (a1, a2, noCurrency(), noAccount()) != STAmount::setRate (STAmount::getRate (a2, a1)),
|
||||
unexpected (STAmount::divide (a1, a2, noIssue()) != STAmount::setRate (STAmount::getRate (a2, a1)),
|
||||
"STAmount setRate(getRate) fail");
|
||||
}
|
||||
|
||||
@@ -1587,22 +1622,22 @@ public:
|
||||
unexpected (STAmount::getRate (STAmount (10), STAmount (1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 2");
|
||||
|
||||
unexpected (STAmount::getRate (STAmount (noCurrency(), noAccount(), 1), STAmount (noCurrency(), noAccount(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
|
||||
unexpected (STAmount::getRate (STAmount (noIssue(), 1), STAmount (noIssue(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 3");
|
||||
|
||||
unexpected (STAmount::getRate (STAmount (noCurrency(), noAccount(), 10), STAmount (noCurrency(), noAccount(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
|
||||
unexpected (STAmount::getRate (STAmount (noIssue(), 10), STAmount (noIssue(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 4");
|
||||
|
||||
unexpected (STAmount::getRate (STAmount (noCurrency(), noAccount(), 1), STAmount (10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
|
||||
unexpected (STAmount::getRate (STAmount (noIssue(), 1), STAmount (10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 5");
|
||||
|
||||
unexpected (STAmount::getRate (STAmount (noCurrency(), noAccount(), 10), STAmount (1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
|
||||
unexpected (STAmount::getRate (STAmount (noIssue(), 10), STAmount (1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 6");
|
||||
|
||||
unexpected (STAmount::getRate (STAmount (1), STAmount (noCurrency(), noAccount(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
|
||||
unexpected (STAmount::getRate (STAmount (1), STAmount (noIssue(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 7");
|
||||
|
||||
unexpected (STAmount::getRate (STAmount (10), STAmount (noCurrency(), noAccount(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
|
||||
unexpected (STAmount::getRate (STAmount (10), STAmount (noIssue(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
|
||||
"STAmount getRate fail 8");
|
||||
|
||||
roundTest (1, 3, 3);
|
||||
@@ -1637,29 +1672,33 @@ public:
|
||||
testcase ("underflow");
|
||||
|
||||
STAmount bigNative (STAmount::cMaxNative / 2);
|
||||
STAmount bigValue (noCurrency(), noAccount(),
|
||||
STAmount bigValue (noIssue(),
|
||||
(STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMaxOffset - 1);
|
||||
STAmount smallValue (noCurrency(), noAccount(),
|
||||
STAmount smallValue (noIssue(),
|
||||
(STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMinOffset + 1);
|
||||
STAmount zeroSt (noCurrency(), noAccount(), 0);
|
||||
STAmount zeroSt (noIssue(), 0);
|
||||
|
||||
STAmount smallXsmall = STAmount::multiply (smallValue, smallValue, noCurrency(), noAccount());
|
||||
STAmount smallXsmall = STAmount::multiply (smallValue, smallValue, noIssue());
|
||||
|
||||
expect (smallXsmall == zero, "smallXsmall != 0");
|
||||
|
||||
STAmount bigDsmall = STAmount::divide (smallValue, bigValue, noCurrency(), noAccount());
|
||||
STAmount bigDsmall = STAmount::divide (smallValue, bigValue, noIssue());
|
||||
|
||||
expect (bigDsmall == zero, beast::String ("small/big != 0: ") + bigDsmall.getText ());
|
||||
|
||||
bigDsmall = STAmount::divide (smallValue, bigNative, noCurrency(), xrpIssuer ());
|
||||
#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 = STAmount::divide (smallValue, bigNative, noCurrency(), xrpAccount ());
|
||||
#endif
|
||||
|
||||
expect (bigDsmall == zero, beast::String ("small/bigNative != 0: ") + bigDsmall.getText ());
|
||||
|
||||
bigDsmall = STAmount::divide (smallValue, bigValue, xrpCurrency (), xrpIssuer ());
|
||||
bigDsmall = STAmount::divide (smallValue, bigValue, xrpIssue ());
|
||||
|
||||
expect (bigDsmall == zero, beast::String ("(small/big)->N != 0: ") + bigDsmall.getText ());
|
||||
|
||||
bigDsmall = STAmount::divide (smallValue, bigNative, xrpCurrency (), xrpIssuer ());
|
||||
bigDsmall = STAmount::divide (smallValue, bigNative, xrpIssue ());
|
||||
|
||||
expect (bigDsmall == zero, beast::String ("(small/bigNative)->N != 0: ") + bigDsmall.getText ());
|
||||
|
||||
@@ -1688,27 +1727,27 @@ public:
|
||||
int offset = -14;
|
||||
STAmount::canonicalizeRound (false, value, offset, true);
|
||||
|
||||
STAmount one (noCurrency(), noAccount(), 1);
|
||||
STAmount two (noCurrency(), noAccount(), 2);
|
||||
STAmount three (noCurrency(), noAccount(), 3);
|
||||
STAmount one (noIssue(), 1);
|
||||
STAmount two (noIssue(), 2);
|
||||
STAmount three (noIssue(), 3);
|
||||
|
||||
STAmount oneThird1 = STAmount::divRound (one, three, noCurrency(), noAccount(), false);
|
||||
STAmount oneThird2 = STAmount::divide (one, three, noCurrency(), noAccount());
|
||||
STAmount oneThird3 = STAmount::divRound (one, three, noCurrency(), noAccount(), true);
|
||||
STAmount oneThird1 = STAmount::divRound (one, three, noIssue(), false);
|
||||
STAmount oneThird2 = STAmount::divide (one, three, noIssue());
|
||||
STAmount oneThird3 = STAmount::divRound (one, three, noIssue(), true);
|
||||
WriteLog (lsINFO, STAmount) << oneThird1;
|
||||
WriteLog (lsINFO, STAmount) << oneThird2;
|
||||
WriteLog (lsINFO, STAmount) << oneThird3;
|
||||
|
||||
STAmount twoThird1 = STAmount::divRound (two, three, noCurrency(), noAccount(), false);
|
||||
STAmount twoThird2 = STAmount::divide (two, three, noCurrency(), noAccount());
|
||||
STAmount twoThird3 = STAmount::divRound (two, three, noCurrency(), noAccount(), true);
|
||||
STAmount twoThird1 = STAmount::divRound (two, three, noIssue(), false);
|
||||
STAmount twoThird2 = STAmount::divide (two, three, noIssue());
|
||||
STAmount twoThird3 = STAmount::divRound (two, three, noIssue(), true);
|
||||
WriteLog (lsINFO, STAmount) << twoThird1;
|
||||
WriteLog (lsINFO, STAmount) << twoThird2;
|
||||
WriteLog (lsINFO, STAmount) << twoThird3;
|
||||
|
||||
STAmount oneA = STAmount::mulRound (oneThird1, three, noCurrency(), noAccount(), false);
|
||||
STAmount oneB = STAmount::multiply (oneThird2, three, noCurrency(), noAccount());
|
||||
STAmount oneC = STAmount::mulRound (oneThird3, three, noCurrency(), noAccount(), true);
|
||||
STAmount oneA = STAmount::mulRound (oneThird1, three, noIssue(), false);
|
||||
STAmount oneB = STAmount::multiply (oneThird2, three, noIssue());
|
||||
STAmount oneC = STAmount::mulRound (oneThird3, three, noIssue(), true);
|
||||
WriteLog (lsINFO, STAmount) << oneA;
|
||||
WriteLog (lsINFO, STAmount) << oneB;
|
||||
WriteLog (lsINFO, STAmount) << oneC;
|
||||
@@ -1720,9 +1759,9 @@ public:
|
||||
WriteLog (lsINFO, STAmount) << fourThirdsB;
|
||||
WriteLog (lsINFO, STAmount) << fourThirdsC;
|
||||
|
||||
STAmount dripTest1 = STAmount::mulRound (twoThird2, two, xrpCurrency (), xrpIssuer (), false);
|
||||
STAmount dripTest2 = STAmount::multiply (twoThird2, two, xrpCurrency (), xrpIssuer ());
|
||||
STAmount dripTest3 = STAmount::mulRound (twoThird2, two, xrpCurrency (), xrpIssuer (), true);
|
||||
STAmount dripTest1 = STAmount::mulRound (twoThird2, two, xrpIssue (), false);
|
||||
STAmount dripTest2 = STAmount::multiply (twoThird2, two, xrpIssue ());
|
||||
STAmount dripTest3 = STAmount::mulRound (twoThird2, two, xrpIssue (), true);
|
||||
WriteLog (lsINFO, STAmount) << dripTest1;
|
||||
WriteLog (lsINFO, STAmount) << dripTest2;
|
||||
WriteLog (lsINFO, STAmount) << dripTest3;
|
||||
|
||||
458
src/ripple/module/data/protocol/STAmount.h
Normal file
458
src/ripple/module/data/protocol/STAmount.h
Normal file
@@ -0,0 +1,458 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_STAMOUNT_H
|
||||
#define RIPPLE_STAMOUNT_H
|
||||
|
||||
#include <ripple/module/data/protocol/FieldNames.h>
|
||||
#include <ripple/module/data/protocol/Serializer.h>
|
||||
#include <ripple/module/data/protocol/SerializedType.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// Internal form:
|
||||
// 1: If amount is zero, then value is zero and offset is -100
|
||||
// 2: Otherwise:
|
||||
// legal offset range is -96 to +80 inclusive
|
||||
// value range is 10^15 to (10^16 - 1) inclusive
|
||||
// amount = value * [10 ^ offset]
|
||||
|
||||
// Wire form:
|
||||
// High 8 bits are (offset+142), legal range is, 80 to 22 inclusive
|
||||
// Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive
|
||||
class STAmount : public SerializedType
|
||||
{
|
||||
public:
|
||||
static const int cMinOffset = -96;
|
||||
static const int cMaxOffset = 80;
|
||||
|
||||
static const std::uint64_t cMinValue = 1000000000000000ull;
|
||||
static const std::uint64_t cMaxValue = 9999999999999999ull;
|
||||
static const std::uint64_t cMaxNative = 9000000000000000000ull;
|
||||
|
||||
// Max native value on network.
|
||||
static const std::uint64_t cMaxNativeN = 100000000000000000ull;
|
||||
static const std::uint64_t cNotNative = 0x8000000000000000ull;
|
||||
static const std::uint64_t cPosNative = 0x4000000000000000ull;
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
STAmount (SField::ref n, std::int64_t v)
|
||||
: SerializedType (n), mOffset (0), mIsNative (true)
|
||||
{
|
||||
set (v);
|
||||
}
|
||||
|
||||
STAmount (Issue const& issue,
|
||||
std::uint64_t uV = 0, int iOff = 0, bool negative = false)
|
||||
: mIssue(issue), mValue (uV), mOffset (iOff), mIsNegative (negative)
|
||||
{
|
||||
canonicalize ();
|
||||
}
|
||||
|
||||
STAmount (Issue const& issue,
|
||||
std::uint32_t uV, int iOff = 0, bool negative = false)
|
||||
: mIssue(issue), mValue (uV), mOffset (iOff), mIsNegative (negative)
|
||||
{
|
||||
canonicalize ();
|
||||
}
|
||||
|
||||
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 v, int iOff = 0)
|
||||
: mIssue(issue), mOffset (iOff)
|
||||
{
|
||||
set (v);
|
||||
canonicalize ();
|
||||
}
|
||||
|
||||
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 ();
|
||||
}
|
||||
|
||||
STAmount (SField::ref n, Issue const& issue, int v, int off = 0)
|
||||
: SerializedType (n), mIssue(issue), mOffset (off)
|
||||
{
|
||||
set (v);
|
||||
canonicalize ();
|
||||
}
|
||||
|
||||
STAmount (SField::ref, const Json::Value&);
|
||||
|
||||
static STAmount createFromInt64 (SField::ref n, std::int64_t v);
|
||||
|
||||
static std::unique_ptr<SerializedType> deserialize (
|
||||
SerializerIterator& sit, SField::ref name)
|
||||
{
|
||||
return std::unique_ptr<SerializedType> (construct (sit, name));
|
||||
}
|
||||
|
||||
bool bSetJson (const Json::Value& jvSource);
|
||||
|
||||
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;
|
||||
|
||||
int getExponent () const
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
std::uint64_t getMantissa () const
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
int signum () const
|
||||
{
|
||||
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
|
||||
{
|
||||
// TODO(tom): what does this next comment mean here?
|
||||
// See https://ripplelabs.atlassian.net/browse/WC-1847?jql=
|
||||
return STAmount (mIssue);
|
||||
}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
// VFALCO: Why -100?
|
||||
mOffset = mIsNative ? 0 : -100;
|
||||
mValue = 0;
|
||||
mIsNegative = false;
|
||||
}
|
||||
|
||||
// Zero while copying currency and issuer.
|
||||
void clear (const STAmount& saTmpl)
|
||||
{
|
||||
clear(saTmpl.mIssue);
|
||||
}
|
||||
|
||||
void clear (Issue const& issue)
|
||||
{
|
||||
setIssue(issue);
|
||||
clear ();
|
||||
}
|
||||
|
||||
STAmount& operator=(beast::Zero)
|
||||
{
|
||||
clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
int compare (const STAmount&) const;
|
||||
|
||||
Account const& getIssuer () const
|
||||
{
|
||||
return mIssue.account;
|
||||
}
|
||||
|
||||
void setIssuer (Account const& uIssuer)
|
||||
{
|
||||
mIssue.account = uIssuer;
|
||||
setIssue(mIssue);
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
bool setValue (const std::string& sAmount);
|
||||
bool setFullValue (
|
||||
const std::string& sAmount, const std::string& sCurrency = "",
|
||||
const std::string& sIssuer = "");
|
||||
void setValue (const STAmount&);
|
||||
|
||||
virtual bool isEquivalent (const SerializedType& t) const;
|
||||
virtual bool isDefault () const
|
||||
{
|
||||
return (mValue == 0) && mIsNative;
|
||||
}
|
||||
|
||||
bool operator== (const STAmount&) const;
|
||||
bool operator!= (const STAmount&) const;
|
||||
bool operator< (const STAmount&) const;
|
||||
bool operator> (const STAmount&) const;
|
||||
bool operator<= (const STAmount&) const;
|
||||
bool operator>= (const STAmount&) const;
|
||||
bool isComparable (const STAmount&) const;
|
||||
void throwComparable (const STAmount&) 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+= (const STAmount&);
|
||||
STAmount& operator-= (const STAmount&);
|
||||
STAmount& operator+= (std::uint64_t);
|
||||
STAmount& operator-= (std::uint64_t);
|
||||
STAmount& operator= (std::uint64_t);
|
||||
|
||||
operator double () const;
|
||||
|
||||
friend STAmount operator+ (const STAmount& v1, const STAmount& v2);
|
||||
friend STAmount operator- (const STAmount& v1, const STAmount& v2);
|
||||
|
||||
static STAmount divide (
|
||||
const STAmount& v1, const STAmount& v2, Issue const& issue);
|
||||
|
||||
static STAmount divide (
|
||||
const STAmount& v1, const STAmount& v2, const STAmount& saUnit)
|
||||
{
|
||||
return divide (v1, v2, saUnit.issue ());
|
||||
}
|
||||
static STAmount divide (const STAmount& v1, const STAmount& v2)
|
||||
{
|
||||
return divide (v1, v2, v1);
|
||||
}
|
||||
|
||||
static STAmount multiply (
|
||||
const STAmount& v1, const STAmount& v2, Issue const& issue);
|
||||
|
||||
static STAmount multiply (
|
||||
const STAmount& v1, const STAmount& v2, const STAmount& saUnit)
|
||||
{
|
||||
return multiply (v1, v2, saUnit.issue());
|
||||
}
|
||||
static STAmount multiply (const STAmount& v1, const STAmount& 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 (
|
||||
const STAmount& v1, const STAmount& v2, bool roundUp);
|
||||
static STAmount subRound (
|
||||
const STAmount& v1, const STAmount& v2, bool roundUp);
|
||||
static STAmount mulRound (
|
||||
const STAmount& v1, const STAmount& v2, Issue const& issue,
|
||||
bool roundUp);
|
||||
static STAmount divRound (
|
||||
const STAmount& v1, const STAmount& v2, Issue const& issue,
|
||||
bool roundUp);
|
||||
|
||||
static STAmount mulRound (
|
||||
const STAmount& v1, const STAmount& v2, const STAmount& saUnit,
|
||||
bool roundUp)
|
||||
{
|
||||
return mulRound (v1, v2, saUnit.issue (), roundUp);
|
||||
}
|
||||
static STAmount mulRound (
|
||||
const STAmount& v1, const STAmount& v2, bool roundUp)
|
||||
{
|
||||
return mulRound (v1, v2, v1.issue (), roundUp);
|
||||
}
|
||||
static STAmount divRound (
|
||||
const STAmount& v1, const STAmount& v2, const STAmount& saUnit,
|
||||
bool roundUp)
|
||||
{
|
||||
return divRound (v1, v2, saUnit.issue (), roundUp);
|
||||
}
|
||||
static STAmount divRound (
|
||||
const STAmount& v1, const STAmount& 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 (
|
||||
const STAmount& offerOut, const STAmount& 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 (
|
||||
const STAmount& out, const STAmount& in, const STAmount& 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;
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline bool isXRP(STAmount const& amount)
|
||||
{
|
||||
return isXRP (amount.issue().currency);
|
||||
}
|
||||
|
||||
// VFALCO TODO Make static member accessors for these in STAmount
|
||||
extern const STAmount saZero;
|
||||
extern const STAmount saOne;
|
||||
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
@@ -73,7 +73,7 @@ STAmount STAmount::addRound (const STAmount& v1, const STAmount& v2, bool roundU
|
||||
return v1;
|
||||
|
||||
if (v1.mValue == 0)
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v2.mValue,
|
||||
return STAmount (v1.getFName (), v1.mIssue, v2.mValue,
|
||||
v2.mOffset, v2.mIsNegative);
|
||||
|
||||
if (v1.mIsNative)
|
||||
@@ -122,18 +122,18 @@ STAmount STAmount::addRound (const STAmount& v1, const STAmount& v2, bool roundU
|
||||
std::int64_t fv = vv1 + vv2;
|
||||
|
||||
if ((fv >= -10) && (fv <= 10))
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer);
|
||||
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.mCurrency, v1.mIssuer, v, ov1, false);
|
||||
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.mCurrency, v1.mIssuer, v, ov1, true);
|
||||
return STAmount (v1.getFName (), v1.mIssue, v, ov1, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ STAmount STAmount::subRound (const STAmount& v1, const STAmount& v2, bool roundU
|
||||
return v1;
|
||||
|
||||
if (v1.mValue == 0)
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v2.mValue,
|
||||
return STAmount (v1.getFName (), v1.mIssue, v2.mValue,
|
||||
v2.mOffset, !v2.mIsNegative);
|
||||
|
||||
if (v1.mIsNative)
|
||||
@@ -194,30 +194,29 @@ STAmount STAmount::subRound (const STAmount& v1, const STAmount& v2, bool roundU
|
||||
std::int64_t fv = vv1 + vv2;
|
||||
|
||||
if ((fv >= -10) && (fv <= 10))
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer);
|
||||
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.mCurrency, v1.mIssuer, v, ov1, false);
|
||||
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.mCurrency, v1.mIssuer, v, ov1, true);
|
||||
return STAmount (v1.getFName (), v1.mIssue, v, ov1, true);
|
||||
}
|
||||
}
|
||||
|
||||
STAmount STAmount::mulRound (
|
||||
const STAmount& v1, const STAmount& v2, Currency const& currency,
|
||||
Account const& issuer, bool roundUp)
|
||||
const STAmount& v1, const STAmount& v2, Issue const& issue, bool roundUp)
|
||||
{
|
||||
if (v1 == zero || v2 == zero)
|
||||
return STAmount (currency, issuer);
|
||||
return {issue};
|
||||
|
||||
if (v1.mIsNative && v2.mIsNative && currency.isZero ())
|
||||
if (v1.mIsNative && v2.mIsNative && isXRP (issue))
|
||||
{
|
||||
std::uint64_t minV = (v1.getSNValue () < v2.getSNValue ()) ?
|
||||
v1.getSNValue () : v2.getSNValue ();
|
||||
@@ -274,19 +273,19 @@ STAmount STAmount::mulRound (
|
||||
std::uint64_t amount = v.getuint64 ();
|
||||
int offset = offset1 + offset2 + 14;
|
||||
canonicalizeRound (
|
||||
currency.isZero (), amount, offset, resultNegative != roundUp);
|
||||
return STAmount (currency, issuer, amount, offset, resultNegative);
|
||||
isXRP (issue), amount, offset, resultNegative != roundUp);
|
||||
return STAmount (issue, amount, offset, resultNegative);
|
||||
}
|
||||
|
||||
STAmount STAmount::divRound (
|
||||
const STAmount& num, const STAmount& den,
|
||||
Currency const& currency, Account const& issuer, bool roundUp)
|
||||
Issue const& issue, bool roundUp)
|
||||
{
|
||||
if (den == zero)
|
||||
throw std::runtime_error ("division by zero");
|
||||
|
||||
if (num == zero)
|
||||
return STAmount (currency, issuer);
|
||||
return {issue};
|
||||
|
||||
std::uint64_t numVal = num.mValue, denVal = den.mValue;
|
||||
int numOffset = num.mOffset, denOffset = den.mOffset;
|
||||
@@ -325,8 +324,8 @@ STAmount STAmount::divRound (
|
||||
std::uint64_t amount = v.getuint64 ();
|
||||
int offset = numOffset - denOffset - 17;
|
||||
canonicalizeRound (
|
||||
currency.isZero (), amount, offset, resultNegative != roundUp);
|
||||
return STAmount (currency, issuer, amount, offset, resultNegative);
|
||||
isXRP (issue), amount, offset, resultNegative != roundUp);
|
||||
return STAmount (issue, amount, offset, resultNegative);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
203
src/ripple/module/data/protocol/SerializedType.h
Normal file
203
src/ripple/module/data/protocol/SerializedType.h
Normal file
@@ -0,0 +1,203 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_SERIALIZEDTYPE_H
|
||||
#define RIPPLE_SERIALIZEDTYPE_H
|
||||
|
||||
#include <ripple/module/data/protocol/FieldNames.h>
|
||||
#include <ripple/module/data/protocol/Serializer.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// VFALCO TODO fix this restriction on copy assignment.
|
||||
//
|
||||
// CAUTION: Do not create a vector (or similar container) of any object derived
|
||||
// from SerializedType. Use Boost ptr_* containers. The copy assignment operator
|
||||
// of SerializedType has semantics that will cause contained types to change
|
||||
// their names when an object is deleted because copy assignment is used to
|
||||
// "slide down" the remaining types and this will not copy the field
|
||||
// name. Changing the copy assignment operator to copy the field name breaks the
|
||||
// use of copy assignment just to copy values, which is used in the transaction
|
||||
// engine code.
|
||||
|
||||
// VFALCO TODO Remove this unused enum
|
||||
/*
|
||||
enum PathFlags
|
||||
{
|
||||
PF_END = 0x00, // End of current path & path list.
|
||||
PF_BOUNDARY = 0xFF, // End of current path & new path follows.
|
||||
|
||||
PF_ACCOUNT = 0x01,
|
||||
PF_OFFER = 0x02,
|
||||
|
||||
PF_WANTED_CURRENCY = 0x10,
|
||||
PF_WANTED_ISSUER = 0x20,
|
||||
PF_REDEEM = 0x40,
|
||||
PF_ISSUE = 0x80,
|
||||
};
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A type which can be exported to a well known binary format.
|
||||
|
||||
A SerializedType:
|
||||
- Always a field
|
||||
- Can always go inside an eligible enclosing SerializedType
|
||||
(such as STArray)
|
||||
- Has a field name
|
||||
|
||||
|
||||
Like JSON, a SerializedObject is a basket which has rules
|
||||
on what it can hold.
|
||||
*/
|
||||
// VFALCO TODO Document this as it looks like a central class.
|
||||
// STObject is derived from it
|
||||
//
|
||||
class SerializedType
|
||||
{
|
||||
public:
|
||||
SerializedType () : fName (&sfGeneric)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
explicit SerializedType (SField::ref n) : fName (&n)
|
||||
{
|
||||
assert (fName);
|
||||
}
|
||||
|
||||
virtual ~SerializedType () { }
|
||||
|
||||
static std::unique_ptr<SerializedType> deserialize (SField::ref name)
|
||||
{
|
||||
return std::unique_ptr<SerializedType> (new SerializedType (name));
|
||||
}
|
||||
|
||||
/** A SerializeType is a field.
|
||||
This sets the name.
|
||||
*/
|
||||
void setFName (SField::ref n)
|
||||
{
|
||||
fName = &n;
|
||||
assert (fName);
|
||||
}
|
||||
SField::ref getFName () const
|
||||
{
|
||||
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
|
||||
{
|
||||
assert (fName->isBinary ());
|
||||
s.addFieldID (fName->fieldType, fName->fieldValue);
|
||||
}
|
||||
|
||||
SerializedType& operator= (const SerializedType& t);
|
||||
|
||||
bool operator== (const SerializedType& t) const
|
||||
{
|
||||
return (getSType () == t.getSType ()) && isEquivalent (t);
|
||||
}
|
||||
bool operator!= (const SerializedType& t) const
|
||||
{
|
||||
return (getSType () != t.getSType ()) || !isEquivalent (t);
|
||||
}
|
||||
|
||||
virtual bool isDefault () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class D>
|
||||
D& downcast()
|
||||
{
|
||||
D* ptr = dynamic_cast<D*> (this);
|
||||
if (ptr == nullptr)
|
||||
throw std::runtime_error ("type mismatch");
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
template <class D>
|
||||
D const& downcast() const
|
||||
{
|
||||
D const * ptr = dynamic_cast<D const*> (this);
|
||||
if (ptr == nullptr)
|
||||
throw std::runtime_error ("type mismatch");
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
// VFALCO TODO make accessors for this
|
||||
SField::ptr fName;
|
||||
|
||||
private:
|
||||
virtual SerializedType* duplicate () const
|
||||
{
|
||||
return new SerializedType (*fName);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline SerializedType* new_clone (const SerializedType& s)
|
||||
{
|
||||
SerializedType* const copy (s.clone ().release ());
|
||||
assert (typeid (*copy) == typeid (s));
|
||||
return copy;
|
||||
}
|
||||
|
||||
inline void delete_clone (const SerializedType* s)
|
||||
{
|
||||
boost::checked_delete (s);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& out, const SerializedType& t)
|
||||
{
|
||||
return out << t.getFullText ();
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
const STAmount saZero (noCurrency(), noAccount(), 0);
|
||||
const STAmount saOne (noCurrency(), noAccount(), 1);
|
||||
const STAmount saZero (noIssue(), 0);
|
||||
const STAmount saOne (noIssue(), 1);
|
||||
|
||||
SerializedType& SerializedType::operator= (const SerializedType& t)
|
||||
{
|
||||
@@ -522,26 +522,6 @@ std::string STPath::getText () const
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
std::string STPathSet::getText () const
|
||||
{
|
||||
std::string ret ("{");
|
||||
bool firstPath = true;
|
||||
|
||||
BOOST_FOREACH (std::vector<STPath>::const_iterator::value_type it, value)
|
||||
{
|
||||
if (!firstPath)
|
||||
{
|
||||
ret += ", ";
|
||||
firstPath = false;
|
||||
}
|
||||
|
||||
ret += it.getText ();
|
||||
}
|
||||
return ret + "}";
|
||||
}
|
||||
#endif
|
||||
|
||||
void STPathSet::add (Serializer& s) const
|
||||
{
|
||||
assert (fName->isBinary ());
|
||||
|
||||
@@ -22,183 +22,14 @@
|
||||
|
||||
#include <ripple/module/data/protocol/FieldNames.h>
|
||||
#include <ripple/module/data/protocol/Serializer.h>
|
||||
#include <ripple/module/data/protocol/SerializedType.h>
|
||||
#include <ripple/module/data/protocol/STAmount.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// VFALCO TODO fix this restriction on copy assignment.
|
||||
//
|
||||
// CAUTION: Do not create a vector (or similar container) of any object derived
|
||||
// from SerializedType. Use Boost ptr_* containers. The copy assignment operator
|
||||
// of SerializedType has semantics that will cause contained types to change
|
||||
// their names when an object is deleted because copy assignment is used to
|
||||
// "slide down" the remaining types and this will not copy the field
|
||||
// name. Changing the copy assignment operator to copy the field name breaks the
|
||||
// use of copy assignment just to copy values, which is used in the transaction
|
||||
// engine code.
|
||||
|
||||
// VFALCO TODO Remove this unused enum
|
||||
/*
|
||||
enum PathFlags
|
||||
{
|
||||
PF_END = 0x00, // End of current path & path list.
|
||||
PF_BOUNDARY = 0xFF, // End of current path & new path follows.
|
||||
|
||||
PF_ACCOUNT = 0x01,
|
||||
PF_OFFER = 0x02,
|
||||
|
||||
PF_WANTED_CURRENCY = 0x10,
|
||||
PF_WANTED_ISSUER = 0x20,
|
||||
PF_REDEEM = 0x40,
|
||||
PF_ISSUE = 0x80,
|
||||
};
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A type which can be exported to a well known binary format.
|
||||
|
||||
A SerializedType:
|
||||
- Always a field
|
||||
- Can always go inside an eligible enclosing SerializedType
|
||||
(such as STArray)
|
||||
- Has a field name
|
||||
|
||||
|
||||
Like JSON, a SerializedObject is a basket which has rules
|
||||
on what it can hold.
|
||||
*/
|
||||
// VFALCO TODO Document this as it looks like a central class.
|
||||
// STObject is derived from it
|
||||
//
|
||||
class SerializedType
|
||||
{
|
||||
public:
|
||||
SerializedType () : fName (&sfGeneric)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
explicit SerializedType (SField::ref n) : fName (&n)
|
||||
{
|
||||
assert (fName);
|
||||
}
|
||||
|
||||
virtual ~SerializedType () { }
|
||||
|
||||
static std::unique_ptr<SerializedType> deserialize (SField::ref name)
|
||||
{
|
||||
return std::unique_ptr<SerializedType> (new SerializedType (name));
|
||||
}
|
||||
|
||||
/** A SerializeType is a field.
|
||||
This sets the name.
|
||||
*/
|
||||
void setFName (SField::ref n)
|
||||
{
|
||||
fName = &n;
|
||||
assert (fName);
|
||||
}
|
||||
SField::ref getFName () const
|
||||
{
|
||||
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
|
||||
{
|
||||
assert (fName->isBinary ());
|
||||
s.addFieldID (fName->fieldType, fName->fieldValue);
|
||||
}
|
||||
|
||||
SerializedType& operator= (const SerializedType& t);
|
||||
|
||||
bool operator== (const SerializedType& t) const
|
||||
{
|
||||
return (getSType () == t.getSType ()) && isEquivalent (t);
|
||||
}
|
||||
bool operator!= (const SerializedType& t) const
|
||||
{
|
||||
return (getSType () != t.getSType ()) || !isEquivalent (t);
|
||||
}
|
||||
|
||||
virtual bool isDefault () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class D>
|
||||
D& downcast()
|
||||
{
|
||||
D* ptr = dynamic_cast<D*> (this);
|
||||
if (ptr == nullptr)
|
||||
throw std::runtime_error ("type mismatch");
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
template <class D>
|
||||
D const& downcast() const
|
||||
{
|
||||
D const * ptr = dynamic_cast<D const*> (this);
|
||||
if (ptr == nullptr)
|
||||
throw std::runtime_error ("type mismatch");
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
// VFALCO TODO make accessors for this
|
||||
SField::ptr fName;
|
||||
|
||||
private:
|
||||
virtual SerializedType* duplicate () const
|
||||
{
|
||||
return new SerializedType (*fName);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline SerializedType* new_clone (const SerializedType& s)
|
||||
{
|
||||
SerializedType* const copy (s.clone ().release ());
|
||||
assert (typeid (*copy) == typeid (s));
|
||||
return copy;
|
||||
}
|
||||
|
||||
inline void delete_clone (const SerializedType* s)
|
||||
{
|
||||
boost::checked_delete (s);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& out, const SerializedType& t)
|
||||
{
|
||||
return out << t.getFullText ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TODO(tom): make STUInt8, STUInt16, STUInt32, STUInt64 a single templated
|
||||
// class to reduce the quadruple redundancy we have all over the rippled code
|
||||
// regarding uint-like types.
|
||||
|
||||
class STUInt8 : public SerializedType
|
||||
{
|
||||
@@ -443,406 +274,10 @@ private:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Internal form:
|
||||
// 1: If amount is zero, then value is zero and offset is -100
|
||||
// 2: Otherwise:
|
||||
// legal offset range is -96 to +80 inclusive
|
||||
// value range is 10^15 to (10^16 - 1) inclusive
|
||||
// amount = value * [10 ^ offset]
|
||||
|
||||
// Wire form:
|
||||
// High 8 bits are (offset+142), legal range is, 80 to 22 inclusive
|
||||
// Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive
|
||||
class STAmount : public SerializedType
|
||||
{
|
||||
public:
|
||||
static const int cMinOffset = -96, cMaxOffset = 80;
|
||||
static const std::uint64_t cMinValue = 1000000000000000ull, cMaxValue = 9999999999999999ull;
|
||||
static const std::uint64_t cMaxNative = 9000000000000000000ull;
|
||||
static const std::uint64_t cMaxNativeN = 100000000000000000ull; // max native value on network
|
||||
static const std::uint64_t cNotNative = 0x8000000000000000ull;
|
||||
static const std::uint64_t cPosNative = 0x4000000000000000ull;
|
||||
|
||||
static std::uint64_t uRateOne;
|
||||
|
||||
STAmount (std::uint64_t v = 0, bool isNeg = false)
|
||||
: mValue (v), mOffset (0), mIsNative (true), mIsNegative (isNeg)
|
||||
{
|
||||
if (v == 0) mIsNegative = false;
|
||||
}
|
||||
|
||||
STAmount (SField::ref n, std::uint64_t v = 0, bool isNeg = false)
|
||||
: SerializedType (n), mValue (v), mOffset (0), mIsNative (true), mIsNegative (isNeg)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
STAmount (SField::ref n, std::int64_t v) : SerializedType (n), mOffset (0), mIsNative (true)
|
||||
{
|
||||
set (v);
|
||||
}
|
||||
|
||||
STAmount (Currency const& currency, Account const& issuer,
|
||||
std::uint64_t uV = 0, int iOff = 0, bool bNegative = false)
|
||||
: mCurrency (currency), mIssuer (issuer), mValue (uV), mOffset (iOff), mIsNegative (bNegative)
|
||||
{
|
||||
canonicalize ();
|
||||
}
|
||||
|
||||
STAmount (Currency const& currency, Account const& issuer,
|
||||
std::uint32_t uV, int iOff = 0, bool bNegative = false)
|
||||
: mCurrency (currency), mIssuer (issuer), mValue (uV), mOffset (iOff), mIsNegative (bNegative)
|
||||
{
|
||||
canonicalize ();
|
||||
}
|
||||
|
||||
STAmount (SField::ref n, Currency const& currency, Account const& issuer,
|
||||
std::uint64_t v = 0, int off = 0, bool isNeg = false) :
|
||||
SerializedType (n), mCurrency (currency), mIssuer (issuer), mValue (v), mOffset (off), mIsNegative (isNeg)
|
||||
{
|
||||
canonicalize ();
|
||||
}
|
||||
|
||||
STAmount (Currency const& currency, Account const& issuer, std::int64_t v, int iOff = 0)
|
||||
: mCurrency (currency), mIssuer (issuer), mOffset (iOff)
|
||||
{
|
||||
set (v);
|
||||
canonicalize ();
|
||||
}
|
||||
|
||||
STAmount (SField::ref n, Currency const& currency, Account const& issuer, std::int64_t v, int off = 0)
|
||||
: SerializedType (n), mCurrency (currency), mIssuer (issuer), mOffset (off)
|
||||
{
|
||||
set (v);
|
||||
canonicalize ();
|
||||
}
|
||||
|
||||
STAmount (Currency const& currency, Account const& issuer, int v, int iOff = 0)
|
||||
: mCurrency (currency), mIssuer (issuer), mOffset (iOff)
|
||||
{
|
||||
set (v);
|
||||
canonicalize ();
|
||||
}
|
||||
|
||||
STAmount (SField::ref n, Currency const& currency, Account const& issuer, int v, int off = 0)
|
||||
: SerializedType (n), mCurrency (currency), mIssuer (issuer), mOffset (off)
|
||||
{
|
||||
set (v);
|
||||
canonicalize ();
|
||||
}
|
||||
|
||||
STAmount (SField::ref, const Json::Value&);
|
||||
|
||||
static STAmount createFromInt64 (SField::ref n, std::int64_t v);
|
||||
|
||||
static std::unique_ptr<SerializedType> deserialize (SerializerIterator& sit, SField::ref name)
|
||||
{
|
||||
return std::unique_ptr<SerializedType> (construct (sit, name));
|
||||
}
|
||||
|
||||
bool bSetJson (const Json::Value& jvSource);
|
||||
|
||||
static STAmount saFromRate (std::uint64_t uRate = 0)
|
||||
{
|
||||
return STAmount (noCurrency(), noAccount(), uRate, -9, false);
|
||||
}
|
||||
|
||||
SerializedTypeID getSType () const
|
||||
{
|
||||
return STI_AMOUNT;
|
||||
}
|
||||
std::string getText () const;
|
||||
std::string getFullText () const;
|
||||
void add (Serializer& s) const;
|
||||
|
||||
int getExponent () const
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
std::uint64_t getMantissa () const
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
int signum () const
|
||||
{
|
||||
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
|
||||
{
|
||||
STAmount c(mCurrency, mIssuer);
|
||||
c = zero;
|
||||
// See https://ripplelabs.atlassian.net/browse/WC-1847?jql=
|
||||
return c;
|
||||
}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
// VFALCO: Why -100?
|
||||
mOffset = mIsNative ? 0 : -100;
|
||||
mValue = 0;
|
||||
mIsNegative = false;
|
||||
}
|
||||
|
||||
// Zero while copying currency and issuer.
|
||||
void clear (const STAmount& saTmpl)
|
||||
{
|
||||
mCurrency = saTmpl.mCurrency;
|
||||
mIssuer = saTmpl.mIssuer;
|
||||
mIsNative = saTmpl.mIsNative;
|
||||
clear ();
|
||||
}
|
||||
void clear (Currency const& currency, Account const& issuer)
|
||||
{
|
||||
mCurrency = currency;
|
||||
mIssuer = issuer;
|
||||
mIsNative = !currency;
|
||||
clear ();
|
||||
}
|
||||
|
||||
STAmount& operator=(beast::Zero)
|
||||
{
|
||||
clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
int compare (const STAmount&) const;
|
||||
|
||||
Account const& getIssuer () const
|
||||
{
|
||||
return mIssuer;
|
||||
}
|
||||
STAmount* setIssuer (Account const& uIssuer)
|
||||
{
|
||||
mIssuer = uIssuer;
|
||||
return this;
|
||||
}
|
||||
|
||||
Currency const& getCurrency () const
|
||||
{
|
||||
return mCurrency;
|
||||
}
|
||||
bool setValue (const std::string& sAmount);
|
||||
bool setFullValue (
|
||||
const std::string& sAmount, const std::string& sCurrency = "",
|
||||
const std::string& sIssuer = "");
|
||||
void setValue (const STAmount&);
|
||||
|
||||
virtual bool isEquivalent (const SerializedType& t) const;
|
||||
virtual bool isDefault () const
|
||||
{
|
||||
return (mValue == 0) && mIssuer.isZero () && mCurrency.isZero ();
|
||||
}
|
||||
|
||||
bool operator== (const STAmount&) const;
|
||||
bool operator!= (const STAmount&) const;
|
||||
bool operator< (const STAmount&) const;
|
||||
bool operator> (const STAmount&) const;
|
||||
bool operator<= (const STAmount&) const;
|
||||
bool operator>= (const STAmount&) const;
|
||||
bool isComparable (const STAmount&) const;
|
||||
void throwComparable (const STAmount&) 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+= (const STAmount&);
|
||||
STAmount& operator-= (const STAmount&);
|
||||
STAmount& operator+= (std::uint64_t);
|
||||
STAmount& operator-= (std::uint64_t);
|
||||
STAmount& operator= (std::uint64_t);
|
||||
|
||||
operator double () const;
|
||||
|
||||
friend STAmount operator+ (const STAmount& v1, const STAmount& v2);
|
||||
friend STAmount operator- (const STAmount& v1, const STAmount& v2);
|
||||
|
||||
static STAmount divide (
|
||||
const STAmount& v1, const STAmount& v2,
|
||||
Currency const& currency, Account const& issuer);
|
||||
|
||||
static STAmount divide (
|
||||
const STAmount& v1, const STAmount& v2, const STAmount& saUnit)
|
||||
{
|
||||
return divide (v1, v2, saUnit.getCurrency (), saUnit.getIssuer ());
|
||||
}
|
||||
static STAmount divide (const STAmount& v1, const STAmount& v2)
|
||||
{
|
||||
return divide (v1, v2, v1);
|
||||
}
|
||||
|
||||
static STAmount multiply (
|
||||
const STAmount& v1, const STAmount& v2,
|
||||
Currency const& currency, Account const& issuer);
|
||||
|
||||
static STAmount multiply (
|
||||
const STAmount& v1, const STAmount& v2, const STAmount& saUnit)
|
||||
{
|
||||
return multiply (v1, v2, saUnit.getCurrency (), saUnit.getIssuer ());
|
||||
}
|
||||
static STAmount multiply (const STAmount& v1, const STAmount& 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 (const STAmount& v1, const STAmount& v2, bool roundUp);
|
||||
static STAmount subRound (const STAmount& v1, const STAmount& v2, bool roundUp);
|
||||
static STAmount mulRound (const STAmount& v1, const STAmount& v2,
|
||||
Currency const& currency, Account const& issuer, bool roundUp);
|
||||
static STAmount divRound (const STAmount& v1, const STAmount& v2,
|
||||
Currency const& currency, Account const& issuer, bool roundUp);
|
||||
|
||||
static STAmount mulRound (const STAmount& v1, const STAmount& v2, const STAmount& saUnit, bool roundUp)
|
||||
{
|
||||
return mulRound (v1, v2, saUnit.getCurrency (), saUnit.getIssuer (), roundUp);
|
||||
}
|
||||
static STAmount mulRound (const STAmount& v1, const STAmount& v2, bool roundUp)
|
||||
{
|
||||
return mulRound (v1, v2, v1.getCurrency (), v1.getIssuer (), roundUp);
|
||||
}
|
||||
static STAmount divRound (const STAmount& v1, const STAmount& v2, const STAmount& saUnit, bool roundUp)
|
||||
{
|
||||
return divRound (v1, v2, saUnit.getCurrency (), saUnit.getIssuer (), roundUp);
|
||||
}
|
||||
static STAmount divRound (const STAmount& v1, const STAmount& v2, bool roundUp)
|
||||
{
|
||||
return divRound (v1, v2, v1.getCurrency (), v1.getIssuer (), 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 (const STAmount& offerOut, const STAmount& offerIn);
|
||||
static STAmount setRate (std::uint64_t rate);
|
||||
|
||||
// Someone is offering X for Y, I need Z, how much do I pay
|
||||
static STAmount getPay (
|
||||
const STAmount& offerOut, const STAmount& offerIn, const STAmount& 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:
|
||||
Currency mCurrency; // Compared by ==. Always update mIsNative.
|
||||
Account mIssuer; // Not compared by ==. 0 for XRP.
|
||||
|
||||
std::uint64_t mValue;
|
||||
int mOffset;
|
||||
bool mIsNative; // Always !mCurrency. Native is XRP.
|
||||
bool mIsNegative;
|
||||
|
||||
void canonicalize ();
|
||||
STAmount* duplicate () const
|
||||
{
|
||||
return new STAmount (*this);
|
||||
}
|
||||
static STAmount* construct (SerializerIterator&, SField::ref name);
|
||||
|
||||
STAmount (SField::ref name, Currency const& cur, Account const& iss,
|
||||
std::uint64_t val, int off, bool isNat, bool isNeg)
|
||||
: SerializedType (name), mCurrency (cur), mIssuer (iss), mValue (val),
|
||||
mOffset (off), mIsNative (isNat), mIsNegative (isNeg)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// VFALCO TODO Make static member accessors for these in STAmount
|
||||
extern const STAmount saZero;
|
||||
extern const STAmount saOne;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// TODO(tom): make STHash128, STHash160 and STHash256 a single templated class
|
||||
// to reduce the triple redundancy we have all over the rippled code.
|
||||
// to reduce the triple redundancy we have all over the rippled code regarding
|
||||
// hash-like classes.
|
||||
|
||||
class STHash128 : public SerializedType
|
||||
{
|
||||
public:
|
||||
@@ -1497,7 +932,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
virtual bool isEquivalent (const SerializedType& t) const;
|
||||
virtual bool isDefault () const
|
||||
{
|
||||
|
||||
@@ -99,7 +99,7 @@ Json::Value doBookOffers (RPC::Context& context)
|
||||
}
|
||||
else
|
||||
{
|
||||
pay_issuer = xrpIssuer ();
|
||||
pay_issuer = xrpAccount ();
|
||||
}
|
||||
|
||||
if (isXRP (pay_currency) && ! isXRP (pay_issuer))
|
||||
@@ -128,7 +128,7 @@ Json::Value doBookOffers (RPC::Context& context)
|
||||
}
|
||||
else
|
||||
{
|
||||
get_issuer = xrpIssuer ();
|
||||
get_issuer = xrpAccount ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -204,12 +204,12 @@ Json::Value doRipplePathFind (RPC::Context& context)
|
||||
STAmount saMaxAmountAct;
|
||||
STAmount saDstAmountAct;
|
||||
STAmount saMaxAmount (
|
||||
uSrcCurrencyID,
|
||||
!!uSrcIssuerID
|
||||
? uSrcIssuerID // Use specifed issuer.
|
||||
: !!uSrcCurrencyID // Default to source account.
|
||||
? Account(raSrc.getAccountID ())
|
||||
: xrpIssuer(),
|
||||
{uSrcCurrencyID,
|
||||
!!uSrcIssuerID
|
||||
? uSrcIssuerID // Use specifed issuer.
|
||||
: !!uSrcCurrencyID // Default to source account.
|
||||
? Account(raSrc.getAccountID ())
|
||||
: xrpAccount()},
|
||||
1);
|
||||
saMaxAmount.negate ();
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
|| !jvSubRequest[jss::taker_gets].isObject ())
|
||||
return rpcError (rpcINVALID_PARAMS);
|
||||
|
||||
// VFALCO TODO Use RippleAsset here
|
||||
// VFALCO TODO Use Issue here
|
||||
Currency pay_currency;
|
||||
Account pay_issuer;
|
||||
Currency get_currency;
|
||||
|
||||
237
src/ripple/types/api/Book.h
Normal file
237
src/ripple/types/api/Book.h
Normal file
@@ -0,0 +1,237 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TYPES_BOOK_H_INCLUDED
|
||||
#define RIPPLE_TYPES_BOOK_H_INCLUDED
|
||||
|
||||
#include <ripple/types/api/Issue.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Specifies an order book.
|
||||
The order book is a pair of Issues called in and out.
|
||||
@see Issue.
|
||||
*/
|
||||
template <bool ByValue>
|
||||
class BookType
|
||||
{
|
||||
public:
|
||||
typedef IssueType <ByValue> Issue;
|
||||
|
||||
Issue in;
|
||||
Issue out;
|
||||
|
||||
BookType ()
|
||||
{
|
||||
}
|
||||
|
||||
BookType (Issue const& in_, Issue const& out_)
|
||||
: in (in_)
|
||||
, out (out_)
|
||||
{
|
||||
}
|
||||
|
||||
template <bool OtherByValue>
|
||||
BookType (BookType <OtherByValue> const& other)
|
||||
: in (other.in)
|
||||
, out (other.out)
|
||||
{
|
||||
}
|
||||
|
||||
/** Assignment.
|
||||
This is only valid when ByValue == `true`
|
||||
*/
|
||||
template <bool OtherByValue>
|
||||
BookType& operator= (BookType <OtherByValue> const& other)
|
||||
{
|
||||
in = other.in;
|
||||
out = other.out;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <bool ByValue>
|
||||
std::string to_string (BookType<ByValue> const& book)
|
||||
{
|
||||
return to_string(book.in) + "->" + to_string(book.out);
|
||||
}
|
||||
|
||||
template <bool ByValue>
|
||||
std::ostream& operator<<(std::ostream& os, BookType<ByValue> const& x)
|
||||
{
|
||||
os << to_string (x);
|
||||
return os;
|
||||
}
|
||||
|
||||
template <bool ByValue, class Hasher>
|
||||
void hash_append (Hasher& h, BookType<ByValue> const& b)
|
||||
{
|
||||
using beast::hash_append;
|
||||
hash_append (h, b.in, b.out);
|
||||
}
|
||||
|
||||
/** Ordered comparison. */
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
int compare (BookType <LhsByValue> const& lhs,
|
||||
BookType <RhsByValue> const& rhs)
|
||||
{
|
||||
int const diff (compare (lhs.in, rhs.in));
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
return compare (lhs.out, rhs.out);
|
||||
}
|
||||
|
||||
/** Equality comparison. */
|
||||
/** @{ */
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator== (BookType <LhsByValue> const& lhs,
|
||||
BookType <RhsByValue> const& rhs)
|
||||
{
|
||||
return (lhs.in == rhs.in) &&
|
||||
(lhs.out == rhs.out);
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator!= (BookType <LhsByValue> const& lhs,
|
||||
BookType <RhsByValue> const& rhs)
|
||||
{
|
||||
return (lhs.in != rhs.in) ||
|
||||
(lhs.out != rhs.out);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Strict weak ordering. */
|
||||
/** @{ */
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator< (BookType <LhsByValue> const& lhs,
|
||||
BookType <RhsByValue> const& rhs)
|
||||
{
|
||||
int const diff (compare (lhs.in, rhs.in));
|
||||
if (diff != 0)
|
||||
return diff < 0;
|
||||
return lhs.out < rhs.out;
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator> (BookType <LhsByValue> const& lhs,
|
||||
BookType <RhsByValue> const& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator>= (BookType <LhsByValue> const& lhs,
|
||||
BookType <RhsByValue> const& rhs)
|
||||
{
|
||||
return ! (lhs < rhs);
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator<= (BookType <LhsByValue> const& lhs,
|
||||
BookType <RhsByValue> const& rhs)
|
||||
{
|
||||
return ! (rhs < lhs);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
typedef BookType <true> Book;
|
||||
typedef BookType <false> BookRef;
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace std {
|
||||
|
||||
template <bool ByValue>
|
||||
struct hash <ripple::IssueType <ByValue>>
|
||||
: private boost::base_from_member <std::hash <ripple::Currency>, 0>
|
||||
, private boost::base_from_member <std::hash <ripple::Account>, 1>
|
||||
{
|
||||
private:
|
||||
typedef boost::base_from_member <
|
||||
std::hash <ripple::Currency>, 0> currency_hash_type;
|
||||
typedef boost::base_from_member <
|
||||
std::hash <ripple::Account>, 1> issuer_hash_type;
|
||||
|
||||
public:
|
||||
typedef std::size_t value_type;
|
||||
typedef ripple::IssueType <ByValue> argument_type;
|
||||
|
||||
value_type operator() (argument_type const& value) const
|
||||
{
|
||||
value_type result (currency_hash_type::member (value.currency));
|
||||
if (!isXRP (value.currency))
|
||||
boost::hash_combine (result,
|
||||
issuer_hash_type::member (value.account));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool ByValue>
|
||||
struct hash <ripple::BookType <ByValue>>
|
||||
{
|
||||
private:
|
||||
typedef std::hash <ripple::IssueType <ByValue>> hasher;
|
||||
|
||||
hasher m_hasher;
|
||||
|
||||
public:
|
||||
typedef std::size_t value_type;
|
||||
typedef ripple::BookType <ByValue> argument_type;
|
||||
|
||||
value_type operator() (argument_type const& value) const
|
||||
{
|
||||
value_type result (m_hasher (value.in));
|
||||
boost::hash_combine (result, m_hasher (value.out));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace boost {
|
||||
|
||||
template <bool ByValue>
|
||||
struct hash <ripple::IssueType <ByValue>>
|
||||
: std::hash <ripple::IssueType <ByValue>>
|
||||
{
|
||||
typedef std::hash <ripple::IssueType <ByValue>> Base;
|
||||
// VFALCO NOTE broken in vs2012
|
||||
//using Base::Base; // inherit ctors
|
||||
};
|
||||
|
||||
template <bool ByValue>
|
||||
struct hash <ripple::BookType <ByValue>>
|
||||
: std::hash <ripple::BookType <ByValue>>
|
||||
{
|
||||
typedef std::hash <ripple::BookType <ByValue>> Base;
|
||||
// VFALCO NOTE broken in vs2012
|
||||
//using Base::Base; // inherit ctors
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
194
src/ripple/types/api/Issue.h
Normal file
194
src/ripple/types/api/Issue.h
Normal file
@@ -0,0 +1,194 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TYPES_ISSUE_INCLUDED
|
||||
#define RIPPLE_TYPES_ISSUE_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include <ripple/types/api/UintTypes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** A currency issued by an account.
|
||||
|
||||
When ByValue is `false`, this only stores references, and the caller
|
||||
is responsible for managing object lifetime.
|
||||
|
||||
@see Currency, Account, Issue, IssueRef, Book
|
||||
*/
|
||||
template <bool ByValue>
|
||||
class IssueType
|
||||
{
|
||||
public:
|
||||
typedef typename
|
||||
std::conditional <ByValue, Currency, Currency const&>::type
|
||||
IssueCurrency;
|
||||
|
||||
typedef typename
|
||||
std::conditional <ByValue, Account, Account const&>::type
|
||||
IssueAccount;
|
||||
|
||||
IssueCurrency currency;
|
||||
IssueAccount account;
|
||||
|
||||
IssueType ()
|
||||
{
|
||||
}
|
||||
|
||||
IssueType (Currency const& c, Account const& a)
|
||||
: currency (c), account (a)
|
||||
{
|
||||
}
|
||||
|
||||
template <bool OtherByValue>
|
||||
IssueType (IssueType <OtherByValue> const& other)
|
||||
: currency (other.currency)
|
||||
, account (other.account)
|
||||
{
|
||||
}
|
||||
|
||||
/** Assignment. */
|
||||
template <bool MaybeByValue = ByValue, bool OtherByValue>
|
||||
std::enable_if_t <MaybeByValue, IssueType&>
|
||||
operator= (IssueType <OtherByValue> const& other)
|
||||
{
|
||||
currency = other.currency;
|
||||
account = other.account;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <bool ByValue>
|
||||
bool isConsistent(IssueType<ByValue> const& ac)
|
||||
{
|
||||
return isXRP (ac.currency) == isXRP (ac.account);
|
||||
}
|
||||
|
||||
template <bool ByValue>
|
||||
std::string to_string (IssueType<ByValue> const& ac)
|
||||
{
|
||||
return to_string(ac.account) + "/" + to_string(ac.currency);
|
||||
}
|
||||
|
||||
template <bool ByValue>
|
||||
std::ostream& operator<< (
|
||||
std::ostream& os, IssueType<ByValue> const& x)
|
||||
{
|
||||
os << to_string (x);
|
||||
return os;
|
||||
}
|
||||
|
||||
template <bool ByValue, class Hasher>
|
||||
void hash_append (Hasher& h, IssueType<ByValue> const& r)
|
||||
{
|
||||
using beast::hash_append;
|
||||
hash_append (h, r.currency, r.account);
|
||||
}
|
||||
|
||||
/** Ordered comparison.
|
||||
The assets are ordered first by currency and then by account,
|
||||
if the currency is not XRP.
|
||||
*/
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
int compare (IssueType <LhsByValue> const& lhs,
|
||||
IssueType <RhsByValue> const& rhs)
|
||||
{
|
||||
int diff = compare (lhs.currency, rhs.currency);
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
if (isXRP (lhs.currency))
|
||||
return 0;
|
||||
return compare (lhs.account, rhs.account);
|
||||
}
|
||||
|
||||
/** Equality comparison. */
|
||||
/** @{ */
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator== (IssueType <LhsByValue> const& lhs,
|
||||
IssueType <RhsByValue> const& rhs)
|
||||
{
|
||||
return compare (lhs, rhs) == 0;
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator!= (IssueType <LhsByValue> const& lhs,
|
||||
IssueType <RhsByValue> const& rhs)
|
||||
{
|
||||
return ! (lhs == rhs);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Strict weak ordering. */
|
||||
/** @{ */
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator< (IssueType <LhsByValue> const& lhs,
|
||||
IssueType <RhsByValue> const& rhs)
|
||||
{
|
||||
return compare (lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator> (IssueType <LhsByValue> const& lhs,
|
||||
IssueType <RhsByValue> const& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator>= (IssueType <LhsByValue> const& lhs,
|
||||
IssueType <RhsByValue> const& rhs)
|
||||
{
|
||||
return ! (lhs < rhs);
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator<= (IssueType <LhsByValue> const& lhs,
|
||||
IssueType <RhsByValue> const& rhs)
|
||||
{
|
||||
return ! (rhs < lhs);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
typedef IssueType <true> Issue;
|
||||
typedef IssueType <false> IssueRef;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Returns an asset specifier that represents XRP. */
|
||||
inline Issue const& xrpIssue ()
|
||||
{
|
||||
static Issue issue {xrpCurrency(), xrpAccount()};
|
||||
return issue;
|
||||
}
|
||||
|
||||
/** Returns an asset specifier that represents no account and currency. */
|
||||
inline Issue const& noIssue ()
|
||||
{
|
||||
static Issue issue {noCurrency(), noAccount()};
|
||||
return issue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,391 +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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TYPES_RIPPLEASSETS_H_INCLUDED
|
||||
#define RIPPLE_TYPES_RIPPLEASSETS_H_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include <ripple/types/api/UintTypes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Ripple asset specifier, expressed as a currency issuer pair.
|
||||
When ByValue is `false`, this only stores references, and the caller
|
||||
is responsible for managing object lifetime.
|
||||
@see Currency, Account, RippleAssset, RippleAssetRef
|
||||
*/
|
||||
template <bool ByValue>
|
||||
class RippleAssetType
|
||||
{
|
||||
public:
|
||||
typedef typename
|
||||
std::conditional <ByValue, Currency, Currency const&>::type
|
||||
AssetCurrency;
|
||||
|
||||
typedef typename
|
||||
std::conditional <ByValue, Account, Account const&>::type
|
||||
AssetIssuer;
|
||||
|
||||
AssetCurrency currency;
|
||||
AssetIssuer issuer;
|
||||
|
||||
RippleAssetType ()
|
||||
{
|
||||
}
|
||||
|
||||
RippleAssetType (Currency const& currency_, Account const& issuer_)
|
||||
: currency (currency_), issuer (issuer_)
|
||||
{
|
||||
// Either XRP and (currency == zero && issuer == zero) or some custom
|
||||
// currency and (currency != 0 && issuer != 0)
|
||||
assert (currency.isZero () == issuer.isZero ());
|
||||
}
|
||||
|
||||
template <bool OtherByValue>
|
||||
RippleAssetType (RippleAssetType <OtherByValue> const& other)
|
||||
: currency (other.currency)
|
||||
, issuer (other.issuer)
|
||||
{
|
||||
}
|
||||
|
||||
/** Assignment. */
|
||||
template <bool MaybeByValue = ByValue, bool OtherByValue>
|
||||
std::enable_if_t <MaybeByValue, RippleAssetType&>
|
||||
operator= (RippleAssetType <OtherByValue> const& other)
|
||||
{
|
||||
currency = other.currency;
|
||||
issuer = other.issuer;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool is_xrp () const
|
||||
{
|
||||
assert (currency.isZero () == issuer.isZero ());
|
||||
if (currency.isZero ())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class Hasher>
|
||||
friend
|
||||
void
|
||||
hash_append (Hasher& h, RippleAssetType const& r)
|
||||
{
|
||||
using beast::hash_append;
|
||||
hash_append (h, r.currency, r.issuer);
|
||||
}
|
||||
};
|
||||
|
||||
/** Ordered comparison.
|
||||
The assets are ordered first by currency and then by issuer,
|
||||
if the currency is not XRP.
|
||||
*/
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
int compare (RippleAssetType <LhsByValue> const& lhs,
|
||||
RippleAssetType <RhsByValue> const& rhs)
|
||||
{
|
||||
int const diff (compare (lhs.currency, rhs.currency));
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
if (lhs.is_xrp ())
|
||||
return 0;
|
||||
return compare (lhs.issuer, rhs.issuer);
|
||||
}
|
||||
|
||||
/** Equality comparison. */
|
||||
/** @{ */
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator== (RippleAssetType <LhsByValue> const& lhs,
|
||||
RippleAssetType <RhsByValue> const& rhs)
|
||||
{
|
||||
return compare (lhs, rhs) == 0;
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator!= (RippleAssetType <LhsByValue> const& lhs,
|
||||
RippleAssetType <RhsByValue> const& rhs)
|
||||
{
|
||||
return ! (lhs == rhs);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Strict weak ordering. */
|
||||
/** @{ */
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator< (RippleAssetType <LhsByValue> const& lhs,
|
||||
RippleAssetType <RhsByValue> const& rhs)
|
||||
{
|
||||
return compare (lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator> (RippleAssetType <LhsByValue> const& lhs,
|
||||
RippleAssetType <RhsByValue> const& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator>= (RippleAssetType <LhsByValue> const& lhs,
|
||||
RippleAssetType <RhsByValue> const& rhs)
|
||||
{
|
||||
return ! (lhs < rhs);
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator<= (RippleAssetType <LhsByValue> const& lhs,
|
||||
RippleAssetType <RhsByValue> const& rhs)
|
||||
{
|
||||
return ! (rhs < lhs);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
typedef RippleAssetType <true> RippleAsset;
|
||||
typedef RippleAssetType <false> RippleAssetRef;
|
||||
|
||||
/** Create an asset specifier by parsing the given JSON.
|
||||
Errors, if any, will be returned or injected into the specified result
|
||||
JSON object using the JSON-RPC error specification interface.
|
||||
@param currency_field The JSON field name of the currency specifier
|
||||
@param issuer_field The JSON field name of the issuer specifier
|
||||
@param result The JSON in which to store any errors.
|
||||
#return An asset representing the parsed JSON if no errors occurred.
|
||||
*/
|
||||
RippleAsset make_asset (Json::Value json,
|
||||
std::string const& currency_field, std::string const& issuer_field,
|
||||
Json::Value* result);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Returns an asset specifier that represents XRP. */
|
||||
inline RippleAssetRef xrp_asset ()
|
||||
{
|
||||
static RippleAsset asset (Currency (0), Account (0));
|
||||
return asset;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Specifies an order book.
|
||||
The order book is defined by the input asset ('in') and output
|
||||
asset ('out').
|
||||
*/
|
||||
template <bool ByValue>
|
||||
class RippleBookType
|
||||
{
|
||||
public:
|
||||
typedef RippleAssetType <ByValue> AssetType;
|
||||
|
||||
AssetType in;
|
||||
AssetType out;
|
||||
|
||||
RippleBookType ()
|
||||
{
|
||||
}
|
||||
|
||||
RippleBookType (AssetType const& in_, AssetType const& out_)
|
||||
: in (in_)
|
||||
, out (out_)
|
||||
{
|
||||
}
|
||||
|
||||
template <bool OtherByValue>
|
||||
RippleBookType (RippleBookType <OtherByValue> const& other)
|
||||
: in (other.in)
|
||||
, out (other.out)
|
||||
{
|
||||
}
|
||||
|
||||
/** Assignment.
|
||||
This is only valid when ByValue == `true`
|
||||
*/
|
||||
template <bool OtherByValue>
|
||||
RippleBookType& operator= (RippleBookType <OtherByValue> const& other)
|
||||
{
|
||||
in = other.in;
|
||||
out = other.out;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Hasher>
|
||||
friend
|
||||
void
|
||||
hash_append (Hasher& h, RippleBookType const& b)
|
||||
{
|
||||
using beast::hash_append;
|
||||
hash_append (h, b.in, b.out);
|
||||
}
|
||||
};
|
||||
|
||||
/** Ordered comparison. */
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
int compare (RippleBookType <LhsByValue> const& lhs,
|
||||
RippleBookType <RhsByValue> const& rhs)
|
||||
{
|
||||
int const diff (compare (lhs.in, rhs.in));
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
return compare (lhs.out, rhs.out);
|
||||
}
|
||||
|
||||
/** Equality comparison. */
|
||||
/** @{ */
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator== (RippleBookType <LhsByValue> const& lhs,
|
||||
RippleBookType <RhsByValue> const& rhs)
|
||||
{
|
||||
return (lhs.in == rhs.in) &&
|
||||
(lhs.out == rhs.out);
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator!= (RippleBookType <LhsByValue> const& lhs,
|
||||
RippleBookType <RhsByValue> const& rhs)
|
||||
{
|
||||
return (lhs.in != rhs.in) ||
|
||||
(lhs.out != rhs.out);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Strict weak ordering. */
|
||||
/** @{ */
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator< (RippleBookType <LhsByValue> const& lhs,
|
||||
RippleBookType <RhsByValue> const& rhs)
|
||||
{
|
||||
int const diff (compare (lhs.in, rhs.in));
|
||||
if (diff != 0)
|
||||
return diff < 0;
|
||||
return lhs.out < rhs.out;
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator> (RippleBookType <LhsByValue> const& lhs,
|
||||
RippleBookType <RhsByValue> const& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator>= (RippleBookType <LhsByValue> const& lhs,
|
||||
RippleBookType <RhsByValue> const& rhs)
|
||||
{
|
||||
return ! (lhs < rhs);
|
||||
}
|
||||
|
||||
template <bool LhsByValue, bool RhsByValue>
|
||||
bool operator<= (RippleBookType <LhsByValue> const& lhs,
|
||||
RippleBookType <RhsByValue> const& rhs)
|
||||
{
|
||||
return ! (rhs < lhs);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
typedef RippleBookType <true> RippleBook;
|
||||
typedef RippleBookType <false> RippleBookRef;
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace std {
|
||||
|
||||
template <bool ByValue>
|
||||
struct hash <ripple::RippleAssetType <ByValue>>
|
||||
: private boost::base_from_member <std::hash <ripple::Currency>, 0>
|
||||
, private boost::base_from_member <std::hash <ripple::Account>, 1>
|
||||
{
|
||||
private:
|
||||
typedef boost::base_from_member <
|
||||
std::hash <ripple::Currency>, 0> currency_hash_type;
|
||||
typedef boost::base_from_member <
|
||||
std::hash <ripple::Account>, 1> issuer_hash_type;
|
||||
|
||||
public:
|
||||
typedef std::size_t value_type;
|
||||
typedef ripple::RippleAssetType <ByValue> argument_type;
|
||||
|
||||
value_type operator() (argument_type const& value) const
|
||||
{
|
||||
value_type result (currency_hash_type::member (value.currency));
|
||||
if (! value.is_xrp ())
|
||||
boost::hash_combine (result,
|
||||
issuer_hash_type::member (value.issuer));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool ByValue>
|
||||
struct hash <ripple::RippleBookType <ByValue>>
|
||||
{
|
||||
private:
|
||||
typedef std::hash <ripple::RippleAssetType <ByValue>> hasher;
|
||||
|
||||
hasher m_hasher;
|
||||
|
||||
public:
|
||||
typedef std::size_t value_type;
|
||||
typedef ripple::RippleBookType <ByValue> argument_type;
|
||||
|
||||
value_type operator() (argument_type const& value) const
|
||||
{
|
||||
value_type result (m_hasher (value.in));
|
||||
boost::hash_combine (result, m_hasher (value.out));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace boost {
|
||||
|
||||
template <bool ByValue>
|
||||
struct hash <ripple::RippleAssetType <ByValue>>
|
||||
: std::hash <ripple::RippleAssetType <ByValue>>
|
||||
{
|
||||
typedef std::hash <ripple::RippleAssetType <ByValue>> Base;
|
||||
// VFALCO NOTE broken in vs2012
|
||||
//using Base::Base; // inherit ctors
|
||||
};
|
||||
|
||||
template <bool ByValue>
|
||||
struct hash <ripple::RippleBookType <ByValue>>
|
||||
: std::hash <ripple::RippleBookType <ByValue>>
|
||||
{
|
||||
typedef std::hash <ripple::RippleBookType <ByValue>> Base;
|
||||
// VFALCO NOTE broken in vs2012
|
||||
//using Base::Base; // inherit ctors
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -51,7 +51,7 @@ typedef std::unordered_set<Currency> CurrencySet;
|
||||
typedef std::unordered_set<NodeID> NodeIDSet;
|
||||
|
||||
/** A special account that's used as the "issuer" for XRP. */
|
||||
Account const& xrpIssuer();
|
||||
Account const& xrpAccount();
|
||||
|
||||
/** XRP currency. */
|
||||
Currency const& xrpCurrency();
|
||||
@@ -64,6 +64,8 @@ Currency const& noCurrency();
|
||||
|
||||
/** We deliberately disallow the currency that looks like "XRP" because too
|
||||
many people were using it instead of the correct XRP currency. */
|
||||
|
||||
|
||||
Currency const& badCurrency();
|
||||
|
||||
inline bool isXRP(Currency const& c)
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class RippleAsset_test : public beast::unit_test::suite
|
||||
class Issue_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
// Comparison, hash tests for uint60 (via base_uint)
|
||||
@@ -75,61 +75,61 @@ public:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Comparison, hash tests for RippleAssetType
|
||||
template <class Asset>
|
||||
void testAssetType ()
|
||||
// Comparison, hash tests for IssueType
|
||||
template <class Issue>
|
||||
void testIssueType ()
|
||||
{
|
||||
Currency const c1 (1); Account const i1 (1);
|
||||
Currency const c2 (2); Account const i2 (2);
|
||||
Currency const c3 (3); Account const i3 (3);
|
||||
|
||||
expect (Asset (c1, i1) != Asset (c2, i1));
|
||||
expect (Asset (c1, i1) < Asset (c2, i1));
|
||||
expect (Asset (c1, i1) <= Asset (c2, i1));
|
||||
expect (Asset (c2, i1) <= Asset (c2, i1));
|
||||
expect (Asset (c2, i1) == Asset (c2, i1));
|
||||
expect (Asset (c2, i1) >= Asset (c2, i1));
|
||||
expect (Asset (c3, i1) >= Asset (c2, i1));
|
||||
expect (Asset (c3, i1) > Asset (c2, i1));
|
||||
expect (Asset (c1, i1) != Asset (c1, i2));
|
||||
expect (Asset (c1, i1) < Asset (c1, i2));
|
||||
expect (Asset (c1, i1) <= Asset (c1, i2));
|
||||
expect (Asset (c1, i2) <= Asset (c1, i2));
|
||||
expect (Asset (c1, i2) == Asset (c1, i2));
|
||||
expect (Asset (c1, i2) >= Asset (c1, i2));
|
||||
expect (Asset (c1, i3) >= Asset (c1, i2));
|
||||
expect (Asset (c1, i3) > Asset (c1, i2));
|
||||
expect (Issue (c1, i1) != Issue (c2, i1));
|
||||
expect (Issue (c1, i1) < Issue (c2, i1));
|
||||
expect (Issue (c1, i1) <= Issue (c2, i1));
|
||||
expect (Issue (c2, i1) <= Issue (c2, i1));
|
||||
expect (Issue (c2, i1) == Issue (c2, i1));
|
||||
expect (Issue (c2, i1) >= Issue (c2, i1));
|
||||
expect (Issue (c3, i1) >= Issue (c2, i1));
|
||||
expect (Issue (c3, i1) > Issue (c2, i1));
|
||||
expect (Issue (c1, i1) != Issue (c1, i2));
|
||||
expect (Issue (c1, i1) < Issue (c1, i2));
|
||||
expect (Issue (c1, i1) <= Issue (c1, i2));
|
||||
expect (Issue (c1, i2) <= Issue (c1, i2));
|
||||
expect (Issue (c1, i2) == Issue (c1, i2));
|
||||
expect (Issue (c1, i2) >= Issue (c1, i2));
|
||||
expect (Issue (c1, i3) >= Issue (c1, i2));
|
||||
expect (Issue (c1, i3) > Issue (c1, i2));
|
||||
|
||||
std::hash <Asset> hash;
|
||||
std::hash <Issue> hash;
|
||||
|
||||
expect (hash (Asset (c1, i1)) == hash (Asset (c1, i1)));
|
||||
expect (hash (Asset (c1, i2)) == hash (Asset (c1, i2)));
|
||||
expect (hash (Asset (c1, i3)) == hash (Asset (c1, i3)));
|
||||
expect (hash (Asset (c2, i1)) == hash (Asset (c2, i1)));
|
||||
expect (hash (Asset (c2, i2)) == hash (Asset (c2, i2)));
|
||||
expect (hash (Asset (c2, i3)) == hash (Asset (c2, i3)));
|
||||
expect (hash (Asset (c3, i1)) == hash (Asset (c3, i1)));
|
||||
expect (hash (Asset (c3, i2)) == hash (Asset (c3, i2)));
|
||||
expect (hash (Asset (c3, i3)) == hash (Asset (c3, i3)));
|
||||
expect (hash (Asset (c1, i1)) != hash (Asset (c1, i2)));
|
||||
expect (hash (Asset (c1, i1)) != hash (Asset (c1, i3)));
|
||||
expect (hash (Asset (c1, i1)) != hash (Asset (c2, i1)));
|
||||
expect (hash (Asset (c1, i1)) != hash (Asset (c2, i2)));
|
||||
expect (hash (Asset (c1, i1)) != hash (Asset (c2, i3)));
|
||||
expect (hash (Asset (c1, i1)) != hash (Asset (c3, i1)));
|
||||
expect (hash (Asset (c1, i1)) != hash (Asset (c3, i2)));
|
||||
expect (hash (Asset (c1, i1)) != hash (Asset (c3, i3)));
|
||||
expect (hash (Issue (c1, i1)) == hash (Issue (c1, i1)));
|
||||
expect (hash (Issue (c1, i2)) == hash (Issue (c1, i2)));
|
||||
expect (hash (Issue (c1, i3)) == hash (Issue (c1, i3)));
|
||||
expect (hash (Issue (c2, i1)) == hash (Issue (c2, i1)));
|
||||
expect (hash (Issue (c2, i2)) == hash (Issue (c2, i2)));
|
||||
expect (hash (Issue (c2, i3)) == hash (Issue (c2, i3)));
|
||||
expect (hash (Issue (c3, i1)) == hash (Issue (c3, i1)));
|
||||
expect (hash (Issue (c3, i2)) == hash (Issue (c3, i2)));
|
||||
expect (hash (Issue (c3, i3)) == hash (Issue (c3, i3)));
|
||||
expect (hash (Issue (c1, i1)) != hash (Issue (c1, i2)));
|
||||
expect (hash (Issue (c1, i1)) != hash (Issue (c1, i3)));
|
||||
expect (hash (Issue (c1, i1)) != hash (Issue (c2, i1)));
|
||||
expect (hash (Issue (c1, i1)) != hash (Issue (c2, i2)));
|
||||
expect (hash (Issue (c1, i1)) != hash (Issue (c2, i3)));
|
||||
expect (hash (Issue (c1, i1)) != hash (Issue (c3, i1)));
|
||||
expect (hash (Issue (c1, i1)) != hash (Issue (c3, i2)));
|
||||
expect (hash (Issue (c1, i1)) != hash (Issue (c3, i3)));
|
||||
}
|
||||
|
||||
template <class Set>
|
||||
void testAssetSet ()
|
||||
void testIssueSet ()
|
||||
{
|
||||
Currency const c1 (1);
|
||||
Account const i1 (1);
|
||||
Currency const c2 (2);
|
||||
Account const i2 (2);
|
||||
RippleAssetRef const a1 (c1, i1);
|
||||
RippleAssetRef const a2 (c2, i2);
|
||||
IssueRef const a1 (c1, i1);
|
||||
IssueRef const a2 (c2, i2);
|
||||
|
||||
{
|
||||
Set c;
|
||||
@@ -139,9 +139,9 @@ public:
|
||||
c.insert (a2);
|
||||
if (! expect (c.size () == 2)) return;
|
||||
|
||||
if (! expect (c.erase (RippleAsset (c1, i2)) == 0)) return;
|
||||
if (! expect (c.erase (RippleAsset (c1, i1)) == 1)) return;
|
||||
if (! expect (c.erase (RippleAsset (c2, i2)) == 1)) return;
|
||||
if (! expect (c.erase (Issue (c1, i2)) == 0)) return;
|
||||
if (! expect (c.erase (Issue (c1, i1)) == 1)) return;
|
||||
if (! expect (c.erase (Issue (c2, i2)) == 1)) return;
|
||||
if (! expect (c.empty ())) return;
|
||||
}
|
||||
|
||||
@@ -153,9 +153,9 @@ public:
|
||||
c.insert (a2);
|
||||
if (! expect (c.size () == 2)) return;
|
||||
|
||||
if (! expect (c.erase (RippleAssetRef (c1, i2)) == 0)) return;
|
||||
if (! expect (c.erase (RippleAssetRef (c1, i1)) == 1)) return;
|
||||
if (! expect (c.erase (RippleAssetRef (c2, i2)) == 1)) return;
|
||||
if (! expect (c.erase (IssueRef (c1, i2)) == 0)) return;
|
||||
if (! expect (c.erase (IssueRef (c1, i1)) == 1)) return;
|
||||
if (! expect (c.erase (IssueRef (c2, i2)) == 1)) return;
|
||||
if (! expect (c.empty ())) return;
|
||||
|
||||
#if STL_SET_HAS_EMPLACE
|
||||
@@ -168,14 +168,14 @@ public:
|
||||
}
|
||||
|
||||
template <class Map>
|
||||
void testAssetMap ()
|
||||
void testIssueMap ()
|
||||
{
|
||||
Currency const c1 (1);
|
||||
Account const i1 (1);
|
||||
Currency const c2 (2);
|
||||
Account const i2 (2);
|
||||
RippleAssetRef const a1 (c1, i1);
|
||||
RippleAssetRef const a2 (c2, i2);
|
||||
IssueRef const a1 (c1, i1);
|
||||
IssueRef const a2 (c2, i2);
|
||||
|
||||
{
|
||||
Map c;
|
||||
@@ -185,9 +185,9 @@ public:
|
||||
c.insert (std::make_pair (a2, 2));
|
||||
if (! expect (c.size () == 2)) return;
|
||||
|
||||
if (! expect (c.erase (RippleAsset (c1, i2)) == 0)) return;
|
||||
if (! expect (c.erase (RippleAsset (c1, i1)) == 1)) return;
|
||||
if (! expect (c.erase (RippleAsset (c2, i2)) == 1)) return;
|
||||
if (! expect (c.erase (Issue (c1, i2)) == 0)) return;
|
||||
if (! expect (c.erase (Issue (c1, i1)) == 1)) return;
|
||||
if (! expect (c.erase (Issue (c2, i2)) == 1)) return;
|
||||
if (! expect (c.empty ())) return;
|
||||
}
|
||||
|
||||
@@ -199,63 +199,63 @@ public:
|
||||
c.insert (std::make_pair (a2, 2));
|
||||
if (! expect (c.size () == 2)) return;
|
||||
|
||||
if (! expect (c.erase (RippleAssetRef (c1, i2)) == 0)) return;
|
||||
if (! expect (c.erase (RippleAssetRef (c1, i1)) == 1)) return;
|
||||
if (! expect (c.erase (RippleAssetRef (c2, i2)) == 1)) return;
|
||||
if (! expect (c.erase (IssueRef (c1, i2)) == 0)) return;
|
||||
if (! expect (c.erase (IssueRef (c1, i1)) == 1)) return;
|
||||
if (! expect (c.erase (IssueRef (c2, i2)) == 1)) return;
|
||||
if (! expect (c.empty ())) return;
|
||||
}
|
||||
}
|
||||
|
||||
void testAssetSets ()
|
||||
void testIssueSets ()
|
||||
{
|
||||
testcase ("std::set <RippleAsset>");
|
||||
testAssetSet <std::set <RippleAsset>> ();
|
||||
testcase ("std::set <Issue>");
|
||||
testIssueSet <std::set <Issue>> ();
|
||||
|
||||
testcase ("std::set <RippleAssetRef>");
|
||||
testAssetSet <std::set <RippleAssetRef>> ();
|
||||
testcase ("std::set <IssueRef>");
|
||||
testIssueSet <std::set <IssueRef>> ();
|
||||
|
||||
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
||||
testcase ("std::unordered_set <RippleAsset>");
|
||||
testAssetSet <std::unordered_set <RippleAsset>> ();
|
||||
testcase ("std::unordered_set <Issue>");
|
||||
testIssueSet <std::unordered_set <Issue>> ();
|
||||
|
||||
testcase ("std::unordered_set <RippleAssetRef>");
|
||||
testAssetSet <std::unordered_set <RippleAssetRef>> ();
|
||||
testcase ("std::unordered_set <IssueRef>");
|
||||
testIssueSet <std::unordered_set <IssueRef>> ();
|
||||
#endif
|
||||
|
||||
testcase ("ripple::unordered_set <RippleAsset>");
|
||||
testAssetSet <ripple::unordered_set <RippleAsset>> ();
|
||||
testcase ("ripple::unordered_set <Issue>");
|
||||
testIssueSet <ripple::unordered_set <Issue>> ();
|
||||
|
||||
testcase ("ripple::unordered_set <RippleAssetRef>");
|
||||
testAssetSet <ripple::unordered_set <RippleAssetRef>> ();
|
||||
testcase ("ripple::unordered_set <IssueRef>");
|
||||
testIssueSet <ripple::unordered_set <IssueRef>> ();
|
||||
}
|
||||
|
||||
void testAssetMaps ()
|
||||
void testIssueMaps ()
|
||||
{
|
||||
testcase ("std::map <RippleAsset, int>");
|
||||
testAssetMap <std::map <RippleAsset, int>> ();
|
||||
testcase ("std::map <Issue, int>");
|
||||
testIssueMap <std::map <Issue, int>> ();
|
||||
|
||||
testcase ("std::map <RippleAssetRef, int>");
|
||||
testAssetMap <std::map <RippleAssetRef, int>> ();
|
||||
testcase ("std::map <IssueRef, int>");
|
||||
testIssueMap <std::map <IssueRef, int>> ();
|
||||
|
||||
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
||||
testcase ("std::unordered_map <RippleAsset, int>");
|
||||
testAssetMap <std::unordered_map <RippleAsset, int>> ();
|
||||
testcase ("std::unordered_map <Issue, int>");
|
||||
testIssueMap <std::unordered_map <Issue, int>> ();
|
||||
|
||||
testcase ("std::unordered_map <RippleAssetRef, int>");
|
||||
testAssetMap <std::unordered_map <RippleAssetRef, int>> ();
|
||||
testcase ("std::unordered_map <IssueRef, int>");
|
||||
testIssueMap <std::unordered_map <IssueRef, int>> ();
|
||||
|
||||
testcase ("ripple::unordered_map <RippleAsset, int>");
|
||||
testAssetMap <ripple::unordered_map <RippleAsset, int>> ();
|
||||
testcase ("ripple::unordered_map <Issue, int>");
|
||||
testIssueMap <ripple::unordered_map <Issue, int>> ();
|
||||
|
||||
testcase ("ripple::unordered_map <RippleAssetRef, int>");
|
||||
testAssetMap <ripple::unordered_map <RippleAssetRef, int>> ();
|
||||
testcase ("ripple::unordered_map <IssueRef, int>");
|
||||
testIssueMap <ripple::unordered_map <IssueRef, int>> ();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Comparison, hash tests for RippleBookType
|
||||
// Comparison, hash tests for BookType
|
||||
template <class Book>
|
||||
void testBook ()
|
||||
{
|
||||
@@ -263,10 +263,10 @@ public:
|
||||
Currency const c2 (2); Account const i2 (2);
|
||||
Currency const c3 (3); Account const i3 (3);
|
||||
|
||||
RippleAsset a1 (c1, i1);
|
||||
RippleAsset a2 (c1, i2);
|
||||
RippleAsset a3 (c2, i2);
|
||||
RippleAsset a4 (c3, i2);
|
||||
Issue a1 (c1, i1);
|
||||
Issue a2 (c1, i2);
|
||||
Issue a3 (c2, i2);
|
||||
Issue a4 (c3, i2);
|
||||
|
||||
expect (Book (a1, a2) != Book (a2, a3));
|
||||
expect (Book (a1, a2) < Book (a2, a3));
|
||||
@@ -320,10 +320,10 @@ public:
|
||||
Account const i1 (1);
|
||||
Currency const c2 (2);
|
||||
Account const i2 (2);
|
||||
RippleAssetRef const a1 (c1, i1);
|
||||
RippleAssetRef const a2 (c2, i2);
|
||||
RippleBookRef const b1 (a1, a2);
|
||||
RippleBookRef const b2 (a2, a1);
|
||||
IssueRef const a1 (c1, i1);
|
||||
IssueRef const a2 (c2, i2);
|
||||
BookRef const b1 (a1, a2);
|
||||
BookRef const b2 (a2, a1);
|
||||
|
||||
{
|
||||
Set c;
|
||||
@@ -333,9 +333,9 @@ public:
|
||||
c.insert (b2);
|
||||
if (! expect (c.size () == 2)) return;
|
||||
|
||||
if (! expect (c.erase (RippleBook (a1, a1)) == 0)) return;
|
||||
if (! expect (c.erase (RippleBook (a1, a2)) == 1)) return;
|
||||
if (! expect (c.erase (RippleBook (a2, a1)) == 1)) return;
|
||||
if (! expect (c.erase (Book (a1, a1)) == 0)) return;
|
||||
if (! expect (c.erase (Book (a1, a2)) == 1)) return;
|
||||
if (! expect (c.erase (Book (a2, a1)) == 1)) return;
|
||||
if (! expect (c.empty ())) return;
|
||||
}
|
||||
|
||||
@@ -347,9 +347,9 @@ public:
|
||||
c.insert (b2);
|
||||
if (! expect (c.size () == 2)) return;
|
||||
|
||||
if (! expect (c.erase (RippleBookRef (a1, a1)) == 0)) return;
|
||||
if (! expect (c.erase (RippleBookRef (a1, a2)) == 1)) return;
|
||||
if (! expect (c.erase (RippleBookRef (a2, a1)) == 1)) return;
|
||||
if (! expect (c.erase (BookRef (a1, a1)) == 0)) return;
|
||||
if (! expect (c.erase (BookRef (a1, a2)) == 1)) return;
|
||||
if (! expect (c.erase (BookRef (a2, a1)) == 1)) return;
|
||||
if (! expect (c.empty ())) return;
|
||||
|
||||
#if STL_SET_HAS_EMPLACE
|
||||
@@ -368,13 +368,13 @@ public:
|
||||
Account const i1 (1);
|
||||
Currency const c2 (2);
|
||||
Account const i2 (2);
|
||||
RippleAssetRef const a1 (c1, i1);
|
||||
RippleAssetRef const a2 (c2, i2);
|
||||
RippleBookRef const b1 (a1, a2);
|
||||
RippleBookRef const b2 (a2, a1);
|
||||
IssueRef const a1 (c1, i1);
|
||||
IssueRef const a2 (c2, i2);
|
||||
BookRef const b1 (a1, a2);
|
||||
BookRef const b2 (a2, a1);
|
||||
|
||||
//typename Map::value_type value_type;
|
||||
//std::pair <RippleBookRef const, int> value_type;
|
||||
//std::pair <BookRef const, int> value_type;
|
||||
|
||||
{
|
||||
Map c;
|
||||
@@ -386,9 +386,9 @@ public:
|
||||
c.insert (std::make_pair (b2, 1));
|
||||
if (! expect (c.size () == 2)) return;
|
||||
|
||||
if (! expect (c.erase (RippleBook (a1, a1)) == 0)) return;
|
||||
if (! expect (c.erase (RippleBook (a1, a2)) == 1)) return;
|
||||
if (! expect (c.erase (RippleBook (a2, a1)) == 1)) return;
|
||||
if (! expect (c.erase (Book (a1, a1)) == 0)) return;
|
||||
if (! expect (c.erase (Book (a1, a2)) == 1)) return;
|
||||
if (! expect (c.erase (Book (a2, a1)) == 1)) return;
|
||||
if (! expect (c.empty ())) return;
|
||||
}
|
||||
|
||||
@@ -402,56 +402,56 @@ public:
|
||||
c.insert (std::make_pair (b2, 1));
|
||||
if (! expect (c.size () == 2)) return;
|
||||
|
||||
if (! expect (c.erase (RippleBookRef (a1, a1)) == 0)) return;
|
||||
if (! expect (c.erase (RippleBookRef (a1, a2)) == 1)) return;
|
||||
if (! expect (c.erase (RippleBookRef (a2, a1)) == 1)) return;
|
||||
if (! expect (c.erase (BookRef (a1, a1)) == 0)) return;
|
||||
if (! expect (c.erase (BookRef (a1, a2)) == 1)) return;
|
||||
if (! expect (c.erase (BookRef (a2, a1)) == 1)) return;
|
||||
if (! expect (c.empty ())) return;
|
||||
}
|
||||
}
|
||||
|
||||
void testBookSets ()
|
||||
{
|
||||
testcase ("std::set <RippleBook>");
|
||||
testBookSet <std::set <RippleBook>> ();
|
||||
testcase ("std::set <Book>");
|
||||
testBookSet <std::set <Book>> ();
|
||||
|
||||
testcase ("std::set <RippleBookRef>");
|
||||
testBookSet <std::set <RippleBookRef>> ();
|
||||
testcase ("std::set <BookRef>");
|
||||
testBookSet <std::set <BookRef>> ();
|
||||
|
||||
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
||||
testcase ("std::unordered_set <RippleBook>");
|
||||
testBookSet <std::unordered_set <RippleBook>> ();
|
||||
testcase ("std::unordered_set <Book>");
|
||||
testBookSet <std::unordered_set <Book>> ();
|
||||
|
||||
testcase ("std::unordered_set <RippleBookRef>");
|
||||
testBookSet <std::unordered_set <RippleBookRef>> ();
|
||||
testcase ("std::unordered_set <BookRef>");
|
||||
testBookSet <std::unordered_set <BookRef>> ();
|
||||
#endif
|
||||
|
||||
testcase ("ripple::unordered_set <RippleBook>");
|
||||
testBookSet <ripple::unordered_set <RippleBook>> ();
|
||||
testcase ("ripple::unordered_set <Book>");
|
||||
testBookSet <ripple::unordered_set <Book>> ();
|
||||
|
||||
testcase ("ripple::unordered_set <RippleBookRef>");
|
||||
testBookSet <ripple::unordered_set <RippleBookRef>> ();
|
||||
testcase ("ripple::unordered_set <BookRef>");
|
||||
testBookSet <ripple::unordered_set <BookRef>> ();
|
||||
}
|
||||
|
||||
void testBookMaps ()
|
||||
{
|
||||
testcase ("std::map <RippleBook, int>");
|
||||
testBookMap <std::map <RippleBook, int>> ();
|
||||
testcase ("std::map <Book, int>");
|
||||
testBookMap <std::map <Book, int>> ();
|
||||
|
||||
testcase ("std::map <RippleBookRef, int>");
|
||||
testBookMap <std::map <RippleBookRef, int>> ();
|
||||
testcase ("std::map <BookRef, int>");
|
||||
testBookMap <std::map <BookRef, int>> ();
|
||||
|
||||
#if RIPPLE_ASSETS_ENABLE_STD_HASH
|
||||
testcase ("std::unordered_map <RippleBook, int>");
|
||||
testBookMap <std::unordered_map <RippleBook, int>> ();
|
||||
testcase ("std::unordered_map <Book, int>");
|
||||
testBookMap <std::unordered_map <Book, int>> ();
|
||||
|
||||
testcase ("std::unordered_map <RippleBookRef, int>");
|
||||
testBookMap <std::unordered_map <RippleBookRef, int>> ();
|
||||
testcase ("std::unordered_map <BookRef, int>");
|
||||
testBookMap <std::unordered_map <BookRef, int>> ();
|
||||
|
||||
testcase ("ripple::unordered_map <RippleBook, int>");
|
||||
testBookMap <ripple::unordered_map <RippleBook, int>> ();
|
||||
testcase ("ripple::unordered_map <Book, int>");
|
||||
testBookMap <ripple::unordered_map <Book, int>> ();
|
||||
|
||||
testcase ("ripple::unordered_map <RippleBookRef, int>");
|
||||
testBookMap <ripple::unordered_map <RippleBookRef, int>> ();
|
||||
testcase ("ripple::unordered_map <BookRef, int>");
|
||||
testBookMap <ripple::unordered_map <BookRef, int>> ();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -467,28 +467,28 @@ public:
|
||||
|
||||
// ---
|
||||
|
||||
testcase ("RippleAsset");
|
||||
testAssetType <RippleAsset> ();
|
||||
testcase ("Issue");
|
||||
testIssueType <Issue> ();
|
||||
|
||||
testcase ("RippleAssetRef");
|
||||
testAssetType <RippleAssetRef> ();
|
||||
testcase ("IssueRef");
|
||||
testIssueType <IssueRef> ();
|
||||
|
||||
testAssetSets ();
|
||||
testAssetMaps ();
|
||||
testIssueSets ();
|
||||
testIssueMaps ();
|
||||
|
||||
// ---
|
||||
|
||||
testcase ("RippleBook");
|
||||
testBook <RippleBook> ();
|
||||
testcase ("Book");
|
||||
testBook <Book> ();
|
||||
|
||||
testcase ("RippleBookRef");
|
||||
testBook <RippleBookRef> ();
|
||||
testcase ("BookRef");
|
||||
testBook <BookRef> ();
|
||||
|
||||
testBookSets ();
|
||||
testBookMaps ();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(RippleAsset,types,ripple);
|
||||
BEAST_DEFINE_TESTSUITE(Issue,types,ripple);
|
||||
|
||||
}
|
||||
@@ -129,7 +129,7 @@ const char* systemCurrencyCode() {
|
||||
return "XRP";
|
||||
}
|
||||
|
||||
Account const& xrpIssuer()
|
||||
Account const& xrpAccount()
|
||||
{
|
||||
static const Account account(0);
|
||||
return account;
|
||||
|
||||
@@ -45,6 +45,6 @@
|
||||
#include <ripple/types/impl/strHex.cpp>
|
||||
#include <ripple/types/impl/UintTypes.cpp>
|
||||
#include <ripple/types/impl/RippleIdentifierTests.cpp>
|
||||
#include <ripple/types/impl/RippleAssets.cpp>
|
||||
#include <ripple/types/impl/Issue.cpp>
|
||||
|
||||
#include <ripple/common/tests/cross_offer.test.cpp>
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <ripple/types/api/AgedHistory.h>
|
||||
#include <ripple/types/api/Blob.h>
|
||||
#include <ripple/types/api/Base58.h>
|
||||
#include <ripple/types/api/Book.h>
|
||||
#include <ripple/types/api/ByteOrder.h>
|
||||
#include <ripple/types/api/strHex.h>
|
||||
#include <ripple/types/api/UInt160.h>
|
||||
@@ -54,7 +55,6 @@
|
||||
#include <ripple/types/api/RippleAccountID.h>
|
||||
#include <ripple/types/api/RippleAccountPublicKey.h>
|
||||
#include <ripple/types/api/RippleAccountPrivateKey.h>
|
||||
#include <ripple/types/api/RippleAssets.h>
|
||||
#include <ripple/types/api/RipplePublicKey.h>
|
||||
#include <ripple/types/api/RipplePrivateKey.h>
|
||||
#include <ripple/types/api/SimpleIdentifier.h>
|
||||
|
||||
Reference in New Issue
Block a user