mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Handle offers in quality directory but not in ledger
This commit is contained in:
@@ -2827,99 +2827,107 @@ void NetworkOPsImp::getBookPage (Ledger::pointer lpLedger, const uint160& uTaker
|
||||
if (!bDone)
|
||||
{
|
||||
SLE::pointer sleOffer = lesActive.entryCache (ltOFFER, uOfferIndex);
|
||||
const uint160 uOfferOwnerID = sleOffer->getFieldAccount160 (sfAccount);
|
||||
const STAmount& saTakerGets = sleOffer->getFieldAmount (sfTakerGets);
|
||||
const STAmount& saTakerPays = sleOffer->getFieldAmount (sfTakerPays);
|
||||
STAmount saOwnerFunds;
|
||||
|
||||
if (uTakerGetsIssuerID == uOfferOwnerID)
|
||||
if (sleOffer)
|
||||
{
|
||||
// If offer is selling issuer's own IOUs, it is fully funded.
|
||||
saOwnerFunds = saTakerGets;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::map<uint160, STAmount>::const_iterator umBalanceEntry = umBalance.find (uOfferOwnerID);
|
||||
const uint160 uOfferOwnerID = sleOffer->getFieldAccount160 (sfAccount);
|
||||
const STAmount& saTakerGets = sleOffer->getFieldAmount (sfTakerGets);
|
||||
const STAmount& saTakerPays = sleOffer->getFieldAmount (sfTakerPays);
|
||||
STAmount saOwnerFunds;
|
||||
|
||||
if (umBalanceEntry != umBalance.end ())
|
||||
if (uTakerGetsIssuerID == uOfferOwnerID)
|
||||
{
|
||||
// Found in running balance table.
|
||||
|
||||
saOwnerFunds = umBalanceEntry->second;
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: saOwnerFunds=%s (cached)") % saOwnerFunds.getFullText());
|
||||
// If offer is selling issuer's own IOUs, it is fully funded.
|
||||
saOwnerFunds = saTakerGets;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Did not find balance in table.
|
||||
std::map<uint160, STAmount>::const_iterator umBalanceEntry = umBalance.find (uOfferOwnerID);
|
||||
|
||||
saOwnerFunds = lesActive.accountHolds (uOfferOwnerID, uTakerGetsCurrencyID, uTakerGetsIssuerID);
|
||||
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: saOwnerFunds=%s (new)") % saOwnerFunds.getFullText());
|
||||
if (saOwnerFunds.isNegative ())
|
||||
if (umBalanceEntry != umBalance.end ())
|
||||
{
|
||||
// Treat negative funds as zero.
|
||||
// Found in running balance table.
|
||||
|
||||
saOwnerFunds.zero ();
|
||||
saOwnerFunds = umBalanceEntry->second;
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: saOwnerFunds=%s (cached)") % saOwnerFunds.getFullText());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Did not find balance in table.
|
||||
|
||||
saOwnerFunds = lesActive.accountHolds (uOfferOwnerID, uTakerGetsCurrencyID, uTakerGetsIssuerID);
|
||||
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: saOwnerFunds=%s (new)") % saOwnerFunds.getFullText());
|
||||
if (saOwnerFunds.isNegative ())
|
||||
{
|
||||
// Treat negative funds as zero.
|
||||
|
||||
saOwnerFunds.zero ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value jvOffer = sleOffer->getJson (0);
|
||||
Json::Value jvOffer = sleOffer->getJson (0);
|
||||
|
||||
STAmount saTakerGetsFunded;
|
||||
STAmount saOwnerFundsLimit;
|
||||
uint32 uOfferRate;
|
||||
STAmount saTakerGetsFunded;
|
||||
STAmount saOwnerFundsLimit;
|
||||
uint32 uOfferRate;
|
||||
|
||||
|
||||
if (uTransferRate != QUALITY_ONE // Have a tranfer fee.
|
||||
&& uTakerID != uTakerGetsIssuerID // Not taking offers of own IOUs.
|
||||
&& uTakerGetsIssuerID != uOfferOwnerID) // Offer owner not issuing ownfunds
|
||||
{
|
||||
// Need to charge a transfer fee to offer owner.
|
||||
uOfferRate = uTransferRate;
|
||||
saOwnerFundsLimit = STAmount::divide (saOwnerFunds, STAmount (CURRENCY_ONE, ACCOUNT_ONE, uOfferRate, -9));
|
||||
if (uTransferRate != QUALITY_ONE // Have a tranfer fee.
|
||||
&& uTakerID != uTakerGetsIssuerID // Not taking offers of own IOUs.
|
||||
&& uTakerGetsIssuerID != uOfferOwnerID) // Offer owner not issuing ownfunds
|
||||
{
|
||||
// Need to charge a transfer fee to offer owner.
|
||||
uOfferRate = uTransferRate;
|
||||
saOwnerFundsLimit = STAmount::divide (saOwnerFunds, STAmount (CURRENCY_ONE, ACCOUNT_ONE, uOfferRate, -9));
|
||||
}
|
||||
else
|
||||
{
|
||||
uOfferRate = QUALITY_ONE;
|
||||
saOwnerFundsLimit = saOwnerFunds;
|
||||
}
|
||||
|
||||
if (saOwnerFundsLimit >= saTakerGets)
|
||||
{
|
||||
// Sufficient funds no shenanigans.
|
||||
saTakerGetsFunded = saTakerGets;
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: saTakerGets=%s") % saTakerGets.getFullText());
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: saTakerPays=%s") % saTakerPays.getFullText());
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: saOwnerFunds=%s") % saOwnerFunds.getFullText());
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: saDirRate=%s") % saDirRate.getText());
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: multiply=%s") % STAmount::multiply(saTakerGetsFunded, saDirRate).getFullText());
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: multiply=%s") % STAmount::multiply(saTakerGetsFunded, saDirRate, saTakerPays).getFullText());
|
||||
|
||||
// Only provide, if not fully funded.
|
||||
|
||||
saTakerGetsFunded = saOwnerFundsLimit;
|
||||
|
||||
saTakerGetsFunded.setJson (jvOffer["taker_gets_funded"]);
|
||||
std::min (saTakerPays, STAmount::multiply (saTakerGetsFunded, saDirRate, saTakerPays)).setJson (jvOffer["taker_pays_funded"]);
|
||||
}
|
||||
|
||||
STAmount saOwnerPays = (QUALITY_ONE == uOfferRate)
|
||||
? saTakerGetsFunded
|
||||
: std::min (saOwnerFunds, STAmount::multiply (saTakerGetsFunded, STAmount (CURRENCY_ONE, ACCOUNT_ONE, uOfferRate, -9)));
|
||||
|
||||
umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
|
||||
|
||||
if (!saOwnerFunds.isZero () || uOfferOwnerID == uTakerID)
|
||||
{
|
||||
// Only provide funded offers and offers of the taker.
|
||||
Json::Value& jvOf = jvOffers.append (jvOffer);
|
||||
jvOf["quality"] = saDirRate.getText ();
|
||||
--iLeft;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uOfferRate = QUALITY_ONE;
|
||||
saOwnerFundsLimit = saOwnerFunds;
|
||||
}
|
||||
|
||||
if (saOwnerFundsLimit >= saTakerGets)
|
||||
{
|
||||
// Sufficient funds no shenanigans.
|
||||
saTakerGetsFunded = saTakerGets;
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: saTakerGets=%s") % saTakerGets.getFullText());
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: saTakerPays=%s") % saTakerPays.getFullText());
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: saOwnerFunds=%s") % saOwnerFunds.getFullText());
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: saDirRate=%s") % saDirRate.getText());
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: multiply=%s") % STAmount::multiply(saTakerGetsFunded, saDirRate).getFullText());
|
||||
// m_journal.info << boost::str(boost::format("getBookPage: multiply=%s") % STAmount::multiply(saTakerGetsFunded, saDirRate, saTakerPays).getFullText());
|
||||
|
||||
// Only provide, if not fully funded.
|
||||
|
||||
saTakerGetsFunded = saOwnerFundsLimit;
|
||||
|
||||
saTakerGetsFunded.setJson (jvOffer["taker_gets_funded"]);
|
||||
std::min (saTakerPays, STAmount::multiply (saTakerGetsFunded, saDirRate, saTakerPays)).setJson (jvOffer["taker_pays_funded"]);
|
||||
}
|
||||
|
||||
STAmount saOwnerPays = (QUALITY_ONE == uOfferRate)
|
||||
? saTakerGetsFunded
|
||||
: std::min (saOwnerFunds, STAmount::multiply (saTakerGetsFunded, STAmount (CURRENCY_ONE, ACCOUNT_ONE, uOfferRate, -9)));
|
||||
|
||||
umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
|
||||
|
||||
if (!saOwnerFunds.isZero () || uOfferOwnerID == uTakerID)
|
||||
{
|
||||
// Only provide funded offers and offers of the taker.
|
||||
Json::Value& jvOf = jvOffers.append (jvOffer);
|
||||
jvOf["quality"] = saDirRate.getText ();
|
||||
--iLeft;
|
||||
}
|
||||
m_journal.warning << "Missing offer";
|
||||
}
|
||||
|
||||
if (!lesActive.dirNext (uTipIndex, sleOfferDir, uBookEntry, uOfferIndex))
|
||||
{
|
||||
|
||||
@@ -197,137 +197,145 @@ TER RippleCalc::calcNodeAdvance (
|
||||
{
|
||||
// Got a new offer.
|
||||
sleOffer = lesActive.entryCache (ltOFFER, uOfferIndex);
|
||||
uOfrOwnerID = sleOffer->getFieldAccount160 (sfAccount);
|
||||
saTakerPays = sleOffer->getFieldAmount (sfTakerPays);
|
||||
saTakerGets = sleOffer->getFieldAmount (sfTakerGets);
|
||||
|
||||
const aciSource asLine = boost::make_tuple (uOfrOwnerID, uCurCurrencyID, uCurIssuerID);
|
||||
|
||||
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("calcNodeAdvance: uOfrOwnerID=%s saTakerPays=%s saTakerGets=%s uOfferIndex=%s")
|
||||
% RippleAddress::createHumanAccountID (uOfrOwnerID)
|
||||
% saTakerPays
|
||||
% saTakerGets
|
||||
% uOfferIndex);
|
||||
|
||||
if (sleOffer->isFieldPresent (sfExpiration) && sleOffer->getFieldU32 (sfExpiration) <= lesActive.getLedger ()->getParentCloseTimeNC ())
|
||||
if (!sleOffer)
|
||||
{
|
||||
// Offer is expired.
|
||||
WriteLog (lsTRACE, RippleCalc) << "calcNodeAdvance: expired offer";
|
||||
musUnfundedFound.insert(uOfferIndex);
|
||||
continue;
|
||||
WriteLog (lsWARNING, RippleCalc) << "Missing offer in directory";
|
||||
bEntryAdvance = true;
|
||||
}
|
||||
else if (!saTakerPays.isPositive () || !saTakerGets.isPositive ())
|
||||
else
|
||||
{
|
||||
// Offer has bad amounts. Offers should never have a bad amounts.
|
||||
uOfrOwnerID = sleOffer->getFieldAccount160 (sfAccount);
|
||||
saTakerPays = sleOffer->getFieldAmount (sfTakerPays);
|
||||
saTakerGets = sleOffer->getFieldAmount (sfTakerGets);
|
||||
|
||||
if (bReverse)
|
||||
{
|
||||
// Past internal error, offer had bad amounts.
|
||||
WriteLog (lsWARNING, RippleCalc) << boost::str (boost::format ("calcNodeAdvance: PAST INTERNAL ERROR: OFFER NON-POSITIVE: saTakerPays=%s saTakerGets=%s")
|
||||
% saTakerPays % saTakerGets);
|
||||
const aciSource asLine = boost::make_tuple (uOfrOwnerID, uCurCurrencyID, uCurIssuerID);
|
||||
|
||||
musUnfundedFound.insert (uOfferIndex); // Mark offer for always deletion.
|
||||
continue;
|
||||
}
|
||||
else if (musUnfundedFound.find (uOfferIndex) != musUnfundedFound.end ())
|
||||
{
|
||||
// Past internal error, offer was found failed to place this in musUnfundedFound.
|
||||
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("calcNodeAdvance: PAST INTERNAL ERROR: OFFER NON-POSITIVE: saTakerPays=%s saTakerGets=%s")
|
||||
% saTakerPays % saTakerGets);
|
||||
|
||||
// Just skip it. It will be deleted.
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reverse should have previously put bad offer in list.
|
||||
// An internal error previously left a bad offer.
|
||||
WriteLog (lsWARNING, RippleCalc) << boost::str (boost::format ("calcNodeAdvance: INTERNAL ERROR: OFFER NON-POSITIVE: saTakerPays=%s saTakerGets=%s")
|
||||
% saTakerPays % saTakerGets);
|
||||
|
||||
// Don't process at all, things are in an unexpected state for this transactions.
|
||||
terResult = tefEXCEPTION;
|
||||
}
|
||||
|
||||
// VFALCO NOTE What's the point of the earlier continue statements?
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allowed to access source from this node?
|
||||
// XXX This can get called multiple times for same source in a row, caching result would be nice.
|
||||
// XXX Going forward could we fund something with a worse quality which was previously skipped? Might need to check
|
||||
// quality.
|
||||
curIssuerNodeConstIterator itForward = psCur.umForward.find (asLine);
|
||||
const bool bFoundForward = itForward != psCur.umForward.end ();
|
||||
|
||||
// Only a allow a source to be used once, in the first node encountered from initial path scan.
|
||||
// This prevents conflicting uses of the same balance when going reverse vs forward.
|
||||
if (bFoundForward && (itForward->second != uNode) && (uOfrOwnerID != uCurIssuerID))
|
||||
{
|
||||
// Temporarily unfunded. Another node uses this source, ignore in this offer.
|
||||
WriteLog (lsTRACE, RippleCalc) << "calcNodeAdvance: temporarily unfunded offer (forward)";
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is overly strict. For contributions to past. We should only count source if actually used.
|
||||
curIssuerNodeConstIterator itReverse = psCur.umReverse.find (asLine);
|
||||
bool bFoundReverse = itReverse != psCur.umReverse.end ();
|
||||
|
||||
// For this quality increment, only allow a source to be used from a single node, in the first node encountered from applying offers
|
||||
// in reverse.
|
||||
if (bFoundReverse && (itReverse->second != uNode) && (uOfrOwnerID != uCurIssuerID))
|
||||
{
|
||||
// Temporarily unfunded. Another node uses this source, ignore in this offer.
|
||||
WriteLog (lsTRACE, RippleCalc) << "calcNodeAdvance: temporarily unfunded offer (reverse)";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine if used in past.
|
||||
// We only need to know if it might need to be marked unfunded.
|
||||
curIssuerNodeConstIterator itPast = mumSource.find (asLine);
|
||||
bool bFoundPast = itPast != mumSource.end ();
|
||||
|
||||
// Only the current node is allowed to use the source.
|
||||
|
||||
saOfferFunds = lesActive.accountFunds (uOfrOwnerID, saTakerGets); // Funds held.
|
||||
|
||||
if (!saOfferFunds.isPositive ())
|
||||
{
|
||||
// Offer is unfunded.
|
||||
WriteLog (lsTRACE, RippleCalc) << "calcNodeAdvance: unfunded offer";
|
||||
|
||||
if (bReverse && !bFoundReverse && !bFoundPast)
|
||||
{
|
||||
// Never mentioned before, clearly just: found unfunded.
|
||||
// That is, even if this offer fails due to fill or kill still do deletions.
|
||||
musUnfundedFound.insert (uOfferIndex); // Mark offer for always deletion.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Moving forward, don't need to insert again
|
||||
// Or, already found it.
|
||||
}
|
||||
|
||||
// YYY Could verify offer is correct place for unfundeds.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bReverse // Need to remember reverse mention.
|
||||
&& !bFoundPast // Not mentioned in previous passes.
|
||||
&& !bFoundReverse) // New to pass.
|
||||
{
|
||||
// Consider source mentioned by current path state.
|
||||
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("calcNodeAdvance: remember=%s/%s/%s")
|
||||
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("calcNodeAdvance: uOfrOwnerID=%s saTakerPays=%s saTakerGets=%s uOfferIndex=%s")
|
||||
% RippleAddress::createHumanAccountID (uOfrOwnerID)
|
||||
% STAmount::createHumanCurrency (uCurCurrencyID)
|
||||
% RippleAddress::createHumanAccountID (uCurIssuerID));
|
||||
% saTakerPays
|
||||
% saTakerGets
|
||||
% uOfferIndex);
|
||||
|
||||
psCur.umReverse.insert (std::make_pair (asLine, uNode));
|
||||
if (sleOffer->isFieldPresent (sfExpiration) && sleOffer->getFieldU32 (sfExpiration) <= lesActive.getLedger ()->getParentCloseTimeNC ())
|
||||
{
|
||||
// Offer is expired.
|
||||
WriteLog (lsTRACE, RippleCalc) << "calcNodeAdvance: expired offer";
|
||||
musUnfundedFound.insert(uOfferIndex);
|
||||
continue;
|
||||
}
|
||||
else if (!saTakerPays.isPositive () || !saTakerGets.isPositive ())
|
||||
{
|
||||
// Offer has bad amounts. Offers should never have a bad amounts.
|
||||
|
||||
if (bReverse)
|
||||
{
|
||||
// Past internal error, offer had bad amounts.
|
||||
WriteLog (lsWARNING, RippleCalc) << boost::str (boost::format ("calcNodeAdvance: PAST INTERNAL ERROR: OFFER NON-POSITIVE: saTakerPays=%s saTakerGets=%s")
|
||||
% saTakerPays % saTakerGets);
|
||||
|
||||
musUnfundedFound.insert (uOfferIndex); // Mark offer for always deletion.
|
||||
continue;
|
||||
}
|
||||
else if (musUnfundedFound.find (uOfferIndex) != musUnfundedFound.end ())
|
||||
{
|
||||
// Past internal error, offer was found failed to place this in musUnfundedFound.
|
||||
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("calcNodeAdvance: PAST INTERNAL ERROR: OFFER NON-POSITIVE: saTakerPays=%s saTakerGets=%s")
|
||||
% saTakerPays % saTakerGets);
|
||||
|
||||
// Just skip it. It will be deleted.
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reverse should have previously put bad offer in list.
|
||||
// An internal error previously left a bad offer.
|
||||
WriteLog (lsWARNING, RippleCalc) << boost::str (boost::format ("calcNodeAdvance: INTERNAL ERROR: OFFER NON-POSITIVE: saTakerPays=%s saTakerGets=%s")
|
||||
% saTakerPays % saTakerGets);
|
||||
|
||||
// Don't process at all, things are in an unexpected state for this transactions.
|
||||
terResult = tefEXCEPTION;
|
||||
}
|
||||
|
||||
// VFALCO NOTE What's the point of the earlier continue statements?
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allowed to access source from this node?
|
||||
// XXX This can get called multiple times for same source in a row, caching result would be nice.
|
||||
// XXX Going forward could we fund something with a worse quality which was previously skipped? Might need to check
|
||||
// quality.
|
||||
curIssuerNodeConstIterator itForward = psCur.umForward.find (asLine);
|
||||
const bool bFoundForward = itForward != psCur.umForward.end ();
|
||||
|
||||
// Only a allow a source to be used once, in the first node encountered from initial path scan.
|
||||
// This prevents conflicting uses of the same balance when going reverse vs forward.
|
||||
if (bFoundForward && (itForward->second != uNode) && (uOfrOwnerID != uCurIssuerID))
|
||||
{
|
||||
// Temporarily unfunded. Another node uses this source, ignore in this offer.
|
||||
WriteLog (lsTRACE, RippleCalc) << "calcNodeAdvance: temporarily unfunded offer (forward)";
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is overly strict. For contributions to past. We should only count source if actually used.
|
||||
curIssuerNodeConstIterator itReverse = psCur.umReverse.find (asLine);
|
||||
bool bFoundReverse = itReverse != psCur.umReverse.end ();
|
||||
|
||||
// For this quality increment, only allow a source to be used from a single node, in the first node encountered from applying offers
|
||||
// in reverse.
|
||||
if (bFoundReverse && (itReverse->second != uNode) && (uOfrOwnerID != uCurIssuerID))
|
||||
{
|
||||
// Temporarily unfunded. Another node uses this source, ignore in this offer.
|
||||
WriteLog (lsTRACE, RippleCalc) << "calcNodeAdvance: temporarily unfunded offer (reverse)";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine if used in past.
|
||||
// We only need to know if it might need to be marked unfunded.
|
||||
curIssuerNodeConstIterator itPast = mumSource.find (asLine);
|
||||
bool bFoundPast = itPast != mumSource.end ();
|
||||
|
||||
// Only the current node is allowed to use the source.
|
||||
|
||||
saOfferFunds = lesActive.accountFunds (uOfrOwnerID, saTakerGets); // Funds held.
|
||||
|
||||
if (!saOfferFunds.isPositive ())
|
||||
{
|
||||
// Offer is unfunded.
|
||||
WriteLog (lsTRACE, RippleCalc) << "calcNodeAdvance: unfunded offer";
|
||||
|
||||
if (bReverse && !bFoundReverse && !bFoundPast)
|
||||
{
|
||||
// Never mentioned before, clearly just: found unfunded.
|
||||
// That is, even if this offer fails due to fill or kill still do deletions.
|
||||
musUnfundedFound.insert (uOfferIndex); // Mark offer for always deletion.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Moving forward, don't need to insert again
|
||||
// Or, already found it.
|
||||
}
|
||||
|
||||
// YYY Could verify offer is correct place for unfundeds.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bReverse // Need to remember reverse mention.
|
||||
&& !bFoundPast // Not mentioned in previous passes.
|
||||
&& !bFoundReverse) // New to pass.
|
||||
{
|
||||
// Consider source mentioned by current path state.
|
||||
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("calcNodeAdvance: remember=%s/%s/%s")
|
||||
% RippleAddress::createHumanAccountID (uOfrOwnerID)
|
||||
% STAmount::createHumanCurrency (uCurCurrencyID)
|
||||
% RippleAddress::createHumanAccountID (uCurIssuerID));
|
||||
|
||||
psCur.umReverse.insert (std::make_pair (asLine, uNode));
|
||||
}
|
||||
|
||||
bFundsDirty = false;
|
||||
bEntryAdvance = false;
|
||||
}
|
||||
|
||||
bFundsDirty = false;
|
||||
bEntryAdvance = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (tesSUCCESS == terResult && (bEntryAdvance || bDirectAdvance));
|
||||
|
||||
|
||||
@@ -227,146 +227,154 @@ TER OfferCreateTransactor::takeOffers (
|
||||
|
||||
SLE::pointer sleOffer = mEngine->entryCache (ltOFFER, uOfferIndex);
|
||||
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: considering offer : " << sleOffer->getJson (0);
|
||||
|
||||
const uint160 uOfferOwnerID = sleOffer->getFieldAccount160 (sfAccount);
|
||||
STAmount saOfferPays = sleOffer->getFieldAmount (sfTakerGets);
|
||||
STAmount saOfferGets = sleOffer->getFieldAmount (sfTakerPays);
|
||||
|
||||
STAmount saOfferFunds; // Funds of offer owner to payout.
|
||||
bool bValid;
|
||||
|
||||
bValid = bValidOffer (
|
||||
sleOffer, uOfferIndex, uOfferOwnerID, saOfferPays, saOfferGets,
|
||||
uTakerAccountID,
|
||||
usOfferUnfundedFound, usOfferUnfundedBecame, usAccountTouched,
|
||||
saOfferFunds);
|
||||
|
||||
if (bValid)
|
||||
if (sleOffer)
|
||||
{
|
||||
STAmount saSubTakerPaid;
|
||||
STAmount saSubTakerGot;
|
||||
STAmount saTakerIssuerFee;
|
||||
STAmount saOfferIssuerFee;
|
||||
STAmount saOfferRate = STAmount::setRate (uTipQuality);
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: considering offer : " << sleOffer->getJson (0);
|
||||
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerPaid: " << saTakerPaid.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerFunds: " << saTakerFunds.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saOfferFunds: " << saOfferFunds.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saOfferPays: " << saOfferPays.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saOfferGets: " << saOfferGets.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saOfferRate: " << saOfferRate.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saSubTakerPays: " << saSubTakerPays.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saSubTakerGets: " << saSubTakerGets.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText ();
|
||||
const uint160 uOfferOwnerID = sleOffer->getFieldAccount160 (sfAccount);
|
||||
STAmount saOfferPays = sleOffer->getFieldAmount (sfTakerGets);
|
||||
STAmount saOfferGets = sleOffer->getFieldAmount (sfTakerPays);
|
||||
|
||||
bool bOfferDelete = STAmount::applyOffer (
|
||||
bSell,
|
||||
lesActive.rippleTransferRate (uTakerAccountID, uOfferOwnerID, uTakerPaysAccountID),
|
||||
lesActive.rippleTransferRate (uOfferOwnerID, uTakerAccountID, uTakerGetsAccountID),
|
||||
saOfferRate,
|
||||
saOfferFunds,
|
||||
saTakerFunds,
|
||||
saOfferPays,
|
||||
saOfferGets,
|
||||
saSubTakerPays,
|
||||
saSubTakerGets,
|
||||
saSubTakerPaid,
|
||||
saSubTakerGot,
|
||||
saTakerIssuerFee,
|
||||
saOfferIssuerFee);
|
||||
STAmount saOfferFunds; // Funds of offer owner to payout.
|
||||
bool bValid;
|
||||
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: applyOffer: saSubTakerPaid: " << saSubTakerPaid.getFullText ();
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText ();
|
||||
bValid = bValidOffer (
|
||||
sleOffer, uOfferIndex, uOfferOwnerID, saOfferPays, saOfferGets,
|
||||
uTakerAccountID,
|
||||
usOfferUnfundedFound, usOfferUnfundedBecame, usAccountTouched,
|
||||
saOfferFunds);
|
||||
|
||||
// Adjust offer
|
||||
|
||||
// Offer owner will pay less. Subtract what taker just got.
|
||||
sleOffer->setFieldAmount (sfTakerGets, saOfferPays -= saSubTakerGot);
|
||||
|
||||
// Offer owner will get less. Subtract what owner just paid.
|
||||
sleOffer->setFieldAmount (sfTakerPays, saOfferGets -= saSubTakerPaid);
|
||||
|
||||
mEngine->entryModify (sleOffer);
|
||||
|
||||
if (bOfferDelete)
|
||||
if (bValid)
|
||||
{
|
||||
// Offer now fully claimed or now unfunded.
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: Offer claimed: Delete.";
|
||||
STAmount saSubTakerPaid;
|
||||
STAmount saSubTakerGot;
|
||||
STAmount saTakerIssuerFee;
|
||||
STAmount saOfferIssuerFee;
|
||||
STAmount saOfferRate = STAmount::setRate (uTipQuality);
|
||||
|
||||
usOfferUnfundedBecame.insert (uOfferIndex); // Delete unfunded offer on success.
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerPaid: " << saTakerPaid.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerFunds: " << saTakerFunds.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saOfferFunds: " << saOfferFunds.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saOfferPays: " << saOfferPays.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saOfferGets: " << saOfferGets.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saOfferRate: " << saOfferRate.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saSubTakerPays: " << saSubTakerPays.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saSubTakerGets: " << saSubTakerGets.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText ();
|
||||
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText ();
|
||||
|
||||
// Offer owner's account is no longer pristine.
|
||||
usAccountTouched.insert (uOfferOwnerID);
|
||||
}
|
||||
else if (saSubTakerGot)
|
||||
{
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: Offer partial claim.";
|
||||
bool bOfferDelete = STAmount::applyOffer (
|
||||
bSell,
|
||||
lesActive.rippleTransferRate (uTakerAccountID, uOfferOwnerID, uTakerPaysAccountID),
|
||||
lesActive.rippleTransferRate (uOfferOwnerID, uTakerAccountID, uTakerGetsAccountID),
|
||||
saOfferRate,
|
||||
saOfferFunds,
|
||||
saTakerFunds,
|
||||
saOfferPays,
|
||||
saOfferGets,
|
||||
saSubTakerPays,
|
||||
saSubTakerGets,
|
||||
saSubTakerPaid,
|
||||
saSubTakerGot,
|
||||
saTakerIssuerFee,
|
||||
saOfferIssuerFee);
|
||||
|
||||
if (!saOfferPays.isPositive () || !saOfferGets.isPositive ())
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: applyOffer: saSubTakerPaid: " << saSubTakerPaid.getFullText ();
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText ();
|
||||
|
||||
// Adjust offer
|
||||
|
||||
// Offer owner will pay less. Subtract what taker just got.
|
||||
sleOffer->setFieldAmount (sfTakerGets, saOfferPays -= saSubTakerGot);
|
||||
|
||||
// Offer owner will get less. Subtract what owner just paid.
|
||||
sleOffer->setFieldAmount (sfTakerPays, saOfferGets -= saSubTakerPaid);
|
||||
|
||||
mEngine->entryModify (sleOffer);
|
||||
|
||||
if (bOfferDelete)
|
||||
{
|
||||
WriteLog (lsWARNING, OfferCreateTransactor) << "takeOffers: ILLEGAL OFFER RESULT.";
|
||||
bUnfunded = true;
|
||||
terResult = bOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING;
|
||||
// Offer now fully claimed or now unfunded.
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: Offer claimed: Delete.";
|
||||
|
||||
usOfferUnfundedBecame.insert (uOfferIndex); // Delete unfunded offer on success.
|
||||
|
||||
// Offer owner's account is no longer pristine.
|
||||
usAccountTouched.insert (uOfferOwnerID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Taker got nothing, probably due to rounding. Consider taker unfunded.
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: No claim.";
|
||||
|
||||
bUnfunded = true;
|
||||
terResult = tesSUCCESS; // Done.
|
||||
}
|
||||
|
||||
assert (uTakerGetsAccountID == saSubTakerGot.getIssuer ());
|
||||
assert (uTakerPaysAccountID == saSubTakerPaid.getIssuer ());
|
||||
|
||||
if (!bUnfunded)
|
||||
{
|
||||
// Distribute funds. The sends charge appropriate fees which are implied by offer.
|
||||
|
||||
terResult = lesActive.accountSend (uOfferOwnerID, uTakerAccountID, saSubTakerGot); // Offer owner pays taker.
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
terResult = lesActive.accountSend (uTakerAccountID, uOfferOwnerID, saSubTakerPaid); // Taker pays offer owner.
|
||||
|
||||
if (bSell)
|
||||
else if (saSubTakerGot)
|
||||
{
|
||||
// Sell semantics:
|
||||
// Reduce amount considered received to original offer's rate.
|
||||
// Not by crossing rate, which is higher.
|
||||
STAmount saEffectiveGot = STAmount::divide(saSubTakerPaid, saTakerRate, saTakerGets);
|
||||
saSubTakerGot = std::min(saEffectiveGot, saSubTakerGot);
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: Offer partial claim.";
|
||||
|
||||
if (!saOfferPays.isPositive () || !saOfferGets.isPositive ())
|
||||
{
|
||||
WriteLog (lsWARNING, OfferCreateTransactor) << "takeOffers: ILLEGAL OFFER RESULT.";
|
||||
bUnfunded = true;
|
||||
terResult = bOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Buy semantics: Reduce amount considered paid by taker's rate. Not by actual cost which is lower.
|
||||
// That is, take less as to just satify our buy requirement.
|
||||
STAmount saTakerCould = saTakerPays - saTakerPaid; // Taker could pay.
|
||||
// Taker got nothing, probably due to rounding. Consider taker unfunded.
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: No claim.";
|
||||
|
||||
if (saTakerFunds < saTakerCould)
|
||||
saTakerCould = saTakerFunds;
|
||||
|
||||
STAmount saTakerUsed = STAmount::multiply (saSubTakerGot, saTakerRate, saTakerPays);
|
||||
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerCould: " << saTakerCould.getFullText ();
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText ();
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerRate: " << saTakerRate.getFullText ();
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerUsed: " << saTakerUsed.getFullText ();
|
||||
|
||||
saSubTakerPaid = std::min (saTakerCould, saTakerUsed);
|
||||
bUnfunded = true;
|
||||
terResult = tesSUCCESS; // Done.
|
||||
}
|
||||
|
||||
saTakerPaid += saSubTakerPaid;
|
||||
saTakerGot += saSubTakerGot;
|
||||
assert (uTakerGetsAccountID == saSubTakerGot.getIssuer ());
|
||||
assert (uTakerPaysAccountID == saSubTakerPaid.getIssuer ());
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
terResult = temUNCERTAIN;
|
||||
if (!bUnfunded)
|
||||
{
|
||||
// Distribute funds. The sends charge appropriate fees which are implied by offer.
|
||||
|
||||
terResult = lesActive.accountSend (uOfferOwnerID, uTakerAccountID, saSubTakerGot); // Offer owner pays taker.
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
terResult = lesActive.accountSend (uTakerAccountID, uOfferOwnerID, saSubTakerPaid); // Taker pays offer owner.
|
||||
|
||||
if (bSell)
|
||||
{
|
||||
// Sell semantics:
|
||||
// Reduce amount considered received to original offer's rate.
|
||||
// Not by crossing rate, which is higher.
|
||||
STAmount saEffectiveGot = STAmount::divide(saSubTakerPaid, saTakerRate, saTakerGets);
|
||||
saSubTakerGot = std::min(saEffectiveGot, saSubTakerGot);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Buy semantics: Reduce amount considered paid by taker's rate. Not by actual cost which is lower.
|
||||
// That is, take less as to just satify our buy requirement.
|
||||
STAmount saTakerCould = saTakerPays - saTakerPaid; // Taker could pay.
|
||||
|
||||
if (saTakerFunds < saTakerCould)
|
||||
saTakerCould = saTakerFunds;
|
||||
|
||||
STAmount saTakerUsed = STAmount::multiply (saSubTakerGot, saTakerRate, saTakerPays);
|
||||
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerCould: " << saTakerCould.getFullText ();
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText ();
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerRate: " << saTakerRate.getFullText ();
|
||||
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: applyOffer: saTakerUsed: " << saTakerUsed.getFullText ();
|
||||
|
||||
saSubTakerPaid = std::min (saTakerCould, saTakerUsed);
|
||||
}
|
||||
|
||||
saTakerPaid += saSubTakerPaid;
|
||||
saTakerGot += saSubTakerGot;
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
terResult = temUNCERTAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLog (lsWARNING, OfferCreateTransactor) << "missing offer";
|
||||
// WRITEME: Remove the missing offer from the directory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user