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