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 <utility>
33 
34 namespace ripple {
35 namespace test {
36 
37 class Env_test : public beast::unit_test::suite
38 {
39 public:
40  template <class T>
41  static std::string
42  to_string(T const& t)
43  {
44  return boost::lexical_cast<std::string>(t);
45  }
46 
47  // Declarations in Account.h
48  void
50  {
51  using namespace jtx;
52  {
53  Account a;
54  Account b(a);
55  a = b;
56  a = std::move(b);
57  Account c(std::move(a));
58  }
59  Account("alice");
60  Account("alice", KeyType::secp256k1);
61  Account("alice", KeyType::ed25519);
62  auto const gw = Account("gw");
63  [](AccountID) {}(gw);
64  auto const USD = gw["USD"];
65  void(Account("alice") < gw);
68  }
69 
70  // Declarations in amount.h
71  void
73  {
74  using namespace jtx;
75 
76  PrettyAmount(0);
77  PrettyAmount(1);
78  PrettyAmount(0u);
79  PrettyAmount(1u);
80  PrettyAmount(-1);
81  static_assert(
83  static_assert(
85  value,
86  "");
87  static_assert(
89  static_assert(
91  value,
92  "");
93 
94  try
95  {
96  XRP(0.0000001);
97  fail("missing exception");
98  }
99  catch (std::domain_error const&)
100  {
101  pass();
102  }
103  XRP(-0.000001);
104  try
105  {
106  XRP(-0.0000009);
107  fail("missing exception");
108  }
109  catch (std::domain_error const&)
110  {
111  pass();
112  }
113 
114  BEAST_EXPECT(to_string(XRP(5)) == "5 XRP");
115  BEAST_EXPECT(to_string(XRP(.80)) == "0.8 XRP");
116  BEAST_EXPECT(to_string(XRP(.005)) == "5000 drops");
117  BEAST_EXPECT(to_string(XRP(0.1)) == "0.1 XRP");
118  BEAST_EXPECT(to_string(XRP(10000)) == "10000 XRP");
119  BEAST_EXPECT(to_string(drops(10)) == "10 drops");
120  BEAST_EXPECT(to_string(drops(123400000)) == "123.4 XRP");
121  BEAST_EXPECT(to_string(XRP(-5)) == "-5 XRP");
122  BEAST_EXPECT(to_string(XRP(-.99)) == "-0.99 XRP");
123  BEAST_EXPECT(to_string(XRP(-.005)) == "-5000 drops");
124  BEAST_EXPECT(to_string(XRP(-0.1)) == "-0.1 XRP");
125  BEAST_EXPECT(to_string(drops(-10)) == "-10 drops");
126  BEAST_EXPECT(to_string(drops(-123400000)) == "-123.4 XRP");
127 
128  BEAST_EXPECT(XRP(1) == drops(1000000));
129  BEAST_EXPECT(XRP(1) == STAmount(1000000));
130  BEAST_EXPECT(STAmount(1000000) == XRP(1));
131 
132  auto const gw = Account("gw");
133  auto const USD = gw["USD"];
134  BEAST_EXPECT(to_string(USD(0)) == "0/USD(gw)");
135  BEAST_EXPECT(to_string(USD(10)) == "10/USD(gw)");
136  BEAST_EXPECT(to_string(USD(-10)) == "-10/USD(gw)");
137  BEAST_EXPECT(USD(0) == STAmount(USD, 0));
138  BEAST_EXPECT(USD(1) == STAmount(USD, 1));
139  BEAST_EXPECT(USD(-1) == STAmount(USD, -1));
140 
141  auto const get = [](AnyAmount a) { return a; };
142  BEAST_EXPECT(!get(USD(10)).is_any);
143  BEAST_EXPECT(get(any(USD(10))).is_any);
144  }
145 
146  // Test Env
147  void
149  {
150  using namespace jtx;
151  auto const n = XRP(10000);
152  auto const gw = Account("gw");
153  auto const USD = gw["USD"];
154  auto const alice = Account("alice");
155 
156  // unfunded
157  {
158  Env env(*this);
159  env(pay("alice", "bob", XRP(1000)),
160  seq(1),
161  fee(10),
162  sig("alice"),
163  ter(terNO_ACCOUNT));
164  }
165 
166  // fund
167  {
168  Env env(*this);
169 
170  // variadics
171  env.fund(n, "alice");
172  env.fund(n, "bob", "carol");
173  env.fund(n, "dave", noripple("eric"));
174  env.fund(n, "fred", noripple("gary", "hank"));
175  env.fund(n, noripple("irene"));
176  env.fund(n, noripple("jim"), "karen");
177  env.fund(n, noripple("lisa", "mary"));
178 
179  // flags
180  env.fund(n, noripple("xavier"));
181  env.require(nflags("xavier", asfDefaultRipple));
182  env.fund(n, "yana");
183  env.require(flags("yana", asfDefaultRipple));
184  }
185 
186  // trust
187  {
188  Env env(*this);
189  env.fund(n, "alice", "bob", gw);
190  env(trust("alice", USD(100)), require(lines("alice", 1)));
191  }
192 
193  // balance
194  {
195  Env env(*this);
196  BEAST_EXPECT(env.balance(alice) == 0);
197  BEAST_EXPECT(env.balance(alice, USD) != 0);
198  BEAST_EXPECT(env.balance(alice, USD) == USD(0));
199  env.fund(n, alice, gw);
200  BEAST_EXPECT(env.balance(alice) == n);
201  BEAST_EXPECT(env.balance(gw) == n);
202  env.trust(USD(1000), alice);
203  env(pay(gw, alice, USD(10)));
204  BEAST_EXPECT(to_string(env.balance("alice", USD)) == "10/USD(gw)");
205  BEAST_EXPECT(
206  to_string(env.balance(gw, alice["USD"])) == "-10/USD(alice)");
207  }
208 
209  // seq
210  {
211  Env env(*this);
212  env.fund(n, noripple("alice", gw));
213  BEAST_EXPECT(env.seq("alice") == 3);
214  BEAST_EXPECT(env.seq(gw) == 3);
215  }
216 
217  // autofill
218  {
219  Env env(*this);
220  env.fund(n, "alice");
221  env.require(balance("alice", n));
222  env(noop("alice"), fee(1), ter(telINSUF_FEE_P));
223  env(noop("alice"), seq(none), ter(temMALFORMED));
224  env(noop("alice"), seq(none), fee(10), ter(temMALFORMED));
225  env(noop("alice"), fee(none), ter(temMALFORMED));
226  env(noop("alice"), sig(none), ter(temMALFORMED));
227  env(noop("alice"), fee(autofill));
228  env(noop("alice"), fee(autofill), seq(autofill));
229  env(noop("alice"), fee(autofill), seq(autofill), sig(autofill));
230  }
231  }
232 
233  // Env::require
234  void
236  {
237  using namespace jtx;
238  Env env(*this);
239  auto const gw = Account("gw");
240  auto const USD = gw["USD"];
241  env.require(balance("alice", none));
242  env.require(balance("alice", XRP(none)));
243  env.fund(XRP(10000), "alice", gw);
244  env.require(balance("alice", USD(none)));
245  env.trust(USD(100), "alice");
246  env.require(balance("alice", XRP(10000))); // fee refunded
247  env.require(balance("alice", USD(0)));
248  env(pay(gw, "alice", USD(10)), require(balance("alice", USD(10))));
249 
250  env.require(nflags("alice", asfRequireDest));
251  env(fset("alice", asfRequireDest),
252  require(flags("alice", asfRequireDest)));
253  env(fclear("alice", asfRequireDest),
254  require(nflags("alice", asfRequireDest)));
255  }
256 
257  // Signing with secp256k1 and ed25519 keys
258  void
260  {
261  using namespace jtx;
262 
264  Account const alice("alice", KeyType::ed25519);
265  Account const bob("bob", KeyType::secp256k1);
266  Account const carol("carol");
267  env.fund(XRP(10000), alice, bob);
268 
269  // Master key only
270  env(noop(alice));
271  env(noop(bob));
272  env(noop(alice), sig("alice"), ter(tefBAD_AUTH));
273  env(noop(alice),
274  sig(Account("alice", KeyType::secp256k1)),
275  ter(tefBAD_AUTH));
276  env(noop(bob), sig(Account("bob", KeyType::ed25519)), ter(tefBAD_AUTH));
277  env(noop(alice), sig(carol), ter(tefBAD_AUTH));
278 
279  // Master and Regular key
280  env(regkey(alice, bob));
281  env(noop(alice));
282  env(noop(alice), sig(bob));
283  env(noop(alice), sig(alice));
284 
285  // Regular key only
286  env(fset(alice, asfDisableMaster), sig(alice));
287  env(noop(alice));
288  env(noop(alice), sig(bob));
289  env(noop(alice), sig(alice), ter(tefMASTER_DISABLED));
290  env(fclear(alice, asfDisableMaster),
291  sig(alice),
293  env(fclear(alice, asfDisableMaster), sig(bob));
294  env(noop(alice), sig(alice));
295  }
296 
297  // Payment basics
298  void
300  {
301  using namespace jtx;
302  Env env(*this);
303  auto const gw = Account("gateway");
304  auto const USD = gw["USD"];
305 
306  env.fund(XRP(10000), "alice", "bob", "carol", gw);
307  env.require(balance("alice", XRP(10000)));
308  env.require(balance("bob", XRP(10000)));
309  env.require(balance("carol", XRP(10000)));
310  env.require(balance(gw, XRP(10000)));
311 
312  env(pay(env.master, "alice", XRP(1000)), fee(none), ter(temMALFORMED));
313  env(pay(env.master, "alice", XRP(1000)), fee(1), ter(telINSUF_FEE_P));
314  env(pay(env.master, "alice", XRP(1000)), seq(none), ter(temMALFORMED));
315  env(pay(env.master, "alice", XRP(1000)), seq(20), ter(terPRE_SEQ));
316  env(pay(env.master, "alice", XRP(1000)), sig(none), ter(temMALFORMED));
317  env(pay(env.master, "alice", XRP(1000)), sig("bob"), ter(tefBAD_AUTH));
318 
319  env(pay(env.master, "dilbert", XRP(1000)), sig(env.master));
320 
321  env.trust(USD(100), "alice", "bob", "carol");
322  env.require(owners("alice", 1), lines("alice", 1));
323  env(rate(gw, 1.05));
324 
325  env(pay(gw, "carol", USD(50)));
326  env.require(balance("carol", USD(50)));
327  env.require(balance(gw, Account("carol")["USD"](-50)));
328 
329  env(offer("carol", XRP(50), USD(50)), require(owners("carol", 2)));
330  env(pay("alice", "bob", any(USD(10))), ter(tecPATH_DRY));
331  env(pay("alice", "bob", any(USD(10))),
332  paths(XRP),
333  sendmax(XRP(10)),
335  env(pay("alice", "bob", any(USD(10))), paths(XRP), sendmax(XRP(20)));
336  env.require(balance("bob", USD(10)));
337  env.require(balance("carol", USD(39.5)));
338 
339  env.memoize("eric");
340  env(regkey("alice", "eric"));
341  env(noop("alice"));
342  env(noop("alice"), sig("alice"));
343  env(noop("alice"), sig("eric"));
344  env(noop("alice"), sig("bob"), ter(tefBAD_AUTH));
345  env(fset("alice", asfDisableMaster), ter(tecNEED_MASTER_KEY));
346  env(fset("alice", asfDisableMaster),
347  sig("eric"),
349  env.require(nflags("alice", asfDisableMaster));
350  env(fset("alice", asfDisableMaster), sig("alice"));
351  env.require(flags("alice", asfDisableMaster));
352  env(regkey("alice", disabled), ter(tecNO_ALTERNATIVE_KEY));
353  env(noop("alice"));
354  env(noop("alice"), sig("alice"), ter(tefMASTER_DISABLED));
355  env(noop("alice"), sig("eric"));
356  env(noop("alice"), sig("bob"), ter(tefBAD_AUTH));
357  env(fclear("alice", asfDisableMaster), sig("bob"), ter(tefBAD_AUTH));
358  env(fclear("alice", asfDisableMaster),
359  sig("alice"),
361  env(fclear("alice", asfDisableMaster));
362  env.require(nflags("alice", asfDisableMaster));
363  env(regkey("alice", disabled));
364  env(noop("alice"), sig("eric"), ter(tefBAD_AUTH));
365  env(noop("alice"));
366  }
367 
368  // Rudimentary test to ensure fail_hard
369  // transactions are neither queued nor
370  // held.
371  void
373  {
374  using namespace jtx;
375  Env env(*this);
376  auto const gw = Account("gateway");
377  auto const USD = gw["USD"];
378 
379  auto const alice = Account{"alice"};
380  env.fund(XRP(10000), alice);
381 
382  auto const localTxCnt = env.app().getOPs().getLocalTxCount();
383  auto const queueTxCount =
384  env.app().getTxQ().getMetrics(*env.current()).txCount;
385  auto const openTxCount = env.current()->txCount();
386  BEAST_EXPECT(localTxCnt == 2 && queueTxCount == 0 && openTxCount == 2);
387 
388  auto applyTxn = [&env](auto&&... txnArgs) {
389  auto jt = env.jt(txnArgs...);
390  Serializer s;
391  jt.stx->add(s);
392 
394 
395  args[jss::tx_blob] = strHex(s.slice());
396  args[jss::fail_hard] = true;
397 
398  return env.rpc("json", "submit", args.toStyledString());
399  };
400 
401  auto jr = applyTxn(noop(alice), fee(1));
402 
403  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "telINSUF_FEE_P");
404  BEAST_EXPECT(
405  env.app().getTxQ().getMetrics(*env.current()).txCount ==
406  queueTxCount);
407  BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
408  BEAST_EXPECT(env.current()->txCount() == openTxCount);
409 
410  jr = applyTxn(noop(alice), sig("bob"));
411 
412  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "tefBAD_AUTH");
413  BEAST_EXPECT(
414  env.app().getTxQ().getMetrics(*env.current()).txCount ==
415  queueTxCount);
416  BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
417  BEAST_EXPECT(env.current()->txCount() == openTxCount);
418 
419  jr = applyTxn(noop(alice), seq(20));
420 
421  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "terPRE_SEQ");
422  BEAST_EXPECT(
423  env.app().getTxQ().getMetrics(*env.current()).txCount ==
424  queueTxCount);
425  BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
426  BEAST_EXPECT(env.current()->txCount() == openTxCount);
427 
428  jr = applyTxn(offer(alice, XRP(1000), USD(1000)));
429 
430  BEAST_EXPECT(
431  jr[jss::result][jss::engine_result] == "tecUNFUNDED_OFFER");
432  BEAST_EXPECT(
433  env.app().getTxQ().getMetrics(*env.current()).txCount ==
434  queueTxCount);
435  BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
436  BEAST_EXPECT(env.current()->txCount() == openTxCount);
437 
438  jr = applyTxn(noop(alice), fee(drops(-10)));
439 
440  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "temBAD_FEE");
441  BEAST_EXPECT(
442  env.app().getTxQ().getMetrics(*env.current()).txCount ==
443  queueTxCount);
444  BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
445  BEAST_EXPECT(env.current()->txCount() == openTxCount);
446 
447  jr = applyTxn(noop(alice));
448 
449  BEAST_EXPECT(jr[jss::result][jss::engine_result] == "tesSUCCESS");
450  BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt + 1);
451  BEAST_EXPECT(env.current()->txCount() == openTxCount + 1);
452  }
453 
454  // Multi-sign basics
455  void
457  {
458  using namespace jtx;
459 
460  Env env(*this);
461  env.fund(XRP(10000), "alice");
462  env(signers("alice", 1, {{"alice", 1}, {"bob", 2}}),
463  ter(temBAD_SIGNER));
464  env(signers("alice", 1, {{"bob", 1}, {"carol", 2}}));
465  env(noop("alice"));
466 
467  auto const baseFee = env.current()->fees().base;
468  env(noop("alice"), msig("bob"), fee(2 * baseFee));
469  env(noop("alice"), msig("carol"), fee(2 * baseFee));
470  env(noop("alice"), msig("bob", "carol"), fee(3 * baseFee));
471  env(noop("alice"),
472  msig("bob", "carol", "dilbert"),
473  fee(4 * baseFee),
475 
476  env(signers("alice", none));
477  }
478 
479  void
481  {
482  using namespace jtx;
483  // create syntax
484  ticket::create("alice", 1);
485 
486  {
487  Env env(*this);
488  env.fund(XRP(10000), "alice");
489  env(noop("alice"),
490  require(owners("alice", 0), tickets("alice", 0)));
491  env(ticket::create("alice", 1),
492  require(owners("alice", 1), tickets("alice", 1)));
493  }
494  }
495 
496  struct UDT
497  {
498  };
499 
500  void
502  {
503  struct T
504  {
505  };
506  using namespace jtx;
507  JTx jt1;
508  // Test a straightforward
509  // property
510  BEAST_EXPECT(!jt1.get<int>());
511  jt1.set<int>(7);
512  BEAST_EXPECT(jt1.get<int>());
513  BEAST_EXPECT(*jt1.get<int>() == 7);
514  BEAST_EXPECT(!jt1.get<UDT>());
515 
516  // Test that the property is
517  // replaced if it exists.
518  jt1.set<int>(17);
519  BEAST_EXPECT(jt1.get<int>());
520  BEAST_EXPECT(*jt1.get<int>() == 17);
521  BEAST_EXPECT(!jt1.get<UDT>());
522 
523  // Test that modifying the
524  // returned prop is saved
525  *jt1.get<int>() = 42;
526  BEAST_EXPECT(jt1.get<int>());
527  BEAST_EXPECT(*jt1.get<int>() == 42);
528  BEAST_EXPECT(!jt1.get<UDT>());
529 
530  // Test get() const
531  auto const& jt2 = jt1;
532  BEAST_EXPECT(jt2.get<int>());
533  BEAST_EXPECT(*jt2.get<int>() == 42);
534  BEAST_EXPECT(!jt2.get<UDT>());
535  }
536 
537  void
539  {
540  using namespace jtx;
541  Env env(*this);
542  env.fund(XRP(100000), "alice");
543  auto jt1 = env.jt(noop("alice"));
544  BEAST_EXPECT(!jt1.get<std::uint16_t>());
545  auto jt2 = env.jt(noop("alice"), prop<std::uint16_t>(-1));
546  BEAST_EXPECT(jt2.get<std::uint16_t>());
547  BEAST_EXPECT(*jt2.get<std::uint16_t>() == 65535);
548  auto jt3 = env.jt(
549  noop("alice"),
550  prop<std::string>("Hello, world!"),
551  prop<bool>(false));
552  BEAST_EXPECT(jt3.get<std::string>());
553  BEAST_EXPECT(*jt3.get<std::string>() == "Hello, world!");
554  BEAST_EXPECT(jt3.get<bool>());
555  BEAST_EXPECT(!*jt3.get<bool>());
556  }
557 
558  void
560  {
561  struct T
562  {
563  };
564  using namespace jtx;
565  JTx jt1;
566  jt1.set<int>(7);
567  BEAST_EXPECT(jt1.get<int>());
568  BEAST_EXPECT(*jt1.get<int>() == 7);
569  BEAST_EXPECT(!jt1.get<UDT>());
570  JTx jt2(jt1);
571  BEAST_EXPECT(jt2.get<int>());
572  BEAST_EXPECT(*jt2.get<int>() == 7);
573  BEAST_EXPECT(!jt2.get<UDT>());
574  JTx jt3;
575  jt3 = jt1;
576  BEAST_EXPECT(jt3.get<int>());
577  BEAST_EXPECT(*jt3.get<int>() == 7);
578  BEAST_EXPECT(!jt3.get<UDT>());
579  }
580 
581  void
583  {
584  struct T
585  {
586  };
587  using namespace jtx;
588  JTx jt1;
589  jt1.set<int>(7);
590  BEAST_EXPECT(jt1.get<int>());
591  BEAST_EXPECT(*jt1.get<int>() == 7);
592  BEAST_EXPECT(!jt1.get<UDT>());
593  JTx jt2(std::move(jt1));
594  BEAST_EXPECT(!jt1.get<int>());
595  BEAST_EXPECT(!jt1.get<UDT>());
596  BEAST_EXPECT(jt2.get<int>());
597  BEAST_EXPECT(*jt2.get<int>() == 7);
598  BEAST_EXPECT(!jt2.get<UDT>());
599  jt1 = std::move(jt2);
600  BEAST_EXPECT(!jt2.get<int>());
601  BEAST_EXPECT(!jt2.get<UDT>());
602  BEAST_EXPECT(jt1.get<int>());
603  BEAST_EXPECT(*jt1.get<int>() == 7);
604  BEAST_EXPECT(!jt1.get<UDT>());
605  }
606 
607  void
609  {
610  using namespace jtx;
611  Env env(*this);
612  env.fund(XRP(10000), "alice");
613  env(noop("alice"), memodata("data"));
614  env(noop("alice"), memoformat("format"));
615  env(noop("alice"), memotype("type"));
616  env(noop("alice"), memondata("format", "type"));
617  env(noop("alice"), memonformat("data", "type"));
618  env(noop("alice"), memontype("data", "format"));
619  env(noop("alice"), memo("data", "format", "type"));
620  env(noop("alice"),
621  memo("data1", "format1", "type1"),
622  memo("data2", "format2", "type2"));
623  }
624 
625  void
627  {
628  using namespace jtx;
629  Env env(*this);
630  JTx jt(noop("alice"));
631  memo("data", "format", "type")(env, jt);
632 
633  auto const& memo = jt.jv["Memos"][0u]["Memo"];
634  BEAST_EXPECT(
635  memo["MemoData"].asString() == strHex(std::string("data")));
636  BEAST_EXPECT(
637  memo["MemoFormat"].asString() == strHex(std::string("format")));
638  BEAST_EXPECT(
639  memo["MemoType"].asString() == strHex(std::string("type")));
640  }
641 
642  void
644  {
645  using namespace jtx;
646  Env env(*this);
647  auto seq = env.current()->seq();
648  BEAST_EXPECT(seq == env.closed()->seq() + 1);
649  env.close();
650  BEAST_EXPECT(env.closed()->seq() == seq);
651  BEAST_EXPECT(env.current()->seq() == seq + 1);
652  env.close();
653  BEAST_EXPECT(env.closed()->seq() == seq + 1);
654  BEAST_EXPECT(env.current()->seq() == seq + 2);
655  }
656 
657  void
659  {
660  using namespace jtx;
661  Env env(*this);
662  env.close();
663  env.close();
664  env.fund(XRP(100000), "alice", "bob");
665  env.close();
666  env(pay("alice", "bob", XRP(100)));
667  env.close();
668  env(noop("alice"));
669  env.close();
670  env(noop("bob"));
671  }
672 
673  void
675  {
676  using namespace jtx;
677  Env env(*this);
678  auto const gw = Account("gw");
679  auto const USD = gw["USD"];
680  env.fund(XRP(10000), "alice", "bob");
681  env.json(
682  pay("alice", "bob", USD(10)),
683  path(Account("alice")),
684  path("bob"),
685  path(USD),
686  path(~XRP),
687  path(~USD),
688  path("bob", USD, ~XRP, ~USD));
689  }
690 
691  // Test that jtx can re-sign a transaction that's already been signed.
692  void
694  {
695  using namespace jtx;
696  Env env(*this);
697 
698  env.fund(XRP(10000), "alice");
699  auto const baseFee = env.current()->fees().base;
700  std::uint32_t const aliceSeq = env.seq("alice");
701 
702  // Sign jsonNoop.
703  Json::Value jsonNoop =
704  env.json(noop("alice"), fee(baseFee), seq(aliceSeq), sig("alice"));
705  // Re-sign jsonNoop.
706  JTx jt = env.jt(jsonNoop);
707  env(jt);
708  }
709 
710  void
712  {
713  using namespace jtx;
714  Env env(*this);
715  Env_ss envs(env);
716 
717  auto const alice = Account("alice");
718  env.fund(XRP(10000), alice);
719 
720  {
721  envs(noop(alice), fee(none), seq(none))();
722 
723  // Make sure we get the right account back.
724  auto tx = env.tx();
725  if (BEAST_EXPECT(tx))
726  {
727  BEAST_EXPECT(tx->getAccountID(sfAccount) == alice.id());
728  BEAST_EXPECT(tx->getTxnType() == ttACCOUNT_SET);
729  }
730  }
731 
732  {
733  auto params = Json::Value(Json::nullValue);
734  envs(noop(alice), fee(none), seq(none))(params);
735 
736  // Make sure we get the right account back.
737  auto tx = env.tx();
738  if (BEAST_EXPECT(tx))
739  {
740  BEAST_EXPECT(tx->getAccountID(sfAccount) == alice.id());
741  BEAST_EXPECT(tx->getTxnType() == ttACCOUNT_SET);
742  }
743  }
744 
745  {
746  auto params = Json::Value(Json::objectValue);
747  // Force the factor low enough to fail
748  params[jss::fee_mult_max] = 1;
749  params[jss::fee_div_max] = 2;
750  // RPC errors result in temINVALID
751  envs(noop(alice), fee(none), seq(none), ter(temINVALID))(params);
752 
753  auto tx = env.tx();
754  BEAST_EXPECT(!tx);
755  }
756  }
757 
758  void
760  {
761  testcase("Env features");
762  using namespace jtx;
763  auto const supported = supported_amendments();
764 
765  // this finds a feature that is not in
766  // the supported amendments list and tests that it can be
767  // enabled explicitly
768 
769  auto const neverSupportedFeat = [&]() -> std::optional<uint256> {
770  auto const n = supported.size();
771  for (size_t i = 0; i < n; ++i)
772  if (!supported[i])
773  return bitsetIndexToFeature(i);
774 
775  return std::nullopt;
776  }();
777 
778  if (!neverSupportedFeat)
779  {
780  log << "No unsupported features found - skipping test."
781  << std::endl;
782  pass();
783  return;
784  }
785 
786  auto hasFeature = [](Env& env, uint256 const& f) {
787  return (
788  env.app().config().features.find(f) !=
789  env.app().config().features.end());
790  };
791 
792  {
793  // default Env has all supported features
794  Env env{*this};
795  BEAST_EXPECT(
796  supported.count() == env.app().config().features.size());
797  foreachFeature(supported, [&](uint256 const& f) {
798  this->BEAST_EXPECT(hasFeature(env, f));
799  });
800  }
801 
802  {
803  // a Env FeatureBitset has *only* those features
805  BEAST_EXPECT(env.app().config().features.size() == 2);
806  foreachFeature(supported, [&](uint256 const& f) {
807  bool const has =
808  (f == featureMultiSignReserve || f == featureFlow);
809  this->BEAST_EXPECT(has == hasFeature(env, f));
810  });
811  }
812 
813  auto const missingSomeFeatures =
815  BEAST_EXPECT(missingSomeFeatures.count() == (supported.count() - 2));
816  {
817  // a Env supported_features_except is missing *only* those features
818  Env env{*this, missingSomeFeatures};
819  BEAST_EXPECT(
820  env.app().config().features.size() == (supported.count() - 2));
821  foreachFeature(supported, [&](uint256 const& f) {
822  bool hasnot =
823  (f == featureMultiSignReserve || f == featureFlow);
824  this->BEAST_EXPECT(hasnot != hasFeature(env, f));
825  });
826  }
827 
828  {
829  // add a feature that is NOT in the supported amendments list
830  // along with a list of explicit amendments
831  // the unsupported feature should be enabled along with
832  // the two supported ones
833  Env env{
834  *this,
836  featureMultiSignReserve, featureFlow, *neverSupportedFeat)};
837 
838  // this app will have just 2 supported amendments and
839  // one additional never supported feature flag
840  BEAST_EXPECT(env.app().config().features.size() == (2 + 1));
841  BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
842 
843  foreachFeature(supported, [&](uint256 const& f) {
844  bool has = (f == featureMultiSignReserve || f == featureFlow);
845  this->BEAST_EXPECT(has == hasFeature(env, f));
846  });
847  }
848 
849  {
850  // add a feature that is NOT in the supported amendments list
851  // and omit a few standard amendments
852  // the unsupported features should be enabled
853  Env env{
854  *this,
855  missingSomeFeatures | FeatureBitset{*neverSupportedFeat}};
856 
857  // this app will have all supported amendments minus 2 and then the
858  // one additional never supported feature flag
859  BEAST_EXPECT(
860  env.app().config().features.size() ==
861  (supported.count() - 2 + 1));
862  BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
863  foreachFeature(supported, [&](uint256 const& f) {
864  bool hasnot =
865  (f == featureMultiSignReserve || f == featureFlow);
866  this->BEAST_EXPECT(hasnot != hasFeature(env, f));
867  });
868  }
869 
870  {
871  // add a feature that is NOT in the supported amendments list
872  // along with all supported amendments
873  // the unsupported features should be enabled
874  Env env{*this, supported_amendments().set(*neverSupportedFeat)};
875 
876  // this app will have all supported amendments and then the
877  // one additional never supported feature flag
878  BEAST_EXPECT(
879  env.app().config().features.size() == (supported.count() + 1));
880  BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
881  foreachFeature(supported, [&](uint256 const& f) {
882  this->BEAST_EXPECT(hasFeature(env, f));
883  });
884  }
885  }
886 
887  void
889  {
890  except([this] {
891  jtx::Env env{
892  *this,
894  (*cfg).deprecatedClearSection("port_rpc");
895  return cfg;
896  }),
897  nullptr,
899  });
900  pass();
901  }
902 
903  void
904  run() override
905  {
906  testAccount();
907  testAmount();
908  testEnv();
909  testRequire();
910  testKeyType();
911  testPayments();
912  testFailHard();
913  testMultiSign();
914  testTicket();
916  testProp();
917  testJTxCopy();
918  testJTxMove();
919  testMemo();
920  testMemoResult();
921  testAdvance();
922  testClose();
923  testPath();
926  testFeatures();
928  }
929 };
930 
931 BEAST_DEFINE_TESTSUITE(Env, app, ripple);
932 
933 } // namespace test
934 } // namespace ripple
ripple::test::Env_test::testJTxCopy
void testJTxCopy()
Definition: Env_test.cpp:559
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:480
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::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:466
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::test::jtx::balance
A balance matches.
Definition: balance.h:38
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::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:759
ripple::test::jtx::Env::jt
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition: Env.h:439
ripple::test::jtx::require
Check a set of conditions.
Definition: require.h:63
std::set::emplace
T emplace(T... args)
ripple::featureMultiSignReserve
const uint256 featureMultiSignReserve
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:241
ripple::test::Env_test::run
void run() override
Definition: Env_test.cpp:904
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:151
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:299
ripple::KeyType::ed25519
@ ed25519
ripple::test::Env_test::testSignAndSubmit
void testSignAndSubmit()
Definition: Env_test.cpp:711
ripple::base_uint< 160, detail::AccountIDTag >
ripple::test::Env_test::testProp
void testProp()
Definition: Env_test.cpp:538
ripple::foreachFeature
void foreachFeature(FeatureBitset bs, F &&f)
Definition: Feature.h:298
ripple::test::Env_test::testJTxProperties
void testJTxProperties()
Definition: Env_test.cpp:501
ripple::test::Env_test::testAccount
void testAccount()
Definition: Env_test.cpp:49
ripple::asfDisableMaster
constexpr std::uint32_t asfDisableMaster
Definition: TxFlags.h:77
ripple::tecNO_ALTERNATIVE_KEY
@ tecNO_ALTERNATIVE_KEY
Definition: TER.h:263
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:456
ripple::test::Env_test::testJTxMove
void testJTxMove()
Definition: Env_test.cpp:582
ripple::test::Env_test::testClose
void testClose()
Definition: Env_test.cpp:658
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:159
ripple::test::Env_test::testExceptionalShutdown
void testExceptionalShutdown()
Definition: Env_test.cpp:888
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:63
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:70
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:249
ripple::test::Env_test::testMemoResult
void testMemoResult()
Definition: Env_test.cpp:626
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:674
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:275
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:148
ripple::test::Env_test::to_string
static std::string to_string(T const &t)
Definition: Env_test.cpp:42
ripple::KeyType::secp256k1
@ secp256k1
ripple::terNO_ACCOUNT
@ terNO_ACCOUNT
Definition: TER.h:198
ripple::ttACCOUNT_SET
@ ttACCOUNT_SET
This transaction type adjusts various account settings.
Definition: TxFormats.h:68
ripple::Serializer
Definition: Serializer.h:39
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
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:282
ripple::test::Env_test::UDT
Definition: Env_test.cpp:496
ripple::test::jtx::flags
Match set account flags.
Definition: flags.h:108
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:64
std::endl
T endl(T... args)
ripple::test::jtx::pay
Json::Value pay(Account const &account, Account const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
ripple::test::Env_test::testKeyType
void testKeyType()
Definition: Env_test.cpp:259
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:693
ripple::asfDefaultRipple
constexpr std::uint32_t asfDefaultRipple
Definition: TxFlags.h:81
ripple::test::jtx::Env::master
Account const & master
Definition: Env.h:121
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:235
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:372
ripple::tecPATH_DRY
@ tecPATH_DRY
Definition: TER.h:261
ripple::test::jtx::memonformat
Definition: memo.h:112
ripple::test::jtx::nflags
Match clear account flags.
Definition: flags.h:125
ripple::terPRE_SEQ
@ terPRE_SEQ
Definition: TER.h:202
std::is_trivially_constructible
optional
ripple::test::Env_test
Definition: Env_test.cpp:37
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:72
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:1747
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:608
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:300
ripple::test::jtx::Env::json
Json::Value json(JsonValue &&jv, FN const &... fN)
Create JSON from parameters.
Definition: Env.h:453
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
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:687
ripple::test::Env_test::testAdvance
void testAdvance()
Definition: Env_test.cpp:643
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:161
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)