rippled
AccountObjects_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2016 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
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>
24 #include <test/jtx.h>
25 
26 #include <boost/utility/string_ref.hpp>
27 
28 #include <algorithm>
29 
30 namespace ripple {
31 namespace test {
32 
33 static char const* bobs_account_objects[] = {
34  R"json({
35  "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
36  "BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000",
37  "BookNode" : "0",
38  "Flags" : 65536,
39  "LedgerEntryType" : "Offer",
40  "OwnerNode" : "0",
41  "Sequence" : 6,
42  "TakerGets" : {
43  "currency" : "USD",
44  "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
45  "value" : "1"
46  },
47  "TakerPays" : "100000000",
48  "index" : "29665262716C19830E26AEEC0916E476FC7D8EF195FF3B4F06829E64F82A3B3E"
49 })json",
50  R"json({
51  "Balance" : {
52  "currency" : "USD",
53  "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
54  "value" : "-1000"
55  },
56  "Flags" : 131072,
57  "HighLimit" : {
58  "currency" : "USD",
59  "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
60  "value" : "1000"
61  },
62  "HighNode" : "0",
63  "LedgerEntryType" : "RippleState",
64  "LowLimit" : {
65  "currency" : "USD",
66  "issuer" : "r9cZvwKU3zzuZK9JFovGg1JC5n7QiqNL8L",
67  "value" : "0"
68  },
69  "LowNode" : "0",
70  "index" : "D13183BCFFC9AAC9F96AEBB5F66E4A652AD1F5D10273AEB615478302BEBFD4A4"
71 })json",
72  R"json({
73  "Balance" : {
74  "currency" : "USD",
75  "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
76  "value" : "-1000"
77  },
78  "Flags" : 131072,
79  "HighLimit" : {
80  "currency" : "USD",
81  "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
82  "value" : "1000"
83  },
84  "HighNode" : "0",
85  "LedgerEntryType" : "RippleState",
86  "LowLimit" : {
87  "currency" : "USD",
88  "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
89  "value" : "0"
90  },
91  "LowNode" : "0",
92  "index" : "D89BC239086183EB9458C396E643795C1134963E6550E682A190A5F021766D43"
93 })json",
94  R"json({
95  "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
96  "BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
97  "BookNode" : "0",
98  "Flags" : 65536,
99  "LedgerEntryType" : "Offer",
100  "OwnerNode" : "0",
101  "Sequence" : 7,
102  "TakerGets" : {
103  "currency" : "USD",
104  "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
105  "value" : "1"
106  },
107  "TakerPays" : "100000000",
108  "index" : "F03ABE26CB8C5F4AFB31A86590BD25C64C5756FCE5CE9704C27AFE291A4A29A1"
109 })json"};
110 
111 class AccountObjects_test : public beast::unit_test::suite
112 {
113 public:
114  void
116  {
117  testcase("error cases");
118 
119  using namespace jtx;
120  Env env(*this);
121 
122  // test error on no account
123  {
124  auto resp = env.rpc("json", "account_objects");
125  BEAST_EXPECT(resp[jss::error_message] == "Syntax error.");
126  }
127  // test error on malformed account string.
128  {
129  Json::Value params;
130  params[jss::account] =
131  "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV";
132  auto resp = env.rpc("json", "account_objects", to_string(params));
133  BEAST_EXPECT(
134  resp[jss::result][jss::error_message] == "Disallowed seed.");
135  }
136  // test error on account that's not in the ledger.
137  {
138  Json::Value params;
139  params[jss::account] = Account{"bogie"}.human();
140  auto resp = env.rpc("json", "account_objects", to_string(params));
141  BEAST_EXPECT(
142  resp[jss::result][jss::error_message] == "Account not found.");
143  }
144  Account const bob{"bob"};
145  // test error on large ledger_index.
146  {
147  Json::Value params;
148  params[jss::account] = bob.human();
149  params[jss::ledger_index] = 10;
150  auto resp = env.rpc("json", "account_objects", to_string(params));
151  BEAST_EXPECT(
152  resp[jss::result][jss::error_message] == "ledgerNotFound");
153  }
154 
155  env.fund(XRP(1000), bob);
156  // test error on type param not a string
157  {
158  Json::Value params;
159  params[jss::account] = bob.human();
160  params[jss::type] = 10;
161  auto resp = env.rpc("json", "account_objects", to_string(params));
162  BEAST_EXPECT(
163  resp[jss::result][jss::error_message] ==
164  "Invalid field 'type', not string.");
165  }
166  // test error on type param not a valid type
167  {
168  Json::Value params;
169  params[jss::account] = bob.human();
170  params[jss::type] = "expedited";
171  auto resp = env.rpc("json", "account_objects", to_string(params));
172  BEAST_EXPECT(
173  resp[jss::result][jss::error_message] ==
174  "Invalid field 'type'.");
175  }
176  // test error on limit -ve
177  {
178  Json::Value params;
179  params[jss::account] = bob.human();
180  params[jss::limit] = -1;
181  auto resp = env.rpc("json", "account_objects", to_string(params));
182  BEAST_EXPECT(
183  resp[jss::result][jss::error_message] ==
184  "Invalid field 'limit', not unsigned integer.");
185  }
186  // test errors on marker
187  {
188  Account const gw{"G"};
189  env.fund(XRP(1000), gw);
190  auto const USD = gw["USD"];
191  env.trust(USD(1000), bob);
192  env(pay(gw, bob, XRP(1)));
193  env(offer(bob, XRP(100), bob["USD"](1)), txflags(tfPassive));
194 
195  Json::Value params;
196  params[jss::account] = bob.human();
197  params[jss::limit] = 1;
198  auto resp = env.rpc("json", "account_objects", to_string(params));
199 
200  auto resume_marker = resp[jss::result][jss::marker];
201  std::string mark = to_string(resume_marker);
202  params[jss::marker] = 10;
203  resp = env.rpc("json", "account_objects", to_string(params));
204  BEAST_EXPECT(
205  resp[jss::result][jss::error_message] ==
206  "Invalid field 'marker', not string.");
207 
208  params[jss::marker] = "This is a string with no comma";
209  resp = env.rpc("json", "account_objects", to_string(params));
210  BEAST_EXPECT(
211  resp[jss::result][jss::error_message] ==
212  "Invalid field 'marker'.");
213 
214  params[jss::marker] = "This string has a comma, but is not hex";
215  resp = env.rpc("json", "account_objects", to_string(params));
216  BEAST_EXPECT(
217  resp[jss::result][jss::error_message] ==
218  "Invalid field 'marker'.");
219 
220  params[jss::marker] = std::string(&mark[1U], 64);
221  resp = env.rpc("json", "account_objects", to_string(params));
222  BEAST_EXPECT(
223  resp[jss::result][jss::error_message] ==
224  "Invalid field 'marker'.");
225 
226  params[jss::marker] = std::string(&mark[1U], 65);
227  resp = env.rpc("json", "account_objects", to_string(params));
228  BEAST_EXPECT(
229  resp[jss::result][jss::error_message] ==
230  "Invalid field 'marker'.");
231 
232  params[jss::marker] = std::string(&mark[1U], 65) + "not hex";
233  resp = env.rpc("json", "account_objects", to_string(params));
234  BEAST_EXPECT(
235  resp[jss::result][jss::error_message] ==
236  "Invalid field 'marker'.");
237 
238  // Should this be an error?
239  // A hex digit is absent from the end of marker.
240  // No account objects returned.
241  params[jss::marker] = std::string(&mark[1U], 128);
242  resp = env.rpc("json", "account_objects", to_string(params));
243  BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
244  }
245  }
246 
247  void
249  {
250  testcase("unsteppedThenStepped");
251 
252  using namespace jtx;
253  Env env(*this);
254 
255  Account const gw1{"G1"};
256  Account const gw2{"G2"};
257  Account const bob{"bob"};
258 
259  auto const USD1 = gw1["USD"];
260  auto const USD2 = gw2["USD"];
261 
262  env.fund(XRP(1000), gw1, gw2, bob);
263  env.trust(USD1(1000), bob);
264  env.trust(USD2(1000), bob);
265 
266  env(pay(gw1, bob, USD1(1000)));
267  env(pay(gw2, bob, USD2(1000)));
268 
269  env(offer(bob, XRP(100), bob["USD"](1)), txflags(tfPassive));
270  env(offer(bob, XRP(100), USD1(1)), txflags(tfPassive));
271 
272  Json::Value bobj[4];
273  for (int i = 0; i < 4; ++i)
274  Json::Reader{}.parse(bobs_account_objects[i], bobj[i]);
275 
276  // test 'unstepped'
277  // i.e. request account objects without explicit limit/marker paging
278  {
279  Json::Value params;
280  params[jss::account] = bob.human();
281  auto resp = env.rpc("json", "account_objects", to_string(params));
282  BEAST_EXPECT(!resp.isMember(jss::marker));
283 
284  BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 4);
285  for (int i = 0; i < 4; ++i)
286  {
287  auto& aobj = resp[jss::result][jss::account_objects][i];
288  aobj.removeMember("PreviousTxnID");
289  aobj.removeMember("PreviousTxnLgrSeq");
290  BEAST_EXPECT(aobj == bobj[i]);
291  }
292  }
293  // test request with type parameter as filter, unstepped
294  {
295  Json::Value params;
296  params[jss::account] = bob.human();
297  params[jss::type] = "state";
298  auto resp = env.rpc("json", "account_objects", to_string(params));
299  BEAST_EXPECT(!resp.isMember(jss::marker));
300 
301  BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 2);
302  for (int i = 0; i < 2; ++i)
303  {
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]);
308  }
309  }
310  // test stepped one-at-a-time with limit=1, resume from prev marker
311  {
312  Json::Value params;
313  params[jss::account] = bob.human();
314  params[jss::limit] = 1;
315  for (int i = 0; i < 4; ++i)
316  {
317  auto resp =
318  env.rpc("json", "account_objects", to_string(params));
319  auto& aobjs = resp[jss::result][jss::account_objects];
320  BEAST_EXPECT(aobjs.size() == 1);
321  auto& aobj = aobjs[0U];
322  if (i < 3)
323  BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
324 
325  aobj.removeMember("PreviousTxnID");
326  aobj.removeMember("PreviousTxnLgrSeq");
327 
328  BEAST_EXPECT(aobj == bobj[i]);
329 
330  auto resume_marker = resp[jss::result][jss::marker];
331  params[jss::marker] = resume_marker;
332  }
333  }
334  }
335 
336  void
338  {
339  testcase("object types");
340 
341  // Give gw a bunch of ledger objects and make sure we can retrieve
342  // them by type.
343  using namespace jtx;
344 
345  Account const alice{"alice"};
346  Account const gw{"gateway"};
347  auto const USD = gw["USD"];
348 
350 
351  // Make a lambda we can use to get "account_objects" easily.
352  auto acct_objs = [&env](Account const& acct, char const* type) {
353  Json::Value params;
354  params[jss::account] = acct.human();
355  params[jss::type] = type;
356  params[jss::ledger_index] = "validated";
357  return env.rpc("json", "account_objects", to_string(params));
358  };
359 
360  // Make a lambda that easily identifies the size of account objects.
361  auto acct_objs_is_size = [](Json::Value const& resp, unsigned size) {
362  return resp[jss::result][jss::account_objects].isArray() &&
363  (resp[jss::result][jss::account_objects].size() == size);
364  };
365 
366  env.fund(XRP(10000), gw, alice);
367  env.close();
368 
369  // Since the account is empty now, all account objects should come
370  // back empty.
371  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::account), 0));
372  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amendments), 0));
373  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::check), 0));
374  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::deposit_preauth), 0));
375  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::directory), 0));
376  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::escrow), 0));
377  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::fee), 0));
378  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hashes), 0));
379  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::offer), 0));
380  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::payment_channel), 0));
381  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::signer_list), 0));
382  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::state), 0));
383  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::ticket), 0));
384 
385  // Set up a trust line so we can find it.
386  env.trust(USD(1000), alice);
387  env.close();
388  env(pay(gw, alice, USD(5)));
389  env.close();
390  {
391  // Find the trustline and make sure it's the right one.
392  Json::Value const resp = acct_objs(gw, jss::state);
393  BEAST_EXPECT(acct_objs_is_size(resp, 1));
394 
395  auto const& state = resp[jss::result][jss::account_objects][0u];
396  BEAST_EXPECT(state[sfBalance.jsonName][jss::value].asInt() == -5);
397  BEAST_EXPECT(
398  state[sfHighLimit.jsonName][jss::value].asUInt() == 1000);
399  }
400  // gw writes a check for USD(10) to alice.
401  env(check::create(gw, alice, USD(10)));
402  env.close();
403  {
404  // Find the check.
405  Json::Value const resp = acct_objs(gw, jss::check);
406  BEAST_EXPECT(acct_objs_is_size(resp, 1));
407 
408  auto const& check = resp[jss::result][jss::account_objects][0u];
409  BEAST_EXPECT(check[sfAccount.jsonName] == gw.human());
410  BEAST_EXPECT(check[sfDestination.jsonName] == alice.human());
411  BEAST_EXPECT(check[sfSendMax.jsonName][jss::value].asUInt() == 10);
412  }
413  // gw preauthorizes payments from alice.
414  env(deposit::auth(gw, alice));
415  env.close();
416  {
417  // Find the preauthorization.
418  Json::Value const resp = acct_objs(gw, jss::deposit_preauth);
419  BEAST_EXPECT(acct_objs_is_size(resp, 1));
420 
421  auto const& preauth = resp[jss::result][jss::account_objects][0u];
422  BEAST_EXPECT(preauth[sfAccount.jsonName] == gw.human());
423  BEAST_EXPECT(preauth[sfAuthorize.jsonName] == alice.human());
424  }
425  {
426  // gw creates an escrow that we can look for in the ledger.
427  Json::Value jvEscrow;
428  jvEscrow[jss::TransactionType] = jss::EscrowCreate;
429  jvEscrow[jss::Flags] = tfUniversal;
430  jvEscrow[jss::Account] = gw.human();
431  jvEscrow[jss::Destination] = gw.human();
432  jvEscrow[jss::Amount] = XRP(100).value().getJson(JsonOptions::none);
433  jvEscrow[sfFinishAfter.jsonName] =
434  env.now().time_since_epoch().count() + 1;
435  env(jvEscrow);
436  env.close();
437  }
438  {
439  // Find the escrow.
440  Json::Value const resp = acct_objs(gw, jss::escrow);
441  BEAST_EXPECT(acct_objs_is_size(resp, 1));
442 
443  auto const& escrow = resp[jss::result][jss::account_objects][0u];
444  BEAST_EXPECT(escrow[sfAccount.jsonName] == gw.human());
445  BEAST_EXPECT(escrow[sfDestination.jsonName] == gw.human());
446  BEAST_EXPECT(escrow[sfAmount.jsonName].asUInt() == 100'000'000);
447  }
448  // gw creates an offer that we can look for in the ledger.
449  env(offer(gw, USD(7), XRP(14)));
450  env.close();
451  {
452  // Find the offer.
453  Json::Value const resp = acct_objs(gw, jss::offer);
454  BEAST_EXPECT(acct_objs_is_size(resp, 1));
455 
456  auto const& offer = resp[jss::result][jss::account_objects][0u];
457  BEAST_EXPECT(offer[sfAccount.jsonName] == gw.human());
458  BEAST_EXPECT(offer[sfTakerGets.jsonName].asUInt() == 14'000'000);
459  BEAST_EXPECT(offer[sfTakerPays.jsonName][jss::value].asUInt() == 7);
460  }
461  {
462  // Create a payment channel from qw to alice that we can look for.
463  Json::Value jvPayChan;
464  jvPayChan[jss::TransactionType] = jss::PaymentChannelCreate;
465  jvPayChan[jss::Flags] = tfUniversal;
466  jvPayChan[jss::Account] = gw.human();
467  jvPayChan[jss::Destination] = alice.human();
468  jvPayChan[jss::Amount] =
469  XRP(300).value().getJson(JsonOptions::none);
470  jvPayChan[sfSettleDelay.jsonName] = 24 * 60 * 60;
471  jvPayChan[sfPublicKey.jsonName] = strHex(gw.pk().slice());
472  env(jvPayChan);
473  env.close();
474  }
475  {
476  // Find the payment channel.
477  Json::Value const resp = acct_objs(gw, jss::payment_channel);
478  BEAST_EXPECT(acct_objs_is_size(resp, 1));
479 
480  auto const& payChan = resp[jss::result][jss::account_objects][0u];
481  BEAST_EXPECT(payChan[sfAccount.jsonName] == gw.human());
482  BEAST_EXPECT(payChan[sfAmount.jsonName].asUInt() == 300'000'000);
483  BEAST_EXPECT(
484  payChan[sfSettleDelay.jsonName].asUInt() == 24 * 60 * 60);
485  }
486  // Make gw multisigning by adding a signerList.
487  env(signers(gw, 6, {{alice, 7}}));
488  env.close();
489  {
490  // Find the signer list.
491  Json::Value const resp = acct_objs(gw, jss::signer_list);
492  BEAST_EXPECT(acct_objs_is_size(resp, 1));
493 
494  auto const& signerList =
495  resp[jss::result][jss::account_objects][0u];
496  BEAST_EXPECT(signerList[sfSignerQuorum.jsonName] == 6);
497  auto const& entry = signerList[sfSignerEntries.jsonName][0u]
499  BEAST_EXPECT(entry[sfAccount.jsonName] == alice.human());
500  BEAST_EXPECT(entry[sfSignerWeight.jsonName].asUInt() == 7);
501  }
502  // Create a Ticket for gw.
503  env(ticket::create(gw, 1));
504  env.close();
505  {
506  // Find the ticket.
507  Json::Value const resp = acct_objs(gw, jss::ticket);
508  BEAST_EXPECT(acct_objs_is_size(resp, 1));
509 
510  auto const& ticket = resp[jss::result][jss::account_objects][0u];
511  BEAST_EXPECT(ticket[sfAccount.jsonName] == gw.human());
512  BEAST_EXPECT(ticket[sfLedgerEntryType.jsonName] == jss::Ticket);
513  BEAST_EXPECT(ticket[sfTicketSequence.jsonName].asUInt() == 12);
514  }
515  {
516  // See how "deletion_blockers_only" handles gw's directory.
517  Json::Value params;
518  params[jss::account] = gw.human();
519  params[jss::deletion_blockers_only] = true;
520  auto resp = env.rpc("json", "account_objects", to_string(params));
521 
522  std::vector<std::string> const expectedLedgerTypes = [] {
524  jss::Escrow.c_str(),
525  jss::Check.c_str(),
526  jss::RippleState.c_str(),
527  jss::PayChannel.c_str()};
528  std::sort(v.begin(), v.end());
529  return v;
530  }();
531 
532  std::uint32_t const expectedAccountObjects{
533  static_cast<std::uint32_t>(std::size(expectedLedgerTypes))};
534 
535  if (BEAST_EXPECT(acct_objs_is_size(resp, expectedAccountObjects)))
536  {
537  auto const& aobjs = resp[jss::result][jss::account_objects];
538  std::vector<std::string> gotLedgerTypes;
539  gotLedgerTypes.reserve(expectedAccountObjects);
540  for (std::uint32_t i = 0; i < expectedAccountObjects; ++i)
541  {
542  gotLedgerTypes.push_back(
543  aobjs[i]["LedgerEntryType"].asString());
544  }
545  std::sort(gotLedgerTypes.begin(), gotLedgerTypes.end());
546  BEAST_EXPECT(gotLedgerTypes == expectedLedgerTypes);
547  }
548  }
549  {
550  // See how "deletion_blockers_only" with `type` handles gw's
551  // directory.
552  Json::Value params;
553  params[jss::account] = gw.human();
554  params[jss::deletion_blockers_only] = true;
555  params[jss::type] = jss::escrow;
556  auto resp = env.rpc("json", "account_objects", to_string(params));
557 
558  if (BEAST_EXPECT(acct_objs_is_size(resp, 1u)))
559  {
560  auto const& aobjs = resp[jss::result][jss::account_objects];
561  BEAST_EXPECT(aobjs[0u]["LedgerEntryType"] == jss::Escrow);
562  }
563  }
564 
565  // Run up the number of directory entries so gw has two
566  // directory nodes.
567  for (int d = 1'000'032; d >= 1'000'000; --d)
568  {
569  env(offer(gw, USD(1), drops(d)));
570  env.close();
571  }
572 
573  // Verify that the non-returning types still don't return anything.
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::directory), 0));
577  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::fee), 0));
578  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hashes), 0));
579  }
580 
581  void
582  run() override
583  {
584  testErrors();
586  testObjectTypes();
587  }
588 };
589 
590 BEAST_DEFINE_TESTSUITE(AccountObjects, app, ripple);
591 
592 } // namespace test
593 } // namespace ripple
ripple::sfSignerWeight
const SF_UINT16 sfSignerWeight
ripple::test::AccountObjects_test::testObjectTypes
void testObjectTypes()
Definition: AccountObjects_test.cpp:337
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountDelete, app, ripple)
ripple::sfSendMax
const SF_AMOUNT sfSendMax
std::string
STL class.
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
ripple::sfDestination
const SF_ACCOUNT sfDestination
ripple::sfAmount
const SF_AMOUNT sfAmount
std::vector::reserve
T reserve(T... args)
ripple::test::AccountObjects_test
Definition: AccountObjects_test.cpp:111
std::vector< std::string >
std::size
T size(T... args)
ripple::tfPassive
const std::uint32_t tfPassive
Definition: TxFlags.h:76
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:109
ripple::sfTicketSequence
const SF_UINT32 sfTicketSequence
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
Json::Reader
Unserialize a JSON document into a Value.
Definition: json_reader.h:36
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:133
std::sort
T sort(T... args)
ripple::test::jtx::Env::trust
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition: Env.cpp:250
algorithm
ripple::sfSignerQuorum
const SF_UINT32 sfSignerQuorum
ripple::test::AccountObjects_test::testUnsteppedThenStepped
void testUnsteppedThenStepped()
Definition: AccountObjects_test.cpp:248
std::vector::push_back
T push_back(T... args)
ripple::test::AccountObjects_test::testErrors
void testErrors()
Definition: AccountObjects_test.cpp:115
ripple::sfTakerPays
const SF_AMOUNT sfTakerPays
std::chrono::time_point::time_since_epoch
T time_since_epoch(T... args)
ripple::sfSettleDelay
const SF_UINT32 sfSettleDelay
ripple::JsonOptions::none
@ none
ripple::test::jtx::txflags
Set the flags on a JTx.
Definition: txflags.h:30
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
ripple::sfTakerGets
const SF_AMOUNT sfTakerGets
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
ripple::sfAuthorize
const SF_ACCOUNT sfAuthorize
std::uint32_t
ripple::sfHighLimit
const SF_AMOUNT sfHighLimit
ripple::sfSignerEntry
const SField sfSignerEntry
ripple::tfUniversal
const std::uint32_t tfUniversal
Definition: TxFlags.h:49
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
ripple::sfSignerEntries
const SField sfSignerEntries
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::sfLedgerEntryType
const SF_UINT16 sfLedgerEntryType
ripple::test::jtx::pay
Json::Value pay(Account const &account, Account const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
ripple::test::jtx::Env::now
NetClock::time_point now()
Returns the current Ripple Network Time.
Definition: Env.h:263
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, boost::optional< std::chrono::milliseconds > consensusDelay=boost::none)
Close and advance the ledger.
Definition: Env.cpp:121
std::vector::begin
T begin(T... args)
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:219
Json::Reader::parse
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:73
ripple::test::AccountObjects_test::run
void run() override
Definition: AccountObjects_test.cpp:582
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::featureTicketBatch
const uint256 featureTicketBatch
Definition: Feature.cpp:189
ripple::sfFinishAfter
const SF_UINT32 sfFinishAfter
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:45
std::vector::end
T end(T... args)
ripple::test::bobs_account_objects
static char const * bobs_account_objects[]
Definition: AccountObjects_test.cpp:33
ripple::sfPublicKey
const SF_VL sfPublicKey
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:115
ripple::test::jtx::Env::rpc
Json::Value rpc(std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:684
Json::Value
Represents a JSON value.
Definition: json_value.h:145