rippled
BookStep.cpp
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 #include <ripple/app/paths/Credit.h>
21 #include <ripple/app/paths/NodeDirectory.h>
22 #include <ripple/app/paths/impl/FlatSets.h>
23 #include <ripple/app/paths/impl/Steps.h>
24 #include <ripple/app/tx/impl/OfferStream.h>
25 #include <ripple/basics/IOUAmount.h>
26 #include <ripple/basics/Log.h>
27 #include <ripple/basics/XRPAmount.h>
28 #include <ripple/basics/contract.h>
29 #include <ripple/ledger/Directory.h>
30 #include <ripple/ledger/PaymentSandbox.h>
31 #include <ripple/protocol/Book.h>
32 #include <ripple/protocol/Feature.h>
33 #include <ripple/protocol/Quality.h>
34 
35 #include <boost/container/flat_set.hpp>
36 
37 #include <numeric>
38 #include <sstream>
39 
40 namespace ripple {
41 
42 template <class TIn, class TOut, class TDerived>
43 class BookStep : public StepImp<TIn, TOut, BookStep<TIn, TOut, TDerived>>
44 {
45 protected:
46  uint32_t const maxOffersToConsume_;
50  // Charge transfer fees when the prev step redeems
51  Step const* const prevStep_ = nullptr;
53  // Mark as inactive (dry) if too many offers are consumed
54  bool inactive_ = false;
56 
57  struct Cache
58  {
59  TIn in;
60  TOut out;
61 
62  Cache(TIn const& in_, TOut const& out_) : in(in_), out(out_)
63  {
64  }
65  };
66 
67  boost::optional<Cache> cache_;
68 
69  static uint32_t
71  {
72  if (ctx.view.rules().enabled(fix1515))
73  return 1000;
74  return 2000;
75  }
76 
77 public:
78  BookStep(StrandContext const& ctx, Issue const& in, Issue const& out)
80  , book_(in, out)
81  , strandSrc_(ctx.strandSrc)
82  , strandDst_(ctx.strandDst)
83  , prevStep_(ctx.prevStep)
84  , ownerPaysTransferFee_(ctx.ownerPaysTransferFee)
85  , j_(ctx.j)
86  {
87  }
88 
89  Book const&
90  book() const
91  {
92  return book_;
93  }
94 
95  boost::optional<EitherAmount>
96  cachedIn() const override
97  {
98  if (!cache_)
99  return boost::none;
100  return EitherAmount(cache_->in);
101  }
102 
103  boost::optional<EitherAmount>
104  cachedOut() const override
105  {
106  if (!cache_)
107  return boost::none;
108  return EitherAmount(cache_->out);
109  }
110 
112  debtDirection(ReadView const& sb, StrandDirection dir) const override
113  {
116  }
117 
118  boost::optional<Book>
119  bookStepBook() const override
120  {
121  return book_;
122  }
123 
125  qualityUpperBound(ReadView const& v, DebtDirection prevStepDir)
126  const override;
127 
129  revImp(
130  PaymentSandbox& sb,
131  ApplyView& afView,
132  boost::container::flat_set<uint256>& ofrsToRm,
133  TOut const& out);
134 
136  fwdImp(
137  PaymentSandbox& sb,
138  ApplyView& afView,
139  boost::container::flat_set<uint256>& ofrsToRm,
140  TIn const& in);
141 
143  validFwd(PaymentSandbox& sb, ApplyView& afView, EitherAmount const& in)
144  override;
145 
146  // Check for errors frozen constraints.
147  TER
148  check(StrandContext const& ctx) const;
149 
150  bool
151  inactive() const override
152  {
153  return inactive_;
154  }
155 
156 protected:
158  logStringImpl(char const* name) const
159  {
160  std::ostringstream ostr;
161  ostr << name << ": "
162  << "\ninIss: " << book_.in.account
163  << "\noutIss: " << book_.out.account
164  << "\ninCur: " << book_.in.currency
165  << "\noutCur: " << book_.out.currency;
166  return ostr.str();
167  }
168 
169 private:
170  friend bool
171  operator==(BookStep const& lhs, BookStep const& rhs)
172  {
173  return lhs.book_ == rhs.book_;
174  }
175 
176  friend bool
177  operator!=(BookStep const& lhs, BookStep const& rhs)
178  {
179  return !(lhs == rhs);
180  }
181 
182  bool
183  equal(Step const& rhs) const override;
184 
185  // Iterate through the offers at the best quality in a book.
186  // Unfunded offers and bad offers are skipped (and returned).
187  // callback is called with the offer SLE, taker pays, taker gets.
188  // If callback returns false, don't process any more offers.
189  // Return the unfunded and bad offers and the number of offers consumed.
190  template <class Callback>
192  forEachOffer(
193  PaymentSandbox& sb,
194  ApplyView& afView,
195  DebtDirection prevStepDebtDir,
196  Callback& callback) const;
197 
198  void
199  consumeOffer(
200  PaymentSandbox& sb,
201  TOffer<TIn, TOut>& offer,
202  TAmounts<TIn, TOut> const& ofrAmt,
203  TAmounts<TIn, TOut> const& stepAmt,
204  TOut const& ownerGives) const;
205 };
206 
207 //------------------------------------------------------------------------------
208 
209 // Flow is used in two different circumstances for transferring funds:
210 // o Payments, and
211 // o Offer crossing.
212 // The rules for handling funds in these two cases are almost, but not
213 // quite, the same.
214 
215 // Payment BookStep template class (not offer crossing).
216 template <class TIn, class TOut>
217 class BookPaymentStep : public BookStep<TIn, TOut, BookPaymentStep<TIn, TOut>>
218 {
219 public:
220  explicit BookPaymentStep() = default;
221 
224 
225  // Never limit self cross quality on a payment.
226  bool
228  AccountID const&,
229  AccountID const&,
230  TOffer<TIn, TOut> const& offer,
231  boost::optional<Quality>&,
233  bool) const
234  {
235  return false;
236  }
237 
238  // A payment can look at offers of any quality
239  bool
241  {
242  return true;
243  }
244 
245  // For a payment ofrInRate is always the same as trIn.
248  const
249  {
250  return trIn;
251  }
252 
253  // For a payment ofrOutRate is always the same as trOut.
256  Step const*,
257  TOffer<TIn, TOut> const&,
258  AccountID const&,
259  std::uint32_t trOut) const
260  {
261  return trOut;
262  }
263 
264  Quality
266  ReadView const& v,
267  Quality const& ofrQ,
268  DebtDirection prevStepDir) const
269  {
270  // Charge the offer owner, not the sender
271  // Charge a fee even if the owner is the same as the issuer
272  // (the old code does not charge a fee)
273  // Calculate amount that goes to the taker and the amount charged the
274  // offer owner
275  auto rate = [&](AccountID const& id) {
276  if (isXRP(id) || id == this->strandDst_)
277  return parityRate;
278  return transferRate(v, id);
279  };
280 
281  auto const trIn =
282  redeems(prevStepDir) ? rate(this->book_.in.account) : parityRate;
283  // Always charge the transfer fee, even if the owner is the issuer
284  auto const trOut = this->ownerPaysTransferFee_
285  ? rate(this->book_.out.account)
286  : parityRate;
287 
288  Quality const q1{getRate(STAmount(trOut.value), STAmount(trIn.value))};
289  return composed_quality(q1, ofrQ);
290  }
291 
293  logString() const override
294  {
295  return this->logStringImpl("BookPaymentStep");
296  }
297 };
298 
299 // Offer crossing BookStep template class (not a payment).
300 template <class TIn, class TOut>
302  : public BookStep<TIn, TOut, BookOfferCrossingStep<TIn, TOut>>
303 {
306 
307 private:
308  // Helper function that throws if the optional passed to the constructor
309  // is none.
310  static Quality
311  getQuality(boost::optional<Quality> const& limitQuality)
312  {
313  // It's really a programming error if the quality is missing.
314  assert(limitQuality);
315  if (!limitQuality)
316  Throw<FlowException>(tefINTERNAL, "Offer requires quality.");
317  return *limitQuality;
318  }
319 
320 public:
322  StrandContext const& ctx,
323  Issue const& in,
324  Issue const& out)
325  : BookStep<TIn, TOut, BookOfferCrossingStep<TIn, TOut>>(ctx, in, out)
327  , qualityThreshold_(getQuality(ctx.limitQuality))
328  {
329  }
330 
331  bool
333  AccountID const& strandSrc,
334  AccountID const& strandDst,
335  TOffer<TIn, TOut> const& offer,
336  boost::optional<Quality>& ofrQ,
338  bool const offerAttempted) const
339  {
340  // This method supports some correct but slightly surprising
341  // behavior in offer crossing. The scenario:
342  //
343  // o alice has already created one or more offers.
344  // o alice creates another offer that can be directly crossed (not
345  // autobridged) by one or more of her previously created offer(s).
346  //
347  // What does the offer crossing do?
348  //
349  // o The offer crossing could go ahead and cross the offers leaving
350  // either one reduced offer (partial crossing) or zero offers
351  // (exact crossing) in the ledger. We don't do this. And, really,
352  // the offer creator probably didn't want us to.
353  //
354  // o We could skip over the self offer in the book and only cross
355  // offers that are not our own. This would make a lot of sense,
356  // but we don't do it. Part of the rationale is that we can only
357  // operate on the tip of the order book. We can't leave an offer
358  // behind -- it would sit on the tip and block access to other
359  // offers.
360  //
361  // o We could delete the self-crossable offer(s) off the tip of the
362  // book and continue with offer crossing. That's what we do.
363  //
364  // To support this scenario offer crossing has a special rule. If:
365  // a. We're offer crossing using default path (no autobridging), and
366  // b. The offer's quality is at least as good as our quality, and
367  // c. We're about to cross one of our own offers, then
368  // d. Delete the old offer from the ledger.
369  if (defaultPath_ && offer.quality() >= qualityThreshold_ &&
370  strandSrc == offer.owner() && strandDst == offer.owner())
371  {
372  // Remove this offer even if no crossing occurs.
373  offers.permRmOffer(offer.key());
374 
375  // If no offers have been attempted yet then it's okay to move to
376  // a different quality.
377  if (!offerAttempted)
378  ofrQ = boost::none;
379 
380  // Return true so the current offer will be deleted.
381  return true;
382  }
383  return false;
384  }
385 
386  // Offer crossing can prune the offers it needs to look at with a
387  // quality threshold.
388  bool
390  {
391  return !defaultPath_ || offer.quality() >= qualityThreshold_;
392  }
393 
394  // For offer crossing don't pay the transfer fee if alice is paying alice.
395  // A regular (non-offer-crossing) payment does not apply this rule.
398  Step const* prevStep,
399  TOffer<TIn, TOut> const& offer,
400  std::uint32_t trIn) const
401  {
402  auto const srcAcct =
403  prevStep ? prevStep->directStepSrcAcct() : boost::none;
404 
405  return // If offer crossing
406  srcAcct && // && prevStep is DirectI
407  offer.owner() == *srcAcct // && src is offer owner
408  ? QUALITY_ONE
409  : trIn; // then rate = QUALITY_ONE
410  }
411 
412  // See comment on getOfrInRate().
415  Step const* prevStep,
416  TOffer<TIn, TOut> const& offer,
417  AccountID const& strandDst,
418  std::uint32_t trOut) const
419  {
420  return // If offer crossing
421  prevStep && prevStep->bookStepBook() && // && prevStep is BookStep
422  offer.owner() == strandDst // && dest is offer owner
423  ? QUALITY_ONE
424  : trOut; // then rate = QUALITY_ONE
425  }
426 
427  Quality
429  ReadView const& v,
430  Quality const& ofrQ,
431  DebtDirection prevStepDir) const
432  {
433  // Offer x-ing does not charge a transfer fee when the offer's owner
434  // is the same as the strand dst. It is important that
435  // `qualityUpperBound` is an upper bound on the quality (it is used to
436  // ignore strands whose quality cannot meet a minimum threshold). When
437  // calculating quality assume no fee is charged, or the estimate will no
438  // longer be an upper bound.
439  return ofrQ;
440  }
441 
443  logString() const override
444  {
445  return this->logStringImpl("BookOfferCrossingStep");
446  }
447 
448 private:
449  bool const defaultPath_;
450  Quality const qualityThreshold_;
451 };
452 
453 //------------------------------------------------------------------------------
454 
455 template <class TIn, class TOut, class TDerived>
456 bool
458 {
459  if (auto bs = dynamic_cast<BookStep<TIn, TOut, TDerived> const*>(&rhs))
460  return book_ == bs->book_;
461  return false;
462 }
463 
464 template <class TIn, class TOut, class TDerived>
467  ReadView const& v,
468  DebtDirection prevStepDir) const
469 {
470  auto const dir = this->debtDirection(v, StrandDirection::forward);
471 
472  // This can be simplified (and sped up) if directories are never empty.
473  Sandbox sb(&v, tapNONE);
474  BookTip bt(sb, book_);
475  if (!bt.step(j_))
476  return {boost::none, dir};
477 
478  Quality const q = static_cast<TDerived const*>(this)->adjustQualityWithFees(
479  v, bt.quality(), prevStepDir);
480  return {q, dir};
481 }
482 
483 // Adjust the offer amount and step amount subject to the given input limit
484 template <class TIn, class TOut>
485 static void
487  Quality const& ofrQ,
488  TAmounts<TIn, TOut>& ofrAmt,
489  TAmounts<TIn, TOut>& stpAmt,
490  TOut& ownerGives,
491  std::uint32_t transferRateIn,
492  std::uint32_t transferRateOut,
493  TIn const& limit)
494 {
495  if (limit < stpAmt.in)
496  {
497  stpAmt.in = limit;
498  auto const inLmt =
499  mulRatio(stpAmt.in, QUALITY_ONE, transferRateIn, /*roundUp*/ false);
500  ofrAmt = ofrQ.ceil_in(ofrAmt, inLmt);
501  stpAmt.out = ofrAmt.out;
502  ownerGives = mulRatio(
503  ofrAmt.out, transferRateOut, QUALITY_ONE, /*roundUp*/ false);
504  }
505 }
506 
507 // Adjust the offer amount and step amount subject to the given output limit
508 template <class TIn, class TOut>
509 static void
511  Quality const& ofrQ,
512  TAmounts<TIn, TOut>& ofrAmt,
513  TAmounts<TIn, TOut>& stpAmt,
514  TOut& ownerGives,
515  std::uint32_t transferRateIn,
516  std::uint32_t transferRateOut,
517  TOut const& limit)
518 {
519  if (limit < stpAmt.out)
520  {
521  stpAmt.out = limit;
522  ownerGives = mulRatio(
523  stpAmt.out, transferRateOut, QUALITY_ONE, /*roundUp*/ false);
524  ofrAmt = ofrQ.ceil_out(ofrAmt, stpAmt.out);
525  stpAmt.in =
526  mulRatio(ofrAmt.in, transferRateIn, QUALITY_ONE, /*roundUp*/ true);
527  }
528 }
529 
530 template <class TIn, class TOut, class TDerived>
531 template <class Callback>
534  PaymentSandbox& sb,
535  ApplyView& afView,
536  DebtDirection prevStepDir,
537  Callback& callback) const
538 {
539  // Charge the offer owner, not the sender
540  // Charge a fee even if the owner is the same as the issuer
541  // (the old code does not charge a fee)
542  // Calculate amount that goes to the taker and the amount charged the offer
543  // owner
544  auto rate = [this, &sb](AccountID const& id) -> std::uint32_t {
545  if (isXRP(id) || id == this->strandDst_)
546  return QUALITY_ONE;
547  return transferRate(sb, id).value;
548  };
549 
550  std::uint32_t const trIn =
551  redeems(prevStepDir) ? rate(book_.in.account) : QUALITY_ONE;
552  // Always charge the transfer fee, even if the owner is the issuer
553  std::uint32_t const trOut =
554  ownerPaysTransferFee_ ? rate(book_.out.account) : QUALITY_ONE;
555 
557  maxOffersToConsume_, j_);
558 
560  sb, afView, book_, sb.parentCloseTime(), counter, j_);
561 
562  bool const flowCross = afView.rules().enabled(featureFlowCross);
563  bool offerAttempted = false;
564  boost::optional<Quality> ofrQ;
565  while (offers.step())
566  {
567  auto& offer = offers.tip();
568 
569  // Note that offer.quality() returns a (non-optional) Quality. So
570  // ofrQ is always safe to use below this point in the loop.
571  if (!ofrQ)
572  ofrQ = offer.quality();
573  else if (*ofrQ != offer.quality())
574  break;
575 
576  if (static_cast<TDerived const*>(this)->limitSelfCrossQuality(
577  strandSrc_, strandDst_, offer, ofrQ, offers, offerAttempted))
578  continue;
579 
580  // Make sure offer owner has authorization to own IOUs from issuer.
581  // An account can always own XRP or their own IOUs.
582  if (flowCross && (!isXRP(offer.issueIn().currency)) &&
583  (offer.owner() != offer.issueIn().account))
584  {
585  auto const& issuerID = offer.issueIn().account;
586  auto const issuer = afView.read(keylet::account(issuerID));
587  if (issuer && ((*issuer)[sfFlags] & lsfRequireAuth))
588  {
589  // Issuer requires authorization. See if offer owner has that.
590  auto const& ownerID = offer.owner();
591  auto const authFlag =
592  issuerID > ownerID ? lsfHighAuth : lsfLowAuth;
593 
594  auto const line = afView.read(
595  keylet::line(ownerID, issuerID, offer.issueIn().currency));
596 
597  if (!line || (((*line)[sfFlags] & authFlag) == 0))
598  {
599  // Offer owner not authorized to hold IOU from issuer.
600  // Remove this offer even if no crossing occurs.
601  offers.permRmOffer(offer.key());
602  if (!offerAttempted)
603  // Change quality only if no previous offers were tried.
604  ofrQ = boost::none;
605  // This continue causes offers.step() to delete the offer.
606  continue;
607  }
608  }
609  }
610 
611  if (!static_cast<TDerived const*>(this)->checkQualityThreshold(offer))
612  break;
613 
614  auto const ofrInRate = static_cast<TDerived const*>(this)->getOfrInRate(
615  prevStep_, offer, trIn);
616 
617  auto const ofrOutRate =
618  static_cast<TDerived const*>(this)->getOfrOutRate(
619  prevStep_, offer, strandDst_, trOut);
620 
621  auto ofrAmt = offer.amount();
622  TAmounts stpAmt{
623  mulRatio(ofrAmt.in, ofrInRate, QUALITY_ONE, /*roundUp*/ true),
624  ofrAmt.out};
625 
626  // owner pays the transfer fee.
627  auto ownerGives =
628  mulRatio(ofrAmt.out, ofrOutRate, QUALITY_ONE, /*roundUp*/ false);
629 
630  auto const funds = (offer.owner() == offer.issueOut().account)
631  ? ownerGives // Offer owner is issuer; they have unlimited funds
632  : offers.ownerFunds();
633 
634  if (funds < ownerGives)
635  {
636  // We already know offer.owner()!=offer.issueOut().account
637  ownerGives = funds;
638  stpAmt.out = mulRatio(
639  ownerGives, QUALITY_ONE, ofrOutRate, /*roundUp*/ false);
640  ofrAmt = ofrQ->ceil_out(ofrAmt, stpAmt.out);
641  stpAmt.in =
642  mulRatio(ofrAmt.in, ofrInRate, QUALITY_ONE, /*roundUp*/ true);
643  }
644 
645  offerAttempted = true;
646  if (!callback(offer, ofrAmt, stpAmt, ownerGives, ofrInRate, ofrOutRate))
647  break;
648  }
649 
650  return {offers.permToRemove(), counter.count()};
651 }
652 
653 template <class TIn, class TOut, class TDerived>
654 void
656  PaymentSandbox& sb,
657  TOffer<TIn, TOut>& offer,
658  TAmounts<TIn, TOut> const& ofrAmt,
659  TAmounts<TIn, TOut> const& stepAmt,
660  TOut const& ownerGives) const
661 {
662  // The offer owner gets the ofrAmt. The difference between ofrAmt and
663  // stepAmt is a transfer fee that goes to book_.in.account
664  {
665  auto const dr = accountSend(
666  sb,
667  book_.in.account,
668  offer.owner(),
669  toSTAmount(ofrAmt.in, book_.in),
670  j_);
671  if (dr != tesSUCCESS)
672  Throw<FlowException>(dr);
673  }
674 
675  // The offer owner pays `ownerGives`. The difference between ownerGives and
676  // stepAmt is a transfer fee that goes to book_.out.account
677  {
678  auto const cr = accountSend(
679  sb,
680  offer.owner(),
681  book_.out.account,
682  toSTAmount(ownerGives, book_.out),
683  j_);
684  if (cr != tesSUCCESS)
685  Throw<FlowException>(cr);
686  }
687 
688  offer.consume(sb, ofrAmt);
689 }
690 
691 template <class TCollection>
692 static auto
693 sum(TCollection const& col)
694 {
695  using TResult = std::decay_t<decltype(*col.begin())>;
696  if (col.empty())
697  return TResult{beast::zero};
698  return std::accumulate(col.begin() + 1, col.end(), *col.begin());
699 };
700 
701 template <class TIn, class TOut, class TDerived>
704  PaymentSandbox& sb,
705  ApplyView& afView,
706  boost::container::flat_set<uint256>& ofrsToRm,
707  TOut const& out)
708 {
709  cache_.reset();
710 
711  TAmounts<TIn, TOut> result(beast::zero, beast::zero);
712 
713  auto remainingOut = out;
714 
715  boost::container::flat_multiset<TIn> savedIns;
716  savedIns.reserve(64);
717  boost::container::flat_multiset<TOut> savedOuts;
718  savedOuts.reserve(64);
719 
720  /* amt fed will be adjusted by owner funds (and may differ from the offer's
721  amounts - tho always <=)
722  Return true to continue to receive offers, false to stop receiving offers.
723  */
724  auto eachOffer = [&](TOffer<TIn, TOut>& offer,
725  TAmounts<TIn, TOut> const& ofrAmt,
726  TAmounts<TIn, TOut> const& stpAmt,
727  TOut const& ownerGives,
728  std::uint32_t transferRateIn,
729  std::uint32_t transferRateOut) mutable -> bool {
730  if (remainingOut <= beast::zero)
731  return false;
732 
733  if (stpAmt.out <= remainingOut)
734  {
735  savedIns.insert(stpAmt.in);
736  savedOuts.insert(stpAmt.out);
737  result = TAmounts<TIn, TOut>(sum(savedIns), sum(savedOuts));
738  remainingOut = out - result.out;
739  this->consumeOffer(sb, offer, ofrAmt, stpAmt, ownerGives);
740  // return true b/c even if the payment is satisfied,
741  // we need to consume the offer
742  return true;
743  }
744  else
745  {
746  auto ofrAdjAmt = ofrAmt;
747  auto stpAdjAmt = stpAmt;
748  auto ownerGivesAdj = ownerGives;
749  limitStepOut(
750  offer.quality(),
751  ofrAdjAmt,
752  stpAdjAmt,
753  ownerGivesAdj,
754  transferRateIn,
755  transferRateOut,
756  remainingOut);
757  remainingOut = beast::zero;
758  savedIns.insert(stpAdjAmt.in);
759  savedOuts.insert(remainingOut);
760  result.in = sum(savedIns);
761  result.out = out;
762  this->consumeOffer(sb, offer, ofrAdjAmt, stpAdjAmt, ownerGivesAdj);
763 
764  // Explicitly check whether the offer is funded. Given that we have
765  // (stpAmt.out > remainingOut), it's natural to assume the offer
766  // will still be funded after consuming remainingOut but that is
767  // not always the case. If the mantissas of two IOU amounts differ
768  // by less than ten, then subtracting them leaves a zero.
769  return offer.fully_consumed();
770  }
771  };
772 
773  {
774  auto const prevStepDebtDir = [&] {
775  if (prevStep_)
776  return prevStep_->debtDirection(sb, StrandDirection::reverse);
777  return DebtDirection::issues;
778  }();
779  auto const r = forEachOffer(sb, afView, prevStepDebtDir, eachOffer);
780  boost::container::flat_set<uint256> toRm = std::move(std::get<0>(r));
781  std::uint32_t const offersConsumed = std::get<1>(r);
782  SetUnion(ofrsToRm, toRm);
783 
784  if (offersConsumed >= maxOffersToConsume_)
785  {
786  // Too many iterations, mark this strand as inactive
787  if (!afView.rules().enabled(fix1515))
788  {
789  // Don't use the liquidity
790  cache_.emplace(beast::zero, beast::zero);
791  return {beast::zero, beast::zero};
792  }
793 
794  // Use the liquidity, but use this to mark the strand as inactive so
795  // it's not used further
796  inactive_ = true;
797  }
798  }
799 
800  switch (remainingOut.signum())
801  {
802  case -1: {
803  // something went very wrong
804  JLOG(j_.error())
805  << "BookStep remainingOut < 0 " << to_string(remainingOut);
806  assert(0);
807  cache_.emplace(beast::zero, beast::zero);
808  return {beast::zero, beast::zero};
809  }
810  case 0: {
811  // due to normalization, remainingOut can be zero without
812  // result.out == out. Force result.out == out for this case
813  result.out = out;
814  }
815  }
816 
817  cache_.emplace(result.in, result.out);
818  return {result.in, result.out};
819 }
820 
821 template <class TIn, class TOut, class TDerived>
824  PaymentSandbox& sb,
825  ApplyView& afView,
826  boost::container::flat_set<uint256>& ofrsToRm,
827  TIn const& in)
828 {
829  assert(cache_);
830 
831  TAmounts<TIn, TOut> result(beast::zero, beast::zero);
832 
833  auto remainingIn = in;
834 
835  boost::container::flat_multiset<TIn> savedIns;
836  savedIns.reserve(64);
837  boost::container::flat_multiset<TOut> savedOuts;
838  savedOuts.reserve(64);
839 
840  // amt fed will be adjusted by owner funds (and may differ from the offer's
841  // amounts - tho always <=)
842  auto eachOffer = [&](TOffer<TIn, TOut>& offer,
843  TAmounts<TIn, TOut> const& ofrAmt,
844  TAmounts<TIn, TOut> const& stpAmt,
845  TOut const& ownerGives,
846  std::uint32_t transferRateIn,
847  std::uint32_t transferRateOut) mutable -> bool {
848  assert(cache_);
849 
850  if (remainingIn <= beast::zero)
851  return false;
852 
853  bool processMore = true;
854  auto ofrAdjAmt = ofrAmt;
855  auto stpAdjAmt = stpAmt;
856  auto ownerGivesAdj = ownerGives;
857 
858  typename boost::container::flat_multiset<TOut>::const_iterator lastOut;
859  if (stpAmt.in <= remainingIn)
860  {
861  savedIns.insert(stpAmt.in);
862  lastOut = savedOuts.insert(stpAmt.out);
863  result = TAmounts<TIn, TOut>(sum(savedIns), sum(savedOuts));
864  // consume the offer even if stepAmt.in == remainingIn
865  processMore = true;
866  }
867  else
868  {
869  limitStepIn(
870  offer.quality(),
871  ofrAdjAmt,
872  stpAdjAmt,
873  ownerGivesAdj,
874  transferRateIn,
875  transferRateOut,
876  remainingIn);
877  savedIns.insert(remainingIn);
878  lastOut = savedOuts.insert(stpAdjAmt.out);
879  result.out = sum(savedOuts);
880  result.in = in;
881 
882  processMore = false;
883  }
884 
885  if (result.out > cache_->out && result.in <= cache_->in)
886  {
887  // The step produced more output in the forward pass than the
888  // reverse pass while consuming the same input (or less). If we
889  // compute the input required to produce the cached output
890  // (produced in the reverse step) and the input is equal to
891  // the input consumed in the forward step, then consume the
892  // input provided in the forward step and produce the output
893  // requested from the reverse step.
894  auto const lastOutAmt = *lastOut;
895  savedOuts.erase(lastOut);
896  auto const remainingOut = cache_->out - sum(savedOuts);
897  auto ofrAdjAmtRev = ofrAmt;
898  auto stpAdjAmtRev = stpAmt;
899  auto ownerGivesAdjRev = ownerGives;
900  limitStepOut(
901  offer.quality(),
902  ofrAdjAmtRev,
903  stpAdjAmtRev,
904  ownerGivesAdjRev,
905  transferRateIn,
906  transferRateOut,
907  remainingOut);
908 
909  if (stpAdjAmtRev.in == remainingIn)
910  {
911  result.in = in;
912  result.out = cache_->out;
913 
914  savedIns.clear();
915  savedIns.insert(result.in);
916  savedOuts.clear();
917  savedOuts.insert(result.out);
918 
919  ofrAdjAmt = ofrAdjAmtRev;
920  stpAdjAmt.in = remainingIn;
921  stpAdjAmt.out = remainingOut;
922  ownerGivesAdj = ownerGivesAdjRev;
923  }
924  else
925  {
926  // This is (likely) a problem case, and wil be caught
927  // with later checks
928  savedOuts.insert(lastOutAmt);
929  }
930  }
931 
932  remainingIn = in - result.in;
933  this->consumeOffer(sb, offer, ofrAdjAmt, stpAdjAmt, ownerGivesAdj);
934 
935  // When the mantissas of two iou amounts differ by less than ten, then
936  // subtracting them leaves a result of zero. This can cause the check
937  // for (stpAmt.in > remainingIn) to incorrectly think an offer will be
938  // funded after subtracting remainingIn.
939  return processMore || offer.fully_consumed();
940  };
941 
942  {
943  auto const prevStepDebtDir = [&] {
944  if (prevStep_)
945  return prevStep_->debtDirection(sb, StrandDirection::forward);
946  return DebtDirection::issues;
947  }();
948  auto const r = forEachOffer(sb, afView, prevStepDebtDir, eachOffer);
949  boost::container::flat_set<uint256> toRm = std::move(std::get<0>(r));
950  std::uint32_t const offersConsumed = std::get<1>(r);
951  SetUnion(ofrsToRm, toRm);
952 
953  if (offersConsumed >= maxOffersToConsume_)
954  {
955  // Too many iterations, mark this strand as inactive (dry)
956  if (!afView.rules().enabled(fix1515))
957  {
958  // Don't use the liquidity
959  cache_.emplace(beast::zero, beast::zero);
960  return {beast::zero, beast::zero};
961  }
962 
963  // Use the liquidity, but use this to mark the strand as inactive so
964  // it's not used further
965  inactive_ = true;
966  }
967  }
968 
969  switch (remainingIn.signum())
970  {
971  case -1: {
972  // something went very wrong
973  JLOG(j_.error())
974  << "BookStep remainingIn < 0 " << to_string(remainingIn);
975  assert(0);
976  cache_.emplace(beast::zero, beast::zero);
977  return {beast::zero, beast::zero};
978  }
979  case 0: {
980  // due to normalization, remainingIn can be zero without
981  // result.in == in. Force result.in == in for this case
982  result.in = in;
983  }
984  }
985 
986  cache_.emplace(result.in, result.out);
987  return {result.in, result.out};
988 }
989 
990 template <class TIn, class TOut, class TDerived>
993  PaymentSandbox& sb,
994  ApplyView& afView,
995  EitherAmount const& in)
996 {
997  if (!cache_)
998  {
999  JLOG(j_.trace()) << "Expected valid cache in validFwd";
1000  return {false, EitherAmount(TOut(beast::zero))};
1001  }
1002 
1003  auto const savCache = *cache_;
1004 
1005  try
1006  {
1007  boost::container::flat_set<uint256> dummy;
1008  fwdImp(sb, afView, dummy, get<TIn>(in)); // changes cache
1009  }
1010  catch (FlowException const&)
1011  {
1012  return {false, EitherAmount(TOut(beast::zero))};
1013  }
1014 
1015  if (!(checkNear(savCache.in, cache_->in) &&
1016  checkNear(savCache.out, cache_->out)))
1017  {
1018  JLOG(j_.warn()) << "Strand re-execute check failed."
1019  << " ExpectedIn: " << to_string(savCache.in)
1020  << " CachedIn: " << to_string(cache_->in)
1021  << " ExpectedOut: " << to_string(savCache.out)
1022  << " CachedOut: " << to_string(cache_->out);
1023  return {false, EitherAmount(cache_->out)};
1024  }
1025  return {true, EitherAmount(cache_->out)};
1026 }
1027 
1028 template <class TIn, class TOut, class TDerived>
1029 TER
1031 {
1032  if (book_.in == book_.out)
1033  {
1034  JLOG(j_.debug()) << "BookStep: Book with same in and out issuer "
1035  << *this;
1036  return temBAD_PATH;
1037  }
1038  if (!isConsistent(book_.in) || !isConsistent(book_.out))
1039  {
1040  JLOG(j_.debug()) << "Book: currency is inconsistent with issuer."
1041  << *this;
1042  return temBAD_PATH;
1043  }
1044 
1045  // Do not allow two books to output the same issue. This may cause offers on
1046  // one step to unfund offers in another step.
1047  if (!ctx.seenBookOuts.insert(book_.out).second ||
1048  ctx.seenDirectIssues[0].count(book_.out))
1049  {
1050  JLOG(j_.debug()) << "BookStep: loop detected: " << *this;
1051  return temBAD_PATH_LOOP;
1052  }
1053 
1054  if (ctx.seenDirectIssues[1].count(book_.out))
1055  {
1056  JLOG(j_.debug()) << "BookStep: loop detected: " << *this;
1057  return temBAD_PATH_LOOP;
1058  }
1059 
1060  auto issuerExists = [](ReadView const& view, Issue const& iss) -> bool {
1061  return isXRP(iss.account) || view.read(keylet::account(iss.account));
1062  };
1063 
1064  if (!issuerExists(ctx.view, book_.in) || !issuerExists(ctx.view, book_.out))
1065  {
1066  JLOG(j_.debug()) << "BookStep: deleted issuer detected: " << *this;
1067  return tecNO_ISSUER;
1068  }
1069 
1070  if (ctx.prevStep)
1071  {
1072  if (auto const prev = ctx.prevStep->directStepSrcAcct())
1073  {
1074  auto const& view = ctx.view;
1075  auto const& cur = book_.in.account;
1076 
1077  auto sle = view.read(keylet::line(*prev, cur, book_.in.currency));
1078  if (!sle)
1079  return terNO_LINE;
1080  if ((*sle)[sfFlags] &
1081  ((cur > *prev) ? lsfHighNoRipple : lsfLowNoRipple))
1082  return terNO_RIPPLE;
1083  }
1084  }
1085 
1086  return tesSUCCESS;
1087 }
1088 
1089 //------------------------------------------------------------------------------
1090 
1091 namespace test {
1092 // Needed for testing
1093 
1094 template <class TIn, class TOut, class TDerived>
1095 static bool
1096 equalHelper(Step const& step, ripple::Book const& book)
1097 {
1098  if (auto bs = dynamic_cast<BookStep<TIn, TOut, TDerived> const*>(&step))
1099  return book == bs->book();
1100  return false;
1101 }
1102 
1103 bool
1104 bookStepEqual(Step const& step, ripple::Book const& book)
1105 {
1106  bool const inXRP = isXRP(book.in.currency);
1107  bool const outXRP = isXRP(book.out.currency);
1108  if (inXRP && outXRP)
1109  return equalHelper<
1110  XRPAmount,
1111  XRPAmount,
1113  if (inXRP && !outXRP)
1114  return equalHelper<
1115  XRPAmount,
1116  IOUAmount,
1118  if (!inXRP && outXRP)
1119  return equalHelper<
1120  IOUAmount,
1121  XRPAmount,
1123  if (!inXRP && !outXRP)
1124  return equalHelper<
1125  IOUAmount,
1126  IOUAmount,
1128  return false;
1129 }
1130 } // namespace test
1131 
1132 //------------------------------------------------------------------------------
1133 
1134 template <class TIn, class TOut>
1136 make_BookStepHelper(StrandContext const& ctx, Issue const& in, Issue const& out)
1137 {
1138  TER ter = tefINTERNAL;
1140  if (ctx.offerCrossing)
1141  {
1142  auto offerCrossingStep =
1143  std::make_unique<BookOfferCrossingStep<TIn, TOut>>(ctx, in, out);
1144  ter = offerCrossingStep->check(ctx);
1145  r = std::move(offerCrossingStep);
1146  }
1147  else // payment
1148  {
1149  auto paymentStep =
1150  std::make_unique<BookPaymentStep<TIn, TOut>>(ctx, in, out);
1151  ter = paymentStep->check(ctx);
1152  r = std::move(paymentStep);
1153  }
1154  if (ter != tesSUCCESS)
1155  return {ter, nullptr};
1156 
1157  return {tesSUCCESS, std::move(r)};
1158 }
1159 
1161 make_BookStepII(StrandContext const& ctx, Issue const& in, Issue const& out)
1162 {
1163  return make_BookStepHelper<IOUAmount, IOUAmount>(ctx, in, out);
1164 }
1165 
1167 make_BookStepIX(StrandContext const& ctx, Issue const& in)
1168 {
1169  return make_BookStepHelper<IOUAmount, XRPAmount>(ctx, in, xrpIssue());
1170 }
1171 
1173 make_BookStepXI(StrandContext const& ctx, Issue const& out)
1174 {
1175  return make_BookStepHelper<XRPAmount, IOUAmount>(ctx, xrpIssue(), out);
1176 }
1177 
1178 } // namespace ripple
ripple::mulRatio
IOUAmount mulRatio(IOUAmount const &amt, std::uint32_t num, std::uint32_t den, bool roundUp)
Definition: IOUAmount.cpp:242
ripple::StrandContext
Context needed to build Strand Steps and for error checking.
Definition: Steps.h:472
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Definition: View.cpp:347
sstream
ripple::BookOfferCrossingStep::logString
std::string logString() const override
Definition: BookStep.cpp:443
ripple::TOfferStreamBase::StepCounter
Definition: OfferStream.h:39
ripple::BookOfferCrossingStep::getOfrInRate
std::uint32_t getOfrInRate(Step const *prevStep, TOffer< TIn, TOut > const &offer, std::uint32_t trIn) const
Definition: BookStep.cpp:397
ripple::BookStep::logStringImpl
std::string logStringImpl(char const *name) const
Definition: BookStep.cpp:158
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:150
std::string
STL class.
ripple::isConsistent
bool isConsistent(Book const &book)
Definition: Book.cpp:25
ripple::FlowOfferStream
Presents and consumes the offers in an order book.
Definition: OfferStream.h:171
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::composed_quality
Quality composed_quality(Quality const &lhs, Quality const &rhs)
Definition: Quality.cpp:101
ripple::limitStepOut
static void limitStepOut(Quality const &ofrQ, TAmounts< TIn, TOut > &ofrAmt, TAmounts< TIn, TOut > &stpAmt, TOut &ownerGives, std::uint32_t transferRateIn, std::uint32_t transferRateOut, TOut const &limit)
Definition: BookStep.cpp:510
ripple::Book::out
Issue out
Definition: Book.h:36
ripple::terNO_LINE
@ terNO_LINE
Definition: TER.h:194
ripple::DebtDirection
DebtDirection
Definition: Steps.h:37
ripple::BookStep::forEachOffer
std::pair< boost::container::flat_set< uint256 >, std::uint32_t > forEachOffer(PaymentSandbox &sb, ApplyView &afView, DebtDirection prevStepDebtDir, Callback &callback) const
Definition: BookStep.cpp:533
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:1173
ripple::make_BookStepII
std::pair< TER, std::unique_ptr< Step > > make_BookStepII(StrandContext const &ctx, Issue const &in, Issue const &out)
Definition: BookStep.cpp:1161
std::pair
ripple::test::equalHelper
static bool equalHelper(Step const &step, ripple::Book const &book)
Definition: BookStep.cpp:1096
ripple::BookPaymentStep::getOfrInRate
std::uint32_t getOfrInRate(Step const *, TOffer< TIn, TOut > const &, std::uint32_t trIn) const
Definition: BookStep.cpp:247
ripple::fix1515
const uint256 fix1515
Definition: Feature.cpp:175
ripple::lsfLowAuth
@ lsfLowAuth
Definition: LedgerFormats.h:123
ripple::lsfLowNoRipple
@ lsfLowNoRipple
Definition: LedgerFormats.h:125
ripple::BookPaymentStep::BookPaymentStep
BookPaymentStep()=default
ripple::BookStep::bookStepBook
boost::optional< Book > bookStepBook() const override
Definition: BookStep.cpp:119
ripple::BookOfferCrossingStep
Definition: BookStep.cpp:301
ripple::BookStep::maxOffersToConsume_
const uint32_t maxOffersToConsume_
Definition: BookStep.cpp:46
ripple::isDefaultPath
static bool isDefaultPath(STPath const &path)
Definition: Pathfinder.cpp:456
ripple::BookStep::book
Book const & book() const
Definition: BookStep.cpp:90
ripple::checkNear
bool checkNear(IOUAmount const &expected, IOUAmount const &actual)
Definition: PaySteps.cpp:36
ripple::BookPaymentStep
Definition: BookStep.cpp:217
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
ripple::BookStep::inactive
bool inactive() const override
Definition: BookStep.cpp:151
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::QualityDirection::in
@ in
ripple::limitStepIn
static void limitStepIn(Quality const &ofrQ, TAmounts< TIn, TOut > &ofrAmt, TAmounts< TIn, TOut > &stpAmt, TOut &ownerGives, std::uint32_t transferRateIn, std::uint32_t transferRateOut, TIn const &limit)
Definition: BookStep.cpp:486
ripple::IOUAmount
Floating point representation of amounts with high dynamic range.
Definition: IOUAmount.h:41
ripple::terNO_RIPPLE
@ terNO_RIPPLE
Definition: TER.h:199
ripple::BookOfferCrossingStep::BookOfferCrossingStep
BookOfferCrossingStep(StrandContext const &ctx, Issue const &in, Issue const &out)
Definition: BookStep.cpp:321
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::BookStep::operator!=
friend bool operator!=(BookStep const &lhs, BookStep const &rhs)
Definition: BookStep.cpp:177
ripple::Step::bookStepBook
virtual boost::optional< Book > bookStepBook() const
If this step is a BookStep, return the book.
Definition: Steps.h:195
ripple::ReadView::parentCloseTime
NetClock::time_point parentCloseTime() const
Returns the close time of the previous ledger.
Definition: ReadView.h:253
ripple::BookStep::Cache
Definition: BookStep.cpp:57
ripple::tapNONE
@ tapNONE
Definition: ApplyView.h:31
ripple::temBAD_PATH
@ temBAD_PATH
Definition: TER.h:91
ripple::BookStep::strandDst_
AccountID strandDst_
Definition: BookStep.cpp:49
ripple::BookStep::validFwd
std::pair< bool, EitherAmount > validFwd(PaymentSandbox &sb, ApplyView &afView, EitherAmount const &in) override
Definition: BookStep.cpp:992
ripple::test::bookStepEqual
bool bookStepEqual(Step const &step, ripple::Book const &book)
Definition: BookStep.cpp:1104
ripple::BookStep::inactive_
bool inactive_
Definition: BookStep.cpp:54
ripple::parityRate
const Rate parityRate(QUALITY_ONE)
A transfer rate signifying a 1:1 exchange.
Definition: Rate.h:94
ripple::BookStep::j_
const beast::Journal j_
Definition: BookStep.cpp:55
ripple::ApplyView
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:140
ripple::BookOfferCrossingStep::defaultPath_
const bool defaultPath_
Definition: BookStep.cpp:449
ripple::lsfHighAuth
@ lsfHighAuth
Definition: LedgerFormats.h:124
ripple::StrandDirection
StrandDirection
Definition: Steps.h:39
ripple::BookOfferCrossingStep::getOfrOutRate
std::uint32_t getOfrOutRate(Step const *prevStep, TOffer< TIn, TOut > const &offer, AccountID const &strandDst, std::uint32_t trOut) const
Definition: BookStep.cpp:414
ripple::BookStep::debtDirection
DebtDirection debtDirection(ReadView const &sb, StrandDirection dir) const override
Definition: BookStep.cpp:112
ripple::getRate
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition: STAmount.cpp:440
ripple::BookStep::ownerPaysTransferFee_
const bool ownerPaysTransferFee_
Definition: BookStep.cpp:52
ripple::BookPaymentStep::adjustQualityWithFees
Quality adjustQualityWithFees(ReadView const &v, Quality const &ofrQ, DebtDirection prevStepDir) const
Definition: BookStep.cpp:265
ripple::Keylet::key
uint256 key
Definition: Keylet.h:41
ripple::base_uint< 160, detail::AccountIDTag >
ripple::BookStep::qualityUpperBound
std::pair< boost::optional< Quality >, DebtDirection > qualityUpperBound(ReadView const &v, DebtDirection prevStepDir) const override
Definition: BookStep.cpp:466
ripple::lsfRequireAuth
@ lsfRequireAuth
Definition: LedgerFormats.h:106
ripple::BookStep::cache_
boost::optional< Cache > cache_
Definition: BookStep.cpp:67
ripple::StrandContext::view
ReadView const & view
Current ReadView.
Definition: Steps.h:474
ripple::BookStep::consumeOffer
void consumeOffer(PaymentSandbox &sb, TOffer< TIn, TOut > &offer, TAmounts< TIn, TOut > const &ofrAmt, TAmounts< TIn, TOut > const &stepAmt, TOut const &ownerGives) const
Definition: BookStep.cpp:655
ripple::QualityDirection::out
@ out
ripple::BookPaymentStep::checkQualityThreshold
bool checkQualityThreshold(TOffer< TIn, TOut > const &offer) const
Definition: BookStep.cpp:240
ripple::BookStep::cachedIn
boost::optional< EitherAmount > cachedIn() const override
Definition: BookStep.cpp:96
ripple::BookStep::fwdImp
std::pair< TIn, TOut > fwdImp(PaymentSandbox &sb, ApplyView &afView, boost::container::flat_set< uint256 > &ofrsToRm, TIn const &in)
Definition: BookStep.cpp:823
ripple::BookStep::BookStep
BookStep(StrandContext const &ctx, Issue const &in, Issue const &out)
Definition: BookStep.cpp:78
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:134
ripple::BookStep::check
TER check(StrandContext const &ctx) const
Definition: BookStep.cpp:1030
ripple::StrandContext::offerCrossing
const bool offerCrossing
true if offer crossing, not payment
Definition: Steps.h:482
ripple::BookTip::quality
Quality const & quality() const noexcept
Definition: BookTip.h:66
ripple::toSTAmount
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
Definition: AmountConversions.h:30
ripple::BookOfferCrossingStep::getQuality
static Quality getQuality(boost::optional< Quality > const &limitQuality)
Definition: BookStep.cpp:311
ripple::BookStep::strandSrc_
AccountID strandSrc_
Definition: BookStep.cpp:48
ripple::TERSubset< CanCvtToTER >
ripple::Sandbox
Discardable, editable view to a ledger.
Definition: Sandbox.h:34
ripple::BookOfferCrossingStep::qualityThreshold_
const Quality qualityThreshold_
Definition: BookStep.cpp:450
ripple::Step
A step in a payment path.
Definition: Steps.h:79
ripple::BookTip
Iterates and consumes raw offers in an order book.
Definition: BookTip.h:37
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j)
Definition: View.cpp:1125
ripple::DebtDirection::redeems
@ redeems
ripple::STAmount
Definition: STAmount.h:42
beast::Journal::error
Stream error() const
Definition: Journal.h:333
ripple::BookStep::getMaxOffersToConsume
static uint32_t getMaxOffersToConsume(StrandContext const &ctx)
Definition: BookStep.cpp:70
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:498
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:89
std::accumulate
T accumulate(T... args)
ripple::BookStep::Cache::Cache
Cache(TIn const &in_, TOut const &out_)
Definition: BookStep.cpp:62
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::BookStep::cachedOut
boost::optional< EitherAmount > cachedOut() const override
Definition: BookStep.cpp:104
std::uint32_t
ripple::Rules::enabled
bool enabled(uint256 const &id) const
Returns true if a feature is enabled.
Definition: ReadView.cpp:103
ripple::keylet::line
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:194
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::lsfHighNoRipple
@ lsfHighNoRipple
Definition: LedgerFormats.h:126
ripple::BookStep::operator==
friend bool operator==(BookStep const &lhs, BookStep const &rhs)
Definition: BookStep.cpp:171
std::decay_t
ripple::StrandDirection::reverse
@ reverse
ripple::DebtDirection::issues
@ issues
std::ostringstream
STL class.
ripple::BookPaymentStep::getOfrOutRate
std::uint32_t getOfrOutRate(Step const *, TOffer< TIn, TOut > const &, AccountID const &, std::uint32_t trOut) const
Definition: BookStep.cpp:255
ripple::redeems
bool redeems(DebtDirection dir)
Definition: Steps.h:42
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:192
ripple::Rate::value
std::uint32_t value
Definition: Rate.h:39
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::BookStep::prevStep_
Step const *const prevStep_
Definition: BookStep.cpp:51
ripple::BookStep
Definition: BookStep.cpp:43
ripple::BookOfferCrossingStep::checkQualityThreshold
bool checkQualityThreshold(TOffer< TIn, TOut > const &offer) const
Definition: BookStep.cpp:389
ripple::make_BookStepHelper
static std::pair< TER, std::unique_ptr< Step > > make_BookStepHelper(StrandContext const &ctx, Issue const &in, Issue const &out)
Definition: BookStep.cpp:1136
ripple::ReadView::rules
virtual Rules const & rules() const =0
Returns the tx processing rules.
ripple::sfFlags
const SF_UINT32 sfFlags
ripple::BookStep::book_
Book book_
Definition: BookStep.cpp:47
ripple::tecNO_ISSUER
@ tecNO_ISSUER
Definition: TER.h:260
ripple::EitherAmount
Definition: AmountSpec.h:57
ripple::StrandContext::prevStep
Step const *const prevStep
The previous step in the strand.
Definition: Steps.h:488
ripple::xrpIssue
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:97
ripple::SetUnion
void SetUnion(boost::container::flat_set< T > &dst, boost::container::flat_set< T > const &src)
Given two flat sets dst and src, compute dst = dst union src.
Definition: FlatSets.h:35
std::ostringstream::str
T str(T... args)
ripple::BookTip::step
bool step(beast::Journal j)
Erases the current offer and advance to the next offer.
Definition: BookTip.cpp:34
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::TOfferStreamBase::StepCounter::count
std::uint32_t count() const
Definition: OfferStream.h:64
ripple::BookStep::revImp
std::pair< TIn, TOut > revImp(PaymentSandbox &sb, ApplyView &afView, boost::container::flat_set< uint256 > &ofrsToRm, TOut const &out)
Definition: BookStep.cpp:703
ripple::Book
Specifies an order book.
Definition: Book.h:32
ripple::temBAD_PATH_LOOP
@ temBAD_PATH_LOOP
Definition: TER.h:92
numeric
ripple::BookOfferCrossingStep::limitSelfCrossQuality
bool limitSelfCrossQuality(AccountID const &strandSrc, AccountID const &strandDst, TOffer< TIn, TOut > const &offer, boost::optional< Quality > &ofrQ, FlowOfferStream< TIn, TOut > &offers, bool const offerAttempted) const
Definition: BookStep.cpp:332
ripple::BookStep::equal
bool equal(Step const &rhs) const override
Definition: BookStep.cpp:457
ripple::BookPaymentStep::limitSelfCrossQuality
bool limitSelfCrossQuality(AccountID const &, AccountID const &, TOffer< TIn, TOut > const &offer, boost::optional< Quality > &, FlowOfferStream< TIn, TOut > &, bool) const
Definition: BookStep.cpp:227
ripple::make_BookStepIX
std::pair< TER, std::unique_ptr< Step > > make_BookStepIX(StrandContext const &ctx, Issue const &in)
Definition: BookStep.cpp:1167
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:494
std::unique_ptr
STL class.
ripple::featureFlowCross
const uint256 featureFlowCross
Definition: Feature.cpp:166
ripple::Step::directStepSrcAcct
virtual boost::optional< AccountID > directStepSrcAcct() const
If this step is DirectStepI (IOU->IOU direct step), return the src account.
Definition: Steps.h:139
ripple::sum
static auto sum(TCollection const &col)
Definition: BookStep.cpp:693
ripple::BookStep::Cache::in
TIn in
Definition: BookStep.cpp:59
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:216
ripple::BookPaymentStep::logString
std::string logString() const override
Definition: BookStep.cpp:293
ripple::TOffer
Definition: Offer.h:49
ripple::Book::in
Issue in
Definition: Book.h:35
ripple::StrandDirection::forward
@ forward
ripple::Issue::account
AccountID account
Definition: Issue.h:38
ripple::BookStep::Cache::out
TOut out
Definition: BookStep.cpp:60
ripple::XRPAmount
Definition: XRPAmount.h:46
ripple::BookOfferCrossingStep::adjustQualityWithFees
Quality adjustQualityWithFees(ReadView const &v, Quality const &ofrQ, DebtDirection prevStepDir) const
Definition: BookStep.cpp:428