Require issuer when specifying currency when creating STAmount.

This commit is contained in:
Arthur Britto
2012-08-25 14:49:45 -07:00
parent 0cb14e4e8a
commit cf450106c4
4 changed files with 136 additions and 111 deletions

View File

@@ -651,10 +651,10 @@ STAmount operator-(const STAmount& v1, const STAmount& v2)
return STAmount(v1.name, v1.mCurrency, -fv, ov1, true);
}
STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& currencyOut)
STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& uCurrencyID, const uint160& uIssuerID)
{
if (den.isZero()) throw std::runtime_error("division by zero");
if (num.isZero()) return STAmount(currencyOut);
if (num.isZero()) return STAmount(uCurrencyID, uIssuerID);
uint64 numVal = num.mValue, denVal = den.mValue;
int numOffset = num.mOffset, denOffset = den.mOffset;
@@ -690,14 +690,14 @@ STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint16
assert(BN_num_bytes(&v) <= 64);
if (num.mIsNegative != den.mIsNegative)
return -STAmount(currencyOut, v.getulong(), finOffset);
else return STAmount(currencyOut, v.getulong(), finOffset);
return -STAmount(uCurrencyID, uIssuerID, v.getulong(), finOffset);
else return STAmount(uCurrencyID, uIssuerID, v.getulong(), finOffset);
}
STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint160& currencyOut)
STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID)
{
if (v1.isZero() || v2.isZero())
return STAmount(currencyOut);
return STAmount(uCurrencyID, uIssuerID);
if (v1.mIsNative && v2.mIsNative) // FIXME: overflow
return STAmount(v1.name, v1.getSNValue() * v2.getSNValue());
@@ -753,8 +753,8 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16
assert(BN_num_bytes(&v) <= 64);
if (v1.mIsNegative != v2.mIsNegative)
return -STAmount(currencyOut, v.getulong(), offset1 + offset2 + 14);
else return STAmount(currencyOut, v.getulong(), offset1 + offset2 + 14);
return -STAmount(uCurrencyID, uIssuerID, v.getulong(), offset1 + offset2 + 14);
else return STAmount(uCurrencyID, uIssuerID, v.getulong(), offset1 + offset2 + 14);
}
// Convert an offer into an index amount so they sort by rate.
@@ -769,7 +769,7 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn)
{
if (offerOut.isZero()) throw std::runtime_error("Worthless offer");
STAmount r = divide(offerIn, offerOut, uint160(1));
STAmount r = divide(offerIn, offerOut, CURRENCY_ONE, ACCOUNT_ONE);
assert((r.getExponent() >= -100) && (r.getExponent() <= 155));
@@ -778,12 +778,12 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn)
return (ret << (64 - 8)) | r.getMantissa();
}
STAmount STAmount::setRate(uint64 rate, const uint160& currencyOut)
STAmount STAmount::setRate(uint64 rate)
{
uint64 mantissa = rate & ~(255ull << (64 - 8));
int exponent = static_cast<int>(rate >> (64 - 8)) - 100;
return STAmount(currencyOut, mantissa, exponent);
return STAmount(CURRENCY_ONE, ACCOUNT_ONE, mantissa, exponent);
}
// Taker gets all taker can pay for with saTakerFunds, limited by saOfferPays and saOfferFunds.
@@ -814,7 +814,7 @@ bool STAmount::applyOffer(
STAmount saOfferGetsAvailable =
saOfferFunds == saOfferPays
? saOfferGets // Offer was fully funded, avoid shenanigans.
: divide(multiply(saTakerPays, saOfferPaysAvailable, uint160(1)), saTakerGets, saOfferGets.getCurrency());
: divide(multiply(saTakerPays, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saTakerGets, saOfferGets.getCurrency(), saOfferGets.getIssuer());
if (saOfferGets == saOfferGetsAvailable && saTakerFunds >= saOfferGets)
{
@@ -836,7 +836,7 @@ bool STAmount::applyOffer(
{
// Taker only get's a portion of offer.
saTakerPaid = saTakerFunds; // Taker paid all he had.
saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, uint160(1)), saOfferGetsAvailable, saOfferPays.getCurrency());
saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saOfferGetsAvailable, saOfferPays.getCurrency(), saOfferPays.getIssuer());
Log(lsINFO) << "applyOffer: saTakerGot=" << saTakerGot.getFullText();
Log(lsINFO) << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable.getFullText();
@@ -848,7 +848,7 @@ bool STAmount::applyOffer(
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?
if (offerOut.isZero())
return STAmount(offerIn.getCurrency());
return STAmount(offerIn.getCurrency(), offerIn.getIssuer());
if (needed >= offerOut)
{
@@ -856,7 +856,7 @@ STAmount STAmount::getPay(const STAmount& offerOut, const STAmount& offerIn, con
return needed;
}
STAmount ret = divide(multiply(needed, offerIn, uint160(1)), offerOut, offerIn.getCurrency());
STAmount ret = divide(multiply(needed, offerIn, CURRENCY_ONE, ACCOUNT_ONE), offerOut, offerIn.getCurrency(), offerIn.getIssuer());
return (ret > offerIn) ? offerIn : ret;
}
@@ -1063,8 +1063,7 @@ BOOST_AUTO_TEST_CASE( NativeCurrency_test )
BOOST_AUTO_TEST_CASE( CustomCurrency_test )
{
uint160 currency(1);
STAmount zero(currency), one(currency, 1), hundred(currency, 100);
STAmount zero(CURRENCY_ONE, ACCOUNT_ONE), one(CURRENCY_ONE, ACCOUNT_ONE, 1), hundred(CURRENCY_ONE, ACCOUNT_ONE, 100);
serdes(one).getRaw();
@@ -1131,33 +1130,33 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test )
if (!(hundred != zero)) BOOST_FAIL("STAmount fail");
if (!(hundred != one)) BOOST_FAIL("STAmount fail");
if ((hundred != hundred)) BOOST_FAIL("STAmount fail");
if (STAmount(currency).getText() != "0") BOOST_FAIL("STAmount fail");
if (STAmount(currency,31).getText() != "31") BOOST_FAIL("STAmount fail");
if (STAmount(currency,31,1).getText() != "310") BOOST_FAIL("STAmount fail");
if (STAmount(currency,31,-1).getText() != "3.1") BOOST_FAIL("STAmount fail");
if (STAmount(currency,31,-2).getText() != "0.31") BOOST_FAIL("STAmount fail");
if (STAmount(CURRENCY_ONE, ACCOUNT_ONE).getText() != "0") BOOST_FAIL("STAmount fail");
if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31).getText() != "31") BOOST_FAIL("STAmount fail");
if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,1).getText() != "310") BOOST_FAIL("STAmount fail");
if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,-1).getText() != "3.1") BOOST_FAIL("STAmount fail");
if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,-2).getText() != "0.31") BOOST_FAIL("STAmount fail");
if (STAmount::multiply(STAmount(currency, 20), STAmount(3), currency).getText() != "60")
if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
if (STAmount::multiply(STAmount(currency, 20), STAmount(3), uint160()).getText() != "60")
if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
if (STAmount::multiply(STAmount(20), STAmount(3), currency).getText() != "60")
if (STAmount::multiply(STAmount(20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
if (STAmount::multiply(STAmount(20), STAmount(3), uint160()).getText() != "60")
if (STAmount::multiply(STAmount(20), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
if (STAmount::divide(STAmount(currency, 60) , STAmount(3), currency).getText() != "20")
if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20")
BOOST_FAIL("STAmount divide fail");
if (STAmount::divide(STAmount(currency, 60) , STAmount(3), uint160()).getText() != "20")
if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "20")
BOOST_FAIL("STAmount divide fail");
if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), currency).getText() != "20")
if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20")
BOOST_FAIL("STAmount divide fail");
if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), uint160()).getText() != "20")
if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), uint160(), ACCOUNT_XNS).getText() != "20")
BOOST_FAIL("STAmount divide fail");
STAmount a1(currency, 60), a2 (currency, 10, -1);
if (STAmount::divide(a2, a1, currency) != STAmount::setRate(STAmount::getRate(a1, a2), currency))
STAmount a1(CURRENCY_ONE, ACCOUNT_ONE, 60), a2 (CURRENCY_ONE, ACCOUNT_ONE, 10, -1);
if (STAmount::divide(a2, a1, CURRENCY_ONE, ACCOUNT_ONE) != STAmount::setRate(STAmount::getRate(a1, a2)))
BOOST_FAIL("STAmount setRate(getRate) fail");
if (STAmount::divide(a1, a2, currency) != STAmount::setRate(STAmount::getRate(a2, a1), currency))
if (STAmount::divide(a1, a2, CURRENCY_ONE, ACCOUNT_ONE) != STAmount::setRate(STAmount::getRate(a2, a1)))
BOOST_FAIL("STAmount setRate(getRate) fail");
BOOST_TEST_MESSAGE("Amount CC Complete");
@@ -1168,22 +1167,21 @@ BOOST_AUTO_TEST_CASE( CurrencyMulDivTests )
// Test currency multiplication and division operations such as
// convertToDisplayAmount, convertToInternalAmount, getRate, getClaimed, and getNeeded
uint160 c(1);
if (STAmount::getRate(STAmount(1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(c, 1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(c, 10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(c, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(c, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
if (STAmount::getRate(STAmount(1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
if (STAmount::getRate(STAmount(10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
}

View File

@@ -261,10 +261,11 @@ public:
: SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false)
{ ; }
STAmount(const uint160& uCurrency, uint64 uV=0, int iOff=0, bool bNegative=false)
: mCurrency(uCurrency), mValue(uV), mOffset(iOff), mIsNegative(bNegative)
STAmount(const uint160& uCurrencyID, const uint160& uIssuerID, uint64 uV=0, int iOff=0, bool bNegative=false)
: mCurrency(uCurrencyID), mIssuer(uIssuerID), mValue(uV), mOffset(iOff), mIsNegative(bNegative)
{ canonicalize(); }
// YYY This should probably require issuer too.
STAmount(const char* n, const uint160& currency, uint64 v = 0, int off = 0, bool isNeg = false) :
SerializedType(n), mCurrency(currency), mValue(v), mOffset(off), mIsNegative(isNeg)
{ canonicalize(); }
@@ -274,14 +275,14 @@ public:
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
static STAmount saFromRate(uint64 uV = 0)
static STAmount saFromRate(uint64 uRate = 0)
{
return STAmount(CURRENCY_ONE, uV, -9, false);
return STAmount(CURRENCY_ONE, ACCOUNT_ONE, uRate, -9, false);
}
static STAmount saFromSigned(const uint160& uCurrency, int64 iV=0, int iOff=0)
static STAmount saFromSigned(const uint160& uCurrencyID, const uint160& uIssuerID, int64 iV=0, int iOff=0)
{
return STAmount(uCurrency, iV < 0 ? -iV : iV, iOff, iV < 0);
return STAmount(uCurrencyID, uIssuerID, iV < 0 ? -iV : iV, iOff, iV < 0);
}
int getLength() const { return mIsNative ? 8 : 28; }
@@ -351,13 +352,13 @@ public:
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, const uint160& currencyOut);
static STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& currencyOut);
static STAmount divide(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID);
static STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID);
// Someone is offering X for Y, what is the rate?
// Rate: smaller is better, the taker wants the most out: in/out
static uint64 getRate(const STAmount& offerOut, const STAmount& offerIn);
static STAmount setRate(uint64 rate, const uint160& currencyOut);
static STAmount setRate(uint64 rate);
// Someone is offering X for Y, I try to pay Z, how much do I get?
// And what's left of the offer? And how much do I actually pay?

View File

@@ -102,7 +102,9 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std
return iIndex >= 0;
}
STAmount TransactionEngine::rippleBalance(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID)
// Returns amount owed by uToAccountID to uFromAccountID.
// <-- $owed/uCurrencyID/uToAccountID: positive: uFromAccountID holds IOUs., negative: uFromAccountID owes IOUs.
STAmount TransactionEngine::rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID)
{
STAmount saBalance;
SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID));
@@ -112,10 +114,11 @@ STAmount TransactionEngine::rippleBalance(const uint160& uToAccountID, const uin
saBalance = sleRippleState->getIValueFieldAmount(sfBalance);
if (uToAccountID < uFromAccountID)
saBalance.negate();
saBalance.setIssuer(uToAccountID);
}
else
{
Log(lsINFO) << "rippleBalance: No credit line between "
Log(lsINFO) << "rippleOwed: No credit line between "
<< NewcoinAddress::createHumanAccountID(uFromAccountID)
<< " and "
<< NewcoinAddress::createHumanAccountID(uToAccountID)
@@ -130,6 +133,8 @@ STAmount TransactionEngine::rippleBalance(const uint160& uToAccountID, const uin
}
// Maximum amount of IOUs uToAccountID will hold from uFromAccountID.
// <-- $amount/uCurrencyID/uToAccountID.
STAmount TransactionEngine::rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID)
{
STAmount saLimit;
@@ -139,6 +144,7 @@ STAmount TransactionEngine::rippleLimit(const uint160& uToAccountID, const uint1
if (sleRippleState)
{
saLimit = sleRippleState->getIValueFieldAmount(uToAccountID < uFromAccountID ? sfLowLimit : sfHighLimit);
saLimit.setIssuer(uToAccountID);
}
return saLimit;
@@ -300,7 +306,7 @@ STAmount TransactionEngine::rippleTransferFee(const uint160& uSenderID, const ui
{
STAmount saTransitRate(CURRENCY_ONE, uTransitRate, -9);
saTransitFee = STAmount::multiply(saAmount, saTransitRate, saAmount.getCurrency());
saTransitFee = STAmount::multiply(saAmount, saTransitRate, saAmount.getCurrency(), saAmount.getIssuer());
}
}
@@ -1583,9 +1589,9 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti
Log(lsINFO) << "doCreditSet: Creating ripple line: " << sleRippleState->getIndex().ToString();
sleRippleState->setIFieldAmount(sfBalance, STAmount(uCurrencyID)); // Zero balance in currency.
sleRippleState->setIFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency.
sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAmount);
sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID));
sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, ACCOUNT_ONE));
sleRippleState->setIFieldAccount(bFlipped ? sfHighID : sfLowID, mTxnAccountID);
sleRippleState->setIFieldAccount(bFlipped ? sfLowID : sfHighID, uDstAccountID);
if (uQualityIn)
@@ -1944,7 +1950,7 @@ bool TransactionEngine::calcNodeOfferRev(
// - Drive on computing saCurDlvAct to derive saPrvDlvAct.
// XXX Behave well, if entry type is wrong (someone beat us to using the hash)
SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip);
STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip), uCurCurrencyID); // For correct ratio
STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio
unsigned int uEntry = 0;
uint256 uCurIndex;
@@ -1987,13 +1993,13 @@ bool TransactionEngine::calcNodeOfferRev(
STAmount saOutBase = MIN(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed.
STAmount saOutCost = MIN(
bFee
? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID)
? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID)
: saOutBase,
saCurOfrFunds); // Limit cost by fees & funds.
STAmount saOutDlvAct = bFee
? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID)
? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID)
: saOutCost; // Out amount after fees.
STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required.
STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required.
saCurDlvAct += saOutDlvAct; // Portion of driver served.
saPrvDlvAct += saInDlvAct; // Portion needed in previous.
@@ -2044,13 +2050,14 @@ bool TransactionEngine::calcNodeOfferRev(
saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer.
STAmount saOutCost = MIN(
bFee
? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID)
? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID)
: saOutBase,
saCurOfrFunds); // Limit cost by fees & funds.
STAmount saOutDlvAct = bFee
? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID)
? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID)
: saOutCost; // Out amount after fees.
STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required.
// Compute input w/o fees required.
STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID);
saCurDlvAct += saOutDlvAct; // Portion of driver served.
saPrvDlvAct += saInDlvAct; // Portion needed in previous.
@@ -2078,7 +2085,7 @@ bool TransactionEngine::calcNodeOfferRev(
Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev< uIndex=%d saPrvDlvReq=%s bSuccess=%d")
% uIndex
% saPrvDlvReq.getText()
% saPrvDlvReq.getFullText()
% bSuccess);
return bSuccess;
@@ -2134,7 +2141,7 @@ bool TransactionEngine::calcNodeOfferFwd(
// Do a directory.
// - Drive on computing saPrvDlvAct to derive saCurDlvAct.
SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip);
STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip), uCurCurrencyID); // For correct ratio
STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio
unsigned int uEntry = 0;
uint256 uCurIndex;
@@ -2158,17 +2165,18 @@ bool TransactionEngine::calcNodeOfferFwd(
: saTransferRate;
const bool bFee = saFeeRate != saOne;
const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID);
const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID, uCurIssuerID);
const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed.
const STAmount saOutCost = MIN(
bFee
? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID)
? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID)
: saOutBase,
saCurOfrFunds); // Limit cost by fees & funds.
const STAmount saOutDlvAct = bFee
? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID)
? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID)
: saOutCost; // Out amount after fees.
const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uCurCurrencyID); // Compute input w/o fees required.
// Compute input w/o fees required.
const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uCurCurrencyID, uCurIssuerID);
saCurDlvAct += saOutDlvAct; // Portion of driver served.
saPrvDlvAct += saInDlvAct; // Portion needed in previous.
@@ -2216,18 +2224,18 @@ bool TransactionEngine::calcNodeOfferFwd(
const bool bFee = saFeeRate != saOne;
const STAmount saInBase = saCurOfrInMax-saCurOfrInAct;
const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID);
const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID, uCurIssuerID);
STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed.
saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer.
const STAmount saOutCost = MIN(
bFee
? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID)
? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID)
: saOutBase,
saCurOfrFunds); // Limit cost by fees & funds.
const STAmount saOutDlvAct = bFee
? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID)
? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID)
: saOutCost; // Out amount after fees.
const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required.
const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required.
saCurOfrInAct += saOutDlvAct; // Portion of driver served.
saPrvDlvAct += saOutDlvAct; // Portion needed in previous.
@@ -2538,8 +2546,11 @@ void TransactionEngine::calcNodeRipple(
// Fee.
Log(lsINFO) << boost::str(boost::format("calcNodeRipple: Fee"));
uint160 uCurrencyID = saCur.getCurrency();
STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID), uQualityIn, uCurrencyID);
const uint160 uCurrencyID = saCur.getCurrency();
const uint160 uCurIssuerID = saCur.getIssuer();
const uint160 uPrvIssuerID = saPrv.getIssuer();
STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID, uCurIssuerID), uQualityIn, uCurrencyID, uCurIssuerID);
Log(lsINFO) << boost::str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCurIn=%s") % bPrvUnlimited % saPrv.getFullText() % saCurIn.getFullText());
if (bPrvUnlimited || saCurIn <= saPrv)
@@ -2552,8 +2563,7 @@ Log(lsINFO) << boost::str(boost::format("calcNodeRipple:3c: saCurReq=%s saPrvAct
else
{
// A part of cur. All of prv. (cur as driver)
uint160 uCurrencyID = saPrv.getCurrency();
STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID), uQualityOut, uCurrencyID);
STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID, uCurIssuerID), uQualityOut, uCurrencyID, uCurIssuerID);
Log(lsINFO) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCurReq.getFullText());
saCurAct += saCurOut;
@@ -2597,25 +2607,32 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE;
// For bPrvAccount
const STAmount saPrvBalance = uIndex && bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID);
const STAmount saPrvLimit = uIndex && bPrvAccount ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID);
const STAmount saPrvOwed = uIndex && bPrvAccount // Previous account is owed.
? rippleOwed(uCurAccountID, uPrvAccountID, uCurrencyID)
: STAmount(uCurrencyID, uCurAccountID);
const STAmount saPrvLimit = uIndex && bPrvAccount // Previous account may owe.
? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID)
: STAmount(uCurrencyID, uCurAccountID);
Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvBalance=%s saPrvLimit=%s")
Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d bPrvIssue=%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvOwed=%s saPrvLimit=%s")
% uIndex
% uLast
% bPrvIssue
% NewcoinAddress::createHumanAccountID(uPrvAccountID)
% NewcoinAddress::createHumanAccountID(uCurAccountID)
% NewcoinAddress::createHumanAccountID(uNxtAccountID)
% STAmount::createHumanCurrency(uCurrencyID)
% uQualityIn
% uQualityOut
% saPrvBalance.getText()
% saPrvLimit.getText());
% saPrvOwed.getFullText()
% saPrvLimit.getFullText());
const STAmount saPrvRedeemReq = bPrvRedeem && saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0);
// Previous can redeem the owed IOUs it holds.
const STAmount saPrvRedeemReq = bPrvRedeem && saPrvOwed.isPositive() ? saPrvOwed : STAmount(uCurrencyID, 0);
STAmount& saPrvRedeemAct = pnPrv.saRevRedeem;
const STAmount saPrvIssueReq = bPrvIssue ? saPrvLimit - saPrvBalance : STAmount(uCurrencyID);
// Previous can issue up to limit minus whatever portion of limit already used (not including redeemable amount).
const STAmount saPrvIssueReq = bPrvIssue && saPrvOwed.isNegative() ? saPrvLimit+saPrvOwed : saPrvLimit;
STAmount& saPrvIssueAct = pnPrv.saRevIssue;
// For !bPrvAccount
@@ -2624,27 +2641,25 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
// For bNxtAccount
const STAmount& saCurRedeemReq = pnCur.saRevRedeem;
STAmount saCurRedeemAct(saCurRedeemReq.getCurrency());
STAmount saCurRedeemAct(saCurRedeemReq.getCurrency(), saCurRedeemReq.getIssuer());
const STAmount& saCurIssueReq = pnCur.saRevIssue;
STAmount saCurIssueAct(saCurIssueReq.getCurrency()); // Track progress.
STAmount saCurIssueAct(saCurIssueReq.getCurrency(), saCurIssueReq.getIssuer()); // Track progress.
// For !bNxtAccount
const STAmount& saCurDeliverReq = pnCur.saRevDeliver;
STAmount saCurDeliverAct(saCurDeliverReq.getCurrency());
STAmount saCurDeliverAct(saCurDeliverReq.getCurrency(), saCurDeliverReq.getIssuer());
// For uIndex == uLast
const STAmount& saCurWantedReq = pspCur->saOutReq; // XXX Credit limits?
// STAmount saPrvDeliverReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit;
STAmount saCurWantedAct(saCurWantedReq.getCurrency());
// For uIndex == uLast, over all deliverable.
const STAmount& saCurWantedReq = bPrvAccount
? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit.
: pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs.
STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer());
Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s/%s saPrvIssueReq=%s/%s saCurWantedReq=%s/%s")
% saPrvRedeemReq.getText()
% saPrvRedeemReq.getHumanCurrency()
% saPrvIssueReq.getText()
% saPrvIssueReq.getHumanCurrency()
% saCurWantedReq.getText()
% saCurWantedReq.getHumanCurrency());
Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurWantedReq=%s")
% saPrvRedeemReq.getFullText()
% saPrvIssueReq.getFullText()
% saCurWantedReq.getFullText());
Log(lsINFO) << pspCur->getJson();
@@ -2698,7 +2713,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
if (bPrvRedeem
&& bRedeem // Allowed to redeem.
&& saCurRedeemReq // Next wants us to redeem.
&& saPrvBalance.isNegative()) // Previous has IOUs to redeem.
&& saPrvOwed) // Previous has IOUs to redeem.
{
// Rate : 1.0 : quality out
Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : quality out"));
@@ -2710,7 +2725,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
if (bPrvRedeem
&& bIssue // Allowed to issue.
&& saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed.
&& saPrvBalance.isNegative() // Previous still has IOUs.
&& saPrvOwed // Previous still has IOUs.
&& saCurIssueReq) // Need some issued.
{
// Rate : 1.0 : transfer_rate
@@ -2723,7 +2738,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
if (bPrvIssue
&& bRedeem // Allowed to redeem.
&& saCurRedeemReq != saCurRedeemAct // Can only redeem if more to be redeemed.
&& !saPrvBalance.isNegative()) // Previous has no IOUs.
&& !saPrvOwed.isPositive()) // Previous has no IOUs.
{
// Rate: quality in : quality out
Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : quality out"));
@@ -2735,7 +2750,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
if (bPrvIssue
&& bIssue // Allowed to issue.
&& saCurRedeemReq == saCurRedeemAct // Can only if issue if more can not be redeemed.
&& !saPrvBalance.isNegative() // Previous has no IOUs.
&& !saPrvOwed.isPositive() // Previous has no IOUs.
&& saCurIssueReq != saCurIssueAct) // Need some issued.
{
// Rate: quality in : 1.0
@@ -2750,14 +2765,15 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
// terResult = tenBAD_AMOUNT;
bSuccess = false;
}
Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurRedeemReq=%s saCurIssueReq=%s saPrvBalance=%s saCurRedeemAct=%s saCurIssueAct=%s")
Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurRedeemReq=%s saCurIssueReq=%s saPrvOwed=%s saCurRedeemAct=%s saCurIssueAct=%s")
% bPrvRedeem
% bPrvIssue
% bRedeem
% bIssue
% saCurRedeemReq.getFullText()
% saCurIssueReq.getFullText()
% saPrvBalance.getFullText()
% saPrvOwed.getFullText()
% saCurRedeemAct.getFullText()
% saCurIssueAct.getFullText());
}
@@ -2771,7 +2787,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
// redeem -> deliver/issue.
if (bPrvRedeem
&& bIssue // Allowed to issue.
&& saPrvBalance.isNegative() // Previous redeeming: Previous still has IOUs.
&& saPrvOwed.isPositive() // Previous redeeming: Previous still has IOUs.
&& saCurDeliverReq) // Need some issued.
{
// Rate : 1.0 : transfer_rate
@@ -2781,7 +2797,8 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
// issue -> deliver/issue
if (bPrvIssue
&& bIssue // Allowed to issue.
&& !saPrvBalance.isNegative() // Previous issuing: Previous has no IOUs.
&& (!saPrvOwed.isPositive() // Previous issuing: Never had IOUs.
|| saPrvOwed == saPrvRedeemAct) // Previous issuing: Previous has no IOUs left after redeeming.
&& saCurDeliverReq != saCurDeliverAct) // Need some issued.
{
// Rate: quality in : 1.0
@@ -2794,6 +2811,15 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
// terResult = tenBAD_AMOUNT;
bSuccess = false;
}
Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurDeliverReq=%s saCurDeliverAct=%s saPrvOwed=%s")
% bPrvRedeem
% bPrvIssue
% bRedeem
% bIssue
% saCurDeliverReq.getFullText()
% saCurDeliverAct.getFullText()
% saPrvOwed.getFullText());
}
else if (!bPrvAccount && bNxtAccount)
{
@@ -2906,14 +2932,14 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point
// For bNxtAccount
const STAmount& saPrvRedeemReq = pnPrv.saFwdRedeem;
STAmount saPrvRedeemAct(saPrvRedeemReq.getCurrency());
STAmount saPrvRedeemAct(saPrvRedeemReq.getCurrency(), saPrvRedeemReq.getIssuer());
const STAmount& saPrvIssueReq = pnPrv.saFwdIssue;
STAmount saPrvIssueAct(saPrvIssueReq.getCurrency());
STAmount saPrvIssueAct(saPrvIssueReq.getCurrency(), saPrvIssueReq.getIssuer());
// For !bPrvAccount
const STAmount& saPrvDeliverReq = pnPrv.saRevDeliver;
STAmount saPrvDeliverAct(saPrvDeliverReq.getCurrency());
STAmount saPrvDeliverAct(saPrvDeliverReq.getCurrency(), saPrvDeliverReq.getIssuer());
// For bNxtAccount
const STAmount& saCurRedeemReq = pnCur.saRevRedeem;
@@ -3003,7 +3029,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point
STAmount saIssueCrd = uQualityIn >= QUALITY_ONE
? saPrvIssueReq // No fee.
: STAmount::multiply(saPrvIssueReq, uQualityIn, uCurrencyID); // Fee.
: STAmount::multiply(saPrvIssueReq, uQualityIn, uCurrencyID, saPrvIssueReq.getIssuer()); // Fee.
// Amount to credit.
saCurReceive = saPrvRedeemReq+saIssueCrd;
@@ -3259,8 +3285,8 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin
pnCur.uAccountID = uAccountID;
pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID;
pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID;
pnCur.saRevRedeem = STAmount(uCurrencyID);
pnCur.saRevIssue = STAmount(uCurrencyID);
pnCur.saRevRedeem = STAmount(uCurrencyID, uAccountID);
pnCur.saRevIssue = STAmount(uCurrencyID, uAccountID);
if (!bFirst)
{

View File

@@ -226,7 +226,7 @@ protected:
void entryModify(SLE::pointer sleEntry);
uint32 rippleTransferRate(const uint160& uIssuerID);
STAmount rippleBalance(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
STAmount rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
STAmount rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
uint32 rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, const SOE_Field sfLow=sfLowQualityIn, const SOE_Field sfHigh=sfHighQualityIn);
uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID)