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] = 1u;
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[jss::error] == "invalidParams");
1349  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
1350 
1351  // request with non-string ledger_hash
1352  jvParams[jss::ledger_hash] = 2;
1353  jrr = env.rpc(
1354  "json",
1355  "ledger",
1356  boost::lexical_cast<std::string>(jvParams))[jss::result];
1357  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1358  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashNotString");
1359 
1360  // malformed (non hex) hash
1361  jvParams[jss::ledger_hash] =
1362  "ZZZZZZZZZZZD92E49E75D81A8826A2E6"
1363  "5A75FD71FC3FD6F36FEB803C5F1D812D";
1364  jrr = env.rpc(
1365  "json",
1366  "ledger",
1367  boost::lexical_cast<std::string>(jvParams))[jss::result];
1368  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1369  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
1370 
1371  // properly formed, but just doesn't exist
1372  jvParams[jss::ledger_hash] =
1373  "8C3EEDB3124D92E49E75D81A8826A2E6"
1374  "5A75FD71FC3FD6F36FEB803C5F1D812D";
1375  jrr = env.rpc(
1376  "json",
1377  "ledger",
1378  boost::lexical_cast<std::string>(jvParams))[jss::result];
1379  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
1380  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
1381  }
1382 
1383  {
1384  // access via the ledger_index field, keyword index values
1385  Json::Value jvParams;
1386  jvParams[jss::ledger_index] = "closed";
1387  auto jrr = env.rpc(
1388  "json",
1389  "ledger",
1390  boost::lexical_cast<std::string>(jvParams))[jss::result];
1391  BEAST_EXPECT(jrr.isMember(jss::ledger));
1392  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1393  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1394  BEAST_EXPECT(jrr.isMember(jss::ledger_index));
1395 
1396  jvParams[jss::ledger_index] = "validated";
1397  jrr = env.rpc(
1398  "json",
1399  "ledger",
1400  boost::lexical_cast<std::string>(jvParams))[jss::result];
1401  BEAST_EXPECT(jrr.isMember(jss::ledger));
1402  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1403  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1404 
1405  jvParams[jss::ledger_index] = "current";
1406  jrr = env.rpc(
1407  "json",
1408  "ledger",
1409  boost::lexical_cast<std::string>(jvParams))[jss::result];
1410  BEAST_EXPECT(jrr.isMember(jss::ledger));
1411  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
1412  BEAST_EXPECT(jrr.isMember(jss::ledger_current_index));
1413 
1414  // ask for a bad ledger keyword
1415  jvParams[jss::ledger_index] = "invalid";
1416  jrr = env.rpc(
1417  "json",
1418  "ledger",
1419  boost::lexical_cast<std::string>(jvParams))[jss::result];
1420  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1421  BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
1422 
1423  // numeric index
1424  for (auto i : {1, 2, 3, 4, 5, 6})
1425  {
1426  jvParams[jss::ledger_index] = i;
1427  jrr = env.rpc(
1428  "json",
1429  "ledger",
1430  boost::lexical_cast<std::string>(jvParams))[jss::result];
1431  BEAST_EXPECT(jrr.isMember(jss::ledger));
1432  if (i < 6)
1433  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1434  BEAST_EXPECT(
1435  jrr[jss::ledger][jss::ledger_index] == std::to_string(i));
1436  }
1437 
1438  // numeric index - out of range
1439  jvParams[jss::ledger_index] = 7;
1440  jrr = env.rpc(
1441  "json",
1442  "ledger",
1443  boost::lexical_cast<std::string>(jvParams))[jss::result];
1444  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
1445  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
1446  }
1447  }
1448 
1449  void
1451  {
1452  testcase("Ledger with queueing disabled");
1453  using namespace test::jtx;
1454  Env env{*this};
1455 
1456  Json::Value jv;
1457  jv[jss::ledger_index] = "current";
1458  jv[jss::queue] = true;
1459  jv[jss::expand] = true;
1460 
1461  auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1462  BEAST_EXPECT(!jrr.isMember(jss::queue_data));
1463  }
1464 
1465  void
1467  {
1468  testcase("Ledger with Queued Transactions");
1469  using namespace test::jtx;
1470  Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
1471  auto& section = cfg->section("transaction_queue");
1472  section.set("minimum_txn_in_ledger_standalone", "3");
1473  section.set("normal_consensus_increase_percent", "0");
1474  return cfg;
1475  })};
1476 
1477  Json::Value jv;
1478  jv[jss::ledger_index] = "current";
1479  jv[jss::queue] = true;
1480  jv[jss::expand] = true;
1481 
1482  Account const alice{"alice"};
1483  Account const bob{"bob"};
1484  Account const charlie{"charlie"};
1485  Account const daria{"daria"};
1486  env.fund(XRP(10000), alice);
1487  env.fund(XRP(10000), bob);
1488  env.close();
1489  env.fund(XRP(10000), charlie);
1490  env.fund(XRP(10000), daria);
1491  env.close();
1492 
1493  auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1494  BEAST_EXPECT(!jrr.isMember(jss::queue_data));
1495 
1496  // Fill the open ledger
1497  for (;;)
1498  {
1499  auto metrics = env.app().getTxQ().getMetrics(*env.current());
1500  if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
1501  break;
1502  env(noop(alice));
1503  }
1504 
1505  BEAST_EXPECT(env.current()->info().seq == 5);
1506  // Put some txs in the queue
1507  // Alice
1508  auto aliceSeq = env.seq(alice);
1509  env(pay(alice, "george", XRP(1000)),
1510  json(R"({"LastLedgerSequence":7})"),
1511  ter(terQUEUED));
1512  env(offer(alice, XRP(50000), alice["USD"](5000)),
1513  seq(aliceSeq + 1),
1514  ter(terQUEUED));
1515  env(noop(alice), seq(aliceSeq + 2), ter(terQUEUED));
1516  // Bob
1517  auto batch = [&env](Account a) {
1518  auto aSeq = env.seq(a);
1519  // Enough fee to get in front of alice in the queue
1520  for (int i = 0; i < 10; ++i)
1521  {
1522  env(noop(a), fee(1000 + i), seq(aSeq + i), ter(terQUEUED));
1523  }
1524  };
1525  batch(bob);
1526  // Charlie
1527  batch(charlie);
1528  // Daria
1529  batch(daria);
1530 
1531  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1532  BEAST_EXPECT(jrr[jss::queue_data].size() == 33);
1533 
1534  // Close enough ledgers so that alice's first tx expires.
1535  env.close();
1536  env.close();
1537  env.close();
1538  BEAST_EXPECT(env.current()->info().seq == 8);
1539 
1540  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1541  BEAST_EXPECT(jrr[jss::queue_data].size() == 11);
1542 
1543  env.close();
1544 
1545  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1546  std::string txid1;
1547  std::string txid2;
1548  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
1549  {
1550  auto const& txj = jrr[jss::queue_data][0u];
1551  BEAST_EXPECT(txj[jss::account] == alice.human());
1552  BEAST_EXPECT(txj[jss::fee_level] == "256");
1553  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
1554  BEAST_EXPECT(txj["retries_remaining"] == 10);
1555  BEAST_EXPECT(txj.isMember(jss::tx));
1556  auto const& tx = txj[jss::tx];
1557  BEAST_EXPECT(tx[jss::Account] == alice.human());
1558  BEAST_EXPECT(tx[jss::TransactionType] == jss::OfferCreate);
1559  txid1 = tx[jss::hash].asString();
1560  }
1561 
1562  env.close();
1563 
1564  jv[jss::expand] = false;
1565 
1566  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1567  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
1568  {
1569  auto const& txj = jrr[jss::queue_data][0u];
1570  BEAST_EXPECT(txj[jss::account] == alice.human());
1571  BEAST_EXPECT(txj[jss::fee_level] == "256");
1572  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
1573  BEAST_EXPECT(txj["retries_remaining"] == 9);
1574  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
1575  BEAST_EXPECT(txj.isMember(jss::tx));
1576  BEAST_EXPECT(txj[jss::tx] == txid1);
1577  }
1578 
1579  env.close();
1580 
1581  jv[jss::expand] = true;
1582  jv[jss::binary] = true;
1583 
1584  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1585  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
1586  {
1587  auto const& txj = jrr[jss::queue_data][0u];
1588  BEAST_EXPECT(txj[jss::account] == alice.human());
1589  BEAST_EXPECT(txj[jss::fee_level] == "256");
1590  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
1591  BEAST_EXPECT(txj["retries_remaining"] == 8);
1592  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
1593  BEAST_EXPECT(txj.isMember(jss::tx));
1594  BEAST_EXPECT(txj[jss::tx].isMember(jss::tx_blob));
1595 
1596  auto const& txj2 = jrr[jss::queue_data][1u];
1597  BEAST_EXPECT(txj2[jss::account] == alice.human());
1598  BEAST_EXPECT(txj2[jss::fee_level] == "256");
1599  BEAST_EXPECT(txj2["preflight_result"] == "tesSUCCESS");
1600  BEAST_EXPECT(txj2["retries_remaining"] == 10);
1601  BEAST_EXPECT(!txj2.isMember("last_result"));
1602  BEAST_EXPECT(txj2.isMember(jss::tx));
1603  BEAST_EXPECT(txj2[jss::tx].isMember(jss::tx_blob));
1604  }
1605 
1606  for (int i = 0; i != 9; ++i)
1607  {
1608  env.close();
1609  }
1610 
1611  jv[jss::expand] = false;
1612  jv[jss::binary] = false;
1613 
1614  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1615  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
1616  {
1617  auto const& txj = jrr[jss::queue_data][0u];
1618  BEAST_EXPECT(txj[jss::account] == alice.human());
1619  BEAST_EXPECT(txj[jss::fee_level] == "256");
1620  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
1621  BEAST_EXPECT(txj["retries_remaining"] == 1);
1622  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
1623  BEAST_EXPECT(txj.isMember(jss::tx));
1624  BEAST_EXPECT(txj[jss::tx] != txid1);
1625  txid2 = txj[jss::tx].asString();
1626  }
1627 
1628  jv[jss::full] = true;
1629 
1630  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1631  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
1632  {
1633  auto const& txj = jrr[jss::queue_data][0u];
1634  BEAST_EXPECT(txj[jss::account] == alice.human());
1635  BEAST_EXPECT(txj[jss::fee_level] == "256");
1636  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
1637  BEAST_EXPECT(txj["retries_remaining"] == 1);
1638  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
1639  BEAST_EXPECT(txj.isMember(jss::tx));
1640  auto const& tx = txj[jss::tx];
1641  BEAST_EXPECT(tx[jss::Account] == alice.human());
1642  BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
1643  BEAST_EXPECT(tx[jss::hash] == txid2);
1644  }
1645  }
1646 
1647  void
1649  {
1650  testcase("Ledger Request, Accounts Option");
1651  using namespace test::jtx;
1652 
1653  Env env{*this};
1654 
1655  env.close();
1656 
1657  std::string index;
1658  {
1659  Json::Value jvParams;
1660  jvParams[jss::ledger_index] = 3u;
1661  jvParams[jss::accounts] = true;
1662  jvParams[jss::expand] = true;
1663  jvParams[jss::type] = "hashes";
1664  auto const jrr =
1665  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
1666  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
1667  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
1668  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
1669  BEAST_EXPECT(
1670  jrr[jss::ledger][jss::accountState][0u]["LedgerEntryType"] ==
1671  jss::LedgerHashes);
1672  index = jrr[jss::ledger][jss::accountState][0u]["index"].asString();
1673  }
1674  {
1675  Json::Value jvParams;
1676  jvParams[jss::ledger_index] = 3u;
1677  jvParams[jss::accounts] = true;
1678  jvParams[jss::expand] = false;
1679  jvParams[jss::type] = "hashes";
1680  auto const jrr =
1681  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
1682  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
1683  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
1684  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
1685  BEAST_EXPECT(jrr[jss::ledger][jss::accountState][0u] == index);
1686  }
1687  }
1688 
1689 public:
1690  void
1691  run() override
1692  {
1694  testBadInput();
1697  testLedgerFull();
1710  testLookupLedger();
1711  testNoQueue();
1712  testQueue();
1714  }
1715 };
1716 
1717 BEAST_DEFINE_TESTSUITE(LedgerRPC, app, ripple);
1718 
1719 } // 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
ripple::sfSendMax
const SF_AMOUNT sfSendMax
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::sfAmount
const SF_AMOUNT sfAmount
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::LedgerRPC_test::testLedgerEntryOffer
void testLedgerEntryOffer()
Definition: LedgerRPC_test.cpp:791
std::chrono::duration
ripple::LedgerRPC_test::testNoQueue
void testNoQueue()
Definition: LedgerRPC_test.cpp:1450
ripple::sfTicketSequence
const SF_UINT32 sfTicketSequence
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:133
ripple::getTicketIndex
uint256 getTicketIndex(AccountID const &account, std::uint32_t ticketSeq)
Definition: Indexes.cpp:116
ripple::LedgerRPC_test
Definition: LedgerRPC_test.cpp:31
std::string::replace
T replace(T... args)
ripple::terQUEUED
@ terQUEUED
Definition: TER.h:200
ripple::sfIndexes
const SF_VECTOR256 sfIndexes
ripple::Keylet::key
uint256 key
Definition: Keylet.h:41
ripple::base_uint< 256 >
ripple::LedgerRPC_test::testLedgerAccountsOption
void testLedgerAccountsOption()
Definition: LedgerRPC_test.cpp:1648
ripple::LedgerRPC_test::testLedgerFullNonAdmin
void testLedgerFullNonAdmin()
Definition: LedgerRPC_test.cpp:245
ripple::sfSettleDelay
const SF_UINT32 sfSettleDelay
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:134
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:1466
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
ripple::sfAuthorize
const SF_ACCOUNT sfAuthorize
std::uint32_t
ripple::sfHighLimit
const SF_AMOUNT sfHighLimit
ripple::LedgerRPC_test::run
void run() override
Definition: LedgerRPC_test.cpp:1691
ripple::tfUniversal
const std::uint32_t tfUniversal
Definition: TxFlags.h:49
ripple::LedgerRPC_test::testLedgerEntryDirectory
void testLedgerEntryDirectory()
Definition: LedgerRPC_test.cpp:551
ripple::LedgerRPC_test::testMissingLedgerEntryLedgerHash
void testMissingLedgerEntryLedgerHash()
Definition: LedgerRPC_test.cpp:206
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::sfLedgerEntryType
const SF_UINT16 sfLedgerEntryType
ripple::keylet::payChan
Keylet payChan(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Definition: Indexes.cpp:325
ripple::LedgerRPC_test::testLedgerAccounts
void testLedgerAccounts()
Definition: LedgerRPC_test.cpp:264
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::FeatureBitset
Definition: Feature.h:156
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::sfFinishAfter
const SF_UINT32 sfFinishAfter
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:45
ripple::LedgerRPC_test::testLedgerEntryDepositPreauth
void testLedgerEntryDepositPreauth()
Definition: LedgerRPC_test.cpp:420
ripple::keylet::check
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition: Indexes.cpp:282
std::unique_ptr
STL class.
ripple::sfPublicKey
const SF_VL sfPublicKey
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