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