mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Use sandbox for takerCross:
Using a PaymentSandbox for taker cross can cause transaction breaking changes. A PaymentSandbox uses a deferred credits table, which can cause tiny differences in computations.
This commit is contained in:
@@ -587,15 +587,15 @@ CreateOffer::step_account (OfferStream& stream, Taker const& taker)
|
|||||||
// the offer to left unfilled.
|
// the offer to left unfilled.
|
||||||
std::pair<TER, Amounts>
|
std::pair<TER, Amounts>
|
||||||
CreateOffer::takerCross (
|
CreateOffer::takerCross (
|
||||||
PaymentSandbox& psb,
|
Sandbox& sb,
|
||||||
PaymentSandbox& psbCancel,
|
Sandbox& sbCancel,
|
||||||
Amounts const& takerAmount)
|
Amounts const& takerAmount)
|
||||||
{
|
{
|
||||||
NetClock::time_point const when{ctx_.view().parentCloseTime()};
|
NetClock::time_point const when{ctx_.view().parentCloseTime()};
|
||||||
|
|
||||||
beast::WrappedSink takerSink (j_, "Taker ");
|
beast::WrappedSink takerSink (j_, "Taker ");
|
||||||
|
|
||||||
Taker taker (cross_type_, psb, account_, takerAmount,
|
Taker taker (cross_type_, sb, account_, takerAmount,
|
||||||
ctx_.tx.getFlags(), beast::Journal (takerSink));
|
ctx_.tx.getFlags(), beast::Journal (takerSink));
|
||||||
|
|
||||||
// If the taker is unfunded before we begin crossing
|
// If the taker is unfunded before we begin crossing
|
||||||
@@ -615,9 +615,9 @@ CreateOffer::takerCross (
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (cross_type_ == CrossType::IouToIou)
|
if (cross_type_ == CrossType::IouToIou)
|
||||||
return bridged_cross (taker, psb, psbCancel, when);
|
return bridged_cross (taker, sb, sbCancel, when);
|
||||||
|
|
||||||
return direct_cross (taker, psb, psbCancel, when);
|
return direct_cross (taker, sb, sbCancel, when);
|
||||||
}
|
}
|
||||||
catch (std::exception const& e)
|
catch (std::exception const& e)
|
||||||
{
|
{
|
||||||
@@ -825,13 +825,13 @@ static std::string to_string (SBoxCmp c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static SBoxCmp compareSandboxes (char const* name, ApplyContext const& ctx,
|
static SBoxCmp compareSandboxes (char const* name, ApplyContext const& ctx,
|
||||||
PaymentSandbox const& psbTaker, PaymentSandbox const& psbFlow,
|
detail::ApplyViewBase const& viewTaker, detail::ApplyViewBase const& viewFlow,
|
||||||
beast::Journal j)
|
beast::Journal j)
|
||||||
{
|
{
|
||||||
SBoxCmp c = SBoxCmp::same;
|
SBoxCmp c = SBoxCmp::same;
|
||||||
CashDiff diff = cashFlowDiff (
|
CashDiff diff = cashFlowDiff (
|
||||||
CashFilter::treatZeroOfferAsDeletion, psbTaker,
|
CashFilter::treatZeroOfferAsDeletion, viewTaker,
|
||||||
CashFilter::none, psbFlow);
|
CashFilter::none, viewFlow);
|
||||||
|
|
||||||
if (diff.hasDiff())
|
if (diff.hasDiff())
|
||||||
{
|
{
|
||||||
@@ -883,23 +883,23 @@ static SBoxCmp compareSandboxes (char const* name, ApplyContext const& ctx,
|
|||||||
|
|
||||||
std::pair<TER, Amounts>
|
std::pair<TER, Amounts>
|
||||||
CreateOffer::cross (
|
CreateOffer::cross (
|
||||||
PaymentSandbox& psb,
|
Sandbox& sb,
|
||||||
PaymentSandbox& psbCancel,
|
Sandbox& sbCancel,
|
||||||
Amounts const& takerAmount)
|
Amounts const& takerAmount)
|
||||||
{
|
{
|
||||||
// There are features for Flow offer crossing and for comparing results
|
// There are features for Flow offer crossing and for comparing results
|
||||||
// between Taker and Flow offer crossing. Turn those into bools.
|
// between Taker and Flow offer crossing. Turn those into bools.
|
||||||
bool const useFlowCross { psb.rules().enabled (featureFlowCross) };
|
bool const useFlowCross { sb.rules().enabled (featureFlowCross) };
|
||||||
bool const doCompare { psb.rules().enabled (featureCompareTakerFlowCross) };
|
bool const doCompare { sb.rules().enabled (featureCompareTakerFlowCross) };
|
||||||
|
|
||||||
PaymentSandbox psbTaker { &psb };
|
Sandbox sbTaker { &sb };
|
||||||
PaymentSandbox psbCancelTaker { &psbCancel };
|
Sandbox sbCancelTaker { &sbCancel };
|
||||||
auto const takerR = (!useFlowCross || doCompare)
|
auto const takerR = (!useFlowCross || doCompare)
|
||||||
? takerCross (psbTaker, psbCancelTaker, takerAmount)
|
? takerCross (sbTaker, sbCancelTaker, takerAmount)
|
||||||
: std::make_pair (tecINTERNAL, takerAmount);
|
: std::make_pair (tecINTERNAL, takerAmount);
|
||||||
|
|
||||||
PaymentSandbox psbFlow { &psb };
|
PaymentSandbox psbFlow { &sb };
|
||||||
PaymentSandbox psbCancelFlow { &psbCancel };
|
PaymentSandbox psbCancelFlow { &sbCancel };
|
||||||
auto const flowR = (useFlowCross || doCompare)
|
auto const flowR = (useFlowCross || doCompare)
|
||||||
? flowCross (psbFlow, psbCancelFlow, takerAmount)
|
? flowCross (psbFlow, psbCancelFlow, takerAmount)
|
||||||
: std::make_pair (tecINTERNAL, takerAmount);
|
: std::make_pair (tecINTERNAL, takerAmount);
|
||||||
@@ -917,7 +917,7 @@ CreateOffer::cross (
|
|||||||
(takerR.second.out == zero && flowR.second.out == zero))
|
(takerR.second.out == zero && flowR.second.out == zero))
|
||||||
{
|
{
|
||||||
c = compareSandboxes ("Both Taker and Flow fully crossed",
|
c = compareSandboxes ("Both Taker and Flow fully crossed",
|
||||||
ctx_, psbTaker, psbFlow, j_);
|
ctx_, sbTaker, psbFlow, j_);
|
||||||
}
|
}
|
||||||
else if (takerR.second.in == zero && takerR.second.out == zero)
|
else if (takerR.second.in == zero && takerR.second.out == zero)
|
||||||
{
|
{
|
||||||
@@ -926,7 +926,7 @@ CreateOffer::cross (
|
|||||||
flowR.second.out == takerAmount.out)
|
flowR.second.out == takerAmount.out)
|
||||||
crossType = "Taker fully crossed, Flow not crossed";
|
crossType = "Taker fully crossed, Flow not crossed";
|
||||||
|
|
||||||
c = compareSandboxes (crossType, ctx_, psbTaker, psbFlow, j_);
|
c = compareSandboxes (crossType, ctx_, sbTaker, psbFlow, j_);
|
||||||
}
|
}
|
||||||
else if (flowR.second.in == zero && flowR.second.out == zero)
|
else if (flowR.second.in == zero && flowR.second.out == zero)
|
||||||
{
|
{
|
||||||
@@ -936,12 +936,12 @@ CreateOffer::cross (
|
|||||||
takerR.second.out == takerAmount.out)
|
takerR.second.out == takerAmount.out)
|
||||||
crossType = "Taker not crossed, Flow fully crossed";
|
crossType = "Taker not crossed, Flow fully crossed";
|
||||||
|
|
||||||
c = compareSandboxes (crossType, ctx_, psbTaker, psbFlow, j_);
|
c = compareSandboxes (crossType, ctx_, sbTaker, psbFlow, j_);
|
||||||
}
|
}
|
||||||
else if (ctx_.tx.getFlags() & tfFillOrKill)
|
else if (ctx_.tx.getFlags() & tfFillOrKill)
|
||||||
{
|
{
|
||||||
c = compareSandboxes (
|
c = compareSandboxes (
|
||||||
"FillOrKill offer", ctx_, psbCancelTaker, psbCancelFlow, j_);
|
"FillOrKill offer", ctx_, sbCancelTaker, psbCancelFlow, j_);
|
||||||
}
|
}
|
||||||
else if (takerR.second.in == takerAmount.in &&
|
else if (takerR.second.in == takerAmount.in &&
|
||||||
flowR.second.in == takerAmount.in &&
|
flowR.second.in == takerAmount.in &&
|
||||||
@@ -949,24 +949,24 @@ CreateOffer::cross (
|
|||||||
flowR.second.out == takerAmount.out)
|
flowR.second.out == takerAmount.out)
|
||||||
{
|
{
|
||||||
char const * crossType = "Neither Taker nor Flow crossed";
|
char const * crossType = "Neither Taker nor Flow crossed";
|
||||||
c = compareSandboxes (crossType, ctx_, psbTaker, psbFlow, j_);
|
c = compareSandboxes (crossType, ctx_, sbTaker, psbFlow, j_);
|
||||||
}
|
}
|
||||||
else if (takerR.second.in == takerAmount.in &&
|
else if (takerR.second.in == takerAmount.in &&
|
||||||
takerR.second.out == takerAmount.out)
|
takerR.second.out == takerAmount.out)
|
||||||
{
|
{
|
||||||
char const * crossType = "Taker not crossed, Flow partially crossed";
|
char const * crossType = "Taker not crossed, Flow partially crossed";
|
||||||
c = compareSandboxes (crossType, ctx_, psbTaker, psbFlow, j_);
|
c = compareSandboxes (crossType, ctx_, sbTaker, psbFlow, j_);
|
||||||
}
|
}
|
||||||
else if (flowR.second.in == takerAmount.in &&
|
else if (flowR.second.in == takerAmount.in &&
|
||||||
flowR.second.out == takerAmount.out)
|
flowR.second.out == takerAmount.out)
|
||||||
{
|
{
|
||||||
char const * crossType = "Taker partially crossed, Flow not crossed";
|
char const * crossType = "Taker partially crossed, Flow not crossed";
|
||||||
c = compareSandboxes (crossType, ctx_, psbTaker, psbFlow, j_);
|
c = compareSandboxes (crossType, ctx_, sbTaker, psbFlow, j_);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
c = compareSandboxes (
|
c = compareSandboxes (
|
||||||
"Partial cross offer", ctx_, psbTaker, psbFlow, j_);
|
"Partial cross offer", ctx_, sbTaker, psbFlow, j_);
|
||||||
|
|
||||||
// If we've gotten this far then the returned amounts matter.
|
// If we've gotten this far then the returned amounts matter.
|
||||||
if (c <= SBoxCmp::dustDiff && takerR.second != flowR.second)
|
if (c <= SBoxCmp::dustDiff && takerR.second != flowR.second)
|
||||||
@@ -1003,13 +1003,13 @@ CreateOffer::cross (
|
|||||||
// Return one result or the other based on amendment.
|
// Return one result or the other based on amendment.
|
||||||
if (useFlowCross)
|
if (useFlowCross)
|
||||||
{
|
{
|
||||||
psbFlow.apply (psb);
|
psbFlow.apply (sb);
|
||||||
psbCancelFlow.apply (psbCancel);
|
psbCancelFlow.apply (sbCancel);
|
||||||
return flowR;
|
return flowR;
|
||||||
}
|
}
|
||||||
|
|
||||||
psbTaker.apply (psb);
|
sbTaker.apply (sb);
|
||||||
psbCancelTaker.apply (psbCancel);
|
sbCancelTaker.apply (sbCancel);
|
||||||
return takerR;
|
return takerR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1039,7 +1039,7 @@ CreateOffer::preCompute()
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::pair<TER, bool>
|
std::pair<TER, bool>
|
||||||
CreateOffer::applyGuts (PaymentSandbox& psb, PaymentSandbox& psbCancel)
|
CreateOffer::applyGuts (Sandbox& sb, Sandbox& sbCancel)
|
||||||
{
|
{
|
||||||
std::uint32_t const uTxFlags = ctx_.tx.getFlags ();
|
std::uint32_t const uTxFlags = ctx_.tx.getFlags ();
|
||||||
|
|
||||||
@@ -1070,7 +1070,7 @@ CreateOffer::applyGuts (PaymentSandbox& psb, PaymentSandbox& psbCancel)
|
|||||||
// Process a cancellation request that's passed along with an offer.
|
// Process a cancellation request that's passed along with an offer.
|
||||||
if (cancelSequence)
|
if (cancelSequence)
|
||||||
{
|
{
|
||||||
auto const sleCancel = psb.peek(
|
auto const sleCancel = sb.peek(
|
||||||
keylet::offer(account_, *cancelSequence));
|
keylet::offer(account_, *cancelSequence));
|
||||||
|
|
||||||
// It's not an error to not find the offer to cancel: it might have
|
// It's not an error to not find the offer to cancel: it might have
|
||||||
@@ -1079,7 +1079,7 @@ CreateOffer::applyGuts (PaymentSandbox& psb, PaymentSandbox& psbCancel)
|
|||||||
if (sleCancel)
|
if (sleCancel)
|
||||||
{
|
{
|
||||||
JLOG(j_.debug()) << "Create cancels order " << *cancelSequence;
|
JLOG(j_.debug()) << "Create cancels order " << *cancelSequence;
|
||||||
result = offerDelete (psb, sleCancel, viewJ);
|
result = offerDelete (sb, sleCancel, viewJ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1111,7 +1111,7 @@ CreateOffer::applyGuts (PaymentSandbox& psb, PaymentSandbox& psbCancel)
|
|||||||
if (!isXRP (uPaysIssuerID))
|
if (!isXRP (uPaysIssuerID))
|
||||||
{
|
{
|
||||||
auto const sle =
|
auto const sle =
|
||||||
psb.read(keylet::account(uPaysIssuerID));
|
sb.read(keylet::account(uPaysIssuerID));
|
||||||
if (sle && sle->isFieldPresent (sfTickSize))
|
if (sle && sle->isFieldPresent (sfTickSize))
|
||||||
uTickSize = std::min (uTickSize,
|
uTickSize = std::min (uTickSize,
|
||||||
(*sle)[sfTickSize]);
|
(*sle)[sfTickSize]);
|
||||||
@@ -1119,7 +1119,7 @@ CreateOffer::applyGuts (PaymentSandbox& psb, PaymentSandbox& psbCancel)
|
|||||||
if (!isXRP (uGetsIssuerID))
|
if (!isXRP (uGetsIssuerID))
|
||||||
{
|
{
|
||||||
auto const sle =
|
auto const sle =
|
||||||
psb.read(keylet::account(uGetsIssuerID));
|
sb.read(keylet::account(uGetsIssuerID));
|
||||||
if (sle && sle->isFieldPresent (sfTickSize))
|
if (sle && sle->isFieldPresent (sfTickSize))
|
||||||
uTickSize = std::min (uTickSize,
|
uTickSize = std::min (uTickSize,
|
||||||
(*sle)[sfTickSize]);
|
(*sle)[sfTickSize]);
|
||||||
@@ -1176,7 +1176,7 @@ CreateOffer::applyGuts (PaymentSandbox& psb, PaymentSandbox& psbCancel)
|
|||||||
stream << " out: " << format_amount (takerAmount.out);
|
stream << " out: " << format_amount (takerAmount.out);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tie(result, place_offer) = cross (psb, psbCancel, takerAmount);
|
std::tie(result, place_offer) = cross (sb, sbCancel, takerAmount);
|
||||||
|
|
||||||
// We expect the implementation of cross to succeed
|
// We expect the implementation of cross to succeed
|
||||||
// or give a tec.
|
// or give a tec.
|
||||||
@@ -1258,7 +1258,7 @@ CreateOffer::applyGuts (PaymentSandbox& psb, PaymentSandbox& psbCancel)
|
|||||||
return { tesSUCCESS, true };
|
return { tesSUCCESS, true };
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const sleCreator = psb.peek (keylet::account(account_));
|
auto const sleCreator = sb.peek (keylet::account(account_));
|
||||||
{
|
{
|
||||||
XRPAmount reserve = ctx_.view().fees().accountReserve(
|
XRPAmount reserve = ctx_.view().fees().accountReserve(
|
||||||
sleCreator->getFieldU32 (sfOwnerCount) + 1);
|
sleCreator->getFieldU32 (sfOwnerCount) + 1);
|
||||||
@@ -1287,14 +1287,14 @@ CreateOffer::applyGuts (PaymentSandbox& psb, PaymentSandbox& psbCancel)
|
|||||||
std::uint64_t uOwnerNode;
|
std::uint64_t uOwnerNode;
|
||||||
|
|
||||||
// Add offer to owner's directory.
|
// Add offer to owner's directory.
|
||||||
std::tie(result, std::ignore) = dirAdd(psb, uOwnerNode,
|
std::tie(result, std::ignore) = dirAdd(sb, uOwnerNode,
|
||||||
keylet::ownerDir (account_), offer_index,
|
keylet::ownerDir (account_), offer_index,
|
||||||
describeOwnerDir (account_), viewJ);
|
describeOwnerDir (account_), viewJ);
|
||||||
|
|
||||||
if (result == tesSUCCESS)
|
if (result == tesSUCCESS)
|
||||||
{
|
{
|
||||||
// Update owner count.
|
// Update owner count.
|
||||||
adjustOwnerCount(psb, sleCreator, 1, viewJ);
|
adjustOwnerCount(sb, sleCreator, 1, viewJ);
|
||||||
|
|
||||||
JLOG (j_.trace()) <<
|
JLOG (j_.trace()) <<
|
||||||
"adding to book: " << to_string (saTakerPays.issue ()) <<
|
"adding to book: " << to_string (saTakerPays.issue ()) <<
|
||||||
@@ -1308,7 +1308,7 @@ CreateOffer::applyGuts (PaymentSandbox& psb, PaymentSandbox& psbCancel)
|
|||||||
// before any crossing occured.
|
// before any crossing occured.
|
||||||
auto dir = keylet::quality (keylet::book (book), uRate);
|
auto dir = keylet::quality (keylet::book (book), uRate);
|
||||||
|
|
||||||
std::tie(result, isNewBook) = dirAdd (psb, uBookNode,
|
std::tie(result, isNewBook) = dirAdd (sb, uBookNode,
|
||||||
dir, offer_index, [&](SLE::ref sle)
|
dir, offer_index, [&](SLE::ref sle)
|
||||||
{
|
{
|
||||||
sle->setFieldH160 (sfTakerPaysCurrency,
|
sle->setFieldH160 (sfTakerPaysCurrency,
|
||||||
@@ -1338,7 +1338,7 @@ CreateOffer::applyGuts (PaymentSandbox& psb, PaymentSandbox& psbCancel)
|
|||||||
sleOffer->setFlag (lsfPassive);
|
sleOffer->setFlag (lsfPassive);
|
||||||
if (bSell)
|
if (bSell)
|
||||||
sleOffer->setFlag (lsfSell);
|
sleOffer->setFlag (lsfSell);
|
||||||
psb.insert(sleOffer);
|
sb.insert(sleOffer);
|
||||||
|
|
||||||
if (isNewBook)
|
if (isNewBook)
|
||||||
ctx_.app.getOrderBookDB().addOrderBook(book);
|
ctx_.app.getOrderBookDB().addOrderBook(book);
|
||||||
@@ -1359,18 +1359,18 @@ CreateOffer::doApply()
|
|||||||
{
|
{
|
||||||
// This is the ledger view that we work against. Transactions are applied
|
// This is the ledger view that we work against. Transactions are applied
|
||||||
// as we go on processing transactions.
|
// as we go on processing transactions.
|
||||||
PaymentSandbox psb (&ctx_.view());
|
Sandbox sb (&ctx_.view());
|
||||||
|
|
||||||
// This is a ledger with just the fees paid and any unfunded or expired
|
// This is a ledger with just the fees paid and any unfunded or expired
|
||||||
// offers we encounter removed. It's used when handling Fill-or-Kill offers,
|
// offers we encounter removed. It's used when handling Fill-or-Kill offers,
|
||||||
// if the order isn't going to be placed, to avoid wasting the work we did.
|
// if the order isn't going to be placed, to avoid wasting the work we did.
|
||||||
PaymentSandbox psbCancel (&ctx_.view());
|
Sandbox sbCancel (&ctx_.view());
|
||||||
|
|
||||||
auto const result = applyGuts(psb, psbCancel);
|
auto const result = applyGuts(sb, sbCancel);
|
||||||
if (result.second)
|
if (result.second)
|
||||||
psb.apply(ctx_.rawView());
|
sb.apply(ctx_.rawView());
|
||||||
else
|
else
|
||||||
psbCancel.apply(ctx_.rawView());
|
sbCancel.apply(ctx_.rawView());
|
||||||
return result.first;
|
return result.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
class PaymentSandbox;
|
class PaymentSandbox;
|
||||||
|
class Sandbox;
|
||||||
|
|
||||||
/** Transactor specialized for creating offers in the ledger. */
|
/** Transactor specialized for creating offers in the ledger. */
|
||||||
class CreateOffer
|
class CreateOffer
|
||||||
@@ -66,7 +67,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::pair<TER, bool>
|
std::pair<TER, bool>
|
||||||
applyGuts (PaymentSandbox& view, PaymentSandbox& view_cancel);
|
applyGuts (Sandbox& view, Sandbox& view_cancel);
|
||||||
|
|
||||||
// Determine if we are authorized to hold the asset we want to get.
|
// Determine if we are authorized to hold the asset we want to get.
|
||||||
static
|
static
|
||||||
@@ -116,8 +117,8 @@ private:
|
|||||||
// Charges fees on top to taker.
|
// Charges fees on top to taker.
|
||||||
std::pair<TER, Amounts>
|
std::pair<TER, Amounts>
|
||||||
takerCross (
|
takerCross (
|
||||||
PaymentSandbox& psb,
|
Sandbox& sb,
|
||||||
PaymentSandbox& psbCancel,
|
Sandbox& sbCancel,
|
||||||
Amounts const& takerAmount);
|
Amounts const& takerAmount);
|
||||||
|
|
||||||
// Use the payment flow code to perform offer crossing.
|
// Use the payment flow code to perform offer crossing.
|
||||||
@@ -133,8 +134,8 @@ private:
|
|||||||
// removed once flowCross is determined to be stable.
|
// removed once flowCross is determined to be stable.
|
||||||
std::pair<TER, Amounts>
|
std::pair<TER, Amounts>
|
||||||
cross (
|
cross (
|
||||||
PaymentSandbox& psb,
|
Sandbox& sb,
|
||||||
PaymentSandbox& psbCancel,
|
Sandbox& sbCancel,
|
||||||
Amounts const& takerAmount);
|
Amounts const& takerAmount);
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|||||||
Reference in New Issue
Block a user