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