rippled
Steps.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #ifndef RIPPLE_APP_PATHS_IMPL_PAYSTEPS_H_INCLUDED
21 #define RIPPLE_APP_PATHS_IMPL_PAYSTEPS_H_INCLUDED
22 
23 #include <ripple/app/paths/impl/AmountSpec.h>
24 #include <ripple/basics/Log.h>
25 #include <ripple/protocol/Quality.h>
26 #include <ripple/protocol/QualityFunction.h>
27 #include <ripple/protocol/STLedgerEntry.h>
28 #include <ripple/protocol/TER.h>
29 
30 #include <boost/container/flat_set.hpp>
31 #include <optional>
32 
33 namespace ripple {
34 class PaymentSandbox;
35 class ReadView;
36 class ApplyView;
37 class AMMContext;
38 
39 enum class DebtDirection { issues, redeems };
40 enum class QualityDirection { in, out };
42 
43 inline bool
45 {
46  return dir == DebtDirection::redeems;
47 }
48 
49 inline bool
51 {
52  return dir == DebtDirection::issues;
53 }
54 
81 class Step
82 {
83 public:
84  virtual ~Step() = default;
85 
99  rev(PaymentSandbox& sb,
100  ApplyView& afView,
101  boost::container::flat_set<uint256>& ofrsToRm,
102  EitherAmount const& out) = 0;
103 
117  fwd(PaymentSandbox& sb,
118  ApplyView& afView,
119  boost::container::flat_set<uint256>& ofrsToRm,
120  EitherAmount const& in) = 0;
121 
127  cachedIn() const = 0;
128 
134  cachedOut() const = 0;
135 
142  {
143  return std::nullopt;
144  }
145 
146  // for debugging. Return the src and dst accounts for a direct step
147  // For XRP endpoints, one of src or dst will be the root account
150  {
151  return std::nullopt;
152  }
153 
162  virtual DebtDirection
163  debtDirection(ReadView const& sb, StrandDirection dir) const = 0;
164 
168  virtual std::uint32_t
169  lineQualityIn(ReadView const&) const
170  {
171  return QUALITY_ONE;
172  }
173 
174  // clang-format off
189  // clang-format on
191  qualityUpperBound(ReadView const& v, DebtDirection prevStepDir) const = 0;
192 
201  getQualityFunc(ReadView const& v, DebtDirection prevStepDir) const;
202 
210  virtual std::uint32_t
211  offersUsed() const
212  {
213  return 0;
214  }
215 
219  virtual std::optional<Book>
220  bookStepBook() const
221  {
222  return std::nullopt;
223  }
224 
228  virtual bool
229  isZero(EitherAmount const& out) const = 0;
230 
236  virtual bool
237  inactive() const
238  {
239  return false;
240  }
241 
245  virtual bool
246  equalOut(EitherAmount const& lhs, EitherAmount const& rhs) const = 0;
247 
251  virtual bool
252  equalIn(EitherAmount const& lhs, EitherAmount const& rhs) const = 0;
253 
265  validFwd(PaymentSandbox& sb, ApplyView& afView, EitherAmount const& in) = 0;
266 
273  friend bool
274  operator==(Step const& lhs, Step const& rhs)
275  {
276  return lhs.equal(rhs);
277  }
278 
285  friend bool
286  operator!=(Step const& lhs, Step const& rhs)
287  {
288  return !(lhs == rhs);
289  }
290 
292  friend std::ostream&
293  operator<<(std::ostream& stream, Step const& step)
294  {
295  stream << step.logString();
296  return stream;
297  }
298 
299 private:
300  virtual std::string
301  logString() const = 0;
302 
303  virtual bool
304  equal(Step const& rhs) const = 0;
305 };
306 
308 Step::getQualityFunc(ReadView const& v, DebtDirection prevStepDir) const
309 {
310  if (auto const res = qualityUpperBound(v, prevStepDir); res.first)
311  return {
313  res.second};
314  else
315  return {std::nullopt, res.second};
316 }
317 
319 using Strand = std::vector<std::unique_ptr<Step>>;
320 
321 inline std::uint32_t
322 offersUsed(Strand const& strand)
323 {
324  std::uint32_t r = 0;
325  for (auto const& step : strand)
326  {
327  if (step)
328  r += step->offersUsed();
329  }
330  return r;
331 }
333 
335 inline bool
336 operator==(Strand const& lhs, Strand const& rhs)
337 {
338  if (lhs.size() != rhs.size())
339  return false;
340  for (size_t i = 0, e = lhs.size(); i != e; ++i)
341  if (*lhs[i] != *rhs[i])
342  return false;
343  return true;
344 }
346 
347 /*
348  Normalize a path by inserting implied accounts and offers
349 
350  @param src Account that is sending assets
351  @param dst Account that is receiving assets
352  @param deliver Asset the dst account will receive
353  (if issuer of deliver == dst, then accept any issuer)
354  @param sendMax Optional asset to send.
355  @param path Liquidity sources to use for this strand of the payment. The path
356  contains an ordered collection of the offer books to use and
357  accounts to ripple through.
358  @return error code and normalized path
359 */
362  AccountID const& src,
363  AccountID const& dst,
364  Issue const& deliver,
365  std::optional<Issue> const& sendMaxIssue,
366  STPath const& path);
367 
392 toStrand(
393  ReadView const& sb,
394  AccountID const& src,
395  AccountID const& dst,
396  Issue const& deliver,
397  std::optional<Quality> const& limitQuality,
398  std::optional<Issue> const& sendMaxIssue,
399  STPath const& path,
400  bool ownerPaysTransferFee,
401  bool offerCrossing,
402  AMMContext& ammContext,
403  beast::Journal j);
404 
431 toStrands(
432  ReadView const& sb,
433  AccountID const& src,
434  AccountID const& dst,
435  Issue const& deliver,
436  std::optional<Quality> const& limitQuality,
437  std::optional<Issue> const& sendMax,
438  STPathSet const& paths,
439  bool addDefaultPath,
440  bool ownerPaysTransferFee,
441  bool offerCrossing,
442  AMMContext& ammContext,
443  beast::Journal j);
444 
446 template <class TIn, class TOut, class TDerived>
447 struct StepImp : public Step
448 {
449  explicit StepImp() = default;
450 
452  rev(PaymentSandbox& sb,
453  ApplyView& afView,
454  boost::container::flat_set<uint256>& ofrsToRm,
455  EitherAmount const& out) override
456  {
457  auto const r = static_cast<TDerived*>(this)->revImp(
458  sb, afView, ofrsToRm, get<TOut>(out));
459  return {EitherAmount(r.first), EitherAmount(r.second)};
460  }
461 
462  // Given the requested amount to consume, compute the amount produced.
463  // Return the consumed/produced
465  fwd(PaymentSandbox& sb,
466  ApplyView& afView,
467  boost::container::flat_set<uint256>& ofrsToRm,
468  EitherAmount const& in) override
469  {
470  auto const r = static_cast<TDerived*>(this)->fwdImp(
471  sb, afView, ofrsToRm, get<TIn>(in));
472  return {EitherAmount(r.first), EitherAmount(r.second)};
473  }
474 
475  bool
476  isZero(EitherAmount const& out) const override
477  {
478  return get<TOut>(out) == beast::zero;
479  }
480 
481  bool
482  equalOut(EitherAmount const& lhs, EitherAmount const& rhs) const override
483  {
484  return get<TOut>(lhs) == get<TOut>(rhs);
485  }
486 
487  bool
488  equalIn(EitherAmount const& lhs, EitherAmount const& rhs) const override
489  {
490  return get<TIn>(lhs) == get<TIn>(rhs);
491  }
492 };
494 
496 // Thrown when unexpected errors occur
497 class FlowException : public std::runtime_error
498 {
499 public:
500  TER ter;
501 
502  FlowException(TER t, std::string const& msg)
503  : std::runtime_error(msg), ter(t)
504  {
505  }
506 
507  explicit FlowException(TER t) : std::runtime_error(transHuman(t)), ter(t)
508  {
509  }
510 };
512 
514 // Check equal with tolerance
515 bool
516 checkNear(IOUAmount const& expected, IOUAmount const& actual);
517 bool
518 checkNear(XRPAmount const& expected, XRPAmount const& actual);
520 
525 {
526  ReadView const& view;
531  bool const isFirst;
532  bool const isLast = false;
533  bool const ownerPaysTransferFee;
534  bool const offerCrossing;
535  bool const isDefaultPath;
536  size_t const strandSize;
537 
540  Step const* const prevStep = nullptr;
550  boost::container::flat_set<Issue>& seenBookOuts;
553 
556  ReadView const& view_,
557  std::vector<std::unique_ptr<Step>> const& strand_,
558  // A strand may not include an inner node that
559  // replicates the source or destination.
560  AccountID const& strandSrc_,
561  AccountID const& strandDst_,
562  Issue const& strandDeliver_,
563  std::optional<Quality> const& limitQuality_,
564  bool isLast_,
565  bool ownerPaysTransferFee_,
566  bool offerCrossing_,
567  bool isDefaultPath_,
568  std::array<boost::container::flat_set<Issue>, 2>&
569  seenDirectIssues_,
570  boost::container::flat_set<Issue>&
571  seenBookOuts_,
572  AMMContext& ammContext_,
573  beast::Journal j_);
574 };
575 
577 namespace test {
578 // Needed for testing
579 bool
581  Step const& step,
582  AccountID const& src,
583  AccountID const& dst,
584  Currency const& currency);
585 
586 bool
587 xrpEndpointStepEqual(Step const& step, AccountID const& acc);
588 
589 bool
590 bookStepEqual(Step const& step, ripple::Book const& book);
591 } // namespace test
592 
595  StrandContext const& ctx,
596  AccountID const& src,
597  AccountID const& dst,
598  Currency const& c);
599 
601 make_BookStepII(StrandContext const& ctx, Issue const& in, Issue const& out);
602 
604 make_BookStepIX(StrandContext const& ctx, Issue const& in);
605 
607 make_BookStepXI(StrandContext const& ctx, Issue const& out);
608 
610 make_XRPEndpointStep(StrandContext const& ctx, AccountID const& acc);
611 
612 template <class InAmt, class OutAmt>
613 bool
614 isDirectXrpToXrp(Strand const& strand);
616 
617 } // namespace ripple
618 
619 #endif
ripple::Step::equalIn
virtual bool equalIn(EitherAmount const &lhs, EitherAmount const &rhs) const =0
Return true if In of lhs == In of rhs.
ripple::StrandContext
Context needed to build Strand Steps and for error checking.
Definition: Steps.h:524
ripple::StrandContext::strandSize
const size_t strandSize
Length of Strand.
Definition: Steps.h:536
ripple::issues
bool issues(DebtDirection dir)
Definition: Steps.h:50
ripple::Issue
A currency issued by an account.
Definition: Issue.h:35
std::string
STL class.
ripple::Step::cachedIn
virtual std::optional< EitherAmount > cachedIn() const =0
Amount of currency computed coming into the Step the last time the step ran in reverse.
ripple::normalizePath
std::pair< TER, STPath > normalizePath(AccountID const &src, AccountID const &dst, Issue const &deliver, std::optional< Issue > const &sendMaxIssue, STPath const &path)
ripple::Step::isZero
virtual bool isZero(EitherAmount const &out) const =0
Check if amount is zero.
ripple::StrandContext::strandDeliver
const Issue strandDeliver
Issue strand delivers.
Definition: Steps.h:529
ripple::DebtDirection
DebtDirection
Definition: Steps.h:39
ripple::PaymentSandbox
A wrapper which makes credits unavailable to balances.
Definition: PaymentSandbox.h:112
ripple::make_BookStepXI
std::pair< TER, std::unique_ptr< Step > > make_BookStepXI(StrandContext const &ctx, Issue const &out)
Definition: BookStep.cpp:1368
ripple::make_BookStepII
std::pair< TER, std::unique_ptr< Step > > make_BookStepII(StrandContext const &ctx, Issue const &in, Issue const &out)
Definition: BookStep.cpp:1356
ripple::Step::directStepSrcAcct
virtual std::optional< AccountID > directStepSrcAcct() const
If this step is DirectStepI (IOU->IOU direct step), return the src account.
Definition: Steps.h:141
std::pair
ripple::Step::operator!=
friend bool operator!=(Step const &lhs, Step const &rhs)
Return true if lhs != rhs.
Definition: Steps.h:286
std::vector
STL class.
ripple::StrandContext::ownerPaysTransferFee
const bool ownerPaysTransferFee
true if owner, not sender, pays fee
Definition: Steps.h:533
ripple::Step::debtDirection
virtual DebtDirection debtDirection(ReadView const &sb, StrandDirection dir) const =0
If this step is a DirectStepI and the src redeems to the dst, return true, otherwise return false.
ripple::Step::lineQualityIn
virtual std::uint32_t lineQualityIn(ReadView const &) const
If this step is a DirectStepI, return the quality in of the dst account.
Definition: Steps.h:169
ripple::checkNear
bool checkNear(IOUAmount const &expected, IOUAmount const &actual)
Definition: PaySteps.cpp:36
ripple::make_DirectStepI
std::pair< TER, std::unique_ptr< Step > > make_DirectStepI(StrandContext const &ctx, AccountID const &src, AccountID const &dst, Currency const &c)
Definition: DirectStep.cpp:976
ripple::QualityDirection::in
@ in
ripple::Step::operator==
friend bool operator==(Step const &lhs, Step const &rhs)
Return true if lhs == rhs.
Definition: Steps.h:274
ripple::test::bookStepEqual
bool bookStepEqual(Step const &step, ripple::Book const &book)
Definition: BookStep.cpp:1299
ripple::Step::operator<<
friend std::ostream & operator<<(std::ostream &stream, Step const &step)
Streaming operator for a Step.
Definition: Steps.h:293
ripple::Step::equalOut
virtual bool equalOut(EitherAmount const &lhs, EitherAmount const &rhs) const =0
Return true if Out of lhs == Out of rhs.
ripple::ApplyView
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:134
ripple::StrandDirection
StrandDirection
Definition: Steps.h:41
ripple::operator==
bool operator==(Manifest const &lhs, Manifest const &rhs)
Definition: Manifest.h:165
ripple::StrandContext::strandSrc
const AccountID strandSrc
Strand source account.
Definition: Steps.h:527
ripple::base_uint< 160, detail::AccountIDTag >
ripple::Step::bookStepBook
virtual std::optional< Book > bookStepBook() const
If this step is a BookStep, return the book.
Definition: Steps.h:220
ripple::StrandContext::view
ReadView const & view
Current ReadView.
Definition: Steps.h:526
ripple::QualityDirection::out
@ out
ripple::AMMContext
Maintains AMM info per overall payment engine execution and individual iteration.
Definition: AMMContext.h:35
ripple::Step::inactive
virtual bool inactive() const
Return true if the step should be considered inactive.
Definition: Steps.h:237
ripple::Step::fwd
virtual std::pair< EitherAmount, EitherAmount > fwd(PaymentSandbox &sb, ApplyView &afView, boost::container::flat_set< uint256 > &ofrsToRm, EitherAmount const &in)=0
Find the amount we get out of the step given the input subject to liquidity limits.
std::ostream
STL class.
ripple::StrandContext::offerCrossing
const bool offerCrossing
true if offer crossing, not payment
Definition: Steps.h:534
ripple::Step::equal
virtual bool equal(Step const &rhs) const =0
ripple::StrandContext::limitQuality
const std::optional< Quality > limitQuality
Worst accepted quality.
Definition: Steps.h:530
ripple::make_XRPEndpointStep
std::pair< TER, std::unique_ptr< Step > > make_XRPEndpointStep(StrandContext const &ctx, AccountID const &acc)
Definition: XRPEndpointStep.cpp:399
ripple::Step
A step in a payment path.
Definition: Steps.h:81
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:580
ripple::Step::qualityUpperBound
virtual std::pair< std::optional< Quality >, DebtDirection > qualityUpperBound(ReadView const &v, DebtDirection prevStepDir) const =0
Find an upper bound of quality for the step.
std::array
STL class.
ripple::Step::validFwd
virtual std::pair< bool, EitherAmount > validFwd(PaymentSandbox &sb, ApplyView &afView, EitherAmount const &in)=0
Check that the step can correctly execute in the forward direction.
ripple::DebtDirection::redeems
@ redeems
ripple::StrandContext::ammContext
AMMContext & ammContext
Definition: Steps.h:551
ripple::toStrands
std::pair< TER, std::vector< Strand > > toStrands(ReadView const &view, AccountID const &src, AccountID const &dst, Issue const &deliver, std::optional< Quality > const &limitQuality, std::optional< Issue > const &sendMax, STPathSet const &paths, bool addDefaultPath, bool ownerPaysTransferFee, bool offerCrossing, AMMContext &ammContext, beast::Journal j)
Create a Strand for each specified path (including the default path, if indicated)
Definition: PaySteps.cpp:468
ripple::StrandContext::seenBookOuts
boost::container::flat_set< Issue > & seenBookOuts
A strand may not include an offer that output the same issue more than once.
Definition: Steps.h:550
std::runtime_error
STL class.
ripple::StrandContext::isLast
const bool isLast
true if Step is last in Strand
Definition: Steps.h:532
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::uint32_t
ripple::isDirectXrpToXrp
bool isDirectXrpToXrp(Strand const &strand)
Definition: PaySteps.cpp:618
ripple::StrandContext::j
const beast::Journal j
Definition: Steps.h:552
ripple::transHuman
std::string transHuman(TER code)
Definition: TER.cpp:230
ripple::Step::getQualityFunc
virtual std::pair< std::optional< QualityFunction >, DebtDirection > getQualityFunc(ReadView const &v, DebtDirection prevStepDir) const
Get QualityFunction.
Definition: Steps.h:308
ripple::StrandDirection::reverse
@ reverse
ripple::DebtDirection::issues
@ issues
ripple::test::directStepEqual
bool directStepEqual(Step const &step, AccountID const &src, AccountID const &dst, Currency const &currency)
Definition: DirectStep.cpp:958
ripple::redeems
bool redeems(DebtDirection dir)
Definition: Steps.h:44
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:54
ripple::Currency
base_uint< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
Definition: UintTypes.h:56
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Step::cachedOut
virtual std::optional< EitherAmount > cachedOut() const =0
Amount of currency computed coming out of the Step the last time the step ran in reverse.
ripple::Step::logString
virtual std::string logString() const =0
std
STL namespace.
ripple::toStrand
std::pair< TER, Strand > toStrand(ReadView const &view, AccountID const &src, AccountID const &dst, Issue const &deliver, std::optional< Quality > const &limitQuality, std::optional< Issue > const &sendMaxIssue, STPath const &path, bool ownerPaysTransferFee, bool offerCrossing, AMMContext &ammContext, beast::Journal j)
Create a Strand for the specified path.
Definition: PaySteps.cpp:135
ripple::StrandContext::StrandContext
StrandContext(ReadView const &view_, std::vector< std::unique_ptr< Step >> const &strand_, AccountID const &strandSrc_, AccountID const &strandDst_, Issue const &strandDeliver_, std::optional< Quality > const &limitQuality_, bool isLast_, bool ownerPaysTransferFee_, bool offerCrossing_, bool isDefaultPath_, std::array< boost::container::flat_set< Issue >, 2 > &seenDirectIssues_, boost::container::flat_set< Issue > &seenBookOuts_, AMMContext &ammContext_, beast::Journal j_)
StrandContext constructor.
Definition: PaySteps.cpp:580
ripple::StrandContext::strandDst
const AccountID strandDst
Strand destination account.
Definition: Steps.h:528
ripple::EitherAmount
Definition: AmountSpec.h:59
ripple::QualityFunction
Average quality of a path as a function of out: q(out) = m * out + b, where m = -1 / poolGets,...
Definition: QualityFunction.h:39
ripple::StrandContext::isFirst
const bool isFirst
true if Step is first in Strand
Definition: Steps.h:531
ripple::StrandContext::prevStep
Step const *const prevStep
The previous step in the strand.
Definition: Steps.h:540
ripple::Step::directStepAccts
virtual std::optional< std::pair< AccountID, AccountID > > directStepAccts() const
Definition: Steps.h:149
optional
ripple::QualityDirection
QualityDirection
Definition: Steps.h:40
ripple::Book
Specifies an order book.
Definition: Book.h:33
ripple::Step::rev
virtual std::pair< EitherAmount, EitherAmount > rev(PaymentSandbox &sb, ApplyView &afView, boost::container::flat_set< uint256 > &ofrsToRm, EitherAmount const &out)=0
Find the amount we need to put into the step to get the requested out subject to liquidity limits.
ripple::test::xrpEndpointStepEqual
bool xrpEndpointStepEqual(Step const &step, AccountID const &acc)
Definition: XRPEndpointStep.cpp:385
ripple::Step::~Step
virtual ~Step()=default
ripple::QualityFunction::CLOBLikeTag
Definition: QualityFunction.h:55
ripple::Step::offersUsed
virtual std::uint32_t offersUsed() const
Return the number of offers consumed or partially consumed the last time the step ran,...
Definition: Steps.h:211
ripple::make_BookStepIX
std::pair< TER, std::unique_ptr< Step > > make_BookStepIX(StrandContext const &ctx, Issue const &in)
Definition: BookStep.cpp:1362
ripple::StrandContext::seenDirectIssues
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.
Definition: Steps.h:546
std::unique_ptr
STL class.
ripple::StrandContext::isDefaultPath
const bool isDefaultPath
true if Strand is default path
Definition: Steps.h:535
ripple::AccountID
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition: AccountID.h:47
ripple::StrandDirection::forward
@ forward