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