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
1535  {
1536  testcase("ledger_entry Request DID");
1537  using namespace test::jtx;
1538  using namespace std::literals::chrono_literals;
1539  Env env{*this};
1540  Account const alice{"alice"};
1541 
1542  env.fund(XRP(10000), alice);
1543  env.close();
1544 
1545  // Lambda to create a DID.
1546  auto didCreate = [](test::jtx::Account const& account) {
1547  Json::Value jv;
1548  jv[jss::TransactionType] = jss::DIDSet;
1549  jv[jss::Account] = account.human();
1550  jv[sfDIDDocument.jsonName] = strHex(std::string{"data"});
1551  jv[sfURI.jsonName] = strHex(std::string{"uri"});
1552  return jv;
1553  };
1554 
1555  env(didCreate(alice));
1556  env.close();
1557 
1558  std::string const ledgerHash{to_string(env.closed()->info().hash)};
1559 
1560  {
1561  // Request the DID using its index.
1562  Json::Value jvParams;
1563  jvParams[jss::did] = alice.human();
1564  jvParams[jss::ledger_hash] = ledgerHash;
1565  Json::Value const jrr = env.rpc(
1566  "json", "ledger_entry", to_string(jvParams))[jss::result];
1567  BEAST_EXPECT(
1568  jrr[jss::node][sfDIDDocument.jsonName] ==
1569  strHex(std::string{"data"}));
1570  BEAST_EXPECT(
1571  jrr[jss::node][sfURI.jsonName] == strHex(std::string{"uri"}));
1572  }
1573  {
1574  // Request an index that is not a DID.
1575  Json::Value jvParams;
1576  jvParams[jss::did] = env.master.human();
1577  jvParams[jss::ledger_hash] = ledgerHash;
1578  Json::Value const jrr = env.rpc(
1579  "json", "ledger_entry", to_string(jvParams))[jss::result];
1580  checkErrorValue(jrr, "entryNotFound", "");
1581  }
1582  }
1583 
1584  void
1585  testLedgerEntryInvalidParams(unsigned int apiVersion)
1586  {
1587  testcase(
1588  "ledger_entry Request With Invalid Parameters v" +
1589  std::to_string(apiVersion));
1590  using namespace test::jtx;
1591  Env env{*this};
1592 
1593  std::string const ledgerHash{to_string(env.closed()->info().hash)};
1594 
1595  auto makeParams = [&apiVersion](std::function<void(Json::Value&)> f) {
1596  Json::Value params;
1597  params[jss::api_version] = apiVersion;
1598  f(params);
1599  return params;
1600  };
1601  // "features" is not an option supported by ledger_entry.
1602  {
1603  auto const jvParams =
1604  makeParams([&ledgerHash](Json::Value& jvParams) {
1605  jvParams[jss::features] = ledgerHash;
1606  jvParams[jss::ledger_hash] = ledgerHash;
1607  });
1608  Json::Value const jrr = env.rpc(
1609  "json", "ledger_entry", to_string(jvParams))[jss::result];
1610 
1611  if (apiVersion < 2u)
1612  checkErrorValue(jrr, "unknownOption", "");
1613  else
1614  checkErrorValue(jrr, "invalidParams", "");
1615  }
1616  Json::Value const injectObject = []() {
1618  obj[jss::account] = "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
1619  obj[jss::ledger_index] = "validated";
1620  return obj;
1621  }();
1622  Json::Value const injectArray = []() {
1624  arr[0u] = "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
1625  arr[1u] = "validated";
1626  return arr;
1627  }();
1628 
1629  // invalid input for fields that can handle an object, but can't handle
1630  // an array
1631  for (auto const& field :
1632  {jss::directory, jss::escrow, jss::offer, jss::ticket, jss::amm})
1633  {
1634  auto const jvParams =
1635  makeParams([&field, &injectArray](Json::Value& jvParams) {
1636  jvParams[field] = injectArray;
1637  });
1638 
1639  Json::Value const jrr = env.rpc(
1640  "json", "ledger_entry", to_string(jvParams))[jss::result];
1641 
1642  if (apiVersion < 2u)
1643  checkErrorValue(jrr, "internal", "Internal error.");
1644  else
1645  checkErrorValue(jrr, "invalidParams", "");
1646  }
1647  // Fields that can handle objects just fine
1648  for (auto const& field :
1649  {jss::directory, jss::escrow, jss::offer, jss::ticket, jss::amm})
1650  {
1651  auto const jvParams =
1652  makeParams([&field, &injectObject](Json::Value& jvParams) {
1653  jvParams[field] = injectObject;
1654  });
1655 
1656  Json::Value const jrr = env.rpc(
1657  "json", "ledger_entry", to_string(jvParams))[jss::result];
1658 
1659  checkErrorValue(jrr, "malformedRequest", "");
1660  }
1661 
1662  for (auto const& inject : {injectObject, injectArray})
1663  {
1664  // invalid input for fields that can't handle an object or an array
1665  for (auto const& field :
1666  {jss::index,
1667  jss::account_root,
1668  jss::check,
1669  jss::payment_channel})
1670  {
1671  auto const jvParams =
1672  makeParams([&field, &inject](Json::Value& jvParams) {
1673  jvParams[field] = inject;
1674  });
1675 
1676  Json::Value const jrr = env.rpc(
1677  "json", "ledger_entry", to_string(jvParams))[jss::result];
1678 
1679  if (apiVersion < 2u)
1680  checkErrorValue(jrr, "internal", "Internal error.");
1681  else
1682  checkErrorValue(jrr, "invalidParams", "");
1683  }
1684  // directory sub-fields
1685  for (auto const& field : {jss::dir_root, jss::owner})
1686  {
1687  auto const jvParams =
1688  makeParams([&field, &inject](Json::Value& jvParams) {
1689  jvParams[jss::directory][field] = inject;
1690  });
1691 
1692  Json::Value const jrr = env.rpc(
1693  "json", "ledger_entry", to_string(jvParams))[jss::result];
1694 
1695  if (apiVersion < 2u)
1696  checkErrorValue(jrr, "internal", "Internal error.");
1697  else
1698  checkErrorValue(jrr, "invalidParams", "");
1699  }
1700  // escrow sub-fields
1701  {
1702  auto const jvParams =
1703  makeParams([&inject](Json::Value& jvParams) {
1704  jvParams[jss::escrow][jss::owner] = inject;
1705  jvParams[jss::escrow][jss::seq] = 99;
1706  });
1707 
1708  Json::Value const jrr = env.rpc(
1709  "json", "ledger_entry", to_string(jvParams))[jss::result];
1710 
1711  if (apiVersion < 2u)
1712  checkErrorValue(jrr, "internal", "Internal error.");
1713  else
1714  checkErrorValue(jrr, "invalidParams", "");
1715  }
1716  // offer sub-fields
1717  {
1718  auto const jvParams =
1719  makeParams([&inject](Json::Value& jvParams) {
1720  jvParams[jss::offer][jss::account] = inject;
1721  jvParams[jss::offer][jss::seq] = 99;
1722  });
1723 
1724  Json::Value const jrr = env.rpc(
1725  "json", "ledger_entry", to_string(jvParams))[jss::result];
1726 
1727  if (apiVersion < 2u)
1728  checkErrorValue(jrr, "internal", "Internal error.");
1729  else
1730  checkErrorValue(jrr, "invalidParams", "");
1731  }
1732  // ripple_state sub-fields
1733  {
1734  auto const jvParams =
1735  makeParams([&inject](Json::Value& jvParams) {
1737  rs[jss::currency] = "FOO";
1738  rs[jss::accounts] = Json::Value(Json::arrayValue);
1739  rs[jss::accounts][0u] =
1740  "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
1741  rs[jss::accounts][1u] =
1742  "rKssEq6pg1KbqEqAFnua5mFAL6Ggpsh2wv";
1743  rs[jss::currency] = inject;
1744  jvParams[jss::ripple_state] = std::move(rs);
1745  });
1746 
1747  Json::Value const jrr = env.rpc(
1748  "json", "ledger_entry", to_string(jvParams))[jss::result];
1749 
1750  if (apiVersion < 2u)
1751  checkErrorValue(jrr, "internal", "Internal error.");
1752  else
1753  checkErrorValue(jrr, "invalidParams", "");
1754  }
1755  // ticket sub-fields
1756  {
1757  auto const jvParams =
1758  makeParams([&inject](Json::Value& jvParams) {
1759  jvParams[jss::ticket][jss::account] = inject;
1760  jvParams[jss::ticket][jss::ticket_seq] = 99;
1761  });
1762 
1763  Json::Value const jrr = env.rpc(
1764  "json", "ledger_entry", to_string(jvParams))[jss::result];
1765 
1766  if (apiVersion < 2u)
1767  checkErrorValue(jrr, "internal", "Internal error.");
1768  else
1769  checkErrorValue(jrr, "invalidParams", "");
1770  }
1771 
1772  // Fields that can handle malformed inputs just fine
1773  for (auto const& field : {jss::nft_page, jss::deposit_preauth})
1774  {
1775  auto const jvParams =
1776  makeParams([&field, &inject](Json::Value& jvParams) {
1777  jvParams[field] = inject;
1778  });
1779 
1780  Json::Value const jrr = env.rpc(
1781  "json", "ledger_entry", to_string(jvParams))[jss::result];
1782 
1783  checkErrorValue(jrr, "malformedRequest", "");
1784  }
1785  // Subfields of deposit_preauth that can handle malformed inputs
1786  // fine
1787  for (auto const& field : {jss::owner, jss::authorized})
1788  {
1789  auto const jvParams =
1790  makeParams([&field, &inject](Json::Value& jvParams) {
1791  auto pa = Json::Value(Json::objectValue);
1792  pa[jss::owner] = "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
1793  pa[jss::authorized] =
1794  "rKssEq6pg1KbqEqAFnua5mFAL6Ggpsh2wv";
1795  pa[field] = inject;
1796  jvParams[jss::deposit_preauth] = std::move(pa);
1797  });
1798 
1799  Json::Value const jrr = env.rpc(
1800  "json", "ledger_entry", to_string(jvParams))[jss::result];
1801 
1802  checkErrorValue(jrr, "malformedRequest", "");
1803  }
1804  }
1805  }
1806 
1811  void
1813  {
1814  testcase("Lookup ledger");
1815  using namespace test::jtx;
1816  Env env{*this, FeatureBitset{}}; // hashes requested below assume
1817  // no amendments
1818  env.fund(XRP(10000), "alice");
1819  env.close();
1820  env.fund(XRP(10000), "bob");
1821  env.close();
1822  env.fund(XRP(10000), "jim");
1823  env.close();
1824  env.fund(XRP(10000), "jill");
1825 
1826  {
1827  // access via the legacy ledger field, keyword index values
1828  Json::Value jvParams;
1829  jvParams[jss::ledger] = "closed";
1830  auto jrr = env.rpc(
1831  "json",
1832  "ledger",
1833  boost::lexical_cast<std::string>(jvParams))[jss::result];
1834  BEAST_EXPECT(jrr.isMember(jss::ledger));
1835  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1836  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1837 
1838  jvParams[jss::ledger] = "validated";
1839  jrr = env.rpc(
1840  "json",
1841  "ledger",
1842  boost::lexical_cast<std::string>(jvParams))[jss::result];
1843  BEAST_EXPECT(jrr.isMember(jss::ledger));
1844  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1845  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1846 
1847  jvParams[jss::ledger] = "current";
1848  jrr = env.rpc(
1849  "json",
1850  "ledger",
1851  boost::lexical_cast<std::string>(jvParams))[jss::result];
1852  BEAST_EXPECT(jrr.isMember(jss::ledger));
1853  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
1854 
1855  // ask for a bad ledger keyword
1856  jvParams[jss::ledger] = "invalid";
1857  jrr = env.rpc(
1858  "json",
1859  "ledger",
1860  boost::lexical_cast<std::string>(jvParams))[jss::result];
1861  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1862  BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
1863 
1864  // numeric index
1865  jvParams[jss::ledger] = 4;
1866  jrr = env.rpc(
1867  "json",
1868  "ledger",
1869  boost::lexical_cast<std::string>(jvParams))[jss::result];
1870  BEAST_EXPECT(jrr.isMember(jss::ledger));
1871  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1872  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "4");
1873 
1874  // numeric index - out of range
1875  jvParams[jss::ledger] = 20;
1876  jrr = env.rpc(
1877  "json",
1878  "ledger",
1879  boost::lexical_cast<std::string>(jvParams))[jss::result];
1880  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
1881  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
1882  }
1883 
1884  {
1885  std::string const hash3{
1886  "E86DE7F3D7A4D9CE17EF7C8BA08A8F4D"
1887  "8F643B9552F0D895A31CDA78F541DE4E"};
1888  // access via the ledger_hash field
1889  Json::Value jvParams;
1890  jvParams[jss::ledger_hash] = hash3;
1891  auto jrr = env.rpc(
1892  "json",
1893  "ledger",
1894  boost::lexical_cast<std::string>(jvParams))[jss::result];
1895  BEAST_EXPECT(jrr.isMember(jss::ledger));
1896  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1897  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "3");
1898 
1899  // extra leading hex chars in hash are not allowed
1900  jvParams[jss::ledger_hash] = "DEADBEEF" + hash3;
1901  jrr = env.rpc(
1902  "json",
1903  "ledger",
1904  boost::lexical_cast<std::string>(jvParams))[jss::result];
1905  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1906  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
1907 
1908  // request with non-string ledger_hash
1909  jvParams[jss::ledger_hash] = 2;
1910  jrr = env.rpc(
1911  "json",
1912  "ledger",
1913  boost::lexical_cast<std::string>(jvParams))[jss::result];
1914  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1915  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashNotString");
1916 
1917  // malformed (non hex) hash
1918  jvParams[jss::ledger_hash] =
1919  "2E81FC6EC0DD943197EGC7E3FBE9AE30"
1920  "7F2775F2F7485BB37307984C3C0F2340";
1921  jrr = env.rpc(
1922  "json",
1923  "ledger",
1924  boost::lexical_cast<std::string>(jvParams))[jss::result];
1925  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1926  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
1927 
1928  // properly formed, but just doesn't exist
1929  jvParams[jss::ledger_hash] =
1930  "8C3EEDB3124D92E49E75D81A8826A2E6"
1931  "5A75FD71FC3FD6F36FEB803C5F1D812D";
1932  jrr = env.rpc(
1933  "json",
1934  "ledger",
1935  boost::lexical_cast<std::string>(jvParams))[jss::result];
1936  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
1937  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
1938  }
1939 
1940  {
1941  // access via the ledger_index field, keyword index values
1942  Json::Value jvParams;
1943  jvParams[jss::ledger_index] = "closed";
1944  auto jrr = env.rpc(
1945  "json",
1946  "ledger",
1947  boost::lexical_cast<std::string>(jvParams))[jss::result];
1948  BEAST_EXPECT(jrr.isMember(jss::ledger));
1949  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1950  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1951  BEAST_EXPECT(jrr.isMember(jss::ledger_index));
1952 
1953  jvParams[jss::ledger_index] = "validated";
1954  jrr = env.rpc(
1955  "json",
1956  "ledger",
1957  boost::lexical_cast<std::string>(jvParams))[jss::result];
1958  BEAST_EXPECT(jrr.isMember(jss::ledger));
1959  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1960  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
1961 
1962  jvParams[jss::ledger_index] = "current";
1963  jrr = env.rpc(
1964  "json",
1965  "ledger",
1966  boost::lexical_cast<std::string>(jvParams))[jss::result];
1967  BEAST_EXPECT(jrr.isMember(jss::ledger));
1968  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
1969  BEAST_EXPECT(jrr.isMember(jss::ledger_current_index));
1970 
1971  // ask for a bad ledger keyword
1972  jvParams[jss::ledger_index] = "invalid";
1973  jrr = env.rpc(
1974  "json",
1975  "ledger",
1976  boost::lexical_cast<std::string>(jvParams))[jss::result];
1977  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
1978  BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
1979 
1980  // numeric index
1981  for (auto i : {1, 2, 3, 4, 5, 6})
1982  {
1983  jvParams[jss::ledger_index] = i;
1984  jrr = env.rpc(
1985  "json",
1986  "ledger",
1987  boost::lexical_cast<std::string>(jvParams))[jss::result];
1988  BEAST_EXPECT(jrr.isMember(jss::ledger));
1989  if (i < 6)
1990  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
1991  BEAST_EXPECT(
1992  jrr[jss::ledger][jss::ledger_index] == std::to_string(i));
1993  }
1994 
1995  // numeric index - out of range
1996  jvParams[jss::ledger_index] = 7;
1997  jrr = env.rpc(
1998  "json",
1999  "ledger",
2000  boost::lexical_cast<std::string>(jvParams))[jss::result];
2001  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
2002  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
2003  }
2004  }
2005 
2006  void
2008  {
2009  testcase("Ledger with queueing disabled");
2010  using namespace test::jtx;
2011  Env env{*this};
2012 
2013  Json::Value jv;
2014  jv[jss::ledger_index] = "current";
2015  jv[jss::queue] = true;
2016  jv[jss::expand] = true;
2017 
2018  auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2019  BEAST_EXPECT(!jrr.isMember(jss::queue_data));
2020  }
2021 
2022  void
2024  {
2025  testcase("Ledger with Queued Transactions");
2026  using namespace test::jtx;
2027  Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
2028  auto& section = cfg->section("transaction_queue");
2029  section.set("minimum_txn_in_ledger_standalone", "3");
2030  section.set("normal_consensus_increase_percent", "0");
2031  return cfg;
2032  })};
2033 
2034  Json::Value jv;
2035  jv[jss::ledger_index] = "current";
2036  jv[jss::queue] = true;
2037  jv[jss::expand] = true;
2038 
2039  Account const alice{"alice"};
2040  Account const bob{"bob"};
2041  Account const charlie{"charlie"};
2042  Account const daria{"daria"};
2043  env.fund(XRP(10000), alice);
2044  env.fund(XRP(10000), bob);
2045  env.close();
2046  env.fund(XRP(10000), charlie);
2047  env.fund(XRP(10000), daria);
2048  env.close();
2049 
2050  auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2051  BEAST_EXPECT(!jrr.isMember(jss::queue_data));
2052 
2053  // Fill the open ledger
2054  for (;;)
2055  {
2056  auto metrics = env.app().getTxQ().getMetrics(*env.current());
2057  if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
2058  break;
2059  env(noop(alice));
2060  }
2061 
2062  BEAST_EXPECT(env.current()->info().seq == 5);
2063  // Put some txs in the queue
2064  // Alice
2065  auto aliceSeq = env.seq(alice);
2066  env(pay(alice, "george", XRP(1000)),
2067  json(R"({"LastLedgerSequence":7})"),
2068  ter(terQUEUED));
2069  env(offer(alice, XRP(50000), alice["USD"](5000)),
2070  seq(aliceSeq + 1),
2071  ter(terQUEUED));
2072  env(noop(alice), seq(aliceSeq + 2), ter(terQUEUED));
2073  // Bob
2074  auto batch = [&env](Account a) {
2075  auto aSeq = env.seq(a);
2076  // Enough fee to get in front of alice in the queue
2077  for (int i = 0; i < 10; ++i)
2078  {
2079  env(noop(a), fee(1000 + i), seq(aSeq + i), ter(terQUEUED));
2080  }
2081  };
2082  batch(bob);
2083  // Charlie
2084  batch(charlie);
2085  // Daria
2086  batch(daria);
2087 
2088  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2089  BEAST_EXPECT(jrr[jss::queue_data].size() == 33);
2090 
2091  // Close enough ledgers so that alice's first tx expires.
2092  env.close();
2093  env.close();
2094  env.close();
2095  BEAST_EXPECT(env.current()->info().seq == 8);
2096 
2097  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2098  BEAST_EXPECT(jrr[jss::queue_data].size() == 11);
2099 
2100  env.close();
2101 
2102  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2103  const std::string txid0 = [&]() {
2104  auto const& parentHash = env.current()->info().parentHash;
2105  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
2106  {
2107  const std::string txid1 = [&]() {
2108  auto const& txj = jrr[jss::queue_data][1u];
2109  BEAST_EXPECT(txj[jss::account] == alice.human());
2110  BEAST_EXPECT(txj[jss::fee_level] == "256");
2111  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2112  BEAST_EXPECT(txj["retries_remaining"] == 10);
2113  BEAST_EXPECT(txj.isMember(jss::tx));
2114  auto const& tx = txj[jss::tx];
2115  BEAST_EXPECT(tx[jss::Account] == alice.human());
2116  BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
2117  return tx[jss::hash].asString();
2118  }();
2119 
2120  auto const& txj = jrr[jss::queue_data][0u];
2121  BEAST_EXPECT(txj[jss::account] == alice.human());
2122  BEAST_EXPECT(txj[jss::fee_level] == "256");
2123  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2124  BEAST_EXPECT(txj["retries_remaining"] == 10);
2125  BEAST_EXPECT(txj.isMember(jss::tx));
2126  auto const& tx = txj[jss::tx];
2127  BEAST_EXPECT(tx[jss::Account] == alice.human());
2128  BEAST_EXPECT(tx[jss::TransactionType] == jss::OfferCreate);
2129  const auto txid0 = tx[jss::hash].asString();
2130  uint256 tx0, tx1;
2131  BEAST_EXPECT(tx0.parseHex(txid0));
2132  BEAST_EXPECT(tx1.parseHex(txid1));
2133  BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
2134  return txid0;
2135  }
2136  return std::string{};
2137  }();
2138 
2139  env.close();
2140 
2141  jv[jss::expand] = false;
2142 
2143  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2144  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
2145  {
2146  auto const& parentHash = env.current()->info().parentHash;
2147  auto const txid1 = [&]() {
2148  auto const& txj = jrr[jss::queue_data][1u];
2149  BEAST_EXPECT(txj[jss::account] == alice.human());
2150  BEAST_EXPECT(txj[jss::fee_level] == "256");
2151  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2152  BEAST_EXPECT(txj.isMember(jss::tx));
2153  return txj[jss::tx].asString();
2154  }();
2155  auto const& txj = jrr[jss::queue_data][0u];
2156  BEAST_EXPECT(txj[jss::account] == alice.human());
2157  BEAST_EXPECT(txj[jss::fee_level] == "256");
2158  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2159  BEAST_EXPECT(txj["retries_remaining"] == 9);
2160  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
2161  BEAST_EXPECT(txj.isMember(jss::tx));
2162  BEAST_EXPECT(txj[jss::tx] == txid0);
2163  uint256 tx0, tx1;
2164  BEAST_EXPECT(tx0.parseHex(txid0));
2165  BEAST_EXPECT(tx1.parseHex(txid1));
2166  BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
2167  }
2168 
2169  env.close();
2170 
2171  jv[jss::expand] = true;
2172  jv[jss::binary] = true;
2173 
2174  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2175  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
2176  {
2177  auto const& txj = jrr[jss::queue_data][1u];
2178  BEAST_EXPECT(txj[jss::account] == alice.human());
2179  BEAST_EXPECT(txj[jss::fee_level] == "256");
2180  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2181  BEAST_EXPECT(txj["retries_remaining"] == 8);
2182  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
2183  BEAST_EXPECT(txj.isMember(jss::tx));
2184  BEAST_EXPECT(txj[jss::tx].isMember(jss::tx_blob));
2185 
2186  auto const& txj2 = jrr[jss::queue_data][0u];
2187  BEAST_EXPECT(txj2[jss::account] == alice.human());
2188  BEAST_EXPECT(txj2[jss::fee_level] == "256");
2189  BEAST_EXPECT(txj2["preflight_result"] == "tesSUCCESS");
2190  BEAST_EXPECT(txj2["retries_remaining"] == 10);
2191  BEAST_EXPECT(!txj2.isMember("last_result"));
2192  BEAST_EXPECT(txj2.isMember(jss::tx));
2193  BEAST_EXPECT(txj2[jss::tx].isMember(jss::tx_blob));
2194  }
2195 
2196  for (int i = 0; i != 9; ++i)
2197  {
2198  env.close();
2199  }
2200 
2201  jv[jss::expand] = false;
2202  jv[jss::binary] = false;
2203 
2204  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2205  const std::string txid2 = [&]() {
2206  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
2207  {
2208  auto const& txj = jrr[jss::queue_data][0u];
2209  BEAST_EXPECT(txj[jss::account] == alice.human());
2210  BEAST_EXPECT(txj[jss::fee_level] == "256");
2211  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2212  BEAST_EXPECT(txj["retries_remaining"] == 1);
2213  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
2214  BEAST_EXPECT(txj.isMember(jss::tx));
2215  BEAST_EXPECT(txj[jss::tx] != txid0);
2216  return txj[jss::tx].asString();
2217  }
2218  return std::string{};
2219  }();
2220 
2221  jv[jss::full] = true;
2222 
2223  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
2224  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
2225  {
2226  auto const& txj = jrr[jss::queue_data][0u];
2227  BEAST_EXPECT(txj[jss::account] == alice.human());
2228  BEAST_EXPECT(txj[jss::fee_level] == "256");
2229  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
2230  BEAST_EXPECT(txj["retries_remaining"] == 1);
2231  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
2232  BEAST_EXPECT(txj.isMember(jss::tx));
2233  auto const& tx = txj[jss::tx];
2234  BEAST_EXPECT(tx[jss::Account] == alice.human());
2235  BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
2236  BEAST_EXPECT(tx[jss::hash] == txid2);
2237  }
2238  }
2239 
2240  void
2242  {
2243  testcase("Ledger Request, Accounts Hashes");
2244  using namespace test::jtx;
2245 
2246  Env env{*this};
2247 
2248  env.close();
2249 
2250  std::string index;
2251  {
2252  Json::Value jvParams;
2253  jvParams[jss::ledger_index] = 3u;
2254  jvParams[jss::accounts] = true;
2255  jvParams[jss::expand] = true;
2256  jvParams[jss::type] = "hashes";
2257  auto const jrr =
2258  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
2259  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
2260  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
2261  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
2262  BEAST_EXPECT(
2263  jrr[jss::ledger][jss::accountState][0u]["LedgerEntryType"] ==
2264  jss::LedgerHashes);
2265  index = jrr[jss::ledger][jss::accountState][0u]["index"].asString();
2266  }
2267  {
2268  Json::Value jvParams;
2269  jvParams[jss::ledger_index] = 3u;
2270  jvParams[jss::accounts] = true;
2271  jvParams[jss::expand] = false;
2272  jvParams[jss::type] = "hashes";
2273  auto const jrr =
2274  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
2275  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
2276  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
2277  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
2278  BEAST_EXPECT(jrr[jss::ledger][jss::accountState][0u] == index);
2279  }
2280  }
2281 
2282 public:
2283  void
2284  run() override
2285  {
2286  testLedgerRequest();
2287  testBadInput();
2288  testLedgerCurrent();
2289  testMissingLedgerEntryLedgerHash();
2290  testLedgerFull();
2291  testLedgerFullNonAdmin();
2292  testLedgerAccounts();
2293  testLedgerEntryAccountRoot();
2294  testLedgerEntryCheck();
2295  testLedgerEntryDepositPreauth();
2296  testLedgerEntryDirectory();
2297  testLedgerEntryEscrow();
2298  testLedgerEntryOffer();
2299  testLedgerEntryPayChan();
2300  testLedgerEntryRippleState();
2301  testLedgerEntryTicket();
2302  testLookupLedger();
2303  testNoQueue();
2304  testQueue();
2305  testLedgerAccountsOption();
2306  testLedgerEntryDID();
2307 
2310  }
2311 };
2312 
2313 BEAST_DEFINE_TESTSUITE(LedgerRPC, app, ripple);
2314 BEAST_DEFINE_TESTSUITE(LedgerRPC_XChain, app, ripple);
2315 
2316 } // 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:1812
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:2007
ripple::LedgerRPC_test::testLedgerEntryInvalidParams
void testLedgerEntryInvalidParams(unsigned int apiVersion)
Definition: LedgerRPC_test.cpp:1585
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:163
ripple::getTicketIndex
uint256 getTicketIndex(AccountID const &account, std::uint32_t ticketSeq)
Definition: Indexes.cpp:124
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:218
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:2241
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:142
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::LedgerRPC_test::testQueue
void testQueue()
Definition: LedgerRPC_test.cpp:2023
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:2284
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::sfURI
const SF_VL sfURI
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::JsonOptions::none
@ none
Definition: STBase.h:42
ripple::sfDIDDocument
const SF_VL sfDIDDocument
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:333
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::LedgerRPC_test::testLedgerEntryDID
void testLedgerEntryDID()
Definition: LedgerRPC_test.cpp:1534
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:290
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