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:
Tom Ritchford
2014-07-03 18:20:47 -04:00
committed by Nik Bougalis
parent a96dee85d2
commit 206efbf30d
42 changed files with 1611 additions and 1490 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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());

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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);
}
}
}

View File

@@ -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 --> $ :"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 ();

View File

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

View File

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

View File

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

View File

@@ -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 ();

View File

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

View File

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

View 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

View File

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

View 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

View File

@@ -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 ());

View File

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

View File

@@ -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 ();
}

View File

@@ -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 ();

View File

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

View 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

View File

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

View File

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

View File

@@ -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);
}

View File

@@ -129,7 +129,7 @@ const char* systemCurrencyCode() {
return "XRP";
}
Account const& xrpIssuer()
Account const& xrpAccount()
{
static const Account account(0);
return account;

View File

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

View File

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