rippled
LedgerRequestRPC_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/ledger/LedgerMaster.h>
21 #include <ripple/beast/unit_test.h>
22 #include <ripple/protocol/ErrorCodes.h>
23 #include <ripple/protocol/jss.h>
24 #include <ripple/rpc/impl/RPCHelpers.h>
25 #include <test/jtx.h>
26 
27 namespace ripple {
28 
29 namespace RPC {
30 
31 class LedgerRequestRPC_test : public beast::unit_test::suite
32 {
33  static constexpr char const* hash1 =
34  "3020EB9E7BE24EF7D7A060CB051583EC117384636D1781AFB5B87F3E348DA489";
35  static constexpr char const* accounthash1 =
36  "BD8A3D72CA73DDE887AD63666EC2BAD07875CBA997A102579B5B95ECDFFEAED8";
37 
38  static constexpr char const* zerohash =
39  "0000000000000000000000000000000000000000000000000000000000000000";
40 
41 public:
42  void
44  {
45  using namespace test::jtx;
46 
47  Env env(*this);
48 
49  env.close();
50  env.close();
51  BEAST_EXPECT(env.current()->info().seq == 5);
52 
53  {
54  // arbitrary text is converted to 0.
55  auto const result = env.rpc("ledger_request", "arbitrary_text");
56  BEAST_EXPECT(
57  RPC::contains_error(result[jss::result]) &&
58  result[jss::result][jss::error_message] ==
59  "Ledger index too small");
60  }
61 
62  {
63  auto const result = env.rpc("ledger_request", "-1");
64  BEAST_EXPECT(
65  RPC::contains_error(result[jss::result]) &&
66  result[jss::result][jss::error_message] ==
67  "Ledger index too small");
68  }
69 
70  {
71  auto const result = env.rpc("ledger_request", "0");
72  BEAST_EXPECT(
73  RPC::contains_error(result[jss::result]) &&
74  result[jss::result][jss::error_message] ==
75  "Ledger index too small");
76  }
77 
78  {
79  auto const result = env.rpc("ledger_request", "1");
80  BEAST_EXPECT(
81  !RPC::contains_error(result[jss::result]) &&
82  result[jss::result][jss::ledger_index] == 1 &&
83  result[jss::result].isMember(jss::ledger));
84  BEAST_EXPECT(
85  result[jss::result][jss::ledger].isMember(jss::ledger_hash) &&
86  result[jss::result][jss::ledger][jss::ledger_hash].isString());
87  }
88 
89  {
90  auto const result = env.rpc("ledger_request", "2");
91  BEAST_EXPECT(
92  !RPC::contains_error(result[jss::result]) &&
93  result[jss::result][jss::ledger_index] == 2 &&
94  result[jss::result].isMember(jss::ledger));
95  BEAST_EXPECT(
96  result[jss::result][jss::ledger].isMember(jss::ledger_hash) &&
97  result[jss::result][jss::ledger][jss::ledger_hash].isString());
98  }
99 
100  {
101  auto const result = env.rpc("ledger_request", "3");
102  BEAST_EXPECT(
103  !RPC::contains_error(result[jss::result]) &&
104  result[jss::result][jss::ledger_index] == 3 &&
105  result[jss::result].isMember(jss::ledger));
106  BEAST_EXPECT(
107  result[jss::result][jss::ledger].isMember(jss::ledger_hash) &&
108  result[jss::result][jss::ledger][jss::ledger_hash].isString());
109 
110  auto const ledgerHash =
111  result[jss::result][jss::ledger][jss::ledger_hash].asString();
112 
113  {
114  auto const r = env.rpc("ledger_request", ledgerHash);
115  BEAST_EXPECT(
116  !RPC::contains_error(r[jss::result]) &&
117  r[jss::result][jss::ledger_index] == 3 &&
118  r[jss::result].isMember(jss::ledger));
119  BEAST_EXPECT(
120  r[jss::result][jss::ledger].isMember(jss::ledger_hash) &&
121  r[jss::result][jss::ledger][jss::ledger_hash] ==
122  ledgerHash);
123  }
124  }
125 
126  {
127  std::string ledgerHash(64, 'q');
128 
129  auto const result = env.rpc("ledger_request", ledgerHash);
130 
131  BEAST_EXPECT(
132  RPC::contains_error(result[jss::result]) &&
133  result[jss::result][jss::error_message] ==
134  "Invalid field 'ledger_hash'.");
135  }
136 
137  {
138  std::string ledgerHash(64, '1');
139 
140  auto const result = env.rpc("ledger_request", ledgerHash);
141 
142  BEAST_EXPECT(
143  !RPC::contains_error(result[jss::result]) &&
144  result[jss::result][jss::have_header] == false);
145  }
146 
147  {
148  auto const result = env.rpc("ledger_request", "4");
149  BEAST_EXPECT(
150  RPC::contains_error(result[jss::result]) &&
151  result[jss::result][jss::error_message] ==
152  "Ledger index too large");
153  }
154 
155  {
156  auto const result = env.rpc("ledger_request", "5");
157  BEAST_EXPECT(
158  RPC::contains_error(result[jss::result]) &&
159  result[jss::result][jss::error_message] ==
160  "Ledger index too large");
161  }
162  }
163 
164  void
166  {
167  using namespace test::jtx;
168  Env env{*this, FeatureBitset{}}; // the hashes being checked below
169  // assume no amendments
170  Account const gw{"gateway"};
171  auto const USD = gw["USD"];
172  env.fund(XRP(100000), gw);
173  env.close();
174 
175  env.memoize("bob");
176  env.fund(XRP(1000), "bob");
177  env.close();
178 
179  env.memoize("alice");
180  env.fund(XRP(1000), "alice");
181  env.close();
182 
183  env.memoize("carol");
184  env.fund(XRP(1000), "carol");
185  env.close();
186 
187  auto result = env.rpc("ledger_request", "1")[jss::result];
188  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "1");
189  BEAST_EXPECT(
190  result[jss::ledger][jss::total_coins] == "100000000000000000");
191  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
192  BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == hash1);
193  BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == zerohash);
194  BEAST_EXPECT(result[jss::ledger][jss::account_hash] == accounthash1);
195  BEAST_EXPECT(result[jss::ledger][jss::transaction_hash] == zerohash);
196 
197  result = env.rpc("ledger_request", "2")[jss::result];
198  constexpr char const* hash2 =
199  "CCC3B3E88CCAC17F1BE6B4A648A55999411F19E3FE55EB721960EB0DF28EDDA5";
200  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "2");
201  BEAST_EXPECT(
202  result[jss::ledger][jss::total_coins] == "100000000000000000");
203  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
204  BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == hash2);
205  BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == hash1);
206  BEAST_EXPECT(
207  result[jss::ledger][jss::account_hash] ==
208  "3C834285F7F464FBE99AFEB84D354A968EB2CAA24523FF26797A973D906A3D29");
209  BEAST_EXPECT(result[jss::ledger][jss::transaction_hash] == zerohash);
210 
211  result = env.rpc("ledger_request", "3")[jss::result];
212  constexpr char const* hash3 =
213  "8D631B20BC989AF568FBA97375290544B0703A5ADC1CF9E9053580461690C9EE";
214  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "3");
215  BEAST_EXPECT(
216  result[jss::ledger][jss::total_coins] == "99999999999999980");
217  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
218  BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == hash3);
219  BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == hash2);
220  BEAST_EXPECT(
221  result[jss::ledger][jss::account_hash] ==
222  "BC9EF2A16BFF80BCFABA6FA84688D858D33BD0FA0435CAA9DF6DA4105A39A29E");
223  BEAST_EXPECT(
224  result[jss::ledger][jss::transaction_hash] ==
225  "0213EC486C058B3942FBE3DAC6839949A5C5B02B8B4244C8998EFDF04DBD8222");
226 
227  result = env.rpc("ledger_request", "4")[jss::result];
228  constexpr char const* hash4 =
229  "1A8E7098B23597E73094DADA58C9D62F3AB93A12C6F7666D56CA85A6CFDE530F";
230  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "4");
231  BEAST_EXPECT(
232  result[jss::ledger][jss::total_coins] == "99999999999999960");
233  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
234  BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == hash4);
235  BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == hash3);
236  BEAST_EXPECT(
237  result[jss::ledger][jss::account_hash] ==
238  "C690188F123C91355ADA8BDF4AC5B5C927076D3590C215096868A5255264C6DD");
239  BEAST_EXPECT(
240  result[jss::ledger][jss::transaction_hash] ==
241  "3CBDB8F42E04333E1642166BFB93AC9A7E1C6C067092CD5D881D6F3AB3D67E76");
242 
243  result = env.rpc("ledger_request", "5")[jss::result];
244  constexpr char const* hash5 =
245  "C6A222D71AE65D7B4F240009EAD5DEB20D7EEDE5A4064F28BBDBFEEB6FBE48E5";
246  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "5");
247  BEAST_EXPECT(
248  result[jss::ledger][jss::total_coins] == "99999999999999940");
249  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
250  BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == hash5);
251  BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == hash4);
252  BEAST_EXPECT(
253  result[jss::ledger][jss::account_hash] ==
254  "EA81CD9D36740736F00CB747E0D0E32D3C10B695823D961F0FB9A1CE7133DD4D");
255  BEAST_EXPECT(
256  result[jss::ledger][jss::transaction_hash] ==
257  "C3D086CD6BDB9E97AD1D513B2C049EF2840BD21D0B3E22D84EBBB89B6D2EF59D");
258 
259  result = env.rpc("ledger_request", "6")[jss::result];
260  BEAST_EXPECT(result[jss::error] == "invalidParams");
261  BEAST_EXPECT(result[jss::status] == "error");
262  BEAST_EXPECT(result[jss::error_message] == "Ledger index too large");
263  }
264 
265  void
267  {
268  using namespace test::jtx;
269  Env env{*this};
270  Account const gw{"gateway"};
271  auto const USD = gw["USD"];
272  env.fund(XRP(100000), gw);
273  env.close();
274 
275  Json::Value jvParams;
276  jvParams[jss::ledger_hash] =
277  "AB868A6CFEEC779C2FF845C0AF00A642259986AF40C01976A7F842B6918936C7";
278  jvParams[jss::ledger_index] = "1";
279  auto result = env.rpc(
280  "json", "ledger_request", jvParams.toStyledString())[jss::result];
281  BEAST_EXPECT(result[jss::error] == "invalidParams");
282  BEAST_EXPECT(result[jss::status] == "error");
283  BEAST_EXPECT(
284  result[jss::error_message] ==
285  "Exactly one of ledger_hash and ledger_index can be set.");
286 
287  // the purpose in this test is to force the ledger expiration/out of
288  // date check to trigger
289  env.timeKeeper().adjustCloseTime(weeks{3});
290  result = env.rpc("ledger_request", "1")[jss::result];
291  BEAST_EXPECT(result[jss::status] == "error");
293  {
294  BEAST_EXPECT(result[jss::error] == "noCurrent");
295  BEAST_EXPECT(
296  result[jss::error_message] == "Current ledger is unavailable.");
297  }
298  else
299  {
300  BEAST_EXPECT(result[jss::error] == "notSynced");
301  BEAST_EXPECT(
302  result[jss::error_message] == "Not synced to the network.");
303  }
304  }
305 
306  void
308  {
309  using namespace test::jtx;
310  using namespace std::chrono_literals;
311  Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
312  cfg->NODE_SIZE = 0;
313  return cfg;
314  })};
315  Account const gw{"gateway"};
316  auto const USD = gw["USD"];
317  env.fund(XRP(100000), gw);
318 
319  int const max_limit = 256;
320 
321  for (auto i = 0; i < max_limit + 10; i++)
322  {
323  Account const bob{std::string("bob") + std::to_string(i)};
324  env.fund(XRP(1000), bob);
325  env.close();
326  }
327 
328  auto result = env.rpc("ledger_request", "1")[jss::result];
329  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "1");
330  BEAST_EXPECT(
331  result[jss::ledger][jss::total_coins] == "100000000000000000");
332  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
333  BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == hash1);
334  BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == zerohash);
335  BEAST_EXPECT(result[jss::ledger][jss::account_hash] == accounthash1);
336  BEAST_EXPECT(result[jss::ledger][jss::transaction_hash] == zerohash);
337  }
338 
339  void
341  {
342  using namespace test::jtx;
343  Env env{*this, envconfig(no_admin)};
344  Account const gw{"gateway"};
345  auto const USD = gw["USD"];
346  env.fund(XRP(100000), gw);
347 
348  auto const result = env.rpc("ledger_request", "1")[jss::result];
349  // The current HTTP/S ServerHandler returns an HTTP 403 error code here
350  // rather than a noPermission JSON error. The JSONRPCClient just eats
351  // that error and returns an null result.
352  BEAST_EXPECT(result.type() == Json::nullValue);
353  }
354 
355  void
356  run() override
357  {
359  testEvolution();
360  testBadInput();
362  testNonAdmin();
363  }
364 };
365 
366 BEAST_DEFINE_TESTSUITE(LedgerRequestRPC, app, ripple);
367 
368 } // namespace RPC
369 } // namespace ripple
ripple::RPC::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountLinesRPC, app, ripple)
std::string
STL class.
ripple::RPC::LedgerRequestRPC_test::zerohash
static constexpr char const * zerohash
Definition: LedgerRequestRPC_test.cpp:38
ripple::RPC::LedgerRequestRPC_test::hash1
static constexpr char const * hash1
Definition: LedgerRequestRPC_test.cpp:33
std::chrono::duration
ripple::RPC::LedgerRequestRPC_test
Definition: LedgerRequestRPC_test.cpp:31
Json::Value::toStyledString
std::string toStyledString() const
Definition: json_value.cpp:1039
ripple::RPC::LedgerRequestRPC_test::testNonAdmin
void testNonAdmin()
Definition: LedgerRequestRPC_test.cpp:340
ripple::RPC::contains_error
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:194
std::to_string
T to_string(T... args)
ripple::RPC::LedgerRequestRPC_test::accounthash1
static constexpr char const * accounthash1
Definition: LedgerRequestRPC_test.cpp:35
ripple::RPC::LedgerRequestRPC_test::testEvolution
void testEvolution()
Definition: LedgerRequestRPC_test.cpp:165
ripple::RPC::LedgerRequestRPC_test::run
void run() override
Definition: LedgerRequestRPC_test.cpp:356
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::RPC::LedgerRequestRPC_test::testLedgerRequest
void testLedgerRequest()
Definition: LedgerRequestRPC_test.cpp:43
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::RPC::apiMaximumSupportedVersion
constexpr unsigned int apiMaximumSupportedVersion
Definition: RPCHelpers.h:244
ripple::FeatureBitset
Definition: Feature.h:113
ripple::RPC::LedgerRequestRPC_test::testBadInput
void testBadInput()
Definition: LedgerRequestRPC_test.cpp:266
ripple::RPC::LedgerRequestRPC_test::testMoreThan256Closed
void testMoreThan256Closed()
Definition: LedgerRequestRPC_test.cpp:307
std::unique_ptr
STL class.
Json::Value
Represents a JSON value.
Definition: json_value.h:145