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