20 #include <ripple/app/paths/Credit.h>
21 #include <ripple/app/paths/impl/StepChecks.h>
22 #include <ripple/app/paths/impl/Steps.h>
23 #include <ripple/basics/IOUAmount.h>
24 #include <ripple/basics/Log.h>
25 #include <ripple/ledger/PaymentSandbox.h>
26 #include <ripple/protocol/Feature.h>
27 #include <ripple/protocol/Quality.h>
29 #include <boost/container/flat_set.hpp>
30 #include <boost/optional.hpp>
37 template <
class TDerived>
38 class DirectStepI :
public StepImp<IOUAmount, IOUAmount, DirectStepI<TDerived>>
124 boost::optional<EitherAmount>
cachedIn ()
const override
131 boost::optional<EitherAmount>
139 boost::optional<AccountID>
145 boost::optional<std::pair<AccountID,AccountID>>
164 boost::container::flat_set<uint256>& ofrsToRm,
171 boost::container::flat_set<uint256>& ofrsToRm,
199 return ! (lhs == rhs);
216 if (
auto ds =
dynamic_cast<DirectStepI const*
> (&rhs))
289 return issues(prevStepDir);
296 return dstQIn == QUALITY_ONE;
337 auto const& field = [
this, qDir]() ->
SF_U32 const&
342 if (this->dst_ < this->
src_)
350 if (this->src_ < this->
dst_)
357 if (! sle->isFieldPresent (field))
360 auto const q = (*sle)[field];
413 JLOG (
j_.
trace()) <<
"DirectStepI: No credit line. " << *
this;
420 !((*sleLine)[
sfFlags] & authField) &&
424 <<
"DirectStepI: can't receive IOUs from issuer without auth."
433 auto const noRippleSrcToDst =
436 if (noRippleSrcToDst)
444 if (owed <= beast::zero)
450 <<
"DirectStepI: dry: owed: " << owed <<
" limit: " << limit;
470 template <
class TDerived>
477 if (srcOwed.signum () > 0)
484 template <
class TDerived>
490 return cache_->srcDebtDir;
498 template <
class TDerived>
503 boost::container::flat_set<uint256>& ,
508 auto const [maxSrcToDst, srcDebtDir] =
509 static_cast<TDerived const*
>(
this)->maxFlow(sb,
out);
512 assert (
static_cast<TDerived const*
>(
this)->verifyDstQualityIn (dstQIn));
514 Issue const srcToDstIss(
515 currency_,
redeems(srcDebtDir) ? dst_ : src_);
518 "DirectStepI::rev" <<
519 " srcRedeems: " <<
redeems(srcDebtDir) <<
521 " maxSrcToDst: " <<
to_string (maxSrcToDst) <<
522 " srcQOut: " << srcQOut <<
523 " dstQIn: " << dstQIn;
525 if (maxSrcToDst.signum () <= 0)
527 JLOG (j_.
trace()) <<
"DirectStepI::rev: dry";
533 return {beast::zero, beast::zero};
537 out, QUALITY_ONE, dstQIn,
true);
539 if (srcToDst <= maxSrcToDst)
542 srcToDst, srcQOut, QUALITY_ONE,
true);
543 cache_.emplace (
in, srcToDst,
out, srcDebtDir);
545 src_, dst_,
toSTAmount (srcToDst, srcToDstIss),
548 "DirectStepI::rev: Non-limiting" <<
549 " srcRedeems: " <<
redeems(srcDebtDir) <<
558 maxSrcToDst, srcQOut, QUALITY_ONE,
true);
560 maxSrcToDst, dstQIn, QUALITY_ONE,
false);
561 cache_.emplace (
in, maxSrcToDst, actualOut, srcDebtDir);
563 src_, dst_,
toSTAmount (maxSrcToDst, srcToDstIss),
566 "DirectStepI::rev: Limiting" <<
567 " srcRedeems: " <<
redeems(srcDebtDir) <<
569 " srcToDst: " <<
to_string (maxSrcToDst) <<
571 return {
in, actualOut};
578 template <
class TDerived>
586 if (cache_->in < fwdIn)
589 auto const diff = fwdIn - cache_->in;
590 if (
diff > smallDiff)
592 if (fwdIn.
exponent () != cache_->in.exponent () ||
593 !cache_->in.mantissa () ||
595 double(cache_->in.mantissa ())) > 1.01)
599 <<
"DirectStepI::fwd: setCacheLimiting"
601 <<
" cacheIn: " <<
to_string (cache_->in)
602 <<
" fwdSrcToDst: " <<
to_string (fwdSrcToDst)
603 <<
" cacheSrcToDst: " <<
to_string (cache_->srcToDst)
605 <<
" cacheOut: " <<
to_string (cache_->out);
606 cache_.emplace (fwdIn, fwdSrcToDst, fwdOut, srcDebtDir);
612 if (fwdSrcToDst < cache_->srcToDst)
613 cache_->srcToDst = fwdSrcToDst;
614 if (fwdOut < cache_->
out)
615 cache_->out = fwdOut;
616 cache_->srcDebtDir = srcDebtDir;
619 template <
class TDerived>
624 boost::container::flat_set<uint256>& ,
629 auto const [maxSrcToDst, srcDebtDir] =
630 static_cast<TDerived const*
>(
this)->maxFlow (sb, cache_->srcToDst);
634 Issue const srcToDstIss (currency_,
redeems(srcDebtDir) ? dst_ : src_);
637 "DirectStepI::fwd" <<
638 " srcRedeems: " <<
redeems(srcDebtDir) <<
640 " maxSrcToDst: " <<
to_string (maxSrcToDst) <<
641 " srcQOut: " << srcQOut <<
642 " dstQIn: " << dstQIn;
644 if (maxSrcToDst.signum () <= 0)
646 JLOG (j_.
trace()) <<
"DirectStepI::fwd: dry";
652 return {beast::zero, beast::zero};
656 in, QUALITY_ONE, srcQOut,
false);
658 if (srcToDst <= maxSrcToDst)
661 srcToDst, dstQIn, QUALITY_ONE,
false);
662 setCacheLimiting (
in, srcToDst,
out, srcDebtDir);
664 src_, dst_,
toSTAmount (cache_->srcToDst, srcToDstIss),
667 "DirectStepI::fwd: Non-limiting" <<
668 " srcRedeems: " <<
redeems(srcDebtDir) <<
677 maxSrcToDst, srcQOut, QUALITY_ONE,
true);
679 maxSrcToDst, dstQIn, QUALITY_ONE,
false);
680 setCacheLimiting (actualIn, maxSrcToDst,
out, srcDebtDir);
682 src_, dst_,
toSTAmount (cache_->srcToDst, srcToDstIss),
685 "DirectStepI::rev: Limiting" <<
686 " srcRedeems: " <<
redeems(srcDebtDir) <<
691 return {cache_->in, cache_->out};
694 template <
class TDerived>
703 JLOG (j_.
trace()) <<
"Expected valid cache in validFwd";
708 auto const savCache = *cache_;
712 auto const [maxSrcToDst, srcDebtDir] =
713 static_cast<TDerived const*
>(
this)->maxFlow(sb, cache_->srcToDst);
718 boost::container::flat_set<uint256> dummy;
719 fwdImp (sb, afView, dummy,
in.iou);
721 catch (FlowException
const&)
726 if (maxSrcToDst < cache_->srcToDst)
729 "DirectStepI: Strand re-execute check failed." <<
730 " Exceeded max src->dst limit" <<
731 " max src->dst: " <<
to_string (maxSrcToDst) <<
732 " actual src->dst: " <<
to_string (cache_->srcToDst);
736 if (!(
checkNear (savCache.in, cache_->in) &&
740 "DirectStepI: Strand re-execute check failed." <<
741 " ExpectedIn: " <<
to_string (savCache.in) <<
742 " CachedIn: " <<
to_string (cache_->in) <<
743 " ExpectedOut: " <<
to_string (savCache.out) <<
744 " CachedOut: " <<
to_string (cache_->out);
751 template <
class TDerived>
757 return {QUALITY_ONE, QUALITY_ONE};
759 auto const prevStepQIn = prevStep_->lineQualityIn(sb);
763 if (prevStepQIn > srcQOut)
764 srcQOut = prevStepQIn;
765 return {srcQOut, QUALITY_ONE};
769 template <
class TDerived>
777 assert(
static_cast<TDerived const*
>(
this)->verifyPrevStepDebtDirection(
778 prevStepDebtDirection));
783 auto dstQIn =
static_cast<TDerived const*
>(
this)->quality(
786 if (isLast_ && dstQIn > QUALITY_ONE)
787 dstQIn = QUALITY_ONE;
788 return {srcQOut, dstQIn};
792 template <
class TDerived>
801 return qualitiesSrcRedeems(sb);
805 auto const prevStepDebtDirection = [&] {
807 return prevStep_->debtDirection(sb, strandDir);
810 return qualitiesSrcIssues(sb, prevStepDebtDirection);
814 template <
class TDerived>
819 return static_cast<TDerived const*
>(
this)->quality (
823 template <
class TDerived>
837 auto dstQIn =
static_cast<TDerived const*
>(
this)->quality(
840 if (isLast_ && dstQIn > QUALITY_ONE)
841 dstQIn = QUALITY_ONE;
842 Issue const iss{currency_, src_};
847 auto const [srcQOut, dstQIn] =
redeems(dir)
848 ? qualitiesSrcRedeems(v)
849 : qualitiesSrcIssues(v, prevStepDir);
851 Issue const iss{currency_, src_};
862 template <
class TDerived>
868 JLOG (j_.
debug()) <<
"DirectStepI: specified bad account.";
874 JLOG (j_.
debug()) <<
"DirectStepI: same src and dst.";
882 <<
"DirectStepI: can't receive IOUs from non-existent issuer: "
902 ctx.
view, *prevSrc, src_, dst_, currency_, j_);
908 Issue const srcIssue{currency_, src_};
909 Issue const dstIssue{currency_, dst_};
922 if (book->out != srcIssue)
931 <<
"DirectStepI: loop detected: Index: " << ctx.
strandSize
937 return static_cast<TDerived const*
>(
this)->check (ctx, sleSrc);
953 return ds->src () == src && ds->dst () == dst &&
954 ds->currency () == currency;
973 auto offerCrossingStep =
974 std::make_unique<DirectIOfferCrossingStep> (ctx, src, dst, c);
975 ter = offerCrossingStep->check (ctx);
976 r = std::move (offerCrossingStep);
981 std::make_unique<DirectIPaymentStep> (ctx, src, dst, c);
982 ter = paymentStep->check (ctx);
983 r = std::move (paymentStep);
986 return {ter,
nullptr};
const SF_U32 sfHighQualityIn(access, STI_UINT32, 16, "HighQualityIn")
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
IOUAmount mulRatio(IOUAmount const &amt, std::uint32_t num, std::uint32_t den, bool roundUp)
Context needed to build Strand Steps and for error checking.
const size_t strandSize
Length of Strand.
Rate transferRate(ReadView const &view, AccountID const &issuer)
bool issues(DebtDirection dir)
std::uint32_t quality(ReadView const &sb, QualityDirection qDir) const
std::pair< IOUAmount, DebtDirection > maxPaymentFlow(ReadView const &sb) const
const uint256 fixQualityUpperBound
int exponent() const noexcept
A currency issued by an account.
STAmount creditBalance(ReadView const &view, AccountID const &account, AccountID const &issuer, Currency const ¤cy)
Returns the amount of IOUs issued by issuer that are held by an account.
A field with a type known at compile time.
bool verifyDstQualityIn(std::uint32_t dstQIn) const
Stream trace() const
Severity stream access functions.
A wrapper which makes credits unavailable to balances.
std::pair< std::uint32_t, std::uint32_t > qualities(ReadView const &sb, DebtDirection srcDebtDir, StrandDirection strandDir) const
bool verifyPrevStepDebtDirection(DebtDirection prevStepDir) const
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
TER check(StrandContext const &ctx) const
AccountID const & src() const
const SF_U32 sfFlags(access, STI_UINT32, 2, "Flags")
std::pair< std::uint32_t, std::uint32_t > qualitiesSrcIssues(ReadView const &sb, DebtDirection prevStepDebtDirection) const
bool checkNear(IOUAmount const &expected, IOUAmount const &actual)
Cache(IOUAmount const &in_, IOUAmount const &srcToDst_, IOUAmount const &out_, DebtDirection srcDebtDir_)
Currency const & currency() const
friend bool operator==(DirectStepI const &lhs, DirectStepI const &rhs)
std::pair< TER, std::unique_ptr< Step > > make_DirectStepI(StrandContext const &ctx, AccountID const &src, AccountID const &dst, Currency const &c)
IOUAmount creditLimit2(ReadView const &v, AccountID const &acc, AccountID const &iss, Currency const &cur)
DirectStepI(StrandContext const &ctx, AccountID const &src, AccountID const &dst, Currency const &c)
Floating point representation of amounts with high dynamic range.
bool verifyDstQualityIn(std::uint32_t dstQIn) const
std::string to_string(ListDisposition disposition)
std::uint32_t quality(ReadView const &sb, QualityDirection qDir) const
virtual boost::optional< Book > bookStepBook() const
If this step is a BookStep, return the book.
IOUAmount toAmount< IOUAmount >(STAmount const &amt)
Writeable view to a ledger, for applying a transaction.
std::string logString() const override
TER check(StrandContext const &ctx, std::shared_ptr< const SLE > const &sleSrc) const
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
TER checkNoRipple(ReadView const &view, AccountID const &prev, AccountID const &cur, AccountID const &next, Currency const ¤cy, beast::Journal j)
void setCacheLimiting(IOUAmount const &fwdIn, IOUAmount const &fwdSrcToDst, IOUAmount const &fwdOut, DebtDirection srcDebtDir)
friend bool operator!=(DirectStepI const &lhs, DirectStepI const &rhs)
ReadView const & view
Current ReadView.
boost::optional< EitherAmount > cachedOut() const override
boost::optional< EitherAmount > cachedIn() const override
std::pair< IOUAmount, IOUAmount > fwdImp(PaymentSandbox &sb, ApplyView &afView, boost::container::flat_set< uint256 > &ofrsToRm, IOUAmount const &in)
std::string logStringImpl(char const *name) const
bool equal(Step const &rhs) const override
const bool offerCrossing
true if offer crossing, not payment
static const account_t account
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
std::pair< IOUAmount, IOUAmount > revImp(PaymentSandbox &sb, ApplyView &afView, boost::container::flat_set< uint256 > &ofrsToRm, IOUAmount const &out)
Step const *const prevStep_
STAmount creditLimit(ReadView const &view, AccountID const &account, AccountID const &issuer, Currency const ¤cy)
Calculate the maximum amount of IOUs that an account can hold.
boost::optional< std::pair< AccountID, AccountID > > directStepAccts() const override
A step in a payment path.
boost::container::flat_set< Issue > & seenBookOuts
A strand may not include an offer that output the same issue more than once.
boost::optional< AccountID > directStepSrcAcct() const override
const bool isLast
true if Step is last in Strand
A generic endpoint for log messages.
const SF_U32 sfLowQualityOut(access, STI_UINT32, 19, "LowQualityOut")
std::uint32_t lineQualityIn(ReadView const &v) const override
bool enabled(uint256 const &id) const
Returns true if a feature is enabled.
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
bool directStepEqual(Step const &step, AccountID const &src, AccountID const &dst, Currency const ¤cy)
bool redeems(DebtDirection dir)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::int64_t mantissa() const noexcept
const SF_U32 sfLowQualityIn(access, STI_UINT32, 18, "LowQualityIn")
const SF_Amount sfBalance(access, STI_AMOUNT, 2, "Balance")
AccountID const & dst() const
virtual Rules const & rules() const =0
Returns the tx processing rules.
std::pair< IOUAmount, DebtDirection > maxFlow(ReadView const &sb, IOUAmount const &desired) const
DebtDirection debtDirection(ReadView const &sb, StrandDirection dir) const override
boost::optional< Cache > cache_
bool verifyPrevStepDebtDirection(DebtDirection) const
const bool isFirst
true if Step is first in Strand
Step const *const prevStep
The previous step in the strand.
std::pair< bool, EitherAmount > validFwd(PaymentSandbox &sb, ApplyView &afView, EitherAmount const &in) override
TER checkFreeze(ReadView const &view, AccountID const &src, AccountID const &dst, Currency const ¤cy)
TER check(StrandContext const &ctx, std::shared_ptr< const SLE > const &sleSrc) const
std::pair< IOUAmount, DebtDirection > maxFlow(ReadView const &sb, IOUAmount const &desired) const
std::pair< boost::optional< Quality >, DebtDirection > qualityUpperBound(ReadView const &v, DebtDirection dir) const override
std::array< boost::container::flat_set< Issue >, 2 > & seenDirectIssues
A strand may not include the same account node more than once in the same currency.
std::pair< std::uint32_t, std::uint32_t > qualitiesSrcRedeems(ReadView const &sb) const
virtual boost::optional< AccountID > directStepSrcAcct() const
If this step is DirectStepI (IOU->IOU direct step), return the src account.
const SF_U32 sfHighQualityOut(access, STI_UINT32, 17, "HighQualityOut")
std::string logString() const override