20 #include <ripple/json/json_reader.h>
21 #include <ripple/json/json_value.h>
22 #include <ripple/json/to_string.h>
23 #include <ripple/protocol/jss.h>
25 #include <test/jtx/AMM.h>
26 #include <test/jtx/xchain_bridge.h>
28 #include <boost/utility/string_ref.hpp>
37 "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
38 "BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000",
41 "LedgerEntryType" : "Offer",
46 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
49 "TakerPays" : "100000000",
50 "index" : "29665262716C19830E26AEEC0916E476FC7D8EF195FF3B4F06829E64F82A3B3E"
55 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
61 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
65 "LedgerEntryType" : "RippleState",
68 "issuer" : "r9cZvwKU3zzuZK9JFovGg1JC5n7QiqNL8L",
72 "index" : "D13183BCFFC9AAC9F96AEBB5F66E4A652AD1F5D10273AEB615478302BEBFD4A4"
77 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
83 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
87 "LedgerEntryType" : "RippleState",
90 "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
94 "index" : "D89BC239086183EB9458C396E643795C1134963E6550E682A190A5F021766D43"
97 "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
98 "BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
101 "LedgerEntryType" : "Offer",
106 "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
109 "TakerPays" : "100000000",
110 "index" : "F03ABE26CB8C5F4AFB31A86590BD25C64C5756FCE5CE9704C27AFE291A4A29A1"
119 testcase(
"error cases");
126 auto resp = env.
rpc(
"json",
"account_objects");
127 BEAST_EXPECT(resp[jss::error_message] ==
"Syntax error.");
132 params[jss::account] =
133 "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV";
134 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
136 resp[jss::result][jss::error_message] ==
"Account malformed.");
142 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
144 resp[jss::result][jss::error_message] ==
"Account not found.");
150 params[jss::account] = bob.human();
151 params[jss::ledger_index] = 10;
152 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
154 resp[jss::result][jss::error_message] ==
"ledgerNotFound");
161 params[jss::account] = bob.human();
162 params[jss::type] = 10;
163 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
165 resp[jss::result][jss::error_message] ==
166 "Invalid field 'type', not string.");
171 params[jss::account] = bob.human();
172 params[jss::type] =
"expedited";
173 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
175 resp[jss::result][jss::error_message] ==
176 "Invalid field 'type'.");
181 params[jss::account] = bob.human();
182 params[jss::limit] = -1;
183 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
185 resp[jss::result][jss::error_message] ==
186 "Invalid field 'limit', not unsigned integer.");
192 auto const USD = gw[
"USD"];
193 env.
trust(USD(1000), bob);
194 env(pay(gw, bob,
XRP(1)));
198 params[jss::account] = bob.human();
199 params[jss::limit] = 1;
200 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
202 auto resume_marker = resp[jss::result][jss::marker];
204 params[jss::marker] = 10;
205 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
207 resp[jss::result][jss::error_message] ==
208 "Invalid field 'marker', not string.");
210 params[jss::marker] =
"This is a string with no comma";
211 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
213 resp[jss::result][jss::error_message] ==
214 "Invalid field 'marker'.");
216 params[jss::marker] =
"This string has a comma, but is not hex";
217 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
219 resp[jss::result][jss::error_message] ==
220 "Invalid field 'marker'.");
223 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
225 resp[jss::result][jss::error_message] ==
226 "Invalid field 'marker'.");
229 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
231 resp[jss::result][jss::error_message] ==
232 "Invalid field 'marker'.");
234 params[jss::marker] =
std::string(&mark[1U], 65) +
"not hex";
235 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
237 resp[jss::result][jss::error_message] ==
238 "Invalid field 'marker'.");
244 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
245 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
252 testcase(
"unsteppedThenStepped");
261 auto const USD1 = gw1[
"USD"];
262 auto const USD2 = gw2[
"USD"];
264 env.
fund(
XRP(1000), gw1, gw2, bob);
265 env.
trust(USD1(1000), bob);
266 env.
trust(USD2(1000), bob);
268 env(pay(gw1, bob, USD1(1000)));
269 env(pay(gw2, bob, USD2(1000)));
275 for (
int i = 0; i < 4; ++i)
282 params[jss::account] = bob.human();
283 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
284 BEAST_EXPECT(!resp.isMember(jss::marker));
286 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 4);
287 for (
int i = 0; i < 4; ++i)
289 auto& aobj = resp[jss::result][jss::account_objects][i];
290 aobj.removeMember(
"PreviousTxnID");
291 aobj.removeMember(
"PreviousTxnLgrSeq");
292 BEAST_EXPECT(aobj == bobj[i]);
298 params[jss::account] = bob.human();
299 params[jss::type] = jss::state;
300 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
301 BEAST_EXPECT(!resp.isMember(jss::marker));
303 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 2);
304 for (
int i = 0; i < 2; ++i)
306 auto& aobj = resp[jss::result][jss::account_objects][i];
307 aobj.removeMember(
"PreviousTxnID");
308 aobj.removeMember(
"PreviousTxnLgrSeq");
309 BEAST_EXPECT(aobj == bobj[i + 1]);
315 params[jss::account] = bob.human();
316 params[jss::limit] = 1;
317 for (
int i = 0; i < 4; ++i)
321 auto& aobjs = resp[jss::result][jss::account_objects];
322 BEAST_EXPECT(aobjs.size() == 1);
323 auto& aobj = aobjs[0U];
325 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
327 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
329 aobj.removeMember(
"PreviousTxnID");
330 aobj.removeMember(
"PreviousTxnLgrSeq");
332 BEAST_EXPECT(aobj == bobj[i]);
334 params[jss::marker] = resp[jss::result][jss::marker];
345 testcase(
"unsteppedThenSteppedWithNFTs");
354 auto const USD1 = gw1[
"USD"];
355 auto const USD2 = gw2[
"USD"];
357 env.
fund(
XRP(1000), gw1, gw2, bob);
364 params[jss::account] = bob.human();
365 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
366 BEAST_EXPECT(!resp.isMember(jss::marker));
367 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
370 params[jss::limit] = 1;
371 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
372 BEAST_EXPECT(!resp.isMember(jss::marker));
373 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
385 params[jss::account] = bob.human();
386 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
387 BEAST_EXPECT(!resp.isMember(jss::marker));
389 unpaged = resp[jss::result][jss::account_objects];
390 BEAST_EXPECT(unpaged.
size() == 1);
395 params[jss::account] = bob.human();
396 params[jss::type] = jss::nft_page;
397 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
398 BEAST_EXPECT(!resp.isMember(jss::marker));
399 Json::Value& aobjs = resp[jss::result][jss::account_objects];
400 BEAST_EXPECT(aobjs.
size() == 1);
408 params[jss::account] = bob.human();
409 params[jss::limit] = 1;
413 Json::Value& aobjs = resp[jss::result][jss::account_objects];
414 BEAST_EXPECT(aobjs.
size() == 1);
415 auto& aobj = aobjs[0U];
416 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
417 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
419 BEAST_EXPECT(aobj == unpaged[0u]);
423 env.
trust(USD1(1000), bob);
424 env.
trust(USD2(1000), bob);
426 env(pay(gw1, bob, USD1(1000)));
427 env(pay(gw2, bob, USD2(1000)));
436 params[jss::account] = bob.human();
437 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
438 BEAST_EXPECT(!resp.isMember(jss::marker));
440 unpaged = resp[jss::result][jss::account_objects];
441 BEAST_EXPECT(unpaged.
size() == 5);
446 params[jss::account] = bob.human();
447 params[jss::type] = jss::nft_page;
448 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
449 BEAST_EXPECT(!resp.isMember(jss::marker));
450 Json::Value& aobjs = resp[jss::result][jss::account_objects];
451 BEAST_EXPECT(aobjs.
size() == 1);
459 params[jss::account] = bob.human();
460 params[jss::limit] = 1;
461 for (
int i = 0; i < 5; ++i)
465 Json::Value& aobjs = resp[jss::result][jss::account_objects];
466 BEAST_EXPECT(aobjs.
size() == 1);
467 auto& aobj = aobjs[0U];
470 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
471 BEAST_EXPECT(resp[jss::result].isMember(jss::marker));
475 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
476 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
479 BEAST_EXPECT(aobj == unpaged[i]);
481 params[jss::marker] = resp[jss::result][jss::marker];
486 for (
int i = 0; i < 32; ++i)
494 params[jss::account] = bob.human();
495 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
496 BEAST_EXPECT(!resp.isMember(jss::marker));
498 unpaged = resp[jss::result][jss::account_objects];
499 BEAST_EXPECT(unpaged.
size() == 6);
504 params[jss::account] = bob.human();
505 params[jss::type] = jss::nft_page;
506 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
507 BEAST_EXPECT(!resp.isMember(jss::marker));
508 Json::Value& aobjs = resp[jss::result][jss::account_objects];
509 BEAST_EXPECT(aobjs.
size() == 2);
514 params[jss::account] = bob.human();
515 params[jss::limit] = 1;
516 for (
int i = 0; i < 6; ++i)
520 Json::Value& aobjs = resp[jss::result][jss::account_objects];
521 BEAST_EXPECT(aobjs.
size() == 1);
522 auto& aobj = aobjs[0U];
525 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
526 BEAST_EXPECT(resp[jss::result].isMember(jss::marker));
530 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
531 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
534 BEAST_EXPECT(aobj == unpaged[i]);
536 params[jss::marker] = resp[jss::result][jss::marker];
544 testcase(
"object types");
552 auto const USD = gw[
"USD"];
554 auto const features =
556 Env env(*
this, features);
559 auto acct_objs = [&env](
567 params[jss::type] = *type;
569 params[jss::limit] = *limit;
571 params[jss::marker] = *marker;
572 params[jss::ledger_index] =
"validated";
573 return env.
rpc(
"json",
"account_objects",
to_string(params));
577 auto acct_objs_is_size = [](
Json::Value const& resp,
unsigned size) {
578 return resp[jss::result][jss::account_objects].
isArray() &&
579 (resp[jss::result][jss::account_objects].
size() == size);
582 env.
fund(
XRP(10000), gw, alice);
587 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::account), 0));
588 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amendments), 0));
589 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::check), 0));
590 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::deposit_preauth), 0));
591 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::directory), 0));
592 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::escrow), 0));
593 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::fee), 0));
594 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hashes), 0));
595 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::nft_page), 0));
596 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::offer), 0));
597 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::payment_channel), 0));
598 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::signer_list), 0));
599 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::state), 0));
600 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::ticket), 0));
601 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amm), 0));
609 Json::Value const resp = acct_objs(gw, jss::nft_page);
610 BEAST_EXPECT(acct_objs_is_size(resp, 1));
612 auto const& nftPage = resp[jss::result][jss::account_objects][0u];
620 env.
trust(USD(1000), alice);
622 env(pay(gw, alice, USD(5)));
626 Json::Value const resp = acct_objs(gw, jss::state);
627 BEAST_EXPECT(acct_objs_is_size(resp, 1));
629 auto const& state = resp[jss::result][jss::account_objects][0u];
635 env(check::create(gw, alice, USD(10)));
639 Json::Value const resp = acct_objs(gw, jss::check);
640 BEAST_EXPECT(acct_objs_is_size(resp, 1));
642 auto const& check = resp[jss::result][jss::account_objects][0u];
648 env(deposit::auth(gw, alice));
652 Json::Value const resp = acct_objs(gw, jss::deposit_preauth);
653 BEAST_EXPECT(acct_objs_is_size(resp, 1));
655 auto const& preauth = resp[jss::result][jss::account_objects][0u];
662 jvEscrow[jss::TransactionType] = jss::EscrowCreate;
664 jvEscrow[jss::Account] = gw.human();
665 jvEscrow[jss::Destination] = gw.human();
674 Json::Value const resp = acct_objs(gw, jss::escrow);
675 BEAST_EXPECT(acct_objs_is_size(resp, 1));
677 auto const& escrow = resp[jss::result][jss::account_objects][0u];
688 auto scenv_acct_objs = [&](
Account const& acct,
char const* type) {
690 params[jss::account] = acct.
human();
691 params[jss::type] = type;
692 params[jss::ledger_index] =
"validated";
693 return scEnv.
rpc(
"json",
"account_objects",
to_string(params));
699 BEAST_EXPECT(acct_objs_is_size(resp, 1));
700 auto const& acct_bridge =
701 resp[jss::result][jss::account_objects][0u];
735 auto scenv_acct_objs = [&](
Account const& acct,
char const* type) {
737 params[jss::account] = acct.
human();
738 params[jss::type] = type;
739 params[jss::ledger_index] =
"validated";
740 return scEnv.
rpc(
"json",
"account_objects",
to_string(params));
746 scenv_acct_objs(x.
scAlice, jss::xchain_owned_claim_id);
747 BEAST_EXPECT(acct_objs_is_size(resp, 1));
749 auto const& xchain_seq =
750 resp[jss::result][jss::account_objects][0u];
759 scenv_acct_objs(x.
scBob, jss::xchain_owned_claim_id);
760 BEAST_EXPECT(acct_objs_is_size(resp, 1));
762 auto const& xchain_seq =
763 resp[jss::result][jss::account_objects][0u];
773 auto const amt =
XRP(1000);
792 auto scenv_acct_objs = [&](
Account const& acct,
char const* type) {
794 params[jss::account] = acct.
human();
795 params[jss::type] = type;
796 params[jss::ledger_index] =
"validated";
797 return scEnv.
rpc(
"json",
"account_objects",
to_string(params));
804 BEAST_EXPECT(acct_objs_is_size(resp, 1));
806 auto const& xchain_create_account_claim_id =
807 resp[jss::result][jss::account_objects][0u];
819 env(offer(gw, USD(7),
XRP(14)));
823 Json::Value const resp = acct_objs(gw, jss::offer);
824 BEAST_EXPECT(acct_objs_is_size(resp, 1));
826 auto const& offer = resp[jss::result][jss::account_objects][0u];
835 jvPayChan[jss::TransactionType] = jss::PaymentChannelCreate;
837 jvPayChan[jss::Account] = gw.human();
838 jvPayChan[jss::Destination] = alice.human();
839 jvPayChan[jss::Amount] =
848 Json::Value const resp = acct_objs(gw, jss::payment_channel);
849 BEAST_EXPECT(acct_objs_is_size(resp, 1));
851 auto const& payChan = resp[jss::result][jss::account_objects][0u];
862 Json::Value const resp = acct_objs(gw, jss::signer_list);
863 BEAST_EXPECT(acct_objs_is_size(resp, 1));
865 auto const& signerList =
866 resp[jss::result][jss::account_objects][0u];
874 env(ticket::create(gw, 1));
878 Json::Value const resp = acct_objs(gw, jss::ticket);
879 BEAST_EXPECT(acct_objs_is_size(resp, 1));
881 auto const& ticket = resp[jss::result][jss::account_objects][0u];
889 params[jss::account] = gw.human();
890 params[jss::deletion_blockers_only] =
true;
891 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
897 jss::NFTokenPage.c_str(),
898 jss::RippleState.c_str(),
899 jss::PayChannel.c_str()};
907 if (BEAST_EXPECT(acct_objs_is_size(resp, expectedAccountObjects)))
909 auto const& aobjs = resp[jss::result][jss::account_objects];
911 gotLedgerTypes.
reserve(expectedAccountObjects);
915 aobjs[i][
"LedgerEntryType"].asString());
918 BEAST_EXPECT(gotLedgerTypes == expectedLedgerTypes);
925 params[jss::account] = gw.human();
926 params[jss::deletion_blockers_only] =
true;
927 params[jss::type] = jss::escrow;
928 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
930 if (BEAST_EXPECT(acct_objs_is_size(resp, 1u)))
932 auto const& aobjs = resp[jss::result][jss::account_objects];
933 BEAST_EXPECT(aobjs[0u][
"LedgerEntryType"] == jss::Escrow);
940 auto const objs = resp[jss::result][jss::account_objects];
941 for (
auto const& obj : resp[jss::result][jss::account_objects])
944 std::sort(typesOut.begin(), typesOut.end());
951 if (!acct_objs_is_size(resp, types.
size()))
954 getTypes(resp, typesOut);
955 return types == typesOut;
958 AMM amm(env, gw,
XRP(1
'000), USD(1'000));
959 amm.deposit(alice, USD(1));
962 BEAST_EXPECT(
lines[jss::lines].size() == 3);
965 acct_objs_is_size(acct_objs(amm.ammAccount(), jss::amm), 1));
967 auto resp = acct_objs(amm.ammAccount(), std::nullopt, 2);
969 getTypes(resp, typesOut);
975 resp[jss::result][jss::marker].
asString());
976 getTypes(resp, typesOut);
981 jss::RippleState.c_str(),
982 jss::RippleState.c_str(),
983 jss::RippleState.c_str()}));
985 resp = acct_objs(amm.ammAccount(), jss::state, 10);
986 BEAST_EXPECT(expectObjects(
988 {jss::RippleState.c_str(),
989 jss::RippleState.c_str(),
990 jss::RippleState.c_str()}));
993 acct_objs_is_size(acct_objs(amm.ammAccount(), jss::offer), 0));
995 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amm), 0));
1000 for (
int d = 1
'000'032; d >= 1
'000'000; --d)
1002 env(offer(gw, USD(1),
drops(d)));
1007 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::account), 0));
1008 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amendments), 0));
1009 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::directory), 0));
1010 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::fee), 0));
1011 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hashes), 0));