|
|
|
|
@@ -266,7 +266,7 @@ STAmount TransactionEngine::accountHolds(const uint160& uAccountID, const uint16
|
|
|
|
|
// Use when you need a default for rippling uAccountID's currency.
|
|
|
|
|
// --> saDefault/currency/issuer
|
|
|
|
|
// <-- saFunds: Funds available. May be negative.
|
|
|
|
|
// If the issuer is the same as uAccountID, result is Default.
|
|
|
|
|
// If the issuer is the same as uAccountID, funds are unlimited, use result is saDefault.
|
|
|
|
|
STAmount TransactionEngine::accountFunds(const uint160& uAccountID, const STAmount& saDefault)
|
|
|
|
|
{
|
|
|
|
|
STAmount saFunds;
|
|
|
|
|
@@ -861,7 +861,9 @@ SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint25
|
|
|
|
|
mNodes.entryCache(sleEntry);
|
|
|
|
|
}
|
|
|
|
|
else if (action == taaDELETE)
|
|
|
|
|
{
|
|
|
|
|
assert(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sleEntry;
|
|
|
|
|
@@ -1321,13 +1323,13 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn,
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << "applyTransaction: terResult=" << strToken << " : " << terResult << " : " << strHuman;
|
|
|
|
|
|
|
|
|
|
if (terResult >= tepPATH_PARTIAL && isSetBit(params, tapRETRY))
|
|
|
|
|
if (isTepPartial(terResult) && isSetBit(params, tapRETRY))
|
|
|
|
|
{
|
|
|
|
|
// Partial result and allowed to retry, reclassify as a retry.
|
|
|
|
|
terResult = terRETRY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tesSUCCESS == terResult || terResult >= tepPATH_PARTIAL)
|
|
|
|
|
if (tesSUCCESS == terResult || isTepPartial(terResult))
|
|
|
|
|
{
|
|
|
|
|
// Transaction succeeded fully or (retries are not allowed and the transaction succeeded partially).
|
|
|
|
|
txnWrite();
|
|
|
|
|
@@ -1348,8 +1350,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn,
|
|
|
|
|
musUnfundedFound.clear();
|
|
|
|
|
|
|
|
|
|
if (!isSetBit(params, tapOPEN_LEDGER)
|
|
|
|
|
&& ((terResult >= temMALFORMED && terResult <= tefFAILURE)
|
|
|
|
|
|| ((terResult >= tefFAILURE && terResult <= terRETRY))))
|
|
|
|
|
&& (isTemMalformed(terResult) || isTefFailure(terResult)))
|
|
|
|
|
{
|
|
|
|
|
// XXX Malformed or failed transaction in closed ledger must bow out.
|
|
|
|
|
}
|
|
|
|
|
@@ -1968,8 +1969,7 @@ TER TransactionEngine::calcNodeOfferRev(
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString());
|
|
|
|
|
|
|
|
|
|
while (!!uDirectTip // Have a quality.
|
|
|
|
|
&& saCurDlvAct != saCurDlvReq)
|
|
|
|
|
while (!!uDirectTip && saCurDlvAct != saCurDlvReq) // Have a quality and not done.
|
|
|
|
|
{
|
|
|
|
|
// Get next quality.
|
|
|
|
|
if (bAdvance)
|
|
|
|
|
@@ -2033,7 +2033,7 @@ TER TransactionEngine::calcNodeOfferRev(
|
|
|
|
|
curIssuerNodeConstIterator itSourcePast = mumSource.find(asLine);
|
|
|
|
|
bool bFoundPast = itSourcePast != mumSource.end();
|
|
|
|
|
|
|
|
|
|
if (!saCurOfrFunds)
|
|
|
|
|
if (!saCurOfrFunds.isPositive())
|
|
|
|
|
{
|
|
|
|
|
// Offer is unfunded.
|
|
|
|
|
Log(lsINFO) << "calcNodeOfferRev: encountered unfunded offer";
|
|
|
|
|
@@ -2048,11 +2048,6 @@ TER TransactionEngine::calcNodeOfferRev(
|
|
|
|
|
// Never mentioned before: found unfunded.
|
|
|
|
|
musUnfundedFound.insert(uOfferIndex); // Mark offer for always deletion.
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Mentioned before: source became unfunded.
|
|
|
|
|
pspCur->vUnfundedBecame.push_back(uOfferIndex); // Mark offer for deletion on use of current path state.
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2069,8 +2064,8 @@ TER TransactionEngine::calcNodeOfferRev(
|
|
|
|
|
: saTransferRate;
|
|
|
|
|
bool bFee = saFeeRate != saOne;
|
|
|
|
|
|
|
|
|
|
STAmount saOutBase = MIN(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed.
|
|
|
|
|
STAmount saOutCost = MIN(
|
|
|
|
|
STAmount saOutBase = std::min(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed.
|
|
|
|
|
STAmount saOutCost = std::min(
|
|
|
|
|
bFee
|
|
|
|
|
? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID)
|
|
|
|
|
: saOutBase,
|
|
|
|
|
@@ -2113,7 +2108,7 @@ TER TransactionEngine::calcNodeOfferRev(
|
|
|
|
|
// Although the fee varies based upon the next offer it does not matter as the offer maker knows in
|
|
|
|
|
// advance that they are obligated to pay a transfer fee of necessary. The owner of next offer has no
|
|
|
|
|
// expectation of a quality in being applied.
|
|
|
|
|
SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip);
|
|
|
|
|
SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip);
|
|
|
|
|
// ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip), uCurCurrencyID); // For correct ratio
|
|
|
|
|
unsigned int uEntry = 0;
|
|
|
|
|
uint256 uNxtIndex;
|
|
|
|
|
@@ -2149,9 +2144,9 @@ TER TransactionEngine::calcNodeOfferRev(
|
|
|
|
|
: saTransferRate;
|
|
|
|
|
bool bFee = saFeeRate != saOne;
|
|
|
|
|
|
|
|
|
|
STAmount saOutBase = MIN(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed.
|
|
|
|
|
saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer.
|
|
|
|
|
STAmount saOutCost = MIN(
|
|
|
|
|
STAmount saOutBase = std::min(saCurOfrOutReq, saCurDlvReq-saCurDlvAct);// Limit offer out by needed.
|
|
|
|
|
saOutBase = std::min(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer.
|
|
|
|
|
STAmount saOutCost = std::min(
|
|
|
|
|
bFee
|
|
|
|
|
? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID)
|
|
|
|
|
: saOutBase,
|
|
|
|
|
@@ -2204,6 +2199,12 @@ TER TransactionEngine::calcNodeOfferRev(
|
|
|
|
|
return terResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// - Offer input is limbo.
|
|
|
|
|
// - Current offers consumed.
|
|
|
|
|
// - Current offer owners debited.
|
|
|
|
|
// - Transfer fees credited to issuer.
|
|
|
|
|
// - Payout to issuer or limbo.
|
|
|
|
|
// - Deliver is set without transfer fees.
|
|
|
|
|
TER TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
const unsigned int uIndex, // 0 < uIndex < uLast
|
|
|
|
|
const PathState::pointer& pspCur,
|
|
|
|
|
@@ -2211,7 +2212,7 @@ TER TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
TER terResult = tepPATH_DRY;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
paymentNode& pnPrv = pspCur->vpnNodes[uIndex-1];
|
|
|
|
|
paymentNode& pnCur = pspCur->vpnNodes[uIndex];
|
|
|
|
|
paymentNode& pnNxt = pspCur->vpnNodes[uIndex+1];
|
|
|
|
|
@@ -2223,7 +2224,7 @@ TER TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
const uint160& uNxtCurrencyID = pnNxt.uCurrencyID;
|
|
|
|
|
const uint160& uNxtIssuerID = pnNxt.uIssuerID;
|
|
|
|
|
|
|
|
|
|
// const uint160& uPrvAccountID = pnPrv.uAccountID;
|
|
|
|
|
const uint160& uPrvAccountID = pnPrv.uAccountID;
|
|
|
|
|
const uint160& uNxtAccountID = pnNxt.uAccountID;
|
|
|
|
|
const STAmount saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID));
|
|
|
|
|
|
|
|
|
|
@@ -2234,15 +2235,42 @@ TER TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
const STAmount& saPrvDlvReq = pnPrv.saFwdDeliver; // Forward driver.
|
|
|
|
|
STAmount saPrvDlvAct;
|
|
|
|
|
|
|
|
|
|
STAmount& saCurDlvReq = pnCur.saFwdDeliver;
|
|
|
|
|
STAmount saCurDlvAct;
|
|
|
|
|
STAmount& saCurDlvAct = pnCur.saFwdDeliver; // How much current node will deliver.
|
|
|
|
|
saCurDlvAct = 0;
|
|
|
|
|
|
|
|
|
|
while (!!uDirectTip // Have a quality.
|
|
|
|
|
&& saPrvDlvAct != saPrvDlvReq)
|
|
|
|
|
bool bNxtOffer = !uNxtAccountID;
|
|
|
|
|
uint256 uNxtTip;
|
|
|
|
|
uint256 uNxtEnd;
|
|
|
|
|
SLE::pointer sleNxtDir;
|
|
|
|
|
bool bNxtDirAdvance;
|
|
|
|
|
bool bNxtEntryDirty;
|
|
|
|
|
bool bNxtEntryAdvance;
|
|
|
|
|
unsigned int uNxtEntry; // Next nodes index.
|
|
|
|
|
uint256 uNxtIndex; // Next offer.
|
|
|
|
|
boost::unordered_map<uint160, STAmount> umNxtBalance; // Account valances.
|
|
|
|
|
STAmount saNxtOfrFunds;
|
|
|
|
|
STAmount saNxtOfrIn;
|
|
|
|
|
STAmount saNxtOfrOut;
|
|
|
|
|
SLE::pointer sleNxtOfr;
|
|
|
|
|
uint160 uNxtOfrAccountID;
|
|
|
|
|
STAmount saNxtFeeRate;
|
|
|
|
|
bool bNxtFee;
|
|
|
|
|
|
|
|
|
|
if (bNxtOffer)
|
|
|
|
|
{
|
|
|
|
|
uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID);
|
|
|
|
|
uNxtEnd = Ledger::getQualityNext(uNxtTip);
|
|
|
|
|
sleNxtDir = entryCache(ltDIR_NODE, uNxtTip);
|
|
|
|
|
bNxtDirAdvance = !sleNxtDir;
|
|
|
|
|
uNxtEntry = 0;
|
|
|
|
|
bNxtEntryAdvance = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (!!uDirectTip && saPrvDlvAct != saPrvDlvReq) // Have a quality and not done.
|
|
|
|
|
{
|
|
|
|
|
// Get next quality.
|
|
|
|
|
if (bAdvance)
|
|
|
|
|
{
|
|
|
|
|
// Get next quality.
|
|
|
|
|
uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
@@ -2278,8 +2306,8 @@ TER TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allowed to access source from this node?
|
|
|
|
|
curIssuerNodeConstIterator itAllow = pspCur->umForward.find(asLine);
|
|
|
|
|
bool bFoundForward = itAllow != pspCur->umForward.end();
|
|
|
|
|
curIssuerNodeConstIterator itAllow = pspCur->umForward.find(asLine);
|
|
|
|
|
const bool bFoundForward = itAllow != pspCur->umForward.end();
|
|
|
|
|
|
|
|
|
|
if (bFoundForward || itAllow->second != uIndex)
|
|
|
|
|
{
|
|
|
|
|
@@ -2290,13 +2318,11 @@ TER TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const STAmount& saCurOfrOutReq = sleOffer->getIValueFieldAmount(sfTakerGets);
|
|
|
|
|
const STAmount& saCurOfrInReq = sleOffer->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
STAmount saCurOfrInAct;
|
|
|
|
|
const STAmount saCurOfrOutReq = sleOffer->getIValueFieldAmount(sfTakerGets);
|
|
|
|
|
STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left.
|
|
|
|
|
STAmount saCurOfrInMax = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct);
|
|
|
|
|
STAmount saCurOfrSpent;
|
|
|
|
|
|
|
|
|
|
if (!saCurOfrFunds)
|
|
|
|
|
if (!saCurOfrFunds.isPositive())
|
|
|
|
|
{
|
|
|
|
|
// Offer is unfunded.
|
|
|
|
|
Log(lsINFO) << "calcNodeOfferFwd: unfunded offer";
|
|
|
|
|
@@ -2306,6 +2332,11 @@ TER TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const STAmount saCurOfrInReq = sleOffer->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
STAmount saCurOfrInMax = std::min(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct);
|
|
|
|
|
STAmount saCurOfrInAct;
|
|
|
|
|
STAmount saCurOfrOutAct;
|
|
|
|
|
|
|
|
|
|
if (!!uNxtAccountID)
|
|
|
|
|
{
|
|
|
|
|
// Next is an account node.
|
|
|
|
|
@@ -2320,103 +2351,188 @@ TER TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
const bool bFee = saFeeRate != saOne;
|
|
|
|
|
|
|
|
|
|
const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID, uCurIssuerID);
|
|
|
|
|
const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed.
|
|
|
|
|
const STAmount saOutBase = std::min(saCurOfrOutReq, saOutPass); // Limit offer out by needed.
|
|
|
|
|
const STAmount saOutCostRaw= bFee
|
|
|
|
|
? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID)
|
|
|
|
|
: saOutBase;
|
|
|
|
|
const STAmount saOutCost = MIN(saOutCostRaw, saCurOfrFunds); // Limit cost by fees & funds.
|
|
|
|
|
const STAmount saOutDlvAct = bFee
|
|
|
|
|
? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID)
|
|
|
|
|
: saOutCost; // Out amount after fees.
|
|
|
|
|
const STAmount saOutCost = std::min(saOutCostRaw, saCurOfrFunds); // Limit cost by fees & funds.
|
|
|
|
|
|
|
|
|
|
saCurOfrSpent = saOutCost; // XXX Check.
|
|
|
|
|
saCurOfrOutAct = bFee
|
|
|
|
|
? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID)
|
|
|
|
|
: saOutCost; // Out amount after fees.
|
|
|
|
|
|
|
|
|
|
// Compute input w/o fees required.
|
|
|
|
|
const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uPrvIssuerID);
|
|
|
|
|
saCurOfrInAct = STAmount::multiply(saCurOfrOutAct, saOfrRate, uPrvCurrencyID, uPrvIssuerID);
|
|
|
|
|
|
|
|
|
|
// Deliver to output.
|
|
|
|
|
accountSend(uCurOfrAccountID, uNxtAccountID, saOutDlvAct);
|
|
|
|
|
|
|
|
|
|
saCurDlvAct += saOutDlvAct; // Portion of driver served.
|
|
|
|
|
accountSend(uCurOfrAccountID, uNxtAccountID, saCurOfrOutAct);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Next is an offer node.
|
|
|
|
|
// Need to step through next offer's nodes to figure out fees.
|
|
|
|
|
STAmount saNxtOfrRate;
|
|
|
|
|
bool bDirectoryFirst = true;
|
|
|
|
|
|
|
|
|
|
uint256 uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID);
|
|
|
|
|
const uint256 uNxtEnd = Ledger::getQualityNext(uNxtTip);
|
|
|
|
|
bool bNxtAdvance = !entryCache(ltDIR_NODE, uNxtTip);
|
|
|
|
|
|
|
|
|
|
while (!!uNxtTip // Have a quality.
|
|
|
|
|
&& saPrvDlvAct != saPrvDlvReq) // Have more to do.
|
|
|
|
|
while (!!uNxtTip && saCurOfrInAct != saCurOfrInMax) // A next offer may be available and have more to do.
|
|
|
|
|
{
|
|
|
|
|
if (bNxtAdvance)
|
|
|
|
|
if (!bNxtDirAdvance)
|
|
|
|
|
{
|
|
|
|
|
uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd);
|
|
|
|
|
// Current directory is fine.
|
|
|
|
|
nothing();
|
|
|
|
|
}
|
|
|
|
|
else if (bDirectoryFirst || bMultiQuality)
|
|
|
|
|
{
|
|
|
|
|
if (bDirectoryFirst)
|
|
|
|
|
bDirectoryFirst = false;
|
|
|
|
|
|
|
|
|
|
uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd);
|
|
|
|
|
if (!!uNxtTip)
|
|
|
|
|
{
|
|
|
|
|
saNxtOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip)); // For correct ratio
|
|
|
|
|
sleNxtDir = entryCache(ltDIR_NODE, uNxtTip);
|
|
|
|
|
|
|
|
|
|
assert(!!sleNxtDir);
|
|
|
|
|
|
|
|
|
|
bNxtDirAdvance = false;
|
|
|
|
|
uNxtEntry = 0;
|
|
|
|
|
bNxtEntryAdvance = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// No more next offers. Should be done rather than fall off end of book.
|
|
|
|
|
Log(lsINFO) << "Unreachable.";
|
|
|
|
|
assert(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bNxtAdvance = true;
|
|
|
|
|
// Don't do another directory.
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!!uNxtTip)
|
|
|
|
|
if (!bNxtEntryAdvance)
|
|
|
|
|
{
|
|
|
|
|
// Do a directory.
|
|
|
|
|
// - Drive on computing saCurDlvAct to derive saPrvDlvAct.
|
|
|
|
|
SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip);
|
|
|
|
|
// ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip)); // For correct ratio
|
|
|
|
|
unsigned int uEntry = 0;
|
|
|
|
|
uint256 uNxtIndex;
|
|
|
|
|
|
|
|
|
|
while (saPrvDlvReq != saPrvDlvAct // Have not met request.
|
|
|
|
|
&& dirNext(uNxtTip, sleNxtDir, uEntry, uNxtIndex))
|
|
|
|
|
{
|
|
|
|
|
// 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();
|
|
|
|
|
const STAmount& saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
|
|
|
|
|
const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID
|
|
|
|
|
? saOne
|
|
|
|
|
: saTransferRate;
|
|
|
|
|
const bool bFee = saFeeRate != saOne;
|
|
|
|
|
|
|
|
|
|
// XXX Skip expireds and unfundeds.
|
|
|
|
|
const STAmount saInBase = saCurOfrInMax-saCurOfrInAct;
|
|
|
|
|
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, uCurIssuerID)
|
|
|
|
|
: saOutBase,
|
|
|
|
|
saCurOfrFunds); // Limit cost by fees & funds.
|
|
|
|
|
const STAmount saOutDlvAct = bFee
|
|
|
|
|
? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID)
|
|
|
|
|
: saOutCost; // Out amount after fees.
|
|
|
|
|
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.
|
|
|
|
|
saCurDlvAct += saInDlvAct; // Portion of driver served.
|
|
|
|
|
}
|
|
|
|
|
// Current next directory is fine.
|
|
|
|
|
nothing();
|
|
|
|
|
}
|
|
|
|
|
else if (dirNext(uNxtTip, sleNxtDir, uEntry, uNxtIndex))
|
|
|
|
|
{
|
|
|
|
|
// Found a next uNxtIndex.
|
|
|
|
|
bNxtEntryAdvance = false;
|
|
|
|
|
bNxtEntryDirty = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// No more offers in nxt directory.
|
|
|
|
|
bNxtDirAdvance = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Do another nxt directory iff bMultiQuality
|
|
|
|
|
if (!bMultiQuality)
|
|
|
|
|
uNxtTip = 0;
|
|
|
|
|
if (bNxtEntryDirty)
|
|
|
|
|
{
|
|
|
|
|
sleNxtOfr = entryCache(ltOFFER, uNxtIndex);
|
|
|
|
|
|
|
|
|
|
if (sleNxtOfr->getIFieldPresent(sfExpiration)
|
|
|
|
|
&& sleNxtOfr->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC())
|
|
|
|
|
{
|
|
|
|
|
// Offer is expired.
|
|
|
|
|
bNxtEntryAdvance = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID();
|
|
|
|
|
|
|
|
|
|
saNxtFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID
|
|
|
|
|
? saOne
|
|
|
|
|
: saTransferRate;
|
|
|
|
|
|
|
|
|
|
bNxtFee = saNxtFeeRate != saOne;
|
|
|
|
|
|
|
|
|
|
boost::unordered_map<uint160, STAmount>::const_iterator itNxtBalance = umNxtBalance.find(uNxtOfrAccountID);
|
|
|
|
|
saNxtOfrFunds = itNxtBalance == umNxtBalance.end()
|
|
|
|
|
? accountFunds(uNxtOfrAccountID, saNxtOfrOut)
|
|
|
|
|
: it->second;
|
|
|
|
|
|
|
|
|
|
saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays);
|
|
|
|
|
saNxtOfrOut = sleNxtOfr->getIValueFieldAmount(sfTakerGets);
|
|
|
|
|
|
|
|
|
|
// Cost (payout + fees) to next offer owner if offer is fully redeem.
|
|
|
|
|
STAmount saNxtOutCost = STAmount::multiply(saNxtOfrOut, saNxtFeeRate, saNxtOfrOut.getCurrency(), saNxtOfrOut.getIssuer());
|
|
|
|
|
|
|
|
|
|
if (saNxtOfrOut > saNxtOfrFunds)
|
|
|
|
|
{
|
|
|
|
|
// Limit offer by funds available.
|
|
|
|
|
STAmount saNxtOutMax = STAmount::divide(saNxtOfrOut, saNxtFeeRate, uCurCurrencyID, uCurIssuerID);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bNxtEntryDirty = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!saNxtOfrFunds.isPositive())
|
|
|
|
|
{
|
|
|
|
|
// Offer is unfunded.
|
|
|
|
|
bNxtEntryAdvance = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STAmount saNxtOutAvail =
|
|
|
|
|
// Driving amount of input.
|
|
|
|
|
const STAmount saInBase = saCurOfrInMax-saCurOfrInAct;
|
|
|
|
|
|
|
|
|
|
// Desired amount of output not including fees.
|
|
|
|
|
const STAmount saOutReq = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID, uCurIssuerID);
|
|
|
|
|
STAmount saOutBase = std::min(
|
|
|
|
|
std::min(saCurOfrOutReq, saOutReq), // Limit offer out by needed.
|
|
|
|
|
saNxtOfrIn); // Limit offer out by supplying offer.
|
|
|
|
|
// Limit cost by fees & funds.
|
|
|
|
|
const STAmount saOutCost = std::min(
|
|
|
|
|
bNxtFee
|
|
|
|
|
? STAmount::multiply(saOutBase, saNxtFeeRate, uCurCurrencyID, uCurIssuerID)
|
|
|
|
|
: saOutBase,
|
|
|
|
|
saCurOfrFunds);
|
|
|
|
|
// Compute output minus fees. Fees are offer's obligation and not passed to input.
|
|
|
|
|
const STAmount saOutDlvPass= bNxtFee
|
|
|
|
|
? STAmount::divide(saOutCost, saNxtFeeRate, uCurCurrencyID, uCurIssuerID)
|
|
|
|
|
: saOutCost;
|
|
|
|
|
// Compute input based on output minus fees.
|
|
|
|
|
const STAmount saInDlvPass = STAmount::multiply(saOutDlvPass, saOfrRate, uPrvCurrencyID, uCurIssuerID);
|
|
|
|
|
|
|
|
|
|
// XXX Check fees.
|
|
|
|
|
sleNxtOfr->setIFieldAmount(sfTakerGets, saNxtOfrIn - saInDlvPass);
|
|
|
|
|
sleNxtOfr->setIFieldAmount(sfTakerPays, saNxtOfrOut - saOutDlvPass);
|
|
|
|
|
|
|
|
|
|
if (saNxtOfrOut == saOutDlvPass) {
|
|
|
|
|
// Consumed all of offer.
|
|
|
|
|
// XXX Move to outside.
|
|
|
|
|
Log(lsINFO) << "calcNodeOfferFwd: offer consumed";
|
|
|
|
|
|
|
|
|
|
pspCur->vUnfundedBecame.push_back(uNxtIndex); // Mark offer for deletion on use of current path state.
|
|
|
|
|
|
|
|
|
|
bNxtEntryAdvance = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
umNxtBalance[uNxtOfrAccountID] = saNxtOfrFunds;
|
|
|
|
|
|
|
|
|
|
saCurOfrSpent += saOutDlvPass; // XXX Check.
|
|
|
|
|
|
|
|
|
|
saCurOfrInAct += saInDlvPass; // Add to input handled.
|
|
|
|
|
|
|
|
|
|
saCurOfrOutAct += saOutDlvPass; // Add to output handled.
|
|
|
|
|
}
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
|
|
// Deliver output to limbo or currency issuer.
|
|
|
|
|
accountSend(
|
|
|
|
|
uCurOfrAccountID, // Offer owner pays.
|
|
|
|
|
uCurOfrAccountID, // Offer owner pays.
|
|
|
|
|
!!uCurIssuerID
|
|
|
|
|
? uCurIssuerID // Output is non-XNS send to issuer.
|
|
|
|
|
: ACCOUNT_XNS, // Output is XNS send to limbo (ACCOUNT_XNS).
|
|
|
|
|
saOutDlvAct);
|
|
|
|
|
#endif
|
|
|
|
|
saCurOfrOutAct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Deliver input to offer owner.
|
|
|
|
|
#if 0
|
|
|
|
|
accountSend(
|
|
|
|
|
!!uPrvAccountID
|
|
|
|
|
? uPrvAccountID // Previous is an account. Source is previous account.
|
|
|
|
|
@@ -2424,10 +2540,16 @@ TER TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
? ACCOUNT_XNS // Previous is offer outputing XNS, source is limbo (ACCOUNT_XNS).
|
|
|
|
|
: uPrvIssuerID, // Previous is offer outputing non-XNS, source is input issuer.
|
|
|
|
|
uCurOfrAccountID, // Offer owner receives.
|
|
|
|
|
saInDlvAct);
|
|
|
|
|
saCurOfrInAct);
|
|
|
|
|
|
|
|
|
|
saPrvDlvAct += saInDlvAct; // Portion needed in previous.
|
|
|
|
|
#endif
|
|
|
|
|
if (saCurOfrFunds == saCurOfrSpent)
|
|
|
|
|
{
|
|
|
|
|
// Offer became unfunded.
|
|
|
|
|
pspCur->vUnfundedBecame.push_back(uOfferIndex); // Mark offer for deletion on use of current path state.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
saPrvDlvAct += saCurOfrInAct; // Portion needed in previous.
|
|
|
|
|
saCurDlvAct += saCurOfrOutAct; // Portion of driver served.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2436,13 +2558,10 @@ TER TransactionEngine::calcNodeOfferFwd(
|
|
|
|
|
uDirectTip = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (saCurDlvAct)
|
|
|
|
|
{
|
|
|
|
|
saCurDlvReq = saCurDlvAct; // Adjust request.
|
|
|
|
|
terResult = tesSUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return !!saCurDlvAct ? tesSUCCESS : terResult;
|
|
|
|
|
#else
|
|
|
|
|
return terResult;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
@@ -2716,7 +2835,7 @@ void TransactionEngine::calcNodeRipple(
|
|
|
|
|
// No fee.
|
|
|
|
|
Log(lsINFO) << boost::str(boost::format("calcNodeRipple: No fees"));
|
|
|
|
|
|
|
|
|
|
STAmount saTransfer = bPrvUnlimited ? saCur : MIN(saPrv, saCur);
|
|
|
|
|
STAmount saTransfer = bPrvUnlimited ? saCur : std::min(saPrv, saCur);
|
|
|
|
|
|
|
|
|
|
saPrvAct += saTransfer;
|
|
|
|
|
saCurAct += saTransfer;
|
|
|
|
|
@@ -2771,12 +2890,12 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS
|
|
|
|
|
paymentNode& pnCur = pspCur->vpnNodes[uIndex];
|
|
|
|
|
paymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1];
|
|
|
|
|
|
|
|
|
|
const bool bRedeem = !!(pnCur.uFlags & STPathElement::typeRedeem);
|
|
|
|
|
const bool bPrvRedeem = !!(pnPrv.uFlags & STPathElement::typeRedeem);
|
|
|
|
|
const bool bIssue = !!(pnCur.uFlags & STPathElement::typeIssue);
|
|
|
|
|
const bool bPrvIssue = !!(pnPrv.uFlags & STPathElement::typeIssue);
|
|
|
|
|
const bool bPrvAccount = !uIndex || !!(pnPrv.uFlags & STPathElement::typeAccount);
|
|
|
|
|
const bool bNxtAccount = uIndex == uLast || !!(pnNxt.uFlags & STPathElement::typeAccount);
|
|
|
|
|
const bool bRedeem = isSetBit(pnCur.uFlags, STPathElement::typeRedeem);
|
|
|
|
|
const bool bPrvRedeem = isSetBit(pnPrv.uFlags, STPathElement::typeRedeem);
|
|
|
|
|
const bool bIssue = isSetBit(pnCur.uFlags, STPathElement::typeIssue);
|
|
|
|
|
const bool bPrvIssue = isSetBit(pnPrv.uFlags, STPathElement::typeIssue);
|
|
|
|
|
const bool bPrvAccount = !uIndex || isSetBit(pnPrv.uFlags, STPathElement::typeAccount);
|
|
|
|
|
const bool bNxtAccount = uIndex == uLast || isSetBit(pnNxt.uFlags, STPathElement::typeAccount);
|
|
|
|
|
|
|
|
|
|
const uint160& uCurAccountID = pnCur.uAccountID;
|
|
|
|
|
const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID;
|
|
|
|
|
@@ -2850,8 +2969,8 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS
|
|
|
|
|
// account --> ACCOUNT --> $
|
|
|
|
|
// Overall 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.
|
|
|
|
|
? std::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: account --> ACCOUNT --> $ : saCurWantedReq=%s")
|
|
|
|
|
@@ -2864,7 +2983,7 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS
|
|
|
|
|
// Redeem at 1:1
|
|
|
|
|
Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Redeem at 1:1"));
|
|
|
|
|
|
|
|
|
|
saCurWantedAct = MIN(saPrvRedeemReq, saCurWantedReq);
|
|
|
|
|
saCurWantedAct = std::min(saPrvRedeemReq, saCurWantedReq);
|
|
|
|
|
saPrvRedeemAct = saCurWantedAct;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -3005,7 +3124,7 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS
|
|
|
|
|
{
|
|
|
|
|
// offer --> ACCOUNT --> $
|
|
|
|
|
const STAmount& saCurWantedReq = bPrvAccount
|
|
|
|
|
? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit.
|
|
|
|
|
? std::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());
|
|
|
|
|
|
|
|
|
|
@@ -3099,10 +3218,10 @@ TER TransactionEngine::calcNodeAccountFwd(
|
|
|
|
|
paymentNode& pnCur = pspCur->vpnNodes[uIndex];
|
|
|
|
|
paymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1];
|
|
|
|
|
|
|
|
|
|
const bool bRedeem = !!(pnCur.uFlags & STPathElement::typeRedeem);
|
|
|
|
|
const bool bIssue = !!(pnCur.uFlags & STPathElement::typeIssue);
|
|
|
|
|
const bool bPrvAccount = !!(pnPrv.uFlags & STPathElement::typeAccount);
|
|
|
|
|
const bool bNxtAccount = !!(pnNxt.uFlags & STPathElement::typeAccount);
|
|
|
|
|
const bool bRedeem = isSetBit(pnCur.uFlags, STPathElement::typeRedeem);
|
|
|
|
|
const bool bIssue = isSetBit(pnCur.uFlags, STPathElement::typeIssue);
|
|
|
|
|
const bool bPrvAccount = isSetBit(pnPrv.uFlags, STPathElement::typeAccount);
|
|
|
|
|
const bool bNxtAccount = isSetBit(pnNxt.uFlags, STPathElement::typeAccount);
|
|
|
|
|
|
|
|
|
|
const uint160& uCurAccountID = pnCur.uAccountID;
|
|
|
|
|
const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID;
|
|
|
|
|
@@ -3172,7 +3291,7 @@ TER TransactionEngine::calcNodeAccountFwd(
|
|
|
|
|
// Redeem requested.
|
|
|
|
|
saCurRedeemAct = saCurRedeemReq.isNegative()
|
|
|
|
|
? saCurRedeemReq
|
|
|
|
|
: MIN(saCurRedeemReq, saCurSendMaxReq);
|
|
|
|
|
: std::min(saCurRedeemReq, saCurSendMaxReq);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
@@ -3185,7 +3304,7 @@ TER TransactionEngine::calcNodeAccountFwd(
|
|
|
|
|
// Issue requested and not over budget.
|
|
|
|
|
saCurIssueAct = saCurSendMaxReq.isNegative()
|
|
|
|
|
? saCurIssueReq
|
|
|
|
|
: MIN(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq);
|
|
|
|
|
: std::min(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
@@ -3433,15 +3552,15 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint
|
|
|
|
|
const bool bFirst = vpnNodes.empty();
|
|
|
|
|
const paymentNode& pnPrv = bFirst ? paymentNode() : vpnNodes.back();
|
|
|
|
|
// true, iff node is a ripple account. false, iff node is an offer node.
|
|
|
|
|
const bool bAccount = !!(iType & STPathElement::typeAccount);
|
|
|
|
|
const bool bAccount = isSetBit(iType, STPathElement::typeAccount);
|
|
|
|
|
// true, iff currency supplied.
|
|
|
|
|
// Currency is specified for the output of the current node.
|
|
|
|
|
const bool bCurrency = !!(iType & STPathElement::typeCurrency);
|
|
|
|
|
const bool bCurrency = isSetBit(iType, STPathElement::typeCurrency);
|
|
|
|
|
// Issuer is specified for the output of the current node.
|
|
|
|
|
const bool bIssuer = !!(iType & STPathElement::typeIssuer);
|
|
|
|
|
const bool bIssuer = isSetBit(iType, STPathElement::typeIssuer);
|
|
|
|
|
// true, iff account is allowed to redeem it's IOUs to next node.
|
|
|
|
|
const bool bRedeem = !!(iType & STPathElement::typeRedeem);
|
|
|
|
|
const bool bIssue = !!(iType & STPathElement::typeIssue);
|
|
|
|
|
const bool bRedeem = isSetBit(iType, STPathElement::typeRedeem);
|
|
|
|
|
const bool bIssue = isSetBit(iType, STPathElement::typeIssue);
|
|
|
|
|
TER terResult = tesSUCCESS;
|
|
|
|
|
|
|
|
|
|
pnCur.uFlags = iType;
|
|
|
|
|
@@ -3476,7 +3595,7 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint
|
|
|
|
|
if (tesSUCCESS == terResult && !vpnNodes.empty())
|
|
|
|
|
{
|
|
|
|
|
const paymentNode& pnBck = vpnNodes.back();
|
|
|
|
|
bool bBckAccount = !!(pnBck.uFlags & STPathElement::typeAccount);
|
|
|
|
|
bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount);
|
|
|
|
|
|
|
|
|
|
if (bBckAccount)
|
|
|
|
|
{
|
|
|
|
|
@@ -3551,8 +3670,8 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint
|
|
|
|
|
{
|
|
|
|
|
// Verify that previous account is allowed to issue.
|
|
|
|
|
const paymentNode& pnBck = vpnNodes.back();
|
|
|
|
|
bool bBckAccount = !!(pnBck.uFlags & STPathElement::typeAccount);
|
|
|
|
|
bool bBckIssue = !!(pnBck.uFlags & STPathElement::typeIssue);
|
|
|
|
|
bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount);
|
|
|
|
|
bool bBckIssue = isSetBit(pnBck.uFlags, STPathElement::typeIssue);
|
|
|
|
|
|
|
|
|
|
if (bBckAccount && !bBckIssue)
|
|
|
|
|
{
|
|
|
|
|
@@ -3751,15 +3870,15 @@ Json::Value PathState::getJson() const
|
|
|
|
|
TER TransactionEngine::calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality)
|
|
|
|
|
{
|
|
|
|
|
const paymentNode& pnCur = pspCur->vpnNodes[uIndex];
|
|
|
|
|
const bool bCurAccount = !!(pnCur.uFlags & STPathElement::typeAccount);
|
|
|
|
|
const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount);
|
|
|
|
|
TER terResult;
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << boost::str(boost::format("calcNode> uIndex=%d") % uIndex);
|
|
|
|
|
|
|
|
|
|
// Do current node reverse.
|
|
|
|
|
terResult = bCurAccount
|
|
|
|
|
? calcNodeAccountRev(uIndex, pspCur, bMultiQuality)
|
|
|
|
|
: calcNodeOfferRev(uIndex, pspCur, bMultiQuality);
|
|
|
|
|
? calcNodeAccountRev(uIndex, pspCur, bMultiQuality)
|
|
|
|
|
: calcNodeOfferRev(uIndex, pspCur, bMultiQuality);
|
|
|
|
|
|
|
|
|
|
// Do previous.
|
|
|
|
|
if (tesSUCCESS == terResult && uIndex)
|
|
|
|
|
@@ -3771,8 +3890,8 @@ TER TransactionEngine::calcNode(const unsigned int uIndex, const PathState::poin
|
|
|
|
|
if (tesSUCCESS == terResult)
|
|
|
|
|
{
|
|
|
|
|
terResult = bCurAccount
|
|
|
|
|
? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality)
|
|
|
|
|
: calcNodeOfferFwd(uIndex, pspCur, bMultiQuality);
|
|
|
|
|
? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality)
|
|
|
|
|
: calcNodeOfferFwd(uIndex, pspCur, bMultiQuality);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log(lsINFO) << boost::str(boost::format("calcNode< uIndex=%d terResult=%d") % uIndex % terResult);
|
|
|
|
|
@@ -3816,9 +3935,9 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn)
|
|
|
|
|
{
|
|
|
|
|
// Ripple if source or destination is non-native or if there are paths.
|
|
|
|
|
const uint32 uTxFlags = txn.getFlags();
|
|
|
|
|
const bool bCreate = !!(uTxFlags & tfCreateAccount);
|
|
|
|
|
const bool bNoRippleDirect = !!(uTxFlags & tfNoRippleDirect);
|
|
|
|
|
const bool bPartialPayment = !!(uTxFlags & tfPartialPayment);
|
|
|
|
|
const bool bCreate = isSetBit(uTxFlags, tfCreateAccount);
|
|
|
|
|
const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect);
|
|
|
|
|
const bool bPartialPayment = isSetBit(uTxFlags, tfPartialPayment);
|
|
|
|
|
const bool bPaths = txn.getITFieldPresent(sfPaths);
|
|
|
|
|
const bool bMax = txn.getITFieldPresent(sfSendMax);
|
|
|
|
|
const uint160 uDstAccountID = txn.getITFieldAccount(sfDestination);
|
|
|
|
|
@@ -4414,7 +4533,7 @@ TER TransactionEngine::doOfferCreate(const SerializedTransaction& txn)
|
|
|
|
|
{
|
|
|
|
|
Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0);
|
|
|
|
|
const uint32 txFlags = txn.getFlags();
|
|
|
|
|
const bool bPassive = !!(txFlags & tfPassive);
|
|
|
|
|
const bool bPassive = isSetBit(txFlags, tfPassive);
|
|
|
|
|
STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays);
|
|
|
|
|
STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets);
|
|
|
|
|
Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText();
|
|
|
|
|
|