rippled
LedgerRPC_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-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/app/misc/Manifest.h>
21 #include <ripple/app/misc/TxQ.h>
22 #include <ripple/basics/StringUtilities.h>
23 #include <ripple/beast/unit_test.h>
24 #include <ripple/protocol/ErrorCodes.h>
25 #include <ripple/protocol/Feature.h>
26 #include <ripple/protocol/jss.h>
27 #include <test/jtx.h>
28 
29 namespace ripple {
30 
31 class LedgerRPC_test : public beast::unit_test::suite
32 {
33  void
35  Json::Value const& jv,
36  std::string const& err,
37  std::string const& msg)
38  {
39  if (BEAST_EXPECT(jv.isMember(jss::status)))
40  BEAST_EXPECT(jv[jss::status] == "error");
41  if (BEAST_EXPECT(jv.isMember(jss::error)))
42  BEAST_EXPECT(jv[jss::error] == err);
43  if (msg.empty())
44  {
45  BEAST_EXPECT(
46  jv[jss::error_message] == Json::nullValue ||
47  jv[jss::error_message] == "");
48  }
49  else if (BEAST_EXPECT(jv.isMember(jss::error_message)))
50  BEAST_EXPECT(jv[jss::error_message] == msg);
51  }
52 
53  // Corrupt a valid address by replacing the 10th character with '!'.
54  // '!' is not part of the ripple alphabet.
57  {
58  std::string ret = std::move(good);
59  ret.replace(10, 1, 1, '!');
60  return ret;
61  }
62 
63  void
65  {
66  testcase("Basic Request");
67  using namespace test::jtx;
68 
69  Env env{*this};
70 
71  env.close();
72  BEAST_EXPECT(env.current()->info().seq == 4);
73 
74  {
75  Json::Value jvParams;
76  // can be either numeric or quoted numeric
77  jvParams[jss::ledger_index] = 1;
78  auto const jrr =
79  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
80  BEAST_EXPECT(jrr[jss::ledger][jss::closed] == true);
81  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "1");
82  BEAST_EXPECT(jrr[jss::ledger][jss::accepted] == true);
83  BEAST_EXPECT(
84  jrr[jss::ledger][jss::totalCoins] ==
85  env.balance(env.master).value().getText());
86  }
87 
88  {
89  Json::Value jvParams;
90  jvParams[jss::ledger_index] = "1";
91  auto const jrr =
92  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
93  BEAST_EXPECT(jrr[jss::ledger][jss::closed] == true);
94  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "1");
95  BEAST_EXPECT(jrr[jss::ledger][jss::accepted] == true);
96  BEAST_EXPECT(
97  jrr[jss::ledger][jss::totalCoins] ==
98  env.balance(env.master).value().getText());
99  }
100 
101  {
102  // using current identifier
103  auto const jrr = env.rpc("ledger", "current")[jss::result];
104  BEAST_EXPECT(jrr[jss::ledger][jss::closed] == false);
105  BEAST_EXPECT(
106  jrr[jss::ledger][jss::ledger_index] ==
107  std::to_string(env.current()->info().seq));
108  BEAST_EXPECT(
109  jrr[jss::ledger_current_index] == env.current()->info().seq);
110  }
111  }
112 
113  void
115  {
116  testcase("Bad Input");
117  using namespace test::jtx;
118  Env env{*this};
119  Account const gw{"gateway"};
120  auto const USD = gw["USD"];
121  Account const bob{"bob"};
122 
123  env.fund(XRP(10000), gw, bob);
124  env.close();
125  env.trust(USD(1000), bob);
126  env.close();
127 
128  {
129  // ask for an arbitrary string - index
130  Json::Value jvParams;
131  jvParams[jss::ledger_index] = "potato";
132  auto const jrr =
133  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
134  checkErrorValue(jrr, "invalidParams", "ledgerIndexMalformed");
135  }
136 
137  {
138  // ask for a negative index
139  Json::Value jvParams;
140  jvParams[jss::ledger_index] = -1;
141  auto const jrr =
142  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
143  checkErrorValue(jrr, "invalidParams", "ledgerIndexMalformed");
144  }
145 
146  {
147  // ask for a bad ledger index
148  Json::Value jvParams;
149  jvParams[jss::ledger_index] = 10u;
150  auto const jrr =
151  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
152  checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound");
153  }
154 
155  {
156  // unrecognized string arg -- error
157  auto const jrr = env.rpc("ledger", "arbitrary_text")[jss::result];
158  checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound");
159  }
160 
161  {
162  // Request queue for closed ledger
163  Json::Value jvParams;
164  jvParams[jss::ledger_index] = "validated";
165  jvParams[jss::queue] = true;
166  auto const jrr =
167  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
168  checkErrorValue(jrr, "invalidParams", "Invalid parameters.");
169  }
170 
171  {
172  // Request a ledger with a very large (double) sequence.
173  auto const ret =
174  env.rpc("json", "ledger", "{ \"ledger_index\" : 2e15 }");
175  BEAST_EXPECT(RPC::contains_error(ret));
176  BEAST_EXPECT(ret[jss::error_message] == "Invalid parameters.");
177  }
178 
179  {
180  // Request a ledger with very large (integer) sequence.
181  auto const ret = env.rpc(
182  "json", "ledger", "{ \"ledger_index\" : 1000000000000000 }");
183  checkErrorValue(ret, "invalidParams", "Invalid parameters.");
184  }
185  }
186 
187  void
189  {
190  testcase("ledger_current Request");
191  using namespace test::jtx;
192 
193  Env env{*this};
194 
195  env.close();
196  BEAST_EXPECT(env.current()->info().seq == 4);
197 
198  {
199  auto const jrr = env.rpc("ledger_current")[jss::result];
200  BEAST_EXPECT(
201  jrr[jss::ledger_current_index] == env.current()->info().seq);
202  }
203  }
204 
205  void
207  {
208  testcase("Missing ledger_entry ledger_hash");
209  using namespace test::jtx;
210  Env env{*this};
211  Account const alice{"alice"};
212  env.fund(XRP(10000), alice);
213  env.close();
214 
215  Json::Value jvParams;
216  jvParams[jss::account_root] = alice.human();
217  jvParams[jss::ledger_hash] =
218  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
219  auto const jrr =
220  env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
221  checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound");
222  }
223 
224  void
226  {
227  testcase("Ledger Request, Full Option");
228  using namespace test::jtx;
229 
230  Env env{*this};
231 
232  env.close();
233 
234  Json::Value jvParams;
235  jvParams[jss::ledger_index] = 3u;
236  jvParams[jss::full] = true;
237  auto const jrr =
238  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
239  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
240  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
241  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 2u);
242  }
243 
244  void
246  {
247  testcase("Ledger Request, Full Option Without Admin");
248  using namespace test::jtx;
249 
250  Env env{*this, envconfig(no_admin)};
251 
252  env.close();
253 
254  Json::Value jvParams;
255  jvParams[jss::ledger_index] = 3u;
256  jvParams[jss::full] = true;
257  auto const jrr =
258  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
260  jrr, "noPermission", "You don't have permission for this command.");
261  }
262 
263  void
265  {
266  testcase("Ledger Request, Accounts Option");
267  using namespace test::jtx;
268 
269  Env env{*this};
270 
271  env.close();
272 
273  Json::Value jvParams;
274  jvParams[jss::ledger_index] = 3u;
275  jvParams[jss::accounts] = true;
276  auto const jrr =
277  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
278  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
279  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
280  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 2u);
281  }
282 
283  void
285  {
286  testcase("ledger_entry Request AccountRoot");
287  using namespace test::jtx;
288  Env env{*this};
289  Account const alice{"alice"};
290  env.fund(XRP(10000), alice);
291  env.close();
292 
293  std::string const ledgerHash{to_string(env.closed()->info().hash)};
294  {
295  // Exercise ledger_closed along the way.
296  Json::Value const jrr = env.rpc("ledger_closed")[jss::result];
297  BEAST_EXPECT(jrr[jss::ledger_hash] == ledgerHash);
298  BEAST_EXPECT(jrr[jss::ledger_index] == 3);
299  }
300 
301  std::string accountRootIndex;
302  {
303  // Request alice's account root.
304  Json::Value jvParams;
305  jvParams[jss::account_root] = alice.human();
306  jvParams[jss::ledger_hash] = ledgerHash;
307  Json::Value const jrr = env.rpc(
308  "json", "ledger_entry", to_string(jvParams))[jss::result];
309  BEAST_EXPECT(jrr.isMember(jss::node));
310  BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
311  BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] == "10000000000");
312  accountRootIndex = jrr[jss::index].asString();
313  }
314  {
315  constexpr char alicesAcctRootBinary[]{
316  "1100612200800000240000000425000000032D00000000559CE54C3B934E4"
317  "73A995B477E92EC229F99CED5B62BF4D2ACE4DC42719103AE2F6240000002"
318  "540BE4008114AE123A8556F3CF91154711376AFB0F894F832B3D"};
319 
320  // Request alice's account root, but with binary == true;
321  Json::Value jvParams;
322  jvParams[jss::account_root] = alice.human();
323  jvParams[jss::binary] = 1;
324  jvParams[jss::ledger_hash] = ledgerHash;
325  Json::Value const jrr = env.rpc(
326  "json", "ledger_entry", to_string(jvParams))[jss::result];
327  BEAST_EXPECT(jrr.isMember(jss::node_binary));
328  BEAST_EXPECT(jrr[jss::node_binary] == alicesAcctRootBinary);
329  }
330  {
331  // Request alice's account root using the index.
332  Json::Value jvParams;
333  jvParams[jss::index] = accountRootIndex;
334  Json::Value const jrr = env.rpc(
335  "json", "ledger_entry", to_string(jvParams))[jss::result];
336  BEAST_EXPECT(!jrr.isMember(jss::node_binary));
337  BEAST_EXPECT(jrr.isMember(jss::node));
338  BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
339  BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] == "10000000000");
340  }
341  {
342  // Request alice's account root by index, but with binary == false.
343  Json::Value jvParams;
344  jvParams[jss::index] = accountRootIndex;
345  jvParams[jss::binary] = 0;
346  Json::Value const jrr = env.rpc(
347  "json", "ledger_entry", to_string(jvParams))[jss::result];
348  BEAST_EXPECT(jrr.isMember(jss::node));
349  BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
350  BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] == "10000000000");
351  }
352  {
353  // Request using a corrupted AccountID.
354  Json::Value jvParams;
355  jvParams[jss::account_root] = makeBadAddress(alice.human());
356  jvParams[jss::ledger_hash] = ledgerHash;
357  Json::Value const jrr = env.rpc(
358  "json", "ledger_entry", to_string(jvParams))[jss::result];
359  checkErrorValue(jrr, "malformedAddress", "");
360  }
361  {
362  // Request an account that is not in the ledger.
363  Json::Value jvParams;
364  jvParams[jss::account_root] = Account("bob").human();
365  jvParams[jss::ledger_hash] = ledgerHash;
366  Json::Value const jrr = env.rpc(
367  "json", "ledger_entry", to_string(jvParams))[jss::result];
368  checkErrorValue(jrr, "entryNotFound", "");
369  }
370  }
371 
372  void
374  {
375  testcase("ledger_entry Request Check");
376  using namespace test::jtx;
377  Env env{*this};
378  Account const alice{"alice"};
379  env.fund(XRP(10000), alice);
380  env.close();
381 
382  auto const checkId = keylet::check(env.master, env.seq(env.master));
383 
384  env(check::create(env.master, alice, XRP(100)));
385  env.close();
386 
387  std::string const ledgerHash{to_string(env.closed()->info().hash)};
388  {
389  // Request a check.
390  Json::Value jvParams;
391  jvParams[jss::check] = to_string(checkId.key);
392  jvParams[jss::ledger_hash] = ledgerHash;
393  Json::Value const jrr = env.rpc(
394  "json", "ledger_entry", to_string(jvParams))[jss::result];
395  BEAST_EXPECT(
396  jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check);
397  BEAST_EXPECT(jrr[jss::node][sfSendMax.jsonName] == "100000000");
398  }
399  {
400  // Request an index that is not a check. We'll use alice's
401  // account root index.
402  std::string accountRootIndex;
403  {
404  Json::Value jvParams;
405  jvParams[jss::account_root] = alice.human();
406  Json::Value const jrr = env.rpc(
407  "json", "ledger_entry", to_string(jvParams))[jss::result];
408  accountRootIndex = jrr[jss::index].asString();
409  }
410  Json::Value jvParams;
411  jvParams[jss::check] = accountRootIndex;
412  jvParams[jss::ledger_hash] = ledgerHash;
413  Json::Value const jrr = env.rpc(
414  "json", "ledger_entry", to_string(jvParams))[jss::result];
415  checkErrorValue(jrr, "malformedRequest", "");
416  }
417  }
418 
419  void
421  {
422  testcase("ledger_entry Deposit Preauth");
423 
424  using namespace test::jtx;
425 
426  Env env{*this};
427  Account const alice{"alice"};
428  Account const becky{"becky"};
429 
430  env.fund(XRP(10000), alice, becky);
431  env.close();
432 
433  env(deposit::auth(alice, becky));
434  env.close();
435 
436  std::string const ledgerHash{to_string(env.closed()->info().hash)};
437  std::string depositPreauthIndex;
438  {
439  // Request a depositPreauth by owner and authorized.
440  Json::Value jvParams;
441  jvParams[jss::deposit_preauth][jss::owner] = alice.human();
442  jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
443  jvParams[jss::ledger_hash] = ledgerHash;
444  Json::Value const jrr = env.rpc(
445  "json", "ledger_entry", to_string(jvParams))[jss::result];
446 
447  BEAST_EXPECT(
448  jrr[jss::node][sfLedgerEntryType.jsonName] ==
449  jss::DepositPreauth);
450  BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human());
451  BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == becky.human());
452  depositPreauthIndex = jrr[jss::node][jss::index].asString();
453  }
454  {
455  // Request a depositPreauth by index.
456  Json::Value jvParams;
457  jvParams[jss::deposit_preauth] = depositPreauthIndex;
458  jvParams[jss::ledger_hash] = ledgerHash;
459  Json::Value const jrr = env.rpc(
460  "json", "ledger_entry", to_string(jvParams))[jss::result];
461 
462  BEAST_EXPECT(
463  jrr[jss::node][sfLedgerEntryType.jsonName] ==
464  jss::DepositPreauth);
465  BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human());
466  BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == becky.human());
467  }
468  {
469  // Malformed request: deposit_preauth neither object nor string.
470  Json::Value jvParams;
471  jvParams[jss::deposit_preauth] = -5;
472  jvParams[jss::ledger_hash] = ledgerHash;
473  Json::Value const jrr = env.rpc(
474  "json", "ledger_entry", to_string(jvParams))[jss::result];
475  checkErrorValue(jrr, "malformedRequest", "");
476  }
477  {
478  // Malformed request: deposit_preauth not hex string.
479  Json::Value jvParams;
480  jvParams[jss::deposit_preauth] = "0123456789ABCDEFG";
481  jvParams[jss::ledger_hash] = ledgerHash;
482  Json::Value const jrr = env.rpc(
483  "json", "ledger_entry", to_string(jvParams))[jss::result];
484  checkErrorValue(jrr, "malformedRequest", "");
485  }
486  {
487  // Malformed request: missing [jss::deposit_preauth][jss::owner]
488  Json::Value jvParams;
489  jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
490  jvParams[jss::ledger_hash] = ledgerHash;
491  Json::Value const jrr = env.rpc(
492  "json", "ledger_entry", to_string(jvParams))[jss::result];
493  checkErrorValue(jrr, "malformedRequest", "");
494  }
495  {
496  // Malformed request: [jss::deposit_preauth][jss::owner] not string.
497  Json::Value jvParams;
498  jvParams[jss::deposit_preauth][jss::owner] = 7;
499  jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
500  jvParams[jss::ledger_hash] = ledgerHash;
501  Json::Value const jrr = env.rpc(
502  "json", "ledger_entry", to_string(jvParams))[jss::result];
503  checkErrorValue(jrr, "malformedRequest", "");
504  }
505  {
506  // Malformed: missing [jss::deposit_preauth][jss::authorized]
507  Json::Value jvParams;
508  jvParams[jss::deposit_preauth][jss::owner] = alice.human();
509  jvParams[jss::ledger_hash] = ledgerHash;
510  Json::Value const jrr = env.rpc(
511  "json", "ledger_entry", to_string(jvParams))[jss::result];
512  checkErrorValue(jrr, "malformedRequest", "");
513  }
514  {
515  // Malformed: [jss::deposit_preauth][jss::authorized] not string.
516  Json::Value jvParams;
517  jvParams[jss::deposit_preauth][jss::owner] = alice.human();
518  jvParams[jss::deposit_preauth][jss::authorized] = 47;
519  jvParams[jss::ledger_hash] = ledgerHash;
520  Json::Value const jrr = env.rpc(
521  "json", "ledger_entry", to_string(jvParams))[jss::result];
522  checkErrorValue(jrr, "malformedRequest", "");
523  }
524  {
525  // Malformed: [jss::deposit_preauth][jss::owner] is malformed.
526  Json::Value jvParams;
527  jvParams[jss::deposit_preauth][jss::owner] =
528  "rP6P9ypfAmc!pw8SZHNwM4nvZHFXDraQas";
529 
530  jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
531  jvParams[jss::ledger_hash] = ledgerHash;
532  Json::Value const jrr = env.rpc(
533  "json", "ledger_entry", to_string(jvParams))[jss::result];
534  checkErrorValue(jrr, "malformedOwner", "");
535  }
536  {
537  // Malformed: [jss::deposit_preauth][jss::authorized] is malformed.
538  Json::Value jvParams;
539  jvParams[jss::deposit_preauth][jss::owner] = alice.human();
540  jvParams[jss::deposit_preauth][jss::authorized] =
541  "rP6P9ypfAmc!pw8SZHNwM4nvZHFXDraQas";
542 
543  jvParams[jss::ledger_hash] = ledgerHash;
544  Json::Value const jrr = env.rpc(
545  "json", "ledger_entry", to_string(jvParams))[jss::result];
546  checkErrorValue(jrr, "malformedAuthorized", "");
547  }
548  }
549 
550  void
552  {
553  testcase("ledger_entry Request Directory");
554  using namespace test::jtx;
555  Env env{*this};
556  Account const alice{"alice"};
557  Account const gw{"gateway"};
558  auto const USD = gw["USD"];
559  env.fund(XRP(10000), alice, gw);
560  env.close();
561 
562  env.trust(USD(1000), alice);
563  env.close();
564 
565  // Run up the number of directory entries so alice has two
566  // directory nodes.
567  for (int d = 1'000'032; d >= 1'000'000; --d)
568  {
569  env(offer(alice, USD(1), drops(d)));
570  }
571  env.close();
572 
573  std::string const ledgerHash{to_string(env.closed()->info().hash)};
574  {
575  // Exercise ledger_closed along the way.
576  Json::Value const jrr = env.rpc("ledger_closed")[jss::result];
577  BEAST_EXPECT(jrr[jss::ledger_hash] == ledgerHash);
578  BEAST_EXPECT(jrr[jss::ledger_index] == 5);
579  }
580 
581  std::string const dirRootIndex =
582  "A33EC6BB85FB5674074C4A3A43373BB17645308F3EAE1933E3E35252162B217D";
583  {
584  // Locate directory by index.
585  Json::Value jvParams;
586  jvParams[jss::directory] = dirRootIndex;
587  jvParams[jss::ledger_hash] = ledgerHash;
588  Json::Value const jrr = env.rpc(
589  "json", "ledger_entry", to_string(jvParams))[jss::result];
590  BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].size() == 32);
591  }
592  {
593  // Locate directory by directory root.
594  Json::Value jvParams;
595  jvParams[jss::directory] = Json::objectValue;
596  jvParams[jss::directory][jss::dir_root] = dirRootIndex;
597  Json::Value const jrr = env.rpc(
598  "json", "ledger_entry", to_string(jvParams))[jss::result];
599  BEAST_EXPECT(jrr[jss::index] == dirRootIndex);
600  }
601  {
602  // Locate directory by owner.
603  Json::Value jvParams;
604  jvParams[jss::directory] = Json::objectValue;
605  jvParams[jss::directory][jss::owner] = alice.human();
606  jvParams[jss::ledger_hash] = ledgerHash;
607  Json::Value const jrr = env.rpc(
608  "json", "ledger_entry", to_string(jvParams))[jss::result];
609  BEAST_EXPECT(jrr[jss::index] == dirRootIndex);
610  }
611  {
612  // Locate directory by directory root and sub_index.
613  Json::Value jvParams;
614  jvParams[jss::directory] = Json::objectValue;
615  jvParams[jss::directory][jss::dir_root] = dirRootIndex;
616  jvParams[jss::directory][jss::sub_index] = 1;
617  Json::Value const jrr = env.rpc(
618  "json", "ledger_entry", to_string(jvParams))[jss::result];
619  BEAST_EXPECT(jrr[jss::index] != dirRootIndex);
620  BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].size() == 2);
621  }
622  {
623  // Locate directory by owner and sub_index.
624  Json::Value jvParams;
625  jvParams[jss::directory] = Json::objectValue;
626  jvParams[jss::directory][jss::owner] = alice.human();
627  jvParams[jss::directory][jss::sub_index] = 1;
628  jvParams[jss::ledger_hash] = ledgerHash;
629  Json::Value const jrr = env.rpc(
630  "json", "ledger_entry", to_string(jvParams))[jss::result];
631  BEAST_EXPECT(jrr[jss::index] != dirRootIndex);
632  BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].size() == 2);
633  }
634  {
635  // Null directory argument.
636  Json::Value jvParams;
637  jvParams[jss::directory] = Json::nullValue;
638  jvParams[jss::ledger_hash] = ledgerHash;
639  Json::Value const jrr = env.rpc(
640  "json", "ledger_entry", to_string(jvParams))[jss::result];
641  checkErrorValue(jrr, "malformedRequest", "");
642  }
643  {
644  // Non-integer sub_index.
645  Json::Value jvParams;
646  jvParams[jss::directory] = Json::objectValue;
647  jvParams[jss::directory][jss::dir_root] = dirRootIndex;
648  jvParams[jss::directory][jss::sub_index] = 1.5;
649  jvParams[jss::ledger_hash] = ledgerHash;
650  Json::Value const jrr = env.rpc(
651  "json", "ledger_entry", to_string(jvParams))[jss::result];
652  checkErrorValue(jrr, "malformedRequest", "");
653  }
654  {
655  // Malformed owner entry.
656  Json::Value jvParams;
657  jvParams[jss::directory] = Json::objectValue;
658 
659  std::string const badAddress = makeBadAddress(alice.human());
660  jvParams[jss::directory][jss::owner] = badAddress;
661  jvParams[jss::ledger_hash] = ledgerHash;
662  Json::Value const jrr = env.rpc(
663  "json", "ledger_entry", to_string(jvParams))[jss::result];
664  checkErrorValue(jrr, "malformedAddress", "");
665  }
666  {
667  // Malformed directory object. Specify both dir_root and owner.
668  Json::Value jvParams;
669  jvParams[jss::directory] = Json::objectValue;
670  jvParams[jss::directory][jss::owner] = alice.human();
671  jvParams[jss::directory][jss::dir_root] = dirRootIndex;
672  jvParams[jss::ledger_hash] = ledgerHash;
673  Json::Value const jrr = env.rpc(
674  "json", "ledger_entry", to_string(jvParams))[jss::result];
675  checkErrorValue(jrr, "malformedRequest", "");
676  }
677  {
678  // Incomplete directory object. Missing both dir_root and owner.
679  Json::Value jvParams;
680  jvParams[jss::directory] = Json::objectValue;
681  jvParams[jss::directory][jss::sub_index] = 1;
682  jvParams[jss::ledger_hash] = ledgerHash;
683  Json::Value const jrr = env.rpc(
684  "json", "ledger_entry", to_string(jvParams))[jss::result];
685  checkErrorValue(jrr, "malformedRequest", "");
686  }
687  }
688 
689  void
691  {
692  testcase("ledger_entry Request Escrow");
693  using namespace test::jtx;
694  Env env{*this};
695  Account const alice{"alice"};
696  env.fund(XRP(10000), alice);
697  env.close();
698 
699  // Lambda to create an escrow.
700  auto escrowCreate = [](test::jtx::Account const& account,
701  test::jtx::Account const& to,
702  STAmount const& amount,
703  NetClock::time_point const& cancelAfter) {
704  Json::Value jv;
705  jv[jss::TransactionType] = jss::EscrowCreate;
706  jv[jss::Flags] = tfUniversal;
707  jv[jss::Account] = account.human();
708  jv[jss::Destination] = to.human();
709  jv[jss::Amount] = amount.getJson(JsonOptions::none);
710  jv[sfFinishAfter.jsonName] =
711  cancelAfter.time_since_epoch().count() + 2;
712  return jv;
713  };
714 
715  using namespace std::chrono_literals;
716  env(escrowCreate(alice, alice, XRP(333), env.now() + 2s));
717  env.close();
718 
719  std::string const ledgerHash{to_string(env.closed()->info().hash)};
720  std::string escrowIndex;
721  {
722  // Request the escrow using owner and sequence.
723  Json::Value jvParams;
724  jvParams[jss::escrow] = Json::objectValue;
725  jvParams[jss::escrow][jss::owner] = alice.human();
726  jvParams[jss::escrow][jss::seq] = env.seq(alice) - 1;
727  Json::Value const jrr = env.rpc(
728  "json", "ledger_entry", to_string(jvParams))[jss::result];
729  BEAST_EXPECT(
730  jrr[jss::node][jss::Amount] == XRP(333).value().getText());
731  escrowIndex = jrr[jss::index].asString();
732  }
733  {
734  // Request the escrow by index.
735  Json::Value jvParams;
736  jvParams[jss::escrow] = escrowIndex;
737  jvParams[jss::ledger_hash] = ledgerHash;
738  Json::Value const jrr = env.rpc(
739  "json", "ledger_entry", to_string(jvParams))[jss::result];
740  BEAST_EXPECT(
741  jrr[jss::node][jss::Amount] == XRP(333).value().getText());
742  }
743  {
744  // Malformed owner entry.
745  Json::Value jvParams;
746  jvParams[jss::escrow] = Json::objectValue;
747 
748  std::string const badAddress = makeBadAddress(alice.human());
749  jvParams[jss::escrow][jss::owner] = badAddress;
750  jvParams[jss::escrow][jss::seq] = env.seq(alice) - 1;
751  jvParams[jss::ledger_hash] = ledgerHash;
752  Json::Value const jrr = env.rpc(
753  "json", "ledger_entry", to_string(jvParams))[jss::result];
754  checkErrorValue(jrr, "malformedOwner", "");
755  }
756  {
757  // Missing owner.
758  Json::Value jvParams;
759  jvParams[jss::escrow] = Json::objectValue;
760  jvParams[jss::escrow][jss::seq] = env.seq(alice) - 1;
761  jvParams[jss::ledger_hash] = ledgerHash;
762  Json::Value const jrr = env.rpc(
763  "json", "ledger_entry", to_string(jvParams))[jss::result];
764  checkErrorValue(jrr, "malformedRequest", "");
765  }
766  {
767  // Missing sequence.
768  Json::Value jvParams;
769  jvParams[jss::escrow] = Json::objectValue;
770  jvParams[jss::escrow][jss::owner] = alice.human();
771  jvParams[jss::ledger_hash] = ledgerHash;
772  Json::Value const jrr = env.rpc(
773  "json", "ledger_entry", to_string(jvParams))[jss::result];
774  checkErrorValue(jrr, "malformedRequest", "");
775  }
776  {
777  // Non-integer sequence.
778  Json::Value jvParams;
779  jvParams[jss::escrow] = Json::objectValue;
780  jvParams[jss::escrow][jss::owner] = alice.human();
781  jvParams[jss::escrow][jss::seq] =
782  std::to_string(env.seq(alice) - 1);
783  jvParams[jss::ledger_hash] = ledgerHash;
784  Json::Value const jrr = env.rpc(
785  "json", "ledger_entry", to_string(jvParams))[jss::result];
786  checkErrorValue(jrr, "malformedRequest", "");
787  }
788  }
789 
790  void
792  {
793  testcase("ledger_entry Request Offer");
794  using namespace test::jtx;
795  Env env{*this};
796  Account const alice{"alice"};
797  Account const gw{"gateway"};
798  auto const USD = gw["USD"];
799  env.fund(XRP(10000), alice, gw);
800  env.close();
801 
802  env(offer(alice, USD(321), XRP(322)));
803  env.close();
804 
805  std::string const ledgerHash{to_string(env.closed()->info().hash)};
806  std::string offerIndex;
807  {
808  // Request the offer using owner and sequence.
809  Json::Value jvParams;
810  jvParams[jss::offer] = Json::objectValue;
811  jvParams[jss::offer][jss::account] = alice.human();
812  jvParams[jss::offer][jss::seq] = env.seq(alice) - 1;
813  jvParams[jss::ledger_hash] = ledgerHash;
814  Json::Value const jrr = env.rpc(
815  "json", "ledger_entry", to_string(jvParams))[jss::result];
816  BEAST_EXPECT(jrr[jss::node][jss::TakerGets] == "322000000");
817  offerIndex = jrr[jss::index].asString();
818  }
819  {
820  // Request the offer using its index.
821  Json::Value jvParams;
822  jvParams[jss::offer] = offerIndex;
823  Json::Value const jrr = env.rpc(
824  "json", "ledger_entry", to_string(jvParams))[jss::result];
825  BEAST_EXPECT(jrr[jss::node][jss::TakerGets] == "322000000");
826  }
827  {
828  // Malformed account entry.
829  Json::Value jvParams;
830  jvParams[jss::offer] = Json::objectValue;
831 
832  std::string const badAddress = makeBadAddress(alice.human());
833  jvParams[jss::offer][jss::account] = badAddress;
834  jvParams[jss::offer][jss::seq] = env.seq(alice) - 1;
835  jvParams[jss::ledger_hash] = ledgerHash;
836  Json::Value const jrr = env.rpc(
837  "json", "ledger_entry", to_string(jvParams))[jss::result];
838  checkErrorValue(jrr, "malformedAddress", "");
839  }
840  {
841  // Malformed offer object. Missing account member.
842  Json::Value jvParams;
843  jvParams[jss::offer] = Json::objectValue;
844  jvParams[jss::offer][jss::seq] = env.seq(alice) - 1;
845  jvParams[jss::ledger_hash] = ledgerHash;
846  Json::Value const jrr = env.rpc(
847  "json", "ledger_entry", to_string(jvParams))[jss::result];
848  checkErrorValue(jrr, "malformedRequest", "");
849  }
850  {
851  // Malformed offer object. Missing seq member.
852  Json::Value jvParams;
853  jvParams[jss::offer] = Json::objectValue;
854  jvParams[jss::offer][jss::account] = alice.human();
855  jvParams[jss::ledger_hash] = ledgerHash;
856  Json::Value const jrr = env.rpc(
857  "json", "ledger_entry", to_string(jvParams))[jss::result];
858  checkErrorValue(jrr, "malformedRequest", "");
859  }
860  {
861  // Malformed offer object. Non-integral seq member.
862  Json::Value jvParams;
863  jvParams[jss::offer] = Json::objectValue;
864  jvParams[jss::offer][jss::account] = alice.human();
865  jvParams[jss::offer][jss::seq] = std::to_string(env.seq(alice) - 1);
866  jvParams[jss::ledger_hash] = ledgerHash;
867  Json::Value const jrr = env.rpc(
868  "json", "ledger_entry", to_string(jvParams))[jss::result];
869  checkErrorValue(jrr, "malformedRequest", "");
870  }
871  }
872 
873  void
875  {
876  testcase("ledger_entry Request Pay Chan");
877  using namespace test::jtx;
878  using namespace std::literals::chrono_literals;
879  Env env{*this};
880  Account const alice{"alice"};
881 
882  env.fund(XRP(10000), alice);
883  env.close();
884 
885  // Lambda to create a PayChan.
886  auto payChanCreate = [](test::jtx::Account const& account,
887  test::jtx::Account const& to,
888  STAmount const& amount,
889  NetClock::duration const& settleDelay,
890  PublicKey const& pk) {
891  Json::Value jv;
892  jv[jss::TransactionType] = jss::PaymentChannelCreate;
893  jv[jss::Account] = account.human();
894  jv[jss::Destination] = to.human();
895  jv[jss::Amount] = amount.getJson(JsonOptions::none);
896  jv[sfSettleDelay.jsonName] = settleDelay.count();
897  jv[sfPublicKey.jsonName] = strHex(pk.slice());
898  return jv;
899  };
900 
901  env(payChanCreate(alice, env.master, XRP(57), 18s, alice.pk()));
902  env.close();
903 
904  std::string const ledgerHash{to_string(env.closed()->info().hash)};
905 
906  uint256 const payChanIndex{
907  keylet::payChan(alice, env.master, env.seq(alice) - 1).key};
908  {
909  // Request the payment channel using its index.
910  Json::Value jvParams;
911  jvParams[jss::payment_channel] = to_string(payChanIndex);
912  jvParams[jss::ledger_hash] = ledgerHash;
913  Json::Value const jrr = env.rpc(
914  "json", "ledger_entry", to_string(jvParams))[jss::result];
915  BEAST_EXPECT(jrr[jss::node][sfAmount.jsonName] == "57000000");
916  BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] == "0");
917  BEAST_EXPECT(jrr[jss::node][sfSettleDelay.jsonName] == 18);
918  }
919  {
920  // Request an index that is not a payment channel.
921  Json::Value jvParams;
922  jvParams[jss::payment_channel] = ledgerHash;
923  jvParams[jss::ledger_hash] = ledgerHash;
924  Json::Value const jrr = env.rpc(
925  "json", "ledger_entry", to_string(jvParams))[jss::result];
926  checkErrorValue(jrr, "entryNotFound", "");
927  }
928  }
929 
930  void
932  {
933  testcase("ledger_entry Request RippleState");
934  using namespace test::jtx;
935  Env env{*this};
936  Account const alice{"alice"};
937  Account const gw{"gateway"};
938  auto const USD = gw["USD"];
939  env.fund(XRP(10000), alice, gw);
940  env.close();
941 
942  env.trust(USD(999), alice);
943  env.close();
944 
945  env(pay(gw, alice, USD(97)));
946  env.close();
947 
948  std::string const ledgerHash{to_string(env.closed()->info().hash)};
949  {
950  // Request the trust line using the accounts and currency.
951  Json::Value jvParams;
952  jvParams[jss::ripple_state] = Json::objectValue;
953  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
954  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
955  jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
956  jvParams[jss::ripple_state][jss::currency] = "USD";
957  jvParams[jss::ledger_hash] = ledgerHash;
958  Json::Value const jrr = env.rpc(
959  "json", "ledger_entry", to_string(jvParams))[jss::result];
960  BEAST_EXPECT(
961  jrr[jss::node][sfBalance.jsonName][jss::value] == "-97");
962  BEAST_EXPECT(
963  jrr[jss::node][sfHighLimit.jsonName][jss::value] == "999");
964  }
965  {
966  // ripple_state is not an object.
967  Json::Value jvParams;
968  jvParams[jss::ripple_state] = "ripple_state";
969  jvParams[jss::ledger_hash] = ledgerHash;
970  Json::Value const jrr = env.rpc(
971  "json", "ledger_entry", to_string(jvParams))[jss::result];
972  checkErrorValue(jrr, "malformedRequest", "");
973  }
974  {
975  // ripple_state.currency is missing.
976  Json::Value jvParams;
977  jvParams[jss::ripple_state] = Json::objectValue;
978  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
979  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
980  jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
981  jvParams[jss::ledger_hash] = ledgerHash;
982  Json::Value const jrr = env.rpc(
983  "json", "ledger_entry", to_string(jvParams))[jss::result];
984  checkErrorValue(jrr, "malformedRequest", "");
985  }
986  {
987  // ripple_state accounts is not an array.
988  Json::Value jvParams;
989  jvParams[jss::ripple_state] = Json::objectValue;
990  jvParams[jss::ripple_state][jss::accounts] = 2;
991  jvParams[jss::ripple_state][jss::currency] = "USD";
992  jvParams[jss::ledger_hash] = ledgerHash;
993  Json::Value const jrr = env.rpc(
994  "json", "ledger_entry", to_string(jvParams))[jss::result];
995  checkErrorValue(jrr, "malformedRequest", "");
996  }
997  {
998  // ripple_state one of the accounts is missing.
999  Json::Value jvParams;
1000  jvParams[jss::ripple_state] = Json::objectValue;
1001  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1002  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1003  jvParams[jss::ripple_state][jss::currency] = "USD";
1004  jvParams[jss::ledger_hash] = ledgerHash;
1005  Json::Value const jrr = env.rpc(
1006  "json", "ledger_entry", to_string(jvParams))[jss::result];
1007  checkErrorValue(jrr, "malformedRequest", "");
1008  }
1009  {
1010  // ripple_state more than 2 accounts.
1011  Json::Value jvParams;
1012  jvParams[jss::ripple_state] = Json::objectValue;
1013  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1014  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1015  jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1016  jvParams[jss::ripple_state][jss::accounts][2u] = alice.human();
1017  jvParams[jss::ripple_state][jss::currency] = "USD";
1018  jvParams[jss::ledger_hash] = ledgerHash;
1019  Json::Value const jrr = env.rpc(
1020  "json", "ledger_entry", to_string(jvParams))[jss::result];
1021  checkErrorValue(jrr, "malformedRequest", "");
1022  }
1023  {
1024  // ripple_state account[0] is not a string.
1025  Json::Value jvParams;
1026  jvParams[jss::ripple_state] = Json::objectValue;
1027  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1028  jvParams[jss::ripple_state][jss::accounts][0u] = 44;
1029  jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1030  jvParams[jss::ripple_state][jss::currency] = "USD";
1031  jvParams[jss::ledger_hash] = ledgerHash;
1032  Json::Value const jrr = env.rpc(
1033  "json", "ledger_entry", to_string(jvParams))[jss::result];
1034  checkErrorValue(jrr, "malformedRequest", "");
1035  }
1036  {
1037  // ripple_state account[1] is not a string.
1038  Json::Value jvParams;
1039  jvParams[jss::ripple_state] = Json::objectValue;
1040  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1041  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1042  jvParams[jss::ripple_state][jss::accounts][1u] = 21;
1043  jvParams[jss::ripple_state][jss::currency] = "USD";
1044  jvParams[jss::ledger_hash] = ledgerHash;
1045  Json::Value const jrr = env.rpc(
1046  "json", "ledger_entry", to_string(jvParams))[jss::result];
1047  checkErrorValue(jrr, "malformedRequest", "");
1048  }
1049  {
1050  // ripple_state account[0] == account[1].
1051  Json::Value jvParams;
1052  jvParams[jss::ripple_state] = Json::objectValue;
1053  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1054  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1055  jvParams[jss::ripple_state][jss::accounts][1u] = alice.human();
1056  jvParams[jss::ripple_state][jss::currency] = "USD";
1057  jvParams[jss::ledger_hash] = ledgerHash;
1058  Json::Value const jrr = env.rpc(
1059  "json", "ledger_entry", to_string(jvParams))[jss::result];
1060  checkErrorValue(jrr, "malformedRequest", "");
1061  }
1062  {
1063  // ripple_state malformed account[0].
1064  Json::Value jvParams;
1065  jvParams[jss::ripple_state] = Json::objectValue;
1066  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1067  jvParams[jss::ripple_state][jss::accounts][0u] =
1068  makeBadAddress(alice.human());
1069  jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1070  jvParams[jss::ripple_state][jss::currency] = "USD";
1071  jvParams[jss::ledger_hash] = ledgerHash;
1072  Json::Value const jrr = env.rpc(
1073  "json", "ledger_entry", to_string(jvParams))[jss::result];
1074  checkErrorValue(jrr, "malformedAddress", "");
1075  }
1076  {
1077  // ripple_state malformed account[1].
1078  Json::Value jvParams;
1079  jvParams[jss::ripple_state] = Json::objectValue;
1080  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1081  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1082  jvParams[jss::ripple_state][jss::accounts][1u] =
1083  makeBadAddress(gw.human());
1084  jvParams[jss::ripple_state][jss::currency] = "USD";
1085  jvParams[jss::ledger_hash] = ledgerHash;
1086  Json::Value const jrr = env.rpc(
1087  "json", "ledger_entry", to_string(jvParams))[jss::result];
1088  checkErrorValue(jrr, "malformedAddress", "");
1089  }
1090  {
1091  // ripple_state malformed currency.
1092  Json::Value jvParams;
1093  jvParams[jss::ripple_state] = Json::objectValue;
1094  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1095  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1096  jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1097  jvParams[jss::ripple_state][jss::currency] = "USDollars";
1098  jvParams[jss::ledger_hash] = ledgerHash;
1099  Json::Value const jrr = env.rpc(
1100  "json", "ledger_entry", to_string(jvParams))[jss::result];
1101  checkErrorValue(jrr, "malformedCurrency", "");
1102  }
1103  }
1104 
1105  void
1107  {
1108  testcase("ledger_entry Request Ticket");
1109  using namespace test::jtx;
1110  Env env{*this, supported_amendments() | featureTicketBatch};
1111  env.close();
1112 
1113  // Create two tickets.
1114  std::uint32_t const tkt1{env.seq(env.master) + 1};
1115  env(ticket::create(env.master, 2));
1116  env.close();
1117 
1118  std::string const ledgerHash{to_string(env.closed()->info().hash)};
1119  // Request four tickets: one before the first one we created, the
1120  // two created tickets, and the ticket that would come after the
1121  // last created ticket.
1122  {
1123  // Not a valid ticket requested by index.
1124  Json::Value jvParams;
1125  jvParams[jss::ticket] =
1126  to_string(getTicketIndex(env.master, tkt1 - 1));
1127  jvParams[jss::ledger_hash] = ledgerHash;
1128  Json::Value const jrr = env.rpc(
1129  "json", "ledger_entry", to_string(jvParams))[jss::result];
1130  checkErrorValue(jrr, "entryNotFound", "");
1131  }
1132  {
1133  // First real ticket requested by index.
1134  Json::Value jvParams;
1135  jvParams[jss::ticket] = to_string(getTicketIndex(env.master, tkt1));
1136  jvParams[jss::ledger_hash] = ledgerHash;
1137  Json::Value const jrr = env.rpc(
1138  "json", "ledger_entry", to_string(jvParams))[jss::result];
1139  BEAST_EXPECT(
1140  jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Ticket);
1141  BEAST_EXPECT(jrr[jss::node][sfTicketSequence.jsonName] == tkt1);
1142  }
1143  {
1144  // Second real ticket requested by account and sequence.
1145  Json::Value jvParams;
1146  jvParams[jss::ticket] = Json::objectValue;
1147  jvParams[jss::ticket][jss::account] = env.master.human();
1148  jvParams[jss::ticket][jss::ticket_seq] = tkt1 + 1;
1149  jvParams[jss::ledger_hash] = ledgerHash;
1150  Json::Value const jrr = env.rpc(
1151  "json", "ledger_entry", to_string(jvParams))[jss::result];
1152  BEAST_EXPECT(
1153  jrr[jss::node][jss::index] ==
1154  to_string(getTicketIndex(env.master, tkt1 + 1)));
1155  }
1156  {
1157  // Not a valid ticket requested by account and sequence.
1158  Json::Value jvParams;
1159  jvParams[jss::ticket] = Json::objectValue;
1160  jvParams[jss::ticket][jss::account] = env.master.human();
1161  jvParams[jss::ticket][jss::ticket_seq] = tkt1 + 2;
1162  jvParams[jss::ledger_hash] = ledgerHash;
1163  Json::Value const jrr = env.rpc(
1164  "json", "ledger_entry", to_string(jvParams))[jss::result];
1165  checkErrorValue(jrr, "entryNotFound", "");
1166  }
1167  {
1168  // Request a ticket using an account root entry.
1169  Json::Value jvParams;
1170  jvParams[jss::ticket] = to_string(keylet::account(env.master).key);
1171  jvParams[jss::ledger_hash] = ledgerHash;
1172  Json::Value const jrr = env.rpc(
1173  "json", "ledger_entry", to_string(jvParams))[jss::result];
1174  checkErrorValue(jrr, "malformedRequest", "");
1175  }
1176  {
1177  // Malformed account entry.
1178  Json::Value jvParams;
1179  jvParams[jss::ticket] = Json::objectValue;
1180 
1181  std::string const badAddress = makeBadAddress(env.master.human());
1182  jvParams[jss::ticket][jss::account] = badAddress;
1183  jvParams[jss::ticket][jss::ticket_seq] = env.seq(env.master) - 1;
1184  jvParams[jss::ledger_hash] = ledgerHash;
1185  Json::Value const jrr = env.rpc(
1186  "json", "ledger_entry", to_string(jvParams))[jss::result];
1187  checkErrorValue(jrr, "malformedAddress", "");
1188  }
1189  {
1190  // Malformed ticket object. Missing account member.
1191  Json::Value jvParams;
1192  jvParams[jss::ticket] = Json::objectValue;
1193  jvParams[jss::ticket][jss::ticket_seq] = env.seq(env.master) - 1;
1194  jvParams[jss::ledger_hash] = ledgerHash;
1195  Json::Value const jrr = env.rpc(
1196  "json", "ledger_entry", to_string(jvParams))[jss::result];
1197  checkErrorValue(jrr, "malformedRequest", "");
1198  }
1199  {
1200  // Malformed ticket object. Missing seq member.
1201  Json::Value jvParams;
1202  jvParams[jss::ticket] = Json::objectValue;
1203  jvParams[jss::ticket][jss::account] = env.master.human();
1204  jvParams[jss::ledger_hash] = ledgerHash;
1205  Json::Value const jrr = env.rpc(
1206  "json", "ledger_entry", to_string(jvParams))[jss::result];
1207  checkErrorValue(jrr, "malformedRequest", "");
1208  }
1209  {
1210  // Malformed ticket object. Non-integral seq member.
1211  Json::Value jvParams;
1212  jvParams[jss::ticket] = Json::objectValue;
1213  jvParams[jss::ticket][jss::account] = env.master.human();
1214  jvParams[jss::ticket][jss::ticket_seq] =
1215  std::to_string(env.seq(env.master) - 1);
1216  jvParams[jss::ledger_hash] = ledgerHash;
1217  Json::Value const jrr = env.rpc(
1218  "json", "ledger_entry", to_string(jvParams))[jss::result];
1219  checkErrorValue(jrr, "malformedRequest", "");
1220  }
1221  }
1222 
1223  void
1225  {
1226  testcase("ledger_entry Request Unknown Option");
1227  using namespace test::jtx;
1228  Env env{*this};
1229 
1230  std::string const ledgerHash{to_string(env.closed()->info().hash)};
1231 
1232  // "features" is not an option supported by ledger_entry.
1233  Json::Value jvParams;
1234  jvParams[jss::features] = ledgerHash;
1235  jvParams[jss::ledger_hash] = ledgerHash;
1236  Json::Value const jrr =
1237  env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
1238  checkErrorValue(jrr, "unknownOption", "");
1239  }
1240 
1245  void
1247  {
1248  testcase("Lookup ledger");
1249  using namespace test::jtx;
1250  Env env{*this, FeatureBitset{}}; // hashes requested below assume
1251  // no amendments
1252  env.fund(XRP(10000), "alice");
1253  env.close();
1254  env.fund(XRP(10000), "bob");
1255  env.close();
1256  env.fund(XRP(10000), "jim");
1257  env.close();
1258  env.fund(XRP(10000), "jill");
1259 
1260  // closed ledger hashes are:
1261  // 1 - AB868A6CFEEC779C2FF845C0AF00A642259986AF40C01976A7F842B6918936C7
1262  // 2 - 8AEDBB96643962F1D40F01E25632ABB3C56C9F04B0231EE4B18248B90173D189
1263  // 3 - 7C3EEDB3124D92E49E75D81A8826A2E65A75FD71FC3FD6F36FEB803C5F1D812D
1264  // 4 - 9F9E6A4ECAA84A08FF94713FA41C3151177D6222EA47DD2F0020CA49913EE2E6
1265  // 5 - C516522DE274EB52CE69A3D22F66DD73A53E16597E06F7A86F66DF7DD4309173
1266  //
1267  {
1268  // access via the legacy ledger field, keyword index values
1269  Json::Value jvParams;
1270  jvParams[jss::ledger] = "closed";
1271  auto jrr = env.rpc(
1272  "json",
1273  "ledger",
1274  boost::lexical_cast<std::string>(jvParams))[jss::result];
1275  BEAST_EXPECT(jrr.isMember(jss::ledger));
1276  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1277  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1278 
1279  jvParams[jss::ledger] = "validated";
1280  jrr = env.rpc(
1281  "json",
1282  "ledger",
1283  boost::lexical_cast<std::string>(jvParams))[jss::result];
1284  BEAST_EXPECT(jrr.isMember(jss::ledger));
1285  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1286  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1287 
1288  jvParams[jss::ledger] = "current";
1289  jrr = env.rpc(
1290  "json",
1291  "ledger",
1292  boost::lexical_cast<std::string>(jvParams))[jss::result];
1293  BEAST_EXPECT(jrr.isMember(jss::ledger));
1294  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
1295 
1296  // ask for a bad ledger keyword
1297  jvParams[jss::ledger] = "invalid";
1298  jrr = env.rpc(
1299  "json",
1300  "ledger",
1301  boost::lexical_cast<std::string>(jvParams))[jss::result];
1302  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1303  BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
1304 
1305  // numeric index
1306  jvParams[jss::ledger] = 4;
1307  jrr = env.rpc(
1308  "json",
1309  "ledger",
1310  boost::lexical_cast<std::string>(jvParams))[jss::result];
1311  BEAST_EXPECT(jrr.isMember(jss::ledger));
1312  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1313  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "4");
1314 
1315  // numeric index - out of range
1316  jvParams[jss::ledger] = 20;
1317  jrr = env.rpc(
1318  "json",
1319  "ledger",
1320  boost::lexical_cast<std::string>(jvParams))[jss::result];
1321  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
1322  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
1323  }
1324 
1325  {
1326  // access via the ledger_hash field
1327  Json::Value jvParams;
1328  jvParams[jss::ledger_hash] =
1329  "7C3EEDB3124D92E49E75D81A8826A2E6"
1330  "5A75FD71FC3FD6F36FEB803C5F1D812D";
1331  auto jrr = env.rpc(
1332  "json",
1333  "ledger",
1334  boost::lexical_cast<std::string>(jvParams))[jss::result];
1335  BEAST_EXPECT(jrr.isMember(jss::ledger));
1336  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1337  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "3");
1338 
1339  // extra leading hex chars in hash will be ignored
1340  jvParams[jss::ledger_hash] =
1341  "DEADBEEF"
1342  "7C3EEDB3124D92E49E75D81A8826A2E6"
1343  "5A75FD71FC3FD6F36FEB803C5F1D812D";
1344  jrr = env.rpc(
1345  "json",
1346  "ledger",
1347  boost::lexical_cast<std::string>(jvParams))[jss::result];
1348  BEAST_EXPECT(jrr.isMember(jss::ledger));
1349  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1350  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "3");
1351 
1352  // request with non-string ledger_hash
1353  jvParams[jss::ledger_hash] = 2;
1354  jrr = env.rpc(
1355  "json",
1356  "ledger",
1357  boost::lexical_cast<std::string>(jvParams))[jss::result];
1358  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1359  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashNotString");
1360 
1361  // malformed (non hex) hash
1362  jvParams[jss::ledger_hash] =
1363  "ZZZZZZZZZZZD92E49E75D81A8826A2E6"
1364  "5A75FD71FC3FD6F36FEB803C5F1D812D";
1365  jrr = env.rpc(
1366  "json",
1367  "ledger",
1368  boost::lexical_cast<std::string>(jvParams))[jss::result];
1369  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1370  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
1371 
1372  // properly formed, but just doesn't exist
1373  jvParams[jss::ledger_hash] =
1374  "8C3EEDB3124D92E49E75D81A8826A2E6"
1375  "5A75FD71FC3FD6F36FEB803C5F1D812D";
1376  jrr = env.rpc(
1377  "json",
1378  "ledger",
1379  boost::lexical_cast<std::string>(jvParams))[jss::result];
1380  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
1381  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
1382  }
1383 
1384  {
1385  // access via the ledger_index field, keyword index values
1386  Json::Value jvParams;
1387  jvParams[jss::ledger_index] = "closed";
1388  auto jrr = env.rpc(
1389  "json",
1390  "ledger",
1391  boost::lexical_cast<std::string>(jvParams))[jss::result];
1392  BEAST_EXPECT(jrr.isMember(jss::ledger));
1393  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1394  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1395  BEAST_EXPECT(jrr.isMember(jss::ledger_index));
1396 
1397  jvParams[jss::ledger_index] = "validated";
1398  jrr = env.rpc(
1399  "json",
1400  "ledger",
1401  boost::lexical_cast<std::string>(jvParams))[jss::result];
1402  BEAST_EXPECT(jrr.isMember(jss::ledger));
1403  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1404  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1405 
1406  jvParams[jss::ledger_index] = "current";
1407  jrr = env.rpc(
1408  "json",
1409  "ledger",
1410  boost::lexical_cast<std::string>(jvParams))[jss::result];
1411  BEAST_EXPECT(jrr.isMember(jss::ledger));
1412  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
1413  BEAST_EXPECT(jrr.isMember(jss::ledger_current_index));
1414 
1415  // ask for a bad ledger keyword
1416  jvParams[jss::ledger_index] = "invalid";
1417  jrr = env.rpc(
1418  "json",
1419  "ledger",
1420  boost::lexical_cast<std::string>(jvParams))[jss::result];
1421  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1422  BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
1423 
1424  // numeric index
1425  for (auto i : {1, 2, 3, 4, 5, 6})
1426  {
1427  jvParams[jss::ledger_index] = i;
1428  jrr = env.rpc(
1429  "json",
1430  "ledger",
1431  boost::lexical_cast<std::string>(jvParams))[jss::result];
1432  BEAST_EXPECT(jrr.isMember(jss::ledger));
1433  if (i < 6)
1434  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1435  BEAST_EXPECT(
1436  jrr[jss::ledger][jss::ledger_index] == std::to_string(i));
1437  }
1438 
1439  // numeric index - out of range
1440  jvParams[jss::ledger_index] = 7;
1441  jrr = env.rpc(
1442  "json",
1443  "ledger",
1444  boost::lexical_cast<std::string>(jvParams))[jss::result];
1445  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
1446  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
1447  }
1448  }
1449 
1450  void
1452  {
1453  testcase("Ledger with queueing disabled");
1454  using namespace test::jtx;
1455  Env env{*this};
1456 
1457  Json::Value jv;
1458  jv[jss::ledger_index] = "current";
1459  jv[jss::queue] = true;
1460  jv[jss::expand] = true;
1461 
1462  auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1463  BEAST_EXPECT(!jrr.isMember(jss::queue_data));
1464  }
1465 
1466  void
1468  {
1469  testcase("Ledger with Queued Transactions");
1470  using namespace test::jtx;
1471  Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
1472  auto& section = cfg->section("transaction_queue");
1473  section.set("minimum_txn_in_ledger_standalone", "3");
1474  section.set("normal_consensus_increase_percent", "0");
1475  return cfg;
1476  })};
1477 
1478  Json::Value jv;
1479  jv[jss::ledger_index] = "current";
1480  jv[jss::queue] = true;
1481  jv[jss::expand] = true;
1482 
1483  Account const alice{"alice"};
1484  Account const bob{"bob"};
1485  Account const charlie{"charlie"};
1486  Account const daria{"daria"};
1487  env.fund(XRP(10000), alice);
1488  env.fund(XRP(10000), bob);
1489  env.close();
1490  env.fund(XRP(10000), charlie);
1491  env.fund(XRP(10000), daria);
1492  env.close();
1493 
1494  auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1495  BEAST_EXPECT(!jrr.isMember(jss::queue_data));
1496 
1497  // Fill the open ledger
1498  for (;;)
1499  {
1500  auto metrics = env.app().getTxQ().getMetrics(*env.current());
1501  if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
1502  break;
1503  env(noop(alice));
1504  }
1505 
1506  BEAST_EXPECT(env.current()->info().seq == 5);
1507  // Put some txs in the queue
1508  // Alice
1509  auto aliceSeq = env.seq(alice);
1510  env(pay(alice, "george", XRP(1000)),
1511  json(R"({"LastLedgerSequence":7})"),
1512  ter(terQUEUED));
1513  env(offer(alice, XRP(50000), alice["USD"](5000)),
1514  seq(aliceSeq + 1),
1515  ter(terQUEUED));
1516  env(noop(alice), seq(aliceSeq + 2), ter(terQUEUED));
1517  // Bob
1518  auto batch = [&env](Account a) {
1519  auto aSeq = env.seq(a);
1520  // Enough fee to get in front of alice in the queue
1521  for (int i = 0; i < 10; ++i)
1522  {
1523  env(noop(a), fee(1000 + i), seq(aSeq + i), ter(terQUEUED));
1524  }
1525  };
1526  batch(bob);
1527  // Charlie
1528  batch(charlie);
1529  // Daria
1530  batch(daria);
1531 
1532  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1533  BEAST_EXPECT(jrr[jss::queue_data].size() == 33);
1534 
1535  // Close enough ledgers so that alice's first tx expires.
1536  env.close();
1537  env.close();
1538  env.close();
1539  BEAST_EXPECT(env.current()->info().seq == 8);
1540 
1541  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1542  BEAST_EXPECT(jrr[jss::queue_data].size() == 11);
1543 
1544  env.close();
1545 
1546  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1547  std::string txid1;
1548  std::string txid2;
1549  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
1550  {
1551  auto const& txj = jrr[jss::queue_data][0u];
1552  BEAST_EXPECT(txj[jss::account] == alice.human());
1553  BEAST_EXPECT(txj[jss::fee_level] == "256");
1554  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
1555  BEAST_EXPECT(txj["retries_remaining"] == 10);
1556  BEAST_EXPECT(txj.isMember(jss::tx));
1557  auto const& tx = txj[jss::tx];
1558  BEAST_EXPECT(tx[jss::Account] == alice.human());
1559  BEAST_EXPECT(tx[jss::TransactionType] == jss::OfferCreate);
1560  txid1 = tx[jss::hash].asString();
1561  }
1562 
1563  env.close();
1564 
1565  jv[jss::expand] = false;
1566 
1567  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1568  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
1569  {
1570  auto const& txj = jrr[jss::queue_data][0u];
1571  BEAST_EXPECT(txj[jss::account] == alice.human());
1572  BEAST_EXPECT(txj[jss::fee_level] == "256");
1573  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
1574  BEAST_EXPECT(txj["retries_remaining"] == 9);
1575  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
1576  BEAST_EXPECT(txj.isMember(jss::tx));
1577  BEAST_EXPECT(txj[jss::tx] == txid1);
1578  }
1579 
1580  env.close();
1581 
1582  jv[jss::expand] = true;
1583  jv[jss::binary] = true;
1584 
1585  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1586  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
1587  {
1588  auto const& txj = jrr[jss::queue_data][0u];
1589  BEAST_EXPECT(txj[jss::account] == alice.human());
1590  BEAST_EXPECT(txj[jss::fee_level] == "256");
1591  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
1592  BEAST_EXPECT(txj["retries_remaining"] == 8);
1593  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
1594  BEAST_EXPECT(txj.isMember(jss::tx));
1595  BEAST_EXPECT(txj[jss::tx].isMember(jss::tx_blob));
1596 
1597  auto const& txj2 = jrr[jss::queue_data][1u];
1598  BEAST_EXPECT(txj2[jss::account] == alice.human());
1599  BEAST_EXPECT(txj2[jss::fee_level] == "256");
1600  BEAST_EXPECT(txj2["preflight_result"] == "tesSUCCESS");
1601  BEAST_EXPECT(txj2["retries_remaining"] == 10);
1602  BEAST_EXPECT(!txj2.isMember("last_result"));
1603  BEAST_EXPECT(txj2.isMember(jss::tx));
1604  BEAST_EXPECT(txj2[jss::tx].isMember(jss::tx_blob));
1605  }
1606 
1607  for (int i = 0; i != 9; ++i)
1608  {
1609  env.close();
1610  }
1611 
1612  jv[jss::expand] = false;
1613  jv[jss::binary] = false;
1614 
1615  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1616  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
1617  {
1618  auto const& txj = jrr[jss::queue_data][0u];
1619  BEAST_EXPECT(txj[jss::account] == alice.human());
1620  BEAST_EXPECT(txj[jss::fee_level] == "256");
1621  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
1622  BEAST_EXPECT(txj["retries_remaining"] == 1);
1623  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
1624  BEAST_EXPECT(txj.isMember(jss::tx));
1625  BEAST_EXPECT(txj[jss::tx] != txid1);
1626  txid2 = txj[jss::tx].asString();
1627  }
1628 
1629  jv[jss::full] = true;
1630 
1631  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1632  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
1633  {
1634  auto const& txj = jrr[jss::queue_data][0u];
1635  BEAST_EXPECT(txj[jss::account] == alice.human());
1636  BEAST_EXPECT(txj[jss::fee_level] == "256");
1637  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
1638  BEAST_EXPECT(txj["retries_remaining"] == 1);
1639  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
1640  BEAST_EXPECT(txj.isMember(jss::tx));
1641  auto const& tx = txj[jss::tx];
1642  BEAST_EXPECT(tx[jss::Account] == alice.human());
1643  BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
1644  BEAST_EXPECT(tx[jss::hash] == txid2);
1645  }
1646  }
1647 
1648  void
1650  {
1651  testcase("Ledger Request, Accounts Option");
1652  using namespace test::jtx;
1653 
1654  Env env{*this};
1655 
1656  env.close();
1657 
1658  std::string index;
1659  {
1660  Json::Value jvParams;
1661  jvParams[jss::ledger_index] = 3u;
1662  jvParams[jss::accounts] = true;
1663  jvParams[jss::expand] = true;
1664  jvParams[jss::type] = "hashes";
1665  auto const jrr =
1666  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
1667  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
1668  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
1669  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
1670  BEAST_EXPECT(
1671  jrr[jss::ledger][jss::accountState][0u]["LedgerEntryType"] ==
1672  jss::LedgerHashes);
1673  index = jrr[jss::ledger][jss::accountState][0u]["index"].asString();
1674  }
1675  {
1676  Json::Value jvParams;
1677  jvParams[jss::ledger_index] = 3u;
1678  jvParams[jss::accounts] = true;
1679  jvParams[jss::expand] = false;
1680  jvParams[jss::type] = "hashes";
1681  auto const jrr =
1682  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
1683  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
1684  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
1685  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
1686  BEAST_EXPECT(jrr[jss::ledger][jss::accountState][0u] == index);
1687  }
1688  }
1689 
1690 public:
1691  void
1692  run() override
1693  {
1695  testBadInput();
1698  testLedgerFull();
1711  testLookupLedger();
1712  testNoQueue();
1713  testQueue();
1715  }
1716 };
1717 
1718 BEAST_DEFINE_TESTSUITE(LedgerRPC, app, ripple);
1719 
1720 } // namespace ripple
ripple::LedgerRPC_test::testLedgerEntryRippleState
void testLedgerEntryRippleState()
Definition: LedgerRPC_test.cpp:931
ripple::LedgerRPC_test::testLedgerEntryUnknownOption
void testLedgerEntryUnknownOption()
Definition: LedgerRPC_test.cpp:1224
ripple::LedgerRPC_test::testLookupLedger
void testLookupLedger()
ledger RPC requests as a way to drive input options to lookupLedger.
Definition: LedgerRPC_test.cpp:1246
std::string
STL class.
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::LedgerRPC_test::testLedgerEntryTicket
void testLedgerEntryTicket()
Definition: LedgerRPC_test.cpp:1106
ripple::sfLedgerEntryType
const SF_U16 sfLedgerEntryType(access, STI_UINT16, 1, "LedgerEntryType", SField::sMD_Never)
Definition: SField.h:346
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::LedgerRPC_test::testLedgerEntryOffer
void testLedgerEntryOffer()
Definition: LedgerRPC_test.cpp:791
ripple::sfAccount
const SF_Account sfAccount(access, STI_ACCOUNT, 1, "Account")
Definition: SField.h:481
std::chrono::duration
ripple::LedgerRPC_test::testNoQueue
void testNoQueue()
Definition: LedgerRPC_test.cpp:1451
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::sfAmount
const SF_Amount sfAmount(access, STI_AMOUNT, 1, "Amount")
Definition: SField.h:441
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
ripple::getTicketIndex
uint256 getTicketIndex(AccountID const &account, std::uint32_t ticketSeq)
Definition: Indexes.cpp:111
ripple::LedgerRPC_test
Definition: LedgerRPC_test.cpp:31
std::string::replace
T replace(T... args)
ripple::terQUEUED
@ terQUEUED
Definition: TER.h:200
ripple::Keylet::key
uint256 key
Definition: Keylet.h:41
ripple::base_uint< 256 >
ripple::LedgerRPC_test::testLedgerAccountsOption
void testLedgerAccountsOption()
Definition: LedgerRPC_test.cpp:1649
ripple::LedgerRPC_test::testLedgerFullNonAdmin
void testLedgerFullNonAdmin()
Definition: LedgerRPC_test.cpp:245
ripple::LedgerRPC_test::testLedgerFull
void testLedgerFull()
Definition: LedgerRPC_test.cpp:225
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::RPC::contains_error
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:218
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:129
ripple::sfSendMax
const SF_Amount sfSendMax(access, STI_AMOUNT, 9, "SendMax")
Definition: SField.h:449
ripple::LedgerRPC_test::makeBadAddress
std::string makeBadAddress(std::string good)
Definition: LedgerRPC_test.cpp:56
ripple::LedgerRPC_test::testBadInput
void testBadInput()
Definition: LedgerRPC_test.cpp:114
ripple::JsonOptions::none
@ none
ripple::LedgerRPC_test::testQueue
void testQueue()
Definition: LedgerRPC_test.cpp:1467
ripple::LedgerRPC_test::testLedgerEntryAccountRoot
void testLedgerEntryAccountRoot()
Definition: LedgerRPC_test.cpp:284
std::to_string
T to_string(T... args)
ripple::STAmount
Definition: STAmount.h:42
std::chrono::time_point
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
ripple::LedgerRPC_test::testLedgerEntryEscrow
void testLedgerEntryEscrow()
Definition: LedgerRPC_test.cpp:690
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
std::uint32_t
ripple::LedgerRPC_test::run
void run() override
Definition: LedgerRPC_test.cpp:1692
ripple::sfIndexes
const SF_Vec256 sfIndexes(access, STI_VECTOR256, 1, "Indexes", SField::sMD_Never)
Definition: SField.h:494
ripple::tfUniversal
const std::uint32_t tfUniversal
Definition: TxFlags.h:49
ripple::LedgerRPC_test::testLedgerEntryDirectory
void testLedgerEntryDirectory()
Definition: LedgerRPC_test.cpp:551
ripple::sfTicketSequence
const SF_U32 sfTicketSequence(access, STI_UINT32, 41, "TicketSequence")
Definition: SField.h:394
ripple::LedgerRPC_test::testMissingLedgerEntryLedgerHash
void testMissingLedgerEntryLedgerHash()
Definition: LedgerRPC_test.cpp:206
ripple::sfPublicKey
const SF_Blob sfPublicKey(access, STI_VL, 1, "PublicKey")
Definition: SField.h:458
ripple::LedgerRPC_test::testLedgerEntryPayChan
void testLedgerEntryPayChan()
Definition: LedgerRPC_test.cpp:874
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::sfBalance
const SF_Amount sfBalance(access, STI_AMOUNT, 2, "Balance")
Definition: SField.h:442
ripple::keylet::payChan
Keylet payChan(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Definition: Indexes.cpp:320
ripple::LedgerRPC_test::testLedgerAccounts
void testLedgerAccounts()
Definition: LedgerRPC_test.cpp:264
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::FeatureBitset
Definition: Feature.h:156
ripple::sfSettleDelay
const SF_U32 sfSettleDelay(access, STI_UINT32, 39, "SettleDelay")
Definition: SField.h:392
std::string::empty
T empty(T... args)
ripple::featureTicketBatch
const uint256 featureTicketBatch
Definition: Feature.cpp:189
ripple::LedgerRPC_test::testLedgerEntryCheck
void testLedgerEntryCheck()
Definition: LedgerRPC_test.cpp:373
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
ripple::LedgerRPC_test::testLedgerEntryDepositPreauth
void testLedgerEntryDepositPreauth()
Definition: LedgerRPC_test.cpp:420
ripple::sfAuthorize
const SF_Account sfAuthorize(access, STI_ACCOUNT, 5, "Authorize")
Definition: SField.h:485
ripple::keylet::check
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition: Indexes.cpp:277
std::unique_ptr
STL class.
ripple::LedgerRPC_test::testLedgerCurrent
void testLedgerCurrent()
Definition: LedgerRPC_test.cpp:188
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::LedgerRPC_test::checkErrorValue
void checkErrorValue(Json::Value const &jv, std::string const &err, std::string const &msg)
Definition: LedgerRPC_test.cpp:34
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
ripple::LedgerRPC_test::testLedgerRequest
void testLedgerRequest()
Definition: LedgerRPC_test.cpp:64