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  {},
229  {}};
230 
232  params[jss::command] = "ripple_path_find";
233  params[jss::source_account] = toBase58(src);
234  params[jss::destination_account] = toBase58(dst);
235  params[jss::destination_amount] =
236  saDstAmount.getJson(JsonOptions::none);
237  if (saSendMax)
238  params[jss::send_max] = saSendMax->getJson(JsonOptions::none);
239  if (saSrcCurrency)
240  {
241  auto& sc = params[jss::source_currencies] = Json::arrayValue;
243  j[jss::currency] = to_string(saSrcCurrency.value());
244  sc.append(j);
245  }
246 
247  Json::Value result;
248  gate g;
249  app.getJobQueue().postCoro(
250  jtCLIENT, "RPC-Client", [&](auto const& coro) {
251  context.params = std::move(params);
252  context.coro = coro;
253  RPC::doCommand(context, result);
254  g.signal();
255  });
256 
257  using namespace std::chrono_literals;
258  BEAST_EXPECT(g.wait_for(5s));
259  BEAST_EXPECT(!result.isMember(jss::error));
260  return result;
261  }
262 
265  jtx::Env& env,
266  jtx::Account const& src,
267  jtx::Account const& dst,
268  STAmount const& saDstAmount,
269  boost::optional<STAmount> const& saSendMax = boost::none,
270  boost::optional<Currency> const& saSrcCurrency = boost::none)
271  {
273  env, src, dst, saDstAmount, saSendMax, saSrcCurrency);
274  BEAST_EXPECT(!result.isMember(jss::error));
275 
276  STAmount da;
277  if (result.isMember(jss::destination_amount))
278  da = amountFromJson(sfGeneric, result[jss::destination_amount]);
279 
280  STAmount sa;
282  if (result.isMember(jss::alternatives))
283  {
284  auto const& alts = result[jss::alternatives];
285  if (alts.size() > 0)
286  {
287  auto const& path = alts[0u];
288 
289  if (path.isMember(jss::source_amount))
290  sa = amountFromJson(sfGeneric, path[jss::source_amount]);
291 
292  if (path.isMember(jss::destination_amount))
293  da = amountFromJson(
294  sfGeneric, path[jss::destination_amount]);
295 
296  if (path.isMember(jss::paths_computed))
297  {
298  Json::Value p;
299  p["Paths"] = path[jss::paths_computed];
300  STParsedJSONObject po("generic", p);
301  paths = po.object->getFieldPathSet(sfPaths);
302  }
303  }
304  }
305 
306  return std::make_tuple(std::move(paths), std::move(sa), std::move(da));
307  }
308 
309  void
311  {
312  testcase("source currency limits");
313  using namespace std::chrono_literals;
314  using namespace jtx;
315  Env env(*this);
316  auto const gw = Account("gateway");
317  env.fund(XRP(10000), "alice", "bob", gw);
318  env.trust(gw["USD"](100), "alice", "bob");
319  env.close();
320 
321  auto& app = env.app();
324 
325  RPC::JsonContext context{
326  {env.journal,
327  app,
328  loadType,
329  app.getOPs(),
330  app.getLedgerMaster(),
331  c,
332  Role::USER},
333  {},
335  {}};
336  Json::Value result;
337  gate g;
338  // Test RPC::Tuning::max_src_cur source currencies.
339  app.getJobQueue().postCoro(
340  jtCLIENT, "RPC-Client", [&](auto const& coro) {
341  context.params = rpf(
342  Account("alice"), Account("bob"), RPC::Tuning::max_src_cur);
343  context.coro = coro;
344  RPC::doCommand(context, result);
345  g.signal();
346  });
347  BEAST_EXPECT(g.wait_for(5s));
348  BEAST_EXPECT(!result.isMember(jss::error));
349 
350  // Test more than RPC::Tuning::max_src_cur source currencies.
351  app.getJobQueue().postCoro(
352  jtCLIENT, "RPC-Client", [&](auto const& coro) {
353  context.params =
354  rpf(Account("alice"),
355  Account("bob"),
357  context.coro = coro;
358  RPC::doCommand(context, result);
359  g.signal();
360  });
361  BEAST_EXPECT(g.wait_for(5s));
362  BEAST_EXPECT(result.isMember(jss::error));
363 
364  // Test RPC::Tuning::max_auto_src_cur source currencies.
365  for (auto i = 0; i < (RPC::Tuning::max_auto_src_cur - 1); ++i)
366  env.trust(Account("alice")[std::to_string(i + 100)](100), "bob");
367  app.getJobQueue().postCoro(
368  jtCLIENT, "RPC-Client", [&](auto const& coro) {
369  context.params = rpf(Account("alice"), Account("bob"), 0);
370  context.coro = coro;
371  RPC::doCommand(context, result);
372  g.signal();
373  });
374  BEAST_EXPECT(g.wait_for(5s));
375  BEAST_EXPECT(!result.isMember(jss::error));
376 
377  // Test more than RPC::Tuning::max_auto_src_cur source currencies.
378  env.trust(Account("alice")["AUD"](100), "bob");
379  app.getJobQueue().postCoro(
380  jtCLIENT, "RPC-Client", [&](auto const& coro) {
381  context.params = rpf(Account("alice"), Account("bob"), 0);
382  context.coro = coro;
383  RPC::doCommand(context, result);
384  g.signal();
385  });
386  BEAST_EXPECT(g.wait_for(5s));
387  BEAST_EXPECT(result.isMember(jss::error));
388  }
389 
390  void
392  {
393  testcase("no direct path no intermediary no alternatives");
394  using namespace jtx;
395  Env env(*this);
396  env.fund(XRP(10000), "alice", "bob");
397 
398  auto const result =
399  find_paths(env, "alice", "bob", Account("bob")["USD"](5));
400  BEAST_EXPECT(std::get<0>(result).empty());
401  }
402 
403  void
405  {
406  testcase("direct path no intermediary");
407  using namespace jtx;
408  Env env(*this);
409  env.fund(XRP(10000), "alice", "bob");
410  env.trust(Account("alice")["USD"](700), "bob");
411 
412  STPathSet st;
413  STAmount sa;
414  std::tie(st, sa, std::ignore) =
415  find_paths(env, "alice", "bob", Account("bob")["USD"](5));
416  BEAST_EXPECT(st.empty());
417  BEAST_EXPECT(equal(sa, Account("alice")["USD"](5)));
418  }
419 
420  void
422  {
423  testcase("payment auto path find");
424  using namespace jtx;
425  Env env(*this);
426  auto const gw = Account("gateway");
427  auto const USD = gw["USD"];
428  env.fund(XRP(10000), "alice", "bob", gw);
429  env.trust(USD(600), "alice");
430  env.trust(USD(700), "bob");
431  env(pay(gw, "alice", USD(70)));
432  env(pay("alice", "bob", USD(24)));
433  env.require(balance("alice", USD(46)));
434  env.require(balance(gw, Account("alice")["USD"](-46)));
435  env.require(balance("bob", USD(24)));
436  env.require(balance(gw, Account("bob")["USD"](-24)));
437  }
438 
439  void
441  {
442  testcase("path find");
443  using namespace jtx;
444  Env env(*this);
445  auto const gw = Account("gateway");
446  auto const USD = gw["USD"];
447  env.fund(XRP(10000), "alice", "bob", gw);
448  env.trust(USD(600), "alice");
449  env.trust(USD(700), "bob");
450  env(pay(gw, "alice", USD(70)));
451  env(pay(gw, "bob", USD(50)));
452 
453  STPathSet st;
454  STAmount sa;
455  std::tie(st, sa, std::ignore) =
456  find_paths(env, "alice", "bob", Account("bob")["USD"](5));
457  BEAST_EXPECT(same(st, stpath("gateway")));
458  BEAST_EXPECT(equal(sa, Account("alice")["USD"](5)));
459  }
460 
461  void
463  {
464  using namespace jtx;
465  testcase("XRP to XRP");
466  Env env(*this);
467  env.fund(XRP(10000), "alice", "bob");
468 
469  auto const result = find_paths(env, "alice", "bob", XRP(5));
470  BEAST_EXPECT(std::get<0>(result).empty());
471  }
472 
473  void
475  {
476  testcase("path find consume all");
477  using namespace jtx;
478 
479  {
480  Env env(*this);
481  env.fund(XRP(10000), "alice", "bob", "carol", "dan", "edward");
482  env.trust(Account("alice")["USD"](10), "bob");
483  env.trust(Account("bob")["USD"](10), "carol");
484  env.trust(Account("carol")["USD"](10), "edward");
485  env.trust(Account("alice")["USD"](100), "dan");
486  env.trust(Account("dan")["USD"](100), "edward");
487 
488  STPathSet st;
489  STAmount sa;
490  STAmount da;
491  std::tie(st, sa, da) = find_paths(
492  env, "alice", "edward", Account("edward")["USD"](-1));
493  BEAST_EXPECT(same(st, stpath("dan"), stpath("bob", "carol")));
494  BEAST_EXPECT(equal(sa, Account("alice")["USD"](110)));
495  BEAST_EXPECT(equal(da, Account("edward")["USD"](110)));
496  }
497 
498  {
499  Env env(*this);
500  auto const gw = Account("gateway");
501  auto const USD = gw["USD"];
502  env.fund(XRP(10000), "alice", "bob", "carol", gw);
503  env.trust(USD(100), "bob", "carol");
504  env(pay(gw, "carol", USD(100)));
505  env(offer("carol", XRP(100), USD(100)));
506 
507  STPathSet st;
508  STAmount sa;
509  STAmount da;
510  std::tie(st, sa, da) = find_paths(
511  env,
512  "alice",
513  "bob",
514  Account("bob")["AUD"](-1),
515  boost::optional<STAmount>(XRP(100000000)));
516  BEAST_EXPECT(st.empty());
517  std::tie(st, sa, da) = find_paths(
518  env,
519  "alice",
520  "bob",
521  Account("bob")["USD"](-1),
522  boost::optional<STAmount>(XRP(100000000)));
523  BEAST_EXPECT(sa == XRP(100));
524  BEAST_EXPECT(equal(da, Account("bob")["USD"](100)));
525  }
526  }
527 
528  void
530  {
531  testcase("alternative path consume both");
532  using namespace jtx;
533  Env env(*this);
534  auto const gw = Account("gateway");
535  auto const USD = gw["USD"];
536  auto const gw2 = Account("gateway2");
537  auto const gw2_USD = gw2["USD"];
538  env.fund(XRP(10000), "alice", "bob", gw, gw2);
539  env.trust(USD(600), "alice");
540  env.trust(gw2_USD(800), "alice");
541  env.trust(USD(700), "bob");
542  env.trust(gw2_USD(900), "bob");
543  env(pay(gw, "alice", USD(70)));
544  env(pay(gw2, "alice", gw2_USD(70)));
545  env(pay("alice", "bob", Account("bob")["USD"](140)),
546  paths(Account("alice")["USD"]));
547  env.require(balance("alice", USD(0)));
548  env.require(balance("alice", gw2_USD(0)));
549  env.require(balance("bob", USD(70)));
550  env.require(balance("bob", gw2_USD(70)));
551  env.require(balance(gw, Account("alice")["USD"](0)));
552  env.require(balance(gw, Account("bob")["USD"](-70)));
553  env.require(balance(gw2, Account("alice")["USD"](0)));
554  env.require(balance(gw2, Account("bob")["USD"](-70)));
555  }
556 
557  void
559  {
560  testcase("alternative paths consume best transfer");
561  using namespace jtx;
562  Env env(*this);
563  auto const gw = Account("gateway");
564  auto const USD = gw["USD"];
565  auto const gw2 = Account("gateway2");
566  auto const gw2_USD = gw2["USD"];
567  env.fund(XRP(10000), "alice", "bob", gw, gw2);
568  env(rate(gw2, 1.1));
569  env.trust(USD(600), "alice");
570  env.trust(gw2_USD(800), "alice");
571  env.trust(USD(700), "bob");
572  env.trust(gw2_USD(900), "bob");
573  env(pay(gw, "alice", USD(70)));
574  env(pay(gw2, "alice", gw2_USD(70)));
575  env(pay("alice", "bob", USD(70)));
576  env.require(balance("alice", USD(0)));
577  env.require(balance("alice", gw2_USD(70)));
578  env.require(balance("bob", USD(70)));
579  env.require(balance("bob", gw2_USD(0)));
580  env.require(balance(gw, Account("alice")["USD"](0)));
581  env.require(balance(gw, Account("bob")["USD"](-70)));
582  env.require(balance(gw2, Account("alice")["USD"](-70)));
583  env.require(balance(gw2, Account("bob")["USD"](0)));
584  }
585 
586  void
588  {
589  testcase("alternative paths - consume best transfer first");
590  using namespace jtx;
591  Env env(*this);
592  auto const gw = Account("gateway");
593  auto const USD = gw["USD"];
594  auto const gw2 = Account("gateway2");
595  auto const gw2_USD = gw2["USD"];
596  env.fund(XRP(10000), "alice", "bob", gw, gw2);
597  env(rate(gw2, 1.1));
598  env.trust(USD(600), "alice");
599  env.trust(gw2_USD(800), "alice");
600  env.trust(USD(700), "bob");
601  env.trust(gw2_USD(900), "bob");
602  env(pay(gw, "alice", USD(70)));
603  env(pay(gw2, "alice", gw2_USD(70)));
604  env(pay("alice", "bob", Account("bob")["USD"](77)),
605  sendmax(Account("alice")["USD"](100)),
606  paths(Account("alice")["USD"]));
607  env.require(balance("alice", USD(0)));
608  env.require(balance("alice", gw2_USD(62.3)));
609  env.require(balance("bob", USD(70)));
610  env.require(balance("bob", gw2_USD(7)));
611  env.require(balance(gw, Account("alice")["USD"](0)));
612  env.require(balance(gw, Account("bob")["USD"](-70)));
613  env.require(balance(gw2, Account("alice")["USD"](-62.3)));
614  env.require(balance(gw2, Account("bob")["USD"](-7)));
615  }
616 
617  void
619  {
620  testcase("alternative paths - limit returned paths to best quality");
621  using namespace jtx;
622  Env env(*this);
623  auto const gw = Account("gateway");
624  auto const USD = gw["USD"];
625  auto const gw2 = Account("gateway2");
626  auto const gw2_USD = gw2["USD"];
627  env.fund(XRP(10000), "alice", "bob", "carol", "dan", gw, gw2);
628  env(rate("carol", 1.1));
629  env.trust(Account("carol")["USD"](800), "alice", "bob");
630  env.trust(Account("dan")["USD"](800), "alice", "bob");
631  env.trust(USD(800), "alice", "bob");
632  env.trust(gw2_USD(800), "alice", "bob");
633  env.trust(Account("alice")["USD"](800), "dan");
634  env.trust(Account("bob")["USD"](800), "dan");
635  env(pay(gw2, "alice", gw2_USD(100)));
636  env(pay("carol", "alice", Account("carol")["USD"](100)));
637  env(pay(gw, "alice", USD(100)));
638 
639  STPathSet st;
640  STAmount sa;
641  std::tie(st, sa, std::ignore) =
642  find_paths(env, "alice", "bob", Account("bob")["USD"](5));
643  BEAST_EXPECT(same(
644  st,
645  stpath("gateway"),
646  stpath("gateway2"),
647  stpath("dan"),
648  stpath("carol")));
649  BEAST_EXPECT(equal(sa, Account("alice")["USD"](5)));
650  }
651 
652  void
654  {
655  testcase("path negative: Issue #5");
656  using namespace jtx;
657  Env env(*this);
658  env.fund(XRP(10000), "alice", "bob", "carol", "dan");
659  env.trust(Account("bob")["USD"](100), "alice", "carol", "dan");
660  env.trust(Account("alice")["USD"](100), "dan");
661  env.trust(Account("carol")["USD"](100), "dan");
662  env(pay("bob", "carol", Account("bob")["USD"](75)));
663  env.require(balance("bob", Account("carol")["USD"](-75)));
664  env.require(balance("carol", Account("bob")["USD"](75)));
665 
666  auto result =
667  find_paths(env, "alice", "bob", Account("bob")["USD"](25));
668  BEAST_EXPECT(std::get<0>(result).empty());
669 
670  env(pay("alice", "bob", Account("alice")["USD"](25)), ter(tecPATH_DRY));
671 
672  result = find_paths(env, "alice", "bob", Account("alice")["USD"](25));
673  BEAST_EXPECT(std::get<0>(result).empty());
674 
675  env.require(balance("alice", Account("bob")["USD"](0)));
676  env.require(balance("alice", Account("dan")["USD"](0)));
677  env.require(balance("bob", Account("alice")["USD"](0)));
678  env.require(balance("bob", Account("carol")["USD"](-75)));
679  env.require(balance("bob", Account("dan")["USD"](0)));
680  env.require(balance("carol", Account("bob")["USD"](75)));
681  env.require(balance("carol", Account("dan")["USD"](0)));
682  env.require(balance("dan", Account("alice")["USD"](0)));
683  env.require(balance("dan", Account("bob")["USD"](0)));
684  env.require(balance("dan", Account("carol")["USD"](0)));
685  }
686 
687  // alice -- limit 40 --> bob
688  // alice --> carol --> dan --> bob
689  // Balance of 100 USD Bob - Balance of 37 USD -> Rod
690  void
692  {
693  testcase("path negative: ripple-client issue #23: smaller");
694  using namespace jtx;
695  Env env(*this);
696  env.fund(XRP(10000), "alice", "bob", "carol", "dan");
697  env.trust(Account("alice")["USD"](40), "bob");
698  env.trust(Account("dan")["USD"](20), "bob");
699  env.trust(Account("alice")["USD"](20), "carol");
700  env.trust(Account("carol")["USD"](20), "dan");
701  env(pay("alice", "bob", Account("bob")["USD"](55)),
702  paths(Account("alice")["USD"]));
703  env.require(balance("bob", Account("alice")["USD"](40)));
704  env.require(balance("bob", Account("dan")["USD"](15)));
705  }
706 
707  // alice -120 USD-> edward -25 USD-> bob
708  // alice -25 USD-> carol -75 USD -> dan -100 USD-> bob
709  void
711  {
712  testcase("path negative: ripple-client issue #23: larger");
713  using namespace jtx;
714  Env env(*this);
715  env.fund(XRP(10000), "alice", "bob", "carol", "dan", "edward");
716  env.trust(Account("alice")["USD"](120), "edward");
717  env.trust(Account("edward")["USD"](25), "bob");
718  env.trust(Account("dan")["USD"](100), "bob");
719  env.trust(Account("alice")["USD"](25), "carol");
720  env.trust(Account("carol")["USD"](75), "dan");
721  env(pay("alice", "bob", Account("bob")["USD"](50)),
722  paths(Account("alice")["USD"]));
723  env.require(balance("alice", Account("edward")["USD"](-25)));
724  env.require(balance("alice", Account("carol")["USD"](-25)));
725  env.require(balance("bob", Account("edward")["USD"](25)));
726  env.require(balance("bob", Account("dan")["USD"](25)));
727  env.require(balance("carol", Account("alice")["USD"](25)));
728  env.require(balance("carol", Account("dan")["USD"](-25)));
729  env.require(balance("dan", Account("carol")["USD"](25)));
730  env.require(balance("dan", Account("bob")["USD"](-25)));
731  }
732 
733  // carol holds gateway AUD, sells gateway AUD for XRP
734  // bob will hold gateway AUD
735  // alice pays bob gateway AUD using XRP
736  void
738  {
739  testcase("via gateway");
740  using namespace jtx;
741  Env env(*this);
742  auto const gw = Account("gateway");
743  auto const AUD = gw["AUD"];
744  env.fund(XRP(10000), "alice", "bob", "carol", gw);
745  env(rate(gw, 1.1));
746  env.trust(AUD(100), "bob", "carol");
747  env(pay(gw, "carol", AUD(50)));
748  env(offer("carol", XRP(50), AUD(50)));
749  env(pay("alice", "bob", AUD(10)), sendmax(XRP(100)), paths(XRP));
750  env.require(balance("bob", AUD(10)));
751  env.require(balance("carol", AUD(39)));
752 
753  auto const result =
754  find_paths(env, "alice", "bob", Account("bob")["USD"](25));
755  BEAST_EXPECT(std::get<0>(result).empty());
756  }
757 
758  void
760  {
761  testcase("path find");
762  using namespace jtx;
763  Env env(*this);
764  env.fund(XRP(10000), "alice", "bob", "carol");
765  env.trust(Account("alice")["USD"](1000), "bob");
766  env.trust(Account("bob")["USD"](1000), "carol");
767 
768  STPathSet st;
769  STAmount sa;
770  std::tie(st, sa, std::ignore) =
771  find_paths(env, "alice", "carol", Account("carol")["USD"](5));
772  BEAST_EXPECT(same(st, stpath("bob")));
773  BEAST_EXPECT(equal(sa, Account("alice")["USD"](5)));
774  }
775 
776  void
778  {
779  testcase("quality set and test");
780  using namespace jtx;
781  Env env(*this);
782  env.fund(XRP(10000), "alice", "bob");
783  env(trust("bob", Account("alice")["USD"](1000)),
784  json("{\"" + sfQualityIn.fieldName + "\": 2000}"),
785  json("{\"" + sfQualityOut.fieldName + "\": 1400000000}"));
786 
787  Json::Value jv;
789  R"({
790  "Balance" : {
791  "currency" : "USD",
792  "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
793  "value" : "0"
794  },
795  "Flags" : 131072,
796  "HighLimit" : {
797  "currency" : "USD",
798  "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
799  "value" : "1000"
800  },
801  "HighNode" : "0000000000000000",
802  "HighQualityIn" : 2000,
803  "HighQualityOut" : 1400000000,
804  "LedgerEntryType" : "RippleState",
805  "LowLimit" : {
806  "currency" : "USD",
807  "issuer" : "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
808  "value" : "0"
809  },
810  "LowNode" : "0000000000000000"
811  })",
812  jv);
813 
814  auto const jv_l =
815  env.le(keylet::line(
816  Account("bob").id(), Account("alice")["USD"].issue()))
817  ->getJson(JsonOptions::none);
818  for (auto it = jv.begin(); it != jv.end(); ++it)
819  BEAST_EXPECT(*it == jv_l[it.memberName()]);
820  }
821 
822  void
824  {
825  testcase("trust normal clear");
826  using namespace jtx;
827  Env env(*this);
828  env.fund(XRP(10000), "alice", "bob");
829  env.trust(Account("bob")["USD"](1000), "alice");
830  env.trust(Account("alice")["USD"](1000), "bob");
831 
832  Json::Value jv;
834  R"({
835  "Balance" : {
836  "currency" : "USD",
837  "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
838  "value" : "0"
839  },
840  "Flags" : 196608,
841  "HighLimit" : {
842  "currency" : "USD",
843  "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
844  "value" : "1000"
845  },
846  "HighNode" : "0000000000000000",
847  "LedgerEntryType" : "RippleState",
848  "LowLimit" : {
849  "currency" : "USD",
850  "issuer" : "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
851  "value" : "1000"
852  },
853  "LowNode" : "0000000000000000"
854  })",
855  jv);
856 
857  auto const jv_l =
858  env.le(keylet::line(
859  Account("bob").id(), Account("alice")["USD"].issue()))
860  ->getJson(JsonOptions::none);
861  for (auto it = jv.begin(); it != jv.end(); ++it)
862  BEAST_EXPECT(*it == jv_l[it.memberName()]);
863 
864  env.trust(Account("bob")["USD"](0), "alice");
865  env.trust(Account("alice")["USD"](0), "bob");
866  BEAST_EXPECT(
867  env.le(keylet::line(
868  Account("bob").id(), Account("alice")["USD"].issue())) ==
869  nullptr);
870  }
871 
872  void
874  {
875  testcase("trust auto clear");
876  using namespace jtx;
877  Env env(*this);
878  env.fund(XRP(10000), "alice", "bob");
879  env.trust(Account("bob")["USD"](1000), "alice");
880  env(pay("bob", "alice", Account("bob")["USD"](50)));
881  env.trust(Account("bob")["USD"](0), "alice");
882 
883  Json::Value jv;
885  R"({
886  "Balance" :
887  {
888  "currency" : "USD",
889  "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
890  "value" : "50"
891  },
892  "Flags" : 65536,
893  "HighLimit" :
894  {
895  "currency" : "USD",
896  "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
897  "value" : "0"
898  },
899  "HighNode" : "0000000000000000",
900  "LedgerEntryType" : "RippleState",
901  "LowLimit" :
902  {
903  "currency" : "USD",
904  "issuer" : "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
905  "value" : "0"
906  },
907  "LowNode" : "0000000000000000"
908  })",
909  jv);
910 
911  auto const jv_l =
912  env.le(keylet::line(
913  Account("alice").id(), Account("bob")["USD"].issue()))
914  ->getJson(JsonOptions::none);
915  for (auto it = jv.begin(); it != jv.end(); ++it)
916  BEAST_EXPECT(*it == jv_l[it.memberName()]);
917 
918  env(pay("alice", "bob", Account("alice")["USD"](50)));
919  BEAST_EXPECT(
920  env.le(keylet::line(
921  Account("alice").id(), Account("bob")["USD"].issue())) ==
922  nullptr);
923  }
924 
925  void
926  path_find_01()
927  {
928  testcase("Path Find: XRP -> XRP and XRP -> IOU");
929  using namespace jtx;
930  Env env(*this);
931  Account A1{"A1"};
932  Account A2{"A2"};
933  Account A3{"A3"};
934  Account G1{"G1"};
935  Account G2{"G2"};
936  Account G3{"G3"};
937  Account M1{"M1"};
938 
939  env.fund(XRP(100000), A1);
940  env.fund(XRP(10000), A2);
941  env.fund(XRP(1000), A3, G1, G2, G3, M1);
942  env.close();
943 
944  env.trust(G1["XYZ"](5000), A1);
945  env.trust(G3["ABC"](5000), A1);
946  env.trust(G2["XYZ"](5000), A2);
947  env.trust(G3["ABC"](5000), A2);
948  env.trust(A2["ABC"](1000), A3);
949  env.trust(G1["XYZ"](100000), M1);
950  env.trust(G2["XYZ"](100000), M1);
951  env.trust(G3["ABC"](100000), M1);
952  env.close();
953 
954  env(pay(G1, A1, G1["XYZ"](3500)));
955  env(pay(G3, A1, G3["ABC"](1200)));
956  env(pay(G2, M1, G2["XYZ"](25000)));
957  env(pay(G3, M1, G3["ABC"](25000)));
958  env.close();
959 
960  env(offer(M1, G1["XYZ"](1000), G2["XYZ"](1000)));
961  env(offer(M1, XRP(10000), G3["ABC"](1000)));
962 
963  STPathSet st;
964  STAmount sa, da;
965 
966  {
967  auto const& send_amt = XRP(10);
968  std::tie(st, sa, da) =
969  find_paths(env, A1, A2, send_amt, boost::none, xrpCurrency());
970  BEAST_EXPECT(equal(da, send_amt));
971  BEAST_EXPECT(st.empty());
972  }
973 
974  {
975  // no path should exist for this since dest account
976  // does not exist.
977  auto const& send_amt = XRP(200);
978  std::tie(st, sa, da) = find_paths(
979  env, A1, Account{"A0"}, send_amt, boost::none, xrpCurrency());
980  BEAST_EXPECT(equal(da, send_amt));
981  BEAST_EXPECT(st.empty());
982  }
983 
984  {
985  auto const& send_amt = G3["ABC"](10);
986  std::tie(st, sa, da) =
987  find_paths(env, A2, G3, send_amt, boost::none, xrpCurrency());
988  BEAST_EXPECT(equal(da, send_amt));
989  BEAST_EXPECT(equal(sa, XRP(100)));
990  BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]))));
991  }
992 
993  {
994  auto const& send_amt = A2["ABC"](1);
995  std::tie(st, sa, da) =
996  find_paths(env, A1, A2, send_amt, boost::none, xrpCurrency());
997  BEAST_EXPECT(equal(da, send_amt));
998  BEAST_EXPECT(equal(sa, XRP(10)));
999  BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]), G3)));
1000  }
1001 
1002  {
1003  auto const& send_amt = A3["ABC"](1);
1004  std::tie(st, sa, da) =
1005  find_paths(env, A1, A3, send_amt, boost::none, xrpCurrency());
1006  BEAST_EXPECT(equal(da, send_amt));
1007  BEAST_EXPECT(equal(sa, XRP(10)));
1008  BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]), G3, A2)));
1009  }
1010  }
1011 
1012  void
1013  path_find_02()
1014  {
1015  testcase("Path Find: non-XRP -> XRP");
1016  using namespace jtx;
1017  Env env(*this);
1018  Account A1{"A1"};
1019  Account A2{"A2"};
1020  Account G3{"G3"};
1021  Account M1{"M1"};
1022 
1023  env.fund(XRP(1000), A1, A2, G3);
1024  env.fund(XRP(11000), M1);
1025  env.close();
1026 
1027  env.trust(G3["ABC"](1000), A1, A2);
1028  env.trust(G3["ABC"](100000), M1);
1029  env.close();
1030 
1031  env(pay(G3, A1, G3["ABC"](1000)));
1032  env(pay(G3, A2, G3["ABC"](1000)));
1033  env(pay(G3, M1, G3["ABC"](1200)));
1034  env.close();
1035 
1036  env(offer(M1, G3["ABC"](1000), XRP(10000)));
1037 
1038  STPathSet st;
1039  STAmount sa, da;
1040 
1041  auto const& send_amt = XRP(10);
1042  std::tie(st, sa, da) =
1043  find_paths(env, A1, A2, send_amt, boost::none, A2["ABC"].currency);
1044  BEAST_EXPECT(equal(da, send_amt));
1045  BEAST_EXPECT(equal(sa, A1["ABC"](1)));
1046  BEAST_EXPECT(same(st, stpath(G3, IPE(xrpIssue()))));
1047  }
1048 
1049  void
1050  path_find_04()
1051  {
1052  testcase("Path Find: Bitstamp and SnapSwap, liquidity with no offers");
1053  using namespace jtx;
1054  Env env(*this);
1055  Account A1{"A1"};
1056  Account A2{"A2"};
1057  Account G1BS{"G1BS"};
1058  Account G2SW{"G2SW"};
1059  Account M1{"M1"};
1060 
1061  env.fund(XRP(1000), G1BS, G2SW, A1, A2);
1062  env.fund(XRP(11000), M1);
1063  env.close();
1064 
1065  env.trust(G1BS["HKD"](2000), A1);
1066  env.trust(G2SW["HKD"](2000), A2);
1067  env.trust(G1BS["HKD"](100000), M1);
1068  env.trust(G2SW["HKD"](100000), M1);
1069  env.close();
1070 
1071  env(pay(G1BS, A1, G1BS["HKD"](1000)));
1072  env(pay(G2SW, A2, G2SW["HKD"](1000)));
1073  // SnapSwap wants to be able to set trust line quality settings so they
1074  // can charge a fee when transactions ripple across. Liquidity
1075  // provider, via trusting/holding both accounts
1076  env(pay(G1BS, M1, G1BS["HKD"](1200)));
1077  env(pay(G2SW, M1, G2SW["HKD"](5000)));
1078  env.close();
1079 
1080  STPathSet st;
1081  STAmount sa, da;
1082 
1083  {
1084  auto const& send_amt = A2["HKD"](10);
1085  std::tie(st, sa, da) = find_paths(
1086  env, A1, A2, send_amt, boost::none, A2["HKD"].currency);
1087  BEAST_EXPECT(equal(da, send_amt));
1088  BEAST_EXPECT(equal(sa, A1["HKD"](10)));
1089  BEAST_EXPECT(same(st, stpath(G1BS, M1, G2SW)));
1090  }
1091 
1092  {
1093  auto const& send_amt = A1["HKD"](10);
1094  std::tie(st, sa, da) = find_paths(
1095  env, A2, A1, send_amt, boost::none, A1["HKD"].currency);
1096  BEAST_EXPECT(equal(da, send_amt));
1097  BEAST_EXPECT(equal(sa, A2["HKD"](10)));
1098  BEAST_EXPECT(same(st, stpath(G2SW, M1, G1BS)));
1099  }
1100 
1101  {
1102  auto const& send_amt = A2["HKD"](10);
1103  std::tie(st, sa, da) = find_paths(
1104  env, G1BS, A2, send_amt, boost::none, A1["HKD"].currency);
1105  BEAST_EXPECT(equal(da, send_amt));
1106  BEAST_EXPECT(equal(sa, G1BS["HKD"](10)));
1107  BEAST_EXPECT(same(st, stpath(M1, G2SW)));
1108  }
1109 
1110  {
1111  auto const& send_amt = M1["HKD"](10);
1112  std::tie(st, sa, da) = find_paths(
1113  env, M1, G1BS, send_amt, boost::none, A1["HKD"].currency);
1114  BEAST_EXPECT(equal(da, send_amt));
1115  BEAST_EXPECT(equal(sa, M1["HKD"](10)));
1116  BEAST_EXPECT(st.empty());
1117  }
1118 
1119  {
1120  auto const& send_amt = A1["HKD"](10);
1121  std::tie(st, sa, da) = find_paths(
1122  env, G2SW, A1, send_amt, boost::none, A1["HKD"].currency);
1123  BEAST_EXPECT(equal(da, send_amt));
1124  BEAST_EXPECT(equal(sa, G2SW["HKD"](10)));
1125  BEAST_EXPECT(same(st, stpath(M1, G1BS)));
1126  }
1127  }
1128 
1129  void
1130  path_find_05()
1131  {
1132  testcase("Path Find: non-XRP -> non-XRP, same currency");
1133  using namespace jtx;
1134  Env env(*this);
1135  Account A1{"A1"};
1136  Account A2{"A2"};
1137  Account A3{"A3"};
1138  Account A4{"A4"};
1139  Account G1{"G1"};
1140  Account G2{"G2"};
1141  Account G3{"G3"};
1142  Account G4{"G4"};
1143  Account M1{"M1"};
1144  Account M2{"M2"};
1145 
1146  env.fund(XRP(1000), A1, A2, A3, G1, G2, G3, G4);
1147  env.fund(XRP(10000), A4);
1148  env.fund(XRP(11000), M1, M2);
1149  env.close();
1150 
1151  env.trust(G1["HKD"](2000), A1);
1152  env.trust(G2["HKD"](2000), A2);
1153  env.trust(G1["HKD"](2000), A3);
1154  env.trust(G1["HKD"](100000), M1);
1155  env.trust(G2["HKD"](100000), M1);
1156  env.trust(G1["HKD"](100000), M2);
1157  env.trust(G2["HKD"](100000), M2);
1158  env.close();
1159 
1160  env(pay(G1, A1, G1["HKD"](1000)));
1161  env(pay(G2, A2, G2["HKD"](1000)));
1162  env(pay(G1, A3, G1["HKD"](1000)));
1163  env(pay(G1, M1, G1["HKD"](1200)));
1164  env(pay(G2, M1, G2["HKD"](5000)));
1165  env(pay(G1, M2, G1["HKD"](1200)));
1166  env(pay(G2, M2, G2["HKD"](5000)));
1167  env.close();
1168 
1169  env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)));
1170  env(offer(M2, XRP(10000), G2["HKD"](1000)));
1171  env(offer(M2, G1["HKD"](1000), XRP(10000)));
1172 
1173  STPathSet st;
1174  STAmount sa, da;
1175 
1176  {
1177  // A) Borrow or repay --
1178  // Source -> Destination (repay source issuer)
1179  auto const& send_amt = G1["HKD"](10);
1180  std::tie(st, sa, da) = find_paths(
1181  env, A1, G1, send_amt, boost::none, G1["HKD"].currency);
1182  BEAST_EXPECT(st.empty());
1183  BEAST_EXPECT(equal(da, send_amt));
1184  BEAST_EXPECT(equal(sa, A1["HKD"](10)));
1185  }
1186 
1187  {
1188  // A2) Borrow or repay --
1189  // Source -> Destination (repay destination issuer)
1190  auto const& send_amt = A1["HKD"](10);
1191  std::tie(st, sa, da) = find_paths(
1192  env, A1, G1, send_amt, boost::none, G1["HKD"].currency);
1193  BEAST_EXPECT(st.empty());
1194  BEAST_EXPECT(equal(da, send_amt));
1195  BEAST_EXPECT(equal(sa, A1["HKD"](10)));
1196  }
1197 
1198  {
1199  // B) Common gateway --
1200  // Source -> AC -> Destination
1201  auto const& send_amt = A3["HKD"](10);
1202  std::tie(st, sa, da) = find_paths(
1203  env, A1, A3, send_amt, boost::none, G1["HKD"].currency);
1204  BEAST_EXPECT(equal(da, send_amt));
1205  BEAST_EXPECT(equal(sa, A1["HKD"](10)));
1206  BEAST_EXPECT(same(st, stpath(G1)));
1207  }
1208 
1209  {
1210  // C) Gateway to gateway --
1211  // Source -> OB -> Destination
1212  auto const& send_amt = G2["HKD"](10);
1213  std::tie(st, sa, da) = find_paths(
1214  env, G1, G2, send_amt, boost::none, G1["HKD"].currency);
1215  BEAST_EXPECT(equal(da, send_amt));
1216  BEAST_EXPECT(equal(sa, G1["HKD"](10)));
1217  BEAST_EXPECT(same(
1218  st,
1219  stpath(IPE(G2["HKD"])),
1220  stpath(M1),
1221  stpath(M2),
1222  stpath(IPE(xrpIssue()), IPE(G2["HKD"]))));
1223  }
1224 
1225  {
1226  // D) User to unlinked gateway via order book --
1227  // Source -> AC -> OB -> Destination
1228  auto const& send_amt = G2["HKD"](10);
1229  std::tie(st, sa, da) = find_paths(
1230  env, A1, G2, send_amt, boost::none, G1["HKD"].currency);
1231  BEAST_EXPECT(equal(da, send_amt));
1232  BEAST_EXPECT(equal(sa, A1["HKD"](10)));
1233  BEAST_EXPECT(same(
1234  st,
1235  stpath(G1, M1),
1236  stpath(G1, M2),
1237  stpath(G1, IPE(G2["HKD"])),
1238  stpath(G1, IPE(xrpIssue()), IPE(G2["HKD"]))));
1239  }
1240 
1241  {
1242  // I4) XRP bridge" --
1243  // Source -> AC -> OB to XRP -> OB from XRP -> AC -> Destination
1244  auto const& send_amt = A2["HKD"](10);
1245  std::tie(st, sa, da) = find_paths(
1246  env, A1, A2, send_amt, boost::none, G1["HKD"].currency);
1247  BEAST_EXPECT(equal(da, send_amt));
1248  BEAST_EXPECT(equal(sa, A1["HKD"](10)));
1249  BEAST_EXPECT(same(
1250  st,
1251  stpath(G1, M1, G2),
1252  stpath(G1, M2, G2),
1253  stpath(G1, IPE(G2["HKD"]), G2),
1254  stpath(G1, IPE(xrpIssue()), IPE(G2["HKD"]), G2)));
1255  }
1256  }
1257 
1258  void
1259  path_find_06()
1260  {
1261  testcase("Path Find: non-XRP -> non-XRP, same currency)");
1262  using namespace jtx;
1263  Env env(*this);
1264  Account A1{"A1"};
1265  Account A2{"A2"};
1266  Account A3{"A3"};
1267  Account G1{"G1"};
1268  Account G2{"G2"};
1269  Account M1{"M1"};
1270 
1271  env.fund(XRP(11000), M1);
1272  env.fund(XRP(1000), A1, A2, A3, G1, G2);
1273  env.close();
1274 
1275  env.trust(G1["HKD"](2000), A1);
1276  env.trust(G2["HKD"](2000), A2);
1277  env.trust(A2["HKD"](2000), A3);
1278  env.trust(G1["HKD"](100000), M1);
1279  env.trust(G2["HKD"](100000), M1);
1280  env.close();
1281 
1282  env(pay(G1, A1, G1["HKD"](1000)));
1283  env(pay(G2, A2, G2["HKD"](1000)));
1284  env(pay(G1, M1, G1["HKD"](5000)));
1285  env(pay(G2, M1, G2["HKD"](5000)));
1286  env.close();
1287 
1288  env(offer(M1, G1["HKD"](1000), G2["HKD"](1000)));
1289 
1290  // E) Gateway to user
1291  // Source -> OB -> AC -> Destination
1292  auto const& send_amt = A2["HKD"](10);
1293  STPathSet st;
1294  STAmount sa, da;
1295  std::tie(st, sa, da) =
1296  find_paths(env, G1, A2, send_amt, boost::none, G1["HKD"].currency);
1297  BEAST_EXPECT(equal(da, send_amt));
1298  BEAST_EXPECT(equal(sa, G1["HKD"](10)));
1299  BEAST_EXPECT(same(st, stpath(M1, G2), stpath(IPE(G2["HKD"]), G2)));
1300  }
1301 
1302  void
1303  run() override
1304  {
1309  path_find();
1323  xrp_to_xrp();
1324 
1325  // The following path_find_NN tests are data driven tests
1326  // that were originally implemented in js/coffee and migrated
1327  // here. The quantities and currencies used are taken directly from
1328  // those legacy tests, which in some cases probably represented
1329  // customer use cases.
1330 
1331  path_find_01();
1332  path_find_02();
1333  path_find_04();
1334  path_find_05();
1335  path_find_06();
1336  }
1337 };
1338 
1339 BEAST_DEFINE_TESTSUITE(Path, app, ripple);
1340 
1341 } // namespace test
1342 } // namespace ripple
ripple::test::Path_test::path_find_01
void path_find_01()
Definition: Path_test.cpp:861
ripple::test::Path_test::quality_paths_quality_set_and_test
void quality_paths_quality_set_and_test()
Definition: Path_test.cpp:777
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:404
ripple::RPC::JsonContext
Definition: Context.h:52
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::sfQualityIn
const SF_U32 sfQualityIn(access, STI_UINT32, 20, "QualityIn")
Definition: SField.h:372
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:458
ripple::test::Path_test::trust_auto_clear_trust_auto_clear
void trust_auto_clear_trust_auto_clear()
Definition: Path_test.cpp:831
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
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:310
ripple::test::jtx::BookSpec::currency
ripple::Currency currency
Definition: amount.h:158
ripple::test::Path_test::run
void run() override
Definition: Path_test.cpp:1238
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:440
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:985
std::chrono::duration
ripple::keylet::offer
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Definition: Indexes.cpp:201
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::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:141
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:691
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:1065
ripple::test::Path_test::issues_path_negative_issue
void issues_path_negative_issue()
Definition: Path_test.cpp:653
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:238
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
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:462
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:618
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:558
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:232
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:474
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:421
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:199
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:529
ripple::test::Path_test::no_direct_path_no_intermediary_no_alternatives
void no_direct_path_no_intermediary_no_alternatives()
Definition: Path_test.cpp:391
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:587
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:1194
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:143
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:172
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
ripple::sfQualityOut
const SF_U32 sfQualityOut(access, STI_UINT32, 21, "QualityOut")
Definition: SField.h:373
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
void close(NetClock::time_point closeTime, boost::optional< std::chrono::milliseconds > consensusDelay=boost::none)
Close and advance the ledger.
Definition: Env.cpp:111
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:201
ripple::test::jtx::Env::le
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:189
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:264
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::sfPaths
const SField sfPaths(access, STI_PATHSET, 1, "Paths")
Definition: SField.h:486
ripple::test::Path_test::via_offers_via_gateway
void via_offers_via_gateway()
Definition: Path_test.cpp:737
ripple::STPathSet::size
std::vector< STPath >::size_type size() const
Definition: STPathSet.h:381
ripple::tecPATH_DRY
@ tecPATH_DRY
Definition: TER.h:252
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:710
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:801
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:948
ripple::test::Path_test::indirect_paths_path_find
void indirect_paths_path_find()
Definition: Path_test.cpp:759
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:121
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:114
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