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