rippled
Env_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/misc/NetworkOPs.h>
21 #include <ripple/app/misc/TxQ.h>
22 #include <ripple/beast/hash/uhash.h>
23 #include <ripple/beast/unit_test.h>
24 #include <ripple/json/to_string.h>
25 #include <ripple/protocol/Feature.h>
26 #include <ripple/protocol/TxFlags.h>
27 #include <ripple/protocol/jss.h>
28 #include <test/jtx.h>
29 
30 #include <boost/lexical_cast.hpp>
31 #include <optional>
32 #include <thread>
33 #include <utility>
34 
35 namespace ripple {
36 namespace test {
37 
38 class Env_test : public beast::unit_test::suite
39 {
40 public:
41  template <class T>
42  static std::string
43  to_string(T const& t)
44  {
45  return boost::lexical_cast<std::string>(t);
46  }
47 
48  // Declarations in Account.h
49  void
51  {
52  using namespace jtx;
53  {
54  Account a;
55  Account b(a);
56  a = b;
57  a = std::move(b);
58  Account c(std::move(a));
59  }
60  Account("alice");
61  Account("alice", KeyType::secp256k1);
62  Account("alice", KeyType::ed25519);
63  auto const gw = Account("gw");
64  [](AccountID) {}(gw);
65  auto const USD = gw["USD"];
66  void(Account("alice") < gw);
69  }
70 
71  // Declarations in amount.h
72  void
74  {
75  using namespace jtx;
76 
77  PrettyAmount(0);
78  PrettyAmount(1);
79  PrettyAmount(0u);
80  PrettyAmount(1u);
81  PrettyAmount(-1);
82  static_assert(
84  static_assert(
86  value,
87  "");
88  static_assert(
90  static_assert(
92  value,
93  "");
94 
95  try
96  {
97  XRP(0.0000001);
98  fail("missing exception");
99  }
100  catch (std::domain_error const&)
101  {
102  pass();
103  }
104  XRP(-0.000001);
105  try
106  {
107  XRP(-0.0000009);
108  fail("missing exception");
109  }
110  catch (std::domain_error const&)
111  {
112  pass();
113  }
114 
115  BEAST_EXPECT(to_string(XRP(5)) == "5 XRP");
116  BEAST_EXPECT(to_string(XRP(.80)) == "0.8 XRP");
117  BEAST_EXPECT(to_string(XRP(.005)) == "5000 drops");
118  BEAST_EXPECT(to_string(XRP(0.1)) == "0.1 XRP");
119  BEAST_EXPECT(to_string(XRP(10000)) == "10000 XRP");
120  BEAST_EXPECT(to_string(drops(10)) == "10 drops");
121  BEAST_EXPECT(to_string(drops(123400000)) == "123.4 XRP");
122  BEAST_EXPECT(to_string(XRP(-5)) == "-5 XRP");
123  BEAST_EXPECT(to_string(XRP(-.99)) == "-0.99 XRP");
124  BEAST_EXPECT(to_string(XRP(-.005)) == "-5000 drops");
125  BEAST_EXPECT(to_string(XRP(-0.1)) == "-0.1 XRP");
126  BEAST_EXPECT(to_string(drops(-10)) == "-10 drops");
127  BEAST_EXPECT(to_string(drops(-123400000)) == "-123.4 XRP");
128 
129  BEAST_EXPECT(XRP(1) == drops(1000000));
130  BEAST_EXPECT(XRP(1) == STAmount(1000000));
131  BEAST_EXPECT(STAmount(1000000) == XRP(1));
132 
133  auto const gw = Account("gw");
134  auto const USD = gw["USD"];
135  BEAST_EXPECT(to_string(USD(0)) == "0/USD(gw)");
136  BEAST_EXPECT(to_string(USD(10)) == "10/USD(gw)");
137  BEAST_EXPECT(to_string(USD(-10)) == "-10/USD(gw)");
138  BEAST_EXPECT(USD(0) == STAmount(USD, 0));
139  BEAST_EXPECT(USD(1) == STAmount(USD, 1));
140  BEAST_EXPECT(USD(-1) == STAmount(USD, -1));
141 
142  auto const get = [](AnyAmount a) { return a; };
143  BEAST_EXPECT(!get(USD(10)).is_any);
144  BEAST_EXPECT(get(any(USD(10))).is_any);
145  }
146 
147  // Test Env
148  void
150  {
151  using namespace jtx;
152  auto const n = XRP(10000);
153  auto const gw = Account("gw");
154  auto const USD = gw["USD"];
155  auto const alice = Account("alice");
156 
157  // unfunded
158  {
159  Env env(*this);
160  env(pay("alice", "bob", XRP(1000)),
161  seq(1),
162  fee(10),
163  sig("alice"),
164  ter(terNO_ACCOUNT));
165  }
166 
167  // fund
168  {
169  Env env(*this);
170 
171  // variadics
172  env.fund(n, "alice");
173  env.fund(n, "bob", "carol");
174  env.fund(n, "dave", noripple("eric"));
175  env.fund(n, "fred", noripple("gary", "hank"));
176  env.fund(n, noripple("irene"));
177  env.fund(n, noripple("jim"), "karen");
178  env.fund(n, noripple("lisa", "mary"));
179 
180  // flags
181  env.fund(n, noripple("xavier"));
182  env.require(nflags("xavier", asfDefaultRipple));
183  env.fund(n, "yana");
184  env.require(flags("yana", asfDefaultRipple));
185  }
186 
187  // trust
188  {
189  Env env(*this);
190  env.fund(n, "alice", "bob", gw);
191  env(trust("alice", USD(100)), require(lines("alice", 1)));
192  }
193 
194  // balance
195  {
196  Env env(*this);
197  BEAST_EXPECT(env.balance(alice) == 0);
198  BEAST_EXPECT(env.balance(alice, USD) != 0);
199  BEAST_EXPECT(env.balance(alice, USD) == USD(0));
200  env.fund(n, alice, gw);
201  BEAST_EXPECT(env.balance(alice) == n);
202  BEAST_EXPECT(env.balance(gw) == n);
203  env.trust(USD(1000), alice);
204  env(pay(gw, alice, USD(10)));
205  BEAST_EXPECT(to_string(env.balance("alice", USD)) == "10/USD(gw)");
206  BEAST_EXPECT(
207  to_string(env.balance(gw, alice["USD"])) == "-10/USD(alice)");
208  }
209 
210  // seq
211  {
212  Env env(*this);
213  env.fund(n, noripple("alice", gw));
214  BEAST_EXPECT(env.seq("alice") == 3);
215  BEAST_EXPECT(env.seq(gw) == 3);
216  }
217 
218  // autofill
219  {
220  Env env(*this);
221  env.fund(n, "alice");
222  env.require(balance("alice", n));
223  env(noop("alice"), fee(1), ter(telINSUF_FEE_P));
224  env(noop("alice"), seq(none), ter(temMALFORMED));
225  env(noop("alice"), seq(none), fee(10), ter(temMALFORMED));
226  env(noop("alice"), fee(none), ter(temMALFORMED));
227  env(noop("alice"), sig(none), ter(temMALFORMED));
228  env(noop("alice"), fee(autofill));
229  env(noop("alice"), fee(autofill), seq(autofill));
230  env(noop("alice"), fee(autofill), seq(autofill), sig(autofill));
231  }
232  }
233 
234  // Env::require
235  void
237  {
238  using namespace jtx;
239  Env env(*this);
240  auto const gw = Account("gw");
241  auto const USD = gw["USD"];
242  env.require(balance("alice", none));
243  env.require(balance("alice", XRP(none)));
244  env.fund(XRP(10000), "alice", gw);
245  env.require(balance("alice", USD(none)));
246  env.trust(USD(100), "alice");
247  env.require(balance("alice", XRP(10000))); // fee refunded
248  env.require(balance("alice", USD(0)));
249  env(pay(gw, "alice", USD(10)), require(balance("alice", USD(10))));
250 
251  env.require(nflags("alice", asfRequireDest));
252  env(fset("alice", asfRequireDest),
253  require(flags("alice", asfRequireDest)));
254  env(fclear("alice", asfRequireDest),
255  require(nflags("alice", asfRequireDest)));
256  }
257 
258  // Signing with secp256k1 and ed25519 keys
259  void
261  {
262  using namespace jtx;
263 
265  Account const alice("alice", KeyType::ed25519);
266  Account const bob("bob", KeyType::secp256k1);
267  Account const carol("carol");
268  env.fund(XRP(10000), alice, bob);
269 
270  // Master key only
271  env(noop(alice));
272  env(noop(bob));
273  env(noop(alice), sig("alice"), ter(tefBAD_AUTH));
274  env(noop(alice),
275  sig(Account("alice", KeyType::secp256k1)),
276  ter(tefBAD_AUTH));
277  env(noop(bob), sig(Account("bob", KeyType::ed25519)), ter(tefBAD_AUTH));
278  env(noop(alice), sig(carol), ter(tefBAD_AUTH));
279 
280  // Master and Regular key
281  env(regkey(alice, bob));
282  env(noop(alice));
283  env(noop(alice), sig(bob));
284  env(noop(alice), sig(alice));
285 
286  // Regular key only
287  env(fset(alice, asfDisableMaster), sig(alice));
288  env(noop(alice));
289  env(noop(alice), sig(bob));
290  env(noop(alice), sig(alice), ter(tefMASTER_DISABLED));
291  env(fclear(alice, asfDisableMaster),
292  sig(alice),
294  env(fclear(alice, asfDisableMaster), sig(bob));
295  env(noop(alice), sig(alice));
296  }
297 
298  // Payment basics
299  void
301  {
302  using namespace jtx;
303  Env env(*this);
304  auto const gw = Account("gateway");
305  auto const USD = gw["USD"];
306 
307  env.fund(XRP(10000), "alice", "bob", "carol", gw);
308  env.require(balance("alice", XRP(10000)));
309  env.require(balance("bob", XRP(10000)));
310  env.require(balance("carol", XRP(10000)));
311  env.require(balance(gw, XRP(10000)));
312 
313  env(pay(env.master, "alice", XRP(1000)), fee(none), ter(temMALFORMED));
314  env(pay(env.master, "alice", XRP(1000)), fee(1), ter(telINSUF_FEE_P));
315  env(pay(env.master, "alice", XRP(1000)), seq(none), ter(temMALFORMED));
316  env(pay(env.master, "alice", XRP(1000)), seq(20), ter(terPRE_SEQ));
317  env(pay(env.master, "alice", XRP(1000)), sig(none), ter(temMALFORMED));
318  env(pay(env.master, "alice", XRP(1000)), sig("bob"), ter(tefBAD_AUTH));
319 
320  env(pay(env.master, "dilbert", XRP(1000)), sig(env.master));
321 
322  env.trust(USD(100), "alice", "bob", "carol");
323  env.require(owners("alice", 1), lines("alice", 1));
324  env(rate(gw, 1.05));
325 
326  env(pay(gw, "carol", USD(50)));
327  env.require(balance("carol", USD(50)));
328  env.require(balance(gw, Account("carol")["USD"](-50)));
329 
330  env(offer("carol", XRP(50), USD(50)), require(owners("carol", 2)));
331  env(pay("alice", "bob", any(USD(10))), ter(tecPATH_DRY));
332  env(pay("alice", "bob", any(USD(10))),
333  paths(XRP),
334  sendmax(XRP(10)),
336  env(pay("alice", "bob", any(USD(10))), paths(XRP), sendmax(XRP(20)));
337  env.require(balance("bob", USD(10)));
338  env.require(balance("carol", USD(39.5)));
339 
340  env.memoize("eric");
341  env(regkey("alice", "eric"));
342  env(noop("alice"));
343  env(noop("alice"), sig("alice"));
344  env(noop("alice"), sig("eric"));
345  env(noop("alice"), sig("bob"), ter(tefBAD_AUTH));
346  env(fset("alice", asfDisableMaster), ter(tecNEED_MASTER_KEY));
347  env(fset("alice", asfDisableMaster),
348  sig("eric"),
350  env.require(nflags("alice", asfDisableMaster));
351  env(fset("alice", asfDisableMaster), sig("alice"));
352  env.require(flags("alice", asfDisableMaster));
353  env(regkey("alice", disabled), ter(tecNO_ALTERNATIVE_KEY));
354  env(noop("alice"));
355  env(noop("alice"), sig("alice"), ter(tefMASTER_DISABLED));
356  env(noop("alice"), sig("eric"));
357  env(noop("alice"), sig("bob"), ter(tefBAD_AUTH));
358  env(fclear("alice", asfDisableMaster), sig("bob"), ter(tefBAD_AUTH));
359  env(fclear("alice", asfDisableMaster),
360  sig("alice"),
362  env(fclear("alice", asfDisableMaster));
363  env.require(nflags("alice", asfDisableMaster));
364  env(regkey("alice", disabled));
365  env(noop("alice"), sig("eric"), ter(tefBAD_AUTH));
366  env(noop("alice"));
367  }
368 
369  // Rudimentary test to ensure fail_hard
370  // transactions are neither queued nor
371  // held.
372  void
374  {
375  using namespace jtx;
376  Env env(*this);
377  auto const gw = Account("gateway");
378  auto const USD = gw["USD"];
379 
380  auto const alice = Account{"alice"};
381  env.fund(XRP(10000), alice);
382 
383  auto const localTxCnt = env.app().getOPs().getLocalTxCount();
384  auto const queueTxCount =
385  env.app().getTxQ().getMetrics(*env.current()).txCount;
386  auto const openTxCount = env.current()->txCount();
387  BEAST_EXPECT(localTxCnt == 2 && queueTxCount == 0 && openTxCount == 2);
388 
389  auto applyTxn = [&env](auto&&... txnArgs) {
390  auto jt = env.jt(txnArgs...);
391  Serializer s;
392  jt.stx->add(s);
393 
395 
396  args[jss::tx_blob] = strHex(s.slice());
397  args[jss::fail_hard] = true;
398 
399  return env.rpc("json", "submit", args.toStyledString());
400  };
401 
402  auto jr = applyTxn(noop(alice), fee(1));
403 
404  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "telINSUF_FEE_P");
405  BEAST_EXPECT(
406  env.app().getTxQ().getMetrics(*env.current()).txCount ==
407  queueTxCount);
408  BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
409  BEAST_EXPECT(env.current()->txCount() == openTxCount);
410 
411  jr = applyTxn(noop(alice), sig("bob"));
412 
413  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "tefBAD_AUTH");
414  BEAST_EXPECT(
415  env.app().getTxQ().getMetrics(*env.current()).txCount ==
416  queueTxCount);
417  BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
418  BEAST_EXPECT(env.current()->txCount() == openTxCount);
419 
420  jr = applyTxn(noop(alice), seq(20));
421 
422  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "terPRE_SEQ");
423  BEAST_EXPECT(
424  env.app().getTxQ().getMetrics(*env.current()).txCount ==
425  queueTxCount);
426  BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
427  BEAST_EXPECT(env.current()->txCount() == openTxCount);
428 
429  jr = applyTxn(offer(alice, XRP(1000), USD(1000)));
430 
431  BEAST_EXPECT(
432  jr[jss::result][jss::engine_result] == "tecUNFUNDED_OFFER");
433  BEAST_EXPECT(
434  env.app().getTxQ().getMetrics(*env.current()).txCount ==
435  queueTxCount);
436  BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
437  BEAST_EXPECT(env.current()->txCount() == openTxCount);
438 
439  jr = applyTxn(noop(alice), fee(drops(-10)));
440 
441  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "temBAD_FEE");
442  BEAST_EXPECT(
443  env.app().getTxQ().getMetrics(*env.current()).txCount ==
444  queueTxCount);
445  BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
446  BEAST_EXPECT(env.current()->txCount() == openTxCount);
447 
448  jr = applyTxn(noop(alice));
449 
450  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "tesSUCCESS");
451  BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt + 1);
452  BEAST_EXPECT(env.current()->txCount() == openTxCount + 1);
453  }
454 
455  // Multi-sign basics
456  void
458  {
459  using namespace jtx;
460 
461  Env env(*this);
462  env.fund(XRP(10000), "alice");
463  env(signers("alice", 1, {{"alice", 1}, {"bob", 2}}),
464  ter(temBAD_SIGNER));
465  env(signers("alice", 1, {{"bob", 1}, {"carol", 2}}));
466  env(noop("alice"));
467 
468  auto const baseFee = env.current()->fees().base;
469  env(noop("alice"), msig("bob"), fee(2 * baseFee));
470  env(noop("alice"), msig("carol"), fee(2 * baseFee));
471  env(noop("alice"), msig("bob", "carol"), fee(3 * baseFee));
472  env(noop("alice"),
473  msig("bob", "carol", "dilbert"),
474  fee(4 * baseFee),
476 
477  env(signers("alice", none));
478  }
479 
480  void
482  {
483  using namespace jtx;
484  // create syntax
485  ticket::create("alice", 1);
486 
487  {
488  Env env(*this);
489  env.fund(XRP(10000), "alice");
490  env(noop("alice"),
491  require(owners("alice", 0), tickets("alice", 0)));
492  env(ticket::create("alice", 1),
493  require(owners("alice", 1), tickets("alice", 1)));
494  }
495  }
496 
497  struct UDT
498  {
499  };
500 
501  void
503  {
504  struct T
505  {
506  };
507  using namespace jtx;
508  JTx jt1;
509  // Test a straightforward
510  // property
511  BEAST_EXPECT(!jt1.get<int>());
512  jt1.set<int>(7);
513  BEAST_EXPECT(jt1.get<int>());
514  BEAST_EXPECT(*jt1.get<int>() == 7);
515  BEAST_EXPECT(!jt1.get<UDT>());
516 
517  // Test that the property is
518  // replaced if it exists.
519  jt1.set<int>(17);
520  BEAST_EXPECT(jt1.get<int>());
521  BEAST_EXPECT(*jt1.get<int>() == 17);
522  BEAST_EXPECT(!jt1.get<UDT>());
523 
524  // Test that modifying the
525  // returned prop is saved
526  *jt1.get<int>() = 42;
527  BEAST_EXPECT(jt1.get<int>());
528  BEAST_EXPECT(*jt1.get<int>() == 42);
529  BEAST_EXPECT(!jt1.get<UDT>());
530 
531  // Test get() const
532  auto const& jt2 = jt1;
533  BEAST_EXPECT(jt2.get<int>());
534  BEAST_EXPECT(*jt2.get<int>() == 42);
535  BEAST_EXPECT(!jt2.get<UDT>());
536  }
537 
538  void
540  {
541  using namespace jtx;
542  Env env(*this);
543  env.fund(XRP(100000), "alice");
544  auto jt1 = env.jt(noop("alice"));
545  BEAST_EXPECT(!jt1.get<std::uint16_t>());
546  auto jt2 = env.jt(noop("alice"), prop<std::uint16_t>(-1));
547  BEAST_EXPECT(jt2.get<std::uint16_t>());
548  BEAST_EXPECT(*jt2.get<std::uint16_t>() == 65535);
549  auto jt3 = env.jt(
550  noop("alice"),
551  prop<std::string>("Hello, world!"),
552  prop<bool>(false));
553  BEAST_EXPECT(jt3.get<std::string>());
554  BEAST_EXPECT(*jt3.get<std::string>() == "Hello, world!");
555  BEAST_EXPECT(jt3.get<bool>());
556  BEAST_EXPECT(!*jt3.get<bool>());
557  }
558 
559  void
561  {
562  struct T
563  {
564  };
565  using namespace jtx;
566  JTx jt1;
567  jt1.set<int>(7);
568  BEAST_EXPECT(jt1.get<int>());
569  BEAST_EXPECT(*jt1.get<int>() == 7);
570  BEAST_EXPECT(!jt1.get<UDT>());
571  JTx jt2(jt1);
572  BEAST_EXPECT(jt2.get<int>());
573  BEAST_EXPECT(*jt2.get<int>() == 7);
574  BEAST_EXPECT(!jt2.get<UDT>());
575  JTx jt3;
576  jt3 = jt1;
577  BEAST_EXPECT(jt3.get<int>());
578  BEAST_EXPECT(*jt3.get<int>() == 7);
579  BEAST_EXPECT(!jt3.get<UDT>());
580  }
581 
582  void
584  {
585  struct T
586  {
587  };
588  using namespace jtx;
589  JTx jt1;
590  jt1.set<int>(7);
591  BEAST_EXPECT(jt1.get<int>());
592  BEAST_EXPECT(*jt1.get<int>() == 7);
593  BEAST_EXPECT(!jt1.get<UDT>());
594  JTx jt2(std::move(jt1));
595  BEAST_EXPECT(!jt1.get<int>());
596  BEAST_EXPECT(!jt1.get<UDT>());
597  BEAST_EXPECT(jt2.get<int>());
598  BEAST_EXPECT(*jt2.get<int>() == 7);
599  BEAST_EXPECT(!jt2.get<UDT>());
600  jt1 = std::move(jt2);
601  BEAST_EXPECT(!jt2.get<int>());
602  BEAST_EXPECT(!jt2.get<UDT>());
603  BEAST_EXPECT(jt1.get<int>());
604  BEAST_EXPECT(*jt1.get<int>() == 7);
605  BEAST_EXPECT(!jt1.get<UDT>());
606  }
607 
608  void
610  {
611  using namespace jtx;
612  Env env(*this);
613  env.fund(XRP(10000), "alice");
614  env(noop("alice"), memodata("data"));
615  env(noop("alice"), memoformat("format"));
616  env(noop("alice"), memotype("type"));
617  env(noop("alice"), memondata("format", "type"));
618  env(noop("alice"), memonformat("data", "type"));
619  env(noop("alice"), memontype("data", "format"));
620  env(noop("alice"), memo("data", "format", "type"));
621  env(noop("alice"),
622  memo("data1", "format1", "type1"),
623  memo("data2", "format2", "type2"));
624  }
625 
626  void
628  {
629  using namespace jtx;
630  Env env(*this);
631  JTx jt(noop("alice"));
632  memo("data", "format", "type")(env, jt);
633 
634  auto const& memo = jt.jv["Memos"][0u]["Memo"];
635  BEAST_EXPECT(
636  memo["MemoData"].asString() == strHex(std::string("data")));
637  BEAST_EXPECT(
638  memo["MemoFormat"].asString() == strHex(std::string("format")));
639  BEAST_EXPECT(
640  memo["MemoType"].asString() == strHex(std::string("type")));
641  }
642 
643  void
645  {
646  using namespace jtx;
647  Env env(*this);
648  auto seq = env.current()->seq();
649  BEAST_EXPECT(seq == env.closed()->seq() + 1);
650  env.close();
651  BEAST_EXPECT(env.closed()->seq() == seq);
652  BEAST_EXPECT(env.current()->seq() == seq + 1);
653  env.close();
654  BEAST_EXPECT(env.closed()->seq() == seq + 1);
655  BEAST_EXPECT(env.current()->seq() == seq + 2);
656  }
657 
658  void
660  {
661  using namespace jtx;
662  Env env(*this);
663  env.close();
664  env.close();
665  env.fund(XRP(100000), "alice", "bob");
666  env.close();
667  env(pay("alice", "bob", XRP(100)));
668  env.close();
669  env(noop("alice"));
670  env.close();
671  env(noop("bob"));
672  }
673 
674  void
676  {
677  using namespace jtx;
678  Env env(*this);
679  auto const gw = Account("gw");
680  auto const USD = gw["USD"];
681  env.fund(XRP(10000), "alice", "bob");
682  env.json(
683  pay("alice", "bob", USD(10)),
684  path(Account("alice")),
685  path("bob"),
686  path(USD),
687  path(~XRP),
688  path(~USD),
689  path("bob", USD, ~XRP, ~USD));
690  }
691 
692  // Test that jtx can re-sign a transaction that's already been signed.
693  void
695  {
696  using namespace jtx;
697  Env env(*this);
698 
699  env.fund(XRP(10000), "alice");
700  auto const baseFee = env.current()->fees().base;
701  std::uint32_t const aliceSeq = env.seq("alice");
702 
703  // Sign jsonNoop.
704  Json::Value jsonNoop =
705  env.json(noop("alice"), fee(baseFee), seq(aliceSeq), sig("alice"));
706  // Re-sign jsonNoop.
707  JTx jt = env.jt(jsonNoop);
708  env(jt);
709  }
710 
711  void
713  {
714  using namespace jtx;
715  Env env(*this);
716  Env_ss envs(env);
717 
718  auto const alice = Account("alice");
719  env.fund(XRP(10000), alice);
720 
721  {
722  envs(noop(alice), fee(none), seq(none))();
723 
724  // Make sure we get the right account back.
725  auto tx = env.tx();
726  if (BEAST_EXPECT(tx))
727  {
728  BEAST_EXPECT(tx->getAccountID(sfAccount) == alice.id());
729  BEAST_EXPECT(tx->getTxnType() == ttACCOUNT_SET);
730  }
731  }
732 
733  {
734  auto params = Json::Value(Json::nullValue);
735  envs(noop(alice), fee(none), seq(none))(params);
736 
737  // Make sure we get the right account back.
738  auto tx = env.tx();
739  if (BEAST_EXPECT(tx))
740  {
741  BEAST_EXPECT(tx->getAccountID(sfAccount) == alice.id());
742  BEAST_EXPECT(tx->getTxnType() == ttACCOUNT_SET);
743  }
744  }
745 
746  {
747  auto params = Json::Value(Json::objectValue);
748  // Force the factor low enough to fail
749  params[jss::fee_mult_max] = 1;
750  params[jss::fee_div_max] = 2;
751  // RPC errors result in temINVALID
752  envs(noop(alice), fee(none), seq(none), ter(temINVALID))(params);
753 
754  auto tx = env.tx();
755  BEAST_EXPECT(!tx);
756  }
757  }
758 
759  void
761  {
762  testcase("Env features");
763  using namespace jtx;
764  auto const supported = supported_amendments();
765 
766  // this finds a feature that is not in
767  // the supported amendments list and tests that it can be
768  // enabled explicitly
769 
770  auto const neverSupportedFeat = [&]() -> std::optional<uint256> {
771  auto const n = supported.size();
772  for (size_t i = 0; i < n; ++i)
773  if (!supported[i])
774  return bitsetIndexToFeature(i);
775 
776  return std::nullopt;
777  }();
778 
779  if (!neverSupportedFeat)
780  {
781  log << "No unsupported features found - skipping test."
782  << std::endl;
783  pass();
784  return;
785  }
786 
787  auto hasFeature = [](Env& env, uint256 const& f) {
788  return (
789  env.app().config().features.find(f) !=
790  env.app().config().features.end());
791  };
792 
793  {
794  // default Env has all supported features
795  Env env{*this};
796  BEAST_EXPECT(
797  supported.count() == env.app().config().features.size());
798  foreachFeature(supported, [&](uint256 const& f) {
799  this->BEAST_EXPECT(hasFeature(env, f));
800  });
801  }
802 
803  {
804  // a Env FeatureBitset has *only* those features
806  BEAST_EXPECT(env.app().config().features.size() == 2);
807  foreachFeature(supported, [&](uint256 const& f) {
808  bool const has =
809  (f == featureMultiSignReserve || f == featureFlow);
810  this->BEAST_EXPECT(has == hasFeature(env, f));
811  });
812  }
813 
814  auto const missingSomeFeatures =
816  BEAST_EXPECT(missingSomeFeatures.count() == (supported.count() - 2));
817  {
818  // a Env supported_features_except is missing *only* those features
819  Env env{*this, missingSomeFeatures};
820  BEAST_EXPECT(
821  env.app().config().features.size() == (supported.count() - 2));
822  foreachFeature(supported, [&](uint256 const& f) {
823  bool hasnot =
824  (f == featureMultiSignReserve || f == featureFlow);
825  this->BEAST_EXPECT(hasnot != hasFeature(env, f));
826  });
827  }
828 
829  {
830  // add a feature that is NOT in the supported amendments list
831  // along with a list of explicit amendments
832  // the unsupported feature should be enabled along with
833  // the two supported ones
834  Env env{
835  *this,
837  featureMultiSignReserve, featureFlow, *neverSupportedFeat)};
838 
839  // this app will have just 2 supported amendments and
840  // one additional never supported feature flag
841  BEAST_EXPECT(env.app().config().features.size() == (2 + 1));
842  BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
843 
844  foreachFeature(supported, [&](uint256 const& f) {
845  bool has = (f == featureMultiSignReserve || f == featureFlow);
846  this->BEAST_EXPECT(has == hasFeature(env, f));
847  });
848  }
849 
850  {
851  // add a feature that is NOT in the supported amendments list
852  // and omit a few standard amendments
853  // the unsupported features should be enabled
854  Env env{
855  *this,
856  missingSomeFeatures | FeatureBitset{*neverSupportedFeat}};
857 
858  // this app will have all supported amendments minus 2 and then the
859  // one additional never supported feature flag
860  BEAST_EXPECT(
861  env.app().config().features.size() ==
862  (supported.count() - 2 + 1));
863  BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
864  foreachFeature(supported, [&](uint256 const& f) {
865  bool hasnot =
866  (f == featureMultiSignReserve || f == featureFlow);
867  this->BEAST_EXPECT(hasnot != hasFeature(env, f));
868  });
869  }
870 
871  {
872  // add a feature that is NOT in the supported amendments list
873  // along with all supported amendments
874  // the unsupported features should be enabled
875  Env env{*this, supported_amendments().set(*neverSupportedFeat)};
876 
877  // this app will have all supported amendments and then the
878  // one additional never supported feature flag
879  BEAST_EXPECT(
880  env.app().config().features.size() == (supported.count() + 1));
881  BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
882  foreachFeature(supported, [&](uint256 const& f) {
883  this->BEAST_EXPECT(hasFeature(env, f));
884  });
885  }
886  }
887 
888  void
890  {
891  except([this] {
892  jtx::Env env{
893  *this,
895  (*cfg).deprecatedClearSection("port_rpc");
896  return cfg;
897  }),
898  nullptr,
900  });
901  pass();
902  }
903 
904  void
906  {
907  using namespace jtx;
908  Env env(*this);
909 
910  auto const alice = Account{"alice"};
911  auto const n = XRP(10000);
912  env.fund(n, alice);
913  BEAST_EXPECT(env.balance(alice) == n);
914 
915  // submit only
916  auto applyBlobTxn = [&env](char const* syncMode, auto&&... txnArgs) {
917  auto jt = env.jt(txnArgs...);
918  Serializer s;
919  jt.stx->add(s);
920 
922 
923  args[jss::tx_blob] = strHex(s.slice());
924  args[jss::fail_hard] = true;
925  args[jss::sync_mode] = syncMode;
926 
927  return env.rpc("json", "submit", args.toStyledString());
928  };
929 
930  auto jr = applyBlobTxn("sync", noop(alice));
931  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "tesSUCCESS");
932 
933  jr = applyBlobTxn("async", noop(alice));
934  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "terSUBMITTED");
935  // Make sure it gets processed before submitting and waiting.
936  env.app().getOPs().transactionBatch(true);
937 
938  auto applier = [&env]() {
939  while (!env.app().getOPs().transactionBatch(false))
941  };
942  auto t = std::thread(applier);
943 
944  jr = applyBlobTxn("wait", noop(alice));
945  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "tesSUCCESS");
946  t.join();
947 
948  jr = applyBlobTxn("scott", noop(alice));
949  BEAST_EXPECT(jr[jss::result][jss::error] == "invalidParams");
950 
951  // sign and submit
952  auto applyJsonTxn = [&env](
953  char const* syncMode,
954  std::string const secret,
955  Json::Value const& val) {
957  args[jss::secret] = secret;
958  args[jss::tx_json] = val;
959  args[jss::fail_hard] = true;
960  args[jss::sync_mode] = syncMode;
961 
962  return env.rpc("json", "submit", args.toStyledString());
963  };
964 
965  Json::Value payment;
966  auto secret = toBase58(generateSeed("alice"));
967  payment = noop("alice");
968  payment[sfSequence.fieldName] = env.seq("alice");
969  payment[sfSetFlag.fieldName] = 0;
970  jr = applyJsonTxn("sync", secret, payment);
971  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "tesSUCCESS");
972 
973  payment[sfSequence.fieldName] = env.seq("alice");
974  jr = applyJsonTxn("async", secret, payment);
975  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "terSUBMITTED");
976 
977  env.app().getOPs().transactionBatch(true);
978  payment[sfSequence.fieldName] = env.seq("alice");
979 
980  auto aSeq = env.seq("alice");
981  t = std::thread(applier);
982  jr = applyJsonTxn("wait", secret, payment);
983  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "tesSUCCESS");
984  t.join();
985  // Ensure the last transaction was processed.
986  BEAST_EXPECT(env.seq("alice") == aSeq + 1);
987 
988  payment[sfSequence.fieldName] = env.seq("alice");
989  jr = applyJsonTxn("scott", secret, payment);
990  BEAST_EXPECT(jr[jss::result][jss::error] == "invalidParams");
991  }
992 
993  void
994  run() override
995  {
996  testAccount();
997  testAmount();
998  testEnv();
999  testRequire();
1000  testKeyType();
1001  testPayments();
1002  testFailHard();
1003  testMultiSign();
1004  testTicket();
1006  testProp();
1007  testJTxCopy();
1008  testJTxMove();
1009  testMemo();
1010  testMemoResult();
1011  testAdvance();
1012  testClose();
1013  testPath();
1014  testResignSigned();
1016  testFeatures();
1018  testSyncSubmit();
1019  }
1020 };
1021 
1022 BEAST_DEFINE_TESTSUITE(Env, app, ripple);
1023 
1024 } // namespace test
1025 } // namespace ripple
ripple::test::Env_test::testJTxCopy
void testJTxCopy()
Definition: Env_test.cpp:560
ripple::test::jtx::noop
Json::Value noop(Account const &account)
The null transaction.
Definition: noop.h:31
ripple::test::Env_test::testTicket
void testTicket()
Definition: Env_test.cpp:481
std::this_thread::sleep_for
T sleep_for(T... args)
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
std::domain_error
STL class.
std::string
STL class.
utility
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
beast::severities::kDisabled
@ kDisabled
Definition: Journal.h:41
ripple::test::Env_test::testSyncSubmit
void testSyncSubmit()
Definition: Env_test.cpp:905
ripple::test::jtx::Env::tx
std::shared_ptr< STTx const > tx() const
Return the tx data for the last JTx.
Definition: Env.cpp:382
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::jtx::owners
Match the number of items in the account's owner directory.
Definition: owners.h:69
ripple::test::jtx::Env::require
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:479
ripple::test::jtx::Env::closed
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
Definition: Env.cpp:115
std::unordered_set
STL class.
ripple::test::jtx::prop
Set a property on a JTx.
Definition: prop.h:32
ripple::test::jtx::memontype
Definition: memo.h:128
ripple::sfSequence
const SF_UINT32 sfSequence
ripple::test::jtx::balance
A balance matches.
Definition: balance.h:38
ripple::SField::fieldName
const std::string fieldName
Definition: SField.h:135
ripple::test::jtx::memo
Add a memo to a JTx.
Definition: memo.h:34
ripple::test::jtx::AnyAmount
Amount specifier with an option for any issuer.
Definition: amount.h:361
ripple::test::Env_test::testFeatures
void testFeatures()
Definition: Env_test.cpp:760
ripple::test::jtx::Env::jt
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition: Env.h:440
std::chrono::milliseconds
ripple::test::jtx::require
Check a set of conditions.
Definition: require.h:63
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
std::set::emplace
T emplace(T... args)
ripple::featureMultiSignReserve
const uint256 featureMultiSignReserve
ripple::sfSetFlag
const SF_UINT32 sfSetFlag
ripple::test::jtx::Env::balance
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition: Env.cpp:183
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:242
ripple::test::Env_test::run
void run() override
Definition: Env_test.cpp:994
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:49
ripple::test::jtx::memotype
Definition: memo.h:82
ripple::test::jtx::msig
Set a multisignature on a JTx.
Definition: multisign.h:63
ripple::test::jtx::memondata
Definition: memo.h:96
ripple::tefBAD_AUTH
@ tefBAD_AUTH
Definition: TER.h:153
ripple::test::jtx::Env::trust
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition: Env.cpp:259
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::test::Env_test::testPayments
void testPayments()
Definition: Env_test.cpp:300
ripple::KeyType::ed25519
@ ed25519
ripple::test::Env_test::testSignAndSubmit
void testSignAndSubmit()
Definition: Env_test.cpp:712
ripple::base_uint< 160, detail::AccountIDTag >
ripple::test::Env_test::testProp
void testProp()
Definition: Env_test.cpp:539
ripple::foreachFeature
void foreachFeature(FeatureBitset bs, F &&f)
Definition: Feature.h:298
ripple::test::Env_test::testJTxProperties
void testJTxProperties()
Definition: Env_test.cpp:502
ripple::test::Env_test::testAccount
void testAccount()
Definition: Env_test.cpp:50
ripple::asfDisableMaster
constexpr std::uint32_t asfDisableMaster
Definition: TxFlags.h:77
ripple::tecNO_ALTERNATIVE_KEY
@ tecNO_ALTERNATIVE_KEY
Definition: TER.h:267
thread
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::test::Env_test::testMultiSign
void testMultiSign()
Definition: Env_test.cpp:457
ripple::test::Env_test::testJTxMove
void testJTxMove()
Definition: Env_test.cpp:583
ripple::test::Env_test::testClose
void testClose()
Definition: Env_test.cpp:659
ripple::test::jtx::any
const any_t any
Returns an amount representing "any issuer".
Definition: amount.cpp:126
ripple::test::jtx::memoformat
Definition: memo.h:68
ripple::tefMASTER_DISABLED
@ tefMASTER_DISABLED
Definition: TER.h:161
ripple::test::Env_test::testExceptionalShutdown
void testExceptionalShutdown()
Definition: Env_test.cpp:889
ripple::temBAD_SIGNER
@ temBAD_SIGNER
Definition: TER.h:113
ripple::JsonOptions::none
@ none
ripple::Application::config
virtual Config & config()=0
ripple::test::jtx::JTx::set
void set(std::unique_ptr< basic_prop > p)
Set a property If the property already exists, it is replaced.
Definition: JTx.h:112
ripple::test::jtx::sendmax
Sets the SendMax on a JTx.
Definition: sendmax.h:31
ripple::test::jtx::JTx
Execution context for applying a JSON transaction.
Definition: JTx.h:42
ripple::test::jtx::JTx::jv
Json::Value jv
Definition: JTx.h:44
ripple::Application::getTxQ
virtual TxQ & getTxQ()=0
ripple::test::jtx::fset
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:28
ripple::telINSUF_FEE_P
@ telINSUF_FEE_P
Definition: TER.h:56
ripple::test::jtx::paths
Set Paths, SendMax on a JTx.
Definition: paths.h:32
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
ripple::STAmount
Definition: STAmount.h:45
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:64
ripple::fixMasterKeyAsRegularKey
const uint256 fixMasterKeyAsRegularKey
ripple::test::jtx::path
Add a path.
Definition: paths.h:55
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:71
std::uint16_t
ripple::test::jtx::sig
Set the regular signature on a JTx.
Definition: sig.h:34
ripple::tecPATH_PARTIAL
@ tecPATH_PARTIAL
Definition: TER.h:253
ripple::test::Env_test::testMemoResult
void testMemoResult()
Definition: Env_test.cpp:627
ripple::test::jtx::Env::seq
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:207
ripple::NetworkOPs::getLocalTxCount
virtual std::size_t getLocalTxCount()=0
ripple::test::jtx::memodata
Definition: memo.h:54
ripple::test::Env_test::testPath
void testPath()
Definition: Env_test.cpp:675
ripple::test::jtx::Env_ss
A transaction testing environment wrapper.
Definition: Env_ss.h:33
ripple::test::jtx::fclear
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition: flags.h:40
ripple::tecNEED_MASTER_KEY
@ tecNEED_MASTER_KEY
Definition: TER.h:279
ripple::NetworkOPs::transactionBatch
virtual bool transactionBatch(bool drain)=0
Apply transactions in batches.
ripple::test::jtx::fee
Set the fee on a JTx.
Definition: fee.h:35
ripple::test::Env_test::testEnv
void testEnv()
Definition: Env_test.cpp:149
ripple::test::Env_test::to_string
static std::string to_string(T const &t)
Definition: Env_test.cpp:43
ripple::KeyType::secp256k1
@ secp256k1
ripple::terNO_ACCOUNT
@ terNO_ACCOUNT
Definition: TER.h:200
ripple::ttACCOUNT_SET
@ ttACCOUNT_SET
This transaction type adjusts various account settings.
Definition: TxFormats.h:68
ripple::Serializer
Definition: Serializer.h:40
ripple::test::jtx::JTx::get
Prop * get()
Return a property if it exists.
Definition: JTx.h:83
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:33
ripple::generateSeed
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
Definition: Seed.cpp:69
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Config::features
std::unordered_set< uint256, beast::uhash<> > features
Definition: Config.h:283
ripple::test::Env_test::UDT
Definition: Env_test.cpp:497
ripple::test::jtx::flags
Match set account flags.
Definition: flags.h:111
ripple::test::jtx::noripple
std::array< Account, 1+sizeof...(Args)> noripple(Account const &account, Args const &... args)
Designate accounts as no-ripple in Env::fund.
Definition: Env.h:65
std::endl
T endl(T... args)
ripple::test::Env_test::testKeyType
void testKeyType()
Definition: Env_test.cpp:260
ripple::test::jtx::regkey
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Definition: regkey.cpp:28
ripple::featureFlow
const uint256 featureFlow
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
ripple::test::Env_test::testResignSigned
void testResignSigned()
Definition: Env_test.cpp:694
ripple::asfDefaultRipple
constexpr std::uint32_t asfDefaultRipple
Definition: TxFlags.h:81
ripple::test::jtx::Env::master
Account const & master
Definition: Env.h:122
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::asfRequireDest
constexpr std::uint32_t asfRequireDest
Definition: TxFlags.h:74
ripple::test::Env_test::testRequire
void testRequire()
Definition: Env_test.cpp:236
ripple::bitsetIndexToFeature
uint256 bitsetIndexToFeature(size_t i)
Definition: Feature.cpp:375
ripple::FeatureBitset::set
FeatureBitset & set(uint256 const &f, bool value=true)
Definition: Feature.h:179
ripple::FeatureBitset
Definition: Feature.h:113
ripple::TxQ::Metrics::txCount
std::size_t txCount
Number of transactions in the queue.
Definition: TxQ.h:167
ripple::test::Env_test::testFailHard
void testFailHard()
Definition: Env_test.cpp:373
ripple::tecPATH_DRY
@ tecPATH_DRY
Definition: TER.h:265
ripple::test::jtx::memonformat
Definition: memo.h:112
ripple::test::jtx::nflags
Match clear account flags.
Definition: flags.h:128
ripple::terPRE_SEQ
@ terPRE_SEQ
Definition: TER.h:204
std::is_trivially_constructible
optional
ripple::test::Env_test
Definition: Env_test.cpp:38
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::test::Env_test::testAmount
void testAmount()
Definition: Env_test.cpp:73
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:85
ripple::TxQ::getMetrics
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
Definition: TxQ.cpp:1748
ripple::test::jtx::Env::memoize
void memoize(Account const &account)
Associate AccountID with account.
Definition: Env.cpp:156
std::unique_ptr
STL class.
std::set
STL class.
ripple::test::Env_test::testMemo
void testMemo()
Definition: Env_test.cpp:609
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:301
ripple::test::jtx::Env::json
Json::Value json(JsonValue &&jv, FN const &... fN)
Create JSON from parameters.
Definition: Env.h:466
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:117
ripple::temINVALID
@ temINVALID
Definition: TER.h:108
ripple::test::jtx::Env::rpc
Json::Value rpc(std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:700
ripple::test::Env_test::testAdvance
void testAdvance()
Definition: Env_test.cpp:644
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::jtx::PrettyAmount
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
Definition: amount.h:73
ripple::get
T & get(EitherAmount &amt)
Definition: AmountSpec.h:118
ripple::test::jtx::owner_count
Definition: owners.h:49
ripple::tefBAD_SIGNATURE
@ tefBAD_SIGNATURE
Definition: TER.h:163
ripple::test::jtx::rate
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Definition: rate.cpp:30
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)