20 #include <ripple/json/json_value.h>
21 #include <ripple/json/to_string.h>
22 #include <ripple/json/json_reader.h>
23 #include <ripple/protocol/jss.h>
26 #include <boost/utility/string_ref.hpp>
35 "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
36 "BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000",
37 "BookNode" : "0000000000000000",
39 "LedgerEntryType" : "Offer",
40 "OwnerNode" : "0000000000000000",
44 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
47 "TakerPays" : "100000000",
48 "index" : "29665262716C19830E26AEEC0916E476FC7D8EF195FF3B4F06829E64F82A3B3E"
52 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
58 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
61 "HighNode" : "0000000000000000",
62 "LedgerEntryType" : "RippleState",
65 "issuer" : "r9cZvwKU3zzuZK9JFovGg1JC5n7QiqNL8L",
68 "LowNode" : "0000000000000000",
69 "index" : "D13183BCFFC9AAC9F96AEBB5F66E4A652AD1F5D10273AEB615478302BEBFD4A4"
73 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
79 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
82 "HighNode" : "0000000000000000",
83 "LedgerEntryType" : "RippleState",
86 "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
89 "LowNode" : "0000000000000000",
90 "index" : "D89BC239086183EB9458C396E643795C1134963E6550E682A190A5F021766D43"
92 "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
93 "BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
94 "BookNode" : "0000000000000000",
96 "LedgerEntryType" : "Offer",
97 "OwnerNode" : "0000000000000000",
101 "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
104 "TakerPays" : "100000000",
105 "index" : "F03ABE26CB8C5F4AFB31A86590BD25C64C5756FCE5CE9704C27AFE291A4A29A1"
109 class AccountObjects_test :
public beast::unit_test::suite
114 testcase(
"error cases");
121 auto resp = env.rpc(
"json",
"account_objects");
122 BEAST_EXPECT( resp[jss::error_message] ==
128 params[jss::account] =
"n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV";
129 auto resp = env.rpc(
"json",
"account_objects",
to_string(params));
130 BEAST_EXPECT( resp[jss::result][jss::error_message] ==
"Disallowed seed.");
135 params[jss::account] = Account{
"bogie" }.human();
136 auto resp = env.rpc(
"json",
"account_objects",
to_string(params));
137 BEAST_EXPECT( resp[jss::result][jss::error_message] ==
"Account not found.");
139 Account
const bob{
"bob" };
143 params[jss::account] = bob.human();
144 params[jss::ledger_index] = 10;
145 auto resp = env.rpc(
"json",
"account_objects",
to_string(params));
146 BEAST_EXPECT( resp[jss::result][jss::error_message] ==
"ledgerNotFound");
149 env.fund(
XRP(1000), bob);
153 params[jss::account] = bob.human();
154 params[jss::type] = 10;
155 auto resp = env.rpc(
"json",
"account_objects",
to_string(params));
156 BEAST_EXPECT( resp[jss::result][jss::error_message] ==
157 "Invalid field 'type', not string.");
162 params[jss::account] = bob.human();
163 params[jss::type] =
"expedited";
164 auto resp = env.rpc(
"json",
"account_objects",
to_string(params));
165 BEAST_EXPECT( resp[jss::result][jss::error_message] ==
"Invalid field 'type'.");
170 params[jss::account] = bob.human();
171 params[jss::limit] = -1;
172 auto resp = env.rpc(
"json",
"account_objects",
to_string(params));
173 BEAST_EXPECT( resp[jss::result][jss::error_message] ==
174 "Invalid field 'limit', not unsigned integer.");
178 Account
const gw{
"G" };
179 env.fund(
XRP(1000), gw);
180 auto const USD = gw[
"USD"];
181 env.trust(USD(1000), bob);
182 env(
pay(gw, bob,
XRP(1)));
186 params[jss::account] = bob.human();
187 params[jss::limit] = 1;
188 auto resp = env.rpc(
"json",
"account_objects",
to_string(params));
190 auto resume_marker = resp[jss::result][jss::marker];
192 params[jss::marker] = 10;
193 resp = env.rpc(
"json",
"account_objects",
to_string(params));
194 BEAST_EXPECT( resp[jss::result][jss::error_message] ==
"Invalid field 'marker', not string.");
196 params[jss::marker] =
"This is a string with no comma";
197 resp = env.rpc(
"json",
"account_objects",
to_string(params));
198 BEAST_EXPECT( resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
200 params[jss::marker] =
"This string has a comma, but is not hex";
201 resp = env.rpc(
"json",
"account_objects",
to_string(params));
202 BEAST_EXPECT( resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
205 resp = env.rpc(
"json",
"account_objects",
to_string(params));
206 BEAST_EXPECT( resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
209 resp = env.rpc(
"json",
"account_objects",
to_string(params));
210 BEAST_EXPECT( resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
212 params[jss::marker] =
std::string(&mark[1U], 65) +
"not hex";
213 resp = env.rpc(
"json",
"account_objects",
to_string(params));
214 BEAST_EXPECT( resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
220 resp = env.rpc(
"json",
"account_objects",
to_string(params));
221 BEAST_EXPECT( resp[jss::result][jss::account_objects].
size() == 0);
227 testcase(
"unsteppedThenStepped");
234 Account
const bob{
"bob" };
236 auto const USD1 = gw1[
"USD"];
237 auto const USD2 = gw2[
"USD"];
239 env.fund(XRP(1000), gw1, gw2, bob);
240 env.trust(USD1(1000), bob);
241 env.trust(USD2(1000), bob);
243 env(pay(gw1, bob, USD1(1000)));
244 env(pay(gw2, bob, USD2(1000)));
246 env(offer(bob, XRP(100), bob[
"USD"](1)),txflags(
tfPassive));
247 env(offer(bob, XRP(100), USD1(1)), txflags(
tfPassive));
250 for (
int i = 0; i < 4; ++i)
257 params[jss::account] = bob.human();
258 auto resp = env.rpc(
"json",
"account_objects",
to_string(params));
259 BEAST_EXPECT( !resp.isMember(jss::marker));
261 BEAST_EXPECT( resp[jss::result][jss::account_objects].
size() == 4);
262 for (
int i = 0; i < 4; ++i)
264 auto& aobj = resp[jss::result][jss::account_objects][i];
265 aobj.removeMember(
"PreviousTxnID");
266 aobj.removeMember(
"PreviousTxnLgrSeq");
270 BEAST_EXPECT(aobj == bobj[i]);
276 params[jss::account] = bob.human();
277 params[jss::type] =
"state";
278 auto resp = env.rpc(
"json",
"account_objects",
to_string(params));
279 BEAST_EXPECT( !resp.isMember(jss::marker));
281 BEAST_EXPECT( resp[jss::result][jss::account_objects].
size() == 2);
282 for (
int i = 0; i < 2; ++i)
284 auto& aobj = resp[jss::result][jss::account_objects][i];
285 aobj.removeMember(
"PreviousTxnID");
286 aobj.removeMember(
"PreviousTxnLgrSeq");
287 BEAST_EXPECT( aobj == bobj[i+1]);
293 params[jss::account] = bob.human();
294 params[jss::limit] = 1;
295 for (
int i = 0; i < 4; ++i)
297 auto resp = env.rpc(
"json",
"account_objects",
to_string(params));
298 auto& aobjs = resp[jss::result][jss::account_objects];
299 BEAST_EXPECT( aobjs.size() == 1);
300 auto& aobj = aobjs[0U];
301 if (i < 3) BEAST_EXPECT( resp[jss::result][jss::limit] == 1);
303 aobj.removeMember(
"PreviousTxnID");
304 aobj.removeMember(
"PreviousTxnLgrSeq");
306 BEAST_EXPECT(aobj == bobj[i]);
308 auto resume_marker = resp[jss::result][jss::marker];
309 params[jss::marker] = resume_marker;
316 testcase(
"object types");
322 Account const alice {
"alice" };
324 auto const USD = gw[
"USD"];
330 auto acct_objs = [&env] (Account
const& acct,
char const* type)
333 params[jss::account] = acct.human();
334 params[jss::type] = type;
335 params[jss::ledger_index] =
"validated";
336 return env.rpc(
"json",
"account_objects",
to_string(params));
340 auto acct_objs_is_size = [](
Json::Value const& resp,
unsigned size) {
341 return resp[jss::result][jss::account_objects].
isArray() &&
342 (resp[jss::result][jss::account_objects].
size() == size);
345 env.fund(
XRP(10000), gw, alice);
350 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::account), 0));
351 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::amendments), 0));
352 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::check), 0));
353 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::deposit_preauth), 0));
354 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::directory), 0));
355 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::escrow), 0));
356 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::fee), 0));
357 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::hashes), 0));
358 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::offer), 0));
359 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::payment_channel), 0));
360 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::signer_list), 0));
361 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::state), 0));
362 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::ticket), 0));
365 env.trust(USD(1000), alice);
367 env(
pay(gw, alice, USD(5)));
371 Json::Value const resp = acct_objs (gw, jss::state);
372 BEAST_EXPECT (acct_objs_is_size (resp, 1));
374 auto const& state = resp[jss::result][jss::account_objects][0u];
379 env (check::create (gw, alice, USD(10)));
383 Json::Value const resp = acct_objs (gw, jss::check);
384 BEAST_EXPECT (acct_objs_is_size (resp, 1));
386 auto const&
check = resp[jss::result][jss::account_objects][0u];
392 env (deposit::auth (gw, alice));
396 Json::Value const resp = acct_objs (gw, jss::deposit_preauth);
397 BEAST_EXPECT (acct_objs_is_size (resp, 1));
399 auto const& preauth = resp[jss::result][jss::account_objects][0u];
406 jvEscrow[jss::TransactionType] = jss::EscrowCreate;
408 jvEscrow[jss::Account] = gw.human();
409 jvEscrow[jss::Destination] = gw.human();
410 jvEscrow[jss::Amount] =
413 env.now().time_since_epoch().count() + 1;
419 Json::Value const resp = acct_objs (gw, jss::escrow);
420 BEAST_EXPECT (acct_objs_is_size (resp, 1));
422 auto const&
escrow = resp[jss::result][jss::account_objects][0u];
428 env (offer (gw, USD (7), XRP (14)));
432 Json::Value const resp = acct_objs (gw, jss::offer);
433 BEAST_EXPECT (acct_objs_is_size (resp, 1));
435 auto const&
offer = resp[jss::result][jss::account_objects][0u];
443 jvPayChan[jss::TransactionType] = jss::PaymentChannelCreate;
445 jvPayChan[jss::Account] = gw.human ();
446 jvPayChan[jss::Destination] = alice.human ();
447 jvPayChan[jss::Amount] =
456 Json::Value const resp = acct_objs (gw, jss::payment_channel);
457 BEAST_EXPECT (acct_objs_is_size (resp, 1));
459 auto const&
payChan = resp[jss::result][jss::account_objects][0u];
465 env (signers (gw, 6, { { alice, 7} }));
469 Json::Value const resp = acct_objs (gw, jss::signer_list);
470 BEAST_EXPECT (acct_objs_is_size (resp, 1));
472 auto const& signerList = resp[jss::result][jss::account_objects][0u];
480 env (ticket::create (gw, gw));
484 Json::Value const resp = acct_objs (gw, jss::ticket);
485 BEAST_EXPECT (acct_objs_is_size (resp, 1));
487 auto const& ticket = resp[jss::result][jss::account_objects][0u];
495 params[jss::account] = gw.human();
496 params[jss::deletion_blockers_only] =
true;
497 auto resp = env.rpc(
"json",
"account_objects",
to_string(params));
502 jss::RippleState.c_str(),
503 jss::PayChannel.c_str()};
512 if (BEAST_EXPECT(acct_objs_is_size(resp, expectedAccountObjects)))
514 auto const& aobjs = resp[jss::result][jss::account_objects];
516 gotLedgerTypes.
reserve(expectedAccountObjects);
520 aobjs[i][
"LedgerEntryType"].asString());
523 BEAST_EXPECT(gotLedgerTypes == expectedLedgerTypes);
529 params[jss::account] = gw.human();
530 params[jss::deletion_blockers_only] =
true;
531 params[jss::type] = jss::escrow;
532 auto resp = env.rpc(
"json",
"account_objects",
to_string(params));
534 if (BEAST_EXPECT(acct_objs_is_size(resp, 1u)))
536 auto const& aobjs = resp[jss::result][jss::account_objects];
538 aobjs[0u][
"LedgerEntryType"] == jss::Escrow);
544 for (
int d = 1
'000'032; d >= 1
'000'000; --d)
546 env (offer (gw, USD (1), drops (d)));
551 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::account), 0));
552 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::amendments), 0));
553 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::directory), 0));
554 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::fee), 0));
555 BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::hashes), 0));