Use enums for some parameters in payments:

* Use enums for StrandDirection, DebtDirection, and QualityDirection
This commit is contained in:
seelabs
2019-07-29 13:17:26 -07:00
committed by Nik Bougalis
parent c217baa367
commit 561942da23
5 changed files with 206 additions and 138 deletions

View File

@@ -110,10 +110,11 @@ public:
return EitherAmount (cache_->out); return EitherAmount (cache_->out);
} }
bool DebtDirection
redeems (ReadView const& sb, bool fwd) const override debtDirection(ReadView const& sb, StrandDirection dir) const override
{ {
return !ownerPaysTransferFee_; return ownerPaysTransferFee_ ? DebtDirection::issues
: DebtDirection::redeems;
} }
boost::optional<Book> boost::optional<Book>
@@ -123,7 +124,7 @@ public:
} }
boost::optional<Quality> boost::optional<Quality>
qualityUpperBound(ReadView const& v, bool& redeems) const override; qualityUpperBound(ReadView const& v, DebtDirection& dir) const override;
std::pair<TIn, TOut> std::pair<TIn, TOut>
revImp ( revImp (
@@ -188,7 +189,7 @@ private:
forEachOffer ( forEachOffer (
PaymentSandbox& sb, PaymentSandbox& sb,
ApplyView& afView, ApplyView& afView,
bool prevStepRedeems, DebtDirection prevStepDebtDir,
Callback& callback) const; Callback& callback) const;
void consumeOffer (PaymentSandbox& sb, void consumeOffer (PaymentSandbox& sb,
@@ -248,7 +249,7 @@ public:
Quality Quality
qualityUpperBound(ReadView const& v, qualityUpperBound(ReadView const& v,
Quality const& ofrQ, Quality const& ofrQ,
bool prevStepRedeems) const DebtDirection prevStepDir) const
{ {
// Charge the offer owner, not the sender // Charge the offer owner, not the sender
// Charge a fee even if the owner is the same as the issuer // Charge a fee even if the owner is the same as the issuer
@@ -262,7 +263,7 @@ public:
}; };
auto const trIn = auto const trIn =
prevStepRedeems ? rate(this->book_.in.account) : parityRate; redeems(prevStepDir) ? rate(this->book_.in.account) : parityRate;
// Always charge the transfer fee, even if the owner is the issuer // Always charge the transfer fee, even if the owner is the issuer
auto const trOut = auto const trOut =
this->ownerPaysTransferFee_ this->ownerPaysTransferFee_
@@ -393,7 +394,7 @@ public:
Quality Quality
qualityUpperBound(ReadView const& v, qualityUpperBound(ReadView const& v,
Quality const& ofrQ, Quality const& ofrQ,
bool prevStepRedeems) const DebtDirection prevStepDir) const
{ {
// Offer x-ing does not charge a transfer fee when the offer's owner // Offer x-ing does not charge a transfer fee when the offer's owner
// is the same as the strand dst. It is important that `qualityUpperBound` // is the same as the strand dst. It is important that `qualityUpperBound`
@@ -427,10 +428,10 @@ bool BookStep<TIn, TOut, TDerived>::equal (Step const& rhs) const
template <class TIn, class TOut, class TDerived> template <class TIn, class TOut, class TDerived>
boost::optional<Quality> boost::optional<Quality>
BookStep<TIn, TOut, TDerived>::qualityUpperBound( BookStep<TIn, TOut, TDerived>::qualityUpperBound(
ReadView const& v, bool& redeems) const ReadView const& v, DebtDirection& dir) const
{ {
auto const prevStepRedeems = redeems; auto const prevStepDir = dir;
redeems = this->redeems(v, true); dir = this->debtDirection(v, StrandDirection::forward);
// This can be simplified (and sped up) if directories are never empty. // This can be simplified (and sped up) if directories are never empty.
Sandbox sb(&v, tapNONE); Sandbox sb(&v, tapNONE);
@@ -439,7 +440,7 @@ BookStep<TIn, TOut, TDerived>::qualityUpperBound(
return boost::none; return boost::none;
return static_cast<TDerived const*>(this)->qualityUpperBound( return static_cast<TDerived const*>(this)->qualityUpperBound(
v, bt.quality(), prevStepRedeems); v, bt.quality(), prevStepDir);
} }
// Adjust the offer amount and step amount subject to the given input limit // Adjust the offer amount and step amount subject to the given input limit
@@ -493,7 +494,7 @@ std::pair<boost::container::flat_set<uint256>, std::uint32_t>
BookStep<TIn, TOut, TDerived>::forEachOffer ( BookStep<TIn, TOut, TDerived>::forEachOffer (
PaymentSandbox& sb, PaymentSandbox& sb,
ApplyView& afView, ApplyView& afView,
bool prevStepRedeems, DebtDirection prevStepDir,
Callback& callback) const Callback& callback) const
{ {
// Charge the offer owner, not the sender // Charge the offer owner, not the sender
@@ -507,9 +508,8 @@ BookStep<TIn, TOut, TDerived>::forEachOffer (
return transferRate (sb, id).value; return transferRate (sb, id).value;
}; };
std::uint32_t const trIn = prevStepRedeems std::uint32_t const trIn =
? rate (book_.in.account) redeems(prevStepDir) ? rate(book_.in.account) : QUALITY_ONE;
: QUALITY_ONE;
// Always charge the transfer fee, even if the owner is the issuer // Always charge the transfer fee, even if the owner is the issuer
std::uint32_t const trOut = ownerPaysTransferFee_ std::uint32_t const trOut = ownerPaysTransferFee_
? rate (book_.out.account) ? rate (book_.out.account)
@@ -726,8 +726,12 @@ BookStep<TIn, TOut, TDerived>::revImp (
}; };
{ {
auto const prevStepRedeems = prevStep_ && prevStep_->redeems (sb, false); auto const prevStepDebtDir = [&]{
auto const r = forEachOffer (sb, afView, prevStepRedeems, eachOffer); if (prevStep_)
return prevStep_->debtDirection (sb, StrandDirection::reverse);
return DebtDirection::issues;
}();
auto const r = forEachOffer (sb, afView, prevStepDebtDir, eachOffer);
boost::container::flat_set<uint256> toRm = std::move(std::get<0>(r)); boost::container::flat_set<uint256> toRm = std::move(std::get<0>(r));
std::uint32_t const offersConsumed = std::get<1>(r); std::uint32_t const offersConsumed = std::get<1>(r);
SetUnion(ofrsToRm, toRm); SetUnion(ofrsToRm, toRm);
@@ -887,8 +891,12 @@ BookStep<TIn, TOut, TDerived>::fwdImp (
}; };
{ {
auto const prevStepRedeems = prevStep_ && prevStep_->redeems (sb, true); auto const prevStepDebtDir = [&] {
auto const r = forEachOffer (sb, afView, prevStepRedeems, eachOffer); if (prevStep_)
return prevStep_->debtDirection(sb, StrandDirection::forward);
return DebtDirection::issues;
}();
auto const r = forEachOffer(sb, afView, prevStepDebtDir, eachOffer);
boost::container::flat_set<uint256> toRm = std::move(std::get<0>(r)); boost::container::flat_set<uint256> toRm = std::move(std::get<0>(r));
std::uint32_t const offersConsumed = std::get<1>(r); std::uint32_t const offersConsumed = std::get<1>(r);
SetUnion(ofrsToRm, toRm); SetUnion(ofrsToRm, toRm);

View File

@@ -26,6 +26,7 @@
#include <ripple/protocol/Quality.h> #include <ripple/protocol/Quality.h>
#include <boost/container/flat_set.hpp> #include <boost/container/flat_set.hpp>
#include <boost/optional.hpp>
#include <numeric> #include <numeric>
#include <sstream> #include <sstream>
@@ -50,17 +51,17 @@ protected:
IOUAmount in; IOUAmount in;
IOUAmount srcToDst; IOUAmount srcToDst;
IOUAmount out; IOUAmount out;
bool srcRedeems; DebtDirection srcDebtDir;
Cache ( Cache (
IOUAmount const& in_, IOUAmount const& in_,
IOUAmount const& srcToDst_, IOUAmount const& srcToDst_,
IOUAmount const& out_, IOUAmount const& out_,
bool srcRedeems_) DebtDirection srcDebtDir_)
: in(in_) : in(in_)
, srcToDst(srcToDst_) , srcToDst(srcToDst_)
, out(out_) , out(out_)
, srcRedeems(srcRedeems_) , srcDebtDir(srcDebtDir_)
{} {}
}; };
@@ -69,17 +70,28 @@ protected:
// Compute the maximum value that can flow from src->dst at // Compute the maximum value that can flow from src->dst at
// the best available quality. // the best available quality.
// return: first element is max amount that can flow, // return: first element is max amount that can flow,
// second is true if dst holds an iou from src. // second is the debt direction of the source w.r.t. the dst
std::pair<IOUAmount, bool> std::pair<IOUAmount, DebtDirection>
maxPaymentFlow ( maxPaymentFlow (
ReadView const& sb) const; ReadView const& sb) const;
// Compute srcQOut and dstQIn when the source redeems.
std::pair<std::uint32_t, std::uint32_t>
qualitiesSrcRedeems(
ReadView const& sb) const;
// Compute srcQOut and dstQIn when the source issues.
std::pair<std::uint32_t, std::uint32_t>
qualitiesSrcIssues(
ReadView const& sb,
DebtDirection prevStepDebtDirection) const;
// Returns srcQOut, dstQIn // Returns srcQOut, dstQIn
std::pair <std::uint32_t, std::uint32_t> std::pair <std::uint32_t, std::uint32_t>
qualities ( qualities (
ReadView const& sb, ReadView const& sb,
bool srcRedeems, DebtDirection srcDebtDir,
bool fwd) const; StrandDirection strandDir) const;
public: public:
DirectStepI ( DirectStepI (
@@ -135,14 +147,14 @@ public:
return std::make_pair(src_, dst_); return std::make_pair(src_, dst_);
} }
bool DebtDirection
redeems (ReadView const& sb, bool fwd) const override; debtDirection (ReadView const& sb, StrandDirection dir) const override;
std::uint32_t std::uint32_t
lineQualityIn (ReadView const& v) const override; lineQualityIn (ReadView const& v) const override;
boost::optional<Quality> boost::optional<Quality>
qualityUpperBound(ReadView const& v, bool& redeems) const override; qualityUpperBound(ReadView const& v, DebtDirection& dir) const override;
std::pair<IOUAmount, IOUAmount> std::pair<IOUAmount, IOUAmount>
revImp ( revImp (
@@ -172,7 +184,7 @@ public:
IOUAmount const& fwdIn, IOUAmount const& fwdIn,
IOUAmount const& fwdSrcToDst, IOUAmount const& fwdSrcToDst,
IOUAmount const& fwdOut, IOUAmount const& fwdOut,
bool srcRedeems); DebtDirection srcDebtDir);
friend bool operator==(DirectStepI const& lhs, DirectStepI const& rhs) friend bool operator==(DirectStepI const& lhs, DirectStepI const& rhs)
{ {
@@ -223,7 +235,7 @@ public:
using DirectStepI<DirectIPaymentStep>::DirectStepI; using DirectStepI<DirectIPaymentStep>::DirectStepI;
using DirectStepI<DirectIPaymentStep>::check; using DirectStepI<DirectIPaymentStep>::check;
bool verifyPrevStepRedeems (bool) const bool verifyPrevStepDebtDirection (DebtDirection) const
{ {
// A payment doesn't care whether or not prevStepRedeems. // A payment doesn't care whether or not prevStepRedeems.
return true; return true;
@@ -237,14 +249,13 @@ public:
std::uint32_t std::uint32_t
quality (ReadView const& sb, quality (ReadView const& sb,
// set true for quality in, false for quality out QualityDirection qDir) const;
bool qin) const;
// Compute the maximum value that can flow from src->dst at // Compute the maximum value that can flow from src->dst at
// the best available quality. // the best available quality.
// return: first element is max amount that can flow, // return: first element is max amount that can flow,
// second is true if dst holds an iou from src. // second is the debt direction w.r.t. the source account
std::pair<IOUAmount, bool> std::pair<IOUAmount, DebtDirection>
maxFlow (ReadView const& sb, IOUAmount const& desired) const; maxFlow (ReadView const& sb, IOUAmount const& desired) const;
// Verify the consistency of the step. These checks are specific to // Verify the consistency of the step. These checks are specific to
@@ -266,15 +277,15 @@ public:
using DirectStepI<DirectIOfferCrossingStep>::DirectStepI; using DirectStepI<DirectIOfferCrossingStep>::DirectStepI;
using DirectStepI<DirectIOfferCrossingStep>::check; using DirectStepI<DirectIOfferCrossingStep>::check;
bool verifyPrevStepRedeems (bool prevStepRedeems) const bool verifyPrevStepDebtDirection (DebtDirection prevStepDir) const
{ {
// During offer crossing we rely on the fact that prevStepRedeems // During offer crossing we rely on the fact that prevStepRedeems
// will *always* be false. That's because: // will *always* issue. That's because:
// o If there's a prevStep_, it will always be a BookStep. // o If there's a prevStep_, it will always be a BookStep.
// o BookStep::redeems() aways returns false when offer crossing. // o BookStep::debtDirection() aways returns `issues` when offer crossing.
// An assert based on this return value will tell us if that // An assert based on this return value will tell us if that
// behavior changes. // behavior changes.
return !prevStepRedeems; return issues(prevStepDir);
} }
bool verifyDstQualityIn (std::uint32_t dstQIn) const bool verifyDstQualityIn (std::uint32_t dstQIn) const
@@ -286,14 +297,13 @@ public:
std::uint32_t std::uint32_t
quality (ReadView const& sb, quality (ReadView const& sb,
// set true for quality in, false for quality out QualityDirection qDir) const;
bool qin) const;
// Compute the maximum value that can flow from src->dst at // Compute the maximum value that can flow from src->dst at
// the best available quality. // the best available quality.
// return: first element is max amount that can flow, // return: first element is max amount that can flow,
// second is true if dst holds an iou from src. // second is the debt direction w.r.t the source
std::pair<IOUAmount, bool> std::pair<IOUAmount, DebtDirection>
maxFlow (ReadView const& sb, IOUAmount const& desired) const; maxFlow (ReadView const& sb, IOUAmount const& desired) const;
// Verify the consistency of the step. These checks are specific to // Verify the consistency of the step. These checks are specific to
@@ -313,8 +323,7 @@ public:
std::uint32_t std::uint32_t
DirectIPaymentStep::quality (ReadView const& sb, DirectIPaymentStep::quality (ReadView const& sb,
// set true for quality in, false for quality out QualityDirection qDir) const
bool qin) const
{ {
if (src_ == dst_) if (src_ == dst_)
return QUALITY_ONE; return QUALITY_ONE;
@@ -324,9 +333,9 @@ DirectIPaymentStep::quality (ReadView const& sb,
if (!sle) if (!sle)
return QUALITY_ONE; return QUALITY_ONE;
auto const& field = [this, qin]() -> SF_U32 const& auto const& field = [this, qDir]() -> SF_U32 const&
{ {
if (qin) if (qDir == QualityDirection::in)
{ {
// compute dst quality in // compute dst quality in
if (this->dst_ < this->src_) if (this->dst_ < this->src_)
@@ -355,21 +364,20 @@ DirectIPaymentStep::quality (ReadView const& sb,
std::uint32_t std::uint32_t
DirectIOfferCrossingStep::quality (ReadView const&, DirectIOfferCrossingStep::quality (ReadView const&,
// set true for quality in, false for quality out QualityDirection qDir) const
bool) const
{ {
// If offer crossing then ignore trust line Quality fields. This // If offer crossing then ignore trust line Quality fields. This
// preserves a long-standing tradition. // preserves a long-standing tradition.
return QUALITY_ONE; return QUALITY_ONE;
} }
std::pair<IOUAmount, bool> std::pair<IOUAmount, DebtDirection>
DirectIPaymentStep::maxFlow (ReadView const& sb, IOUAmount const&) const DirectIPaymentStep::maxFlow (ReadView const& sb, IOUAmount const&) const
{ {
return maxPaymentFlow (sb); return maxPaymentFlow (sb);
} }
std::pair<IOUAmount, bool> std::pair<IOUAmount, DebtDirection>
DirectIOfferCrossingStep::maxFlow ( DirectIOfferCrossingStep::maxFlow (
ReadView const& sb, IOUAmount const& desired) const ReadView const& sb, IOUAmount const& desired) const
{ {
@@ -386,7 +394,7 @@ DirectIOfferCrossingStep::maxFlow (
// "dstQIn" is always QUALITY_ONE for offer crossing. // "dstQIn" is always QUALITY_ONE for offer crossing.
if (isLast_) if (isLast_)
return {desired, false}; return {desired, DebtDirection::issues};
return maxPaymentFlow (sb); return maxPaymentFlow (sb);
} }
@@ -460,29 +468,31 @@ DirectIOfferCrossingStep::check (
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template <class TDerived> template <class TDerived>
std::pair<IOUAmount, bool> std::pair<IOUAmount, DebtDirection>
DirectStepI<TDerived>::maxPaymentFlow (ReadView const& sb) const DirectStepI<TDerived>::maxPaymentFlow (ReadView const& sb) const
{ {
auto const srcOwed = toAmount<IOUAmount> ( auto const srcOwed = toAmount<IOUAmount> (
accountHolds (sb, src_, currency_, dst_, fhIGNORE_FREEZE, j_)); accountHolds (sb, src_, currency_, dst_, fhIGNORE_FREEZE, j_));
if (srcOwed.signum () > 0) if (srcOwed.signum () > 0)
return {srcOwed, true}; return {srcOwed, DebtDirection::redeems};
// srcOwed is negative or zero // srcOwed is negative or zero
return {creditLimit2 (sb, dst_, src_, currency_) + srcOwed, false}; return {creditLimit2 (sb, dst_, src_, currency_) + srcOwed, DebtDirection::issues};
} }
template <class TDerived> template <class TDerived>
bool DebtDirection
DirectStepI<TDerived>::redeems (ReadView const& sb, bool fwd) const DirectStepI<TDerived>::debtDirection(ReadView const& sb, StrandDirection dir)
const
{ {
if (fwd && cache_) if (dir == StrandDirection::forward && cache_)
return cache_->srcRedeems; return cache_->srcDebtDir;
auto const srcOwed = accountHolds ( auto const srcOwed =
sb, src_, currency_, dst_, fhIGNORE_FREEZE, j_); accountHolds(sb, src_, currency_, dst_, fhIGNORE_FREEZE, j_);
return srcOwed.signum () > 0; return srcOwed.signum() > 0 ? DebtDirection::redeems
: DebtDirection::issues;
} }
template <class TDerived> template <class TDerived>
@@ -495,21 +505,22 @@ DirectStepI<TDerived>::revImp (
{ {
cache_.reset (); cache_.reset ();
bool srcRedeems; DebtDirection srcDebtDir;
IOUAmount maxSrcToDst; IOUAmount maxSrcToDst;
std::tie (maxSrcToDst, srcRedeems) = std::tie (maxSrcToDst, srcDebtDir) =
static_cast<TDerived const*>(this)->maxFlow (sb, out); static_cast<TDerived const*>(this)->maxFlow (sb, out);
std::uint32_t srcQOut, dstQIn; std::uint32_t srcQOut, dstQIn;
std::tie (srcQOut, dstQIn) = qualities (sb, srcRedeems, false); std::tie (srcQOut, dstQIn) = qualities (sb, srcDebtDir, StrandDirection::reverse);
assert (static_cast<TDerived const*>(this)->verifyDstQualityIn (dstQIn)); assert (static_cast<TDerived const*>(this)->verifyDstQualityIn (dstQIn));
Issue const srcToDstIss (currency_, srcRedeems ? dst_ : src_); Issue const srcToDstIss(
currency_, redeems(srcDebtDir) ? dst_ : src_);
JLOG (j_.trace()) << JLOG (j_.trace()) <<
"DirectStepI::rev" << "DirectStepI::rev" <<
" srcRedeems: " << srcRedeems << " srcRedeems: " << redeems(srcDebtDir) <<
" outReq: " << to_string (out) << " outReq: " << to_string (out) <<
" maxSrcToDst: " << to_string (maxSrcToDst) << " maxSrcToDst: " << to_string (maxSrcToDst) <<
" srcQOut: " << srcQOut << " srcQOut: " << srcQOut <<
@@ -522,7 +533,7 @@ DirectStepI<TDerived>::revImp (
IOUAmount (beast::zero), IOUAmount (beast::zero),
IOUAmount (beast::zero), IOUAmount (beast::zero),
IOUAmount (beast::zero), IOUAmount (beast::zero),
srcRedeems); srcDebtDir);
return {beast::zero, beast::zero}; return {beast::zero, beast::zero};
} }
@@ -533,13 +544,13 @@ DirectStepI<TDerived>::revImp (
{ {
IOUAmount const in = mulRatio ( IOUAmount const in = mulRatio (
srcToDst, srcQOut, QUALITY_ONE, /*roundUp*/ true); srcToDst, srcQOut, QUALITY_ONE, /*roundUp*/ true);
cache_.emplace (in, srcToDst, out, srcRedeems); cache_.emplace (in, srcToDst, out, srcDebtDir);
rippleCredit (sb, rippleCredit (sb,
src_, dst_, toSTAmount (srcToDst, srcToDstIss), src_, dst_, toSTAmount (srcToDst, srcToDstIss),
/*checkIssuer*/ true, j_); /*checkIssuer*/ true, j_);
JLOG (j_.trace()) << JLOG (j_.trace()) <<
"DirectStepI::rev: Non-limiting" << "DirectStepI::rev: Non-limiting" <<
" srcRedeems: " << srcRedeems << " srcRedeems: " << redeems(srcDebtDir) <<
" in: " << to_string (in) << " in: " << to_string (in) <<
" srcToDst: " << to_string (srcToDst) << " srcToDst: " << to_string (srcToDst) <<
" out: " << to_string (out); " out: " << to_string (out);
@@ -551,13 +562,13 @@ DirectStepI<TDerived>::revImp (
maxSrcToDst, srcQOut, QUALITY_ONE, /*roundUp*/ true); maxSrcToDst, srcQOut, QUALITY_ONE, /*roundUp*/ true);
IOUAmount const actualOut = mulRatio ( IOUAmount const actualOut = mulRatio (
maxSrcToDst, dstQIn, QUALITY_ONE, /*roundUp*/ false); maxSrcToDst, dstQIn, QUALITY_ONE, /*roundUp*/ false);
cache_.emplace (in, maxSrcToDst, actualOut, srcRedeems); cache_.emplace (in, maxSrcToDst, actualOut, srcDebtDir);
rippleCredit (sb, rippleCredit (sb,
src_, dst_, toSTAmount (maxSrcToDst, srcToDstIss), src_, dst_, toSTAmount (maxSrcToDst, srcToDstIss),
/*checkIssuer*/ true, j_); /*checkIssuer*/ true, j_);
JLOG (j_.trace()) << JLOG (j_.trace()) <<
"DirectStepI::rev: Limiting" << "DirectStepI::rev: Limiting" <<
" srcRedeems: " << srcRedeems << " srcRedeems: " << redeems(srcDebtDir) <<
" in: " << to_string (in) << " in: " << to_string (in) <<
" srcToDst: " << to_string (maxSrcToDst) << " srcToDst: " << to_string (maxSrcToDst) <<
" out: " << to_string (out); " out: " << to_string (out);
@@ -574,7 +585,7 @@ DirectStepI<TDerived>::setCacheLimiting (
IOUAmount const& fwdIn, IOUAmount const& fwdIn,
IOUAmount const& fwdSrcToDst, IOUAmount const& fwdSrcToDst,
IOUAmount const& fwdOut, IOUAmount const& fwdOut,
bool srcRedeems) DebtDirection srcDebtDir)
{ {
if (cache_->in < fwdIn) if (cache_->in < fwdIn)
{ {
@@ -596,7 +607,7 @@ DirectStepI<TDerived>::setCacheLimiting (
<< " cacheSrcToDst: " << to_string (cache_->srcToDst) << " cacheSrcToDst: " << to_string (cache_->srcToDst)
<< " fwdOut: " << to_string (fwdOut) << " fwdOut: " << to_string (fwdOut)
<< " cacheOut: " << to_string (cache_->out); << " cacheOut: " << to_string (cache_->out);
cache_.emplace (fwdIn, fwdSrcToDst, fwdOut, srcRedeems); cache_.emplace (fwdIn, fwdSrcToDst, fwdOut, srcDebtDir);
return; return;
} }
} }
@@ -606,7 +617,7 @@ DirectStepI<TDerived>::setCacheLimiting (
cache_->srcToDst = fwdSrcToDst; cache_->srcToDst = fwdSrcToDst;
if (fwdOut < cache_->out) if (fwdOut < cache_->out)
cache_->out = fwdOut; cache_->out = fwdOut;
cache_->srcRedeems = srcRedeems; cache_->srcDebtDir = srcDebtDir;
}; };
template <class TDerived> template <class TDerived>
@@ -619,19 +630,19 @@ DirectStepI<TDerived>::fwdImp (
{ {
assert (cache_); assert (cache_);
bool srcRedeems; DebtDirection srcDebtDir;
IOUAmount maxSrcToDst; IOUAmount maxSrcToDst;
std::tie (maxSrcToDst, srcRedeems) = std::tie (maxSrcToDst, srcDebtDir) =
static_cast<TDerived const*>(this)->maxFlow (sb, cache_->srcToDst); static_cast<TDerived const*>(this)->maxFlow (sb, cache_->srcToDst);
std::uint32_t srcQOut, dstQIn; std::uint32_t srcQOut, dstQIn;
std::tie (srcQOut, dstQIn) = qualities (sb, srcRedeems, true); std::tie (srcQOut, dstQIn) = qualities (sb, srcDebtDir, StrandDirection::forward);
Issue const srcToDstIss (currency_, srcRedeems ? dst_ : src_); Issue const srcToDstIss (currency_, redeems(srcDebtDir) ? dst_ : src_);
JLOG (j_.trace()) << JLOG (j_.trace()) <<
"DirectStepI::fwd" << "DirectStepI::fwd" <<
" srcRedeems: " << srcRedeems << " srcRedeems: " << redeems(srcDebtDir) <<
" inReq: " << to_string (in) << " inReq: " << to_string (in) <<
" maxSrcToDst: " << to_string (maxSrcToDst) << " maxSrcToDst: " << to_string (maxSrcToDst) <<
" srcQOut: " << srcQOut << " srcQOut: " << srcQOut <<
@@ -644,7 +655,7 @@ DirectStepI<TDerived>::fwdImp (
IOUAmount (beast::zero), IOUAmount (beast::zero),
IOUAmount (beast::zero), IOUAmount (beast::zero),
IOUAmount (beast::zero), IOUAmount (beast::zero),
srcRedeems); srcDebtDir);
return {beast::zero, beast::zero}; return {beast::zero, beast::zero};
} }
@@ -655,13 +666,13 @@ DirectStepI<TDerived>::fwdImp (
{ {
IOUAmount const out = mulRatio ( IOUAmount const out = mulRatio (
srcToDst, dstQIn, QUALITY_ONE, /*roundUp*/ false); srcToDst, dstQIn, QUALITY_ONE, /*roundUp*/ false);
setCacheLimiting (in, srcToDst, out, srcRedeems); setCacheLimiting (in, srcToDst, out, srcDebtDir);
rippleCredit (sb, rippleCredit (sb,
src_, dst_, toSTAmount (cache_->srcToDst, srcToDstIss), src_, dst_, toSTAmount (cache_->srcToDst, srcToDstIss),
/*checkIssuer*/ true, j_); /*checkIssuer*/ true, j_);
JLOG (j_.trace()) << JLOG (j_.trace()) <<
"DirectStepI::fwd: Non-limiting" << "DirectStepI::fwd: Non-limiting" <<
" srcRedeems: " << srcRedeems << " srcRedeems: " << redeems(srcDebtDir) <<
" in: " << to_string (in) << " in: " << to_string (in) <<
" srcToDst: " << to_string (srcToDst) << " srcToDst: " << to_string (srcToDst) <<
" out: " << to_string (out); " out: " << to_string (out);
@@ -673,13 +684,13 @@ DirectStepI<TDerived>::fwdImp (
maxSrcToDst, srcQOut, QUALITY_ONE, /*roundUp*/ true); maxSrcToDst, srcQOut, QUALITY_ONE, /*roundUp*/ true);
IOUAmount const out = mulRatio ( IOUAmount const out = mulRatio (
maxSrcToDst, dstQIn, QUALITY_ONE, /*roundUp*/ false); maxSrcToDst, dstQIn, QUALITY_ONE, /*roundUp*/ false);
setCacheLimiting (actualIn, maxSrcToDst, out, srcRedeems); setCacheLimiting (actualIn, maxSrcToDst, out, srcDebtDir);
rippleCredit (sb, rippleCredit (sb,
src_, dst_, toSTAmount (cache_->srcToDst, srcToDstIss), src_, dst_, toSTAmount (cache_->srcToDst, srcToDstIss),
/*checkIssuer*/ true, j_); /*checkIssuer*/ true, j_);
JLOG (j_.trace()) << JLOG (j_.trace()) <<
"DirectStepI::rev: Limiting" << "DirectStepI::rev: Limiting" <<
" srcRedeems: " << srcRedeems << " srcRedeems: " << redeems(srcDebtDir) <<
" in: " << to_string (actualIn) << " in: " << to_string (actualIn) <<
" srcToDst: " << to_string (srcToDst) << " srcToDst: " << to_string (srcToDst) <<
" out: " << to_string (out); " out: " << to_string (out);
@@ -705,9 +716,9 @@ DirectStepI<TDerived>::validFwd (
assert (!in.native); assert (!in.native);
bool srcRedeems; DebtDirection srcDebtDir;
IOUAmount maxSrcToDst; IOUAmount maxSrcToDst;
std::tie (maxSrcToDst, srcRedeems) = std::tie (maxSrcToDst, srcDebtDir) =
static_cast<TDerived const*>(this)->maxFlow (sb, cache_->srcToDst); static_cast<TDerived const*>(this)->maxFlow (sb, cache_->srcToDst);
try try
@@ -747,40 +758,65 @@ DirectStepI<TDerived>::validFwd (
// Returns srcQOut, dstQIn // Returns srcQOut, dstQIn
template <class TDerived> template <class TDerived>
std::pair<std::uint32_t, std::uint32_t> std::pair<std::uint32_t, std::uint32_t>
DirectStepI<TDerived>::qualities ( DirectStepI<TDerived>::qualitiesSrcRedeems(
ReadView const& sb, ReadView const& sb) const
bool srcRedeems,
bool fwd) const
{
if (srcRedeems)
{ {
if (!prevStep_) if (!prevStep_)
return {QUALITY_ONE, QUALITY_ONE}; return {QUALITY_ONE, QUALITY_ONE};
auto const prevStepQIn = prevStep_->lineQualityIn(sb); auto const prevStepQIn = prevStep_->lineQualityIn(sb);
auto srcQOut = static_cast<TDerived const*>(this)->quality ( auto srcQOut =
sb, /* src quality out */ false); static_cast<TDerived const*>(this)->quality(sb, QualityDirection::out);
if (prevStepQIn > srcQOut) if (prevStepQIn > srcQOut)
srcQOut = prevStepQIn; srcQOut = prevStepQIn;
return {srcQOut, QUALITY_ONE}; return {srcQOut, QUALITY_ONE};
} }
else
// Returns srcQOut, dstQIn
template <class TDerived>
std::pair<std::uint32_t, std::uint32_t>
DirectStepI<TDerived>::qualitiesSrcIssues(
ReadView const& sb,
DebtDirection prevStepDebtDirection) const
{ {
// Charge a transfer rate when issuing and previous step redeems // Charge a transfer rate when issuing and previous step redeems
auto const prevStepRedeems = prevStep_ && prevStep_->redeems (sb, fwd);
assert (static_cast<TDerived const*>(this)->verifyPrevStepRedeems (
prevStepRedeems));
std::uint32_t const srcQOut = assert(static_cast<TDerived const*>(this)->verifyPrevStepDebtDirection(
prevStepRedeems ? transferRate (sb, src_).value : QUALITY_ONE; prevStepDebtDirection));
std::uint32_t const srcQOut = redeems(prevStepDebtDirection)
? transferRate(sb, src_).value
: QUALITY_ONE;
auto dstQIn = static_cast<TDerived const*>(this)->quality( auto dstQIn = static_cast<TDerived const*>(this)->quality(
sb, /* dst quality in */ true); sb, QualityDirection::in);
if (isLast_ && dstQIn > QUALITY_ONE) if (isLast_ && dstQIn > QUALITY_ONE)
dstQIn = QUALITY_ONE; dstQIn = QUALITY_ONE;
return {srcQOut, dstQIn}; return {srcQOut, dstQIn};
} }
// Returns srcQOut, dstQIn
template <class TDerived>
std::pair<std::uint32_t, std::uint32_t>
DirectStepI<TDerived>::qualities(
ReadView const& sb,
DebtDirection srcDebtDir,
StrandDirection strandDir) const
{
if (redeems(srcDebtDir))
{
return qualitiesSrcRedeems(sb);
}
else
{
auto const prevStepDebtDirection = [&] {
if (prevStep_)
return prevStep_->debtDirection(sb, strandDir);
return DebtDirection::issues;
}();
return qualitiesSrcIssues(sb, prevStepDebtDirection);
}
} }
template <class TDerived> template <class TDerived>
@@ -789,19 +825,23 @@ DirectStepI<TDerived>::lineQualityIn (ReadView const& v) const
{ {
// dst quality in // dst quality in
return static_cast<TDerived const*>(this)->quality ( return static_cast<TDerived const*>(this)->quality (
v, /* dst quality in */ true); v, QualityDirection::in);
} }
template <class TDerived> template <class TDerived>
boost::optional<Quality> boost::optional<Quality>
DirectStepI<TDerived>::qualityUpperBound(ReadView const& v, bool& redeems) const DirectStepI<TDerived>::qualityUpperBound(ReadView const& v, DebtDirection& dir)
const
{ {
auto const prevRedeems = redeems; auto const prevStepDebtDir = dir;
redeems = this->redeems(v, true); dir = this->debtDirection(v, StrandDirection::forward);
std::uint32_t const srcQOut = std::uint32_t const srcQOut = [&]() -> std::uint32_t {
(prevRedeems && !redeems) ? transferRate(v, src_).value : QUALITY_ONE; if (redeems(prevStepDebtDir) && issues(dir))
auto dstQIn = static_cast<TDerived const*>(this)->quality ( return transferRate(v, src_).value;
v, /* dst quality in */ true); return QUALITY_ONE;
}();
auto dstQIn =
static_cast<TDerived const*>(this)->quality(v, QualityDirection::in);
if (isLast_ && dstQIn > QUALITY_ONE) if (isLast_ && dstQIn > QUALITY_ONE)
dstQIn = QUALITY_ONE; dstQIn = QUALITY_ONE;

View File

@@ -34,6 +34,24 @@ class PaymentSandbox;
class ReadView; class ReadView;
class ApplyView; class ApplyView;
enum class DebtDirection { issues, redeems };
enum class QualityDirection { in, out };
enum class StrandDirection { forward, reverse };
inline
bool
redeems(DebtDirection dir)
{
return dir == DebtDirection::redeems;
}
inline
bool
issues(DebtDirection dir)
{
return dir == DebtDirection::issues;
}
/** /**
A step in a payment path A step in a payment path
@@ -63,7 +81,6 @@ class ApplyView;
class Step class Step
{ {
public: public:
/** Step destructor. */
virtual ~Step() = default; virtual ~Step() = default;
/** /**
@@ -145,13 +162,10 @@ public:
otherwise return true. otherwise return true.
@param sb view with the strand's state of balances and offers @param sb view with the strand's state of balances and offers
@param fwd false -> called from rev(); true -> called from fwd(). @param dir reverse -> called from rev(); forward -> called from fwd().
*/ */
virtual bool virtual DebtDirection
redeems (ReadView const& sb, bool fwd) const debtDirection (ReadView const& sb, StrandDirection dir) const = 0;
{
return false;
}
/** /**
If this step is a DirectStepI, return the quality in of the dst account. If this step is a DirectStepI, return the quality in of the dst account.
@@ -166,14 +180,14 @@ public:
Find an upper bound of quality for the step Find an upper bound of quality for the step
@param v view to query the ledger state from @param v view to query the ledger state from
@param redeems in/out param. Set to true if the previous step redeems. @param dir in/out param. Set to DebtDirection::redeems if the previous step redeems.
Will be set to true if this step redeems; Will be set to false if this Will be set to DebtDirection::redeems if this step redeems; Will be set to DebtDirection::issues if this
step does not redeem. step does not redeem
@return The upper bound of quality for the step, or boost::none if the @return The upper bound of quality for the step, or boost::none if the
step is dry. step is dry.
*/ */
virtual boost::optional<Quality> virtual boost::optional<Quality>
qualityUpperBound(ReadView const& v, bool& redeems) const = 0; qualityUpperBound(ReadView const& v, DebtDirection& dir) const = 0;
/** /**
If this step is a BookStep, return the book. If this step is a BookStep, return the book.

View File

@@ -401,10 +401,10 @@ boost::optional<Quality>
qualityUpperBound(ReadView const& v, Strand const& strand) qualityUpperBound(ReadView const& v, Strand const& strand)
{ {
Quality q{STAmount::uRateOne}; Quality q{STAmount::uRateOne};
bool redeems = false; DebtDirection dir = DebtDirection::issues;
for (auto const& step : strand) for (auto const& step : strand)
{ {
if (auto const stepQ = step->qualityUpperBound(v, redeems)) if (auto const stepQ = step->qualityUpperBound(v, dir))
q = composed_quality(q, *stepQ); q = composed_quality(q, *stepQ);
else else
return boost::none; return boost::none;

View File

@@ -89,8 +89,14 @@ public:
return cached (); return cached ();
} }
DebtDirection
debtDirection(ReadView const& sb, StrandDirection dir) const override
{
return DebtDirection::issues;
}
boost::optional<Quality> boost::optional<Quality>
qualityUpperBound(ReadView const& v, bool& redeems) const override; qualityUpperBound(ReadView const& v, DebtDirection& dir) const override;
std::pair<XRPAmount, XRPAmount> std::pair<XRPAmount, XRPAmount>
revImp ( revImp (
@@ -237,9 +243,9 @@ inline bool operator==(XRPEndpointStep<TDerived> const& lhs,
template <class TDerived> template <class TDerived>
boost::optional<Quality> boost::optional<Quality>
XRPEndpointStep<TDerived>::qualityUpperBound( XRPEndpointStep<TDerived>::qualityUpperBound(
ReadView const& v, bool& redeems) const ReadView const& v, DebtDirection& dir) const
{ {
redeems = this->redeems(v, true); dir = this->debtDirection(v, StrandDirection::forward);
return Quality{STAmount::uRateOne}; return Quality{STAmount::uRateOne};
} }