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>
27 #include <boost/utility/string_ref.hpp>
36 "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
37 "BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000",
40 "LedgerEntryType" : "Offer",
45 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
48 "TakerPays" : "100000000",
49 "index" : "29665262716C19830E26AEEC0916E476FC7D8EF195FF3B4F06829E64F82A3B3E"
54 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
60 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
64 "LedgerEntryType" : "RippleState",
67 "issuer" : "r9cZvwKU3zzuZK9JFovGg1JC5n7QiqNL8L",
71 "index" : "D13183BCFFC9AAC9F96AEBB5F66E4A652AD1F5D10273AEB615478302BEBFD4A4"
76 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
82 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
86 "LedgerEntryType" : "RippleState",
89 "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
93 "index" : "D89BC239086183EB9458C396E643795C1134963E6550E682A190A5F021766D43"
96 "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
97 "BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
100 "LedgerEntryType" : "Offer",
105 "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
108 "TakerPays" : "100000000",
109 "index" : "F03ABE26CB8C5F4AFB31A86590BD25C64C5756FCE5CE9704C27AFE291A4A29A1"
118 testcase(
"error cases");
125 auto resp = env.
rpc(
"json",
"account_objects");
126 BEAST_EXPECT(resp[jss::error_message] ==
"Syntax error.");
131 params[jss::account] =
132 "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV";
133 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
135 resp[jss::result][jss::error_message] ==
"Account malformed.");
141 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
143 resp[jss::result][jss::error_message] ==
"Account not found.");
149 params[jss::account] = bob.human();
150 params[jss::ledger_index] = 10;
151 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
153 resp[jss::result][jss::error_message] ==
"ledgerNotFound");
160 params[jss::account] = bob.human();
161 params[jss::type] = 10;
162 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
164 resp[jss::result][jss::error_message] ==
165 "Invalid field 'type', not string.");
170 params[jss::account] = bob.human();
171 params[jss::type] =
"expedited";
172 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
174 resp[jss::result][jss::error_message] ==
175 "Invalid field 'type'.");
180 params[jss::account] = bob.human();
181 params[jss::limit] = -1;
182 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
184 resp[jss::result][jss::error_message] ==
185 "Invalid field 'limit', not unsigned integer.");
191 auto const USD = gw[
"USD"];
192 env.
trust(USD(1000), bob);
193 env(pay(gw, bob,
XRP(1)));
197 params[jss::account] = bob.human();
198 params[jss::limit] = 1;
199 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
201 auto resume_marker = resp[jss::result][jss::marker];
203 params[jss::marker] = 10;
204 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
206 resp[jss::result][jss::error_message] ==
207 "Invalid field 'marker', not string.");
209 params[jss::marker] =
"This is a string with no comma";
210 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
212 resp[jss::result][jss::error_message] ==
213 "Invalid field 'marker'.");
215 params[jss::marker] =
"This string has a comma, but is not hex";
216 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
218 resp[jss::result][jss::error_message] ==
219 "Invalid field 'marker'.");
222 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
224 resp[jss::result][jss::error_message] ==
225 "Invalid field 'marker'.");
228 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
230 resp[jss::result][jss::error_message] ==
231 "Invalid field 'marker'.");
233 params[jss::marker] =
std::string(&mark[1U], 65) +
"not hex";
234 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
236 resp[jss::result][jss::error_message] ==
237 "Invalid field 'marker'.");
243 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
244 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
251 testcase(
"unsteppedThenStepped");
260 auto const USD1 = gw1[
"USD"];
261 auto const USD2 = gw2[
"USD"];
263 env.
fund(
XRP(1000), gw1, gw2, bob);
264 env.
trust(USD1(1000), bob);
265 env.
trust(USD2(1000), bob);
267 env(pay(gw1, bob, USD1(1000)));
268 env(pay(gw2, bob, USD2(1000)));
274 for (
int i = 0; i < 4; ++i)
281 params[jss::account] = bob.human();
282 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
283 BEAST_EXPECT(!resp.isMember(jss::marker));
285 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 4);
286 for (
int i = 0; i < 4; ++i)
288 auto& aobj = resp[jss::result][jss::account_objects][i];
289 aobj.removeMember(
"PreviousTxnID");
290 aobj.removeMember(
"PreviousTxnLgrSeq");
291 BEAST_EXPECT(aobj == bobj[i]);
297 params[jss::account] = bob.human();
298 params[jss::type] = jss::state;
299 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
300 BEAST_EXPECT(!resp.isMember(jss::marker));
302 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 2);
303 for (
int i = 0; i < 2; ++i)
305 auto& aobj = resp[jss::result][jss::account_objects][i];
306 aobj.removeMember(
"PreviousTxnID");
307 aobj.removeMember(
"PreviousTxnLgrSeq");
308 BEAST_EXPECT(aobj == bobj[i + 1]);
314 params[jss::account] = bob.human();
315 params[jss::limit] = 1;
316 for (
int i = 0; i < 4; ++i)
320 auto& aobjs = resp[jss::result][jss::account_objects];
321 BEAST_EXPECT(aobjs.size() == 1);
322 auto& aobj = aobjs[0U];
324 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
326 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
328 aobj.removeMember(
"PreviousTxnID");
329 aobj.removeMember(
"PreviousTxnLgrSeq");
331 BEAST_EXPECT(aobj == bobj[i]);
333 params[jss::marker] = resp[jss::result][jss::marker];
344 testcase(
"unsteppedThenSteppedWithNFTs");
353 auto const USD1 = gw1[
"USD"];
354 auto const USD2 = gw2[
"USD"];
356 env.
fund(
XRP(1000), gw1, gw2, bob);
363 params[jss::account] = bob.human();
364 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
365 BEAST_EXPECT(!resp.isMember(jss::marker));
366 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
369 params[jss::limit] = 1;
370 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
371 BEAST_EXPECT(!resp.isMember(jss::marker));
372 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
384 params[jss::account] = bob.human();
385 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
386 BEAST_EXPECT(!resp.isMember(jss::marker));
388 unpaged = resp[jss::result][jss::account_objects];
389 BEAST_EXPECT(unpaged.
size() == 1);
394 params[jss::account] = bob.human();
395 params[jss::type] = jss::nft_page;
396 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
397 BEAST_EXPECT(!resp.isMember(jss::marker));
398 Json::Value& aobjs = resp[jss::result][jss::account_objects];
399 BEAST_EXPECT(aobjs.
size() == 1);
407 params[jss::account] = bob.human();
408 params[jss::limit] = 1;
412 Json::Value& aobjs = resp[jss::result][jss::account_objects];
413 BEAST_EXPECT(aobjs.
size() == 1);
414 auto& aobj = aobjs[0U];
415 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
416 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
418 BEAST_EXPECT(aobj == unpaged[0u]);
422 env.
trust(USD1(1000), bob);
423 env.
trust(USD2(1000), bob);
425 env(pay(gw1, bob, USD1(1000)));
426 env(pay(gw2, bob, USD2(1000)));
435 params[jss::account] = bob.human();
436 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
437 BEAST_EXPECT(!resp.isMember(jss::marker));
439 unpaged = resp[jss::result][jss::account_objects];
440 BEAST_EXPECT(unpaged.
size() == 5);
445 params[jss::account] = bob.human();
446 params[jss::type] = jss::nft_page;
447 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
448 BEAST_EXPECT(!resp.isMember(jss::marker));
449 Json::Value& aobjs = resp[jss::result][jss::account_objects];
450 BEAST_EXPECT(aobjs.
size() == 1);
458 params[jss::account] = bob.human();
459 params[jss::limit] = 1;
460 for (
int i = 0; i < 5; ++i)
464 Json::Value& aobjs = resp[jss::result][jss::account_objects];
465 BEAST_EXPECT(aobjs.
size() == 1);
466 auto& aobj = aobjs[0U];
469 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
470 BEAST_EXPECT(resp[jss::result].isMember(jss::marker));
474 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
475 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
478 BEAST_EXPECT(aobj == unpaged[i]);
480 params[jss::marker] = resp[jss::result][jss::marker];
485 for (
int i = 0; i < 32; ++i)
493 params[jss::account] = bob.human();
494 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
495 BEAST_EXPECT(!resp.isMember(jss::marker));
497 unpaged = resp[jss::result][jss::account_objects];
498 BEAST_EXPECT(unpaged.
size() == 6);
503 params[jss::account] = bob.human();
504 params[jss::type] = jss::nft_page;
505 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
506 BEAST_EXPECT(!resp.isMember(jss::marker));
507 Json::Value& aobjs = resp[jss::result][jss::account_objects];
508 BEAST_EXPECT(aobjs.
size() == 2);
513 params[jss::account] = bob.human();
514 params[jss::limit] = 1;
515 for (
int i = 0; i < 6; ++i)
519 Json::Value& aobjs = resp[jss::result][jss::account_objects];
520 BEAST_EXPECT(aobjs.
size() == 1);
521 auto& aobj = aobjs[0U];
524 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
525 BEAST_EXPECT(resp[jss::result].isMember(jss::marker));
529 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
530 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
533 BEAST_EXPECT(aobj == unpaged[i]);
535 params[jss::marker] = resp[jss::result][jss::marker];
543 testcase(
"object types");
551 auto const USD = gw[
"USD"];
556 auto acct_objs = [&env](
564 params[jss::type] = *type;
566 params[jss::limit] = *limit;
568 params[jss::marker] = *marker;
569 params[jss::ledger_index] =
"validated";
570 return env.
rpc(
"json",
"account_objects",
to_string(params));
574 auto acct_objs_is_size = [](
Json::Value const& resp,
unsigned size) {
575 return resp[jss::result][jss::account_objects].
isArray() &&
576 (resp[jss::result][jss::account_objects].
size() == size);
579 env.
fund(
XRP(10000), gw, alice);
584 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::account), 0));
585 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amendments), 0));
586 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::check), 0));
587 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::deposit_preauth), 0));
588 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::directory), 0));
589 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::escrow), 0));
590 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::fee), 0));
591 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hashes), 0));
592 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::nft_page), 0));
593 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::offer), 0));
594 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::payment_channel), 0));
595 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::signer_list), 0));
596 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::state), 0));
597 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::ticket), 0));
598 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amm), 0));
606 Json::Value const resp = acct_objs(gw, jss::nft_page);
607 BEAST_EXPECT(acct_objs_is_size(resp, 1));
609 auto const& nftPage = resp[jss::result][jss::account_objects][0u];
617 env.
trust(USD(1000), alice);
619 env(pay(gw, alice, USD(5)));
623 Json::Value const resp = acct_objs(gw, jss::state);
624 BEAST_EXPECT(acct_objs_is_size(resp, 1));
626 auto const& state = resp[jss::result][jss::account_objects][0u];
632 env(check::create(gw, alice, USD(10)));
636 Json::Value const resp = acct_objs(gw, jss::check);
637 BEAST_EXPECT(acct_objs_is_size(resp, 1));
639 auto const& check = resp[jss::result][jss::account_objects][0u];
645 env(deposit::auth(gw, alice));
649 Json::Value const resp = acct_objs(gw, jss::deposit_preauth);
650 BEAST_EXPECT(acct_objs_is_size(resp, 1));
652 auto const& preauth = resp[jss::result][jss::account_objects][0u];
659 jvEscrow[jss::TransactionType] = jss::EscrowCreate;
661 jvEscrow[jss::Account] = gw.human();
662 jvEscrow[jss::Destination] = gw.human();
671 Json::Value const resp = acct_objs(gw, jss::escrow);
672 BEAST_EXPECT(acct_objs_is_size(resp, 1));
674 auto const& escrow = resp[jss::result][jss::account_objects][0u];
680 env(offer(gw, USD(7),
XRP(14)));
684 Json::Value const resp = acct_objs(gw, jss::offer);
685 BEAST_EXPECT(acct_objs_is_size(resp, 1));
687 auto const& offer = resp[jss::result][jss::account_objects][0u];
695 jvPayChan[jss::TransactionType] = jss::PaymentChannelCreate;
697 jvPayChan[jss::Account] = gw.human();
698 jvPayChan[jss::Destination] = alice.human();
699 jvPayChan[jss::Amount] =
708 Json::Value const resp = acct_objs(gw, jss::payment_channel);
709 BEAST_EXPECT(acct_objs_is_size(resp, 1));
711 auto const& payChan = resp[jss::result][jss::account_objects][0u];
718 env(signers(gw, 6, {{alice, 7}}));
722 Json::Value const resp = acct_objs(gw, jss::signer_list);
723 BEAST_EXPECT(acct_objs_is_size(resp, 1));
725 auto const& signerList =
726 resp[jss::result][jss::account_objects][0u];
734 env(ticket::create(gw, 1));
738 Json::Value const resp = acct_objs(gw, jss::ticket);
739 BEAST_EXPECT(acct_objs_is_size(resp, 1));
741 auto const& ticket = resp[jss::result][jss::account_objects][0u];
749 params[jss::account] = gw.human();
750 params[jss::deletion_blockers_only] =
true;
751 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
757 jss::NFTokenPage.c_str(),
758 jss::RippleState.c_str(),
759 jss::PayChannel.c_str()};
767 if (BEAST_EXPECT(acct_objs_is_size(resp, expectedAccountObjects)))
769 auto const& aobjs = resp[jss::result][jss::account_objects];
771 gotLedgerTypes.
reserve(expectedAccountObjects);
775 aobjs[i][
"LedgerEntryType"].asString());
778 BEAST_EXPECT(gotLedgerTypes == expectedLedgerTypes);
785 params[jss::account] = gw.human();
786 params[jss::deletion_blockers_only] =
true;
787 params[jss::type] = jss::escrow;
788 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
790 if (BEAST_EXPECT(acct_objs_is_size(resp, 1u)))
792 auto const& aobjs = resp[jss::result][jss::account_objects];
793 BEAST_EXPECT(aobjs[0u][
"LedgerEntryType"] == jss::Escrow);
800 auto const objs = resp[jss::result][jss::account_objects];
801 for (
auto const& obj : resp[jss::result][jss::account_objects])
804 std::sort(typesOut.begin(), typesOut.end());
811 if (!acct_objs_is_size(resp, types.
size()))
814 getTypes(resp, typesOut);
815 return types == typesOut;
818 AMM amm(env, gw,
XRP(1
'000), USD(1'000));
819 amm.deposit(alice, USD(1));
822 BEAST_EXPECT(
lines[jss::lines].size() == 3);
825 acct_objs_is_size(acct_objs(amm.ammAccount(), jss::amm), 1));
827 auto resp = acct_objs(amm.ammAccount(), std::nullopt, 2);
829 getTypes(resp, typesOut);
835 resp[jss::result][jss::marker].
asString());
836 getTypes(resp, typesOut);
841 jss::RippleState.c_str(),
842 jss::RippleState.c_str(),
843 jss::RippleState.c_str()}));
845 resp = acct_objs(amm.ammAccount(), jss::state, 10);
846 BEAST_EXPECT(expectObjects(
848 {jss::RippleState.c_str(),
849 jss::RippleState.c_str(),
850 jss::RippleState.c_str()}));
853 acct_objs_is_size(acct_objs(amm.ammAccount(), jss::offer), 0));
855 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amm), 0));
860 for (
int d = 1
'000'032; d >= 1
'000'000; --d)
862 env(offer(gw, USD(1),
drops(d)));
867 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::account), 0));
868 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amendments), 0));
869 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::directory), 0));
870 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::fee), 0));
871 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hashes), 0));