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