rippled
PaySteps.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/Steps.h>
21 #include <ripple/basics/IOUAmount.h>
22 #include <ripple/basics/XRPAmount.h>
23 #include <ripple/basics/contract.h>
24 #include <ripple/json/json_writer.h>
25 #include <ripple/ledger/ReadView.h>
26 #include <ripple/protocol/Feature.h>
27 
28 #include <algorithm>
29 #include <numeric>
30 #include <sstream>
31 
32 namespace ripple {
33 
34 // Check equal with tolerance
35 bool
36 checkNear(IOUAmount const& expected, IOUAmount const& actual)
37 {
38  double const ratTol = 0.001;
39  if (abs(expected.exponent() - actual.exponent()) > 1)
40  return false;
41 
42  if (actual.exponent() < -20)
43  return true;
44 
45  auto const a = (expected.exponent() < actual.exponent())
46  ? expected.mantissa() / 10
47  : expected.mantissa();
48  auto const b = (actual.exponent() < expected.exponent())
49  ? actual.mantissa() / 10
50  : actual.mantissa();
51  if (a == b)
52  return true;
53 
54  double const diff = std::abs(a - b);
55  auto const r = diff / std::max(std::abs(a), std::abs(b));
56  return r <= ratTol;
57 };
58 
59 bool
60 checkNear(XRPAmount const& expected, XRPAmount const& actual)
61 {
62  return expected == actual;
63 };
64 
65 static bool
67 {
69  return false;
70  return isXRP(pe.getAccountID());
71 };
72 
75  StrandContext const& ctx,
76  STPathElement const* e1,
77  STPathElement const* e2,
78  Issue const& curIssue)
79 {
80  auto& j = ctx.j;
81 
82  if (ctx.isFirst && e1->isAccount() &&
84  isXRP(e1->getCurrency()))
85  {
86  return make_XRPEndpointStep(ctx, e1->getAccountID());
87  }
88 
89  if (ctx.isLast && isXRPAccount(*e1) && e2->isAccount())
90  return make_XRPEndpointStep(ctx, e2->getAccountID());
91 
92  if (e1->isAccount() && e2->isAccount())
93  {
94  return make_DirectStepI(
95  ctx, e1->getAccountID(), e2->getAccountID(), curIssue.currency);
96  }
97 
98  if (e1->isOffer() && e2->isAccount())
99  {
100  // should already be taken care of
101  JLOG(j.error())
102  << "Found offer/account payment step. Aborting payment strand.";
103  assert(0);
105  }
106 
107  assert(
110  auto const outCurrency = e2->getNodeType() & STPathElement::typeCurrency
111  ? e2->getCurrency()
112  : curIssue.currency;
113  auto const outIssuer = e2->getNodeType() & STPathElement::typeIssuer
114  ? e2->getIssuerID()
115  : curIssue.account;
116 
117  if (isXRP(curIssue.currency) && isXRP(outCurrency))
118  {
119  JLOG(j.info()) << "Found xrp/xrp offer payment step";
121  }
122 
123  assert(e2->isOffer());
124 
125  if (isXRP(outCurrency))
126  return make_BookStepIX(ctx, curIssue);
127 
128  if (isXRP(curIssue.currency))
129  return make_BookStepXI(ctx, {outCurrency, outIssuer});
130 
131  return make_BookStepII(ctx, curIssue, {outCurrency, outIssuer});
132 }
133 
136  ReadView const& view,
137  AccountID const& src,
138  AccountID const& dst,
139  Issue const& deliver,
140  std::optional<Quality> const& limitQuality,
141  std::optional<Issue> const& sendMaxIssue,
142  STPath const& path,
143  bool ownerPaysTransferFee,
144  bool offerCrossing,
145  beast::Journal j)
146 {
147  if (isXRP(src) || isXRP(dst) || !isConsistent(deliver) ||
148  (sendMaxIssue && !isConsistent(*sendMaxIssue)))
149  return {temBAD_PATH, Strand{}};
150 
151  if ((sendMaxIssue && sendMaxIssue->account == noAccount()) ||
152  (src == noAccount()) || (dst == noAccount()) ||
153  (deliver.account == noAccount()))
154  return {temBAD_PATH, Strand{}};
155 
156  for (auto const& pe : path)
157  {
158  auto const t = pe.getNodeType();
159 
160  if ((t & ~STPathElement::typeAll) || !t)
161  return {temBAD_PATH, Strand{}};
162 
163  bool const hasAccount = t & STPathElement::typeAccount;
164  bool const hasIssuer = t & STPathElement::typeIssuer;
165  bool const hasCurrency = t & STPathElement::typeCurrency;
166 
167  if (hasAccount && (hasIssuer || hasCurrency))
168  return {temBAD_PATH, Strand{}};
169 
170  if (hasIssuer && isXRP(pe.getIssuerID()))
171  return {temBAD_PATH, Strand{}};
172 
173  if (hasAccount && isXRP(pe.getAccountID()))
174  return {temBAD_PATH, Strand{}};
175 
176  if (hasCurrency && hasIssuer &&
177  isXRP(pe.getCurrency()) != isXRP(pe.getIssuerID()))
178  return {temBAD_PATH, Strand{}};
179 
180  if (hasIssuer && (pe.getIssuerID() == noAccount()))
181  return {temBAD_PATH, Strand{}};
182 
183  if (hasAccount && (pe.getAccountID() == noAccount()))
184  return {temBAD_PATH, Strand{}};
185  }
186 
187  Issue curIssue = [&] {
188  auto const& currency =
189  sendMaxIssue ? sendMaxIssue->currency : deliver.currency;
190  if (isXRP(currency))
191  return xrpIssue();
192  return Issue{currency, src};
193  }();
194 
195  auto hasCurrency = [](STPathElement const pe) {
196  return pe.getNodeType() & STPathElement::typeCurrency;
197  };
198 
200  // reserve enough for the path, the implied source, destination,
201  // sendmax and deliver.
202  normPath.reserve(4 + path.size());
203  {
204  normPath.emplace_back(
205  STPathElement::typeAll, src, curIssue.currency, curIssue.account);
206 
207  if (sendMaxIssue && sendMaxIssue->account != src &&
208  (path.empty() || !path[0].isAccount() ||
209  path[0].getAccountID() != sendMaxIssue->account))
210  {
211  normPath.emplace_back(
212  sendMaxIssue->account, std::nullopt, std::nullopt);
213  }
214 
215  for (auto const& i : path)
216  normPath.push_back(i);
217 
218  {
219  // Note that for offer crossing (only) we do use an offer book
220  // even if all that is changing is the Issue.account.
221  STPathElement const& lastCurrency =
222  *std::find_if(normPath.rbegin(), normPath.rend(), hasCurrency);
223  if ((lastCurrency.getCurrency() != deliver.currency) ||
224  (offerCrossing &&
225  lastCurrency.getIssuerID() != deliver.account))
226  {
227  normPath.emplace_back(
228  std::nullopt, deliver.currency, deliver.account);
229  }
230  }
231 
232  if (!((normPath.back().isAccount() &&
233  normPath.back().getAccountID() == deliver.account) ||
234  (dst == deliver.account)))
235  {
236  normPath.emplace_back(deliver.account, std::nullopt, std::nullopt);
237  }
238 
239  if (!normPath.back().isAccount() ||
240  normPath.back().getAccountID() != dst)
241  {
242  normPath.emplace_back(dst, std::nullopt, std::nullopt);
243  }
244  }
245 
246  if (normPath.size() < 2)
247  return {temBAD_PATH, Strand{}};
248 
249  auto const strandSrc = normPath.front().getAccountID();
250  auto const strandDst = normPath.back().getAccountID();
251  bool const isDefaultPath = path.empty();
252 
253  Strand result;
254  result.reserve(2 * normPath.size());
255 
256  /* A strand may not include the same account node more than once
257  in the same currency. In a direct step, an account will show up
258  at most twice: once as a src and once as a dst (hence the two element
259  array). The strandSrc and strandDst will only show up once each.
260  */
262  // A strand may not include the same offer book more than once
263  boost::container::flat_set<Issue> seenBookOuts;
264  seenDirectIssues[0].reserve(normPath.size());
265  seenDirectIssues[1].reserve(normPath.size());
266  seenBookOuts.reserve(normPath.size());
267  auto ctx = [&](bool isLast = false) {
268  return StrandContext{
269  view,
270  result,
271  strandSrc,
272  strandDst,
273  deliver,
274  limitQuality,
275  isLast,
276  ownerPaysTransferFee,
277  offerCrossing,
279  seenDirectIssues,
280  seenBookOuts,
281  j};
282  };
283 
284  for (std::size_t i = 0; i < normPath.size() - 1; ++i)
285  {
286  /* Iterate through the path elements considering them in pairs.
287  The first element of the pair is `cur` and the second element is
288  `next`. When an offer is one of the pairs, the step created will be
289  for `next`. This means when `cur` is an offer and `next` is an
290  account then no step is created, as a step has already been created
291  for that offer.
292  */
294  auto cur = &normPath[i];
295  auto const next = &normPath[i + 1];
296 
297  if (cur->isAccount())
298  curIssue.account = cur->getAccountID();
299  else if (cur->hasIssuer())
300  curIssue.account = cur->getIssuerID();
301 
302  if (cur->hasCurrency())
303  {
304  curIssue.currency = cur->getCurrency();
305  if (isXRP(curIssue.currency))
306  curIssue.account = xrpAccount();
307  }
308 
309  if (cur->isAccount() && next->isAccount())
310  {
311  if (!isXRP(curIssue.currency) &&
312  curIssue.account != cur->getAccountID() &&
313  curIssue.account != next->getAccountID())
314  {
315  JLOG(j.trace()) << "Inserting implied account";
316  auto msr = make_DirectStepI(
317  ctx(),
318  cur->getAccountID(),
319  curIssue.account,
320  curIssue.currency);
321  if (msr.first != tesSUCCESS)
322  return {msr.first, Strand{}};
323  result.push_back(std::move(msr.second));
324  impliedPE.emplace(
326  curIssue.account,
327  xrpCurrency(),
328  xrpAccount());
329  cur = &*impliedPE;
330  }
331  }
332  else if (cur->isAccount() && next->isOffer())
333  {
334  if (curIssue.account != cur->getAccountID())
335  {
336  JLOG(j.trace()) << "Inserting implied account before offer";
337  auto msr = make_DirectStepI(
338  ctx(),
339  cur->getAccountID(),
340  curIssue.account,
341  curIssue.currency);
342  if (msr.first != tesSUCCESS)
343  return {msr.first, Strand{}};
344  result.push_back(std::move(msr.second));
345  impliedPE.emplace(
347  curIssue.account,
348  xrpCurrency(),
349  xrpAccount());
350  cur = &*impliedPE;
351  }
352  }
353  else if (cur->isOffer() && next->isAccount())
354  {
355  if (curIssue.account != next->getAccountID() &&
356  !isXRP(next->getAccountID()))
357  {
358  if (isXRP(curIssue))
359  {
360  if (i != normPath.size() - 2)
361  return {temBAD_PATH, Strand{}};
362  else
363  {
364  // Last step. insert xrp endpoint step
365  auto msr =
366  make_XRPEndpointStep(ctx(), next->getAccountID());
367  if (msr.first != tesSUCCESS)
368  return {msr.first, Strand{}};
369  result.push_back(std::move(msr.second));
370  }
371  }
372  else
373  {
374  JLOG(j.trace()) << "Inserting implied account after offer";
375  auto msr = make_DirectStepI(
376  ctx(),
377  curIssue.account,
378  next->getAccountID(),
379  curIssue.currency);
380  if (msr.first != tesSUCCESS)
381  return {msr.first, Strand{}};
382  result.push_back(std::move(msr.second));
383  }
384  }
385  continue;
386  }
387 
388  if (!next->isOffer() && next->hasCurrency() &&
389  next->getCurrency() != curIssue.currency)
390  {
391  // Should never happen
392  assert(0);
393  return {temBAD_PATH, Strand{}};
394  }
395 
396  auto s = toStep(
397  ctx(/*isLast*/ i == normPath.size() - 2), cur, next, curIssue);
398  if (s.first == tesSUCCESS)
399  result.emplace_back(std::move(s.second));
400  else
401  {
402  JLOG(j.debug()) << "toStep failed: " << s.first;
403  return {s.first, Strand{}};
404  }
405  }
406 
407  auto checkStrand = [&]() -> bool {
408  auto stepAccts = [](Step const& s) -> std::pair<AccountID, AccountID> {
409  if (auto r = s.directStepAccts())
410  return *r;
411  if (auto const r = s.bookStepBook())
412  return std::make_pair(r->in.account, r->out.account);
413  Throw<FlowException>(
414  tefEXCEPTION, "Step should be either a direct or book step");
415  return std::make_pair(xrpAccount(), xrpAccount());
416  };
417 
418  auto curAcc = src;
419  auto curIss = [&] {
420  auto& currency =
421  sendMaxIssue ? sendMaxIssue->currency : deliver.currency;
422  if (isXRP(currency))
423  return xrpIssue();
424  return Issue{currency, src};
425  }();
426 
427  for (auto const& s : result)
428  {
429  auto const accts = stepAccts(*s);
430  if (accts.first != curAcc)
431  return false;
432 
433  if (auto const b = s->bookStepBook())
434  {
435  if (curIss != b->in)
436  return false;
437  curIss = b->out;
438  }
439  else
440  {
441  curIss.account = accts.second;
442  }
443 
444  curAcc = accts.second;
445  }
446  if (curAcc != dst)
447  return false;
448  if (curIss.currency != deliver.currency)
449  return false;
450  if (curIss.account != deliver.account && curIss.account != dst)
451  return false;
452  return true;
453  };
454 
455  if (!checkStrand())
456  {
457  JLOG(j.warn()) << "Flow check strand failed";
458  assert(0);
459  return {temBAD_PATH, Strand{}};
460  }
461 
462  return {tesSUCCESS, std::move(result)};
463 }
464 
467  ReadView const& view,
468  AccountID const& src,
469  AccountID const& dst,
470  Issue const& deliver,
471  std::optional<Quality> const& limitQuality,
472  std::optional<Issue> const& sendMax,
473  STPathSet const& paths,
474  bool addDefaultPath,
475  bool ownerPaysTransferFee,
476  bool offerCrossing,
477  beast::Journal j)
478 {
479  std::vector<Strand> result;
480  result.reserve(1 + paths.size());
481  // Insert the strand into result if it is not already part of the vector
482  auto insert = [&](Strand s) {
483  bool const hasStrand =
484  std::find(result.begin(), result.end(), s) != result.end();
485 
486  if (!hasStrand)
487  result.emplace_back(std::move(s));
488  };
489 
490  if (addDefaultPath)
491  {
492  auto sp = toStrand(
493  view,
494  src,
495  dst,
496  deliver,
497  limitQuality,
498  sendMax,
499  STPath(),
500  ownerPaysTransferFee,
501  offerCrossing,
502  j);
503  auto const ter = sp.first;
504  auto& strand = sp.second;
505 
506  if (ter != tesSUCCESS)
507  {
508  JLOG(j.trace()) << "failed to add default path";
509  if (isTemMalformed(ter) || paths.empty())
510  {
511  return {ter, std::vector<Strand>{}};
512  }
513  }
514  else if (strand.empty())
515  {
516  JLOG(j.trace()) << "toStrand failed";
517  Throw<FlowException>(
518  tefEXCEPTION, "toStrand returned tes & empty strand");
519  }
520  else
521  {
522  insert(std::move(strand));
523  }
524  }
525  else if (paths.empty())
526  {
527  JLOG(j.debug()) << "Flow: Invalid transaction: No paths and direct "
528  "ripple not allowed.";
530  }
531 
532  TER lastFailTer = tesSUCCESS;
533  for (auto const& p : paths)
534  {
535  auto sp = toStrand(
536  view,
537  src,
538  dst,
539  deliver,
540  limitQuality,
541  sendMax,
542  p,
543  ownerPaysTransferFee,
544  offerCrossing,
545  j);
546  auto ter = sp.first;
547  auto& strand = sp.second;
548 
549  if (ter != tesSUCCESS)
550  {
551  lastFailTer = ter;
552  JLOG(j.trace()) << "failed to add path: ter: " << ter
553  << "path: " << p.getJson(JsonOptions::none);
554  if (isTemMalformed(ter))
555  return {ter, std::vector<Strand>{}};
556  }
557  else if (strand.empty())
558  {
559  JLOG(j.trace()) << "toStrand failed";
560  Throw<FlowException>(
561  tefEXCEPTION, "toStrand returned tes & empty strand");
562  }
563  else
564  {
565  insert(std::move(strand));
566  }
567  }
568 
569  if (result.empty())
570  return {lastFailTer, std::move(result)};
571 
572  return {tesSUCCESS, std::move(result)};
573 }
574 
576  ReadView const& view_,
577  std::vector<std::unique_ptr<Step>> const& strand_,
578  // A strand may not include an inner node that
579  // replicates the source or destination.
580  AccountID const& strandSrc_,
581  AccountID const& strandDst_,
582  Issue const& strandDeliver_,
583  std::optional<Quality> const& limitQuality_,
584  bool isLast_,
585  bool ownerPaysTransferFee_,
586  bool offerCrossing_,
587  bool isDefaultPath_,
588  std::array<boost::container::flat_set<Issue>, 2>& seenDirectIssues_,
589  boost::container::flat_set<Issue>& seenBookOuts_,
590  beast::Journal j_)
591  : view(view_)
592  , strandSrc(strandSrc_)
593  , strandDst(strandDst_)
594  , strandDeliver(strandDeliver_)
595  , limitQuality(limitQuality_)
596  , isFirst(strand_.empty())
597  , isLast(isLast_)
598  , ownerPaysTransferFee(ownerPaysTransferFee_)
599  , offerCrossing(offerCrossing_)
600  , isDefaultPath(isDefaultPath_)
601  , strandSize(strand_.size())
602  , prevStep(!strand_.empty() ? strand_.back().get() : nullptr)
603  , seenDirectIssues(seenDirectIssues_)
604  , seenBookOuts(seenBookOuts_)
605  , j(j_)
606 {
607 }
608 
609 template <class InAmt, class OutAmt>
610 bool
611 isDirectXrpToXrp(Strand const& strand)
612 {
613  return false;
614 }
615 
616 template <>
617 bool
619 {
620  return (strand.size() == 2);
621 }
622 
623 template bool
624 isDirectXrpToXrp<XRPAmount, IOUAmount>(Strand const& strand);
625 template bool
626 isDirectXrpToXrp<IOUAmount, XRPAmount>(Strand const& strand);
627 template bool
628 isDirectXrpToXrp<IOUAmount, IOUAmount>(Strand const& strand);
629 
630 } // namespace ripple
ripple::StrandContext
Context needed to build Strand Steps and for error checking.
Definition: Steps.h:497
sstream
ripple::IOUAmount::exponent
int exponent() const noexcept
Definition: IOUAmount.h:163
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
ripple::STPathElement::isOffer
bool isOffer() const
Definition: STPathSet.h:323
ripple::isConsistent
bool isConsistent(Book const &book)
Definition: Book.cpp:25
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::make_BookStepXI
std::pair< TER, std::unique_ptr< Step > > make_BookStepXI(StrandContext const &ctx, Issue const &out)
Definition: BookStep.cpp:1192
ripple::STPathElement::typeAll
@ typeAll
Definition: STPathSet.h:52
ripple::make_BookStepII
std::pair< TER, std::unique_ptr< Step > > make_BookStepII(StrandContext const &ctx, Issue const &in, Issue const &out)
Definition: BookStep.cpp:1180
std::pair
std::vector::reserve
T reserve(T... args)
std::vector
STL class.
std::find_if
T find_if(T... args)
std::vector::size
T size(T... args)
ripple::STPathElement::getCurrency
Currency const & getCurrency() const
Definition: STPathSet.h:361
ripple::isDefaultPath
static bool isDefaultPath(STPath const &path)
Definition: Pathfinder.cpp:455
ripple::checkNear
bool checkNear(IOUAmount const &expected, IOUAmount const &actual)
Definition: PaySteps.cpp:36
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
ripple::isDirectXrpToXrp< IOUAmount, IOUAmount >
template bool isDirectXrpToXrp< IOUAmount, IOUAmount >(Strand const &strand)
std::optional::emplace
T emplace(T... args)
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::make_DirectStepI
std::pair< TER, std::unique_ptr< Step > > make_DirectStepI(StrandContext const &ctx, AccountID const &src, AccountID const &dst, Currency const &c)
Definition: DirectStep.cpp:976
ripple::IOUAmount
Floating point representation of amounts with high dynamic range.
Definition: IOUAmount.h:43
std::vector::back
T back(T... args)
ripple::toStrand
std::pair< TER, Strand > toStrand(ReadView const &view, AccountID const &src, AccountID const &dst, Issue const &deliver, std::optional< Quality > const &limitQuality, std::optional< Issue > const &sendMaxIssue, STPath const &path, bool ownerPaysTransferFee, bool offerCrossing, beast::Journal j)
Create a Strand for the specified path.
Definition: PaySteps.cpp:135
ripple::temBAD_PATH
@ temBAD_PATH
Definition: TER.h:94
std::vector::front
T front(T... args)
ripple::STPathElement::typeCurrency
@ typeCurrency
Definition: STPathSet.h:49
ripple::STPathSet
Definition: STPathSet.h:176
algorithm
ripple::STPathSet::empty
bool empty() const
Definition: STPathSet.h:503
ripple::STPathElement::typeIssuer
@ typeIssuer
Definition: STPathSet.h:50
std::vector::push_back
T push_back(T... args)
ripple::toStrands
std::pair< TER, std::vector< Strand > > toStrands(ReadView const &view, AccountID const &src, AccountID const &dst, Issue const &deliver, std::optional< Quality > const &limitQuality, std::optional< Issue > const &sendMax, STPathSet const &paths, bool addDefaultPath, bool ownerPaysTransferFee, bool offerCrossing, beast::Journal j)
Create a Strand for each specified path (including the default path, if indicated)
Definition: PaySteps.cpp:466
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:82
ripple::toStep
static std::pair< TER, std::unique_ptr< Step > > toStep(StrandContext const &ctx, STPathElement const *e1, STPathElement const *e2, Issue const &curIssue)
Definition: PaySteps.cpp:74
ripple::STPathElement::getNodeType
auto getNodeType() const
Definition: STPathSet.h:317
ripple::STPathSet::size
std::vector< STPath >::size_type size() const
Definition: STPathSet.h:497
ripple::JsonOptions::none
@ none
ripple::TERSubset< CanCvtToTER >
ripple::make_XRPEndpointStep
std::pair< TER, std::unique_ptr< Step > > make_XRPEndpointStep(StrandContext const &ctx, AccountID const &acc)
Definition: XRPEndpointStep.cpp:399
ripple::Step
A step in a payment path.
Definition: Steps.h:79
std::array
STL class.
ripple::xrpAccount
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:168
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:89
ripple::StrandContext::isLast
const bool isLast
true if Step is last in Strand
Definition: Steps.h:505
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::isDirectXrpToXrp
bool isDirectXrpToXrp(Strand const &strand)
Definition: PaySteps.cpp:611
ripple::StrandContext::j
const beast::Journal j
Definition: Steps.h:524
ripple::STPathElement::getIssuerID
AccountID const & getIssuerID() const
Definition: STPathSet.h:367
std::vector::rend
T rend(T... args)
ripple::isDirectXrpToXrp< XRPAmount, XRPAmount >
bool isDirectXrpToXrp< XRPAmount, XRPAmount >(Strand const &strand)
Definition: PaySteps.cpp:618
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:125
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::IOUAmount::mantissa
std::int64_t mantissa() const noexcept
Definition: IOUAmount.h:169
ripple::abs
constexpr Number abs(Number x) noexcept
Definition: Number.h:327
ripple::StrandContext::StrandContext
StrandContext(ReadView const &view_, std::vector< std::unique_ptr< Step >> const &strand_, AccountID const &strandSrc_, AccountID const &strandDst_, Issue const &strandDeliver_, std::optional< Quality > const &limitQuality_, bool isLast_, bool ownerPaysTransferFee_, bool offerCrossing_, bool isDefaultPath_, std::array< boost::container::flat_set< Issue >, 2 > &seenDirectIssues_, boost::container::flat_set< Issue > &seenBookOuts_, beast::Journal j_)
StrandContext constructor.
Definition: PaySteps.cpp:575
ripple::STPathElement
Definition: STPathSet.h:34
ripple::isXRPAccount
static bool isXRPAccount(STPathElement const &pe)
Definition: PaySteps.cpp:66
std::vector::begin
T begin(T... args)
ripple::STPathElement::typeAccount
@ typeAccount
Definition: STPathSet.h:47
ripple::temRIPPLE_EMPTY
@ temRIPPLE_EMPTY
Definition: TER.h:111
ripple::StrandContext::isFirst
const bool isFirst
true if Step is first in Strand
Definition: Steps.h:504
std::vector::empty
T empty(T... args)
ripple::xrpIssue
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:95
std::optional< Quality >
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t
std::make_pair
T make_pair(T... args)
std::vector::end
T end(T... args)
ripple::tefEXCEPTION
@ tefEXCEPTION
Definition: TER.h:154
numeric
std::max
T max(T... args)
ripple::isDirectXrpToXrp< IOUAmount, XRPAmount >
template bool isDirectXrpToXrp< IOUAmount, XRPAmount >(Strand const &strand)
ripple::STPathElement::isAccount
bool isAccount() const
Definition: STPathSet.h:329
ripple::make_BookStepIX
std::pair< TER, std::unique_ptr< Step > > make_BookStepIX(StrandContext const &ctx, Issue const &in)
Definition: BookStep.cpp:1186
std::unique_ptr
STL class.
ripple::STPath
Definition: STPathSet.h:118
ripple::isDirectXrpToXrp< XRPAmount, IOUAmount >
template bool isDirectXrpToXrp< XRPAmount, IOUAmount >(Strand const &strand)
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:222
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:175
ripple::xrpCurrency
Currency const & xrpCurrency()
XRP currency.
Definition: UintTypes.cpp:121
ripple::isTemMalformed
bool isTemMalformed(TER x)
Definition: TER.h:579
ripple::Issue::account
AccountID account
Definition: Issue.h:38
std::vector::rbegin
T rbegin(T... args)
ripple::get
T & get(EitherAmount &amt)
Definition: AmountSpec.h:118
ripple::XRPAmount
Definition: XRPAmount.h:46
ripple::STPathElement::getAccountID
AccountID const & getAccountID() const
Definition: STPathSet.h:355