rippled
Loading...
Searching...
No Matches
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 <test/jtx.h>
21#include <xrpld/app/misc/NetworkOPs.h>
22#include <xrpld/app/misc/TxQ.h>
23#include <xrpl/beast/hash/uhash.h>
24#include <xrpl/beast/unit_test.h>
25#include <xrpl/protocol/Feature.h>
26#include <xrpl/protocol/TxFlags.h>
27#include <xrpl/protocol/jss.h>
28
29#include <boost/lexical_cast.hpp>
30
31#include <optional>
32#include <utility>
33
34namespace ripple {
35namespace test {
36
38{
39public:
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("chenna");
54 Account b(a);
55 a = b;
56 a = std::move(b);
57 Account c(std::move(a));
58 }
59 Account("alice");
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"),
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
263 Env env{*this, supported_amendments() | fixMasterKeyAsRegularKey};
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)),
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));
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}}),
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 envs(
751 noop(alice),
752 fee(none),
753 seq(none),
755 "Fee of 10 exceeds the requested tx limit of 5"))(params);
756
757 auto tx = env.tx();
758 BEAST_EXPECT(!tx);
759 }
760 }
761
762 void
764 {
765 testcase("Env features");
766 using namespace jtx;
767 auto const supported = supported_amendments();
768
769 // this finds a feature that is not in
770 // the supported amendments list and tests that it can be
771 // enabled explicitly
772
773 auto const neverSupportedFeat = [&]() -> std::optional<uint256> {
774 auto const n = supported.size();
775 for (size_t i = 0; i < n; ++i)
776 if (!supported[i])
777 return bitsetIndexToFeature(i);
778
779 return std::nullopt;
780 }();
781
782 if (!neverSupportedFeat)
783 {
784 log << "No unsupported features found - skipping test."
785 << std::endl;
786 pass();
787 return;
788 }
789
790 auto hasFeature = [](Env& env, uint256 const& f) {
791 return (
792 env.app().config().features.find(f) !=
793 env.app().config().features.end());
794 };
795
796 {
797 // default Env has all supported features
798 Env env{*this};
799 BEAST_EXPECT(
800 supported.count() == env.app().config().features.size());
801 foreachFeature(supported, [&](uint256 const& f) {
802 this->BEAST_EXPECT(hasFeature(env, f));
803 });
804 }
805
806 {
807 // a Env FeatureBitset has *only* those features
808 Env env{*this, FeatureBitset(featureMultiSignReserve, featureFlow)};
809 BEAST_EXPECT(env.app().config().features.size() == 2);
810 foreachFeature(supported, [&](uint256 const& f) {
811 bool const has =
812 (f == featureMultiSignReserve || f == featureFlow);
813 this->BEAST_EXPECT(has == hasFeature(env, f));
814 });
815 }
816
817 auto const missingSomeFeatures =
818 supported_amendments() - featureMultiSignReserve - featureFlow;
819 BEAST_EXPECT(missingSomeFeatures.count() == (supported.count() - 2));
820 {
821 // a Env supported_features_except is missing *only* those features
822 Env env{*this, missingSomeFeatures};
823 BEAST_EXPECT(
824 env.app().config().features.size() == (supported.count() - 2));
825 foreachFeature(supported, [&](uint256 const& f) {
826 bool hasnot =
827 (f == featureMultiSignReserve || f == featureFlow);
828 this->BEAST_EXPECT(hasnot != hasFeature(env, f));
829 });
830 }
831
832 {
833 // add a feature that is NOT in the supported amendments list
834 // along with a list of explicit amendments
835 // the unsupported feature should be enabled along with
836 // the two supported ones
837 Env env{
838 *this,
840 featureMultiSignReserve, featureFlow, *neverSupportedFeat)};
841
842 // this app will have just 2 supported amendments and
843 // one additional never supported feature flag
844 BEAST_EXPECT(env.app().config().features.size() == (2 + 1));
845 BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
846
847 foreachFeature(supported, [&](uint256 const& f) {
848 bool has = (f == featureMultiSignReserve || f == featureFlow);
849 this->BEAST_EXPECT(has == hasFeature(env, f));
850 });
851 }
852
853 {
854 // add a feature that is NOT in the supported amendments list
855 // and omit a few standard amendments
856 // the unsupported features should be enabled
857 Env env{
858 *this,
859 missingSomeFeatures | FeatureBitset{*neverSupportedFeat}};
860
861 // this app will have all supported amendments minus 2 and then the
862 // one additional never supported feature flag
863 BEAST_EXPECT(
864 env.app().config().features.size() ==
865 (supported.count() - 2 + 1));
866 BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
867 foreachFeature(supported, [&](uint256 const& f) {
868 bool hasnot =
869 (f == featureMultiSignReserve || f == featureFlow);
870 this->BEAST_EXPECT(hasnot != hasFeature(env, f));
871 });
872 }
873
874 {
875 // add a feature that is NOT in the supported amendments list
876 // along with all supported amendments
877 // the unsupported features should be enabled
878 Env env{*this, supported_amendments().set(*neverSupportedFeat)};
879
880 // this app will have all supported amendments and then the
881 // one additional never supported feature flag
882 BEAST_EXPECT(
883 env.app().config().features.size() == (supported.count() + 1));
884 BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
885 foreachFeature(supported, [&](uint256 const& f) {
886 this->BEAST_EXPECT(hasFeature(env, f));
887 });
888 }
889 }
890
891 void
893 {
894 except([this] {
895 jtx::Env env{
896 *this,
898 (*cfg).deprecatedClearSection("port_rpc");
899 return cfg;
900 }),
901 nullptr,
903 });
904 pass();
905 }
906
907 void
908 run() override
909 {
910 testAccount();
911 testAmount();
912 testEnv();
913 testRequire();
914 testKeyType();
915 testPayments();
916 testFailHard();
918 testTicket();
920 testProp();
921 testJTxCopy();
922 testJTxMove();
923 testMemo();
925 testAdvance();
926 testClose();
927 testPath();
930 testFeatures();
932 }
933};
934
935BEAST_DEFINE_TESTSUITE(Env, app, ripple);
936
937} // namespace test
938} // namespace ripple
Represents a JSON value.
Definition: json_value.h:148
A testsuite class.
Definition: suite.h:55
log_os< char > log
Logging output stream.
Definition: suite.h:152
void pass()
Record a successful test condition.
Definition: suite.h:511
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:155
bool except(F &&f, String const &reason)
Definition: suite.h:448
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition: suite.h:533
virtual Config & config()=0
virtual NetworkOPs & getOPs()=0
virtual TxQ & getTxQ()=0
std::unordered_set< uint256, beast::uhash<> > features
Definition: Config.h:277
FeatureBitset & set(uint256 const &f, bool value=true)
Definition: Feature.h:220
virtual std::size_t getLocalTxCount()=0
Slice slice() const noexcept
Definition: Serializer.h:67
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
Definition: TxQ.cpp:1777
static std::string to_string(T const &t)
Definition: Env_test.cpp:42
void testExceptionalShutdown()
Definition: Env_test.cpp:892
void run() override
Runs the suite.
Definition: Env_test.cpp:908
Immutable cryptographic account descriptor.
Definition: Account.h:39
A transaction testing environment wrapper.
Definition: Env_ss.h:34
A transaction testing environment.
Definition: Env.h:118
Json::Value json(JsonValue &&jv, FN const &... fN)
Create JSON from parameters.
Definition: Env.h:517
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
Definition: Env.cpp:109
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:210
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:530
std::shared_ptr< STTx const > tx() const
Return the tx data for the last JTx.
Definition: Env.cpp:453
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:326
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:115
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition: Env.cpp:262
Account const & master
Definition: Env.h:122
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition: Env.h:491
Application & app()
Definition: Env.h:256
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:765
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:231
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition: Env.cpp:177
void memoize(Account const &account)
Associate AccountID with account.
Definition: Env.cpp:150
A balance matches.
Definition: balance.h:39
Set the fee on a JTx.
Definition: fee.h:36
Match set account flags.
Definition: flags.h:112
Add a memo to a JTx.
Definition: memo.h:35
Set a multisignature on a JTx.
Definition: multisign.h:66
Match clear account flags.
Definition: flags.h:129
Match the number of items in the account's owner directory.
Definition: owners.h:71
Add a path.
Definition: paths.h:57
Set Paths, SendMax on a JTx.
Definition: paths.h:34
Check a set of conditions.
Definition: require.h:65
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: rpc.h:35
Sets the SendMax on a JTx.
Definition: sendmax.h:32
Set the regular signature on a JTx.
Definition: sig.h:35
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:35
T emplace(T... args)
T endl(T... args)
@ nullValue
'null' value
Definition: json_value.h:37
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:44
Json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
Definition: ticket.cpp:30
owner_count< ltRIPPLE_STATE > lines
Match the number of trust lines in the account's owner directory.
Definition: owners.h:87
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition: flags.h:40
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Definition: regkey.cpp:28
Json::Value signers(Account const &account, std::uint32_t quorum, std::vector< signer > const &v)
Definition: multisign.cpp:33
static none_t const none
Definition: tags.h:34
static autofill_t const autofill
Definition: tags.h:42
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:31
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:28
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:54
any_t const any
Returns an amount representing "any issuer".
Definition: amount.cpp:126
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Definition: rate.cpp:31
Json::Value noop(Account const &account)
The null transaction.
Definition: noop.h:31
static disabled_t const disabled
Definition: tags.h:50
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Definition: offer.cpp:28
owner_count< ltTICKET > tickets
Match the number of tickets on the account.
Definition: ticket.h:64
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:104
FeatureBitset supported_amendments()
Definition: Env.h:71
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition: AccountID.h:49
@ telINSUF_FEE_P
Definition: TER.h:57
uint256 bitsetIndexToFeature(size_t i)
Definition: Feature.cpp:415
constexpr std::uint32_t asfRequireDest
Definition: TxFlags.h:76
@ rpcHIGH_FEE
Definition: ErrorCodes.h:58
constexpr std::uint32_t asfDisableMaster
Definition: TxFlags.h:79
@ tefBAD_AUTH
Definition: TER.h:169
@ tefBAD_SIGNATURE
Definition: TER.h:179
@ tefMASTER_DISABLED
Definition: TER.h:177
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
constexpr std::uint32_t asfDefaultRipple
Definition: TxFlags.h:83
@ tecNEED_MASTER_KEY
Definition: TER.h:295
@ tecPATH_PARTIAL
Definition: TER.h:269
@ tecNO_ALTERNATIVE_KEY
Definition: TER.h:283
@ tecPATH_DRY
Definition: TER.h:281
void foreachFeature(FeatureBitset bs, F &&f)
Definition: Feature.h:339
T get(Section const &section, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
Definition: BasicConfig.h:355
@ terNO_ACCOUNT
Definition: TER.h:217
@ terPRE_SEQ
Definition: TER.h:221
@ temBAD_SIGNER
Definition: TER.h:115
@ temMALFORMED
Definition: TER.h:87
std::size_t txCount
Number of transactions in the queue.
Definition: TxQ.h:169
Amount specifier with an option for any issuer.
Execution context for applying a JSON transaction.
Definition: JTx.h:44
Prop * get()
Return a property if it exists.
Definition: JTx.h:88
Json::Value jv
Definition: JTx.h:45
void set(std::unique_ptr< basic_prop > p)
Set a property If the property already exists, it is replaced.
Definition: JTx.h:117
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
Set a property on a JTx.
Definition: prop.h:34
Set the sequence number on a JTx.
Definition: seq.h:34