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_value.h>
21 #include <ripple/json/to_string.h>
22 #include <ripple/json/json_reader.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" , R"json({
50  "Balance" : {
51  "currency" : "USD",
52  "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
53  "value" : "-1000"
54  },
55  "Flags" : 131072,
56  "HighLimit" : {
57  "currency" : "USD",
58  "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
59  "value" : "1000"
60  },
61  "HighNode" : "0000000000000000",
62  "LedgerEntryType" : "RippleState",
63  "LowLimit" : {
64  "currency" : "USD",
65  "issuer" : "r9cZvwKU3zzuZK9JFovGg1JC5n7QiqNL8L",
66  "value" : "0"
67  },
68  "LowNode" : "0000000000000000",
69  "index" : "D13183BCFFC9AAC9F96AEBB5F66E4A652AD1F5D10273AEB615478302BEBFD4A4"
70 })json" , R"json({
71  "Balance" : {
72  "currency" : "USD",
73  "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
74  "value" : "-1000"
75  },
76  "Flags" : 131072,
77  "HighLimit" : {
78  "currency" : "USD",
79  "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
80  "value" : "1000"
81  },
82  "HighNode" : "0000000000000000",
83  "LedgerEntryType" : "RippleState",
84  "LowLimit" : {
85  "currency" : "USD",
86  "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
87  "value" : "0"
88  },
89  "LowNode" : "0000000000000000",
90  "index" : "D89BC239086183EB9458C396E643795C1134963E6550E682A190A5F021766D43"
91 })json" , R"json({
92  "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
93  "BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
94  "BookNode" : "0000000000000000",
95  "Flags" : 65536,
96  "LedgerEntryType" : "Offer",
97  "OwnerNode" : "0000000000000000",
98  "Sequence" : 7,
99  "TakerGets" : {
100  "currency" : "USD",
101  "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
102  "value" : "1"
103  },
104  "TakerPays" : "100000000",
105  "index" : "F03ABE26CB8C5F4AFB31A86590BD25C64C5756FCE5CE9704C27AFE291A4A29A1"
106 })json"
107 };
108 
109 class AccountObjects_test : public beast::unit_test::suite
110 {
111 public:
112  void testErrors()
113  {
114  testcase("error cases");
115 
116  using namespace jtx;
117  Env env(*this);
118 
119  // test error on no account
120  {
121  auto resp = env.rpc("json", "account_objects");
122  BEAST_EXPECT( resp[jss::error_message] ==
123  "Syntax error.");
124  }
125  // test error on malformed account string.
126  {
127  Json::Value params;
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.");
131  }
132  // test error on account that's not in the ledger.
133  {
134  Json::Value params;
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.");
138  }
139  Account const bob{ "bob" };
140  // test error on large ledger_index.
141  {
142  Json::Value params;
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");
147  }
148 
149  env.fund(XRP(1000), bob);
150  // test error on type param not a string
151  {
152  Json::Value params;
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.");
158  }
159  // test error on type param not a valid type
160  {
161  Json::Value params;
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'.");
166  }
167  // test error on limit -ve
168  {
169  Json::Value params;
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.");
175  }
176  // test errors on marker
177  {
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)));
183  env(offer(bob, XRP(100), bob["USD"](1)), txflags(tfPassive));
184 
185  Json::Value params;
186  params[jss::account] = bob.human();
187  params[jss::limit] = 1;
188  auto resp = env.rpc("json", "account_objects", to_string(params));
189 
190  auto resume_marker = resp[jss::result][jss::marker];
191  std::string mark = to_string(resume_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.");
195 
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'.");
199 
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'.");
203 
204  params[jss::marker] = std::string(&mark[1U], 64);
205  resp = env.rpc("json", "account_objects", to_string(params));
206  BEAST_EXPECT( resp[jss::result][jss::error_message] == "Invalid field 'marker'.");
207 
208  params[jss::marker] = std::string(&mark[1U], 65);
209  resp = env.rpc("json", "account_objects", to_string(params));
210  BEAST_EXPECT( resp[jss::result][jss::error_message] == "Invalid field 'marker'.");
211 
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'.");
215 
216  // Should this be an error?
217  // A hex digit is absent from the end of marker.
218  // No account objects returned.
219  params[jss::marker] = std::string(&mark[1U], 128);
220  resp = env.rpc("json", "account_objects", to_string(params));
221  BEAST_EXPECT( resp[jss::result][jss::account_objects].size() == 0);
222  }
223  }
224 
226  {
227  testcase("unsteppedThenStepped");
228 
229  using namespace jtx;
230  Env env(*this);
231 
232  Account const gw1{ "G1" };
233  Account const gw2{ "G2" };
234  Account const bob{ "bob" };
235 
236  auto const USD1 = gw1["USD"];
237  auto const USD2 = gw2["USD"];
238 
239  env.fund(XRP(1000), gw1, gw2, bob);
240  env.trust(USD1(1000), bob);
241  env.trust(USD2(1000), bob);
242 
243  env(pay(gw1, bob, USD1(1000)));
244  env(pay(gw2, bob, USD2(1000)));
245 
246  env(offer(bob, XRP(100), bob["USD"](1)),txflags(tfPassive));
247  env(offer(bob, XRP(100), USD1(1)), txflags(tfPassive));
248 
249  Json::Value bobj[4];
250  for (int i = 0; i < 4; ++i)
251  Json::Reader{}.parse(bobs_account_objects[i], bobj[i]);
252 
253  // test 'unstepped'
254  // i.e. request account objects without explicit limit/marker paging
255  {
256  Json::Value params;
257  params[jss::account] = bob.human();
258  auto resp = env.rpc("json", "account_objects", to_string(params));
259  BEAST_EXPECT( !resp.isMember(jss::marker));
260 
261  BEAST_EXPECT( resp[jss::result][jss::account_objects].size() == 4);
262  for (int i = 0; i < 4; ++i)
263  {
264  auto& aobj = resp[jss::result][jss::account_objects][i];
265  aobj.removeMember("PreviousTxnID");
266  aobj.removeMember("PreviousTxnLgrSeq");
267 
268  if (aobj != bobj[i])
269  std::cout << "Fail at " << i << ": " << aobj << std::endl;
270  BEAST_EXPECT(aobj == bobj[i]);
271  }
272  }
273  // test request with type parameter as filter, unstepped
274  {
275  Json::Value params;
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));
280 
281  BEAST_EXPECT( resp[jss::result][jss::account_objects].size() == 2);
282  for (int i = 0; i < 2; ++i)
283  {
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]);
288  }
289  }
290  // test stepped one-at-a-time with limit=1, resume from prev marker
291  {
292  Json::Value params;
293  params[jss::account] = bob.human();
294  params[jss::limit] = 1;
295  for (int i = 0; i < 4; ++i)
296  {
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);
302 
303  aobj.removeMember("PreviousTxnID");
304  aobj.removeMember("PreviousTxnLgrSeq");
305 
306  BEAST_EXPECT(aobj == bobj[i]);
307 
308  auto resume_marker = resp[jss::result][jss::marker];
309  params[jss::marker] = resume_marker;
310  }
311  }
312  }
313 
314  void testObjectTypes()
315  {
316  testcase("object types");
317 
318  // Give gw a bunch of ledger objects and make sure we can retrieve
319  // them by type.
320  using namespace jtx;
321 
322  Account const alice { "alice" };
323  Account const gw{ "gateway" };
324  auto const USD = gw["USD"];
325 
326  // Test for ticket account objects when they are supported.
327  Env env(*this, supported_amendments().set(featureTickets));
328 
329  // Make a lambda we can use to get "account_objects" easily.
330  auto acct_objs = [&env] (Account const& acct, char const* type)
331  {
332  Json::Value params;
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));
337  };
338 
339  // Make a lambda that easily identifies the size of account objects.
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);
343  };
344 
345  env.fund(XRP(10000), gw, alice);
346  env.close();
347 
348  // Since the account is empty now, all account objects should come
349  // back empty.
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));
363 
364  // Set up a trust line so we can find it.
365  env.trust(USD(1000), alice);
366  env.close();
367  env(pay(gw, alice, USD(5)));
368  env.close();
369  {
370  // Find the trustline and make sure it's the right one.
371  Json::Value const resp = acct_objs (gw, jss::state);
372  BEAST_EXPECT (acct_objs_is_size (resp, 1));
373 
374  auto const& state = resp[jss::result][jss::account_objects][0u];
375  BEAST_EXPECT (state[sfBalance.jsonName][jss::value].asInt() == -5);
376  BEAST_EXPECT (state[sfHighLimit.jsonName][jss::value].asUInt() == 1000);
377  }
378  // gw writes a check for USD(10) to alice.
379  env (check::create (gw, alice, USD(10)));
380  env.close();
381  {
382  // Find the check.
383  Json::Value const resp = acct_objs (gw, jss::check);
384  BEAST_EXPECT (acct_objs_is_size (resp, 1));
385 
386  auto const& check = resp[jss::result][jss::account_objects][0u];
387  BEAST_EXPECT (check[sfAccount.jsonName] == gw.human());
388  BEAST_EXPECT (check[sfDestination.jsonName] == alice.human());
389  BEAST_EXPECT (check[sfSendMax.jsonName][jss::value].asUInt() == 10);
390  }
391  // gw preauthorizes payments from alice.
392  env (deposit::auth (gw, alice));
393  env.close();
394  {
395  // Find the preauthorization.
396  Json::Value const resp = acct_objs (gw, jss::deposit_preauth);
397  BEAST_EXPECT (acct_objs_is_size (resp, 1));
398 
399  auto const& preauth = resp[jss::result][jss::account_objects][0u];
400  BEAST_EXPECT (preauth[sfAccount.jsonName] == gw.human());
401  BEAST_EXPECT (preauth[sfAuthorize.jsonName] == alice.human());
402  }
403  {
404  // gw creates an escrow that we can look for in the ledger.
405  Json::Value jvEscrow;
406  jvEscrow[jss::TransactionType] = jss::EscrowCreate;
407  jvEscrow[jss::Flags] = tfUniversal;
408  jvEscrow[jss::Account] = gw.human();
409  jvEscrow[jss::Destination] = gw.human();
410  jvEscrow[jss::Amount] =
411  XRP(100).value().getJson(JsonOptions::none);
412  jvEscrow[sfFinishAfter.jsonName] =
413  env.now().time_since_epoch().count() + 1;
414  env (jvEscrow);
415  env.close();
416  }
417  {
418  // Find the escrow.
419  Json::Value const resp = acct_objs (gw, jss::escrow);
420  BEAST_EXPECT (acct_objs_is_size (resp, 1));
421 
422  auto const& escrow = resp[jss::result][jss::account_objects][0u];
423  BEAST_EXPECT (escrow[sfAccount.jsonName] == gw.human());
424  BEAST_EXPECT (escrow[sfDestination.jsonName] == gw.human());
425  BEAST_EXPECT (escrow[sfAmount.jsonName].asUInt() == 100'000'000);
426  }
427  // gw creates an offer that we can look for in the ledger.
428  env (offer (gw, USD (7), XRP (14)));
429  env.close();
430  {
431  // Find the offer.
432  Json::Value const resp = acct_objs (gw, jss::offer);
433  BEAST_EXPECT (acct_objs_is_size (resp, 1));
434 
435  auto const& offer = resp[jss::result][jss::account_objects][0u];
436  BEAST_EXPECT (offer[sfAccount.jsonName] == gw.human());
437  BEAST_EXPECT (offer[sfTakerGets.jsonName].asUInt() == 14'000'000);
438  BEAST_EXPECT (offer[sfTakerPays.jsonName][jss::value].asUInt() == 7);
439  }
440  {
441  // Create a payment channel from qw to alice that we can look for.
442  Json::Value jvPayChan;
443  jvPayChan[jss::TransactionType] = jss::PaymentChannelCreate;
444  jvPayChan[jss::Flags] = tfUniversal;
445  jvPayChan[jss::Account] = gw.human ();
446  jvPayChan[jss::Destination] = alice.human ();
447  jvPayChan[jss::Amount] =
448  XRP (300).value().getJson (JsonOptions::none);
449  jvPayChan[sfSettleDelay.jsonName] = 24 * 60 * 60;
450  jvPayChan[sfPublicKey.jsonName] = strHex (gw.pk().slice ());
451  env (jvPayChan);
452  env.close();
453  }
454  {
455  // Find the payment channel.
456  Json::Value const resp = acct_objs (gw, jss::payment_channel);
457  BEAST_EXPECT (acct_objs_is_size (resp, 1));
458 
459  auto const& payChan = resp[jss::result][jss::account_objects][0u];
460  BEAST_EXPECT (payChan[sfAccount.jsonName] == gw.human());
461  BEAST_EXPECT (payChan[sfAmount.jsonName].asUInt() == 300'000'000);
462  BEAST_EXPECT (payChan[sfSettleDelay.jsonName].asUInt() == 24 * 60 * 60);
463  }
464  // Make gw multisigning by adding a signerList.
465  env (signers (gw, 6, { { alice, 7} }));
466  env.close();
467  {
468  // Find the signer list.
469  Json::Value const resp = acct_objs (gw, jss::signer_list);
470  BEAST_EXPECT (acct_objs_is_size (resp, 1));
471 
472  auto const& signerList = resp[jss::result][jss::account_objects][0u];
473  BEAST_EXPECT (signerList[sfSignerQuorum.jsonName] == 6);
474  auto const& entry =
476  BEAST_EXPECT (entry[sfAccount.jsonName] == alice.human());
477  BEAST_EXPECT (entry[sfSignerWeight.jsonName].asUInt() == 7);
478  }
479  // Create a Ticket for gw.
480  env (ticket::create (gw, gw));
481  env.close();
482  {
483  // Find the ticket.
484  Json::Value const resp = acct_objs (gw, jss::ticket);
485  BEAST_EXPECT (acct_objs_is_size (resp, 1));
486 
487  auto const& ticket = resp[jss::result][jss::account_objects][0u];
488  BEAST_EXPECT (ticket[sfAccount.jsonName] == gw.human());
489  BEAST_EXPECT (ticket[sfLedgerEntryType.jsonName] == jss::Ticket);
490  BEAST_EXPECT (ticket[sfSequence.jsonName].asUInt() == 11);
491  }
492  {
493  // See how "deletion_blockers_only" handles gw's directory.
494  Json::Value params;
495  params[jss::account] = gw.human();
496  params[jss::deletion_blockers_only] = true;
497  auto resp = env.rpc("json", "account_objects", to_string(params));
498 
499  std::vector<std::string> const expectedLedgerTypes = [] {
500  std::vector<std::string> v{jss::Escrow.c_str(),
501  jss::Check.c_str(),
502  jss::RippleState.c_str(),
503  jss::PayChannel.c_str()};
504  std::sort(v.begin(), v.end());
505  return v;
506  }();
507 
508  std::uint32_t const expectedAccountObjects{
509  static_cast<std::uint32_t>(std::size(expectedLedgerTypes))
510  };
511 
512  if (BEAST_EXPECT(acct_objs_is_size(resp, expectedAccountObjects)))
513  {
514  auto const& aobjs = resp[jss::result][jss::account_objects];
515  std::vector<std::string> gotLedgerTypes;
516  gotLedgerTypes.reserve(expectedAccountObjects);
517  for (std::uint32_t i = 0; i < expectedAccountObjects; ++i)
518  {
519  gotLedgerTypes.push_back(
520  aobjs[i]["LedgerEntryType"].asString());
521  }
522  std::sort(gotLedgerTypes.begin(), gotLedgerTypes.end());
523  BEAST_EXPECT(gotLedgerTypes == expectedLedgerTypes);
524  }
525  }
526  {
527  // See how "deletion_blockers_only" with `type` handles gw's directory.
528  Json::Value params;
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));
533 
534  if (BEAST_EXPECT(acct_objs_is_size(resp, 1u)))
535  {
536  auto const& aobjs = resp[jss::result][jss::account_objects];
537  BEAST_EXPECT(
538  aobjs[0u]["LedgerEntryType"] == jss::Escrow);
539  }
540  }
541 
542  // Run up the number of directory entries so gw has two
543  // directory nodes.
544  for (int d = 1'000'032; d >= 1'000'000; --d)
545  {
546  env (offer (gw, USD (1), drops (d)));
547  env.close();
548  }
549 
550  // Verify that the non-returning types still don't return anything.
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));
556  }
557 
558  void run() override
559  {
560  testErrors();
562  testObjectTypes();
563  }
564 };
565 
566 BEAST_DEFINE_TESTSUITE(AccountObjects,app,ripple);
567 
568 }
569 }
570 
ripple::test::AccountObjects_test::testObjectTypes
void testObjectTypes()
Definition: AccountObjects_test.cpp:320
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:109
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountDelete, app, ripple)
std::string
STL class.
ripple::sfLedgerEntryType
const SF_U16 sfLedgerEntryType(access, STI_UINT16, 1, "LedgerEntryType", SField::sMD_Never)
Definition: SField.h:330
std::vector::reserve
T reserve(T... args)
ripple::sfSignerQuorum
const SF_U32 sfSignerQuorum(access, STI_UINT32, 35, "SignerQuorum")
Definition: SField.h:372
std::vector< std::string >
std::size
T size(T... args)
ripple::sfSequence
const SF_U32 sfSequence(access, STI_UINT32, 4, "Sequence")
Definition: SField.h:340
ripple::tfPassive
const std::uint32_t tfPassive
Definition: TxFlags.h:76
ripple::keylet::payChan
Keylet payChan(AccountID const &source, AccountID const &dst, std::uint32_t seq)
A PaymentChannel.
Definition: Indexes.cpp:350
ripple::sfAccount
const SF_Account sfAccount(access, STI_ACCOUNT, 1, "Account")
Definition: SField.h:460
ripple::sfTakerPays
const SF_Amount sfTakerPays(access, STI_AMOUNT, 4, "TakerPays")
Definition: SField.h:426
Json::check
void check(bool condition, std::string const &message)
Definition: json/Writer.h:234
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
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:423
ripple::sfSignerEntries
const SField sfSignerEntries(access, STI_ARRAY, 4, "SignerEntries")
Definition: SField.h:496
ripple::test::jtx::offer
Json::Value offer(Account const &account, STAmount const &in, STAmount const &out, std::uint32_t flags)
Create an offer.
Definition: offer.cpp:28
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:140
ripple::sfHighLimit
const SF_Amount sfHighLimit(access, STI_AMOUNT, 7, "HighLimit")
Definition: SField.h:429
ripple::sfFinishAfter
const SF_U32 sfFinishAfter(access, STI_UINT32, 37, "FinishAfter")
Definition: SField.h:374
std::sort
T sort(T... args)
algorithm
ripple::test::AccountObjects_test::testUnsteppedThenStepped
void testUnsteppedThenStepped()
Definition: AccountObjects_test.cpp:231
std::vector::push_back
T push_back(T... args)
ripple::test::AccountObjects_test::testErrors
void testErrors()
Definition: AccountObjects_test.cpp:118
std::cout
ripple::sfSendMax
const SF_Amount sfSendMax(access, STI_AMOUNT, 9, "SendMax")
Definition: SField.h:431
ripple::JsonOptions::none
@ none
ripple::keylet::escrow
Keylet escrow(AccountID const &source, std::uint32_t seq)
An escrow entry.
Definition: Indexes.cpp:339
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:271
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:720
ripple::sfSignerEntry
const SField sfSignerEntry(access, STI_OBJECT, 11, "SignerEntry")
Definition: SField.h:488
std::uint32_t
ripple::featureTickets
const uint256 featureTickets
Definition: Feature.cpp:157
ripple::tfUniversal
const std::uint32_t tfUniversal
Definition: TxFlags.h:49
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1056
ripple::sfPublicKey
const SF_Blob sfPublicKey(access, STI_VL, 1, "PublicKey")
Definition: SField.h:440
ripple::sfSignerWeight
const SF_U16 sfSignerWeight(access, STI_UINT16, 3, "SignerWeight")
Definition: SField.h:332
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:424
ripple::test::jtx::pay
Json::Value pay(Account const &account, Account const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
std::vector::begin
T begin(T... args)
Json::Reader::parse
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:76
ripple::test::AccountObjects_test::run
void run() override
Definition: AccountObjects_test.cpp:564
ripple::sfSettleDelay
const SF_U32 sfSettleDelay(access, STI_UINT32, 39, "SettleDelay")
Definition: SField.h:376
ripple::sfTakerGets
const SF_Amount sfTakerGets(access, STI_AMOUNT, 5, "TakerGets")
Definition: SField.h:427
ripple::sfDestination
const SF_Account sfDestination(access, STI_ACCOUNT, 3, "Destination")
Definition: SField.h:462
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:70
std::vector::end
T end(T... args)
ripple::sfAuthorize
const SF_Account sfAuthorize(access, STI_ACCOUNT, 5, "Authorize")
Definition: SField.h:464
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:117
Json::Value
Represents a JSON value.
Definition: json_value.h:141