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