rippled
Path_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2015 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/AccountCurrencies.h>
21 #include <ripple/basics/contract.h>
22 #include <ripple/beast/unit_test.h>
23 #include <ripple/core/JobQueue.h>
24 #include <ripple/json/json_reader.h>
25 #include <ripple/json/to_string.h>
26 #include <ripple/protocol/STParsedJSON.h>
27 #include <ripple/protocol/TxFlags.h>
28 #include <ripple/protocol/jss.h>
29 #include <ripple/resource/Fees.h>
30 #include <ripple/rpc/Context.h>
31 #include <ripple/rpc/RPCHandler.h>
32 #include <ripple/rpc/impl/RPCHelpers.h>
33 #include <ripple/rpc/impl/Tuning.h>
34 #include <chrono>
35 #include <condition_variable>
36 #include <mutex>
37 #include <test/jtx.h>
38 #include <thread>
39 
40 namespace ripple {
41 namespace test {
42 
43 //------------------------------------------------------------------------------
44 
45 namespace detail {
46 
47 void
49 {
50  st.push_back(STPathElement({account.id(), boost::none, boost::none}));
51 }
52 
53 template <class T>
55 stpath_append_one(STPath& st, T const& t)
56 {
58 }
59 
60 void
62 {
63  st.push_back(STPathElement({iou.account.id(), iou.currency, boost::none}));
64 }
65 
66 void
68 {
69  st.push_back(pe);
70 }
71 
72 void
74 {
75  st.push_back(STPathElement({boost::none, book.currency, book.account}));
76 }
77 
78 template <class T, class... Args>
79 void
80 stpath_append(STPath& st, T const& t, Args const&... args)
81 {
82  stpath_append_one(st, t);
83  if constexpr (sizeof...(args) > 0)
84  stpath_append(st, args...);
85 }
86 
87 template <class... Args>
88 void
89 stpathset_append(STPathSet& st, STPath const& p, Args const&... args)
90 {
91  st.push_back(p);
92  if constexpr (sizeof...(args) > 0)
93  stpathset_append(st, args...);
94 }
95 
96 } // namespace detail
97 
98 template <class... Args>
99 STPath
100 stpath(Args const&... args)
101 {
102  STPath st;
103  detail::stpath_append(st, args...);
104  return st;
105 }
106 
107 template <class... Args>
108 bool
109 same(STPathSet const& st1, Args const&... args)
110 {
111  STPathSet st2;
112  detail::stpathset_append(st2, args...);
113  if (st1.size() != st2.size())
114  return false;
115 
116  for (auto const& p : st2)
117  {
118  if (std::find(st1.begin(), st1.end(), p) == st1.end())
119  return false;
120  }
121  return true;
122 }
123 
124 bool
125 equal(STAmount const& sa1, STAmount const& sa2)
126 {
127  return sa1 == sa2 && sa1.issue().account == sa2.issue().account;
128 }
129 
131 rpf(jtx::Account const& src, jtx::Account const& dst, std::uint32_t num_src)
132 {
134  jv[jss::command] = "ripple_path_find";
135  jv[jss::source_account] = toBase58(src);
136 
137  if (num_src > 0)
138  {
139  auto& sc = (jv[jss::source_currencies] = Json::arrayValue);
141  while (num_src--)
142  {
143  j[jss::currency] = std::to_string(num_src + 100);
144  sc.append(j);
145  }
146  }
147 
148  auto const d = toBase58(dst);
149  jv[jss::destination_account] = d;
150 
151  Json::Value& j = (jv[jss::destination_amount] = Json::objectValue);
152  j[jss::currency] = "USD";
153  j[jss::value] = "0.01";
154  j[jss::issuer] = d;
155 
156  return jv;
157 }
158 
159 // Issue path element
160 auto
161 IPE(Issue const& iss)
162 {
163  return STPathElement(
165  xrpAccount(),
166  iss.currency,
167  iss.account);
168 };
169 
170 //------------------------------------------------------------------------------
171 
172 class Path_test : public beast::unit_test::suite
173 {
174 public:
175  class gate
176  {
177  private:
180  bool signaled_ = false;
181 
182  public:
183  // Thread safe, blocks until signaled or period expires.
184  // Returns `true` if signaled.
185  template <class Rep, class Period>
186  bool
188  {
190  auto b = cv_.wait_for(lk, rel_time, [=] { return signaled_; });
191  signaled_ = false;
192  return b;
193  }
194 
195  void
197  {
199  signaled_ = true;
200  cv_.notify_all();
201  }
202  };
203 
204  auto
206  jtx::Env& env,
207  jtx::Account const& src,
208  jtx::Account const& dst,
209  STAmount const& saDstAmount,
210  boost::optional<STAmount> const& saSendMax = boost::none,
211  boost::optional<Currency> const& saSrcCurrency = boost::none)
212  {
213  using namespace jtx;
214 
215  auto& app = env.app();
218 
219  RPC::JsonContext context{
220  {env.journal,
221  app,
222  loadType,
223  app.getOPs(),
224  app.getLedgerMaster(),
225  c,
226  Role::USER,
227  {},
228  {},
230  {},
231  {}};
232 
234  params[jss::command] = "ripple_path_find";
235  params[jss::source_account] = toBase58(src);
236  params[jss::destination_account] = toBase58(dst);
237  params[jss::destination_amount] =
238  saDstAmount.getJson(JsonOptions::none);
239  if (saSendMax)
240  params[jss::send_max] = saSendMax->getJson(JsonOptions::none);
241  if (saSrcCurrency)
242  {
243  auto& sc = params[jss::source_currencies] = Json::arrayValue;
245  j[jss::currency] = to_string(saSrcCurrency.value());
246  sc.append(j);
247  }
248 
249  Json::Value result;
250  gate g;
251  app.getJobQueue().postCoro(
252  jtCLIENT, "RPC-Client", [&](auto const& coro) {
253  context.params = std::move(params);
254  context.coro = coro;
255  RPC::doCommand(context, result);
256  g.signal();
257  });
258 
259  using namespace std::chrono_literals;
260  BEAST_EXPECT(g.wait_for(5s));
261  BEAST_EXPECT(!result.isMember(jss::error));
262  return result;
263  }
264 
267  jtx::Env& env,
268  jtx::Account const& src,
269  jtx::Account const& dst,
270  STAmount const& saDstAmount,
271  boost::optional<STAmount> const& saSendMax = boost::none,
272  boost::optional<Currency> const& saSrcCurrency = boost::none)
273  {
275  env, src, dst, saDstAmount, saSendMax, saSrcCurrency);
276  BEAST_EXPECT(!result.isMember(jss::error));
277 
278  STAmount da;
279  if (result.isMember(jss::destination_amount))
280  da = amountFromJson(sfGeneric, result[jss::destination_amount]);
281 
282  STAmount sa;
284  if (result.isMember(jss::alternatives))
285  {
286  auto const& alts = result[jss::alternatives];
287  if (alts.size() > 0)
288  {
289  auto const& path = alts[0u];
290 
291  if (path.isMember(jss::source_amount))
292  sa = amountFromJson(sfGeneric, path[jss::source_amount]);
293 
294  if (path.isMember(jss::destination_amount))
295  da = amountFromJson(
296  sfGeneric, path[jss::destination_amount]);
297 
298  if (path.isMember(jss::paths_computed))
299  {
300  Json::Value p;
301  p["Paths"] = path[jss::paths_computed];
302  STParsedJSONObject po("generic", p);
303  paths = po.object->getFieldPathSet(sfPaths);
304  }
305  }
306  }
307 
308  return std::make_tuple(std::move(paths), std::move(sa), std::move(da));
309  }
310 
311  void
313  {
314  testcase("source currency limits");
315  using namespace std::chrono_literals;
316  using namespace jtx;
317  Env env(*this);
318  auto const gw = Account("gateway");
319  env.fund(XRP(10000), "alice", "bob", gw);
320  env.trust(gw["USD"](100), "alice", "bob");
321  env.close();
322 
323  auto& app = env.app();
326 
327  RPC::JsonContext context{
328  {env.journal,
329  app,
330  loadType,
331  app.getOPs(),
332  app.getLedgerMaster(),
333  c,
334  Role::USER,
335  {},
336  {},
338  {},
339  {}};
340  Json::Value result;
341  gate g;
342  // Test RPC::Tuning::max_src_cur source currencies.
343  app.getJobQueue().postCoro(
344  jtCLIENT, "RPC-Client", [&](auto const& coro) {
345  context.params = rpf(
346  Account("alice"), Account("bob"), RPC::Tuning::max_src_cur);
347  context.coro = coro;
348  RPC::doCommand(context, result);
349  g.signal();
350  });
351  BEAST_EXPECT(g.wait_for(5s));
352  BEAST_EXPECT(!result.isMember(jss::error));
353 
354  // Test more than RPC::Tuning::max_src_cur source currencies.
355  app.getJobQueue().postCoro(
356  jtCLIENT, "RPC-Client", [&](auto const& coro) {
357  context.params =
358  rpf(Account("alice"),
359  Account("bob"),
361  context.coro = coro;
362  RPC::doCommand(context, result);
363  g.signal();
364  });
365  BEAST_EXPECT(g.wait_for(5s));
366  BEAST_EXPECT(result.isMember(jss::error));
367 
368  // Test RPC::Tuning::max_auto_src_cur source currencies.
369  for (auto i = 0; i < (RPC::Tuning::max_auto_src_cur - 1); ++i)
370  env.trust(Account("alice")[std::to_string(i + 100)](100), "bob");
371  app.getJobQueue().postCoro(
372  jtCLIENT, "RPC-Client", [&](auto const& coro) {
373  context.params = rpf(Account("alice"), Account("bob"), 0);
374  context.coro = coro;
375  RPC::doCommand(context, result);
376  g.signal();
377  });
378  BEAST_EXPECT(g.wait_for(5s));
379  BEAST_EXPECT(!result.isMember(jss::error));
380 
381  // Test more than RPC::Tuning::max_auto_src_cur source currencies.
382  env.trust(Account("alice")["AUD"](100), "bob");
383  app.getJobQueue().postCoro(
384  jtCLIENT, "RPC-Client", [&](auto const& coro) {
385  context.params = rpf(Account("alice"), Account("bob"), 0);
386  context.coro = coro;
387  RPC::doCommand(context, result);
388  g.signal();
389  });
390  BEAST_EXPECT(g.wait_for(5s));
391  BEAST_EXPECT(result.isMember(jss::error));
392  }
393 
394  void
396  {
397  testcase("no direct path no intermediary no alternatives");
398  using namespace jtx;
399  Env env(*this);
400  env.fund(XRP(10000), "alice", "bob");
401 
402  auto const result =
403  find_paths(env, "alice", "bob", Account("bob")["USD"](5));
404  BEAST_EXPECT(std::get<0>(result).empty());
405  }
406 
407  void
409  {
410  testcase("direct path no intermediary");
411  using namespace jtx;
412  Env env(*this);
413  env.fund(XRP(10000), "alice", "bob");
414  env.trust(Account("alice")["USD"](700), "bob");
415 
416  STPathSet st;
417  STAmount sa;
418  std::tie(st, sa, std::ignore) =
419  find_paths(env, "alice", "bob", Account("bob")["USD"](5));
420  BEAST_EXPECT(st.empty());
421  BEAST_EXPECT(equal(sa, Account("alice")["USD"](5)));
422  }
423 
424  void
426  {
427  testcase("payment auto path find");
428  using namespace jtx;
429  Env env(*this);
430  auto const gw = Account("gateway");
431  auto const USD = gw["USD"];
432  env.fund(XRP(10000), "alice", "bob", gw);
433  env.trust(USD(600), "alice");
434  env.trust(USD(700), "bob");
435  env(pay(gw, "alice", USD(70)));
436  env(pay("alice", "bob", USD(24)));
437  env.require(balance("alice", USD(46)));
438  env.require(balance(gw, Account("alice")["USD"](-46)));
439  env.require(balance("bob", USD(24)));
440  env.require(balance(gw, Account("bob")["USD"](-24)));
441  }
442 
443  void
445  {
446  testcase("path find");
447  using namespace jtx;
448  Env env(*this);
449  auto const gw = Account("gateway");
450  auto const USD = gw["USD"];
451  env.fund(XRP(10000), "alice", "bob", gw);
452  env.trust(USD(600), "alice");
453  env.trust(USD(700), "bob");
454  env(pay(gw, "alice", USD(70)));
455  env(pay(gw, "bob", USD(50)));
456 
457  STPathSet st;
458  STAmount sa;
459  std::tie(st, sa, std::ignore) =
460  find_paths(env, "alice", "bob", Account("bob")["USD"](5));
461  BEAST_EXPECT(same(st, stpath("gateway")));
462  BEAST_EXPECT(equal(sa, Account("alice")["USD"](5)));
463  }
464 
465  void
467  {
468  using namespace jtx;
469  testcase("XRP to XRP");
470  Env env(*this);
471  env.fund(XRP(10000), "alice", "bob");
472 
473  auto const result = find_paths(env, "alice", "bob", XRP(5));
474  BEAST_EXPECT(std::get<0>(result).empty());
475  }
476 
477  void
479  {
480  testcase("path find consume all");
481  using namespace jtx;
482 
483  {
484  Env env(*this);
485  env.fund(XRP(10000), "alice", "bob", "carol", "dan", "edward");
486  env.trust(Account("alice")["USD"](10), "bob");
487  env.trust(Account("bob")["USD"](10), "carol");
488  env.trust(Account("carol")["USD"](10), "edward");
489  env.trust(Account("alice")["USD"](100), "dan");
490  env.trust(Account("dan")["USD"](100), "edward");
491 
492  STPathSet st;
493  STAmount sa;
494  STAmount da;
495  std::tie(st, sa, da) = find_paths(
496  env, "alice", "edward", Account("edward")["USD"](-1));
497  BEAST_EXPECT(same(st, stpath("dan"), stpath("bob", "carol")));
498  BEAST_EXPECT(equal(sa, Account("alice")["USD"](110)));
499  BEAST_EXPECT(equal(da, Account("edward")["USD"](110)));
500  }
501 
502  {
503  Env env(*this);
504  auto const gw = Account("gateway");
505  auto const USD = gw["USD"];
506  env.fund(XRP(10000), "alice", "bob", "carol", gw);
507  env.trust(USD(100), "bob", "carol");
508  env(pay(gw, "carol", USD(100)));
509  env(offer("carol", XRP(100), USD(100)));
510 
511  STPathSet st;
512  STAmount sa;
513  STAmount da;
514  std::tie(st, sa, da) = find_paths(
515  env,
516  "alice",
517  "bob",
518  Account("bob")["AUD"](-1),
519  boost::optional<STAmount>(XRP(100000000)));
520  BEAST_EXPECT(st.empty());
521  std::tie(st, sa, da) = find_paths(
522  env,
523  "alice",
524  "bob",
525  Account("bob")["USD"](-1),
526  boost::optional<STAmount>(XRP(100000000)));
527  BEAST_EXPECT(sa == XRP(100));
528  BEAST_EXPECT(equal(da, Account("bob")["USD"](100)));
529  }
530  }
531 
532  void
534  {
535  testcase("alternative path consume both");
536  using namespace jtx;
537  Env env(*this);
538  auto const gw = Account("gateway");
539  auto const USD = gw["USD"];
540  auto const gw2 = Account("gateway2");
541  auto const gw2_USD = gw2["USD"];
542  env.fund(XRP(10000), "alice", "bob", gw, gw2);
543  env.trust(USD(600), "alice");
544  env.trust(gw2_USD(800), "alice");
545  env.trust(USD(700), "bob");
546  env.trust(gw2_USD(900), "bob");
547  env(pay(gw, "alice", USD(70)));
548  env(pay(gw2, "alice", gw2_USD(70)));
549  env(pay("alice", "bob", Account("bob")["USD"](140)),
550  paths(Account("alice")["USD"]));
551  env.require(balance("alice", USD(0)));
552  env.require(balance("alice", gw2_USD(0)));
553  env.require(balance("bob", USD(70)));
554  env.require(balance("bob", gw2_USD(70)));
555  env.require(balance(gw, Account("alice")["USD"](0)));
556  env.require(balance(gw, Account("bob")["USD"](-70)));
557  env.require(balance(gw2, Account("alice")["USD"](0)));
558  env.require(balance(gw2, Account("bob")["USD"](-70)));
559  }
560 
561  void
563  {
564  testcase("alternative paths consume best transfer");
565  using namespace jtx;
566  Env env(*this);
567  auto const gw = Account("gateway");
568  auto const USD = gw["USD"];
569  auto const gw2 = Account("gateway2");
570  auto const gw2_USD = gw2["USD"];
571  env.fund(XRP(10000), "alice", "bob", gw, gw2);
572  env(rate(gw2, 1.1));
573  env.trust(USD(600), "alice");
574  env.trust(gw2_USD(800), "alice");
575  env.trust(USD(700), "bob");
576  env.trust(gw2_USD(900), "bob");
577  env(pay(gw, "alice", USD(70)));
578  env(pay(gw2, "alice", gw2_USD(70)));
579  env(pay("alice", "bob", USD(70)));
580  env.require(balance("alice", USD(0)));
581  env.require(balance("alice", gw2_USD(70)));
582  env.require(balance("bob", USD(70)));
583  env.require(balance("bob", gw2_USD(0)));
584  env.require(balance(gw, Account("alice")["USD"](0)));
585  env.require(balance(gw, Account("bob")["USD"](-70)));
586  env.require(balance(gw2, Account("alice")["USD"](-70)));
587  env.require(balance(gw2, Account("bob")["USD"](0)));
588  }
589 
590  void
592  {
593  testcase("alternative paths - consume best transfer first");
594  using namespace jtx;
595  Env env(*this);
596  auto const gw = Account("gateway");
597  auto const USD = gw["USD"];
598  auto const gw2 = Account("gateway2");
599  auto const gw2_USD = gw2["USD"];
600  env.fund(XRP(10000), "alice", "bob", gw, gw2);
601  env(rate(gw2, 1.1));
602  env.trust(USD(600), "alice");
603  env.trust(gw2_USD(800), "alice");
604  env.trust(USD(700), "bob");
605  env.trust(gw2_USD(900), "bob");
606  env(pay(gw, "alice", USD(70)));
607  env(pay(gw2, "alice", gw2_USD(70)));
608  env(pay("alice", "bob", Account("bob")["USD"](77)),
609  sendmax(Account("alice")["USD"](100)),
610  paths(Account("alice")["USD"]));
611  env.require(balance("alice", USD(0)));
612  env.require(balance("alice", gw2_USD(62.3)));
613  env.require(balance("bob", USD(70)));
614  env.require(balance("bob", gw2_USD(7)));
615  env.require(balance(gw, Account("alice")["USD"](0)));
616  env.require(balance(gw, Account("bob")["USD"](-70)));
617  env.require(balance(gw2, Account("alice")["USD"](-62.3)));
618  env.require(balance(gw2, Account("bob")["USD"](-7)));
619  }
620 
621  void
623  {
624  testcase("alternative paths - limit returned paths to best quality");
625  using namespace jtx;
626  Env env(*this);
627  auto const gw = Account("gateway");
628  auto const USD = gw["USD"];
629  auto const gw2 = Account("gateway2");
630  auto const gw2_USD = gw2["USD"];
631  env.fund(XRP(10000), "alice", "bob", "carol", "dan", gw, gw2);
632  env(rate("carol", 1.1));
633  env.trust(Account("carol")["USD"](800), "alice", "bob");
634  env.trust(Account("dan")["USD"](800), "alice", "bob");
635  env.trust(USD(800), "alice", "bob");
636  env.trust(gw2_USD(800), "alice", "bob");
637  env.trust(Account("alice")["USD"](800), "dan");
638  env.trust(Account("bob")["USD"](800), "dan");
639  env(pay(gw2, "alice", gw2_USD(100)));
640  env(pay("carol", "alice", Account("carol")["USD"](100)));
641  env(pay(gw, "alice", USD(100)));
642 
643  STPathSet st;
644  STAmount sa;
645  std::tie(st, sa, std::ignore) =
646  find_paths(env, "alice", "bob", Account("bob")["USD"](5));
647  BEAST_EXPECT(same(
648  st,
649  stpath("gateway"),
650  stpath("gateway2"),
651  stpath("dan"),
652  stpath("carol")));
653  BEAST_EXPECT(equal(sa, Account("alice")["USD"](5)));
654  }
655 
656  void
658  {
659  testcase("path negative: Issue #5");
660  using namespace jtx;
661  Env env(*this);
662  env.fund(XRP(10000), "alice", "bob", "carol", "dan");
663  env.trust(Account("bob")["USD"](100), "alice", "carol", "dan");
664  env.trust(Account("alice")["USD"](100), "dan");
665  env.trust(Account("carol")["USD"](100), "dan");
666  env(pay("bob", "carol", Account("bob")["USD"](75)));
667  env.require(balance("bob", Account("carol")["USD"](-75)));
668  env.require(balance("carol", Account("bob")["USD"](75)));
669 
670  auto result =
671  find_paths(env, "alice", "bob", Account("bob")["USD"](25));
672  BEAST_EXPECT(std::get<0>(result).empty());
673 
674  env(pay("alice", "bob", Account("alice")["USD"](25)), ter(tecPATH_DRY));
675 
676  result = find_paths(env, "alice", "bob", Account("alice")["USD"](25));
677  BEAST_EXPECT(std::get<0>(result).empty());
678 
679  env.require(balance("alice", Account("bob")["USD"](0)));
680  env.require(balance("alice", Account("dan")["USD"](0)));
681  env.require(balance("bob", Account("alice")["USD"](0)));
682  env.require(balance("bob", Account("carol")["USD"](-75)));
683  env.require(balance("bob", Account("dan")["USD"](0)));
684  env.require(balance("carol", Account("bob")["USD"](75)));
685  env.require(balance("carol", Account("dan")["USD"](0)));
686  env.require(balance("dan", Account("alice")["USD"](0)));
687  env.require(balance("dan", Account("bob")["USD"](0)));
688  env.require(balance("dan", Account("carol")["USD"](0)));
689  }
690 
691  // alice -- limit 40 --> bob
692  // alice --> carol --> dan --> bob
693  // Balance of 100 USD Bob - Balance of 37 USD -> Rod
694  void
696  {
697  testcase("path negative: ripple-client issue #23: smaller");
698  using namespace jtx;
699  Env env(*this);
700  env.fund(XRP(10000), "alice", "bob", "carol", "dan");
701  env.trust(Account("alice")["USD"](40), "bob");
702  env.trust(Account("dan")["USD"](20), "bob");
703  env.trust(Account("alice")["USD"](20), "carol");
704  env.trust(Account("carol")["USD"](20), "dan");
705  env(pay("alice", "bob", Account("bob")["USD"](55)),
706  paths(Account("alice")["USD"]));
707  env.require(balance("bob", Account("alice")["USD"](40)));
708  env.require(balance("bob", Account("dan")["USD"](15)));
709  }
710 
711  // alice -120 USD-> edward -25 USD-> bob
712  // alice -25 USD-> carol -75 USD -> dan -100 USD-> bob
713  void
715  {
716  testcase("path negative: ripple-client issue #23: larger");
717  using namespace jtx;
718  Env env(*this);
719  env.fund(XRP(10000), "alice", "bob", "carol", "dan", "edward");
720  env.trust(Account("alice")["USD"](120), "edward");
721  env.trust(Account("edward")["USD"](25), "bob");
722  env.trust(Account("dan")["USD"](100), "bob");
723  env.trust(Account("alice")["USD"](25), "carol");
724  env.trust(Account("carol")["USD"](75), "dan");
725  env(pay("alice", "bob", Account("bob")["USD"](50)),
726  paths(Account("alice")["USD"]));
727  env.require(balance("alice", Account("edward")["USD"](-25)));
728  env.require(balance("alice", Account("carol")["USD"](-25)));
729  env.require(balance("bob", Account("edward")["USD"](25)));
730  env.require(balance("bob", Account("dan")["USD"](25)));
731  env.require(balance("carol", Account("alice")["USD"](25)));
732  env.require(balance("carol", Account("dan")["USD"](-25)));
733  env.require(balance("dan", Account("carol")["USD"](25)));
734  env.require(balance("dan", Account("bob")["USD"](-25)));
735  }
736 
737  // carol holds gateway AUD, sells gateway AUD for XRP
738  // bob will hold gateway AUD
739  // alice pays bob gateway AUD using XRP
740  void
742  {
743  testcase("via gateway");
744  using namespace jtx;
745  Env env(*this);
746  auto const gw = Account("gateway");
747  auto const AUD = gw["AUD"];
748  env.fund(XRP(10000), "alice", "bob", "carol", gw);
749  env(rate(gw, 1.1));
750  env.trust(AUD(100), "bob", "carol");
751  env(pay(gw, "carol", AUD(50)));
752  env(offer("carol", XRP(50), AUD(50)));
753  env(pay("alice", "bob", AUD(10)), sendmax(XRP(100)), paths(XRP));
754  env.require(balance("bob", AUD(10)));
755  env.require(balance("carol", AUD(39)));
756 
757  auto const result =
758  find_paths(env, "alice", "bob", Account("bob")["USD"](25));
759  BEAST_EXPECT(std::get<0>(result).empty());
760  }
761 
762  void
764  {
765  testcase("path find");
766  using namespace jtx;
767  Env env(*this);
768  env.fund(XRP(10000), "alice", "bob", "carol");
769  env.trust(Account("alice")["USD"](1000), "bob");
770  env.trust(Account("bob")["USD"](1000), "carol");
771 
772  STPathSet st;
773  STAmount sa;
774  std::tie(st, sa, std::ignore) =
775  find_paths(env, "alice", "carol", Account("carol")["USD"](5));
776  BEAST_EXPECT(same(st, stpath("bob")));
777  BEAST_EXPECT(equal(sa, Account("alice")["USD"](5)));
778  }
779 
780  void
782  {
783  testcase("quality set and test");
784  using namespace jtx;
785  Env env(*this);
786  env.fund(XRP(10000), "alice", "bob");
787  env(trust("bob", Account("alice")["USD"](1000)),
788  json("{\"" + sfQualityIn.fieldName + "\": 2000}"),
789  json("{\"" + sfQualityOut.fieldName + "\": 1400000000}"));
790 
791  Json::Value jv;
793  R"({
794  "Balance" : {
795  "currency" : "USD",
796  "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
797  "value" : "0"
798  },
799  "Flags" : 131072,
800  "HighLimit" : {
801  "currency" : "USD",
802  "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
803  "value" : "1000"
804  },
805  "HighNode" : "0",
806  "HighQualityIn" : 2000,
807  "HighQualityOut" : 1400000000,
808  "LedgerEntryType" : "RippleState",
809  "LowLimit" : {
810  "currency" : "USD",
811  "issuer" : "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
812  "value" : "0"
813  },
814  "LowNode" : "0"
815  })",
816  jv);
817 
818  auto const jv_l =
819  env.le(keylet::line(
820  Account("bob").id(), Account("alice")["USD"].issue()))
821  ->getJson(JsonOptions::none);
822  for (auto it = jv.begin(); it != jv.end(); ++it)
823  BEAST_EXPECT(*it == jv_l[it.memberName()]);
824  }
825 
826  void
828  {
829  testcase("trust normal clear");
830  using namespace jtx;
831  Env env(*this);
832  env.fund(XRP(10000), "alice", "bob");
833  env.trust(Account("bob")["USD"](1000), "alice");
834  env.trust(Account("alice")["USD"](1000), "bob");
835 
836  Json::Value jv;
838  R"({
839  "Balance" : {
840  "currency" : "USD",
841  "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
842  "value" : "0"
843  },
844  "Flags" : 196608,
845  "HighLimit" : {
846  "currency" : "USD",
847  "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
848  "value" : "1000"
849  },
850  "HighNode" : "0",
851  "LedgerEntryType" : "RippleState",
852  "LowLimit" : {
853  "currency" : "USD",
854  "issuer" : "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
855  "value" : "1000"
856  },
857  "LowNode" : "0"
858  })",
859  jv);
860 
861  auto const jv_l =
862  env.le(keylet::line(
863  Account("bob").id(), Account("alice")["USD"].issue()))
864  ->getJson(JsonOptions::none);
865  for (auto it = jv.begin(); it != jv.end(); ++it)
866  BEAST_EXPECT(*it == jv_l[it.memberName()]);
867 
868  env.trust(Account("bob")["USD"](0), "alice");
869  env.trust(Account("alice")["USD"](0), "bob");
870  BEAST_EXPECT(
871  env.le(keylet::line(
872  Account("bob").id(), Account("alice")["USD"].issue())) ==
873  nullptr);
874  }
875 
876  void
878  {
879  testcase("trust auto clear");
880  using namespace jtx;
881  Env env(*this);
882  env.fund(XRP(10000), "alice", "bob");
883  env.trust(Account("bob")["USD"](1000), "alice");
884  env(pay("bob", "alice", Account("bob")["USD"](50)));
885  env.trust(Account("bob")["USD"](0), "alice");
886 
887  Json::Value jv;
889  R"({
890  "Balance" :
891  {
892  "currency" : "USD",
893  "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
894  "value" : "50"
895  },
896  "Flags" : 65536,
897  "HighLimit" :
898  {
899  "currency" : "USD",
900  "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
901  "value" : "0"
902  },
903  "HighNode" : "0",
904  "LedgerEntryType" : "RippleState",
905  "LowLimit" :
906  {
907  "currency" : "USD",
908  "issuer" : "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
909  "value" : "0"
910  },
911  "LowNode" : "0"
912  })",
913  jv);
914 
915  auto const jv_l =
916  env.le(keylet::line(
917  Account("alice").id(), Account("bob")["USD"].issue()))
918  ->getJson(JsonOptions::none);
919  for (auto it = jv.begin(); it != jv.end(); ++it)
920  BEAST_EXPECT(*it == jv_l[it.memberName()]);
921 
922  env(pay("alice", "bob", Account("alice")["USD"](50)));
923  BEAST_EXPECT(
924  env.le(keylet::line(
925  Account("alice").id(), Account("bob")["USD"].issue())) ==
926  nullptr);
927  }
928 
929  void
930  path_find_01()
931  {
932  testcase("Path Find: XRP -> XRP and XRP -> IOU");
933  using namespace jtx;
934  Env env(*this);
935  Account A1{"A1"};
936  Account A2{"A2"};
937  Account A3{"A3"};
938  Account G1{"G1"};
939  Account G2{"G2"};
940  Account G3{"G3"};
941  Account M1{"M1"};
942 
943  env.fund(XRP(100000), A1);
944  env.fund(XRP(10000), A2);
945  env.fund(XRP(1000), A3, G1, G2, G3, M1);
946  env.close();
947 
948  env.trust(G1["XYZ"](5000), A1);
949  env.trust(G3["ABC"](5000), A1);
950  env.trust(G2["XYZ"](5000), A2);
951  env.trust(G3["ABC"](5000), A2);
952  env.trust(A2["ABC"](1000), A3);
953  env.trust(G1["XYZ"](100000), M1);
954  env.trust(G2["XYZ"](100000), M1);
955  env.trust(G3["ABC"](100000), M1);
956  env.close();
957 
958  env(pay(G1, A1, G1["XYZ"](3500)));
959  env(pay(G3, A1, G3["ABC"](1200)));
960  env(pay(G2, M1, G2["XYZ"](25000)));
961  env(pay(G3, M1, G3["ABC"](25000)));
962  env.close();
963 
964  env(offer(M1, G1["XYZ"](1000), G2["XYZ"](1000)));
965  env(offer(M1, XRP(10000), G3["ABC"](1000)));
966 
967  STPathSet st;
968  STAmount sa, da;
969 
970  {
971  auto const& send_amt = XRP(10);
972  std::tie(st, sa, da) =
973  find_paths(env, A1, A2, send_amt, boost::none, xrpCurrency());
974  BEAST_EXPECT(equal(da, send_amt));
975  BEAST_EXPECT(st.empty());
976  }
977 
978  {
979  // no path should exist for this since dest account
980  // does not exist.
981  auto const& send_amt = XRP(200);
982  std::tie(st, sa, da) = find_paths(
983  env, A1, Account{"A0"}, send_amt, boost::none, xrpCurrency());
984  BEAST_EXPECT(equal(da, send_amt));
985  BEAST_EXPECT(st.empty());
986  }
987 
988  {
989  auto const& send_amt = G3["ABC"](10);
990  std::tie(st, sa, da) =
991  find_paths(env, A2, G3, send_amt, boost::none, xrpCurrency());
992  BEAST_EXPECT(equal(da, send_amt));
993  BEAST_EXPECT(equal(sa, XRP(100)));
994  BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]))));
995  }
996 
997  {
998  auto const& send_amt = A2["ABC"](1);
999  std::tie(st, sa, da) =
1000  find_paths(env, A1, A2, send_amt, boost::none, xrpCurrency());
1001  BEAST_EXPECT(equal(da, send_amt));
1002  BEAST_EXPECT(equal(sa, XRP(10)));
1003  BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]), G3)));
1004  }
1005 
1006  {
1007  auto const& send_amt = A3["ABC"](1);
1008  std::tie(st, sa, da) =
1009  find_paths(env, A1, A3, send_amt, boost::none, xrpCurrency());
1010  BEAST_EXPECT(equal(da, send_amt));
1011  BEAST_EXPECT(equal(sa, XRP(10)));
1012  BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]), G3, A2)));
1013  }
1014  }
1015 
1016  void
1017  path_find_02()
1018  {
1019  testcase("Path Find: non-XRP -> XRP");
1020  using namespace jtx;
1021  Env env(*this);
1022  Account A1{"A1"};
1023  Account A2{"A2"};
1024  Account G3{"G3"};
1025  Account M1{"M1"};
1026 
1027  env.fund(XRP(1000), A1, A2, G3);
1028  env.fund(XRP(11000), M1);
1029  env.close();
1030 
1031  env.trust(G3["ABC"](1000), A1, A2);
1032  env.trust(G3["ABC"](100000), M1);
1033  env.close();
1034 
1035  env(pay(G3, A1, G3["ABC"](1000)));
1036  env(pay(G3, A2, G3["ABC"](1000)));
1037  env(pay(G3, M1, G3["ABC"](1200)));
1038  env.close();
1039 
1040  env(offer(M1, G3["ABC"](1000), XRP(10000)));
1041 
1042  STPathSet st;
1043  STAmount sa, da;
1044 
1045  auto const& send_amt = XRP(10);
1046  std::tie(st, sa, da) =
1047  find_paths(env, A1, A2, send_amt, boost::none, A2["ABC"].currency);
1048  BEAST_EXPECT(equal(da, send_amt));
1049  BEAST_EXPECT(equal(sa, A1["ABC"](1)));
1050  BEAST_EXPECT(same(st, stpath(G3, IPE(xrpIssue()))));
1051  }
1052 
1053  void
1054  path_find_04()
1055  {
1056  testcase("Path Find: Bitstamp and SnapSwap, liquidity with no offers");
1057  using namespace jtx;
1058  Env env(*this);
1059  Account A1{"A1"};
1060  Account A2{"A2"};
1061  Account G1BS{"G1BS"};
1062  Account G2SW{"G2SW"};
1063  Account M1{"M1"};
1064 
1065  env.fund(XRP(1000), G1BS, G2SW, A1, A2);
1066  env.fund(XRP(11000), M1);
1067  env.close();
1068 
1069  env.trust(G1BS["HKD"](2000), A1);
1070  env.trust(G2SW["HKD"](2000), A2);
1071  env.trust(G1BS["HKD"](100000), M1);
1072  env.trust(G2SW["HKD"](100000), M1);
1073  env.close();
1074 
1075  env(pay(G1BS, A1, G1BS["HKD"](1000)));
1076  env(pay(G2SW, A2, G2SW["HKD"](1000)));
1077  // SnapSwap wants to be able to set trust line quality settings so they
1078  // can charge a fee when transactions ripple across. Liquidity
1079  // provider, via trusting/holding both accounts
1080  env(pay(G1BS, M1, G1BS["HKD"](1200)));
1081  env(pay(G2SW, M1, G2SW["HKD"](5000)));
1082  env.close();
1083 
1084  STPathSet st;
1085  STAmount sa, da;
1086 
1087  {
1088  auto const& send_amt = A2["HKD"](10);
1089  std::tie(st, sa, da) = find_paths(
1090  env, A1, A2, send_amt, boost::none, A2["HKD"].currency);
1091  BEAST_EXPECT(equal(da, send_amt));
1092  BEAST_EXPECT(equal(sa, A1["HKD"](10)));
1093  BEAST_EXPECT(same(st, stpath(G1BS, M1, G2SW)));
1094  }
1095 
1096  {
1097  auto const& send_amt = A1["HKD"](10);
1098  std::tie(st, sa, da) = find_paths(
1099  env, A2, A1, send_amt, boost::none, A1["HKD"].currency);
1100  BEAST_EXPECT(equal(da, send_amt));
1101  BEAST_EXPECT(equal(sa, A2["HKD"](10)));
1102  BEAST_EXPECT(same(st, stpath(G2SW, M1, G1BS)));
1103  }
1104 
1105  {
1106  auto const& send_amt = A2["HKD"](10);
1107  std::tie(st, sa, da) = find_paths(
1108  env, G1BS, A2, send_amt, boost::none, A1["HKD"].currency);
1109  BEAST_EXPECT(equal(da, send_amt));
1110  BEAST_EXPECT(equal(sa, G1BS["HKD"](10)));
1111  BEAST_EXPECT(same(st, stpath(M1, G2SW)));
1112  }
1113 
1114  {
1115  auto const& send_amt = M1["HKD"](10);
1116  std::tie(st, sa, da) = find_paths(
1117  env, M1, G1BS, send_amt, boost::none, A1["HKD"].currency);
1118  BEAST_EXPECT(equal(da, send_amt));
1119  BEAST_EXPECT(equal(sa, M1["HKD"](10)));
1120  BEAST_EXPECT(st.empty());
1121  }
1122 
1123  {
1124  auto const& send_amt = A1["HKD"](10);
1125  std::tie(st, sa, da) = find_paths(
1126  env, G2SW, A1, send_amt, boost::none, A1["HKD"].currency);
1127  BEAST_EXPECT(equal(da, send_amt));
1128  BEAST_EXPECT(equal(sa, G2SW["HKD"](10)));
1129  BEAST_EXPECT(same(st, stpath(M1, G1BS)));
1130  }
1131  }
1132 
1133  void
1134  path_find_05()
1135  {
1136  testcase("Path Find: non-XRP -> non-XRP, same currency");
1137  using namespace jtx;
1138  Env env(*this);
1139  Account A1{"A1"};
1140  Account A2{"A2"};
1141  Account A3{"A3"};
1142  Account A4{"A4"};
1143  Account G1{"G1"};
1144  Account G2{"G2"};
1145  Account G3{"G3"};
1146  Account G4{"G4"};
1147  Account M1{"M1"};
1148  Account M2{"M2"};
1149 
1150  env.fund(XRP(1000), A1, A2, A3, G1, G2, G3, G4);
1151  env.fund(XRP(10000), A4);
1152  env.fund(XRP(11000), M1, M2);
1153  env.close();
1154 
1155  env.trust(G1["HKD"](2000), A1);
1156  env.trust(G2["HKD"](2000), A2);
1157  env.trust(G1["HKD"](2000), A3);
1158  env.trust(G1["HKD"](100000), M1);
1159  env.trust(G2["HKD"](100000), M1);
1160  env.trust(G1["HKD"](100000), M2);
1161  env.trust(G2["HKD"](100000), M2);
1162  env.close();
1163 
1164  env(pay(G1, A1, G1["HKD"](1000)));
1165  env(pay(G2, A2, G2["HKD"](1000)));
1166  env(pay(G1, A3, G1["HKD"](1000)));
1167  env(pay(G1, M1, G1["HKD"](1200)));
1168  env(pay(G2, M1, G2["HKD"](5000)));
1169  env(pay(G1, M2, G1["HKD"](1200)));
1170  env(pay(G2, M2, G2["HKD"](5000)));
1171  env.close();
1172 
1173  env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)));
1174  env(offer(M2, XRP(10000), G2["HKD"](1000)));
1175  env(offer(M2, G1["HKD"](1000), XRP(10000)));
1176 
1177  STPathSet st;
1178  STAmount sa, da;
1179 
1180  {
1181  // A) Borrow or repay --
1182  // Source -> Destination (repay source issuer)
1183  auto const& send_amt = G1["HKD"](10);
1184  std::tie(st, sa, da) = find_paths(
1185  env, A1, G1, send_amt, boost::none, G1["HKD"].currency);
1186  BEAST_EXPECT(st.empty());
1187  BEAST_EXPECT(equal(da, send_amt));
1188  BEAST_EXPECT(equal(sa, A1["HKD"](10)));
1189  }
1190 
1191  {
1192  // A2) Borrow or repay --
1193  // Source -> Destination (repay destination issuer)
1194  auto const& send_amt = A1["HKD"](10);
1195  std::tie(st, sa, da) = find_paths(
1196  env, A1, G1, send_amt, boost::none, G1["HKD"].currency);
1197  BEAST_EXPECT(st.empty());
1198  BEAST_EXPECT(equal(da, send_amt));
1199  BEAST_EXPECT(equal(sa, A1["HKD"](10)));
1200  }
1201 
1202  {
1203  // B) Common gateway --
1204  // Source -> AC -> Destination
1205  auto const& send_amt = A3["HKD"](10);
1206  std::tie(st, sa, da) = find_paths(
1207  env, A1, A3, send_amt, boost::none, G1["HKD"].currency);
1208  BEAST_EXPECT(equal(da, send_amt));
1209  BEAST_EXPECT(equal(sa, A1["HKD"](10)));
1210  BEAST_EXPECT(same(st, stpath(G1)));
1211  }
1212 
1213  {
1214  // C) Gateway to gateway --
1215  // Source -> OB -> Destination
1216  auto const& send_amt = G2["HKD"](10);
1217  std::tie(st, sa, da) = find_paths(
1218  env, G1, G2, send_amt, boost::none, G1["HKD"].currency);
1219  BEAST_EXPECT(equal(da, send_amt));
1220  BEAST_EXPECT(equal(sa, G1["HKD"](10)));
1221  BEAST_EXPECT(same(
1222  st,
1223  stpath(IPE(G2["HKD"])),
1224  stpath(M1),
1225  stpath(M2),
1226  stpath(IPE(xrpIssue()), IPE(G2["HKD"]))));
1227  }
1228 
1229  {
1230  // D) User to unlinked gateway via order book --
1231  // Source -> AC -> OB -> Destination
1232  auto const& send_amt = G2["HKD"](10);
1233  std::tie(st, sa, da) = find_paths(
1234  env, A1, G2, send_amt, boost::none, G1["HKD"].currency);
1235  BEAST_EXPECT(equal(da, send_amt));
1236  BEAST_EXPECT(equal(sa, A1["HKD"](10)));
1237  BEAST_EXPECT(same(
1238  st,
1239  stpath(G1, M1),
1240  stpath(G1, M2),
1241  stpath(G1, IPE(G2["HKD"])),
1242  stpath(G1, IPE(xrpIssue()), IPE(G2["HKD"]))));
1243  }
1244 
1245  {
1246  // I4) XRP bridge" --
1247  // Source -> AC -> OB to XRP -> OB from XRP -> AC -> Destination
1248  auto const& send_amt = A2["HKD"](10);
1249  std::tie(st, sa, da) = find_paths(
1250  env, A1, A2, send_amt, boost::none, G1["HKD"].currency);
1251  BEAST_EXPECT(equal(da, send_amt));
1252  BEAST_EXPECT(equal(sa, A1["HKD"](10)));
1253  BEAST_EXPECT(same(
1254  st,
1255  stpath(G1, M1, G2),
1256  stpath(G1, M2, G2),
1257  stpath(G1, IPE(G2["HKD"]), G2),
1258  stpath(G1, IPE(xrpIssue()), IPE(G2["HKD"]), G2)));
1259  }
1260  }
1261 
1262  void
1263  path_find_06()
1264  {
1265  testcase("Path Find: non-XRP -> non-XRP, same currency)");
1266  using namespace jtx;
1267  Env env(*this);
1268  Account A1{"A1"};
1269  Account A2{"A2"};
1270  Account A3{"A3"};
1271  Account G1{"G1"};
1272  Account G2{"G2"};
1273  Account M1{"M1"};
1274 
1275  env.fund(XRP(11000), M1);
1276  env.fund(XRP(1000), A1, A2, A3, G1, G2);
1277  env.close();
1278 
1279  env.trust(G1["HKD"](2000), A1);
1280  env.trust(G2["HKD"](2000), A2);
1281  env.trust(A2["HKD"](2000), A3);
1282  env.trust(G1["HKD"](100000), M1);
1283  env.trust(G2["HKD"](100000), M1);
1284  env.close();
1285 
1286  env(pay(G1, A1, G1["HKD"](1000)));
1287  env(pay(G2, A2, G2["HKD"](1000)));
1288  env(pay(G1, M1, G1["HKD"](5000)));
1289  env(pay(G2, M1, G2["HKD"](5000)));
1290  env.close();
1291 
1292  env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)));
1293 
1294  // E) Gateway to user
1295  // Source -> OB -> AC -> Destination
1296  auto const& send_amt = A2["HKD"](10);
1297  STPathSet st;
1298  STAmount sa, da;
1299  std::tie(st, sa, da) =
1300  find_paths(env, G1, A2, send_amt, boost::none, G1["HKD"].currency);
1301  BEAST_EXPECT(equal(da, send_amt));
1302  BEAST_EXPECT(equal(sa, G1["HKD"](10)));
1303  BEAST_EXPECT(same(st, stpath(M1, G2), stpath(IPE(G2["HKD"]), G2)));
1304  }
1305 
1306  void
1307  run() override
1308  {
1313  path_find();
1327  xrp_to_xrp();
1328 
1329  // The following path_find_NN tests are data driven tests
1330  // that were originally implemented in js/coffee and migrated
1331  // here. The quantities and currencies used are taken directly from
1332  // those legacy tests, which in some cases probably represented
1333  // customer use cases.
1334 
1335  path_find_01();
1336  path_find_02();
1337  path_find_04();
1338  path_find_05();
1339  path_find_06();
1340  }
1341 };
1342 
1343 BEAST_DEFINE_TESTSUITE(Path, app, ripple);
1344 
1345 } // namespace test
1346 } // namespace ripple
ripple::test::Path_test::path_find_01
void path_find_01()
Definition: Path_test.cpp:865
ripple::test::Path_test::quality_paths_quality_set_and_test
void quality_paths_quality_set_and_test()
Definition: Path_test.cpp:781
ripple::test::jtx::json
Inject raw JSON.
Definition: jtx_json.h:31
ripple::test::Path_test::direct_path_no_intermediary
void direct_path_no_intermediary()
Definition: Path_test.cpp:408
ripple::sfPaths
const SField sfPaths
ripple::RPC::JsonContext
Definition: Context.h:53
std::make_tuple
T make_tuple(T... args)
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::STPath::push_back
void push_back(STPathElement const &e)
Definition: STPathSet.h:234
ripple::test::Path_test::gate
Definition: Path_test.cpp:175
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountDelete, app, ripple)
ripple::jtCLIENT
@ jtCLIENT
Definition: Job.h:48
ripple::STPathSet::end
std::vector< STPath >::const_iterator end() const
Definition: STPathSet.h:375
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:332
ripple::test::jtx::ter
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
ripple::test::Path_test::gate::signaled_
bool signaled_
Definition: Path_test.cpp:180
ripple::test::jtx::Env::require
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:466
ripple::test::Path_test::trust_auto_clear_trust_auto_clear
void trust_auto_clear_trust_auto_clear()
Definition: Path_test.cpp:835
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::sfQualityOut
const SF_UINT32 sfQualityOut
ripple::test::jtx::balance
A balance matches.
Definition: balance.h:38
ripple::test::Path_test::source_currencies_limit
void source_currencies_limit()
Definition: Path_test.cpp:312
ripple::test::jtx::BookSpec::currency
ripple::Currency currency
Definition: amount.h:158
ripple::test::Path_test::run
void run() override
Definition: Path_test.cpp:1242
std::find
T find(T... args)
ripple::test::Path_test::gate::wait_for
bool wait_for(std::chrono::duration< Rep, Period > const &rel_time)
Definition: Path_test.cpp:187
ripple::test::Path_test::path_find
void path_find()
Definition: Path_test.cpp:444
ripple::test::jtx::trust
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition: trust.cpp:30
ripple::SField::fieldName
const std::string fieldName
Definition: SField.h:129
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:594
ripple::test::Path_test::path_find_04
void path_find_04()
Definition: Path_test.cpp:989
std::chrono::duration
ripple::keylet::offer
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Definition: Indexes.cpp:223
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:29
ripple::test::Path_test
Definition: Path_test.cpp:172
ripple::sfQualityIn
const SF_UINT32 sfQualityIn
ripple::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:143
ripple::test::Path_test::issues_path_negative_ripple_client_issue_23_smaller
void issues_path_negative_ripple_client_issue_23_smaller()
Definition: Path_test.cpp:695
std::lock_guard
STL class.
ripple::STParsedJSONObject
Holds the serialized result of parsing an input JSON object.
Definition: STParsedJSON.h:31
ripple::Resource::feeReferenceRPC
const Charge feeReferenceRPC
std::tuple
ripple::RPC::APIVersionIfUnspecified
constexpr unsigned int APIVersionIfUnspecified
Definition: RPCHelpers.h:212
ripple::test::Path_test::path_find_05
void path_find_05()
Definition: Path_test.cpp:1069
ripple::test::Path_test::issues_path_negative_issue
void issues_path_negative_issue()
Definition: Path_test.cpp:657
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:240
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:45
Json::Value::end
const_iterator end() const
Definition: json_value.cpp:1064
ripple::test::same
bool same(STPathSet const &st1, Args const &... args)
Definition: Path_test.cpp:109
ripple::test::jtx::IOU::account
Account account
Definition: amount.h:294
ripple::test::Path_test::xrp_to_xrp
void xrp_to_xrp()
Definition: Path_test.cpp:466
Json::Reader
Unserialize a JSON document into a Value.
Definition: json_reader.h:36
ripple::test::Path_test::alternative_paths_limit_returned_paths_to_best_quality
void alternative_paths_limit_returned_paths_to_best_quality()
Definition: Path_test.cpp:622
ripple::test::Path_test::gate::mutex_
std::mutex mutex_
Definition: Path_test.cpp:179
ripple::test::Path_test::alternative_paths_consume_best_transfer
void alternative_paths_consume_best_transfer()
Definition: Path_test.cpp:562
ripple::STPathElement::typeCurrency
@ typeCurrency
Definition: STPathSet.h:40
ripple::STPathSet
Definition: STPathSet.h:309
ripple::test::jtx::Env::trust
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition: Env.cpp:250
ripple::test::jtx::BookSpec
Definition: amount.h:155
ripple::STPathSet::empty
bool empty() const
Definition: STPathSet.h:387
ripple::STPathElement::typeIssuer
@ typeIssuer
Definition: STPathSet.h:41
ripple::test::Path_test::path_find_consume_all
void path_find_consume_all()
Definition: Path_test.cpp:478
ripple::test::jtx::Account::id
AccountID id() const
Returns the Account ID.
Definition: Account.h:102
std::tie
T tie(T... args)
ripple::test::stpath
STPath stpath(Args const &... args)
Definition: Path_test.cpp:100
ripple::test::Path_test::payment_auto_path_find
void payment_auto_path_find()
Definition: Path_test.cpp:425
ripple::test::rpf
Json::Value rpf(jtx::Account const &src, jtx::Account const &dst, std::uint32_t num_src)
Definition: Path_test.cpp:131
ripple::RPC::doCommand
Status doCommand(RPC::JsonContext &context, Json::Value &result)
Execute an RPC command and store the results in a Json::Value.
Definition: RPCHandler.cpp:213
thread
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::test::Path_test::alternative_path_consume_both
void alternative_path_consume_both()
Definition: Path_test.cpp:533
ripple::test::Path_test::no_direct_path_no_intermediary_no_alternatives
void no_direct_path_no_intermediary_no_alternatives()
Definition: Path_test.cpp:395
ripple::test::detail::stpath_append
void stpath_append(STPath &st, T const &t, Args const &... args)
Definition: Path_test.cpp:80
std::enable_if_t
ripple::Role::USER
@ USER
ripple::test::Path_test::alternative_paths_consume_best_transfer_first
void alternative_paths_consume_best_transfer_first()
Definition: Path_test.cpp:591
chrono
ripple::RPC::Tuning::max_src_cur
static constexpr int max_src_cur
Maximum number of source currencies allowed in a path find request.
Definition: rpc/impl/Tuning.h:75
ripple::JsonOptions::none
@ none
ripple::test::jtx::sendmax
Sets the SendMax on a JTx.
Definition: sendmax.h:31
ripple::test::Path_test::path_find_06
void path_find_06()
Definition: Path_test.cpp:1198
std::unique_lock
STL class.
std::to_string
T to_string(T... args)
ripple::test::jtx::paths
Set Paths, SendMax on a JTx.
Definition: paths.h:32
ripple::test::jtx::IOU::currency
ripple::Currency currency
Definition: amount.h:295
ripple::STAmount
Definition: STAmount.h:42
ripple::xrpAccount
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:90
ripple::amountFromJson
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition: STAmount.cpp:826
ripple::test::jtx::path
Add a path.
Definition: paths.h:55
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
std::uint32_t
ripple::keylet::line
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:194
ripple::STParsedJSONObject::object
boost::optional< STObject > object
The STObject if the parse was successful.
Definition: STParsedJSON.h:50
ripple::STPathSet::begin
std::vector< STPath >::const_iterator begin() const
Definition: STPathSet.h:369
ripple::test::Path_test::gate::cv_
std::condition_variable cv_
Definition: Path_test.cpp:178
ripple::test::Path_test::gate::signal
void signal()
Definition: Path_test.cpp:196
std::condition_variable::wait_for
T wait_for(T... args)
ripple::test::equal
bool equal(STAmount const &sa1, STAmount const &sa2)
Definition: Path_test.cpp:125
ripple::test::jtx::BookSpec::account
AccountID account
Definition: amount.h:157
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::detail::stpath_append_one
void stpath_append_one(STPath &st, jtx::Account const &account)
Definition: Path_test.cpp:48
ripple::test::jtx::IOU
Converts to IOU Issue or STAmount.
Definition: amount.h:291
ripple::test::jtx::pay
Json::Value pay(Account const &account, Account const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
ripple::STPathElement
Definition: STPathSet.h:33
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, boost::optional< std::chrono::milliseconds > consensusDelay=boost::none)
Close and advance the ledger.
Definition: Env.cpp:121
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:197
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:219
ripple::test::jtx::Env::le
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:207
ripple::RPC::Tuning::max_auto_src_cur
static constexpr int max_auto_src_cur
Maximum number of auto source currencies in a path find request.
Definition: rpc/impl/Tuning.h:78
ripple::test::Path_test::find_paths
std::tuple< STPathSet, STAmount, STAmount > find_paths(jtx::Env &env, jtx::Account const &src, jtx::Account const &dst, STAmount const &saDstAmount, boost::optional< STAmount > const &saSendMax=boost::none, boost::optional< Currency > const &saSrcCurrency=boost::none)
Definition: Path_test.cpp:266
Json::Reader::parse
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:73
condition_variable
ripple::Resource::Consumer
An endpoint that consumes resources.
Definition: Consumer.h:33
ripple::Resource::Charge
A consumption charge.
Definition: Charge.h:30
ripple::test::IPE
auto IPE(Issue const &iss)
Definition: Path_test.cpp:161
ripple::test::Path_test::via_offers_via_gateway
void via_offers_via_gateway()
Definition: Path_test.cpp:741
ripple::STPathSet::size
std::vector< STPath >::size_type size() const
Definition: STPathSet.h:381
ripple::tecPATH_DRY
@ tecPATH_DRY
Definition: TER.h:255
ripple::test::Path_test::issues_path_negative_ripple_client_issue_23_larger
void issues_path_negative_ripple_client_issue_23_larger()
Definition: Path_test.cpp:714
ripple::xrpIssue
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:97
ripple::test::detail::stpathset_append
void stpathset_append(STPathSet &st, STPath const &p, Args const &... args)
Definition: Path_test.cpp:89
mutex
ripple::test::Path_test::trust_auto_clear_trust_normal_clear
void trust_auto_clear_trust_normal_clear()
Definition: Path_test.cpp:805
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::test::Path_test::path_find_02
void path_find_02()
Definition: Path_test.cpp:952
ripple::test::Path_test::indirect_paths_path_find
void indirect_paths_path_find()
Definition: Path_test.cpp:763
Json::Value::begin
const_iterator begin() const
Definition: json_value.cpp:1046
ripple::STPath
Definition: STPathSet.h:212
std::condition_variable::notify_all
T notify_all(T... args)
ripple::test::Path_test::find_paths_request
auto find_paths_request(jtx::Env &env, jtx::Account const &src, jtx::Account const &dst, STAmount const &saDstAmount, boost::optional< STAmount > const &saSendMax=boost::none, boost::optional< Currency > const &saSrcCurrency=boost::none)
Definition: Path_test.cpp:205
ripple::xrpCurrency
Currency const & xrpCurrency()
XRP currency.
Definition: UintTypes.cpp:124
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:115
ripple::Issue::account
AccountID account
Definition: Issue.h:38
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::jtx::rate
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Definition: rate.cpp:30
ripple::STPathSet::push_back
void push_back(STPath const &e)
Definition: STPathSet.h:393