mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-25 05:25:55 +00:00
Abstract valid offer testing in OfferCreate.
This commit is contained in:
@@ -7,6 +7,80 @@
|
|||||||
|
|
||||||
SETUP_LOG();
|
SETUP_LOG();
|
||||||
|
|
||||||
|
// Make sure an offer is still valid. If not, mark it unfunded.
|
||||||
|
bool OfferCreateTransactor::bValidOffer(
|
||||||
|
SLE::ref sleOfferDir,
|
||||||
|
const uint256& uOfferIndex,
|
||||||
|
const uint160& uOfferOwnerID,
|
||||||
|
const STAmount& saOfferPays,
|
||||||
|
const STAmount& saOfferGets,
|
||||||
|
const uint160& uTakerAccountID,
|
||||||
|
boost::unordered_set<uint256>& usOfferUnfundedFound,
|
||||||
|
boost::unordered_set<uint256>& usOfferUnfundedBecame,
|
||||||
|
boost::unordered_set<uint160>& usAccountTouched,
|
||||||
|
STAmount& saOfferFunds) { // <--
|
||||||
|
bool bValid;
|
||||||
|
|
||||||
|
if (sleOfferDir->isFieldPresent(sfExpiration) && sleOfferDir->getFieldU32(sfExpiration) <= mEngine->getLedger()->getParentCloseTimeNC())
|
||||||
|
{
|
||||||
|
// Offer is expired. Expired offers are considered unfunded. Delete it.
|
||||||
|
cLog(lsINFO) << "bValidOffer: encountered expired offer";
|
||||||
|
|
||||||
|
usOfferUnfundedFound.insert(uOfferIndex);
|
||||||
|
|
||||||
|
bValid = false;
|
||||||
|
}
|
||||||
|
else if (uOfferOwnerID == uTakerAccountID)
|
||||||
|
{
|
||||||
|
// Would take own offer. Consider old offer expired. Delete it.
|
||||||
|
cLog(lsINFO) << "bValidOffer: encountered taker's own old offer";
|
||||||
|
|
||||||
|
usOfferUnfundedFound.insert(uOfferIndex);
|
||||||
|
|
||||||
|
bValid = false;
|
||||||
|
}
|
||||||
|
else if (!saOfferGets.isPositive() || !saOfferPays.isPositive())
|
||||||
|
{
|
||||||
|
// Offer has bad amounts. Consider offer expired. Delete it.
|
||||||
|
cLog(lsWARNING) << boost::str(boost::format("bValidOffer: BAD OFFER: saOfferPays=%s saOfferGets=%s")
|
||||||
|
% saOfferPays % saOfferGets);
|
||||||
|
|
||||||
|
usOfferUnfundedFound.insert(uOfferIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cLog(lsINFO) << "bValidOffer: saOfferPays=" << saOfferPays.getFullText();
|
||||||
|
|
||||||
|
saOfferFunds = mEngine->getNodes().accountFunds(uOfferOwnerID, saOfferPays);
|
||||||
|
|
||||||
|
if (!saOfferFunds.isPositive())
|
||||||
|
{
|
||||||
|
// Offer is unfunded, possibly due to previous balance action.
|
||||||
|
cLog(lsINFO) << "bValidOffer: offer unfunded: delete";
|
||||||
|
|
||||||
|
boost::unordered_set<uint160>::iterator account = usAccountTouched.find(uOfferOwnerID);
|
||||||
|
if (account != usAccountTouched.end())
|
||||||
|
{
|
||||||
|
// Previously touched account.
|
||||||
|
usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Never touched source account.
|
||||||
|
usOfferUnfundedFound.insert(uOfferIndex); // Delete found unfunded offer when possible.
|
||||||
|
}
|
||||||
|
|
||||||
|
bValid = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bValid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bValid;
|
||||||
|
}
|
||||||
|
|
||||||
// Take as much as possible. Adjusts account balances. Charges fees on top to taker.
|
// Take as much as possible. Adjusts account balances. Charges fees on top to taker.
|
||||||
// --> uBookBase: The order book to take against.
|
// --> uBookBase: The order book to take against.
|
||||||
// --> saTakerPays: What the taker offers (w/ issuer)
|
// --> saTakerPays: What the taker offers (w/ issuer)
|
||||||
@@ -28,7 +102,7 @@ TER OfferCreateTransactor::takeOffers(
|
|||||||
bool& bUnfunded)
|
bool& bUnfunded)
|
||||||
{
|
{
|
||||||
// The book has the most elements. Take the perspective of the book.
|
// The book has the most elements. Take the perspective of the book.
|
||||||
// Book is ordered for taker: taker pays / taker gets, < is better
|
// Book is ordered for taker: taker pays / taker gets (smaller is better)
|
||||||
|
|
||||||
// The order is for the other books currencys for get and pays are opposites.
|
// The order is for the other books currencys for get and pays are opposites.
|
||||||
// We want the same ratio for the respective currencies.
|
// We want the same ratio for the respective currencies.
|
||||||
@@ -141,162 +215,121 @@ TER OfferCreateTransactor::takeOffers(
|
|||||||
STAmount saOfferPays = sleOffer->getFieldAmount(sfTakerGets);
|
STAmount saOfferPays = sleOffer->getFieldAmount(sfTakerGets);
|
||||||
STAmount saOfferGets = sleOffer->getFieldAmount(sfTakerPays);
|
STAmount saOfferGets = sleOffer->getFieldAmount(sfTakerPays);
|
||||||
|
|
||||||
if (sleOffer->isFieldPresent(sfExpiration) && sleOffer->getFieldU32(sfExpiration) <= mEngine->getLedger()->getParentCloseTimeNC())
|
STAmount saOfferFunds; // Funds of offer owner to payout.
|
||||||
{
|
bool bValid;
|
||||||
// Offer is expired. Expired offers are considered unfunded. Delete it.
|
|
||||||
cLog(lsINFO) << "takeOffers: encountered expired offer";
|
|
||||||
|
|
||||||
usOfferUnfundedFound.insert(uOfferIndex);
|
bValid = bValidOffer(
|
||||||
}
|
sleOfferDir, uOfferIndex, uOfferOwnerID, saOfferPays, saOfferGets,
|
||||||
else if (uOfferOwnerID == uTakerAccountID)
|
uTakerAccountID,
|
||||||
{
|
usOfferUnfundedFound, usOfferUnfundedBecame, usAccountTouched,
|
||||||
// Would take own offer. Consider old offer expired. Delete it.
|
saOfferFunds);
|
||||||
cLog(lsINFO) << "takeOffers: encountered taker's own old offer";
|
|
||||||
|
|
||||||
usOfferUnfundedBecame.insert(uOfferIndex);
|
if (bValid) {
|
||||||
}
|
STAmount saSubTakerPaid;
|
||||||
else if (!saOfferGets.isPositive() || !saOfferPays.isPositive())
|
STAmount saSubTakerGot;
|
||||||
{
|
STAmount saTakerIssuerFee;
|
||||||
// Offer has bad amounts. Consider offer expired. Delete it.
|
STAmount saOfferIssuerFee;
|
||||||
cLog(lsWARNING) << boost::str(boost::format("takeOffers: BAD OFFER: saOfferPays=%s saOfferGets=%s")
|
STAmount saOfferRate = STAmount::setRate(uTipQuality);
|
||||||
% saOfferPays % saOfferGets);
|
|
||||||
|
|
||||||
usOfferUnfundedFound.insert(uOfferIndex);
|
cLog(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText();
|
||||||
}
|
cLog(lsINFO) << "takeOffers: applyOffer: saTakerPaid: " << saTakerPaid.getFullText();
|
||||||
else
|
cLog(lsINFO) << "takeOffers: applyOffer: saTakerFunds: " << saTakerFunds.getFullText();
|
||||||
{
|
cLog(lsINFO) << "takeOffers: applyOffer: saOfferFunds: " << saOfferFunds.getFullText();
|
||||||
// Get offer funds available.
|
cLog(lsINFO) << "takeOffers: applyOffer: saOfferPays: " << saOfferPays.getFullText();
|
||||||
|
cLog(lsINFO) << "takeOffers: applyOffer: saOfferGets: " << saOfferGets.getFullText();
|
||||||
|
cLog(lsINFO) << "takeOffers: applyOffer: saOfferRate: " << saOfferRate.getFullText();
|
||||||
|
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerPays: " << saSubTakerPays.getFullText();
|
||||||
|
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerGets: " << saSubTakerGets.getFullText();
|
||||||
|
cLog(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText();
|
||||||
|
cLog(lsINFO) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText();
|
||||||
|
|
||||||
cLog(lsINFO) << "takeOffers: saOfferPays=" << saOfferPays.getFullText();
|
bool bOfferDelete = STAmount::applyOffer(
|
||||||
|
lesActive.rippleTransferRate(uTakerAccountID, uOfferOwnerID, uTakerPaysAccountID),
|
||||||
|
lesActive.rippleTransferRate(uOfferOwnerID, uTakerAccountID, uTakerGetsAccountID),
|
||||||
|
saOfferRate,
|
||||||
|
saOfferFunds,
|
||||||
|
saTakerFunds,
|
||||||
|
saOfferPays,
|
||||||
|
saOfferGets,
|
||||||
|
saSubTakerPays,
|
||||||
|
saSubTakerGets,
|
||||||
|
saSubTakerPaid,
|
||||||
|
saSubTakerGot,
|
||||||
|
saTakerIssuerFee,
|
||||||
|
saOfferIssuerFee);
|
||||||
|
|
||||||
STAmount saOfferFunds = lesActive.accountFunds(uOfferOwnerID, saOfferPays);
|
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerPaid: " << saSubTakerPaid.getFullText();
|
||||||
SLE::pointer sleOfferAccount; // Owner of offer.
|
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText();
|
||||||
|
|
||||||
if (!saOfferFunds.isPositive()) // Includes zero.
|
// 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)
|
||||||
{
|
{
|
||||||
// Offer is unfunded, possibly due to previous balance action.
|
// Offer now fully claimed or now unfunded.
|
||||||
cLog(lsINFO) << "takeOffers: offer unfunded: delete";
|
cLog(lsINFO) << "takeOffers: Offer claimed: Delete.";
|
||||||
|
|
||||||
boost::unordered_set<uint160>::iterator account = usAccountTouched.find(uOfferOwnerID);
|
usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success.
|
||||||
if (account != usAccountTouched.end())
|
|
||||||
|
// Offer owner's account is no longer pristine.
|
||||||
|
usAccountTouched.insert(uOfferOwnerID);
|
||||||
|
}
|
||||||
|
else if (saSubTakerGot)
|
||||||
|
{
|
||||||
|
cLog(lsINFO) << "takeOffers: Offer partial claim.";
|
||||||
|
|
||||||
|
if (!saOfferPays.isPositive() || !saOfferGets.isPositive())
|
||||||
{
|
{
|
||||||
// Previously touched account.
|
cLog(lsWARNING) << "takeOffers: ILLEGAL OFFER RESULT.";
|
||||||
usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success.
|
bUnfunded = true;
|
||||||
}
|
terResult = bOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING;
|
||||||
else
|
|
||||||
{
|
|
||||||
// Never touched source account.
|
|
||||||
usOfferUnfundedFound.insert(uOfferIndex); // Delete found unfunded offer when possible.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
STAmount saSubTakerPaid;
|
// Taker got nothing, probably due to rounding. Consider taker unfunded.
|
||||||
STAmount saSubTakerGot;
|
cLog(lsINFO) << "takeOffers: No claim.";
|
||||||
STAmount saTakerIssuerFee;
|
|
||||||
STAmount saOfferIssuerFee;
|
|
||||||
STAmount saOfferRate = STAmount::setRate(uTipQuality);
|
|
||||||
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText();
|
bUnfunded = true;
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerPaid: " << saTakerPaid.getFullText();
|
terResult = tesSUCCESS; // Done.
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerFunds: " << saTakerFunds.getFullText();
|
}
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saOfferFunds: " << saOfferFunds.getFullText();
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saOfferPays: " << saOfferPays.getFullText();
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saOfferGets: " << saOfferGets.getFullText();
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saOfferRate: " << saOfferRate.getFullText();
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerPays: " << saSubTakerPays.getFullText();
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerGets: " << saSubTakerGets.getFullText();
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText();
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText();
|
|
||||||
|
|
||||||
bool bOfferDelete = STAmount::applyOffer(
|
assert(uTakerGetsAccountID == saSubTakerGot.getIssuer());
|
||||||
lesActive.rippleTransferRate(uTakerAccountID, uOfferOwnerID, uTakerPaysAccountID),
|
assert(uTakerPaysAccountID == saSubTakerPaid.getIssuer());
|
||||||
lesActive.rippleTransferRate(uOfferOwnerID, uTakerAccountID, uTakerGetsAccountID),
|
|
||||||
saOfferRate,
|
|
||||||
saOfferFunds,
|
|
||||||
saTakerFunds,
|
|
||||||
saOfferPays,
|
|
||||||
saOfferGets,
|
|
||||||
saSubTakerPays,
|
|
||||||
saSubTakerGets,
|
|
||||||
saSubTakerPaid,
|
|
||||||
saSubTakerGot,
|
|
||||||
saTakerIssuerFee,
|
|
||||||
saOfferIssuerFee);
|
|
||||||
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerPaid: " << saSubTakerPaid.getFullText();
|
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.
|
||||||
|
|
||||||
|
// Reduce amount considered paid by taker's rate (not actual cost).
|
||||||
|
STAmount saTakerCould = saTakerPays - saTakerPaid; // Taker could pay.
|
||||||
|
if (saTakerFunds < saTakerCould)
|
||||||
|
saTakerCould = saTakerFunds;
|
||||||
|
|
||||||
|
STAmount saTakerUsed = STAmount::multiply(saSubTakerGot, saTakerRate, saTakerPays);
|
||||||
|
|
||||||
|
cLog(lsINFO) << "takeOffers: applyOffer: saTakerCould: " << saTakerCould.getFullText();
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText();
|
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText();
|
||||||
|
cLog(lsINFO) << "takeOffers: applyOffer: saTakerRate: " << saTakerRate.getFullText();
|
||||||
|
cLog(lsINFO) << "takeOffers: applyOffer: saTakerUsed: " << saTakerUsed.getFullText();
|
||||||
|
|
||||||
// Adjust offer
|
saTakerPaid += std::min(saTakerCould, saTakerUsed);
|
||||||
|
saTakerGot += saSubTakerGot;
|
||||||
|
|
||||||
// Offer owner will pay less. Subtract what taker just got.
|
if (tesSUCCESS == terResult)
|
||||||
sleOffer->setFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot);
|
terResult = temUNCERTAIN;
|
||||||
|
|
||||||
// Offer owner will get less. Subtract what owner just paid.
|
|
||||||
sleOffer->setFieldAmount(sfTakerPays, saOfferGets -= saSubTakerPaid);
|
|
||||||
|
|
||||||
mEngine->entryModify(sleOffer);
|
|
||||||
|
|
||||||
if (bOfferDelete)
|
|
||||||
{
|
|
||||||
// Offer now fully claimed or now unfunded.
|
|
||||||
cLog(lsINFO) << "takeOffers: Offer claimed: Delete.";
|
|
||||||
|
|
||||||
usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success.
|
|
||||||
|
|
||||||
// Offer owner's account is no longer pristine.
|
|
||||||
usAccountTouched.insert(uOfferOwnerID);
|
|
||||||
}
|
|
||||||
else if (saSubTakerGot)
|
|
||||||
{
|
|
||||||
cLog(lsINFO) << "takeOffers: Offer partial claim.";
|
|
||||||
|
|
||||||
if (!saOfferPays.isPositive() || !saOfferGets.isPositive())
|
|
||||||
{
|
|
||||||
cLog(lsWARNING) << "takeOffers: ILLEGAL OFFER RESULT.";
|
|
||||||
bUnfunded = true;
|
|
||||||
terResult = bOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Taker got nothing, probably due to rounding. Consider taker unfunded.
|
|
||||||
cLog(lsINFO) << "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.
|
|
||||||
|
|
||||||
// Reduce amount considered paid by taker's rate (not actual cost).
|
|
||||||
STAmount saTakerCould = saTakerPays - saTakerPaid; // Taker could pay.
|
|
||||||
if (saTakerFunds < saTakerCould)
|
|
||||||
saTakerCould = saTakerFunds;
|
|
||||||
|
|
||||||
STAmount saTakerUsed = STAmount::multiply(saSubTakerGot, saTakerRate, saTakerPays);
|
|
||||||
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerCould: " << saTakerCould.getFullText();
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText();
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerRate: " << saTakerRate.getFullText();
|
|
||||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerUsed: " << saTakerUsed.getFullText();
|
|
||||||
|
|
||||||
saTakerPaid += std::min(saTakerCould, saTakerUsed);
|
|
||||||
saTakerGot += saSubTakerGot;
|
|
||||||
|
|
||||||
if (tesSUCCESS == terResult)
|
|
||||||
terResult = temUNCERTAIN;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,18 @@
|
|||||||
class OfferCreateTransactor : public Transactor
|
class OfferCreateTransactor : public Transactor
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
bool bValidOffer(
|
||||||
|
SLE::ref sleOfferDir,
|
||||||
|
const uint256& uOffer,
|
||||||
|
const uint160& uOfferOwnerID,
|
||||||
|
const STAmount& saOfferPays,
|
||||||
|
const STAmount& saOfferGets,
|
||||||
|
const uint160& uTakerAccountID,
|
||||||
|
boost::unordered_set<uint256>& usOfferUnfundedFound,
|
||||||
|
boost::unordered_set<uint256>& usOfferUnfundedBecame,
|
||||||
|
boost::unordered_set<uint160>& usAccountTouched,
|
||||||
|
STAmount& saOfferFunds);
|
||||||
|
|
||||||
TER takeOffers(
|
TER takeOffers(
|
||||||
const bool bOpenLedger,
|
const bool bOpenLedger,
|
||||||
const bool bPassive,
|
const bool bPassive,
|
||||||
|
|||||||
Reference in New Issue
Block a user