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/AccountID.h>
25 #include <ripple/protocol/ErrorCodes.h>
26 #include <ripple/protocol/STXChainBridge.h>
27 #include <ripple/protocol/jss.h>
28 #include <test/jtx.h>
29 #include <test/jtx/attester.h>
30 #include <test/jtx/multisign.h>
31 #include <test/jtx/xchain_bridge.h>
32 
33 namespace ripple {
34 
35 class LedgerRPC_XChain_test : public beast::unit_test::suite,
37 {
38  void
40  Json::Value const& jv,
41  std::string const& err,
42  std::string const& msg)
43  {
44  if (BEAST_EXPECT(jv.isMember(jss::status)))
45  BEAST_EXPECT(jv[jss::status] == "error");
46  if (BEAST_EXPECT(jv.isMember(jss::error)))
47  BEAST_EXPECT(jv[jss::error] == err);
48  if (msg.empty())
49  {
50  BEAST_EXPECT(
51  jv[jss::error_message] == Json::nullValue ||
52  jv[jss::error_message] == "");
53  }
54  else if (BEAST_EXPECT(jv.isMember(jss::error_message)))
55  BEAST_EXPECT(jv[jss::error_message] == msg);
56  }
57 
58  void
60  {
61  testcase("ledger_entry: bridge");
62  using namespace test::jtx;
63 
64  Env mcEnv{*this, features};
65  Env scEnv(*this, envconfig(port_increment, 3), features);
66 
67  createBridgeObjects(mcEnv, scEnv);
68 
69  std::string const ledgerHash{to_string(mcEnv.closed()->info().hash)};
70  std::string bridge_index;
71  Json::Value mcBridge;
72  {
73  // request the bridge via RPC
74  Json::Value jvParams;
75  jvParams[jss::bridge_account] = mcDoor.human();
76  jvParams[jss::bridge] = jvb;
77  Json::Value const jrr = mcEnv.rpc(
78  "json", "ledger_entry", to_string(jvParams))[jss::result];
79 
80  BEAST_EXPECT(jrr.isMember(jss::node));
81  auto r = jrr[jss::node];
82  // std::cout << to_string(r) << '\n';
83 
84  BEAST_EXPECT(r.isMember(jss::Account));
85  BEAST_EXPECT(r[jss::Account] == mcDoor.human());
86 
87  BEAST_EXPECT(r.isMember(jss::Flags));
88 
89  BEAST_EXPECT(r.isMember(sfLedgerEntryType.jsonName));
90  BEAST_EXPECT(r[sfLedgerEntryType.jsonName] == jss::Bridge);
91 
92  // we not created an account yet
93  BEAST_EXPECT(r.isMember(sfXChainAccountCreateCount.jsonName));
94  BEAST_EXPECT(r[sfXChainAccountCreateCount.jsonName].asInt() == 0);
95 
96  // we have not claimed a locking chain tx yet
97  BEAST_EXPECT(r.isMember(sfXChainAccountClaimCount.jsonName));
98  BEAST_EXPECT(r[sfXChainAccountClaimCount.jsonName].asInt() == 0);
99 
100  BEAST_EXPECT(r.isMember(jss::index));
101  bridge_index = r[jss::index].asString();
102  mcBridge = r;
103  }
104  {
105  // request the bridge via RPC by index
106  Json::Value jvParams;
107  jvParams[jss::index] = bridge_index;
108  Json::Value const jrr = mcEnv.rpc(
109  "json", "ledger_entry", to_string(jvParams))[jss::result];
110 
111  BEAST_EXPECT(jrr.isMember(jss::node));
112  BEAST_EXPECT(jrr[jss::node] == mcBridge);
113  }
114  {
115  // swap door accounts and make sure we get an error value
116  Json::Value jvParams;
117  // Sidechain door account is "master", not scDoor
118  jvParams[jss::bridge_account] = Account::master.human();
119  jvParams[jss::bridge] = jvb;
120  jvParams[jss::ledger_hash] = ledgerHash;
121  Json::Value const jrr = mcEnv.rpc(
122  "json", "ledger_entry", to_string(jvParams))[jss::result];
123 
124  checkErrorValue(jrr, "entryNotFound", "");
125  }
126  {
127  // create two claim ids and verify that the bridge counter was
128  // incremented
129  mcEnv(xchain_create_claim_id(mcAlice, jvb, reward, scAlice));
130  mcEnv.close();
131  mcEnv(xchain_create_claim_id(mcBob, jvb, reward, scBob));
132  mcEnv.close();
133 
134  // request the bridge via RPC
135  Json::Value jvParams;
136  jvParams[jss::bridge_account] = mcDoor.human();
137  jvParams[jss::bridge] = jvb;
138  // std::cout << to_string(jvParams) << '\n';
139  Json::Value const jrr = mcEnv.rpc(
140  "json", "ledger_entry", to_string(jvParams))[jss::result];
141 
142  BEAST_EXPECT(jrr.isMember(jss::node));
143  auto r = jrr[jss::node];
144 
145  // we executed two create claim id txs
146  BEAST_EXPECT(r.isMember(sfXChainClaimID.jsonName));
147  BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 2);
148  }
149  }
150 
151  void
153  {
154  testcase("ledger_entry: xchain_claim_id");
155  using namespace test::jtx;
156 
157  Env mcEnv{*this, features};
158  Env scEnv(*this, envconfig(port_increment, 3), features);
159 
160  createBridgeObjects(mcEnv, scEnv);
161 
162  scEnv(xchain_create_claim_id(scAlice, jvb, reward, mcAlice));
163  scEnv.close();
164  scEnv(xchain_create_claim_id(scBob, jvb, reward, mcBob));
165  scEnv.close();
166 
167  std::string bridge_index;
168  {
169  // request the xchain_claim_id via RPC
170  Json::Value jvParams;
171  jvParams[jss::xchain_owned_claim_id] = jvXRPBridgeRPC;
172  jvParams[jss::xchain_owned_claim_id][jss::xchain_owned_claim_id] =
173  1;
174  // std::cout << to_string(jvParams) << '\n';
175  Json::Value const jrr = scEnv.rpc(
176  "json", "ledger_entry", to_string(jvParams))[jss::result];
177 
178  BEAST_EXPECT(jrr.isMember(jss::node));
179  auto r = jrr[jss::node];
180  // std::cout << to_string(r) << '\n';
181 
182  BEAST_EXPECT(r.isMember(jss::Account));
183  BEAST_EXPECT(r[jss::Account] == scAlice.human());
184  BEAST_EXPECT(
185  r[sfLedgerEntryType.jsonName] == jss::XChainOwnedClaimID);
186  BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 1);
187  BEAST_EXPECT(r[sfOwnerNode.jsonName].asInt() == 0);
188  }
189 
190  {
191  // request the xchain_claim_id via RPC
192  Json::Value jvParams;
193  jvParams[jss::xchain_owned_claim_id] = jvXRPBridgeRPC;
194  jvParams[jss::xchain_owned_claim_id][jss::xchain_owned_claim_id] =
195  2;
196  Json::Value const jrr = scEnv.rpc(
197  "json", "ledger_entry", to_string(jvParams))[jss::result];
198 
199  BEAST_EXPECT(jrr.isMember(jss::node));
200  auto r = jrr[jss::node];
201  // std::cout << to_string(r) << '\n';
202 
203  BEAST_EXPECT(r.isMember(jss::Account));
204  BEAST_EXPECT(r[jss::Account] == scBob.human());
205  BEAST_EXPECT(
206  r[sfLedgerEntryType.jsonName] == jss::XChainOwnedClaimID);
207  BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 2);
208  BEAST_EXPECT(r[sfOwnerNode.jsonName].asInt() == 0);
209  }
210  }
211 
212  void
214  {
215  testcase("ledger_entry: xchain_create_account_claim_id");
216  using namespace test::jtx;
217 
218  Env mcEnv{*this, features};
219  Env scEnv(*this, envconfig(port_increment, 3), features);
220 
221  // note: signers.size() and quorum are both 5 in createBridgeObjects
222  createBridgeObjects(mcEnv, scEnv);
223 
224  auto scCarol =
225  Account("scCarol"); // Don't fund it - it will be created with the
226  // xchain transaction
227  auto const amt = XRP(1000);
228  mcEnv(sidechain_xchain_account_create(
229  mcAlice, jvb, scCarol, amt, reward));
230  mcEnv.close();
231 
232  // send less than quorum of attestations (otherwise funds are
233  // immediately transferred and no "claim" object is created)
234  size_t constexpr num_attest = 3;
235  auto attestations = create_account_attestations(
236  scAttester,
237  jvb,
238  mcAlice,
239  amt,
240  reward,
241  payee,
242  /*wasLockingChainSend*/ true,
243  1,
244  scCarol,
245  signers,
246  UT_XCHAIN_DEFAULT_NUM_SIGNERS);
247  for (size_t i = 0; i < num_attest; ++i)
248  {
249  scEnv(attestations[i]);
250  }
251  scEnv.close();
252 
253  {
254  // request the create account claim_id via RPC
255  Json::Value jvParams;
256  jvParams[jss::xchain_owned_create_account_claim_id] =
258  jvParams[jss::xchain_owned_create_account_claim_id]
259  [jss::xchain_owned_create_account_claim_id] = 1;
260  // std::cout << to_string(jvParams) << '\n';
261  Json::Value const jrr = scEnv.rpc(
262  "json", "ledger_entry", to_string(jvParams))[jss::result];
263  // std::cout << to_string(jrr) << '\n';
264 
265  BEAST_EXPECT(jrr.isMember(jss::node));
266  auto r = jrr[jss::node];
267 
268  BEAST_EXPECT(r.isMember(jss::Account));
269  BEAST_EXPECT(r[jss::Account] == Account::master.human());
270 
271  BEAST_EXPECT(r.isMember(sfXChainAccountCreateCount.jsonName));
272  BEAST_EXPECT(r[sfXChainAccountCreateCount.jsonName].asInt() == 1);
273 
274  BEAST_EXPECT(
277  BEAST_EXPECT(attest.isArray());
278  BEAST_EXPECT(attest.size() == 3);
279  BEAST_EXPECT(attest[Json::Value::UInt(0)].isMember(
281  Json::Value a[num_attest];
282  for (size_t i = 0; i < num_attest; ++i)
283  {
284  a[i] = attest[Json::Value::UInt(0)]
286  BEAST_EXPECT(
287  a[i].isMember(jss::Amount) &&
288  a[i][jss::Amount].asInt() == 1000 * drop_per_xrp);
289  BEAST_EXPECT(
290  a[i].isMember(jss::Destination) &&
291  a[i][jss::Destination] == scCarol.human());
292  BEAST_EXPECT(
293  a[i].isMember(sfAttestationSignerAccount.jsonName) &&
294  std::any_of(
295  signers.begin(), signers.end(), [&](signer const& s) {
296  return a[i][sfAttestationSignerAccount.jsonName] ==
297  s.account.human();
298  }));
299  BEAST_EXPECT(
300  a[i].isMember(sfAttestationRewardAccount.jsonName) &&
301  std::any_of(
302  payee.begin(),
303  payee.end(),
304  [&](Account const& account) {
305  return a[i][sfAttestationRewardAccount.jsonName] ==
306  account.human();
307  }));
308  BEAST_EXPECT(
309  a[i].isMember(sfWasLockingChainSend.jsonName) &&
310  a[i][sfWasLockingChainSend.jsonName] == 1);
311  BEAST_EXPECT(
312  a[i].isMember(sfSignatureReward.jsonName) &&
313  a[i][sfSignatureReward.jsonName].asInt() ==
314  1 * drop_per_xrp);
315  }
316  }
317 
318  // complete attestations quorum - CreateAccountClaimID should not be
319  // present anymore
320  for (size_t i = num_attest; i < UT_XCHAIN_DEFAULT_NUM_SIGNERS; ++i)
321  {
322  scEnv(attestations[i]);
323  }
324  scEnv.close();
325  {
326  // request the create account claim_id via RPC
327  Json::Value jvParams;
328  jvParams[jss::xchain_owned_create_account_claim_id] =
330  jvParams[jss::xchain_owned_create_account_claim_id]
331  [jss::xchain_owned_create_account_claim_id] = 1;
332  // std::cout << to_string(jvParams) << '\n';
333  Json::Value const jrr = scEnv.rpc(
334  "json", "ledger_entry", to_string(jvParams))[jss::result];
335  checkErrorValue(jrr, "entryNotFound", "");
336  }
337  }
338 
339 public:
340  void
341  run() override
342  {
346  }
347 };
348 
349 class LedgerRPC_test : public beast::unit_test::suite
350 {
351  void
353  Json::Value const& jv,
354  std::string const& err,
355  std::string const& msg)
356  {
357  if (BEAST_EXPECT(jv.isMember(jss::status)))
358  BEAST_EXPECT(jv[jss::status] == "error");
359  if (BEAST_EXPECT(jv.isMember(jss::error)))
360  BEAST_EXPECT(jv[jss::error] == err);
361  if (msg.empty())
362  {
363  BEAST_EXPECT(
364  jv[jss::error_message] == Json::nullValue ||
365  jv[jss::error_message] == "");
366  }
367  else if (BEAST_EXPECT(jv.isMember(jss::error_message)))
368  BEAST_EXPECT(jv[jss::error_message] == msg);
369  }
370 
371  // Corrupt a valid address by replacing the 10th character with '!'.
372  // '!' is not part of the ripple alphabet.
375  {
376  std::string ret = std::move(good);
377  ret.replace(10, 1, 1, '!');
378  return ret;
379  }
380 
381  void
383  {
384  testcase("Basic Request");
385  using namespace test::jtx;
386 
387  Env env{*this};
388 
389  env.close();
390  BEAST_EXPECT(env.current()->info().seq == 4);
391 
392  {
393  Json::Value jvParams;
394  // can be either numeric or quoted numeric
395  jvParams[jss::ledger_index] = 1;
396  auto const jrr =
397  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
398  BEAST_EXPECT(jrr[jss::ledger][jss::closed] == true);
399  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "1");
400  }
401 
402  {
403  Json::Value jvParams;
404  jvParams[jss::ledger_index] = "1";
405  auto const jrr =
406  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
407  BEAST_EXPECT(jrr[jss::ledger][jss::closed] == true);
408  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "1");
409  }
410 
411  {
412  // using current identifier
413  auto const jrr = env.rpc("ledger", "current")[jss::result];
414  BEAST_EXPECT(jrr[jss::ledger][jss::closed] == false);
415  BEAST_EXPECT(
416  jrr[jss::ledger][jss::ledger_index] ==
417  std::to_string(env.current()->info().seq));
418  BEAST_EXPECT(
419  jrr[jss::ledger_current_index] == env.current()->info().seq);
420  }
421  }
422 
423  void
425  {
426  testcase("Bad Input");
427  using namespace test::jtx;
428  Env env{*this};
429  Account const gw{"gateway"};
430  auto const USD = gw["USD"];
431  Account const bob{"bob"};
432 
433  env.fund(XRP(10000), gw, bob);
434  env.close();
435  env.trust(USD(1000), bob);
436  env.close();
437 
438  {
439  // ask for an arbitrary string - index
440  Json::Value jvParams;
441  jvParams[jss::ledger_index] = "potato";
442  auto const jrr =
443  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
444  checkErrorValue(jrr, "invalidParams", "ledgerIndexMalformed");
445  }
446 
447  {
448  // ask for a negative index
449  Json::Value jvParams;
450  jvParams[jss::ledger_index] = -1;
451  auto const jrr =
452  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
453  checkErrorValue(jrr, "invalidParams", "ledgerIndexMalformed");
454  }
455 
456  {
457  // ask for a bad ledger index
458  Json::Value jvParams;
459  jvParams[jss::ledger_index] = 10u;
460  auto const jrr =
461  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
462  checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound");
463  }
464 
465  {
466  // unrecognized string arg -- error
467  auto const jrr = env.rpc("ledger", "arbitrary_text")[jss::result];
468  checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound");
469  }
470 
471  {
472  // Request queue for closed ledger
473  Json::Value jvParams;
474  jvParams[jss::ledger_index] = "validated";
475  jvParams[jss::queue] = true;
476  auto const jrr =
477  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
478  checkErrorValue(jrr, "invalidParams", "Invalid parameters.");
479  }
480 
481  {
482  // Request a ledger with a very large (double) sequence.
483  auto const ret =
484  env.rpc("json", "ledger", "{ \"ledger_index\" : 2e15 }");
485  BEAST_EXPECT(RPC::contains_error(ret));
486  BEAST_EXPECT(ret[jss::error_message] == "Invalid parameters.");
487  }
488 
489  {
490  // Request a ledger with very large (integer) sequence.
491  auto const ret = env.rpc(
492  "json", "ledger", "{ \"ledger_index\" : 1000000000000000 }");
493  checkErrorValue(ret, "invalidParams", "Invalid parameters.");
494  }
495  }
496 
497  void
499  {
500  testcase("ledger_current Request");
501  using namespace test::jtx;
502 
503  Env env{*this};
504 
505  env.close();
506  BEAST_EXPECT(env.current()->info().seq == 4);
507 
508  {
509  auto const jrr = env.rpc("ledger_current")[jss::result];
510  BEAST_EXPECT(
511  jrr[jss::ledger_current_index] == env.current()->info().seq);
512  }
513  }
514 
515  void
517  {
518  testcase("Missing ledger_entry ledger_hash");
519  using namespace test::jtx;
520  Env env{*this};
521  Account const alice{"alice"};
522  env.fund(XRP(10000), alice);
523  env.close();
524 
525  Json::Value jvParams;
526  jvParams[jss::account_root] = alice.human();
527  jvParams[jss::ledger_hash] =
528  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
529  auto const jrr =
530  env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
531  checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound");
532  }
533 
534  void
536  {
537  testcase("Ledger Request, Full Option");
538  using namespace test::jtx;
539 
540  Env env{*this};
541 
542  env.close();
543 
544  Json::Value jvParams;
545  jvParams[jss::ledger_index] = 3u;
546  jvParams[jss::full] = true;
547  auto const jrr =
548  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
549  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
550  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
551  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 3u);
552  }
553 
554  void
556  {
557  testcase("Ledger Request, Full Option Without Admin");
558  using namespace test::jtx;
559 
560  Env env{*this, envconfig(no_admin)};
561 
562  // env.close();
563 
564  Json::Value jvParams;
565  jvParams[jss::ledger_index] = 1u;
566  jvParams[jss::full] = true;
567  auto const jrr =
568  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
570  jrr, "noPermission", "You don't have permission for this command.");
571  }
572 
573  void
575  {
576  testcase("Ledger Request, Accounts Option");
577  using namespace test::jtx;
578 
579  Env env{*this};
580 
581  env.close();
582 
583  Json::Value jvParams;
584  jvParams[jss::ledger_index] = 3u;
585  jvParams[jss::accounts] = true;
586  auto const jrr =
587  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
588  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
589  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
590  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 3u);
591  }
592 
593  void
595  {
596  testcase("ledger_entry Request AccountRoot");
597  using namespace test::jtx;
598  Env env{*this};
599  Account const alice{"alice"};
600  env.fund(XRP(10000), alice);
601  env.close();
602 
603  std::string const ledgerHash{to_string(env.closed()->info().hash)};
604  {
605  // Exercise ledger_closed along the way.
606  Json::Value const jrr = env.rpc("ledger_closed")[jss::result];
607  BEAST_EXPECT(jrr[jss::ledger_hash] == ledgerHash);
608  BEAST_EXPECT(jrr[jss::ledger_index] == 3);
609  }
610 
611  std::string accountRootIndex;
612  {
613  // Request alice's account root.
614  Json::Value jvParams;
615  jvParams[jss::account_root] = alice.human();
616  jvParams[jss::ledger_hash] = ledgerHash;
617  Json::Value const jrr = env.rpc(
618  "json", "ledger_entry", to_string(jvParams))[jss::result];
619  BEAST_EXPECT(jrr.isMember(jss::node));
620  BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
621  BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] == "10000000000");
622  accountRootIndex = jrr[jss::index].asString();
623  }
624  {
625  constexpr char alicesAcctRootBinary[]{
626  "1100612200800000240000000425000000032D00000000559CE54C3B934E4"
627  "73A995B477E92EC229F99CED5B62BF4D2ACE4DC42719103AE2F6240000002"
628  "540BE4008114AE123A8556F3CF91154711376AFB0F894F832B3D"};
629 
630  // Request alice's account root, but with binary == true;
631  Json::Value jvParams;
632  jvParams[jss::account_root] = alice.human();
633  jvParams[jss::binary] = 1;
634  jvParams[jss::ledger_hash] = ledgerHash;
635  Json::Value const jrr = env.rpc(
636  "json", "ledger_entry", to_string(jvParams))[jss::result];
637  BEAST_EXPECT(jrr.isMember(jss::node_binary));
638  BEAST_EXPECT(jrr[jss::node_binary] == alicesAcctRootBinary);
639  }
640  {
641  // Request alice's account root using the index.
642  Json::Value jvParams;
643  jvParams[jss::index] = accountRootIndex;
644  Json::Value const jrr = env.rpc(
645  "json", "ledger_entry", to_string(jvParams))[jss::result];
646  BEAST_EXPECT(!jrr.isMember(jss::node_binary));
647  BEAST_EXPECT(jrr.isMember(jss::node));
648  BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
649  BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] == "10000000000");
650  }
651  {
652  // Request alice's account root by index, but with binary == false.
653  Json::Value jvParams;
654  jvParams[jss::index] = accountRootIndex;
655  jvParams[jss::binary] = 0;
656  Json::Value const jrr = env.rpc(
657  "json", "ledger_entry", to_string(jvParams))[jss::result];
658  BEAST_EXPECT(jrr.isMember(jss::node));
659  BEAST_EXPECT(jrr[jss::node][jss::Account] == alice.human());
660  BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] == "10000000000");
661  }
662  {
663  // Request using a corrupted AccountID.
664  Json::Value jvParams;
665  jvParams[jss::account_root] = makeBadAddress(alice.human());
666  jvParams[jss::ledger_hash] = ledgerHash;
667  Json::Value const jrr = env.rpc(
668  "json", "ledger_entry", to_string(jvParams))[jss::result];
669  checkErrorValue(jrr, "malformedAddress", "");
670  }
671  {
672  // Request an account that is not in the ledger.
673  Json::Value jvParams;
674  jvParams[jss::account_root] = Account("bob").human();
675  jvParams[jss::ledger_hash] = ledgerHash;
676  Json::Value const jrr = env.rpc(
677  "json", "ledger_entry", to_string(jvParams))[jss::result];
678  checkErrorValue(jrr, "entryNotFound", "");
679  }
680  }
681 
682  void
684  {
685  testcase("ledger_entry Request Check");
686  using namespace test::jtx;
687  Env env{*this};
688  Account const alice{"alice"};
689  env.fund(XRP(10000), alice);
690  env.close();
691 
692  auto const checkId = keylet::check(env.master, env.seq(env.master));
693 
694  env(check::create(env.master, alice, XRP(100)));
695  env.close();
696 
697  std::string const ledgerHash{to_string(env.closed()->info().hash)};
698  {
699  // Request a check.
700  Json::Value jvParams;
701  jvParams[jss::check] = to_string(checkId.key);
702  jvParams[jss::ledger_hash] = ledgerHash;
703  Json::Value const jrr = env.rpc(
704  "json", "ledger_entry", to_string(jvParams))[jss::result];
705  BEAST_EXPECT(
706  jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check);
707  BEAST_EXPECT(jrr[jss::node][sfSendMax.jsonName] == "100000000");
708  }
709  {
710  // Request an index that is not a check. We'll use alice's
711  // account root index.
712  std::string accountRootIndex;
713  {
714  Json::Value jvParams;
715  jvParams[jss::account_root] = alice.human();
716  Json::Value const jrr = env.rpc(
717  "json", "ledger_entry", to_string(jvParams))[jss::result];
718  accountRootIndex = jrr[jss::index].asString();
719  }
720  Json::Value jvParams;
721  jvParams[jss::check] = accountRootIndex;
722  jvParams[jss::ledger_hash] = ledgerHash;
723  Json::Value const jrr = env.rpc(
724  "json", "ledger_entry", to_string(jvParams))[jss::result];
725  checkErrorValue(jrr, "unexpectedLedgerType", "");
726  }
727  }
728 
729  void
731  {
732  testcase("ledger_entry Deposit Preauth");
733 
734  using namespace test::jtx;
735 
736  Env env{*this};
737  Account const alice{"alice"};
738  Account const becky{"becky"};
739 
740  env.fund(XRP(10000), alice, becky);
741  env.close();
742 
743  env(deposit::auth(alice, becky));
744  env.close();
745 
746  std::string const ledgerHash{to_string(env.closed()->info().hash)};
747  std::string depositPreauthIndex;
748  {
749  // Request a depositPreauth by owner and authorized.
750  Json::Value jvParams;
751  jvParams[jss::deposit_preauth][jss::owner] = alice.human();
752  jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
753  jvParams[jss::ledger_hash] = ledgerHash;
754  Json::Value const jrr = env.rpc(
755  "json", "ledger_entry", to_string(jvParams))[jss::result];
756 
757  BEAST_EXPECT(
758  jrr[jss::node][sfLedgerEntryType.jsonName] ==
759  jss::DepositPreauth);
760  BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human());
761  BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == becky.human());
762  depositPreauthIndex = jrr[jss::node][jss::index].asString();
763  }
764  {
765  // Request a depositPreauth by index.
766  Json::Value jvParams;
767  jvParams[jss::deposit_preauth] = depositPreauthIndex;
768  jvParams[jss::ledger_hash] = ledgerHash;
769  Json::Value const jrr = env.rpc(
770  "json", "ledger_entry", to_string(jvParams))[jss::result];
771 
772  BEAST_EXPECT(
773  jrr[jss::node][sfLedgerEntryType.jsonName] ==
774  jss::DepositPreauth);
775  BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human());
776  BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == becky.human());
777  }
778  {
779  // Malformed request: deposit_preauth neither object nor string.
780  Json::Value jvParams;
781  jvParams[jss::deposit_preauth] = -5;
782  jvParams[jss::ledger_hash] = ledgerHash;
783  Json::Value const jrr = env.rpc(
784  "json", "ledger_entry", to_string(jvParams))[jss::result];
785  checkErrorValue(jrr, "malformedRequest", "");
786  }
787  {
788  // Malformed request: deposit_preauth not hex string.
789  Json::Value jvParams;
790  jvParams[jss::deposit_preauth] = "0123456789ABCDEFG";
791  jvParams[jss::ledger_hash] = ledgerHash;
792  Json::Value const jrr = env.rpc(
793  "json", "ledger_entry", to_string(jvParams))[jss::result];
794  checkErrorValue(jrr, "malformedRequest", "");
795  }
796  {
797  // Malformed request: missing [jss::deposit_preauth][jss::owner]
798  Json::Value jvParams;
799  jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
800  jvParams[jss::ledger_hash] = ledgerHash;
801  Json::Value const jrr = env.rpc(
802  "json", "ledger_entry", to_string(jvParams))[jss::result];
803  checkErrorValue(jrr, "malformedRequest", "");
804  }
805  {
806  // Malformed request: [jss::deposit_preauth][jss::owner] not string.
807  Json::Value jvParams;
808  jvParams[jss::deposit_preauth][jss::owner] = 7;
809  jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
810  jvParams[jss::ledger_hash] = ledgerHash;
811  Json::Value const jrr = env.rpc(
812  "json", "ledger_entry", to_string(jvParams))[jss::result];
813  checkErrorValue(jrr, "malformedRequest", "");
814  }
815  {
816  // Malformed: missing [jss::deposit_preauth][jss::authorized]
817  Json::Value jvParams;
818  jvParams[jss::deposit_preauth][jss::owner] = alice.human();
819  jvParams[jss::ledger_hash] = ledgerHash;
820  Json::Value const jrr = env.rpc(
821  "json", "ledger_entry", to_string(jvParams))[jss::result];
822  checkErrorValue(jrr, "malformedRequest", "");
823  }
824  {
825  // Malformed: [jss::deposit_preauth][jss::authorized] not string.
826  Json::Value jvParams;
827  jvParams[jss::deposit_preauth][jss::owner] = alice.human();
828  jvParams[jss::deposit_preauth][jss::authorized] = 47;
829  jvParams[jss::ledger_hash] = ledgerHash;
830  Json::Value const jrr = env.rpc(
831  "json", "ledger_entry", to_string(jvParams))[jss::result];
832  checkErrorValue(jrr, "malformedRequest", "");
833  }
834  {
835  // Malformed: [jss::deposit_preauth][jss::owner] is malformed.
836  Json::Value jvParams;
837  jvParams[jss::deposit_preauth][jss::owner] =
838  "rP6P9ypfAmc!pw8SZHNwM4nvZHFXDraQas";
839 
840  jvParams[jss::deposit_preauth][jss::authorized] = becky.human();
841  jvParams[jss::ledger_hash] = ledgerHash;
842  Json::Value const jrr = env.rpc(
843  "json", "ledger_entry", to_string(jvParams))[jss::result];
844  checkErrorValue(jrr, "malformedOwner", "");
845  }
846  {
847  // Malformed: [jss::deposit_preauth][jss::authorized] is malformed.
848  Json::Value jvParams;
849  jvParams[jss::deposit_preauth][jss::owner] = alice.human();
850  jvParams[jss::deposit_preauth][jss::authorized] =
851  "rP6P9ypfAmc!pw8SZHNwM4nvZHFXDraQas";
852 
853  jvParams[jss::ledger_hash] = ledgerHash;
854  Json::Value const jrr = env.rpc(
855  "json", "ledger_entry", to_string(jvParams))[jss::result];
856  checkErrorValue(jrr, "malformedAuthorized", "");
857  }
858  }
859 
860  void
862  {
863  testcase("ledger_entry Request Directory");
864  using namespace test::jtx;
865  Env env{*this};
866  Account const alice{"alice"};
867  Account const gw{"gateway"};
868  auto const USD = gw["USD"];
869  env.fund(XRP(10000), alice, gw);
870  env.close();
871 
872  env.trust(USD(1000), alice);
873  env.close();
874 
875  // Run up the number of directory entries so alice has two
876  // directory nodes.
877  for (int d = 1'000'032; d >= 1'000'000; --d)
878  {
879  env(offer(alice, USD(1), drops(d)));
880  }
881  env.close();
882 
883  std::string const ledgerHash{to_string(env.closed()->info().hash)};
884  {
885  // Exercise ledger_closed along the way.
886  Json::Value const jrr = env.rpc("ledger_closed")[jss::result];
887  BEAST_EXPECT(jrr[jss::ledger_hash] == ledgerHash);
888  BEAST_EXPECT(jrr[jss::ledger_index] == 5);
889  }
890 
891  std::string const dirRootIndex =
892  "A33EC6BB85FB5674074C4A3A43373BB17645308F3EAE1933E3E35252162B217D";
893  {
894  // Locate directory by index.
895  Json::Value jvParams;
896  jvParams[jss::directory] = dirRootIndex;
897  jvParams[jss::ledger_hash] = ledgerHash;
898  Json::Value const jrr = env.rpc(
899  "json", "ledger_entry", to_string(jvParams))[jss::result];
900  BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].size() == 32);
901  }
902  {
903  // Locate directory by directory root.
904  Json::Value jvParams;
905  jvParams[jss::directory] = Json::objectValue;
906  jvParams[jss::directory][jss::dir_root] = dirRootIndex;
907  Json::Value const jrr = env.rpc(
908  "json", "ledger_entry", to_string(jvParams))[jss::result];
909  BEAST_EXPECT(jrr[jss::index] == dirRootIndex);
910  }
911  {
912  // Locate directory by owner.
913  Json::Value jvParams;
914  jvParams[jss::directory] = Json::objectValue;
915  jvParams[jss::directory][jss::owner] = alice.human();
916  jvParams[jss::ledger_hash] = ledgerHash;
917  Json::Value const jrr = env.rpc(
918  "json", "ledger_entry", to_string(jvParams))[jss::result];
919  BEAST_EXPECT(jrr[jss::index] == dirRootIndex);
920  }
921  {
922  // Locate directory by directory root and sub_index.
923  Json::Value jvParams;
924  jvParams[jss::directory] = Json::objectValue;
925  jvParams[jss::directory][jss::dir_root] = dirRootIndex;
926  jvParams[jss::directory][jss::sub_index] = 1;
927  Json::Value const jrr = env.rpc(
928  "json", "ledger_entry", to_string(jvParams))[jss::result];
929  BEAST_EXPECT(jrr[jss::index] != dirRootIndex);
930  BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].size() == 2);
931  }
932  {
933  // Locate directory by owner and sub_index.
934  Json::Value jvParams;
935  jvParams[jss::directory] = Json::objectValue;
936  jvParams[jss::directory][jss::owner] = alice.human();
937  jvParams[jss::directory][jss::sub_index] = 1;
938  jvParams[jss::ledger_hash] = ledgerHash;
939  Json::Value const jrr = env.rpc(
940  "json", "ledger_entry", to_string(jvParams))[jss::result];
941  BEAST_EXPECT(jrr[jss::index] != dirRootIndex);
942  BEAST_EXPECT(jrr[jss::node][sfIndexes.jsonName].size() == 2);
943  }
944  {
945  // Null directory argument.
946  Json::Value jvParams;
947  jvParams[jss::directory] = Json::nullValue;
948  jvParams[jss::ledger_hash] = ledgerHash;
949  Json::Value const jrr = env.rpc(
950  "json", "ledger_entry", to_string(jvParams))[jss::result];
951  checkErrorValue(jrr, "malformedRequest", "");
952  }
953  {
954  // Non-integer sub_index.
955  Json::Value jvParams;
956  jvParams[jss::directory] = Json::objectValue;
957  jvParams[jss::directory][jss::dir_root] = dirRootIndex;
958  jvParams[jss::directory][jss::sub_index] = 1.5;
959  jvParams[jss::ledger_hash] = ledgerHash;
960  Json::Value const jrr = env.rpc(
961  "json", "ledger_entry", to_string(jvParams))[jss::result];
962  checkErrorValue(jrr, "malformedRequest", "");
963  }
964  {
965  // Malformed owner entry.
966  Json::Value jvParams;
967  jvParams[jss::directory] = Json::objectValue;
968 
969  std::string const badAddress = makeBadAddress(alice.human());
970  jvParams[jss::directory][jss::owner] = badAddress;
971  jvParams[jss::ledger_hash] = ledgerHash;
972  Json::Value const jrr = env.rpc(
973  "json", "ledger_entry", to_string(jvParams))[jss::result];
974  checkErrorValue(jrr, "malformedAddress", "");
975  }
976  {
977  // Malformed directory object. Specify both dir_root and owner.
978  Json::Value jvParams;
979  jvParams[jss::directory] = Json::objectValue;
980  jvParams[jss::directory][jss::owner] = alice.human();
981  jvParams[jss::directory][jss::dir_root] = dirRootIndex;
982  jvParams[jss::ledger_hash] = ledgerHash;
983  Json::Value const jrr = env.rpc(
984  "json", "ledger_entry", to_string(jvParams))[jss::result];
985  checkErrorValue(jrr, "malformedRequest", "");
986  }
987  {
988  // Incomplete directory object. Missing both dir_root and owner.
989  Json::Value jvParams;
990  jvParams[jss::directory] = Json::objectValue;
991  jvParams[jss::directory][jss::sub_index] = 1;
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 
999  void
1001  {
1002  testcase("ledger_entry Request Escrow");
1003  using namespace test::jtx;
1004  Env env{*this};
1005  Account const alice{"alice"};
1006  env.fund(XRP(10000), alice);
1007  env.close();
1008 
1009  // Lambda to create an escrow.
1010  auto escrowCreate = [](test::jtx::Account const& account,
1011  test::jtx::Account const& to,
1012  STAmount const& amount,
1013  NetClock::time_point const& cancelAfter) {
1014  Json::Value jv;
1015  jv[jss::TransactionType] = jss::EscrowCreate;
1016  jv[jss::Flags] = tfUniversal;
1017  jv[jss::Account] = account.human();
1018  jv[jss::Destination] = to.human();
1019  jv[jss::Amount] = amount.getJson(JsonOptions::none);
1020  jv[sfFinishAfter.jsonName] =
1021  cancelAfter.time_since_epoch().count() + 2;
1022  return jv;
1023  };
1024 
1025  using namespace std::chrono_literals;
1026  env(escrowCreate(alice, alice, XRP(333), env.now() + 2s));
1027  env.close();
1028 
1029  std::string const ledgerHash{to_string(env.closed()->info().hash)};
1030  std::string escrowIndex;
1031  {
1032  // Request the escrow using owner and sequence.
1033  Json::Value jvParams;
1034  jvParams[jss::escrow] = Json::objectValue;
1035  jvParams[jss::escrow][jss::owner] = alice.human();
1036  jvParams[jss::escrow][jss::seq] = env.seq(alice) - 1;
1037  Json::Value const jrr = env.rpc(
1038  "json", "ledger_entry", to_string(jvParams))[jss::result];
1039  BEAST_EXPECT(
1040  jrr[jss::node][jss::Amount] == XRP(333).value().getText());
1041  escrowIndex = jrr[jss::index].asString();
1042  }
1043  {
1044  // Request the escrow by index.
1045  Json::Value jvParams;
1046  jvParams[jss::escrow] = escrowIndex;
1047  jvParams[jss::ledger_hash] = ledgerHash;
1048  Json::Value const jrr = env.rpc(
1049  "json", "ledger_entry", to_string(jvParams))[jss::result];
1050  BEAST_EXPECT(
1051  jrr[jss::node][jss::Amount] == XRP(333).value().getText());
1052  }
1053  {
1054  // Malformed owner entry.
1055  Json::Value jvParams;
1056  jvParams[jss::escrow] = Json::objectValue;
1057 
1058  std::string const badAddress = makeBadAddress(alice.human());
1059  jvParams[jss::escrow][jss::owner] = badAddress;
1060  jvParams[jss::escrow][jss::seq] = env.seq(alice) - 1;
1061  jvParams[jss::ledger_hash] = ledgerHash;
1062  Json::Value const jrr = env.rpc(
1063  "json", "ledger_entry", to_string(jvParams))[jss::result];
1064  checkErrorValue(jrr, "malformedOwner", "");
1065  }
1066  {
1067  // Missing owner.
1068  Json::Value jvParams;
1069  jvParams[jss::escrow] = Json::objectValue;
1070  jvParams[jss::escrow][jss::seq] = env.seq(alice) - 1;
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, "malformedRequest", "");
1075  }
1076  {
1077  // Missing sequence.
1078  Json::Value jvParams;
1079  jvParams[jss::escrow] = Json::objectValue;
1080  jvParams[jss::escrow][jss::owner] = alice.human();
1081  jvParams[jss::ledger_hash] = ledgerHash;
1082  Json::Value const jrr = env.rpc(
1083  "json", "ledger_entry", to_string(jvParams))[jss::result];
1084  checkErrorValue(jrr, "malformedRequest", "");
1085  }
1086  {
1087  // Non-integer sequence.
1088  Json::Value jvParams;
1089  jvParams[jss::escrow] = Json::objectValue;
1090  jvParams[jss::escrow][jss::owner] = alice.human();
1091  jvParams[jss::escrow][jss::seq] =
1092  std::to_string(env.seq(alice) - 1);
1093  jvParams[jss::ledger_hash] = ledgerHash;
1094  Json::Value const jrr = env.rpc(
1095  "json", "ledger_entry", to_string(jvParams))[jss::result];
1096  checkErrorValue(jrr, "malformedRequest", "");
1097  }
1098  }
1099 
1100  void
1102  {
1103  testcase("ledger_entry Request Offer");
1104  using namespace test::jtx;
1105  Env env{*this};
1106  Account const alice{"alice"};
1107  Account const gw{"gateway"};
1108  auto const USD = gw["USD"];
1109  env.fund(XRP(10000), alice, gw);
1110  env.close();
1111 
1112  env(offer(alice, USD(321), XRP(322)));
1113  env.close();
1114 
1115  std::string const ledgerHash{to_string(env.closed()->info().hash)};
1116  std::string offerIndex;
1117  {
1118  // Request the offer using owner and sequence.
1119  Json::Value jvParams;
1120  jvParams[jss::offer] = Json::objectValue;
1121  jvParams[jss::offer][jss::account] = alice.human();
1122  jvParams[jss::offer][jss::seq] = env.seq(alice) - 1;
1123  jvParams[jss::ledger_hash] = ledgerHash;
1124  Json::Value const jrr = env.rpc(
1125  "json", "ledger_entry", to_string(jvParams))[jss::result];
1126  BEAST_EXPECT(jrr[jss::node][jss::TakerGets] == "322000000");
1127  offerIndex = jrr[jss::index].asString();
1128  }
1129  {
1130  // Request the offer using its index.
1131  Json::Value jvParams;
1132  jvParams[jss::offer] = offerIndex;
1133  Json::Value const jrr = env.rpc(
1134  "json", "ledger_entry", to_string(jvParams))[jss::result];
1135  BEAST_EXPECT(jrr[jss::node][jss::TakerGets] == "322000000");
1136  }
1137  {
1138  // Malformed account entry.
1139  Json::Value jvParams;
1140  jvParams[jss::offer] = Json::objectValue;
1141 
1142  std::string const badAddress = makeBadAddress(alice.human());
1143  jvParams[jss::offer][jss::account] = badAddress;
1144  jvParams[jss::offer][jss::seq] = env.seq(alice) - 1;
1145  jvParams[jss::ledger_hash] = ledgerHash;
1146  Json::Value const jrr = env.rpc(
1147  "json", "ledger_entry", to_string(jvParams))[jss::result];
1148  checkErrorValue(jrr, "malformedAddress", "");
1149  }
1150  {
1151  // Malformed offer object. Missing account member.
1152  Json::Value jvParams;
1153  jvParams[jss::offer] = Json::objectValue;
1154  jvParams[jss::offer][jss::seq] = env.seq(alice) - 1;
1155  jvParams[jss::ledger_hash] = ledgerHash;
1156  Json::Value const jrr = env.rpc(
1157  "json", "ledger_entry", to_string(jvParams))[jss::result];
1158  checkErrorValue(jrr, "malformedRequest", "");
1159  }
1160  {
1161  // Malformed offer object. Missing seq member.
1162  Json::Value jvParams;
1163  jvParams[jss::offer] = Json::objectValue;
1164  jvParams[jss::offer][jss::account] = alice.human();
1165  jvParams[jss::ledger_hash] = ledgerHash;
1166  Json::Value const jrr = env.rpc(
1167  "json", "ledger_entry", to_string(jvParams))[jss::result];
1168  checkErrorValue(jrr, "malformedRequest", "");
1169  }
1170  {
1171  // Malformed offer object. Non-integral seq member.
1172  Json::Value jvParams;
1173  jvParams[jss::offer] = Json::objectValue;
1174  jvParams[jss::offer][jss::account] = alice.human();
1175  jvParams[jss::offer][jss::seq] = std::to_string(env.seq(alice) - 1);
1176  jvParams[jss::ledger_hash] = ledgerHash;
1177  Json::Value const jrr = env.rpc(
1178  "json", "ledger_entry", to_string(jvParams))[jss::result];
1179  checkErrorValue(jrr, "malformedRequest", "");
1180  }
1181  }
1182 
1183  void
1185  {
1186  testcase("ledger_entry Request Pay Chan");
1187  using namespace test::jtx;
1188  using namespace std::literals::chrono_literals;
1189  Env env{*this};
1190  Account const alice{"alice"};
1191 
1192  env.fund(XRP(10000), alice);
1193  env.close();
1194 
1195  // Lambda to create a PayChan.
1196  auto payChanCreate = [](test::jtx::Account const& account,
1197  test::jtx::Account const& to,
1198  STAmount const& amount,
1199  NetClock::duration const& settleDelay,
1200  PublicKey const& pk) {
1201  Json::Value jv;
1202  jv[jss::TransactionType] = jss::PaymentChannelCreate;
1203  jv[jss::Account] = account.human();
1204  jv[jss::Destination] = to.human();
1205  jv[jss::Amount] = amount.getJson(JsonOptions::none);
1206  jv[sfSettleDelay.jsonName] = settleDelay.count();
1207  jv[sfPublicKey.jsonName] = strHex(pk.slice());
1208  return jv;
1209  };
1210 
1211  env(payChanCreate(alice, env.master, XRP(57), 18s, alice.pk()));
1212  env.close();
1213 
1214  std::string const ledgerHash{to_string(env.closed()->info().hash)};
1215 
1216  uint256 const payChanIndex{
1217  keylet::payChan(alice, env.master, env.seq(alice) - 1).key};
1218  {
1219  // Request the payment channel using its index.
1220  Json::Value jvParams;
1221  jvParams[jss::payment_channel] = to_string(payChanIndex);
1222  jvParams[jss::ledger_hash] = ledgerHash;
1223  Json::Value const jrr = env.rpc(
1224  "json", "ledger_entry", to_string(jvParams))[jss::result];
1225  BEAST_EXPECT(jrr[jss::node][sfAmount.jsonName] == "57000000");
1226  BEAST_EXPECT(jrr[jss::node][sfBalance.jsonName] == "0");
1227  BEAST_EXPECT(jrr[jss::node][sfSettleDelay.jsonName] == 18);
1228  }
1229  {
1230  // Request an index that is not a payment channel.
1231  Json::Value jvParams;
1232  jvParams[jss::payment_channel] = ledgerHash;
1233  jvParams[jss::ledger_hash] = ledgerHash;
1234  Json::Value const jrr = env.rpc(
1235  "json", "ledger_entry", to_string(jvParams))[jss::result];
1236  checkErrorValue(jrr, "entryNotFound", "");
1237  }
1238  }
1239 
1240  void
1242  {
1243  testcase("ledger_entry Request RippleState");
1244  using namespace test::jtx;
1245  Env env{*this};
1246  Account const alice{"alice"};
1247  Account const gw{"gateway"};
1248  auto const USD = gw["USD"];
1249  env.fund(XRP(10000), alice, gw);
1250  env.close();
1251 
1252  env.trust(USD(999), alice);
1253  env.close();
1254 
1255  env(pay(gw, alice, USD(97)));
1256  env.close();
1257 
1258  std::string const ledgerHash{to_string(env.closed()->info().hash)};
1259  {
1260  // Request the trust line using the accounts and currency.
1261  Json::Value jvParams;
1262  jvParams[jss::ripple_state] = Json::objectValue;
1263  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1264  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1265  jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1266  jvParams[jss::ripple_state][jss::currency] = "USD";
1267  jvParams[jss::ledger_hash] = ledgerHash;
1268  Json::Value const jrr = env.rpc(
1269  "json", "ledger_entry", to_string(jvParams))[jss::result];
1270  BEAST_EXPECT(
1271  jrr[jss::node][sfBalance.jsonName][jss::value] == "-97");
1272  BEAST_EXPECT(
1273  jrr[jss::node][sfHighLimit.jsonName][jss::value] == "999");
1274  }
1275  {
1276  // ripple_state is not an object.
1277  Json::Value jvParams;
1278  jvParams[jss::ripple_state] = "ripple_state";
1279  jvParams[jss::ledger_hash] = ledgerHash;
1280  Json::Value const jrr = env.rpc(
1281  "json", "ledger_entry", to_string(jvParams))[jss::result];
1282  checkErrorValue(jrr, "malformedRequest", "");
1283  }
1284  {
1285  // ripple_state.currency is missing.
1286  Json::Value jvParams;
1287  jvParams[jss::ripple_state] = Json::objectValue;
1288  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1289  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1290  jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1291  jvParams[jss::ledger_hash] = ledgerHash;
1292  Json::Value const jrr = env.rpc(
1293  "json", "ledger_entry", to_string(jvParams))[jss::result];
1294  checkErrorValue(jrr, "malformedRequest", "");
1295  }
1296  {
1297  // ripple_state accounts is not an array.
1298  Json::Value jvParams;
1299  jvParams[jss::ripple_state] = Json::objectValue;
1300  jvParams[jss::ripple_state][jss::accounts] = 2;
1301  jvParams[jss::ripple_state][jss::currency] = "USD";
1302  jvParams[jss::ledger_hash] = ledgerHash;
1303  Json::Value const jrr = env.rpc(
1304  "json", "ledger_entry", to_string(jvParams))[jss::result];
1305  checkErrorValue(jrr, "malformedRequest", "");
1306  }
1307  {
1308  // ripple_state one of the accounts is missing.
1309  Json::Value jvParams;
1310  jvParams[jss::ripple_state] = Json::objectValue;
1311  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1312  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1313  jvParams[jss::ripple_state][jss::currency] = "USD";
1314  jvParams[jss::ledger_hash] = ledgerHash;
1315  Json::Value const jrr = env.rpc(
1316  "json", "ledger_entry", to_string(jvParams))[jss::result];
1317  checkErrorValue(jrr, "malformedRequest", "");
1318  }
1319  {
1320  // ripple_state more than 2 accounts.
1321  Json::Value jvParams;
1322  jvParams[jss::ripple_state] = Json::objectValue;
1323  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1324  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1325  jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1326  jvParams[jss::ripple_state][jss::accounts][2u] = alice.human();
1327  jvParams[jss::ripple_state][jss::currency] = "USD";
1328  jvParams[jss::ledger_hash] = ledgerHash;
1329  Json::Value const jrr = env.rpc(
1330  "json", "ledger_entry", to_string(jvParams))[jss::result];
1331  checkErrorValue(jrr, "malformedRequest", "");
1332  }
1333  {
1334  // ripple_state account[0] is not a string.
1335  Json::Value jvParams;
1336  jvParams[jss::ripple_state] = Json::objectValue;
1337  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1338  jvParams[jss::ripple_state][jss::accounts][0u] = 44;
1339  jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1340  jvParams[jss::ripple_state][jss::currency] = "USD";
1341  jvParams[jss::ledger_hash] = ledgerHash;
1342  Json::Value const jrr = env.rpc(
1343  "json", "ledger_entry", to_string(jvParams))[jss::result];
1344  checkErrorValue(jrr, "malformedRequest", "");
1345  }
1346  {
1347  // ripple_state account[1] is not a string.
1348  Json::Value jvParams;
1349  jvParams[jss::ripple_state] = Json::objectValue;
1350  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1351  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1352  jvParams[jss::ripple_state][jss::accounts][1u] = 21;
1353  jvParams[jss::ripple_state][jss::currency] = "USD";
1354  jvParams[jss::ledger_hash] = ledgerHash;
1355  Json::Value const jrr = env.rpc(
1356  "json", "ledger_entry", to_string(jvParams))[jss::result];
1357  checkErrorValue(jrr, "malformedRequest", "");
1358  }
1359  {
1360  // ripple_state account[0] == account[1].
1361  Json::Value jvParams;
1362  jvParams[jss::ripple_state] = Json::objectValue;
1363  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1364  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1365  jvParams[jss::ripple_state][jss::accounts][1u] = alice.human();
1366  jvParams[jss::ripple_state][jss::currency] = "USD";
1367  jvParams[jss::ledger_hash] = ledgerHash;
1368  Json::Value const jrr = env.rpc(
1369  "json", "ledger_entry", to_string(jvParams))[jss::result];
1370  checkErrorValue(jrr, "malformedRequest", "");
1371  }
1372  {
1373  // ripple_state malformed account[0].
1374  Json::Value jvParams;
1375  jvParams[jss::ripple_state] = Json::objectValue;
1376  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1377  jvParams[jss::ripple_state][jss::accounts][0u] =
1378  makeBadAddress(alice.human());
1379  jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1380  jvParams[jss::ripple_state][jss::currency] = "USD";
1381  jvParams[jss::ledger_hash] = ledgerHash;
1382  Json::Value const jrr = env.rpc(
1383  "json", "ledger_entry", to_string(jvParams))[jss::result];
1384  checkErrorValue(jrr, "malformedAddress", "");
1385  }
1386  {
1387  // ripple_state malformed account[1].
1388  Json::Value jvParams;
1389  jvParams[jss::ripple_state] = Json::objectValue;
1390  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1391  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1392  jvParams[jss::ripple_state][jss::accounts][1u] =
1393  makeBadAddress(gw.human());
1394  jvParams[jss::ripple_state][jss::currency] = "USD";
1395  jvParams[jss::ledger_hash] = ledgerHash;
1396  Json::Value const jrr = env.rpc(
1397  "json", "ledger_entry", to_string(jvParams))[jss::result];
1398  checkErrorValue(jrr, "malformedAddress", "");
1399  }
1400  {
1401  // ripple_state malformed currency.
1402  Json::Value jvParams;
1403  jvParams[jss::ripple_state] = Json::objectValue;
1404  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
1405  jvParams[jss::ripple_state][jss::accounts][0u] = alice.human();
1406  jvParams[jss::ripple_state][jss::accounts][1u] = gw.human();
1407  jvParams[jss::ripple_state][jss::currency] = "USDollars";
1408  jvParams[jss::ledger_hash] = ledgerHash;
1409  Json::Value const jrr = env.rpc(
1410  "json", "ledger_entry", to_string(jvParams))[jss::result];
1411  checkErrorValue(jrr, "malformedCurrency", "");
1412  }
1413  }
1414 
1415  void
1417  {
1418  testcase("ledger_entry Request Ticket");
1419  using namespace test::jtx;
1420  Env env{*this};
1421  env.close();
1422 
1423  // Create two tickets.
1424  std::uint32_t const tkt1{env.seq(env.master) + 1};
1425  env(ticket::create(env.master, 2));
1426  env.close();
1427 
1428  std::string const ledgerHash{to_string(env.closed()->info().hash)};
1429  // Request four tickets: one before the first one we created, the
1430  // two created tickets, and the ticket that would come after the
1431  // last created ticket.
1432  {
1433  // Not a valid ticket requested by index.
1434  Json::Value jvParams;
1435  jvParams[jss::ticket] =
1436  to_string(getTicketIndex(env.master, tkt1 - 1));
1437  jvParams[jss::ledger_hash] = ledgerHash;
1438  Json::Value const jrr = env.rpc(
1439  "json", "ledger_entry", to_string(jvParams))[jss::result];
1440  checkErrorValue(jrr, "entryNotFound", "");
1441  }
1442  {
1443  // First real ticket requested by index.
1444  Json::Value jvParams;
1445  jvParams[jss::ticket] = to_string(getTicketIndex(env.master, tkt1));
1446  jvParams[jss::ledger_hash] = ledgerHash;
1447  Json::Value const jrr = env.rpc(
1448  "json", "ledger_entry", to_string(jvParams))[jss::result];
1449  BEAST_EXPECT(
1450  jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Ticket);
1451  BEAST_EXPECT(jrr[jss::node][sfTicketSequence.jsonName] == tkt1);
1452  }
1453  {
1454  // Second real ticket requested by account and sequence.
1455  Json::Value jvParams;
1456  jvParams[jss::ticket] = Json::objectValue;
1457  jvParams[jss::ticket][jss::account] = env.master.human();
1458  jvParams[jss::ticket][jss::ticket_seq] = tkt1 + 1;
1459  jvParams[jss::ledger_hash] = ledgerHash;
1460  Json::Value const jrr = env.rpc(
1461  "json", "ledger_entry", to_string(jvParams))[jss::result];
1462  BEAST_EXPECT(
1463  jrr[jss::node][jss::index] ==
1464  to_string(getTicketIndex(env.master, tkt1 + 1)));
1465  }
1466  {
1467  // Not a valid ticket requested by account and sequence.
1468  Json::Value jvParams;
1469  jvParams[jss::ticket] = Json::objectValue;
1470  jvParams[jss::ticket][jss::account] = env.master.human();
1471  jvParams[jss::ticket][jss::ticket_seq] = tkt1 + 2;
1472  jvParams[jss::ledger_hash] = ledgerHash;
1473  Json::Value const jrr = env.rpc(
1474  "json", "ledger_entry", to_string(jvParams))[jss::result];
1475  checkErrorValue(jrr, "entryNotFound", "");
1476  }
1477  {
1478  // Request a ticket using an account root entry.
1479  Json::Value jvParams;
1480  jvParams[jss::ticket] = to_string(keylet::account(env.master).key);
1481  jvParams[jss::ledger_hash] = ledgerHash;
1482  Json::Value const jrr = env.rpc(
1483  "json", "ledger_entry", to_string(jvParams))[jss::result];
1484  checkErrorValue(jrr, "unexpectedLedgerType", "");
1485  }
1486  {
1487  // Malformed account entry.
1488  Json::Value jvParams;
1489  jvParams[jss::ticket] = Json::objectValue;
1490 
1491  std::string const badAddress = makeBadAddress(env.master.human());
1492  jvParams[jss::ticket][jss::account] = badAddress;
1493  jvParams[jss::ticket][jss::ticket_seq] = env.seq(env.master) - 1;
1494  jvParams[jss::ledger_hash] = ledgerHash;
1495  Json::Value const jrr = env.rpc(
1496  "json", "ledger_entry", to_string(jvParams))[jss::result];
1497  checkErrorValue(jrr, "malformedAddress", "");
1498  }
1499  {
1500  // Malformed ticket object. Missing account member.
1501  Json::Value jvParams;
1502  jvParams[jss::ticket] = Json::objectValue;
1503  jvParams[jss::ticket][jss::ticket_seq] = env.seq(env.master) - 1;
1504  jvParams[jss::ledger_hash] = ledgerHash;
1505  Json::Value const jrr = env.rpc(
1506  "json", "ledger_entry", to_string(jvParams))[jss::result];
1507  checkErrorValue(jrr, "malformedRequest", "");
1508  }
1509  {
1510  // Malformed ticket object. Missing seq member.
1511  Json::Value jvParams;
1512  jvParams[jss::ticket] = Json::objectValue;
1513  jvParams[jss::ticket][jss::account] = env.master.human();
1514  jvParams[jss::ledger_hash] = ledgerHash;
1515  Json::Value const jrr = env.rpc(
1516  "json", "ledger_entry", to_string(jvParams))[jss::result];
1517  checkErrorValue(jrr, "malformedRequest", "");
1518  }
1519  {
1520  // Malformed ticket object. Non-integral seq member.
1521  Json::Value jvParams;
1522  jvParams[jss::ticket] = Json::objectValue;
1523  jvParams[jss::ticket][jss::account] = env.master.human();
1524  jvParams[jss::ticket][jss::ticket_seq] =
1525  std::to_string(env.seq(env.master) - 1);
1526  jvParams[jss::ledger_hash] = ledgerHash;
1527  Json::Value const jrr = env.rpc(
1528  "json", "ledger_entry", to_string(jvParams))[jss::result];
1529  checkErrorValue(jrr, "malformedRequest", "");
1530  }
1531  }
1532 
1533  void
1534  testLedgerEntryInvalidParams(unsigned int apiVersion)
1535  {
1536  testcase(
1537  "ledger_entry Request With Invalid Parameters v" +
1538  std::to_string(apiVersion));
1539  using namespace test::jtx;
1540  Env env{*this};
1541 
1542  std::string const ledgerHash{to_string(env.closed()->info().hash)};
1543 
1544  auto makeParams = [&apiVersion](std::function<void(Json::Value&)> f) {
1545  Json::Value params;
1546  params[jss::api_version] = apiVersion;
1547  f(params);
1548  return params;
1549  };
1550  // "features" is not an option supported by ledger_entry.
1551  {
1552  auto const jvParams =
1553  makeParams([&ledgerHash](Json::Value& jvParams) {
1554  jvParams[jss::features] = ledgerHash;
1555  jvParams[jss::ledger_hash] = ledgerHash;
1556  });
1557  Json::Value const jrr = env.rpc(
1558  "json", "ledger_entry", to_string(jvParams))[jss::result];
1559 
1560  if (apiVersion < 2u)
1561  checkErrorValue(jrr, "unknownOption", "");
1562  else
1563  checkErrorValue(jrr, "invalidParams", "");
1564  }
1565  Json::Value const injectObject = []() {
1567  obj[jss::account] = "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
1568  obj[jss::ledger_index] = "validated";
1569  return obj;
1570  }();
1571  Json::Value const injectArray = []() {
1573  arr[0u] = "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
1574  arr[1u] = "validated";
1575  return arr;
1576  }();
1577 
1578  // invalid input for fields that can handle an object, but can't handle
1579  // an array
1580  for (auto const& field :
1581  {jss::directory, jss::escrow, jss::offer, jss::ticket, jss::amm})
1582  {
1583  auto const jvParams =
1584  makeParams([&field, &injectArray](Json::Value& jvParams) {
1585  jvParams[field] = injectArray;
1586  });
1587 
1588  Json::Value const jrr = env.rpc(
1589  "json", "ledger_entry", to_string(jvParams))[jss::result];
1590 
1591  if (apiVersion < 2u)
1592  checkErrorValue(jrr, "internal", "Internal error.");
1593  else
1594  checkErrorValue(jrr, "invalidParams", "");
1595  }
1596  // Fields that can handle objects just fine
1597  for (auto const& field :
1598  {jss::directory, jss::escrow, jss::offer, jss::ticket, jss::amm})
1599  {
1600  auto const jvParams =
1601  makeParams([&field, &injectObject](Json::Value& jvParams) {
1602  jvParams[field] = injectObject;
1603  });
1604 
1605  Json::Value const jrr = env.rpc(
1606  "json", "ledger_entry", to_string(jvParams))[jss::result];
1607 
1608  checkErrorValue(jrr, "malformedRequest", "");
1609  }
1610 
1611  for (auto const& inject : {injectObject, injectArray})
1612  {
1613  // invalid input for fields that can't handle an object or an array
1614  for (auto const& field :
1615  {jss::index,
1616  jss::account_root,
1617  jss::check,
1618  jss::payment_channel})
1619  {
1620  auto const jvParams =
1621  makeParams([&field, &inject](Json::Value& jvParams) {
1622  jvParams[field] = inject;
1623  });
1624 
1625  Json::Value const jrr = env.rpc(
1626  "json", "ledger_entry", to_string(jvParams))[jss::result];
1627 
1628  if (apiVersion < 2u)
1629  checkErrorValue(jrr, "internal", "Internal error.");
1630  else
1631  checkErrorValue(jrr, "invalidParams", "");
1632  }
1633  // directory sub-fields
1634  for (auto const& field : {jss::dir_root, jss::owner})
1635  {
1636  auto const jvParams =
1637  makeParams([&field, &inject](Json::Value& jvParams) {
1638  jvParams[jss::directory][field] = inject;
1639  });
1640 
1641  Json::Value const jrr = env.rpc(
1642  "json", "ledger_entry", to_string(jvParams))[jss::result];
1643 
1644  if (apiVersion < 2u)
1645  checkErrorValue(jrr, "internal", "Internal error.");
1646  else
1647  checkErrorValue(jrr, "invalidParams", "");
1648  }
1649  // escrow sub-fields
1650  {
1651  auto const jvParams =
1652  makeParams([&inject](Json::Value& jvParams) {
1653  jvParams[jss::escrow][jss::owner] = inject;
1654  jvParams[jss::escrow][jss::seq] = 99;
1655  });
1656 
1657  Json::Value const jrr = env.rpc(
1658  "json", "ledger_entry", to_string(jvParams))[jss::result];
1659 
1660  if (apiVersion < 2u)
1661  checkErrorValue(jrr, "internal", "Internal error.");
1662  else
1663  checkErrorValue(jrr, "invalidParams", "");
1664  }
1665  // offer sub-fields
1666  {
1667  auto const jvParams =
1668  makeParams([&inject](Json::Value& jvParams) {
1669  jvParams[jss::offer][jss::account] = inject;
1670  jvParams[jss::offer][jss::seq] = 99;
1671  });
1672 
1673  Json::Value const jrr = env.rpc(
1674  "json", "ledger_entry", to_string(jvParams))[jss::result];
1675 
1676  if (apiVersion < 2u)
1677  checkErrorValue(jrr, "internal", "Internal error.");
1678  else
1679  checkErrorValue(jrr, "invalidParams", "");
1680  }
1681  // ripple_state sub-fields
1682  {
1683  auto const jvParams =
1684  makeParams([&inject](Json::Value& jvParams) {
1686  rs[jss::currency] = "FOO";
1687  rs[jss::accounts] = Json::Value(Json::arrayValue);
1688  rs[jss::accounts][0u] =
1689  "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
1690  rs[jss::accounts][1u] =
1691  "rKssEq6pg1KbqEqAFnua5mFAL6Ggpsh2wv";
1692  rs[jss::currency] = inject;
1693  jvParams[jss::ripple_state] = std::move(rs);
1694  });
1695 
1696  Json::Value const jrr = env.rpc(
1697  "json", "ledger_entry", to_string(jvParams))[jss::result];
1698 
1699  if (apiVersion < 2u)
1700  checkErrorValue(jrr, "internal", "Internal error.");
1701  else
1702  checkErrorValue(jrr, "invalidParams", "");
1703  }
1704  // ticket sub-fields
1705  {
1706  auto const jvParams =
1707  makeParams([&inject](Json::Value& jvParams) {
1708  jvParams[jss::ticket][jss::account] = inject;
1709  jvParams[jss::ticket][jss::ticket_seq] = 99;
1710  });
1711 
1712  Json::Value const jrr = env.rpc(
1713  "json", "ledger_entry", to_string(jvParams))[jss::result];
1714 
1715  if (apiVersion < 2u)
1716  checkErrorValue(jrr, "internal", "Internal error.");
1717  else
1718  checkErrorValue(jrr, "invalidParams", "");
1719  }
1720 
1721  // Fields that can handle malformed inputs just fine
1722  for (auto const& field : {jss::nft_page, jss::deposit_preauth})
1723  {
1724  auto const jvParams =
1725  makeParams([&field, &inject](Json::Value& jvParams) {
1726  jvParams[field] = inject;
1727  });
1728 
1729  Json::Value const jrr = env.rpc(
1730  "json", "ledger_entry", to_string(jvParams))[jss::result];
1731 
1732  checkErrorValue(jrr, "malformedRequest", "");
1733  }
1734  // Subfields of deposit_preauth that can handle malformed inputs
1735  // fine
1736  for (auto const& field : {jss::owner, jss::authorized})
1737  {
1738  auto const jvParams =
1739  makeParams([&field, &inject](Json::Value& jvParams) {
1740  auto pa = Json::Value(Json::objectValue);
1741  pa[jss::owner] = "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
1742  pa[jss::authorized] =
1743  "rKssEq6pg1KbqEqAFnua5mFAL6Ggpsh2wv";
1744  pa[field] = inject;
1745  jvParams[jss::deposit_preauth] = std::move(pa);
1746  });
1747 
1748  Json::Value const jrr = env.rpc(
1749  "json", "ledger_entry", to_string(jvParams))[jss::result];
1750 
1751  checkErrorValue(jrr, "malformedRequest", "");
1752  }
1753  }
1754  }
1755 
1760  void
1762  {
1763  testcase("Lookup ledger");
1764  using namespace test::jtx;
1765  Env env{*this, FeatureBitset{}}; // hashes requested below assume
1766  // no amendments
1767  env.fund(XRP(10000), "alice");
1768  env.close();
1769  env.fund(XRP(10000), "bob");
1770  env.close();
1771  env.fund(XRP(10000), "jim");
1772  env.close();
1773  env.fund(XRP(10000), "jill");
1774 
1775  {
1776  // access via the legacy ledger field, keyword index values
1777  Json::Value jvParams;
1778  jvParams[jss::ledger] = "closed";
1779  auto jrr = env.rpc(
1780  "json",
1781  "ledger",
1782  boost::lexical_cast<std::string>(jvParams))[jss::result];
1783  BEAST_EXPECT(jrr.isMember(jss::ledger));
1784  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1785  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1786 
1787  jvParams[jss::ledger] = "validated";
1788  jrr = env.rpc(
1789  "json",
1790  "ledger",
1791  boost::lexical_cast<std::string>(jvParams))[jss::result];
1792  BEAST_EXPECT(jrr.isMember(jss::ledger));
1793  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1794  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1795 
1796  jvParams[jss::ledger] = "current";
1797  jrr = env.rpc(
1798  "json",
1799  "ledger",
1800  boost::lexical_cast<std::string>(jvParams))[jss::result];
1801  BEAST_EXPECT(jrr.isMember(jss::ledger));
1802  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
1803 
1804  // ask for a bad ledger keyword
1805  jvParams[jss::ledger] = "invalid";
1806  jrr = env.rpc(
1807  "json",
1808  "ledger",
1809  boost::lexical_cast<std::string>(jvParams))[jss::result];
1810  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1811  BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
1812 
1813  // numeric index
1814  jvParams[jss::ledger] = 4;
1815  jrr = env.rpc(
1816  "json",
1817  "ledger",
1818  boost::lexical_cast<std::string>(jvParams))[jss::result];
1819  BEAST_EXPECT(jrr.isMember(jss::ledger));
1820  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1821  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "4");
1822 
1823  // numeric index - out of range
1824  jvParams[jss::ledger] = 20;
1825  jrr = env.rpc(
1826  "json",
1827  "ledger",
1828  boost::lexical_cast<std::string>(jvParams))[jss::result];
1829  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
1830  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
1831  }
1832 
1833  {
1834  std::string const hash3{
1835  "E86DE7F3D7A4D9CE17EF7C8BA08A8F4D"
1836  "8F643B9552F0D895A31CDA78F541DE4E"};
1837  // access via the ledger_hash field
1838  Json::Value jvParams;
1839  jvParams[jss::ledger_hash] = hash3;
1840  auto jrr = env.rpc(
1841  "json",
1842  "ledger",
1843  boost::lexical_cast<std::string>(jvParams))[jss::result];
1844  BEAST_EXPECT(jrr.isMember(jss::ledger));
1845  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1846  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "3");
1847 
1848  // extra leading hex chars in hash are not allowed
1849  jvParams[jss::ledger_hash] = "DEADBEEF" + hash3;
1850  jrr = env.rpc(
1851  "json",
1852  "ledger",
1853  boost::lexical_cast<std::string>(jvParams))[jss::result];
1854  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1855  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
1856 
1857  // request with non-string ledger_hash
1858  jvParams[jss::ledger_hash] = 2;
1859  jrr = env.rpc(
1860  "json",
1861  "ledger",
1862  boost::lexical_cast<std::string>(jvParams))[jss::result];
1863  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1864  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashNotString");
1865 
1866  // malformed (non hex) hash
1867  jvParams[jss::ledger_hash] =
1868  "2E81FC6EC0DD943197EGC7E3FBE9AE30"
1869  "7F2775F2F7485BB37307984C3C0F2340";
1870  jrr = env.rpc(
1871  "json",
1872  "ledger",
1873  boost::lexical_cast<std::string>(jvParams))[jss::result];
1874  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1875  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
1876 
1877  // properly formed, but just doesn't exist
1878  jvParams[jss::ledger_hash] =
1879  "8C3EEDB3124D92E49E75D81A8826A2E6"
1880  "5A75FD71FC3FD6F36FEB803C5F1D812D";
1881  jrr = env.rpc(
1882  "json",
1883  "ledger",
1884  boost::lexical_cast<std::string>(jvParams))[jss::result];
1885  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
1886  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
1887  }
1888 
1889  {
1890  // access via the ledger_index field, keyword index values
1891  Json::Value jvParams;
1892  jvParams[jss::ledger_index] = "closed";
1893  auto jrr = env.rpc(
1894  "json",
1895  "ledger",
1896  boost::lexical_cast<std::string>(jvParams))[jss::result];
1897  BEAST_EXPECT(jrr.isMember(jss::ledger));
1898  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1899  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1900  BEAST_EXPECT(jrr.isMember(jss::ledger_index));
1901 
1902  jvParams[jss::ledger_index] = "validated";
1903  jrr = env.rpc(
1904  "json",
1905  "ledger",
1906  boost::lexical_cast<std::string>(jvParams))[jss::result];
1907  BEAST_EXPECT(jrr.isMember(jss::ledger));
1908  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1909  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1910 
1911  jvParams[jss::ledger_index] = "current";
1912  jrr = env.rpc(
1913  "json",
1914  "ledger",
1915  boost::lexical_cast<std::string>(jvParams))[jss::result];
1916  BEAST_EXPECT(jrr.isMember(jss::ledger));
1917  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
1918  BEAST_EXPECT(jrr.isMember(jss::ledger_current_index));
1919 
1920  // ask for a bad ledger keyword
1921  jvParams[jss::ledger_index] = "invalid";
1922  jrr = env.rpc(
1923  "json",
1924  "ledger",
1925  boost::lexical_cast<std::string>(jvParams))[jss::result];
1926  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1927  BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
1928 
1929  // numeric index
1930  for (auto i : {1, 2, 3, 4, 5, 6})
1931  {
1932  jvParams[jss::ledger_index] = i;
1933  jrr = env.rpc(
1934  "json",
1935  "ledger",
1936  boost::lexical_cast<std::string>(jvParams))[jss::result];
1937  BEAST_EXPECT(jrr.isMember(jss::ledger));
1938  if (i < 6)
1939  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1940  BEAST_EXPECT(
1941  jrr[jss::ledger][jss::ledger_index] == std::to_string(i));
1942  }
1943 
1944  // numeric index - out of range
1945  jvParams[jss::ledger_index] = 7;
1946  jrr = env.rpc(
1947  "json",
1948  "ledger",
1949  boost::lexical_cast<std::string>(jvParams))[jss::result];
1950  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
1951  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
1952  }
1953  }
1954 
1955  void
1957  {
1958  testcase("Ledger with queueing disabled");
1959  using namespace test::jtx;
1960  Env env{*this};
1961 
1962  Json::Value jv;
1963  jv[jss::ledger_index] = "current";
1964  jv[jss::queue] = true;
1965  jv[jss::expand] = true;
1966 
1967  auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
1968  BEAST_EXPECT(!jrr.isMember(jss::queue_data));
1969  }
1970 
1971  void
1973  {
1974  testcase("Ledger with Queued Transactions");
1975  using namespace test::jtx;
1976  Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
1977  auto& section = cfg->section("transaction_queue");
1978  section.set("minimum_txn_in_ledger_standalone", "3");
1979  section.set("normal_consensus_increase_percent", "0");
1980  return cfg;
1981  })};
1982 
1983  Json::Value jv;
1984  jv[jss::ledger_index] = "current";
1985  jv[jss::queue] = true;
1986  jv[jss::expand] = true;
1987 
1988  Account const alice{"alice"};
1989  Account const bob{"bob"};
1990  Account const charlie{"charlie"};
1991  Account const daria{"daria"};
1992  env.fund(XRP(10000), alice);
1993  env.fund(XRP(10000), bob);
1994  env.close();
1995  env.fund(XRP(10000), charlie);
1996  env.fund(XRP(10000), daria);
1997  env.close();
1998 
1999  auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2000  BEAST_EXPECT(!jrr.isMember(jss::queue_data));
2001 
2002  // Fill the open ledger
2003  for (;;)
2004  {
2005  auto metrics = env.app().getTxQ().getMetrics(*env.current());
2006  if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
2007  break;
2008  env(noop(alice));
2009  }
2010 
2011  BEAST_EXPECT(env.current()->info().seq == 5);
2012  // Put some txs in the queue
2013  // Alice
2014  auto aliceSeq = env.seq(alice);
2015  env(pay(alice, "george", XRP(1000)),
2016  json(R"({"LastLedgerSequence":7})"),
2017  ter(terQUEUED));
2018  env(offer(alice, XRP(50000), alice["USD"](5000)),
2019  seq(aliceSeq + 1),
2020  ter(terQUEUED));
2021  env(noop(alice), seq(aliceSeq + 2), ter(terQUEUED));
2022  // Bob
2023  auto batch = [&env](Account a) {
2024  auto aSeq = env.seq(a);
2025  // Enough fee to get in front of alice in the queue
2026  for (int i = 0; i < 10; ++i)
2027  {
2028  env(noop(a), fee(1000 + i), seq(aSeq + i), ter(terQUEUED));
2029  }
2030  };
2031  batch(bob);
2032  // Charlie
2033  batch(charlie);
2034  // Daria
2035  batch(daria);
2036 
2037  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2038  BEAST_EXPECT(jrr[jss::queue_data].size() == 33);
2039 
2040  // Close enough ledgers so that alice's first tx expires.
2041  env.close();
2042  env.close();
2043  env.close();
2044  BEAST_EXPECT(env.current()->info().seq == 8);
2045 
2046  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2047  BEAST_EXPECT(jrr[jss::queue_data].size() == 11);
2048 
2049  env.close();
2050 
2051  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2052  const std::string txid0 = [&]() {
2053  auto const& parentHash = env.current()->info().parentHash;
2054  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
2055  {
2056  const std::string txid1 = [&]() {
2057  auto const& txj = jrr[jss::queue_data][1u];
2058  BEAST_EXPECT(txj[jss::account] == alice.human());
2059  BEAST_EXPECT(txj[jss::fee_level] == "256");
2060  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2061  BEAST_EXPECT(txj["retries_remaining"] == 10);
2062  BEAST_EXPECT(txj.isMember(jss::tx));
2063  auto const& tx = txj[jss::tx];
2064  BEAST_EXPECT(tx[jss::Account] == alice.human());
2065  BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
2066  return tx[jss::hash].asString();
2067  }();
2068 
2069  auto const& txj = jrr[jss::queue_data][0u];
2070  BEAST_EXPECT(txj[jss::account] == alice.human());
2071  BEAST_EXPECT(txj[jss::fee_level] == "256");
2072  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2073  BEAST_EXPECT(txj["retries_remaining"] == 10);
2074  BEAST_EXPECT(txj.isMember(jss::tx));
2075  auto const& tx = txj[jss::tx];
2076  BEAST_EXPECT(tx[jss::Account] == alice.human());
2077  BEAST_EXPECT(tx[jss::TransactionType] == jss::OfferCreate);
2078  const auto txid0 = tx[jss::hash].asString();
2079  uint256 tx0, tx1;
2080  BEAST_EXPECT(tx0.parseHex(txid0));
2081  BEAST_EXPECT(tx1.parseHex(txid1));
2082  BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
2083  return txid0;
2084  }
2085  return std::string{};
2086  }();
2087 
2088  env.close();
2089 
2090  jv[jss::expand] = false;
2091 
2092  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2093  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
2094  {
2095  auto const& parentHash = env.current()->info().parentHash;
2096  auto const txid1 = [&]() {
2097  auto const& txj = jrr[jss::queue_data][1u];
2098  BEAST_EXPECT(txj[jss::account] == alice.human());
2099  BEAST_EXPECT(txj[jss::fee_level] == "256");
2100  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2101  BEAST_EXPECT(txj.isMember(jss::tx));
2102  return txj[jss::tx].asString();
2103  }();
2104  auto const& txj = jrr[jss::queue_data][0u];
2105  BEAST_EXPECT(txj[jss::account] == alice.human());
2106  BEAST_EXPECT(txj[jss::fee_level] == "256");
2107  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2108  BEAST_EXPECT(txj["retries_remaining"] == 9);
2109  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
2110  BEAST_EXPECT(txj.isMember(jss::tx));
2111  BEAST_EXPECT(txj[jss::tx] == txid0);
2112  uint256 tx0, tx1;
2113  BEAST_EXPECT(tx0.parseHex(txid0));
2114  BEAST_EXPECT(tx1.parseHex(txid1));
2115  BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
2116  }
2117 
2118  env.close();
2119 
2120  jv[jss::expand] = true;
2121  jv[jss::binary] = true;
2122 
2123  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2124  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
2125  {
2126  auto const& txj = jrr[jss::queue_data][1u];
2127  BEAST_EXPECT(txj[jss::account] == alice.human());
2128  BEAST_EXPECT(txj[jss::fee_level] == "256");
2129  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2130  BEAST_EXPECT(txj["retries_remaining"] == 8);
2131  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
2132  BEAST_EXPECT(txj.isMember(jss::tx));
2133  BEAST_EXPECT(txj[jss::tx].isMember(jss::tx_blob));
2134 
2135  auto const& txj2 = jrr[jss::queue_data][0u];
2136  BEAST_EXPECT(txj2[jss::account] == alice.human());
2137  BEAST_EXPECT(txj2[jss::fee_level] == "256");
2138  BEAST_EXPECT(txj2["preflight_result"] == "tesSUCCESS");
2139  BEAST_EXPECT(txj2["retries_remaining"] == 10);
2140  BEAST_EXPECT(!txj2.isMember("last_result"));
2141  BEAST_EXPECT(txj2.isMember(jss::tx));
2142  BEAST_EXPECT(txj2[jss::tx].isMember(jss::tx_blob));
2143  }
2144 
2145  for (int i = 0; i != 9; ++i)
2146  {
2147  env.close();
2148  }
2149 
2150  jv[jss::expand] = false;
2151  jv[jss::binary] = false;
2152 
2153  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2154  const std::string txid2 = [&]() {
2155  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
2156  {
2157  auto const& txj = jrr[jss::queue_data][0u];
2158  BEAST_EXPECT(txj[jss::account] == alice.human());
2159  BEAST_EXPECT(txj[jss::fee_level] == "256");
2160  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2161  BEAST_EXPECT(txj["retries_remaining"] == 1);
2162  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
2163  BEAST_EXPECT(txj.isMember(jss::tx));
2164  BEAST_EXPECT(txj[jss::tx] != txid0);
2165  return txj[jss::tx].asString();
2166  }
2167  return std::string{};
2168  }();
2169 
2170  jv[jss::full] = true;
2171 
2172  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2173  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
2174  {
2175  auto const& txj = jrr[jss::queue_data][0u];
2176  BEAST_EXPECT(txj[jss::account] == alice.human());
2177  BEAST_EXPECT(txj[jss::fee_level] == "256");
2178  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2179  BEAST_EXPECT(txj["retries_remaining"] == 1);
2180  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
2181  BEAST_EXPECT(txj.isMember(jss::tx));
2182  auto const& tx = txj[jss::tx];
2183  BEAST_EXPECT(tx[jss::Account] == alice.human());
2184  BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
2185  BEAST_EXPECT(tx[jss::hash] == txid2);
2186  }
2187  }
2188 
2189  void
2191  {
2192  testcase("Ledger Request, Accounts Hashes");
2193  using namespace test::jtx;
2194 
2195  Env env{*this};
2196 
2197  env.close();
2198 
2199  std::string index;
2200  {
2201  Json::Value jvParams;
2202  jvParams[jss::ledger_index] = 3u;
2203  jvParams[jss::accounts] = true;
2204  jvParams[jss::expand] = true;
2205  jvParams[jss::type] = "hashes";
2206  auto const jrr =
2207  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
2208  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
2209  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
2210  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
2211  BEAST_EXPECT(
2212  jrr[jss::ledger][jss::accountState][0u]["LedgerEntryType"] ==
2213  jss::LedgerHashes);
2214  index = jrr[jss::ledger][jss::accountState][0u]["index"].asString();
2215  }
2216  {
2217  Json::Value jvParams;
2218  jvParams[jss::ledger_index] = 3u;
2219  jvParams[jss::accounts] = true;
2220  jvParams[jss::expand] = false;
2221  jvParams[jss::type] = "hashes";
2222  auto const jrr =
2223  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
2224  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
2225  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
2226  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
2227  BEAST_EXPECT(jrr[jss::ledger][jss::accountState][0u] == index);
2228  }
2229  }
2230 
2231 public:
2232  void
2233  run() override
2234  {
2235  testLedgerRequest();
2236  testBadInput();
2237  testLedgerCurrent();
2238  testMissingLedgerEntryLedgerHash();
2239  testLedgerFull();
2240  testLedgerFullNonAdmin();
2241  testLedgerAccounts();
2242  testLedgerEntryAccountRoot();
2243  testLedgerEntryCheck();
2244  testLedgerEntryDepositPreauth();
2245  testLedgerEntryDirectory();
2246  testLedgerEntryEscrow();
2247  testLedgerEntryOffer();
2248  testLedgerEntryPayChan();
2249  testLedgerEntryRippleState();
2250  testLedgerEntryTicket();
2251  testLookupLedger();
2252  testNoQueue();
2253  testQueue();
2254  testLedgerAccountsOption();
2255 
2258  }
2259 };
2260 
2261 BEAST_DEFINE_TESTSUITE(LedgerRPC, app, ripple);
2262 BEAST_DEFINE_TESTSUITE(LedgerRPC_XChain, app, ripple);
2263 
2264 } // namespace ripple
ripple::test::jtx::XChainBridgeObjects::createBridgeObjects
void createBridgeObjects(Env &mcEnv, Env &scEnv)
Definition: xchain_bridge.cpp:509
ripple::LedgerRPC_test::testLedgerEntryRippleState
void testLedgerEntryRippleState()
Definition: LedgerRPC_test.cpp:1241
ripple::LedgerRPC_XChain_test
Definition: LedgerRPC_test.cpp:35
ripple::LedgerRPC_test::testLookupLedger
void testLookupLedger()
ledger RPC requests as a way to drive input options to lookupLedger.
Definition: LedgerRPC_test.cpp:1761
ripple::sfSendMax
const SF_AMOUNT sfSendMax
std::string
STL class.
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::sfOwnerNode
const SF_UINT64 sfOwnerNode
ripple::test::jtx::XChainBridgeObjects::features
const FeatureBitset features
Definition: xchain_bridge.h:187
ripple::LedgerRPC_test::testLedgerEntryTicket
void testLedgerEntryTicket()
Definition: LedgerRPC_test.cpp:1416
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:1101
ripple::test::jtx::XChainBridgeObjects::jvb
Json::Value jvb
Definition: xchain_bridge.h:184
std::chrono::duration
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:113
ripple::LedgerRPC_test::testNoQueue
void testNoQueue()
Definition: LedgerRPC_test.cpp:1956
ripple::LedgerRPC_test::testLedgerEntryInvalidParams
void testLedgerEntryInvalidParams(unsigned int apiVersion)
Definition: LedgerRPC_test.cpp:1534
ripple::sfTicketSequence
const SF_UINT32 sfTicketSequence
ripple::test::jtx::forAllApiVersions
void forAllApiVersions(VersionedTestCallable auto... testCallable)
Definition: Env.h:743
ripple::sfWasLockingChainSend
const SF_UINT8 sfWasLockingChainSend
std::bind_front
T bind_front(T... args)
std::function
std::any_of
T any_of(T... args)
ripple::sfXChainAccountClaimCount
const SF_UINT64 sfXChainAccountClaimCount
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:141
ripple::getTicketIndex
uint256 getTicketIndex(AccountID const &account, std::uint32_t ticketSeq)
Definition: Indexes.cpp:123
ripple::LedgerRPC_test
Definition: LedgerRPC_test.cpp:349
ripple::sfXChainClaimID
const SF_UINT64 sfXChainClaimID
std::string::replace
T replace(T... args)
ripple::terQUEUED
@ terQUEUED
Definition: TER.h:215
ripple::sfIndexes
const SF_VECTOR256 sfIndexes
ripple::Keylet::key
uint256 key
Definition: Keylet.h:40
ripple::base_uint< 256 >
ripple::test::jtx::XChainBridgeObjects::reward
const STAmount reward
Definition: xchain_bridge.h:194
ripple::test::jtx::XChainBridgeObjects::scCarol
const Account scCarol
Definition: xchain_bridge.h:163
ripple::LedgerRPC_test::testLedgerAccountsOption
void testLedgerAccountsOption()
Definition: LedgerRPC_test.cpp:2190
ripple::LedgerRPC_test::testLedgerFullNonAdmin
void testLedgerFullNonAdmin()
Definition: LedgerRPC_test.cpp:555
ripple::sfSettleDelay
const SF_UINT32 sfSettleDelay
ripple::LedgerRPC_test::testLedgerFull
void testLedgerFull()
Definition: LedgerRPC_test.cpp:535
ripple::sfSignatureReward
const SF_AMOUNT sfSignatureReward
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:196
ripple::PublicKey
A public key.
Definition: PublicKey.h:61
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:141
ripple::LedgerRPC_test::makeBadAddress
std::string makeBadAddress(std::string good)
Definition: LedgerRPC_test.cpp:374
ripple::LedgerRPC_test::testBadInput
void testBadInput()
Definition: LedgerRPC_test.cpp:424
ripple::JsonOptions::none
@ none
ripple::LedgerRPC_test::testQueue
void testQueue()
Definition: LedgerRPC_test.cpp:1972
ripple::LedgerRPC_test::testLedgerEntryAccountRoot
void testLedgerEntryAccountRoot()
Definition: LedgerRPC_test.cpp:594
std::to_string
T to_string(T... args)
ripple::test::jtx::XChainBridgeObjects::payee
const std::vector< Account > payee
Definition: xchain_bridge.h:190
ripple::STAmount
Definition: STAmount.h:46
ripple::LedgerRPC_XChain_test::testLedgerEntryBridge
void testLedgerEntryBridge()
Definition: LedgerRPC_test.cpp:59
ripple::sfXChainCreateAccountProofSig
const SField sfXChainCreateAccountProofSig
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:1000
ripple::LedgerRPC_XChain_test::checkErrorValue
void checkErrorValue(Json::Value const &jv, std::string const &err, std::string const &msg)
Definition: LedgerRPC_test.cpp:39
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::sfAttestationSignerAccount
const SF_ACCOUNT sfAttestationSignerAccount
ripple::sfAuthorize
const SF_ACCOUNT sfAuthorize
std::uint32_t
ripple::sfHighLimit
const SF_AMOUNT sfHighLimit
ripple::test::jtx::XChainBridgeObjects::scAttester
const Account scAttester
Definition: xchain_bridge.h:165
ripple::LedgerRPC_test::run
void run() override
Definition: LedgerRPC_test.cpp:2233
Json::Value::UInt
Json::UInt UInt
Definition: json_value.h:153
ripple::LedgerRPC_test::testLedgerEntryDirectory
void testLedgerEntryDirectory()
Definition: LedgerRPC_test.cpp:861
ripple::LedgerRPC_test::testMissingLedgerEntryLedgerHash
void testMissingLedgerEntryLedgerHash()
Definition: LedgerRPC_test.cpp:516
ripple::LedgerRPC_test::testLedgerEntryPayChan
void testLedgerEntryPayChan()
Definition: LedgerRPC_test.cpp:1184
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:332
ripple::test::jtx::XChainBridgeObjects::mcDoor
const Account mcDoor
Definition: xchain_bridge.h:155
ripple::LedgerRPC_test::testLedgerAccounts
void testLedgerAccounts()
Definition: LedgerRPC_test.cpp:574
ripple::LedgerRPC_XChain_test::testLedgerEntryClaimID
void testLedgerEntryClaimID()
Definition: LedgerRPC_test.cpp:152
ripple::test::jtx::XChainBridgeObjects
Definition: xchain_bridge.h:152
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::test::jtx::XChainBridgeObjects::scBob
const Account scBob
Definition: xchain_bridge.h:162
ripple::LedgerRPC_XChain_test::run
void run() override
Definition: LedgerRPC_test.cpp:341
ripple::sfXChainAccountCreateCount
const SF_UINT64 sfXChainAccountCreateCount
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::test::jtx::XChainBridgeObjects::scAlice
const Account scAlice
Definition: xchain_bridge.h:161
ripple::FeatureBitset
Definition: Feature.h:113
ripple::test::jtx::XChainBridgeObjects::jvXRPBridgeRPC
const Json::Value jvXRPBridgeRPC
Definition: xchain_bridge.h:183
std::string::empty
T empty(T... args)
ripple::sfXChainCreateAccountAttestations
const SField sfXChainCreateAccountAttestations
ripple::test::jtx::XChainBridgeObjects::drop_per_xrp
static constexpr int drop_per_xrp
Definition: xchain_bridge.h:205
ripple::LedgerRPC_test::testLedgerEntryCheck
void testLedgerEntryCheck()
Definition: LedgerRPC_test.cpp:683
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::sfFinishAfter
const SF_UINT32 sfFinishAfter
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::sfAccount
const SF_ACCOUNT sfAccount
Json::Value::asInt
Int asInt() const
Definition: json_value.cpp:503
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::LedgerRPC_test::testLedgerEntryDepositPreauth
void testLedgerEntryDepositPreauth()
Definition: LedgerRPC_test.cpp:730
ripple::sfAttestationRewardAccount
const SF_ACCOUNT sfAttestationRewardAccount
ripple::LedgerRPC_XChain_test::testLedgerEntryCreateAccountClaimID
void testLedgerEntryCreateAccountClaimID()
Definition: LedgerRPC_test.cpp:213
ripple::test::jtx::XChainBridgeObjects::mcBob
const Account mcBob
Definition: xchain_bridge.h:157
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:496
ripple::tfUniversal
constexpr std::uint32_t tfUniversal
Definition: TxFlags.h:59
ripple::keylet::check
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition: Indexes.cpp:289
ripple::test::jtx::XChainBridgeObjects::mcAlice
const Account mcAlice
Definition: xchain_bridge.h:156
std::unique_ptr
STL class.
ripple::sfPublicKey
const SF_VL sfPublicKey
ripple::test::jtx::XChainBridgeObjects::signers
const std::vector< signer > signers
Definition: xchain_bridge.h:188
ripple::LedgerRPC_test::testLedgerCurrent
void testLedgerCurrent()
Definition: LedgerRPC_test.cpp:498
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:352
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:382