rippled
LedgerData_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2016 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/StringUtilities.h>
21 #include <ripple/protocol/Feature.h>
22 #include <ripple/protocol/jss.h>
23 #include <test/jtx.h>
24 
25 namespace ripple {
26 
27 class LedgerData_test : public beast::unit_test::suite
28 {
29 public:
30  // test helper
31  static bool
32  checkArraySize(Json::Value const& val, unsigned int size)
33  {
34  return val.isArray() && val.size() == size;
35  }
36 
37  // test helper
38  static bool
40  {
41  return val.isMember(jss::marker) && val[jss::marker].isString() &&
42  val[jss::marker].asString().size() > 0;
43  }
44 
45  void
47  {
48  using namespace test::jtx;
49  Env env{*this, asAdmin ? envconfig() : envconfig(no_admin)};
50  Account const gw{"gateway"};
51  auto const USD = gw["USD"];
52  env.fund(XRP(100000), gw);
53 
54  int const max_limit = 256; // would be 2048 for binary requests, no
55  // need to test that here
56 
57  for (auto i = 0; i < max_limit + 10; i++)
58  {
59  Account const bob{std::string("bob") + std::to_string(i)};
60  env.fund(XRP(1000), bob);
61  }
62  env.close();
63 
64  // with no limit specified, we get the max_limit if the total number of
65  // accounts is greater than max, which it is here
66  Json::Value jvParams;
67  jvParams[jss::ledger_index] = "current";
68  jvParams[jss::binary] = false;
69  {
70  auto const jrr = env.rpc(
71  "json",
72  "ledger_data",
73  boost::lexical_cast<std::string>(jvParams))[jss::result];
74  BEAST_EXPECT(
75  jrr[jss::ledger_current_index].isIntegral() &&
76  jrr[jss::ledger_current_index].asInt() > 0);
77  BEAST_EXPECT(checkMarker(jrr));
78  BEAST_EXPECT(checkArraySize(jrr[jss::state], max_limit));
79  }
80 
81  // check limits values around the max_limit (+/- 1)
82  for (auto delta = -1; delta <= 1; delta++)
83  {
84  jvParams[jss::limit] = max_limit + delta;
85  auto const jrr = env.rpc(
86  "json",
87  "ledger_data",
88  boost::lexical_cast<std::string>(jvParams))[jss::result];
89  BEAST_EXPECT(checkArraySize(
90  jrr[jss::state],
91  (delta > 0 && !asAdmin) ? max_limit : max_limit + delta));
92  }
93  }
94 
95  void
97  {
98  using namespace test::jtx;
99  Env env{*this, envconfig(no_admin)};
100  Account const gw{"gateway"};
101  auto const USD = gw["USD"];
102  env.fund(XRP(100000), gw);
103 
104  int const num_accounts = 10;
105 
106  for (auto i = 0; i < num_accounts; i++)
107  {
108  Account const bob{std::string("bob") + std::to_string(i)};
109  env.fund(XRP(1000), bob);
110  }
111  env.close();
112 
113  // with no limit specified, we should get all of our fund entries
114  // plus three more related to the gateway setup
115  Json::Value jvParams;
116  jvParams[jss::ledger_index] = "current";
117  jvParams[jss::binary] = true;
118  auto const jrr = env.rpc(
119  "json",
120  "ledger_data",
121  boost::lexical_cast<std::string>(jvParams))[jss::result];
122  BEAST_EXPECT(
123  jrr[jss::ledger_current_index].isIntegral() &&
124  jrr[jss::ledger_current_index].asInt() > 0);
125  BEAST_EXPECT(!jrr.isMember(jss::marker));
126  BEAST_EXPECT(checkArraySize(jrr[jss::state], num_accounts + 3));
127  }
128 
129  void
131  {
132  using namespace test::jtx;
133  Env env{*this};
134  Account const gw{"gateway"};
135  auto const USD = gw["USD"];
136  Account const bob{"bob"};
137 
138  env.fund(XRP(10000), gw, bob);
139  env.trust(USD(1000), bob);
140 
141  {
142  // bad limit
143  Json::Value jvParams;
144  jvParams[jss::limit] = "0"; // NOT an integer
145  auto const jrr = env.rpc(
146  "json",
147  "ledger_data",
148  boost::lexical_cast<std::string>(jvParams))[jss::result];
149  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
150  BEAST_EXPECT(jrr[jss::status] == "error");
151  BEAST_EXPECT(
152  jrr[jss::error_message] ==
153  "Invalid field 'limit', not integer.");
154  }
155 
156  {
157  // invalid marker
158  Json::Value jvParams;
159  jvParams[jss::marker] = "NOT_A_MARKER";
160  auto const jrr = env.rpc(
161  "json",
162  "ledger_data",
163  boost::lexical_cast<std::string>(jvParams))[jss::result];
164  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
165  BEAST_EXPECT(jrr[jss::status] == "error");
166  BEAST_EXPECT(
167  jrr[jss::error_message] ==
168  "Invalid field 'marker', not valid.");
169  }
170 
171  {
172  // invalid marker - not a string
173  Json::Value jvParams;
174  jvParams[jss::marker] = 1;
175  auto const jrr = env.rpc(
176  "json",
177  "ledger_data",
178  boost::lexical_cast<std::string>(jvParams))[jss::result];
179  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
180  BEAST_EXPECT(jrr[jss::status] == "error");
181  BEAST_EXPECT(
182  jrr[jss::error_message] ==
183  "Invalid field 'marker', not valid.");
184  }
185 
186  {
187  // ask for a bad ledger index
188  Json::Value jvParams;
189  jvParams[jss::ledger_index] = 10u;
190  auto const jrr = env.rpc(
191  "json",
192  "ledger_data",
193  boost::lexical_cast<std::string>(jvParams))[jss::result];
194  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
195  BEAST_EXPECT(jrr[jss::status] == "error");
196  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
197  }
198  }
199 
200  void
202  {
203  using namespace test::jtx;
204  Env env{*this, envconfig(no_admin)};
205  Account const gw{"gateway"};
206  auto const USD = gw["USD"];
207  env.fund(XRP(100000), gw);
208 
209  int const num_accounts = 20;
210 
211  for (auto i = 0; i < num_accounts; i++)
212  {
213  Account const bob{std::string("bob") + std::to_string(i)};
214  env.fund(XRP(1000), bob);
215  }
216  env.close();
217 
218  // with no limit specified, we should get all of our fund entries
219  // plus three more related to the gateway setup
220  Json::Value jvParams;
221  jvParams[jss::ledger_index] = "current";
222  jvParams[jss::binary] = false;
223  auto jrr = env.rpc(
224  "json",
225  "ledger_data",
226  boost::lexical_cast<std::string>(jvParams))[jss::result];
227  auto const total_count = jrr[jss::state].size();
228 
229  // now make request with a limit and loop until we get all
230  jvParams[jss::limit] = 5;
231  jrr = env.rpc(
232  "json",
233  "ledger_data",
234  boost::lexical_cast<std::string>(jvParams))[jss::result];
235  BEAST_EXPECT(checkMarker(jrr));
236  auto running_total = jrr[jss::state].size();
237  while (jrr.isMember(jss::marker))
238  {
239  jvParams[jss::marker] = jrr[jss::marker];
240  jrr = env.rpc(
241  "json",
242  "ledger_data",
243  boost::lexical_cast<std::string>(jvParams))[jss::result];
244  running_total += jrr[jss::state].size();
245  }
246  BEAST_EXPECT(running_total == total_count);
247  }
248 
249  void
251  {
252  using namespace test::jtx;
253  Env env{*this};
254  env.fund(XRP(100000), "alice");
255  env.close();
256 
257  // Ledger header should be present in the first query
258  {
259  // Closed ledger with non binary form
260  Json::Value jvParams;
261  jvParams[jss::ledger_index] = "closed";
262  auto jrr = env.rpc(
263  "json",
264  "ledger_data",
265  boost::lexical_cast<std::string>(jvParams))[jss::result];
266  if (BEAST_EXPECT(jrr.isMember(jss::ledger)))
267  BEAST_EXPECT(
268  jrr[jss::ledger][jss::ledger_hash] ==
269  to_string(env.closed()->info().hash));
270  }
271  {
272  // Closed ledger with binary form
273  Json::Value jvParams;
274  jvParams[jss::ledger_index] = "closed";
275  jvParams[jss::binary] = true;
276  auto jrr = env.rpc(
277  "json",
278  "ledger_data",
279  boost::lexical_cast<std::string>(jvParams))[jss::result];
280  if (BEAST_EXPECT(jrr.isMember(jss::ledger)))
281  {
282  auto data =
283  strUnHex(jrr[jss::ledger][jss::ledger_data].asString());
284  if (BEAST_EXPECT(data))
285  {
286  Serializer s(data->data(), data->size());
287  std::uint32_t seq = 0;
288  BEAST_EXPECT(s.getInteger<std::uint32_t>(seq, 0));
289  BEAST_EXPECT(seq == 3);
290  }
291  }
292  }
293  {
294  // Current ledger with binary form
295  Json::Value jvParams;
296  jvParams[jss::binary] = true;
297  auto jrr = env.rpc(
298  "json",
299  "ledger_data",
300  boost::lexical_cast<std::string>(jvParams))[jss::result];
301  BEAST_EXPECT(jrr.isMember(jss::ledger));
302  BEAST_EXPECT(!jrr[jss::ledger].isMember(jss::ledger_data));
303  }
304  }
305 
306  void
308  {
309  // Put a bunch of different LedgerEntryTypes into a ledger
310  using namespace test::jtx;
311  using namespace std::chrono;
312  Env env{
313  *this,
314  envconfig(validator, ""),
315  supported_amendments().set(featureTickets)};
316 
317  Account const gw{"gateway"};
318  auto const USD = gw["USD"];
319  env.fund(XRP(100000), gw);
320 
321  int const num_accounts = 10;
322 
323  for (auto i = 0; i < num_accounts; i++)
324  {
325  Account const bob{std::string("bob") + std::to_string(i)};
326  env.fund(XRP(1000), bob);
327  }
328  env(offer(Account{"bob0"}, USD(100), XRP(100)));
329  env.trust(Account{"bob2"}["USD"](100), Account{"bob3"});
330 
331  auto majorities = getMajorityAmendments(*env.closed());
332  for (int i = 0; i <= 256; ++i)
333  {
334  env.close();
335  majorities = getMajorityAmendments(*env.closed());
336  if (!majorities.empty())
337  break;
338  }
339  env(signers(
340  Account{"bob0"}, 1, {{Account{"bob1"}, 1}, {Account{"bob2"}, 1}}));
341  env(ticket::create(env.master));
342 
343  {
344  Json::Value jv;
345  jv[jss::TransactionType] = jss::EscrowCreate;
346  jv[jss::Flags] = tfUniversal;
347  jv[jss::Account] = Account{"bob5"}.human();
348  jv[jss::Destination] = Account{"bob6"}.human();
349  jv[jss::Amount] = XRP(50).value().getJson(JsonOptions::none);
350  jv[sfFinishAfter.fieldName] = NetClock::time_point{env.now() + 10s}
352  .count();
353  env(jv);
354  }
355 
356  {
357  Json::Value jv;
358  jv[jss::TransactionType] = jss::PaymentChannelCreate;
359  jv[jss::Flags] = tfUniversal;
360  jv[jss::Account] = Account{"bob6"}.human();
361  jv[jss::Destination] = Account{"bob7"}.human();
362  jv[jss::Amount] = XRP(100).value().getJson(JsonOptions::none);
363  jv[jss::SettleDelay] = NetClock::duration{10s}.count();
364  jv[sfPublicKey.fieldName] = strHex(Account{"bob6"}.pk().slice());
365  jv[sfCancelAfter.fieldName] = NetClock::time_point{env.now() + 300s}
367  .count();
368  env(jv);
369  }
370 
371  env(check::create("bob6", "bob7", XRP(100)));
372 
373  // bob9 DepositPreauths bob4 and bob8.
374  env(deposit::auth(Account{"bob9"}, Account{"bob4"}));
375  env(deposit::auth(Account{"bob9"}, Account{"bob8"}));
376  env.close();
377 
378  // Now fetch each type
379  auto makeRequest = [&env](Json::StaticString t) {
380  Json::Value jvParams;
381  jvParams[jss::ledger_index] = "current";
382  jvParams[jss::type] = t;
383  return env.rpc(
384  "json",
385  "ledger_data",
386  boost::lexical_cast<std::string>(jvParams))[jss::result];
387  };
388 
389  { // jvParams[jss::type] = "account";
390  auto const jrr = makeRequest(jss::account);
391  BEAST_EXPECT(checkArraySize(jrr[jss::state], 12));
392  for (auto const& j : jrr[jss::state])
393  BEAST_EXPECT(j["LedgerEntryType"] == jss::AccountRoot);
394  }
395 
396  { // jvParams[jss::type] = "amendments";
397  auto const jrr = makeRequest(jss::amendments);
398  BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
399  for (auto const& j : jrr[jss::state])
400  BEAST_EXPECT(j["LedgerEntryType"] == jss::Amendments);
401  }
402 
403  { // jvParams[jss::type] = "check";
404  auto const jrr = makeRequest(jss::check);
405  BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
406  for (auto const& j : jrr[jss::state])
407  BEAST_EXPECT(j["LedgerEntryType"] == jss::Check);
408  }
409 
410  { // jvParams[jss::type] = "directory";
411  auto const jrr = makeRequest(jss::directory);
412  BEAST_EXPECT(checkArraySize(jrr[jss::state], 9));
413  for (auto const& j : jrr[jss::state])
414  BEAST_EXPECT(j["LedgerEntryType"] == jss::DirectoryNode);
415  }
416 
417  { // jvParams[jss::type] = "fee";
418  auto const jrr = makeRequest(jss::fee);
419  BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
420  for (auto const& j : jrr[jss::state])
421  BEAST_EXPECT(j["LedgerEntryType"] == jss::FeeSettings);
422  }
423 
424  { // jvParams[jss::type] = "hashes";
425  auto const jrr = makeRequest(jss::hashes);
426  BEAST_EXPECT(checkArraySize(jrr[jss::state], 2));
427  for (auto const& j : jrr[jss::state])
428  BEAST_EXPECT(j["LedgerEntryType"] == jss::LedgerHashes);
429  }
430 
431  { // jvParams[jss::type] = "offer";
432  auto const jrr = makeRequest(jss::offer);
433  BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
434  for (auto const& j : jrr[jss::state])
435  BEAST_EXPECT(j["LedgerEntryType"] == jss::Offer);
436  }
437 
438  { // jvParams[jss::type] = "signer_list";
439  auto const jrr = makeRequest(jss::signer_list);
440  BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
441  for (auto const& j : jrr[jss::state])
442  BEAST_EXPECT(j["LedgerEntryType"] == jss::SignerList);
443  }
444 
445  { // jvParams[jss::type] = "state";
446  auto const jrr = makeRequest(jss::state);
447  BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
448  for (auto const& j : jrr[jss::state])
449  BEAST_EXPECT(j["LedgerEntryType"] == jss::RippleState);
450  }
451 
452  { // jvParams[jss::type] = "ticket";
453  auto const jrr = makeRequest(jss::ticket);
454  BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
455  for (auto const& j : jrr[jss::state])
456  BEAST_EXPECT(j["LedgerEntryType"] == jss::Ticket);
457  }
458 
459  { // jvParams[jss::type] = "escrow";
460  auto const jrr = makeRequest(jss::escrow);
461  BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
462  for (auto const& j : jrr[jss::state])
463  BEAST_EXPECT(j["LedgerEntryType"] == jss::Escrow);
464  }
465 
466  { // jvParams[jss::type] = "payment_channel";
467  auto const jrr = makeRequest(jss::payment_channel);
468  BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
469  for (auto const& j : jrr[jss::state])
470  BEAST_EXPECT(j["LedgerEntryType"] == jss::PayChannel);
471  }
472 
473  { // jvParams[jss::type] = "deposit_preauth";
474  auto const jrr = makeRequest(jss::deposit_preauth);
475  BEAST_EXPECT(checkArraySize(jrr[jss::state], 2));
476  for (auto const& j : jrr[jss::state])
477  BEAST_EXPECT(j["LedgerEntryType"] == jss::DepositPreauth);
478  }
479 
480  { // jvParams[jss::type] = "misspelling";
481  Json::Value jvParams;
482  jvParams[jss::ledger_index] = "current";
483  jvParams[jss::type] = "misspelling";
484  auto const jrr = env.rpc(
485  "json",
486  "ledger_data",
487  boost::lexical_cast<std::string>(jvParams))[jss::result];
488  BEAST_EXPECT(jrr.isMember("error"));
489  BEAST_EXPECT(jrr["error"] == "invalidParams");
490  BEAST_EXPECT(jrr["error_message"] == "Invalid field 'type'.");
491  }
492  }
493 
494  void
495  run() override
496  {
500  testBadInput();
503  testLedgerType();
504  }
505 };
506 
507 BEAST_DEFINE_TESTSUITE_PRIO(LedgerData, app, ripple, 1);
508 
509 } // namespace ripple
ripple::getMajorityAmendments
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition: View.cpp:550
std::string
STL class.
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
ripple::LedgerData_test::testLedgerHeader
void testLedgerHeader()
Definition: LedgerData_test.cpp:250
std::string::size
T size(T... args)
ripple::SField::fieldName
const std::string fieldName
Definition: SField.h:129
std::chrono::duration
ripple::strUnHex
boost::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Definition: StringUtilities.h:72
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::sfFinishAfter
const SF_U32 sfFinishAfter(access, STI_UINT32, 37, "FinishAfter")
Definition: SField.h:390
ripple::Serializer::getInteger
bool getInteger(Integer &number, int offset)
Definition: Serializer.h:125
ripple::LedgerData_test
Definition: LedgerData_test.cpp:27
std::chrono::time_point::time_since_epoch
T time_since_epoch(T... args)
ripple::LedgerData_test::checkMarker
static bool checkMarker(Json::Value const &val)
Definition: LedgerData_test.cpp:39
ripple::JsonOptions::none
@ none
ripple::LedgerData_test::checkArraySize
static bool checkArraySize(Json::Value const &val, unsigned int size)
Definition: LedgerData_test.cpp:32
ripple::BEAST_DEFINE_TESTSUITE_PRIO
BEAST_DEFINE_TESTSUITE_PRIO(TrustAndBalance, app, ripple, 1)
std::to_string
T to_string(T... args)
std::chrono::time_point
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
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::LedgerData_test::testCurrentLedgerBinary
void testCurrentLedgerBinary()
Definition: LedgerData_test.cpp:96
std::uint32_t
ripple::featureTickets
const uint256 featureTickets
Definition: Feature.cpp:163
ripple::tfUniversal
const std::uint32_t tfUniversal
Definition: TxFlags.h:49
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
ripple::Serializer
Definition: Serializer.h:39
ripple::sfPublicKey
const SF_Blob sfPublicKey(access, STI_VL, 1, "PublicKey")
Definition: SField.h:457
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
Json::StaticString
Lightweight wrapper to tag static string.
Definition: json_value.h:60
ripple::LedgerData_test::run
void run() override
Definition: LedgerData_test.cpp:495
ripple::LedgerData_test::testBadInput
void testBadInput()
Definition: LedgerData_test.cpp:130
ripple::FeatureBitset::set
FeatureBitset & set(uint256 const &f, bool value=true)
Definition: Feature.h:220
std::chrono::duration::count
T count(T... args)
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:67
ripple::LedgerData_test::testLedgerType
void testLedgerType()
Definition: LedgerData_test.cpp:307
ripple::LedgerData_test::testMarkerFollow
void testMarkerFollow()
Definition: LedgerData_test.cpp:201
ripple::LedgerData_test::testCurrentLedgerToLimits
void testCurrentLedgerToLimits(bool asAdmin)
Definition: LedgerData_test.cpp:46
ripple::sfCancelAfter
const SF_U32 sfCancelAfter(access, STI_UINT32, 36, "CancelAfter")
Definition: SField.h:389
Json::Value
Represents a JSON value.
Definition: json_value.h:145
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
std::chrono