|
|
|
|
@@ -149,15 +149,25 @@ uint32 TransactionEngine::rippleTransferRate(const uint160& uIssuerID)
|
|
|
|
|
{
|
|
|
|
|
SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uIssuerID));
|
|
|
|
|
|
|
|
|
|
return sleAccount->getIFieldPresent(sfTransferRate)
|
|
|
|
|
? sleAccount->getIFieldU32(sfTransferRate)
|
|
|
|
|
: QUALITY_ONE;
|
|
|
|
|
uint32 uQuality = sleAccount && sleAccount->getIFieldPresent(sfTransferRate)
|
|
|
|
|
? sleAccount->getIFieldU32(sfTransferRate)
|
|
|
|
|
: QUALITY_ONE;
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << str(boost::format("rippleTransferRate: uIssuerID=%s account_exists=%d transfer_rate=%f")
|
|
|
|
|
% NewcoinAddress::createHumanAccountID(uIssuerID)
|
|
|
|
|
% !!sleAccount
|
|
|
|
|
% (uQuality/1000000000.0));
|
|
|
|
|
|
|
|
|
|
assert(sleAccount);
|
|
|
|
|
|
|
|
|
|
return uQuality;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXX Might not need this, might store in nodes on calc reverse.
|
|
|
|
|
uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID)
|
|
|
|
|
{
|
|
|
|
|
uint32 uQualityIn = QUALITY_ONE;
|
|
|
|
|
uint32 uQualityIn = QUALITY_ONE;
|
|
|
|
|
SLE::pointer sleRippleState;
|
|
|
|
|
|
|
|
|
|
if (uToAccountID == uFromAccountID)
|
|
|
|
|
{
|
|
|
|
|
@@ -165,7 +175,7 @@ uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uin
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID));
|
|
|
|
|
sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID));
|
|
|
|
|
|
|
|
|
|
if (sleRippleState)
|
|
|
|
|
{
|
|
|
|
|
@@ -177,12 +187,17 @@ uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uin
|
|
|
|
|
if (!uQualityIn)
|
|
|
|
|
uQualityIn = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
assert(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << str(boost::format("rippleQualityIn: uToAccountID=%s uFromAccountID=%s uCurrencyID=%s bLine=%d uQualityIn=%f")
|
|
|
|
|
% NewcoinAddress::createHumanAccountID(uToAccountID)
|
|
|
|
|
% NewcoinAddress::createHumanAccountID(uFromAccountID)
|
|
|
|
|
% STAmount::createHumanCurrency(uCurrencyID)
|
|
|
|
|
% !!sleRippleState
|
|
|
|
|
% (uQualityIn/1000000000.0));
|
|
|
|
|
|
|
|
|
|
assert(uToAccountID == uFromAccountID || !!sleRippleState);
|
|
|
|
|
|
|
|
|
|
return uQualityIn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -236,7 +251,7 @@ STAmount TransactionEngine::accountHolds(const uint160& uAccountID, const uint16
|
|
|
|
|
{
|
|
|
|
|
STAmount saAmount;
|
|
|
|
|
|
|
|
|
|
if (uCurrencyID.isZero())
|
|
|
|
|
if (!uCurrencyID)
|
|
|
|
|
{
|
|
|
|
|
SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uAccountID));
|
|
|
|
|
|
|
|
|
|
@@ -382,7 +397,7 @@ STAmount TransactionEngine::rippleSend(const uint160& uSenderID, const uint160&
|
|
|
|
|
|
|
|
|
|
STAmount saTransitFee = rippleTransferFee(uSenderID, uReceiverID, uIssuerID, saAmount);
|
|
|
|
|
|
|
|
|
|
saActual = saTransitFee.isZero() ? saAmount : saAmount+saTransitFee;
|
|
|
|
|
saActual = !saTransitFee ? saAmount : saAmount+saTransitFee;
|
|
|
|
|
|
|
|
|
|
saActual.setIssuer(uIssuerID); // XXX Make sure this done in + above.
|
|
|
|
|
|
|
|
|
|
@@ -818,7 +833,7 @@ SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint25
|
|
|
|
|
{
|
|
|
|
|
SLE::pointer sleEntry;
|
|
|
|
|
|
|
|
|
|
if (!uIndex.isZero())
|
|
|
|
|
if (!!uIndex)
|
|
|
|
|
{
|
|
|
|
|
LedgerEntryAction action;
|
|
|
|
|
sleEntry = mNodes.getEntry(uIndex, action);
|
|
|
|
|
@@ -837,7 +852,7 @@ SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint25
|
|
|
|
|
|
|
|
|
|
SLE::pointer TransactionEngine::entryCreate(LedgerEntryType letType, const uint256& uIndex)
|
|
|
|
|
{
|
|
|
|
|
assert(!uIndex.isZero());
|
|
|
|
|
assert(!!uIndex);
|
|
|
|
|
|
|
|
|
|
SLE::pointer sleNew = boost::make_shared<SerializedLedgerEntry>(letType);
|
|
|
|
|
sleNew->setIndex(uIndex);
|
|
|
|
|
@@ -1015,7 +1030,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
|
|
|
|
|
|
|
|
|
if (terSUCCESS == terResult && (params & tepNO_CHECK_FEE) == tepNONE)
|
|
|
|
|
{
|
|
|
|
|
if (!saCost.isZero())
|
|
|
|
|
if (!!saCost)
|
|
|
|
|
{
|
|
|
|
|
if (saPaid < saCost)
|
|
|
|
|
{
|
|
|
|
|
@@ -1026,7 +1041,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!saPaid.isZero())
|
|
|
|
|
if (!!saPaid)
|
|
|
|
|
{
|
|
|
|
|
// Transaction is malformed.
|
|
|
|
|
Log(lsWARNING) << "applyTransaction: fee not allowed";
|
|
|
|
|
@@ -1153,7 +1168,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
|
|
|
|
|
|
|
|
|
// Deduct the fee, so it's not available during the transaction.
|
|
|
|
|
// Will only write the account back, if the transaction succeeds.
|
|
|
|
|
if (terSUCCESS != terResult || saCost.isZero())
|
|
|
|
|
if (terSUCCESS != terResult || !saCost)
|
|
|
|
|
{
|
|
|
|
|
nothing();
|
|
|
|
|
}
|
|
|
|
|
@@ -1176,7 +1191,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
|
|
|
|
{
|
|
|
|
|
nothing();
|
|
|
|
|
}
|
|
|
|
|
else if (!saCost.isZero())
|
|
|
|
|
else if (!!saCost)
|
|
|
|
|
{
|
|
|
|
|
uint32 a_seq = mTxnAccount->getIFieldU32(sfSequence);
|
|
|
|
|
|
|
|
|
|
@@ -1325,7 +1340,7 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact
|
|
|
|
|
{
|
|
|
|
|
uint128 uHash = txn.getITFieldH128(sfEmailHash);
|
|
|
|
|
|
|
|
|
|
if (uHash.isZero())
|
|
|
|
|
if (!uHash)
|
|
|
|
|
{
|
|
|
|
|
Log(lsINFO) << "doAccountSet: unset email hash";
|
|
|
|
|
|
|
|
|
|
@@ -1347,7 +1362,7 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact
|
|
|
|
|
{
|
|
|
|
|
uint256 uHash = txn.getITFieldH256(sfWalletLocator);
|
|
|
|
|
|
|
|
|
|
if (uHash.isZero())
|
|
|
|
|
if (!uHash)
|
|
|
|
|
{
|
|
|
|
|
Log(lsINFO) << "doAccountSet: unset wallet locator";
|
|
|
|
|
|
|
|
|
|
@@ -1444,7 +1459,7 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact
|
|
|
|
|
uint256 uHash = txn.getITFieldH256(sfPublishHash);
|
|
|
|
|
uint32 uSize = txn.getITFieldU32(sfPublishSize);
|
|
|
|
|
|
|
|
|
|
if (uHash.isZero())
|
|
|
|
|
if (!uHash)
|
|
|
|
|
{
|
|
|
|
|
Log(lsINFO) << "doAccountSet: unset publish";
|
|
|
|
|
|
|
|
|
|
@@ -1520,16 +1535,16 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti
|
|
|
|
|
{
|
|
|
|
|
// A line exists in one or more directions.
|
|
|
|
|
#if 0
|
|
|
|
|
if (saLimitAmount.isZero())
|
|
|
|
|
if (!saLimitAmount)
|
|
|
|
|
{
|
|
|
|
|
// Zeroing line.
|
|
|
|
|
uint160 uLowID = sleRippleState->getIValueFieldAccount(sfLowID).getAccountID();
|
|
|
|
|
uint160 uHighID = sleRippleState->getIValueFieldAccount(sfHighID).getAccountID();
|
|
|
|
|
bool bLow = uLowID == uSrcAccountID;
|
|
|
|
|
bool bHigh = uLowID == uDstAccountID;
|
|
|
|
|
bool bBalanceZero = sleRippleState->getIValueFieldAmount(sfBalance).isZero();
|
|
|
|
|
bool bBalanceZero = !sleRippleState->getIValueFieldAmount(sfBalance);
|
|
|
|
|
STAmount saDstLimit = sleRippleState->getIValueFieldAmount(bSendLow ? sfLowLimit : sfHighLimit);
|
|
|
|
|
bool bDstLimitZero = saDstLimit.isZero();
|
|
|
|
|
bool bDstLimitZero = !saDstLimit;
|
|
|
|
|
|
|
|
|
|
assert(bLow || bHigh);
|
|
|
|
|
|
|
|
|
|
@@ -1580,7 +1595,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti
|
|
|
|
|
Log(lsINFO) << "doCreditSet: Modifying ripple line: bDelIndex=" << bDelIndex;
|
|
|
|
|
}
|
|
|
|
|
// Line does not exist.
|
|
|
|
|
else if (saLimitAmount.isZero())
|
|
|
|
|
else if (!saLimitAmount)
|
|
|
|
|
{
|
|
|
|
|
Log(lsINFO) << "doCreditSet: Redundant: Setting non-existant ripple line to 0.";
|
|
|
|
|
|
|
|
|
|
@@ -1814,12 +1829,6 @@ void TransactionEngine::calcOfferBridgeNext(
|
|
|
|
|
STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets);
|
|
|
|
|
STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
|
|
|
|
|
if (sleOffer->getIFieldPresent(sfGetsIssuer))
|
|
|
|
|
saOfferPays.setIssuer(sleOffer->getIValueFieldAccount(sfGetsIssuer).getAccountID());
|
|
|
|
|
|
|
|
|
|
if (sleOffer->getIFieldPresent(sfPaysIssuer))
|
|
|
|
|
saOfferGets.setIssuer(sleOffer->getIValueFieldAccount(sfPaysIssuer).getAccountID());
|
|
|
|
|
|
|
|
|
|
if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC())
|
|
|
|
|
{
|
|
|
|
|
// Offer is expired.
|
|
|
|
|
@@ -1915,18 +1924,30 @@ bool TransactionEngine::calcNodeOfferRev(
|
|
|
|
|
const uint160& uNxtIssuerID = pnNxt.uIssuerID;
|
|
|
|
|
const uint160& uNxtAccountID = pnNxt.uAccountID;
|
|
|
|
|
|
|
|
|
|
const STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransferRate(uCurIssuerID), -9);
|
|
|
|
|
const STAmount saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID));
|
|
|
|
|
|
|
|
|
|
uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID);
|
|
|
|
|
const uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip);
|
|
|
|
|
bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip);
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << str(boost::format("calcNodeOfferRev> uIndex=%d prv=%s/%s cur=%s/%s nxt=%s/%s saTransferRate=%s")
|
|
|
|
|
% uIndex
|
|
|
|
|
% STAmount::createHumanCurrency(uPrvCurrencyID)
|
|
|
|
|
% NewcoinAddress::createHumanAccountID(uPrvIssuerID)
|
|
|
|
|
% STAmount::createHumanCurrency(uCurCurrencyID)
|
|
|
|
|
% NewcoinAddress::createHumanAccountID(uCurIssuerID)
|
|
|
|
|
% STAmount::createHumanCurrency(uNxtCurrencyID)
|
|
|
|
|
% NewcoinAddress::createHumanAccountID(uNxtIssuerID)
|
|
|
|
|
% saTransferRate.getText());
|
|
|
|
|
|
|
|
|
|
STAmount& saPrvDlvReq = pnPrv.saRevDeliver; // To be adjusted.
|
|
|
|
|
STAmount saPrvDlvAct;
|
|
|
|
|
|
|
|
|
|
const STAmount& saCurDlvReq = pnCur.saRevDeliver; // Reverse driver.
|
|
|
|
|
STAmount saCurDlvAct;
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString());
|
|
|
|
|
|
|
|
|
|
while (!!uDirectTip // Have a quality.
|
|
|
|
|
&& saCurDlvAct != saCurDlvReq)
|
|
|
|
|
{
|
|
|
|
|
@@ -1934,6 +1955,8 @@ bool TransactionEngine::calcNodeOfferRev(
|
|
|
|
|
if (bAdvance)
|
|
|
|
|
{
|
|
|
|
|
uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd);
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
@@ -1953,16 +1976,12 @@ bool TransactionEngine::calcNodeOfferRev(
|
|
|
|
|
while (saCurDlvReq != saCurDlvAct // Have not met request.
|
|
|
|
|
&& dirNext(uDirectTip, sleDirectDir, uEntry, uCurIndex))
|
|
|
|
|
{
|
|
|
|
|
Log(lsINFO) << str(boost::format("calcNodeOfferRev: uCurIndex=%s") % uCurIndex.ToString());
|
|
|
|
|
|
|
|
|
|
SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex);
|
|
|
|
|
uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID();
|
|
|
|
|
STAmount saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets);
|
|
|
|
|
STAmount saCurOfrIn = sleCurOfr->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
// XXX Move issuer into STAmount
|
|
|
|
|
if (sleCurOfr->getIFieldPresent(sfGetsIssuer))
|
|
|
|
|
saCurOfrOutReq.setIssuer(sleCurOfr->getIValueFieldAccount(sfGetsIssuer).getAccountID());
|
|
|
|
|
|
|
|
|
|
if (sleCurOfr->getIFieldPresent(sfPaysIssuer))
|
|
|
|
|
saCurOfrIn.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID());
|
|
|
|
|
const STAmount& saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets);
|
|
|
|
|
// UNUSED? const STAmount& saCurOfrIn = sleCurOfr->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
|
|
|
|
|
STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left.
|
|
|
|
|
|
|
|
|
|
@@ -2039,10 +2058,7 @@ bool TransactionEngine::calcNodeOfferRev(
|
|
|
|
|
// YYY This could combine offers with the same fee before doing math.
|
|
|
|
|
SLE::pointer sleNxtOfr = entryCache(ltOFFER, uNxtIndex);
|
|
|
|
|
uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID();
|
|
|
|
|
STAmount saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
// XXX Move issuer into STAmount
|
|
|
|
|
if (sleNxtOfr->getIFieldPresent(sfPaysIssuer))
|
|
|
|
|
saNxtOfrIn.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID());
|
|
|
|
|
const STAmount& saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
|
|
|
|
|
STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID
|
|
|
|
|
? saOne
|
|
|
|
|
@@ -2085,6 +2101,11 @@ bool TransactionEngine::calcNodeOfferRev(
|
|
|
|
|
bSuccess = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << str(boost::format("calcNodeOfferRev< uIndex=%d saPrvDlvReq=%s bSuccess=%d")
|
|
|
|
|
% uIndex
|
|
|
|
|
% saPrvDlvReq.getText()
|
|
|
|
|
% bSuccess);
|
|
|
|
|
|
|
|
|
|
return bSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2108,7 +2129,7 @@ bool TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
const uint160& uNxtIssuerID = pnNxt.uIssuerID;
|
|
|
|
|
|
|
|
|
|
const uint160& uNxtAccountID = pnNxt.uAccountID;
|
|
|
|
|
const STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransferRate(uCurIssuerID), -9);
|
|
|
|
|
const STAmount saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID));
|
|
|
|
|
|
|
|
|
|
uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID);
|
|
|
|
|
const uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip);
|
|
|
|
|
@@ -2147,18 +2168,11 @@ bool TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
{
|
|
|
|
|
SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex);
|
|
|
|
|
uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID();
|
|
|
|
|
STAmount saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets);
|
|
|
|
|
STAmount saCurOfrInReq = sleCurOfr->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
// XXX Move issuer into STAmount
|
|
|
|
|
if (sleCurOfr->getIFieldPresent(sfGetsIssuer))
|
|
|
|
|
saCurOfrOutReq.setIssuer(sleCurOfr->getIValueFieldAccount(sfGetsIssuer).getAccountID());
|
|
|
|
|
|
|
|
|
|
if (sleCurOfr->getIFieldPresent(sfPaysIssuer))
|
|
|
|
|
saCurOfrInReq.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID());
|
|
|
|
|
const STAmount& saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets);
|
|
|
|
|
const STAmount& saCurOfrInReq = sleCurOfr->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
STAmount saCurOfrInAct;
|
|
|
|
|
STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left.
|
|
|
|
|
|
|
|
|
|
saCurOfrInReq = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct);
|
|
|
|
|
STAmount saCurOfrInMax = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct);
|
|
|
|
|
|
|
|
|
|
if (!!uNxtAccountID)
|
|
|
|
|
{
|
|
|
|
|
@@ -2166,10 +2180,10 @@ bool TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
|
|
|
|
|
const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtAccountID == uCurIssuerID
|
|
|
|
|
? saOne
|
|
|
|
|
: saTransferRate;
|
|
|
|
|
: saTransferRate;
|
|
|
|
|
const bool bFee = saFeeRate != saOne;
|
|
|
|
|
|
|
|
|
|
const STAmount saOutPass = STAmount::divide(saCurOfrInReq, saOfrRate, uCurCurrencyID);
|
|
|
|
|
const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID);
|
|
|
|
|
const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed.
|
|
|
|
|
const STAmount saOutCost = MIN(
|
|
|
|
|
bFee
|
|
|
|
|
@@ -2219,17 +2233,14 @@ bool TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
// YYY This could combine offers with the same fee before doing math.
|
|
|
|
|
SLE::pointer sleNxtOfr = entryCache(ltOFFER, uNxtIndex);
|
|
|
|
|
const uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID();
|
|
|
|
|
STAmount saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
// XXX Move issuer into STAmount
|
|
|
|
|
if (sleNxtOfr->getIFieldPresent(sfPaysIssuer))
|
|
|
|
|
saNxtOfrIn.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID());
|
|
|
|
|
const STAmount& saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
|
|
|
|
|
const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID
|
|
|
|
|
? saOne
|
|
|
|
|
: saTransferRate;
|
|
|
|
|
const bool bFee = saFeeRate != saOne;
|
|
|
|
|
|
|
|
|
|
const STAmount saInBase = saCurOfrInReq-saCurOfrInAct;
|
|
|
|
|
const STAmount saInBase = saCurOfrInMax-saCurOfrInAct;
|
|
|
|
|
const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID);
|
|
|
|
|
STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed.
|
|
|
|
|
saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer.
|
|
|
|
|
@@ -2601,8 +2612,8 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
|
|
|
|
|
const bool bPrvAccount = !uIndex || !!(pnPrv.uFlags & STPathElement::typeAccount);
|
|
|
|
|
const bool bNxtAccount = uIndex == uLast || !!(pnNxt.uFlags & STPathElement::typeAccount);
|
|
|
|
|
|
|
|
|
|
const uint160& uPrvAccountID = pnPrv.uAccountID;
|
|
|
|
|
const uint160& uCurAccountID = pnCur.uAccountID;
|
|
|
|
|
const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID;
|
|
|
|
|
const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue.
|
|
|
|
|
|
|
|
|
|
const uint160& uCurrencyID = pnCur.uCurrencyID;
|
|
|
|
|
@@ -2614,6 +2625,18 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
|
|
|
|
|
const STAmount saPrvBalance = uIndex && bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID);
|
|
|
|
|
const STAmount saPrvLimit = uIndex && bPrvAccount ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID);
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << str(boost::format("calcNodeAccountRev> uIndex=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvBalance=%s saPrvLimit=%s")
|
|
|
|
|
% uIndex
|
|
|
|
|
% uLast
|
|
|
|
|
% NewcoinAddress::createHumanAccountID(uPrvAccountID)
|
|
|
|
|
% NewcoinAddress::createHumanAccountID(uCurAccountID)
|
|
|
|
|
% NewcoinAddress::createHumanAccountID(uNxtAccountID)
|
|
|
|
|
% STAmount::createHumanCurrency(uCurrencyID)
|
|
|
|
|
% uQualityIn
|
|
|
|
|
% uQualityOut
|
|
|
|
|
% saPrvBalance.getText()
|
|
|
|
|
% saPrvLimit.getText());
|
|
|
|
|
|
|
|
|
|
const STAmount saPrvRedeemReq = bPrvRedeem && saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0);
|
|
|
|
|
STAmount& saPrvRedeemAct = pnPrv.saRevRedeem;
|
|
|
|
|
|
|
|
|
|
@@ -2621,7 +2644,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
|
|
|
|
|
STAmount& saPrvIssueAct = pnPrv.saRevIssue;
|
|
|
|
|
|
|
|
|
|
// For !bPrvAccount
|
|
|
|
|
const STAmount saPrvDeliverReq = STAmount(uCurrencyID, -1); // Unlimited.
|
|
|
|
|
const STAmount saPrvDeliverReq = STAmount::saFromSigned(uCurrencyID, -1); // Unlimited.
|
|
|
|
|
STAmount& saPrvDeliverAct = pnPrv.saRevDeliver;
|
|
|
|
|
|
|
|
|
|
// For bNxtAccount
|
|
|
|
|
@@ -2629,20 +2652,18 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point
|
|
|
|
|
STAmount saCurRedeemAct(saCurRedeemReq.getCurrency());
|
|
|
|
|
|
|
|
|
|
const STAmount& saCurIssueReq = pnCur.saRevIssue;
|
|
|
|
|
STAmount saCurIssueAct(saCurIssueReq.getCurrency()); // Track progress.
|
|
|
|
|
STAmount saCurIssueAct(saCurIssueReq.getCurrency()); // Track progress.
|
|
|
|
|
|
|
|
|
|
// For !bNxtAccount
|
|
|
|
|
const STAmount& saCurDeliverReq = pnCur.saRevDeliver;
|
|
|
|
|
STAmount saCurDeliverAct(saCurDeliverReq.getCurrency());
|
|
|
|
|
|
|
|
|
|
// For uIndex == uLast
|
|
|
|
|
const STAmount& saCurWantedReq = pspCur->saOutReq; // XXX Credit limits?
|
|
|
|
|
const STAmount& saCurWantedReq = pspCur->saOutReq; // XXX Credit limits?
|
|
|
|
|
// STAmount saPrvDeliverReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit;
|
|
|
|
|
STAmount saCurWantedAct(saCurWantedReq.getCurrency());
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << str(boost::format("calcNodeAccountRev> uIndex=%d/%d saPrvRedeemReq=%s/%s saPrvIssueReq=%s/%s saCurWantedReq=%s/%s")
|
|
|
|
|
% uIndex
|
|
|
|
|
% uLast
|
|
|
|
|
Log(lsINFO) << str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s/%s saPrvIssueReq=%s/%s saCurWantedReq=%s/%s")
|
|
|
|
|
% saPrvRedeemReq.getText()
|
|
|
|
|
% saPrvRedeemReq.getHumanCurrency()
|
|
|
|
|
% saPrvIssueReq.getText()
|
|
|
|
|
@@ -3188,7 +3209,8 @@ bool PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssu
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
bValid = pushNode(
|
|
|
|
|
0, // Offer
|
|
|
|
|
STPathElement::typeCurrency // Offer.
|
|
|
|
|
| STPathElement::typeIssuer,
|
|
|
|
|
ACCOUNT_ONE, // Placeholder for offers.
|
|
|
|
|
uCurrencyID, // The offer's output is what is now wanted.
|
|
|
|
|
uIssuerID);
|
|
|
|
|
@@ -3417,14 +3439,21 @@ PathState::PathState(
|
|
|
|
|
bValid = pushNode(
|
|
|
|
|
STPathElement::typeAccount // Last node is always an account.
|
|
|
|
|
| STPathElement::typeRedeem // Does not matter just pass error check.
|
|
|
|
|
| STPathElement::typeIssue, // Does not matter just pass error check.
|
|
|
|
|
| STPathElement::typeIssue // Does not matter just pass error check.
|
|
|
|
|
| STPathElement::typeCurrency
|
|
|
|
|
| STPathElement::typeIssuer,
|
|
|
|
|
uReceiverID, // Receive to output
|
|
|
|
|
uOutCurrencyID, // Desired currency
|
|
|
|
|
uOutIssuerID);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << "PathState: " << getJson();
|
|
|
|
|
Log(lsINFO) << str(boost::format("PathState: in=%s/%s out=%s/%s %s")
|
|
|
|
|
% STAmount::createHumanCurrency(uInCurrencyID)
|
|
|
|
|
% NewcoinAddress::createHumanAccountID(uInIssuerID)
|
|
|
|
|
% STAmount::createHumanCurrency(uOutCurrencyID)
|
|
|
|
|
% NewcoinAddress::createHumanAccountID(uOutIssuerID)
|
|
|
|
|
% getJson());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Json::Value PathState::getJson() const
|
|
|
|
|
@@ -3517,6 +3546,8 @@ bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur,
|
|
|
|
|
const bool bCurAccount = !!(pnCur.uFlags & STPathElement::typeAccount);
|
|
|
|
|
bool bValid;
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << str(boost::format("calcNode> uIndex=%d") % uIndex);
|
|
|
|
|
|
|
|
|
|
// Do current node reverse.
|
|
|
|
|
bValid = bCurAccount
|
|
|
|
|
? calcNodeAccountRev(uIndex, pspCur, bMultiQuality)
|
|
|
|
|
@@ -3536,6 +3567,8 @@ bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur,
|
|
|
|
|
: calcNodeOfferFwd(uIndex, pspCur, bMultiQuality);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << str(boost::format("calcNode< uIndex=%d bValid=%d") % uIndex % bValid);
|
|
|
|
|
|
|
|
|
|
return bValid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -3553,14 +3586,14 @@ void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths)
|
|
|
|
|
|
|
|
|
|
assert(pspCur->vpnNodes.size() >= 2);
|
|
|
|
|
|
|
|
|
|
bool bValid = calcNode(uLast, pspCur, iPaths == 1);
|
|
|
|
|
pspCur->bValid = calcNode(uLast, pspCur, iPaths == 1);
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << "pathNext: bValid="
|
|
|
|
|
<< bValid
|
|
|
|
|
<< pspCur->bValid
|
|
|
|
|
<< " saOutAct=" << pspCur->saOutAct.getText()
|
|
|
|
|
<< " saInAct=" << pspCur->saInAct.getText();
|
|
|
|
|
|
|
|
|
|
pspCur->uQuality = bValid
|
|
|
|
|
pspCur->uQuality = pspCur->bValid
|
|
|
|
|
? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality.
|
|
|
|
|
: 0; // Mark path as inactive.
|
|
|
|
|
|
|
|
|
|
@@ -3614,7 +3647,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction
|
|
|
|
|
return tenINVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID));
|
|
|
|
|
SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID));
|
|
|
|
|
if (!sleDst)
|
|
|
|
|
{
|
|
|
|
|
// Destination account does not exist.
|
|
|
|
|
@@ -3644,7 +3677,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXX Should bMax be sufficient to imply ripple?
|
|
|
|
|
bool bRipple = bPaths || bMax || !saDstAmount.isNative();
|
|
|
|
|
bool bRipple = bPaths || bMax || !saDstAmount.isNative();
|
|
|
|
|
|
|
|
|
|
if (!bRipple)
|
|
|
|
|
{
|
|
|
|
|
@@ -3714,7 +3747,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction
|
|
|
|
|
return terOVER_LIMIT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (saDstBalance.isZero())
|
|
|
|
|
if (!saDstBalance)
|
|
|
|
|
{
|
|
|
|
|
// XXX May be able to delete indexes for credit limits which are zero.
|
|
|
|
|
nothing();
|
|
|
|
|
@@ -3858,7 +3891,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction
|
|
|
|
|
// Partial payment not allowed.
|
|
|
|
|
terResult = terPATH_PARTIAL; // XXX No effect, except unfunded and charge fee.
|
|
|
|
|
}
|
|
|
|
|
else if (saPaid.isZero())
|
|
|
|
|
else if (!saPaid)
|
|
|
|
|
{
|
|
|
|
|
// Nothing claimed.
|
|
|
|
|
terResult = terPATH_EMPTY; // XXX No effect except unfundeds and charge fee.
|
|
|
|
|
@@ -3964,7 +3997,7 @@ TransactionEngineResult TransactionEngine::takeOffers(
|
|
|
|
|
STAmount& saTakerPaid,
|
|
|
|
|
STAmount& saTakerGot)
|
|
|
|
|
{
|
|
|
|
|
assert(!saTakerPays.isZero() && !saTakerGets.isZero());
|
|
|
|
|
assert(!!saTakerPays && !!saTakerGets);
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << "takeOffers: against book: " << uBookBase.ToString();
|
|
|
|
|
|
|
|
|
|
@@ -4033,12 +4066,6 @@ TransactionEngineResult TransactionEngine::takeOffers(
|
|
|
|
|
STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets);
|
|
|
|
|
STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
|
|
|
|
|
if (sleOffer->getIFieldPresent(sfGetsIssuer))
|
|
|
|
|
saOfferPays.setIssuer(sleOffer->getIValueFieldAccount(sfGetsIssuer).getAccountID());
|
|
|
|
|
|
|
|
|
|
if (sleOffer->getIFieldPresent(sfPaysIssuer))
|
|
|
|
|
saOfferGets.setIssuer(sleOffer->getIValueFieldAccount(sfPaysIssuer).getAccountID());
|
|
|
|
|
|
|
|
|
|
if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC())
|
|
|
|
|
{
|
|
|
|
|
// Offer is expired. Delete it.
|
|
|
|
|
@@ -4152,14 +4179,12 @@ TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransac
|
|
|
|
|
Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0);
|
|
|
|
|
const uint32 txFlags = txn.getFlags();
|
|
|
|
|
const bool bPassive = !!(txFlags & tfPassive);
|
|
|
|
|
const uint160 uPaysIssuerID = txn.getITFieldAccount(sfPaysIssuer);
|
|
|
|
|
const uint160 uGetsIssuerID = txn.getITFieldAccount(sfGetsIssuer);
|
|
|
|
|
STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays);
|
|
|
|
|
saTakerPays.setIssuer(uPaysIssuerID);
|
|
|
|
|
Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText();
|
|
|
|
|
STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays);
|
|
|
|
|
STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets);
|
|
|
|
|
saTakerGets.setIssuer(uGetsIssuerID);
|
|
|
|
|
Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText();
|
|
|
|
|
Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText();
|
|
|
|
|
const uint160 uPaysIssuerID = saTakerPays.getIssuer();
|
|
|
|
|
const uint160 uGetsIssuerID = saTakerGets.getIssuer();
|
|
|
|
|
const uint32 uExpiration = txn.getITFieldU32(sfExpiration);
|
|
|
|
|
const bool bHaveExpiration = txn.getITFieldPresent(sfExpiration);
|
|
|
|
|
const uint32 uSequence = txn.getSequence();
|
|
|
|
|
@@ -4196,7 +4221,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText();
|
|
|
|
|
|
|
|
|
|
terResult = tenBAD_OFFER;
|
|
|
|
|
}
|
|
|
|
|
else if (saTakerPays.isZero() || saTakerGets.isZero())
|
|
|
|
|
else if (!saTakerPays || !saTakerGets)
|
|
|
|
|
{
|
|
|
|
|
Log(lsWARNING) << "doOfferCreate: Malformed offer: bad amount";
|
|
|
|
|
|
|
|
|
|
@@ -4208,7 +4233,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText();
|
|
|
|
|
|
|
|
|
|
terResult = tenREDUNDANT;
|
|
|
|
|
}
|
|
|
|
|
else if (saTakerPays.isNative() != uPaysIssuerID.isZero() || saTakerGets.isNative() != uGetsIssuerID.isZero())
|
|
|
|
|
else if (saTakerPays.isNative() != !uPaysIssuerID || saTakerGets.isNative() != !uGetsIssuerID)
|
|
|
|
|
{
|
|
|
|
|
Log(lsWARNING) << "doOfferCreate: Malformed offer: bad issuer";
|
|
|
|
|
|
|
|
|
|
@@ -4281,8 +4306,8 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText();
|
|
|
|
|
// Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID);
|
|
|
|
|
|
|
|
|
|
if (terSUCCESS == terResult
|
|
|
|
|
&& !saTakerPays.isZero() // Still wanting something.
|
|
|
|
|
&& !saTakerGets.isZero() // Still offering something.
|
|
|
|
|
&& !!saTakerPays // Still wanting something.
|
|
|
|
|
&& !!saTakerGets // Still offering something.
|
|
|
|
|
&& accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded.
|
|
|
|
|
{
|
|
|
|
|
// We need to place the remainder of the offer into its order book.
|
|
|
|
|
@@ -4324,12 +4349,6 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText();
|
|
|
|
|
sleOffer->setIFieldU64(sfOwnerNode, uOwnerNode);
|
|
|
|
|
sleOffer->setIFieldU64(sfBookNode, uBookNode);
|
|
|
|
|
|
|
|
|
|
if (!saTakerPays.isNative())
|
|
|
|
|
sleOffer->setIFieldAccount(sfPaysIssuer, uPaysIssuerID);
|
|
|
|
|
|
|
|
|
|
if (!saTakerGets.isNative())
|
|
|
|
|
sleOffer->setIFieldAccount(sfGetsIssuer, uGetsIssuerID);
|
|
|
|
|
|
|
|
|
|
if (uExpiration)
|
|
|
|
|
sleOffer->setIFieldU32(sfExpiration, uExpiration);
|
|
|
|
|
|
|
|
|
|
|