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" : "0000000000000000",
38  "Flags" : 65536,
39  "LedgerEntryType" : "Offer",
40  "OwnerNode" : "0000000000000000",
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" : "0000000000000000",
63  "LedgerEntryType" : "RippleState",
64  "LowLimit" : {
65  "currency" : "USD",
66  "issuer" : "r9cZvwKU3zzuZK9JFovGg1JC5n7QiqNL8L",
67  "value" : "0"
68  },
69  "LowNode" : "0000000000000000",
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" : "0000000000000000",
85  "LedgerEntryType" : "RippleState",
86  "LowLimit" : {
87  "currency" : "USD",
88  "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
89  "value" : "0"
90  },
91  "LowNode" : "0000000000000000",
92  "index" : "D89BC239086183EB9458C396E643795C1134963E6550E682A190A5F021766D43"
93 })json",
94  R"json({
95  "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
96  "BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
97  "BookNode" : "0000000000000000",
98  "Flags" : 65536,
99  "LedgerEntryType" : "Offer",
100  "OwnerNode" : "0000000000000000",
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 
291  if (aobj != bobj[i])
292  std::cout << "Fail at " << i << ": " << aobj << std::endl;
293  BEAST_EXPECT(aobj == bobj[i]);
294  }
295  }
296  // test request with type parameter as filter, unstepped
297  {
298  Json::Value params;
299  params[jss::account] = bob.human();
300  params[jss::type] = "state";
301  auto resp = env.rpc("json", "account_objects", to_string(params));
302  BEAST_EXPECT(!resp.isMember(jss::marker));
303 
304  BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 2);
305  for (int i = 0; i < 2; ++i)
306  {
307  auto& aobj = resp[jss::result][jss::account_objects][i];
308  aobj.removeMember("PreviousTxnID");
309  aobj.removeMember("PreviousTxnLgrSeq");
310  BEAST_EXPECT(aobj == bobj[i + 1]);
311  }
312  }
313  // test stepped one-at-a-time with limit=1, resume from prev marker
314  {
315  Json::Value params;
316  params[jss::account] = bob.human();
317  params[jss::limit] = 1;
318  for (int i = 0; i < 4; ++i)
319  {
320  auto resp =
321  env.rpc("json", "account_objects", to_string(params));
322  auto& aobjs = resp[jss::result][jss::account_objects];
323  BEAST_EXPECT(aobjs.size() == 1);
324  auto& aobj = aobjs[0U];
325  if (i < 3)
326  BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
327 
328  aobj.removeMember("PreviousTxnID");
329  aobj.removeMember("PreviousTxnLgrSeq");
330 
331  BEAST_EXPECT(aobj == bobj[i]);
332 
333  auto resume_marker = resp[jss::result][jss::marker];
334  params[jss::marker] = resume_marker;
335  }
336  }
337  }
338 
339  void
341  {
342  testcase("object types");
343 
344  // Give gw a bunch of ledger objects and make sure we can retrieve
345  // them by type.
346  using namespace jtx;
347 
348  Account const alice{"alice"};
349  Account const gw{"gateway"};
350  auto const USD = gw["USD"];
351 
353 
354  // Make a lambda we can use to get "account_objects" easily.
355  auto acct_objs = [&env](Account const& acct, char const* type) {
356  Json::Value params;
357  params[jss::account] = acct.human();
358  params[jss::type] = type;
359  params[jss::ledger_index] = "validated";
360  return env.rpc("json", "account_objects", to_string(params));
361  };
362 
363  // Make a lambda that easily identifies the size of account objects.
364  auto acct_objs_is_size = [](Json::Value const& resp, unsigned size) {
365  return resp[jss::result][jss::account_objects].isArray() &&
366  (resp[jss::result][jss::account_objects].size() == size);
367  };
368 
369  env.fund(XRP(10000), gw, alice);
370  env.close();
371 
372  // Since the account is empty now, all account objects should come
373  // back empty.
374  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::account), 0));
375  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amendments), 0));
376  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::check), 0));
377  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::deposit_preauth), 0));
378  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::directory), 0));
379  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::escrow), 0));
380  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::fee), 0));
381  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hashes), 0));
382  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::offer), 0));
383  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::payment_channel), 0));
384  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::signer_list), 0));
385  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::state), 0));
386  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::ticket), 0));
387 
388  // Set up a trust line so we can find it.
389  env.trust(USD(1000), alice);
390  env.close();
391  env(pay(gw, alice, USD(5)));
392  env.close();
393  {
394  // Find the trustline and make sure it's the right one.
395  Json::Value const resp = acct_objs(gw, jss::state);
396  BEAST_EXPECT(acct_objs_is_size(resp, 1));
397 
398  auto const& state = resp[jss::result][jss::account_objects][0u];
399  BEAST_EXPECT(state[sfBalance.jsonName][jss::value].asInt() == -5);
400  BEAST_EXPECT(
401  state[sfHighLimit.jsonName][jss::value].asUInt() == 1000);
402  }
403  // gw writes a check for USD(10) to alice.
404  env(check::create(gw, alice, USD(10)));
405  env.close();
406  {
407  // Find the check.
408  Json::Value const resp = acct_objs(gw, jss::check);
409  BEAST_EXPECT(acct_objs_is_size(resp, 1));
410 
411  auto const& check = resp[jss::result][jss::account_objects][0u];
412  BEAST_EXPECT(check[sfAccount.jsonName] == gw.human());
413  BEAST_EXPECT(check[sfDestination.jsonName] == alice.human());
414  BEAST_EXPECT(check[sfSendMax.jsonName][jss::value].asUInt() == 10);
415  }
416  // gw preauthorizes payments from alice.
417  env(deposit::auth(gw, alice));
418  env.close();
419  {
420  // Find the preauthorization.
421  Json::Value const resp = acct_objs(gw, jss::deposit_preauth);
422  BEAST_EXPECT(acct_objs_is_size(resp, 1));
423 
424  auto const& preauth = resp[jss::result][jss::account_objects][0u];
425  BEAST_EXPECT(preauth[sfAccount.jsonName] == gw.human());
426  BEAST_EXPECT(preauth[sfAuthorize.jsonName] == alice.human());
427  }
428  {
429  // gw creates an escrow that we can look for in the ledger.
430  Json::Value jvEscrow;
431  jvEscrow[jss::TransactionType] = jss::EscrowCreate;
432  jvEscrow[jss::Flags] = tfUniversal;
433  jvEscrow[jss::Account] = gw.human();
434  jvEscrow[jss::Destination] = gw.human();
435  jvEscrow[jss::Amount] = XRP(100).value().getJson(JsonOptions::none);
436  jvEscrow[sfFinishAfter.jsonName] =
437  env.now().time_since_epoch().count() + 1;
438  env(jvEscrow);
439  env.close();
440  }
441  {
442  // Find the escrow.
443  Json::Value const resp = acct_objs(gw, jss::escrow);
444  BEAST_EXPECT(acct_objs_is_size(resp, 1));
445 
446  auto const& escrow = resp[jss::result][jss::account_objects][0u];
447  BEAST_EXPECT(escrow[sfAccount.jsonName] == gw.human());
448  BEAST_EXPECT(escrow[sfDestination.jsonName] == gw.human());
449  BEAST_EXPECT(escrow[sfAmount.jsonName].asUInt() == 100'000'000);
450  }
451  // gw creates an offer that we can look for in the ledger.
452  env(offer(gw, USD(7), XRP(14)));
453  env.close();
454  {
455  // Find the offer.
456  Json::Value const resp = acct_objs(gw, jss::offer);
457  BEAST_EXPECT(acct_objs_is_size(resp, 1));
458 
459  auto const& offer = resp[jss::result][jss::account_objects][0u];
460  BEAST_EXPECT(offer[sfAccount.jsonName] == gw.human());
461  BEAST_EXPECT(offer[sfTakerGets.jsonName].asUInt() == 14'000'000);
462  BEAST_EXPECT(offer[sfTakerPays.jsonName][jss::value].asUInt() == 7);
463  }
464  {
465  // Create a payment channel from qw to alice that we can look for.
466  Json::Value jvPayChan;
467  jvPayChan[jss::TransactionType] = jss::PaymentChannelCreate;
468  jvPayChan[jss::Flags] = tfUniversal;
469  jvPayChan[jss::Account] = gw.human();
470  jvPayChan[jss::Destination] = alice.human();
471  jvPayChan[jss::Amount] =
472  XRP(300).value().getJson(JsonOptions::none);
473  jvPayChan[sfSettleDelay.jsonName] = 24 * 60 * 60;
474  jvPayChan[sfPublicKey.jsonName] = strHex(gw.pk().slice());
475  env(jvPayChan);
476  env.close();
477  }
478  {
479  // Find the payment channel.
480  Json::Value const resp = acct_objs(gw, jss::payment_channel);
481  BEAST_EXPECT(acct_objs_is_size(resp, 1));
482 
483  auto const& payChan = resp[jss::result][jss::account_objects][0u];
484  BEAST_EXPECT(payChan[sfAccount.jsonName] == gw.human());
485  BEAST_EXPECT(payChan[sfAmount.jsonName].asUInt() == 300'000'000);
486  BEAST_EXPECT(
487  payChan[sfSettleDelay.jsonName].asUInt() == 24 * 60 * 60);
488  }
489  // Make gw multisigning by adding a signerList.
490  env(signers(gw, 6, {{alice, 7}}));
491  env.close();
492  {
493  // Find the signer list.
494  Json::Value const resp = acct_objs(gw, jss::signer_list);
495  BEAST_EXPECT(acct_objs_is_size(resp, 1));
496 
497  auto const& signerList =
498  resp[jss::result][jss::account_objects][0u];
499  BEAST_EXPECT(signerList[sfSignerQuorum.jsonName] == 6);
500  auto const& entry = signerList[sfSignerEntries.jsonName][0u]
502  BEAST_EXPECT(entry[sfAccount.jsonName] == alice.human());
503  BEAST_EXPECT(entry[sfSignerWeight.jsonName].asUInt() == 7);
504  }
505  // Create a Ticket for gw.
506  env(ticket::create(gw, 1));
507  env.close();
508  {
509  // Find the ticket.
510  Json::Value const resp = acct_objs(gw, jss::ticket);
511  BEAST_EXPECT(acct_objs_is_size(resp, 1));
512 
513  auto const& ticket = resp[jss::result][jss::account_objects][0u];
514  BEAST_EXPECT(ticket[sfAccount.jsonName] == gw.human());
515  BEAST_EXPECT(ticket[sfLedgerEntryType.jsonName] == jss::Ticket);
516  BEAST_EXPECT(ticket[sfTicketSequence.jsonName].asUInt() == 12);
517  }
518  {
519  // See how "deletion_blockers_only" handles gw's directory.
520  Json::Value params;
521  params[jss::account] = gw.human();
522  params[jss::deletion_blockers_only] = true;
523  auto resp = env.rpc("json", "account_objects", to_string(params));
524 
525  std::vector<std::string> const expectedLedgerTypes = [] {
527  jss::Escrow.c_str(),
528  jss::Check.c_str(),
529  jss::RippleState.c_str(),
530  jss::PayChannel.c_str()};
531  std::sort(v.begin(), v.end());
532  return v;
533  }();
534 
535  std::uint32_t const expectedAccountObjects{
536  static_cast<std::uint32_t>(std::size(expectedLedgerTypes))};
537 
538  if (BEAST_EXPECT(acct_objs_is_size(resp, expectedAccountObjects)))
539  {
540  auto const& aobjs = resp[jss::result][jss::account_objects];
541  std::vector<std::string> gotLedgerTypes;
542  gotLedgerTypes.reserve(expectedAccountObjects);
543  for (std::uint32_t i = 0; i < expectedAccountObjects; ++i)
544  {
545  gotLedgerTypes.push_back(
546  aobjs[i]["LedgerEntryType"].asString());
547  }
548  std::sort(gotLedgerTypes.begin(), gotLedgerTypes.end());
549  BEAST_EXPECT(gotLedgerTypes == expectedLedgerTypes);
550  }
551  }
552  {
553  // See how "deletion_blockers_only" with `type` handles gw's
554  // directory.
555  Json::Value params;
556  params[jss::account] = gw.human();
557  params[jss::deletion_blockers_only] = true;
558  params[jss::type] = jss::escrow;
559  auto resp = env.rpc("json", "account_objects", to_string(params));
560 
561  if (BEAST_EXPECT(acct_objs_is_size(resp, 1u)))
562  {
563  auto const& aobjs = resp[jss::result][jss::account_objects];
564  BEAST_EXPECT(aobjs[0u]["LedgerEntryType"] == jss::Escrow);
565  }
566  }
567 
568  // Run up the number of directory entries so gw has two
569  // directory nodes.
570  for (int d = 1'000'032; d >= 1'000'000; --d)
571  {
572  env(offer(gw, USD(1), drops(d)));
573  env.close();
574  }
575 
576  // Verify that the non-returning types still don't return anything.
577  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::account), 0));
578  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amendments), 0));
579  BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::directory), 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  }
583 
584  void
585  run() override
586  {
587  testErrors();
589  testObjectTypes();
590  }
591 };
592 
593 BEAST_DEFINE_TESTSUITE(AccountObjects, app, ripple);
594 
595 } // namespace test
596 } // namespace ripple
ripple::test::AccountObjects_test::testObjectTypes
void testObjectTypes()
Definition: AccountObjects_test.cpp:340
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)
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::sfLedgerEntryType
const SF_U16 sfLedgerEntryType(access, STI_UINT16, 1, "LedgerEntryType", SField::sMD_Never)
Definition: SField.h:346
std::vector::reserve
T reserve(T... args)
ripple::sfSignerQuorum
const SF_U32 sfSignerQuorum(access, STI_UINT32, 35, "SignerQuorum")
Definition: SField.h:388
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::sfAccount
const SF_Account sfAccount(access, STI_ACCOUNT, 1, "Account")
Definition: SField.h:481
ripple::sfTakerPays
const SF_Amount sfTakerPays(access, STI_AMOUNT, 4, "TakerPays")
Definition: SField.h:444
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:109
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::sfAmount
const SF_Amount sfAmount(access, STI_AMOUNT, 1, "Amount")
Definition: SField.h:441
ripple::sfSignerEntries
const SField sfSignerEntries(access, STI_ARRAY, 4, "SignerEntries")
Definition: SField.h:518
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:133
ripple::sfHighLimit
const SF_Amount sfHighLimit(access, STI_AMOUNT, 7, "HighLimit")
Definition: SField.h:447
ripple::sfFinishAfter
const SF_U32 sfFinishAfter(access, STI_UINT32, 37, "FinishAfter")
Definition: SField.h:390
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::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
std::cout
std::chrono::time_point::time_since_epoch
T time_since_epoch(T... args)
ripple::sfSendMax
const SF_Amount sfSendMax(access, STI_AMOUNT, 9, "SendMax")
Definition: SField.h:449
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::sfSignerEntry
const SField sfSignerEntry(access, STI_OBJECT, 11, "SignerEntry")
Definition: SField.h:509
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
std::uint32_t
ripple::tfUniversal
const std::uint32_t tfUniversal
Definition: TxFlags.h:49
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
ripple::sfTicketSequence
const SF_U32 sfTicketSequence(access, STI_UINT32, 41, "TicketSequence")
Definition: SField.h:394
ripple::sfPublicKey
const SF_Blob sfPublicKey(access, STI_VL, 1, "PublicKey")
Definition: SField.h:458
ripple::sfSignerWeight
const SF_U16 sfSignerWeight(access, STI_UINT16, 3, "SignerWeight")
Definition: SField.h:348
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
std::endl
T endl(T... args)
ripple::sfBalance
const SF_Amount sfBalance(access, STI_AMOUNT, 2, "Balance")
Definition: SField.h:442
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:585
ripple::sfSettleDelay
const SF_U32 sfSettleDelay(access, STI_UINT32, 39, "SettleDelay")
Definition: SField.h:392
ripple::sfTakerGets
const SF_Amount sfTakerGets(access, STI_AMOUNT, 5, "TakerGets")
Definition: SField.h:445
ripple::featureTicketBatch
const uint256 featureTicketBatch
Definition: Feature.cpp:189
ripple::sfDestination
const SF_Account sfDestination(access, STI_ACCOUNT, 3, "Destination")
Definition: SField.h:483
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:67
std::vector::end
T end(T... args)
ripple::sfAuthorize
const SF_Account sfAuthorize(access, STI_ACCOUNT, 5, "Authorize")
Definition: SField.h:485
ripple::test::bobs_account_objects
static char const * bobs_account_objects[]
Definition: AccountObjects_test.cpp:33
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