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