20 #include <ripple/app/misc/Manifest.h>
21 #include <ripple/app/misc/TxQ.h>
22 #include <ripple/basics/StringUtilities.h>
23 #include <ripple/beast/unit_test.h>
24 #include <ripple/protocol/ErrorCodes.h>
25 #include <ripple/protocol/jss.h>
38 if (BEAST_EXPECT(jv.
isMember(jss::status)))
39 BEAST_EXPECT(jv[jss::status] ==
"error");
40 if (BEAST_EXPECT(jv.
isMember(jss::error)))
41 BEAST_EXPECT(jv[jss::error] == err);
46 jv[jss::error_message] ==
"");
48 else if (BEAST_EXPECT(jv.
isMember(jss::error_message)))
49 BEAST_EXPECT(jv[jss::error_message] == msg);
65 testcase(
"Basic Request");
66 using namespace test::jtx;
71 BEAST_EXPECT(env.current()->info().seq == 4);
76 jvParams[jss::ledger_index] = 1;
78 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
79 BEAST_EXPECT(jrr[jss::ledger][jss::closed] ==
true);
80 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"1");
85 jvParams[jss::ledger_index] =
"1";
87 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
88 BEAST_EXPECT(jrr[jss::ledger][jss::closed] ==
true);
89 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"1");
94 auto const jrr = env.rpc(
"ledger",
"current")[jss::result];
95 BEAST_EXPECT(jrr[jss::ledger][jss::closed] ==
false);
97 jrr[jss::ledger][jss::ledger_index] ==
100 jrr[jss::ledger_current_index] == env.current()->info().seq);
107 testcase(
"Bad Input");
108 using namespace test::jtx;
110 Account
const gw{
"gateway"};
111 auto const USD = gw[
"USD"];
112 Account
const bob{
"bob"};
114 env.fund(XRP(10000), gw, bob);
116 env.trust(USD(1000), bob);
122 jvParams[jss::ledger_index] =
"potato";
124 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
131 jvParams[jss::ledger_index] = -1;
133 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
140 jvParams[jss::ledger_index] = 10u;
142 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
148 auto const jrr = env.rpc(
"ledger",
"arbitrary_text")[jss::result];
155 jvParams[jss::ledger_index] =
"validated";
156 jvParams[jss::queue] =
true;
158 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
165 env.rpc(
"json",
"ledger",
"{ \"ledger_index\" : 2e15 }");
167 BEAST_EXPECT(ret[jss::error_message] ==
"Invalid parameters.");
172 auto const ret = env.rpc(
173 "json",
"ledger",
"{ \"ledger_index\" : 1000000000000000 }");
181 testcase(
"ledger_current Request");
182 using namespace test::jtx;
187 BEAST_EXPECT(env.current()->info().seq == 4);
190 auto const jrr = env.rpc(
"ledger_current")[jss::result];
192 jrr[jss::ledger_current_index] == env.current()->info().seq);
199 testcase(
"Missing ledger_entry ledger_hash");
200 using namespace test::jtx;
202 Account
const alice{
"alice"};
203 env.fund(XRP(10000), alice);
207 jvParams[jss::account_root] = alice.human();
208 jvParams[jss::ledger_hash] =
209 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
211 env.rpc(
"json",
"ledger_entry",
to_string(jvParams))[jss::result];
218 testcase(
"Ledger Request, Full Option");
219 using namespace test::jtx;
226 jvParams[jss::ledger_index] = 3u;
227 jvParams[jss::full] =
true;
229 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
230 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
231 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
232 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 3u);
238 testcase(
"Ledger Request, Full Option Without Admin");
239 using namespace test::jtx;
241 Env env{*
this, envconfig(no_admin)};
246 jvParams[jss::ledger_index] = 1u;
247 jvParams[jss::full] =
true;
249 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
251 jrr,
"noPermission",
"You don't have permission for this command.");
257 testcase(
"Ledger Request, Accounts Option");
258 using namespace test::jtx;
265 jvParams[jss::ledger_index] = 3u;
266 jvParams[jss::accounts] =
true;
268 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
269 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
270 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
271 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 3u);
277 testcase(
"ledger_entry Request AccountRoot");
278 using namespace test::jtx;
280 Account
const alice{
"alice"};
281 env.fund(XRP(10000), alice);
287 Json::Value const jrr = env.rpc(
"ledger_closed")[jss::result];
288 BEAST_EXPECT(jrr[jss::ledger_hash] == ledgerHash);
289 BEAST_EXPECT(jrr[jss::ledger_index] == 3);
296 jvParams[jss::account_root] = alice.human();
297 jvParams[jss::ledger_hash] = ledgerHash;
299 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
300 BEAST_EXPECT(jrr.
isMember(jss::node));
301 BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
303 accountRootIndex = jrr[jss::index].
asString();
306 constexpr
char alicesAcctRootBinary[]{
307 "1100612200800000240000000425000000032D00000000559CE54C3B934E4"
308 "73A995B477E92EC229F99CED5B62BF4D2ACE4DC42719103AE2F6240000002"
309 "540BE4008114AE123A8556F3CF91154711376AFB0F894F832B3D"};
313 jvParams[jss::account_root] = alice.human();
314 jvParams[jss::binary] = 1;
315 jvParams[jss::ledger_hash] = ledgerHash;
317 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
318 BEAST_EXPECT(jrr.
isMember(jss::node_binary));
319 BEAST_EXPECT(jrr[jss::node_binary] == alicesAcctRootBinary);
324 jvParams[jss::index] = accountRootIndex;
326 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
327 BEAST_EXPECT(!jrr.
isMember(jss::node_binary));
328 BEAST_EXPECT(jrr.
isMember(jss::node));
329 BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
335 jvParams[jss::index] = accountRootIndex;
336 jvParams[jss::binary] = 0;
338 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
339 BEAST_EXPECT(jrr.
isMember(jss::node));
340 BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
347 jvParams[jss::ledger_hash] = ledgerHash;
349 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
355 jvParams[jss::account_root] = Account(
"bob").human();
356 jvParams[jss::ledger_hash] = ledgerHash;
358 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
366 testcase(
"ledger_entry Request Check");
367 using namespace test::jtx;
369 Account
const alice{
"alice"};
370 env.fund(XRP(10000), alice);
373 auto const checkId =
keylet::check(env.master, env.seq(env.master));
375 env(check::create(env.master, alice, XRP(100)));
382 jvParams[jss::check] =
to_string(checkId.key);
383 jvParams[jss::ledger_hash] = ledgerHash;
385 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
396 jvParams[jss::account_root] = alice.human();
398 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
399 accountRootIndex = jrr[jss::index].
asString();
402 jvParams[jss::check] = accountRootIndex;
403 jvParams[jss::ledger_hash] = ledgerHash;
405 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
413 testcase(
"ledger_entry Deposit Preauth");
415 using namespace test::jtx;
418 Account
const alice{
"alice"};
419 Account
const becky{
"becky"};
421 env.fund(XRP(10000), alice, becky);
424 env(deposit::auth(alice, becky));
432 jvParams[jss::deposit_preauth][jss::owner] = alice.human();
433 jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
434 jvParams[jss::ledger_hash] = ledgerHash;
436 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
440 jss::DepositPreauth);
443 depositPreauthIndex = jrr[jss::node][jss::index].
asString();
448 jvParams[jss::deposit_preauth] = depositPreauthIndex;
449 jvParams[jss::ledger_hash] = ledgerHash;
451 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
455 jss::DepositPreauth);
462 jvParams[jss::deposit_preauth] = -5;
463 jvParams[jss::ledger_hash] = ledgerHash;
465 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
471 jvParams[jss::deposit_preauth] =
"0123456789ABCDEFG";
472 jvParams[jss::ledger_hash] = ledgerHash;
474 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
480 jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
481 jvParams[jss::ledger_hash] = ledgerHash;
483 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
489 jvParams[jss::deposit_preauth][jss::owner] = 7;
490 jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
491 jvParams[jss::ledger_hash] = ledgerHash;
493 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
499 jvParams[jss::deposit_preauth][jss::owner] = alice.human();
500 jvParams[jss::ledger_hash] = ledgerHash;
502 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
508 jvParams[jss::deposit_preauth][jss::owner] = alice.human();
509 jvParams[jss::deposit_preauth][jss::authorized] = 47;
510 jvParams[jss::ledger_hash] = ledgerHash;
512 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
518 jvParams[jss::deposit_preauth][jss::owner] =
519 "rP6P9ypfAmc!pw8SZHNwM4nvZHFXDraQas";
521 jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
522 jvParams[jss::ledger_hash] = ledgerHash;
524 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
530 jvParams[jss::deposit_preauth][jss::owner] = alice.human();
531 jvParams[jss::deposit_preauth][jss::authorized] =
532 "rP6P9ypfAmc!pw8SZHNwM4nvZHFXDraQas";
534 jvParams[jss::ledger_hash] = ledgerHash;
536 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
544 testcase(
"ledger_entry Request Directory");
545 using namespace test::jtx;
547 Account
const alice{
"alice"};
548 Account
const gw{
"gateway"};
549 auto const USD = gw[
"USD"];
550 env.fund(XRP(10000), alice, gw);
553 env.trust(USD(1000), alice);
558 for (
int d = 1
'000'032; d >= 1
'000'000; --d)
560 env(offer(alice, USD(1), drops(d)));
567 Json::Value const jrr = env.rpc(
"ledger_closed")[jss::result];
568 BEAST_EXPECT(jrr[jss::ledger_hash] == ledgerHash);
569 BEAST_EXPECT(jrr[jss::ledger_index] == 5);
573 "A33EC6BB85FB5674074C4A3A43373BB17645308F3EAE1933E3E35252162B217D";
577 jvParams[jss::directory] = dirRootIndex;
578 jvParams[jss::ledger_hash] = ledgerHash;
580 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
587 jvParams[jss::directory][jss::dir_root] = dirRootIndex;
589 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
590 BEAST_EXPECT(jrr[jss::index] == dirRootIndex);
596 jvParams[jss::directory][jss::owner] = alice.human();
597 jvParams[jss::ledger_hash] = ledgerHash;
599 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
600 BEAST_EXPECT(jrr[jss::index] == dirRootIndex);
606 jvParams[jss::directory][jss::dir_root] = dirRootIndex;
607 jvParams[jss::directory][jss::sub_index] = 1;
609 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
610 BEAST_EXPECT(jrr[jss::index] != dirRootIndex);
617 jvParams[jss::directory][jss::owner] = alice.human();
618 jvParams[jss::directory][jss::sub_index] = 1;
619 jvParams[jss::ledger_hash] = ledgerHash;
621 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
622 BEAST_EXPECT(jrr[jss::index] != dirRootIndex);
629 jvParams[jss::ledger_hash] = ledgerHash;
631 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
638 jvParams[jss::directory][jss::dir_root] = dirRootIndex;
639 jvParams[jss::directory][jss::sub_index] = 1.5;
640 jvParams[jss::ledger_hash] = ledgerHash;
642 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
651 jvParams[jss::directory][jss::owner] = badAddress;
652 jvParams[jss::ledger_hash] = ledgerHash;
654 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
661 jvParams[jss::directory][jss::owner] = alice.human();
662 jvParams[jss::directory][jss::dir_root] = dirRootIndex;
663 jvParams[jss::ledger_hash] = ledgerHash;
665 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
672 jvParams[jss::directory][jss::sub_index] = 1;
673 jvParams[jss::ledger_hash] = ledgerHash;
675 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
683 testcase(
"ledger_entry Request Escrow");
684 using namespace test::jtx;
686 Account
const alice{
"alice"};
687 env.fund(XRP(10000), alice);
696 jv[jss::TransactionType] = jss::EscrowCreate;
698 jv[jss::Account] = account.human();
699 jv[jss::Destination] = to.human();
702 cancelAfter.time_since_epoch().count() + 2;
706 using namespace std::chrono_literals;
707 env(escrowCreate(alice, alice, XRP(333), env.now() + 2s));
716 jvParams[jss::escrow][jss::owner] = alice.human();
717 jvParams[jss::escrow][jss::seq] = env.seq(alice) - 1;
719 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
721 jrr[jss::node][jss::Amount] == XRP(333).value().getText());
722 escrowIndex = jrr[jss::index].
asString();
727 jvParams[jss::escrow] = escrowIndex;
728 jvParams[jss::ledger_hash] = ledgerHash;
730 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
732 jrr[jss::node][jss::Amount] == XRP(333).value().getText());
740 jvParams[jss::escrow][jss::owner] = badAddress;
741 jvParams[jss::escrow][jss::seq] = env.seq(alice) - 1;
742 jvParams[jss::ledger_hash] = ledgerHash;
744 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
751 jvParams[jss::escrow][jss::seq] = env.seq(alice) - 1;
752 jvParams[jss::ledger_hash] = ledgerHash;
754 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
761 jvParams[jss::escrow][jss::owner] = alice.human();
762 jvParams[jss::ledger_hash] = ledgerHash;
764 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
771 jvParams[jss::escrow][jss::owner] = alice.human();
772 jvParams[jss::escrow][jss::seq] =
774 jvParams[jss::ledger_hash] = ledgerHash;
776 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
784 testcase(
"ledger_entry Request Offer");
785 using namespace test::jtx;
787 Account
const alice{
"alice"};
788 Account
const gw{
"gateway"};
789 auto const USD = gw[
"USD"];
790 env.fund(XRP(10000), alice, gw);
793 env(offer(alice, USD(321), XRP(322)));
802 jvParams[jss::offer][jss::account] = alice.human();
803 jvParams[jss::offer][jss::seq] = env.seq(alice) - 1;
804 jvParams[jss::ledger_hash] = ledgerHash;
806 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
807 BEAST_EXPECT(jrr[jss::node][jss::TakerGets] ==
"322000000");
808 offerIndex = jrr[jss::index].
asString();
813 jvParams[jss::offer] = offerIndex;
815 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
816 BEAST_EXPECT(jrr[jss::node][jss::TakerGets] ==
"322000000");
824 jvParams[jss::offer][jss::account] = badAddress;
825 jvParams[jss::offer][jss::seq] = env.seq(alice) - 1;
826 jvParams[jss::ledger_hash] = ledgerHash;
828 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
835 jvParams[jss::offer][jss::seq] = env.seq(alice) - 1;
836 jvParams[jss::ledger_hash] = ledgerHash;
838 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
845 jvParams[jss::offer][jss::account] = alice.human();
846 jvParams[jss::ledger_hash] = ledgerHash;
848 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
855 jvParams[jss::offer][jss::account] = alice.human();
856 jvParams[jss::offer][jss::seq] =
std::to_string(env.seq(alice) - 1);
857 jvParams[jss::ledger_hash] = ledgerHash;
859 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
867 testcase(
"ledger_entry Request Pay Chan");
868 using namespace test::jtx;
869 using namespace std::literals::chrono_literals;
871 Account
const alice{
"alice"};
873 env.fund(XRP(10000), alice);
883 jv[jss::TransactionType] = jss::PaymentChannelCreate;
884 jv[jss::Account] = account.human();
885 jv[jss::Destination] = to.human();
892 env(payChanCreate(alice, env.master, XRP(57), 18s, alice.pk()));
902 jvParams[jss::payment_channel] =
to_string(payChanIndex);
903 jvParams[jss::ledger_hash] = ledgerHash;
905 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
913 jvParams[jss::payment_channel] = ledgerHash;
914 jvParams[jss::ledger_hash] = ledgerHash;
916 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
924 testcase(
"ledger_entry Request RippleState");
925 using namespace test::jtx;
927 Account
const alice{
"alice"};
928 Account
const gw{
"gateway"};
929 auto const USD = gw[
"USD"];
930 env.fund(XRP(10000), alice, gw);
933 env.trust(USD(999), alice);
936 env(pay(gw, alice, USD(97)));
945 jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
946 jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
947 jvParams[jss::ripple_state][jss::currency] =
"USD";
948 jvParams[jss::ledger_hash] = ledgerHash;
950 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
959 jvParams[jss::ripple_state] =
"ripple_state";
960 jvParams[jss::ledger_hash] = ledgerHash;
962 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
970 jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
971 jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
972 jvParams[jss::ledger_hash] = ledgerHash;
974 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
981 jvParams[jss::ripple_state][jss::accounts] = 2;
982 jvParams[jss::ripple_state][jss::currency] =
"USD";
983 jvParams[jss::ledger_hash] = ledgerHash;
985 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
993 jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
994 jvParams[jss::ripple_state][jss::currency] =
"USD";
995 jvParams[jss::ledger_hash] = ledgerHash;
997 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1005 jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1006 jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1007 jvParams[jss::ripple_state][jss::accounts][2u] = alice.human();
1008 jvParams[jss::ripple_state][jss::currency] =
"USD";
1009 jvParams[jss::ledger_hash] = ledgerHash;
1011 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1019 jvParams[jss::ripple_state][jss::accounts][0u] = 44;
1020 jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1021 jvParams[jss::ripple_state][jss::currency] =
"USD";
1022 jvParams[jss::ledger_hash] = ledgerHash;
1024 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1032 jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1033 jvParams[jss::ripple_state][jss::accounts][1u] = 21;
1034 jvParams[jss::ripple_state][jss::currency] =
"USD";
1035 jvParams[jss::ledger_hash] = ledgerHash;
1037 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1045 jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1046 jvParams[jss::ripple_state][jss::accounts][1u] = alice.human();
1047 jvParams[jss::ripple_state][jss::currency] =
"USD";
1048 jvParams[jss::ledger_hash] = ledgerHash;
1050 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1058 jvParams[jss::ripple_state][jss::accounts][0u] =
1060 jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1061 jvParams[jss::ripple_state][jss::currency] =
"USD";
1062 jvParams[jss::ledger_hash] = ledgerHash;
1064 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1072 jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1073 jvParams[jss::ripple_state][jss::accounts][1u] =
1075 jvParams[jss::ripple_state][jss::currency] =
"USD";
1076 jvParams[jss::ledger_hash] = ledgerHash;
1078 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1086 jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1087 jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1088 jvParams[jss::ripple_state][jss::currency] =
"USDollars";
1089 jvParams[jss::ledger_hash] = ledgerHash;
1091 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1099 testcase(
"ledger_entry Request Ticket");
1100 using namespace test::jtx;
1106 env(ticket::create(env.master, 2));
1116 jvParams[jss::ticket] =
1118 jvParams[jss::ledger_hash] = ledgerHash;
1120 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1127 jvParams[jss::ledger_hash] = ledgerHash;
1129 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1138 jvParams[jss::ticket][jss::account] = env.master.human();
1139 jvParams[jss::ticket][jss::ticket_seq] = tkt1 + 1;
1140 jvParams[jss::ledger_hash] = ledgerHash;
1142 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1144 jrr[jss::node][jss::index] ==
1151 jvParams[jss::ticket][jss::account] = env.master.human();
1152 jvParams[jss::ticket][jss::ticket_seq] = tkt1 + 2;
1153 jvParams[jss::ledger_hash] = ledgerHash;
1155 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1162 jvParams[jss::ledger_hash] = ledgerHash;
1164 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1173 jvParams[jss::ticket][jss::account] = badAddress;
1174 jvParams[jss::ticket][jss::ticket_seq] = env.seq(env.master) - 1;
1175 jvParams[jss::ledger_hash] = ledgerHash;
1177 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1184 jvParams[jss::ticket][jss::ticket_seq] = env.seq(env.master) - 1;
1185 jvParams[jss::ledger_hash] = ledgerHash;
1187 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1194 jvParams[jss::ticket][jss::account] = env.master.human();
1195 jvParams[jss::ledger_hash] = ledgerHash;
1197 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1204 jvParams[jss::ticket][jss::account] = env.master.human();
1205 jvParams[jss::ticket][jss::ticket_seq] =
1207 jvParams[jss::ledger_hash] = ledgerHash;
1209 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1218 "ledger_entry Request With Invalid Parameters v" +
1220 using namespace test::jtx;
1227 params[jss::api_version] = apiVersion;
1233 auto const jvParams =
1235 jvParams[jss::features] = ledgerHash;
1236 jvParams[jss::ledger_hash] = ledgerHash;
1239 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1241 if (apiVersion < 2u)
1248 obj[jss::account] =
"rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
1249 obj[jss::ledger_index] =
"validated";
1254 arr[0u] =
"rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
1255 arr[1u] =
"validated";
1261 for (
auto const& field :
1262 {jss::directory, jss::escrow, jss::offer, jss::ticket, jss::amm})
1264 auto const jvParams =
1265 makeParams([&field, &injectArray](
Json::Value& jvParams) {
1266 jvParams[field] = injectArray;
1270 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1272 if (apiVersion < 2u)
1278 for (
auto const& field :
1279 {jss::directory, jss::escrow, jss::offer, jss::ticket, jss::amm})
1281 auto const jvParams =
1282 makeParams([&field, &injectObject](
Json::Value& jvParams) {
1283 jvParams[field] = injectObject;
1287 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1292 for (
auto const& inject : {injectObject, injectArray})
1295 for (
auto const& field :
1299 jss::payment_channel})
1301 auto const jvParams =
1302 makeParams([&field, &inject](
Json::Value& jvParams) {
1303 jvParams[field] = inject;
1307 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1309 if (apiVersion < 2u)
1315 for (
auto const& field : {jss::dir_root, jss::owner})
1317 auto const jvParams =
1318 makeParams([&field, &inject](
Json::Value& jvParams) {
1319 jvParams[jss::directory][field] = inject;
1323 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1325 if (apiVersion < 2u)
1332 auto const jvParams =
1334 jvParams[jss::escrow][jss::owner] = inject;
1335 jvParams[jss::escrow][jss::seq] = 99;
1339 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1341 if (apiVersion < 2u)
1348 auto const jvParams =
1350 jvParams[jss::offer][jss::account] = inject;
1351 jvParams[jss::offer][jss::seq] = 99;
1355 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1357 if (apiVersion < 2u)
1364 auto const jvParams =
1367 rs[jss::currency] =
"FOO";
1369 rs[jss::accounts][0u] =
1370 "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
1371 rs[jss::accounts][1u] =
1372 "rKssEq6pg1KbqEqAFnua5mFAL6Ggpsh2wv";
1373 rs[jss::currency] = inject;
1374 jvParams[jss::ripple_state] = std::move(rs);
1378 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1380 if (apiVersion < 2u)
1387 auto const jvParams =
1389 jvParams[jss::ticket][jss::account] = inject;
1390 jvParams[jss::ticket][jss::ticket_seq] = 99;
1394 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1396 if (apiVersion < 2u)
1403 for (
auto const& field : {jss::nft_page, jss::deposit_preauth})
1405 auto const jvParams =
1406 makeParams([&field, &inject](
Json::Value& jvParams) {
1407 jvParams[field] = inject;
1411 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1417 for (
auto const& field : {jss::owner, jss::authorized})
1419 auto const jvParams =
1420 makeParams([&field, &inject](
Json::Value& jvParams) {
1422 pa[jss::owner] =
"rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
1423 pa[jss::authorized] =
1424 "rKssEq6pg1KbqEqAFnua5mFAL6Ggpsh2wv";
1426 jvParams[jss::deposit_preauth] = std::move(pa);
1430 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
1444 testcase(
"Lookup ledger");
1445 using namespace test::jtx;
1448 env.fund(XRP(10000),
"alice");
1450 env.fund(XRP(10000),
"bob");
1452 env.fund(XRP(10000),
"jim");
1454 env.fund(XRP(10000),
"jill");
1459 jvParams[jss::ledger] =
"closed";
1463 boost::lexical_cast<std::string>(jvParams))[jss::result];
1464 BEAST_EXPECT(jrr.isMember(jss::ledger));
1465 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1466 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"5");
1468 jvParams[jss::ledger] =
"validated";
1472 boost::lexical_cast<std::string>(jvParams))[jss::result];
1473 BEAST_EXPECT(jrr.isMember(jss::ledger));
1474 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1475 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"5");
1477 jvParams[jss::ledger] =
"current";
1481 boost::lexical_cast<std::string>(jvParams))[jss::result];
1482 BEAST_EXPECT(jrr.isMember(jss::ledger));
1483 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"6");
1486 jvParams[jss::ledger] =
"invalid";
1490 boost::lexical_cast<std::string>(jvParams))[jss::result];
1491 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1492 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerIndexMalformed");
1495 jvParams[jss::ledger] = 4;
1499 boost::lexical_cast<std::string>(jvParams))[jss::result];
1500 BEAST_EXPECT(jrr.isMember(jss::ledger));
1501 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1502 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"4");
1505 jvParams[jss::ledger] = 20;
1509 boost::lexical_cast<std::string>(jvParams))[jss::result];
1510 BEAST_EXPECT(jrr[jss::error] ==
"lgrNotFound");
1511 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerNotFound");
1516 "E86DE7F3D7A4D9CE17EF7C8BA08A8F4D"
1517 "8F643B9552F0D895A31CDA78F541DE4E"};
1520 jvParams[jss::ledger_hash] = hash3;
1524 boost::lexical_cast<std::string>(jvParams))[jss::result];
1525 BEAST_EXPECT(jrr.isMember(jss::ledger));
1526 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1527 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"3");
1530 jvParams[jss::ledger_hash] =
"DEADBEEF" + hash3;
1534 boost::lexical_cast<std::string>(jvParams))[jss::result];
1535 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1536 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerHashMalformed");
1539 jvParams[jss::ledger_hash] = 2;
1543 boost::lexical_cast<std::string>(jvParams))[jss::result];
1544 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1545 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerHashNotString");
1548 jvParams[jss::ledger_hash] =
1549 "2E81FC6EC0DD943197EGC7E3FBE9AE30"
1550 "7F2775F2F7485BB37307984C3C0F2340";
1554 boost::lexical_cast<std::string>(jvParams))[jss::result];
1555 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1556 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerHashMalformed");
1559 jvParams[jss::ledger_hash] =
1560 "8C3EEDB3124D92E49E75D81A8826A2E6"
1561 "5A75FD71FC3FD6F36FEB803C5F1D812D";
1565 boost::lexical_cast<std::string>(jvParams))[jss::result];
1566 BEAST_EXPECT(jrr[jss::error] ==
"lgrNotFound");
1567 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerNotFound");
1573 jvParams[jss::ledger_index] =
"closed";
1577 boost::lexical_cast<std::string>(jvParams))[jss::result];
1578 BEAST_EXPECT(jrr.isMember(jss::ledger));
1579 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1580 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"5");
1581 BEAST_EXPECT(jrr.isMember(jss::ledger_index));
1583 jvParams[jss::ledger_index] =
"validated";
1587 boost::lexical_cast<std::string>(jvParams))[jss::result];
1588 BEAST_EXPECT(jrr.isMember(jss::ledger));
1589 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1590 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"5");
1592 jvParams[jss::ledger_index] =
"current";
1596 boost::lexical_cast<std::string>(jvParams))[jss::result];
1597 BEAST_EXPECT(jrr.isMember(jss::ledger));
1598 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"6");
1599 BEAST_EXPECT(jrr.isMember(jss::ledger_current_index));
1602 jvParams[jss::ledger_index] =
"invalid";
1606 boost::lexical_cast<std::string>(jvParams))[jss::result];
1607 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1608 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerIndexMalformed");
1611 for (
auto i : {1, 2, 3, 4, 5, 6})
1613 jvParams[jss::ledger_index] = i;
1617 boost::lexical_cast<std::string>(jvParams))[jss::result];
1618 BEAST_EXPECT(jrr.isMember(jss::ledger));
1620 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1626 jvParams[jss::ledger_index] = 7;
1630 boost::lexical_cast<std::string>(jvParams))[jss::result];
1631 BEAST_EXPECT(jrr[jss::error] ==
"lgrNotFound");
1632 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerNotFound");
1639 testcase(
"Ledger with queueing disabled");
1640 using namespace test::jtx;
1644 jv[jss::ledger_index] =
"current";
1645 jv[jss::queue] =
true;
1646 jv[jss::expand] =
true;
1648 auto jrr = env.rpc(
"json",
"ledger",
to_string(jv))[jss::result];
1649 BEAST_EXPECT(!jrr.isMember(jss::queue_data));
1655 testcase(
"Ledger with Queued Transactions");
1656 using namespace test::jtx;
1658 auto& section = cfg->section(
"transaction_queue");
1659 section.set(
"minimum_txn_in_ledger_standalone",
"3");
1660 section.set(
"normal_consensus_increase_percent",
"0");
1665 jv[jss::ledger_index] =
"current";
1666 jv[jss::queue] =
true;
1667 jv[jss::expand] =
true;
1669 Account
const alice{
"alice"};
1670 Account
const bob{
"bob"};
1671 Account
const charlie{
"charlie"};
1672 Account
const daria{
"daria"};
1673 env.fund(XRP(10000), alice);
1674 env.fund(XRP(10000), bob);
1676 env.fund(XRP(10000), charlie);
1677 env.fund(XRP(10000), daria);
1680 auto jrr = env.rpc(
"json",
"ledger",
to_string(jv))[jss::result];
1681 BEAST_EXPECT(!jrr.isMember(jss::queue_data));
1686 auto metrics = env.app().getTxQ().getMetrics(*env.current());
1687 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
1692 BEAST_EXPECT(env.current()->info().seq == 5);
1695 auto aliceSeq = env.seq(alice);
1696 env(pay(alice,
"george", XRP(1000)),
1697 json(R
"({"LastLedgerSequence":7})"),
1699 env(offer(alice, XRP(50000), alice["USD"](5000)),
1702 env(noop(alice), seq(aliceSeq + 2), ter(
terQUEUED));
1704 auto batch = [&env](Account a) {
1705 auto aSeq = env.seq(a);
1707 for (
int i = 0; i < 10; ++i)
1709 env(noop(a), fee(1000 + i), seq(aSeq + i), ter(
terQUEUED));
1718 jrr = env.rpc(
"json",
"ledger",
to_string(jv))[jss::result];
1719 BEAST_EXPECT(jrr[jss::queue_data].size() == 33);
1725 BEAST_EXPECT(env.current()->info().seq == 8);
1727 jrr = env.rpc(
"json",
"ledger",
to_string(jv))[jss::result];
1728 BEAST_EXPECT(jrr[jss::queue_data].size() == 11);
1732 jrr = env.rpc(
"json",
"ledger",
to_string(jv))[jss::result];
1734 auto const& parentHash = env.current()->info().parentHash;
1735 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
1738 auto const& txj = jrr[jss::queue_data][1u];
1739 BEAST_EXPECT(txj[jss::account] == alice.human());
1740 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
1741 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
1742 BEAST_EXPECT(txj[
"retries_remaining"] == 10);
1743 BEAST_EXPECT(txj.isMember(jss::tx));
1744 auto const& tx = txj[jss::tx];
1745 BEAST_EXPECT(tx[jss::Account] == alice.human());
1746 BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
1747 return tx[jss::hash].asString();
1750 auto const& txj = jrr[jss::queue_data][0u];
1751 BEAST_EXPECT(txj[jss::account] == alice.human());
1752 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
1753 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
1754 BEAST_EXPECT(txj[
"retries_remaining"] == 10);
1755 BEAST_EXPECT(txj.isMember(jss::tx));
1756 auto const& tx = txj[jss::tx];
1757 BEAST_EXPECT(tx[jss::Account] == alice.human());
1758 BEAST_EXPECT(tx[jss::TransactionType] == jss::OfferCreate);
1759 const auto txid0 = tx[jss::hash].asString();
1763 BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
1771 jv[jss::expand] =
false;
1773 jrr = env.rpc(
"json",
"ledger",
to_string(jv))[jss::result];
1774 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
1776 auto const& parentHash = env.current()->info().parentHash;
1777 auto const txid1 = [&]() {
1778 auto const& txj = jrr[jss::queue_data][1u];
1779 BEAST_EXPECT(txj[jss::account] == alice.human());
1780 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
1781 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
1782 BEAST_EXPECT(txj.isMember(jss::tx));
1783 return txj[jss::tx].asString();
1785 auto const& txj = jrr[jss::queue_data][0u];
1786 BEAST_EXPECT(txj[jss::account] == alice.human());
1787 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
1788 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
1789 BEAST_EXPECT(txj[
"retries_remaining"] == 9);
1790 BEAST_EXPECT(txj[
"last_result"] ==
"terPRE_SEQ");
1791 BEAST_EXPECT(txj.isMember(jss::tx));
1792 BEAST_EXPECT(txj[jss::tx] == txid0);
1796 BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
1801 jv[jss::expand] =
true;
1802 jv[jss::binary] =
true;
1804 jrr = env.rpc(
"json",
"ledger",
to_string(jv))[jss::result];
1805 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
1807 auto const& txj = jrr[jss::queue_data][1u];
1808 BEAST_EXPECT(txj[jss::account] == alice.human());
1809 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
1810 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
1811 BEAST_EXPECT(txj[
"retries_remaining"] == 8);
1812 BEAST_EXPECT(txj[
"last_result"] ==
"terPRE_SEQ");
1813 BEAST_EXPECT(txj.isMember(jss::tx));
1814 BEAST_EXPECT(txj[jss::tx].isMember(jss::tx_blob));
1816 auto const& txj2 = jrr[jss::queue_data][0u];
1817 BEAST_EXPECT(txj2[jss::account] == alice.human());
1818 BEAST_EXPECT(txj2[jss::fee_level] ==
"256");
1819 BEAST_EXPECT(txj2[
"preflight_result"] ==
"tesSUCCESS");
1820 BEAST_EXPECT(txj2[
"retries_remaining"] == 10);
1821 BEAST_EXPECT(!txj2.isMember(
"last_result"));
1822 BEAST_EXPECT(txj2.isMember(jss::tx));
1823 BEAST_EXPECT(txj2[jss::tx].isMember(jss::tx_blob));
1826 for (
int i = 0; i != 9; ++i)
1831 jv[jss::expand] =
false;
1832 jv[jss::binary] =
false;
1834 jrr = env.rpc(
"json",
"ledger",
to_string(jv))[jss::result];
1836 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
1838 auto const& txj = jrr[jss::queue_data][0u];
1839 BEAST_EXPECT(txj[jss::account] == alice.human());
1840 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
1841 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
1842 BEAST_EXPECT(txj[
"retries_remaining"] == 1);
1843 BEAST_EXPECT(txj[
"last_result"] ==
"terPRE_SEQ");
1844 BEAST_EXPECT(txj.isMember(jss::tx));
1845 BEAST_EXPECT(txj[jss::tx] != txid0);
1846 return txj[jss::tx].asString();
1851 jv[jss::full] =
true;
1853 jrr = env.rpc(
"json",
"ledger",
to_string(jv))[jss::result];
1854 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
1856 auto const& txj = jrr[jss::queue_data][0u];
1857 BEAST_EXPECT(txj[jss::account] == alice.human());
1858 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
1859 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
1860 BEAST_EXPECT(txj[
"retries_remaining"] == 1);
1861 BEAST_EXPECT(txj[
"last_result"] ==
"terPRE_SEQ");
1862 BEAST_EXPECT(txj.isMember(jss::tx));
1863 auto const& tx = txj[jss::tx];
1864 BEAST_EXPECT(tx[jss::Account] == alice.human());
1865 BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
1866 BEAST_EXPECT(tx[jss::hash] == txid2);
1873 testcase(
"Ledger Request, Accounts Hashes");
1874 using namespace test::jtx;
1883 jvParams[jss::ledger_index] = 3u;
1884 jvParams[jss::accounts] =
true;
1885 jvParams[jss::expand] =
true;
1886 jvParams[jss::type] =
"hashes";
1888 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
1889 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
1890 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
1891 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
1893 jrr[jss::ledger][jss::accountState][0u][
"LedgerEntryType"] ==
1895 index = jrr[jss::ledger][jss::accountState][0u][
"index"].asString();
1899 jvParams[jss::ledger_index] = 3u;
1900 jvParams[jss::accounts] =
true;
1901 jvParams[jss::expand] =
false;
1902 jvParams[jss::type] =
"hashes";
1904 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
1905 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
1906 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
1907 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
1908 BEAST_EXPECT(jrr[jss::ledger][jss::accountState][0u] == index);