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, envconfig([](std::unique_ptr<Config> cfg) {
322  cfg->NODE_SIZE = 0;
323  return cfg;
324  })};
325  Account const gw{"gateway"};
326  auto const USD = gw["USD"];
327  env.fund(XRP(100000), gw);
328 
329  int const max_limit = 256;
330 
331  for (auto i = 0; i < max_limit + 10; i++)
332  {
333  Account const bob{std::string("bob") + std::to_string(i)};
334  env.fund(XRP(1000), bob);
335  env.close();
336  }
337 
338  auto result = env.rpc("ledger_request", "1")[jss::result];
339  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "1");
340  BEAST_EXPECT(
341  result[jss::ledger][jss::total_coins] == "100000000000000000");
342  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
343  BEAST_EXPECT(
344  result[jss::ledger][jss::ledger_hash] ==
345  "E9BB323980D202EC7E51BAB2AA8E35353F9C7BDAB59BF17378EADD4D0486EF9F");
346  BEAST_EXPECT(
347  result[jss::ledger][jss::parent_hash] ==
348  "0000000000000000000000000000000000000000000000000000000000000000");
349  BEAST_EXPECT(
350  result[jss::ledger][jss::account_hash] ==
351  "A21ED30C04C88046FC61DB9DC19375EEDBD365FD8C17286F27127DF804E9CAA6");
352  BEAST_EXPECT(
353  result[jss::ledger][jss::transaction_hash] ==
354  "0000000000000000000000000000000000000000000000000000000000000000");
355  }
356 
357  void
359  {
360  using namespace test::jtx;
361  Env env{*this, envconfig(no_admin)};
362  Account const gw{"gateway"};
363  auto const USD = gw["USD"];
364  env.fund(XRP(100000), gw);
365 
366  auto const result = env.rpc("ledger_request", "1")[jss::result];
367  // The current HTTP/S ServerHandler returns an HTTP 403 error code here
368  // rather than a noPermission JSON error. The JSONRPCClient just eats
369  // that error and returns an null result.
370  BEAST_EXPECT(result.type() == Json::nullValue);
371  }
372 
373  void
374  run() override
375  {
377  testEvolution();
378  testBadInput();
380  testNonAdmin();
381  }
382 };
383 
384 BEAST_DEFINE_TESTSUITE(LedgerRequestRPC, app, ripple);
385 
386 } // namespace RPC
387 } // 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:358
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::testEvolution
void testEvolution()
Definition: LedgerRequestRPC_test.cpp:157
ripple::RPC::LedgerRequestRPC_test::run
void run() override
Definition: LedgerRequestRPC_test.cpp:374
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::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:276
ripple::RPC::LedgerRequestRPC_test::testMoreThan256Closed
void testMoreThan256Closed()
Definition: LedgerRequestRPC_test.cpp:317
std::unique_ptr
STL class.
Json::Value
Represents a JSON value.
Definition: json_value.h:145