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>
26 #include <boost/utility/string_ref.hpp>
35 "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
36 "BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000",
39 "LedgerEntryType" : "Offer",
44 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
47 "TakerPays" : "100000000",
48 "index" : "29665262716C19830E26AEEC0916E476FC7D8EF195FF3B4F06829E64F82A3B3E"
53 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
59 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
63 "LedgerEntryType" : "RippleState",
66 "issuer" : "r9cZvwKU3zzuZK9JFovGg1JC5n7QiqNL8L",
70 "index" : "D13183BCFFC9AAC9F96AEBB5F66E4A652AD1F5D10273AEB615478302BEBFD4A4"
75 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
81 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
85 "LedgerEntryType" : "RippleState",
88 "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
92 "index" : "D89BC239086183EB9458C396E643795C1134963E6550E682A190A5F021766D43"
95 "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
96 "BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
99 "LedgerEntryType" : "Offer",
104 "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
107 "TakerPays" : "100000000",
108 "index" : "F03ABE26CB8C5F4AFB31A86590BD25C64C5756FCE5CE9704C27AFE291A4A29A1"
117 testcase(
"error cases");
124 auto resp = env.
rpc(
"json",
"account_objects");
125 BEAST_EXPECT(resp[jss::error_message] ==
"Syntax error.");
130 params[jss::account] =
131 "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV";
132 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
134 resp[jss::result][jss::error_message] ==
"Account malformed.");
140 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
142 resp[jss::result][jss::error_message] ==
"Account not found.");
148 params[jss::account] = bob.human();
149 params[jss::ledger_index] = 10;
150 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
152 resp[jss::result][jss::error_message] ==
"ledgerNotFound");
159 params[jss::account] = bob.human();
160 params[jss::type] = 10;
161 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
163 resp[jss::result][jss::error_message] ==
164 "Invalid field 'type', not string.");
169 params[jss::account] = bob.human();
170 params[jss::type] =
"expedited";
171 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
173 resp[jss::result][jss::error_message] ==
174 "Invalid field 'type'.");
179 params[jss::account] = bob.human();
180 params[jss::limit] = -1;
181 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
183 resp[jss::result][jss::error_message] ==
184 "Invalid field 'limit', not unsigned integer.");
190 auto const USD = gw[
"USD"];
191 env.
trust(USD(1000), bob);
192 env(
pay(gw, bob,
XRP(1)));
196 params[jss::account] = bob.human();
197 params[jss::limit] = 1;
198 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
200 auto resume_marker = resp[jss::result][jss::marker];
202 params[jss::marker] = 10;
203 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
205 resp[jss::result][jss::error_message] ==
206 "Invalid field 'marker', not string.");
208 params[jss::marker] =
"This is a string with no comma";
209 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
211 resp[jss::result][jss::error_message] ==
212 "Invalid field 'marker'.");
214 params[jss::marker] =
"This string has a comma, but is not hex";
215 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
217 resp[jss::result][jss::error_message] ==
218 "Invalid field 'marker'.");
221 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
223 resp[jss::result][jss::error_message] ==
224 "Invalid field 'marker'.");
227 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
229 resp[jss::result][jss::error_message] ==
230 "Invalid field 'marker'.");
232 params[jss::marker] =
std::string(&mark[1U], 65) +
"not hex";
233 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
235 resp[jss::result][jss::error_message] ==
236 "Invalid field 'marker'.");
242 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
243 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
250 testcase(
"unsteppedThenStepped");
259 auto const USD1 = gw1[
"USD"];
260 auto const USD2 = gw2[
"USD"];
262 env.
fund(
XRP(1000), gw1, gw2, bob);
263 env.
trust(USD1(1000), bob);
264 env.
trust(USD2(1000), bob);
266 env(
pay(gw1, bob, USD1(1000)));
267 env(
pay(gw2, bob, USD2(1000)));
273 for (
int i = 0; i < 4; ++i)
280 params[jss::account] = bob.human();
281 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
282 BEAST_EXPECT(!resp.isMember(jss::marker));
284 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 4);
285 for (
int i = 0; i < 4; ++i)
287 auto& aobj = resp[jss::result][jss::account_objects][i];
288 aobj.removeMember(
"PreviousTxnID");
289 aobj.removeMember(
"PreviousTxnLgrSeq");
290 BEAST_EXPECT(aobj == bobj[i]);
296 params[jss::account] = bob.human();
297 params[jss::type] = jss::state;
298 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
299 BEAST_EXPECT(!resp.isMember(jss::marker));
301 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 2);
302 for (
int i = 0; i < 2; ++i)
304 auto& aobj = resp[jss::result][jss::account_objects][i];
305 aobj.removeMember(
"PreviousTxnID");
306 aobj.removeMember(
"PreviousTxnLgrSeq");
307 BEAST_EXPECT(aobj == bobj[i + 1]);
313 params[jss::account] = bob.human();
314 params[jss::limit] = 1;
315 for (
int i = 0; i < 4; ++i)
319 auto& aobjs = resp[jss::result][jss::account_objects];
320 BEAST_EXPECT(aobjs.size() == 1);
321 auto& aobj = aobjs[0U];
323 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
325 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
327 aobj.removeMember(
"PreviousTxnID");
328 aobj.removeMember(
"PreviousTxnLgrSeq");
330 BEAST_EXPECT(aobj == bobj[i]);
332 params[jss::marker] = resp[jss::result][jss::marker];
343 testcase(
"unsteppedThenSteppedWithNFTs");
352 auto const USD1 = gw1[
"USD"];
353 auto const USD2 = gw2[
"USD"];
355 env.
fund(
XRP(1000), gw1, gw2, bob);
362 params[jss::account] = bob.human();
363 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
364 BEAST_EXPECT(!resp.isMember(jss::marker));
365 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
368 params[jss::limit] = 1;
369 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
370 BEAST_EXPECT(!resp.isMember(jss::marker));
371 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
383 params[jss::account] = bob.human();
384 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
385 BEAST_EXPECT(!resp.isMember(jss::marker));
387 unpaged = resp[jss::result][jss::account_objects];
388 BEAST_EXPECT(unpaged.
size() == 1);
393 params[jss::account] = bob.human();
394 params[jss::type] = jss::nft_page;
395 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
396 BEAST_EXPECT(!resp.isMember(jss::marker));
397 Json::Value& aobjs = resp[jss::result][jss::account_objects];
398 BEAST_EXPECT(aobjs.
size() == 1);
406 params[jss::account] = bob.human();
407 params[jss::limit] = 1;
411 Json::Value& aobjs = resp[jss::result][jss::account_objects];
412 BEAST_EXPECT(aobjs.
size() == 1);
413 auto& aobj = aobjs[0U];
414 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
415 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
417 BEAST_EXPECT(aobj == unpaged[0u]);
421 env.
trust(USD1(1000), bob);
422 env.
trust(USD2(1000), bob);
424 env(
pay(gw1, bob, USD1(1000)));
425 env(
pay(gw2, bob, USD2(1000)));
434 params[jss::account] = bob.human();
435 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
436 BEAST_EXPECT(!resp.isMember(jss::marker));
438 unpaged = resp[jss::result][jss::account_objects];
439 BEAST_EXPECT(unpaged.
size() == 5);
444 params[jss::account] = bob.human();
445 params[jss::type] = jss::nft_page;
446 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
447 BEAST_EXPECT(!resp.isMember(jss::marker));
448 Json::Value& aobjs = resp[jss::result][jss::account_objects];
449 BEAST_EXPECT(aobjs.
size() == 1);
457 params[jss::account] = bob.human();
458 params[jss::limit] = 1;
459 for (
int i = 0; i < 5; ++i)
463 Json::Value& aobjs = resp[jss::result][jss::account_objects];
464 BEAST_EXPECT(aobjs.
size() == 1);
465 auto& aobj = aobjs[0U];
468 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
469 BEAST_EXPECT(resp[jss::result].isMember(jss::marker));
473 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
474 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
477 BEAST_EXPECT(aobj == unpaged[i]);
479 params[jss::marker] = resp[jss::result][jss::marker];
484 for (
int i = 0; i < 32; ++i)
492 params[jss::account] = bob.human();
493 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
494 BEAST_EXPECT(!resp.isMember(jss::marker));
496 unpaged = resp[jss::result][jss::account_objects];
497 BEAST_EXPECT(unpaged.
size() == 6);
502 params[jss::account] = bob.human();
503 params[jss::type] = jss::nft_page;
504 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
505 BEAST_EXPECT(!resp.isMember(jss::marker));
506 Json::Value& aobjs = resp[jss::result][jss::account_objects];
507 BEAST_EXPECT(aobjs.
size() == 2);
512 params[jss::account] = bob.human();
513 params[jss::limit] = 1;
514 for (
int i = 0; i < 6; ++i)
518 Json::Value& aobjs = resp[jss::result][jss::account_objects];
519 BEAST_EXPECT(aobjs.
size() == 1);
520 auto& aobj = aobjs[0U];
523 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
524 BEAST_EXPECT(resp[jss::result].isMember(jss::marker));
528 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
529 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
532 BEAST_EXPECT(aobj == unpaged[i]);
534 params[jss::marker] = resp[jss::result][jss::marker];
542 testcase(
"object types");
550 auto const USD = gw[
"USD"];
555 auto acct_objs = [&env](
Account const& acct,
char const* type) {
557 params[jss::account] = acct.
human();
558 params[jss::type] = type;
559 params[jss::ledger_index] =
"validated";
560 return env.
rpc(
"json",
"account_objects",
to_string(params));
564 auto acct_objs_is_size = [](
Json::Value const& resp,
unsigned size) {
565 return resp[jss::result][jss::account_objects].
isArray() &&
566 (resp[jss::result][jss::account_objects].
size() == size);
569 env.
fund(
XRP(10000), gw, alice);
574 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::account), 0));
575 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amendments), 0));
576 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::check), 0));
577 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::deposit_preauth), 0));
578 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::directory), 0));
579 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::escrow), 0));
580 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::fee), 0));
581 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hashes), 0));
582 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::nft_page), 0));
583 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::offer), 0));
584 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::payment_channel), 0));
585 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::signer_list), 0));
586 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::state), 0));
587 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::ticket), 0));
595 Json::Value const resp = acct_objs(gw, jss::nft_page);
596 BEAST_EXPECT(acct_objs_is_size(resp, 1));
598 auto const& nftPage = resp[jss::result][jss::account_objects][0u];
606 env.
trust(USD(1000), alice);
608 env(
pay(gw, alice, USD(5)));
612 Json::Value const resp = acct_objs(gw, jss::state);
613 BEAST_EXPECT(acct_objs_is_size(resp, 1));
615 auto const& state = resp[jss::result][jss::account_objects][0u];
621 env(check::create(gw, alice, USD(10)));
625 Json::Value const resp = acct_objs(gw, jss::check);
626 BEAST_EXPECT(acct_objs_is_size(resp, 1));
628 auto const& check = resp[jss::result][jss::account_objects][0u];
634 env(deposit::auth(gw, alice));
638 Json::Value const resp = acct_objs(gw, jss::deposit_preauth);
639 BEAST_EXPECT(acct_objs_is_size(resp, 1));
641 auto const& preauth = resp[jss::result][jss::account_objects][0u];
648 jvEscrow[jss::TransactionType] = jss::EscrowCreate;
650 jvEscrow[jss::Account] = gw.human();
651 jvEscrow[jss::Destination] = gw.human();
660 Json::Value const resp = acct_objs(gw, jss::escrow);
661 BEAST_EXPECT(acct_objs_is_size(resp, 1));
663 auto const& escrow = resp[jss::result][jss::account_objects][0u];
669 env(offer(gw, USD(7),
XRP(14)));
673 Json::Value const resp = acct_objs(gw, jss::offer);
674 BEAST_EXPECT(acct_objs_is_size(resp, 1));
676 auto const& offer = resp[jss::result][jss::account_objects][0u];
684 jvPayChan[jss::TransactionType] = jss::PaymentChannelCreate;
686 jvPayChan[jss::Account] = gw.human();
687 jvPayChan[jss::Destination] = alice.human();
688 jvPayChan[jss::Amount] =
697 Json::Value const resp = acct_objs(gw, jss::payment_channel);
698 BEAST_EXPECT(acct_objs_is_size(resp, 1));
700 auto const& payChan = resp[jss::result][jss::account_objects][0u];
707 env(signers(gw, 6, {{alice, 7}}));
711 Json::Value const resp = acct_objs(gw, jss::signer_list);
712 BEAST_EXPECT(acct_objs_is_size(resp, 1));
714 auto const& signerList =
715 resp[jss::result][jss::account_objects][0u];
723 env(ticket::create(gw, 1));
727 Json::Value const resp = acct_objs(gw, jss::ticket);
728 BEAST_EXPECT(acct_objs_is_size(resp, 1));
730 auto const& ticket = resp[jss::result][jss::account_objects][0u];
738 params[jss::account] = gw.human();
739 params[jss::deletion_blockers_only] =
true;
740 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
746 jss::NFTokenPage.c_str(),
747 jss::RippleState.c_str(),
748 jss::PayChannel.c_str()};
756 if (BEAST_EXPECT(acct_objs_is_size(resp, expectedAccountObjects)))
758 auto const& aobjs = resp[jss::result][jss::account_objects];
760 gotLedgerTypes.
reserve(expectedAccountObjects);
764 aobjs[i][
"LedgerEntryType"].asString());
767 BEAST_EXPECT(gotLedgerTypes == expectedLedgerTypes);
774 params[jss::account] = gw.human();
775 params[jss::deletion_blockers_only] =
true;
776 params[jss::type] = jss::escrow;
777 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
779 if (BEAST_EXPECT(acct_objs_is_size(resp, 1u)))
781 auto const& aobjs = resp[jss::result][jss::account_objects];
782 BEAST_EXPECT(aobjs[0u][
"LedgerEntryType"] == jss::Escrow);
788 for (
int d = 1
'000'032; d >= 1
'000'000; --d)
790 env(offer(gw, USD(1),
drops(d)));
795 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::account), 0));
796 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amendments), 0));
797 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::directory), 0));
798 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::fee), 0));
799 BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hashes), 0));