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);
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(trust("alice", USD(100)), require(lines("alice", 1)));
193 }
194
195 // balance
196 {
197 Env env(*this);
198 BEAST_EXPECT(env.balance(alice) == 0);
199 BEAST_EXPECT(env.balance(alice, USD) != 0);
200 BEAST_EXPECT(env.balance(alice, USD) == USD(0));
201 env.fund(n, alice, gw);
202 BEAST_EXPECT(env.balance(alice) == n);
203 BEAST_EXPECT(env.balance(gw) == n);
204 env.trust(USD(1000), alice);
205 env(pay(gw, alice, USD(10)));
206 BEAST_EXPECT(to_string(env.balance("alice", USD)) == "10/USD(gw)");
207 BEAST_EXPECT(
208 to_string(env.balance(gw, alice["USD"])) == "-10/USD(alice)");
209 }
210
211 // seq
212 {
213 Env env(*this);
214 env.fund(n, noripple("alice", gw));
215 BEAST_EXPECT(env.seq("alice") == 3);
216 BEAST_EXPECT(env.seq(gw) == 3);
217 }
218
219 // autofill
220 {
221 Env env(*this);
222 env.fund(n, "alice");
223 env.require(balance("alice", n));
224 env(noop("alice"), fee(1), ter(telINSUF_FEE_P));
225 env(noop("alice"), seq(none), ter(temMALFORMED));
226 env(noop("alice"), seq(none), fee(10), ter(temMALFORMED));
227 env(noop("alice"), fee(none), ter(temMALFORMED));
228 env(noop("alice"), sig(none), ter(temMALFORMED));
229 env(noop("alice"), fee(autofill));
230 env(noop("alice"), fee(autofill), seq(autofill));
231 env(noop("alice"), fee(autofill), seq(autofill), sig(autofill));
232 }
233 }
234
235 // Env::require
236 void
238 {
239 using namespace jtx;
240 Env env(*this);
241 auto const gw = Account("gw");
242 auto const USD = gw["USD"];
243 env.require(balance("alice", none));
244 env.require(balance("alice", XRP(none)));
245 env.fund(XRP(10000), "alice", gw);
246 env.require(balance("alice", USD(none)));
247 env.trust(USD(100), "alice");
248 env.require(balance("alice", XRP(10000))); // fee refunded
249 env.require(balance("alice", USD(0)));
250 env(pay(gw, "alice", USD(10)), require(balance("alice", USD(10))));
251
252 env.require(nflags("alice", asfRequireDest));
253 env(fset("alice", asfRequireDest),
254 require(flags("alice", asfRequireDest)));
255 env(fclear("alice", asfRequireDest),
256 require(nflags("alice", asfRequireDest)));
257 }
258
259 // Signing with secp256k1 and ed25519 keys
260 void
262 {
263 using namespace jtx;
264
265 Env env{*this, supported_amendments() | fixMasterKeyAsRegularKey};
266 Account const alice("alice", KeyType::ed25519);
267 Account const bob("bob", KeyType::secp256k1);
268 Account const carol("carol");
269 env.fund(XRP(10000), alice, bob);
270
271 // Master key only
272 env(noop(alice));
273 env(noop(bob));
274 env(noop(alice), sig("alice"), ter(tefBAD_AUTH));
275 env(noop(alice),
276 sig(Account("alice", KeyType::secp256k1)),
278 env(noop(bob), sig(Account("bob", KeyType::ed25519)), ter(tefBAD_AUTH));
279 env(noop(alice), sig(carol), ter(tefBAD_AUTH));
280
281 // Master and Regular key
282 env(regkey(alice, bob));
283 env(noop(alice));
284 env(noop(alice), sig(bob));
285 env(noop(alice), sig(alice));
286
287 // Regular key only
288 env(fset(alice, asfDisableMaster), sig(alice));
289 env(noop(alice));
290 env(noop(alice), sig(bob));
291 env(noop(alice), sig(alice), ter(tefMASTER_DISABLED));
292 env(fclear(alice, asfDisableMaster),
293 sig(alice),
295 env(fclear(alice, asfDisableMaster), sig(bob));
296 env(noop(alice), sig(alice));
297 }
298
299 // Payment basics
300 void
302 {
303 using namespace jtx;
304 Env env(*this);
305 auto const gw = Account("gateway");
306 auto const USD = gw["USD"];
307
308 env.fund(XRP(10000), "alice", "bob", "carol", gw);
309 env.require(balance("alice", XRP(10000)));
310 env.require(balance("bob", XRP(10000)));
311 env.require(balance("carol", XRP(10000)));
312 env.require(balance(gw, XRP(10000)));
313
314 env(pay(env.master, "alice", XRP(1000)), fee(none), ter(temMALFORMED));
315 env(pay(env.master, "alice", XRP(1000)), fee(1), ter(telINSUF_FEE_P));
316 env(pay(env.master, "alice", XRP(1000)), seq(none), ter(temMALFORMED));
317 env(pay(env.master, "alice", XRP(1000)), seq(20), ter(terPRE_SEQ));
318 env(pay(env.master, "alice", XRP(1000)), sig(none), ter(temMALFORMED));
319 env(pay(env.master, "alice", XRP(1000)), sig("bob"), ter(tefBAD_AUTH));
320
321 env(pay(env.master, "dilbert", XRP(1000)), sig(env.master));
322
323 env.trust(USD(100), "alice", "bob", "carol");
324 env.require(owners("alice", 1), lines("alice", 1));
325 env(rate(gw, 1.05));
326
327 env(pay(gw, "carol", USD(50)));
328 env.require(balance("carol", USD(50)));
329 env.require(balance(gw, Account("carol")["USD"](-50)));
330
331 env(offer("carol", XRP(50), USD(50)), require(owners("carol", 2)));
332 env(pay("alice", "bob", any(USD(10))), ter(tecPATH_DRY));
333 env(pay("alice", "bob", any(USD(10))),
334 paths(XRP),
335 sendmax(XRP(10)),
337 env(pay("alice", "bob", any(USD(10))), paths(XRP), sendmax(XRP(20)));
338 env.require(balance("bob", USD(10)));
339 env.require(balance("carol", USD(39.5)));
340
341 env.memoize("eric");
342 env(regkey("alice", "eric"));
343 env(noop("alice"));
344 env(noop("alice"), sig("alice"));
345 env(noop("alice"), sig("eric"));
346 env(noop("alice"), sig("bob"), ter(tefBAD_AUTH));
348 env(fset("alice", asfDisableMaster),
349 sig("eric"),
351 env.require(nflags("alice", asfDisableMaster));
352 env(fset("alice", asfDisableMaster), sig("alice"));
353 env.require(flags("alice", asfDisableMaster));
354 env(regkey("alice", disabled), ter(tecNO_ALTERNATIVE_KEY));
355 env(noop("alice"));
356 env(noop("alice"), sig("alice"), ter(tefMASTER_DISABLED));
357 env(noop("alice"), sig("eric"));
358 env(noop("alice"), sig("bob"), ter(tefBAD_AUTH));
359 env(fclear("alice", asfDisableMaster), sig("bob"), ter(tefBAD_AUTH));
360 env(fclear("alice", asfDisableMaster),
361 sig("alice"),
363 env(fclear("alice", asfDisableMaster));
364 env.require(nflags("alice", asfDisableMaster));
365 env(regkey("alice", disabled));
366 env(noop("alice"), sig("eric"), ter(tefBAD_AUTH));
367 env(noop("alice"));
368 }
369
370 // Rudimentary test to ensure fail_hard
371 // transactions are neither queued nor
372 // held.
373 void
375 {
376 using namespace jtx;
377 Env env(*this);
378 auto const gw = Account("gateway");
379 auto const USD = gw["USD"];
380
381 auto const alice = Account{"alice"};
382 env.fund(XRP(10000), alice);
383
384 auto const localTxCnt = env.app().getOPs().getLocalTxCount();
385 auto const queueTxCount =
386 env.app().getTxQ().getMetrics(*env.current()).txCount;
387 auto const openTxCount = env.current()->txCount();
388 BEAST_EXPECT(localTxCnt == 2 && queueTxCount == 0 && openTxCount == 2);
389
390 auto applyTxn = [&env](auto&&... txnArgs) {
391 auto jt = env.jt(txnArgs...);
392 Serializer s;
393 jt.stx->add(s);
394
396
397 args[jss::tx_blob] = strHex(s.slice());
398 args[jss::fail_hard] = true;
399
400 return env.rpc("json", "submit", args.toStyledString());
401 };
402
403 auto jr = applyTxn(noop(alice), fee(1));
404
405 BEAST_EXPECT(jr[jss::result][jss::engine_result] == "telINSUF_FEE_P");
406 BEAST_EXPECT(
407 env.app().getTxQ().getMetrics(*env.current()).txCount ==
408 queueTxCount);
409 BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
410 BEAST_EXPECT(env.current()->txCount() == openTxCount);
411
412 jr = applyTxn(noop(alice), sig("bob"));
413
414 BEAST_EXPECT(jr[jss::result][jss::engine_result] == "tefBAD_AUTH");
415 BEAST_EXPECT(
416 env.app().getTxQ().getMetrics(*env.current()).txCount ==
417 queueTxCount);
418 BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
419 BEAST_EXPECT(env.current()->txCount() == openTxCount);
420
421 jr = applyTxn(noop(alice), seq(20));
422
423 BEAST_EXPECT(jr[jss::result][jss::engine_result] == "terPRE_SEQ");
424 BEAST_EXPECT(
425 env.app().getTxQ().getMetrics(*env.current()).txCount ==
426 queueTxCount);
427 BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
428 BEAST_EXPECT(env.current()->txCount() == openTxCount);
429
430 jr = applyTxn(offer(alice, XRP(1000), USD(1000)));
431
432 BEAST_EXPECT(
433 jr[jss::result][jss::engine_result] == "tecUNFUNDED_OFFER");
434 BEAST_EXPECT(
435 env.app().getTxQ().getMetrics(*env.current()).txCount ==
436 queueTxCount);
437 BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
438 BEAST_EXPECT(env.current()->txCount() == openTxCount);
439
440 jr = applyTxn(noop(alice), fee(drops(-10)));
441
442 BEAST_EXPECT(jr[jss::result][jss::engine_result] == "temBAD_FEE");
443 BEAST_EXPECT(
444 env.app().getTxQ().getMetrics(*env.current()).txCount ==
445 queueTxCount);
446 BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt);
447 BEAST_EXPECT(env.current()->txCount() == openTxCount);
448
449 jr = applyTxn(noop(alice));
450
451 BEAST_EXPECT(jr[jss::result][jss::engine_result] == "tesSUCCESS");
452 BEAST_EXPECT(env.app().getOPs().getLocalTxCount() == localTxCnt + 1);
453 BEAST_EXPECT(env.current()->txCount() == openTxCount + 1);
454 }
455
456 // Multi-sign basics
457 void
459 {
460 using namespace jtx;
461
462 Env env(*this);
463 env.fund(XRP(10000), "alice");
464 env(signers("alice", 1, {{"alice", 1}, {"bob", 2}}),
466 env(signers("alice", 1, {{"bob", 1}, {"carol", 2}}));
467 env(noop("alice"));
468
469 auto const baseFee = env.current()->fees().base;
470 env(noop("alice"), msig("bob"), fee(2 * baseFee));
471 env(noop("alice"), msig("carol"), fee(2 * baseFee));
472 env(noop("alice"), msig("bob", "carol"), fee(3 * baseFee));
473 env(noop("alice"),
474 msig("bob", "carol", "dilbert"),
475 fee(4 * baseFee),
477
478 env(signers("alice", none));
479 }
480
481 void
483 {
484 using namespace jtx;
485 // create syntax
486 ticket::create("alice", 1);
487
488 {
489 Env env(*this);
490 env.fund(XRP(10000), "alice");
491 env(noop("alice"),
492 require(owners("alice", 0), tickets("alice", 0)));
493 env(ticket::create("alice", 1),
494 require(owners("alice", 1), tickets("alice", 1)));
495 }
496 }
497
498 struct UDT
499 {
500 };
501
502 void
504 {
505 struct T
506 {
507 };
508 using namespace jtx;
509 JTx jt1;
510 // Test a straightforward
511 // property
512 BEAST_EXPECT(!jt1.get<int>());
513 jt1.set<int>(7);
514 BEAST_EXPECT(jt1.get<int>());
515 BEAST_EXPECT(*jt1.get<int>() == 7);
516 BEAST_EXPECT(!jt1.get<UDT>());
517
518 // Test that the property is
519 // replaced if it exists.
520 jt1.set<int>(17);
521 BEAST_EXPECT(jt1.get<int>());
522 BEAST_EXPECT(*jt1.get<int>() == 17);
523 BEAST_EXPECT(!jt1.get<UDT>());
524
525 // Test that modifying the
526 // returned prop is saved
527 *jt1.get<int>() = 42;
528 BEAST_EXPECT(jt1.get<int>());
529 BEAST_EXPECT(*jt1.get<int>() == 42);
530 BEAST_EXPECT(!jt1.get<UDT>());
531
532 // Test get() const
533 auto const& jt2 = jt1;
534 BEAST_EXPECT(jt2.get<int>());
535 BEAST_EXPECT(*jt2.get<int>() == 42);
536 BEAST_EXPECT(!jt2.get<UDT>());
537 }
538
539 void
541 {
542 using namespace jtx;
543 Env env(*this);
544 env.fund(XRP(100000), "alice");
545 auto jt1 = env.jt(noop("alice"));
546 BEAST_EXPECT(!jt1.get<std::uint16_t>());
547 auto jt2 = env.jt(noop("alice"), prop<std::uint16_t>(-1));
548 BEAST_EXPECT(jt2.get<std::uint16_t>());
549 BEAST_EXPECT(*jt2.get<std::uint16_t>() == 65535);
550 auto jt3 = env.jt(
551 noop("alice"),
552 prop<std::string>("Hello, world!"),
553 prop<bool>(false));
554 BEAST_EXPECT(jt3.get<std::string>());
555 BEAST_EXPECT(*jt3.get<std::string>() == "Hello, world!");
556 BEAST_EXPECT(jt3.get<bool>());
557 BEAST_EXPECT(!*jt3.get<bool>());
558 }
559
560 void
562 {
563 struct T
564 {
565 };
566 using namespace jtx;
567 JTx jt1;
568 jt1.set<int>(7);
569 BEAST_EXPECT(jt1.get<int>());
570 BEAST_EXPECT(*jt1.get<int>() == 7);
571 BEAST_EXPECT(!jt1.get<UDT>());
572 JTx jt2(jt1);
573 BEAST_EXPECT(jt2.get<int>());
574 BEAST_EXPECT(*jt2.get<int>() == 7);
575 BEAST_EXPECT(!jt2.get<UDT>());
576 JTx jt3;
577 jt3 = jt1;
578 BEAST_EXPECT(jt3.get<int>());
579 BEAST_EXPECT(*jt3.get<int>() == 7);
580 BEAST_EXPECT(!jt3.get<UDT>());
581 }
582
583 void
585 {
586 struct T
587 {
588 };
589 using namespace jtx;
590 JTx jt1;
591 jt1.set<int>(7);
592 BEAST_EXPECT(jt1.get<int>());
593 BEAST_EXPECT(*jt1.get<int>() == 7);
594 BEAST_EXPECT(!jt1.get<UDT>());
595 JTx jt2(std::move(jt1));
596 BEAST_EXPECT(!jt1.get<int>());
597 BEAST_EXPECT(!jt1.get<UDT>());
598 BEAST_EXPECT(jt2.get<int>());
599 BEAST_EXPECT(*jt2.get<int>() == 7);
600 BEAST_EXPECT(!jt2.get<UDT>());
601 jt1 = std::move(jt2);
602 BEAST_EXPECT(!jt2.get<int>());
603 BEAST_EXPECT(!jt2.get<UDT>());
604 BEAST_EXPECT(jt1.get<int>());
605 BEAST_EXPECT(*jt1.get<int>() == 7);
606 BEAST_EXPECT(!jt1.get<UDT>());
607 }
608
609 void
611 {
612 using namespace jtx;
613 Env env(*this);
614 env.fund(XRP(10000), "alice");
615 env(noop("alice"), memodata("data"));
616 env(noop("alice"), memoformat("format"));
617 env(noop("alice"), memotype("type"));
618 env(noop("alice"), memondata("format", "type"));
619 env(noop("alice"), memonformat("data", "type"));
620 env(noop("alice"), memontype("data", "format"));
621 env(noop("alice"), memo("data", "format", "type"));
622 env(noop("alice"),
623 memo("data1", "format1", "type1"),
624 memo("data2", "format2", "type2"));
625 }
626
627 void
629 {
630 using namespace jtx;
631 Env env(*this);
632 JTx jt(noop("alice"));
633 memo("data", "format", "type")(env, jt);
634
635 auto const& memo = jt.jv["Memos"][0u]["Memo"];
636 BEAST_EXPECT(
637 memo["MemoData"].asString() == strHex(std::string("data")));
638 BEAST_EXPECT(
639 memo["MemoFormat"].asString() == strHex(std::string("format")));
640 BEAST_EXPECT(
641 memo["MemoType"].asString() == strHex(std::string("type")));
642 }
643
644 void
646 {
647 using namespace jtx;
648 Env env(*this);
649 auto seq = env.current()->seq();
650 BEAST_EXPECT(seq == env.closed()->seq() + 1);
651 env.close();
652 BEAST_EXPECT(env.closed()->seq() == seq);
653 BEAST_EXPECT(env.current()->seq() == seq + 1);
654 env.close();
655 BEAST_EXPECT(env.closed()->seq() == seq + 1);
656 BEAST_EXPECT(env.current()->seq() == seq + 2);
657 }
658
659 void
661 {
662 using namespace jtx;
663 Env env(*this);
664 env.close();
665 env.close();
666 env.fund(XRP(100000), "alice", "bob");
667 env.close();
668 env(pay("alice", "bob", XRP(100)));
669 env.close();
670 env(noop("alice"));
671 env.close();
672 env(noop("bob"));
673 }
674
675 void
677 {
678 using namespace jtx;
679 Env env(*this);
680 auto const gw = Account("gw");
681 auto const USD = gw["USD"];
682 env.fund(XRP(10000), "alice", "bob");
683 env.json(
684 pay("alice", "bob", USD(10)),
685 path(Account("alice")),
686 path("bob"),
687 path(USD),
688 path(~XRP),
689 path(~USD),
690 path("bob", USD, ~XRP, ~USD));
691 }
692
693 // Test that jtx can re-sign a transaction that's already been signed.
694 void
696 {
697 using namespace jtx;
698 Env env(*this);
699
700 env.fund(XRP(10000), "alice");
701 auto const baseFee = env.current()->fees().base;
702 std::uint32_t const aliceSeq = env.seq("alice");
703
704 // Sign jsonNoop.
705 Json::Value jsonNoop =
706 env.json(noop("alice"), fee(baseFee), seq(aliceSeq), sig("alice"));
707 // Re-sign jsonNoop.
708 JTx jt = env.jt(jsonNoop);
709 env(jt);
710 }
711
712 void
714 {
715 using namespace jtx;
716 Env env(*this);
717 Env_ss envs(env);
718
719 auto const alice = Account("alice");
720 env.fund(XRP(10000), alice);
721
722 {
723 envs(noop(alice), fee(none), seq(none))();
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::nullValue);
736 envs(noop(alice), fee(none), seq(none))(params);
737
738 // Make sure we get the right account back.
739 auto tx = env.tx();
740 if (BEAST_EXPECT(tx))
741 {
742 BEAST_EXPECT(tx->getAccountID(sfAccount) == alice.id());
743 BEAST_EXPECT(tx->getTxnType() == ttACCOUNT_SET);
744 }
745 }
746
747 {
748 auto params = Json::Value(Json::objectValue);
749 // Force the factor low enough to fail
750 params[jss::fee_mult_max] = 1;
751 params[jss::fee_div_max] = 2;
752 envs(
753 noop(alice),
754 fee(none),
755 seq(none),
757 "Fee of 10 exceeds the requested tx limit of 5"))(params);
758
759 auto tx = env.tx();
760 BEAST_EXPECT(!tx);
761 }
762 }
763
764 void
766 {
767 testcase("Env features");
768 using namespace jtx;
769 auto const supported = supported_amendments();
770
771 // this finds a feature that is not in
772 // the supported amendments list and tests that it can be
773 // enabled explicitly
774
775 auto const neverSupportedFeat = [&]() -> std::optional<uint256> {
776 auto const n = supported.size();
777 for (size_t i = 0; i < n; ++i)
778 if (!supported[i])
779 return bitsetIndexToFeature(i);
780
781 return std::nullopt;
782 }();
783
784 if (!neverSupportedFeat)
785 {
786 log << "No unsupported features found - skipping test."
787 << std::endl;
788 pass();
789 return;
790 }
791
792 auto hasFeature = [](Env& env, uint256 const& f) {
793 return (
794 env.app().config().features.find(f) !=
795 env.app().config().features.end());
796 };
797
798 {
799 // default Env has all supported features
800 Env env{*this};
801 BEAST_EXPECT(
802 supported.count() == env.app().config().features.size());
803 foreachFeature(supported, [&](uint256 const& f) {
804 this->BEAST_EXPECT(hasFeature(env, f));
805 });
806 }
807
808 {
809 // a Env FeatureBitset has *only* those features
810 Env env{*this, FeatureBitset(featureMultiSignReserve, featureFlow)};
811 BEAST_EXPECT(env.app().config().features.size() == 2);
812 foreachFeature(supported, [&](uint256 const& f) {
813 bool const has =
814 (f == featureMultiSignReserve || f == featureFlow);
815 this->BEAST_EXPECT(has == hasFeature(env, f));
816 });
817 }
818
819 auto const missingSomeFeatures =
820 supported_amendments() - featureMultiSignReserve - featureFlow;
821 BEAST_EXPECT(missingSomeFeatures.count() == (supported.count() - 2));
822 {
823 // a Env supported_features_except is missing *only* those features
824 Env env{*this, missingSomeFeatures};
825 BEAST_EXPECT(
826 env.app().config().features.size() == (supported.count() - 2));
827 foreachFeature(supported, [&](uint256 const& f) {
828 bool hasnot =
829 (f == featureMultiSignReserve || f == featureFlow);
830 this->BEAST_EXPECT(hasnot != hasFeature(env, f));
831 });
832 }
833
834 {
835 // add a feature that is NOT in the supported amendments list
836 // along with a list of explicit amendments
837 // the unsupported feature should be enabled along with
838 // the two supported ones
839 Env env{
840 *this,
842 featureMultiSignReserve, featureFlow, *neverSupportedFeat)};
843
844 // this app will have just 2 supported amendments and
845 // one additional never supported feature flag
846 BEAST_EXPECT(env.app().config().features.size() == (2 + 1));
847 BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
848
849 foreachFeature(supported, [&](uint256 const& f) {
850 bool has = (f == featureMultiSignReserve || f == featureFlow);
851 this->BEAST_EXPECT(has == hasFeature(env, f));
852 });
853 }
854
855 {
856 // add a feature that is NOT in the supported amendments list
857 // and omit a few standard amendments
858 // the unsupported features should be enabled
859 Env env{
860 *this,
861 missingSomeFeatures | FeatureBitset{*neverSupportedFeat}};
862
863 // this app will have all supported amendments minus 2 and then the
864 // one additional never supported feature flag
865 BEAST_EXPECT(
866 env.app().config().features.size() ==
867 (supported.count() - 2 + 1));
868 BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
869 foreachFeature(supported, [&](uint256 const& f) {
870 bool hasnot =
871 (f == featureMultiSignReserve || f == featureFlow);
872 this->BEAST_EXPECT(hasnot != hasFeature(env, f));
873 });
874 }
875
876 {
877 // add a feature that is NOT in the supported amendments list
878 // along with all supported amendments
879 // the unsupported features should be enabled
880 Env env{*this, supported_amendments().set(*neverSupportedFeat)};
881
882 // this app will have all supported amendments and then the
883 // one additional never supported feature flag
884 BEAST_EXPECT(
885 env.app().config().features.size() == (supported.count() + 1));
886 BEAST_EXPECT(hasFeature(env, *neverSupportedFeat));
887 foreachFeature(supported, [&](uint256 const& f) {
888 this->BEAST_EXPECT(hasFeature(env, f));
889 });
890 }
891 }
892
893 void
895 {
896 except([this] {
897 jtx::Env env{
898 *this,
900 (*cfg).deprecatedClearSection("port_rpc");
901 return cfg;
902 }),
903 nullptr,
905 });
906 pass();
907 }
908
909 void
910 run() override
911 {
912 testAccount();
913 testAmount();
914 testEnv();
915 testRequire();
916 testKeyType();
917 testPayments();
918 testFailHard();
920 testTicket();
922 testProp();
923 testJTxCopy();
924 testJTxMove();
925 testMemo();
927 testAdvance();
928 testClose();
929 testPath();
932 testFeatures();
934 }
935};
936
937BEAST_DEFINE_TESTSUITE(Env, app, ripple);
938
939} // namespace test
940} // 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:1778
static std::string to_string(T const &t)
Definition: Env_test.cpp:44
void testExceptionalShutdown()
Definition: Env_test.cpp:894
void run() override
Runs the suite.
Definition: Env_test.cpp:910
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:120
Json::Value json(JsonValue &&jv, FN const &... fN)
Create JSON from parameters.
Definition: Env.h:519
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
Definition: Env.cpp:111
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:212
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:532
std::shared_ptr< STTx const > tx() const
Return the tx data for the last JTx.
Definition: Env.cpp:455
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:328
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:117
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition: Env.cpp:264
Account const & master
Definition: Env.h:124
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition: Env.h:493
Application & app()
Definition: Env.h:258
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:767
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:233
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition: Env.cpp:179
void memoize(Account const &account)
Associate AccountID with account.
Definition: Env.cpp:152
A balance matches.
Definition: balance.h:39
Set the fee on a JTx.
Definition: fee.h:37
Match set account flags.
Definition: flags.h:113
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:130
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 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: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
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Definition: rate.cpp:32
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: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
FeatureBitset supported_amendments()
Definition: Env.h:73
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: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