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/protocol/ErrorCodes.h>
21 #include <ripple/protocol/jss.h>
22 #include <test/jtx.h>
23 #include <ripple/beast/unit_test.h>
24 #include <ripple/app/ledger/LedgerMaster.h>
25 
26 namespace ripple {
27 
28 namespace RPC {
29 
30 class LedgerRequestRPC_test : public beast::unit_test::suite
31 {
32 public:
33 
35  {
36  using namespace test::jtx;
37 
38  Env env(*this);
39 
40  env.close();
41  env.close();
42  BEAST_EXPECT(env.current()->info().seq == 5);
43 
44  {
45  // arbitrary text is converted to 0.
46  auto const result = env.rpc("ledger_request", "arbitrary_text");
47  BEAST_EXPECT(RPC::contains_error(result[jss::result]) &&
48  result[jss::result][jss::error_message] ==
49  "Ledger index too small");
50  }
51 
52  {
53  auto const result = env.rpc("ledger_request", "-1");
54  BEAST_EXPECT(RPC::contains_error(result[jss::result]) &&
55  result[jss::result][jss::error_message] ==
56  "Ledger index too small");
57  }
58 
59  {
60  auto const result = env.rpc("ledger_request", "0");
61  BEAST_EXPECT(RPC::contains_error(result[jss::result]) &&
62  result[jss::result][jss::error_message] ==
63  "Ledger index too small");
64  }
65 
66  {
67  auto const result = env.rpc("ledger_request", "1");
68  BEAST_EXPECT(!RPC::contains_error(result[jss::result]) &&
69  result[jss::result][jss::ledger_index] == 1 &&
70  result[jss::result].isMember(jss::ledger));
71  BEAST_EXPECT(result[jss::result][jss::ledger].
72  isMember(jss::ledger_hash) &&
73  result[jss::result][jss::ledger]
74  [jss::ledger_hash].isString());
75  }
76 
77  {
78  auto const result = env.rpc("ledger_request", "2");
79  BEAST_EXPECT(!RPC::contains_error(result[jss::result]) &&
80  result[jss::result][jss::ledger_index] == 2 &&
81  result[jss::result].isMember(jss::ledger));
82  BEAST_EXPECT(result[jss::result][jss::ledger].
83  isMember(jss::ledger_hash) &&
84  result[jss::result][jss::ledger]
85  [jss::ledger_hash].isString());
86  }
87 
88  {
89  auto const result = env.rpc("ledger_request", "3");
90  BEAST_EXPECT(!RPC::contains_error(result[jss::result]) &&
91  result[jss::result][jss::ledger_index] == 3 &&
92  result[jss::result].isMember(jss::ledger));
93  BEAST_EXPECT(result[jss::result][jss::ledger].
94  isMember(jss::ledger_hash) &&
95  result[jss::result][jss::ledger]
96  [jss::ledger_hash].isString());
97 
98  auto const ledgerHash = result[jss::result]
99  [jss::ledger][jss::ledger_hash].asString();
100 
101  {
102  auto const r = env.rpc("ledger_request", ledgerHash);
103  BEAST_EXPECT(!RPC::contains_error(r[jss::result]) &&
104  r[jss::result][jss::ledger_index] == 3 &&
105  r[jss::result].isMember(jss::ledger));
106  BEAST_EXPECT(r[jss::result][jss::ledger].
107  isMember(jss::ledger_hash) &&
108  r[jss::result][jss::ledger]
109  [jss::ledger_hash] == ledgerHash);
110  }
111  }
112 
113  {
114  std::string ledgerHash(64, 'q');
115 
116  auto const result = env.rpc("ledger_request", ledgerHash);
117 
118  BEAST_EXPECT(RPC::contains_error(result[jss::result]) &&
119  result[jss::result][jss::error_message] ==
120  "Invalid field 'ledger_hash'.");
121  }
122 
123  {
124  std::string ledgerHash(64, '1');
125 
126  auto const result = env.rpc("ledger_request", ledgerHash);
127 
128  BEAST_EXPECT(!RPC::contains_error(result[jss::result]) &&
129  result[jss::result][jss::have_header] == false);
130  }
131 
132  {
133  auto const result = env.rpc("ledger_request", "4");
134  BEAST_EXPECT(RPC::contains_error(result[jss::result]) &&
135  result[jss::result][jss::error_message] ==
136  "Ledger index too large");
137  }
138 
139  {
140  auto const result = env.rpc("ledger_request", "5");
141  BEAST_EXPECT(RPC::contains_error(result[jss::result]) &&
142  result[jss::result][jss::error_message] ==
143  "Ledger index too large");
144  }
145 
146  }
147 
149  {
150  using namespace test::jtx;
151  Env env {*this, FeatureBitset{}}; //the hashes being checked below assume
152  //no amendments
153  Account const gw { "gateway" };
154  auto const USD = gw["USD"];
155  env.fund(XRP(100000), gw);
156  env.close();
157 
158  env.memoize("bob");
159  env.fund(XRP(1000), "bob");
160  env.close();
161 
162  env.memoize("alice");
163  env.fund(XRP(1000), "alice");
164  env.close();
165 
166  env.memoize("carol");
167  env.fund(XRP(1000), "carol");
168  env.close();
169 
170  auto result = env.rpc ( "ledger_request", "1" ) [jss::result];
171  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "1");
172  BEAST_EXPECT(result[jss::ledger][jss::total_coins] == "100000000000000000");
173  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
174  BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == "AB868A6CFEEC779C2FF845C0AF00A642259986AF40C01976A7F842B6918936C7");
175  BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == "0000000000000000000000000000000000000000000000000000000000000000");
176  BEAST_EXPECT(result[jss::ledger][jss::account_hash] == "A21ED30C04C88046FC61DB9DC19375EEDBD365FD8C17286F27127DF804E9CAA6");
177  BEAST_EXPECT(result[jss::ledger][jss::transaction_hash] == "0000000000000000000000000000000000000000000000000000000000000000");
178 
179  result = env.rpc ( "ledger_request", "2" ) [jss::result];
180  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "2");
181  BEAST_EXPECT(result[jss::ledger][jss::total_coins] == "100000000000000000");
182  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
183  BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == "8AEDBB96643962F1D40F01E25632ABB3C56C9F04B0231EE4B18248B90173D189");
184  BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == "AB868A6CFEEC779C2FF845C0AF00A642259986AF40C01976A7F842B6918936C7");
185  BEAST_EXPECT(result[jss::ledger][jss::account_hash] == "183D5235C7C1FB5AE67AD2F6CC3B28F5FB86E8C4F89DB50DD85641A96470534E");
186  BEAST_EXPECT(result[jss::ledger][jss::transaction_hash] == "0000000000000000000000000000000000000000000000000000000000000000");
187 
188  result = env.rpc ( "ledger_request", "3" ) [jss::result];
189  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "3");
190  BEAST_EXPECT(result[jss::ledger][jss::total_coins] == "99999999999999980");
191  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
192  BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == "D2EE1E2A7288AAD43D6FA8AD8007FD1A95646F365EF3A1AD608A03258F11CF18");
193  BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == "8AEDBB96643962F1D40F01E25632ABB3C56C9F04B0231EE4B18248B90173D189");
194  BEAST_EXPECT(result[jss::ledger][jss::account_hash] == "22565DC00D1A30F2C15871714E512976EF476281E5E87FF63D3E129C9069F4F4");
195  BEAST_EXPECT(result[jss::ledger][jss::transaction_hash] == "0213EC486C058B3942FBE3DAC6839949A5C5B02B8B4244C8998EFDF04DBD8222");
196 
197  result = env.rpc ( "ledger_request", "4" ) [jss::result];
198  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "4");
199  BEAST_EXPECT(result[jss::ledger][jss::total_coins] == "99999999999999960");
200  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
201  BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == "8F9032390CDD4C9D7A5B216AFDA3B525A3B39D7589C69D90D4C6BCA4619DD33C");
202  BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == "D2EE1E2A7288AAD43D6FA8AD8007FD1A95646F365EF3A1AD608A03258F11CF18");
203  BEAST_EXPECT(result[jss::ledger][jss::account_hash] == "C3335CA14E712CB28F2A7C09BEB9A24BF30BBFA5528F156C19F6665D7A588FEA");
204  BEAST_EXPECT(result[jss::ledger][jss::transaction_hash] == "3CBDB8F42E04333E1642166BFB93AC9A7E1C6C067092CD5D881D6F3AB3D67E76");
205 
206  result = env.rpc ( "ledger_request", "5" ) [jss::result];
207  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "5");
208  BEAST_EXPECT(result[jss::ledger][jss::total_coins] == "99999999999999940");
209  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
210  BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == "3EDEB201735867A8EEECBC79A75902C05A7E3F192E4C12E02E67BFDDE5566CCE");
211  BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == "8F9032390CDD4C9D7A5B216AFDA3B525A3B39D7589C69D90D4C6BCA4619DD33C");
212  BEAST_EXPECT(result[jss::ledger][jss::account_hash] == "7C77B1E9EB86410D84EE0CD50716AAA21192F19CF533194AD705798895248212");
213  BEAST_EXPECT(result[jss::ledger][jss::transaction_hash] == "C3D086CD6BDB9E97AD1D513B2C049EF2840BD21D0B3E22D84EBBB89B6D2EF59D");
214 
215  result = env.rpc ( "ledger_request", "6" ) [jss::result];
216  BEAST_EXPECT(result[jss::error] == "invalidParams");
217  BEAST_EXPECT(result[jss::status] == "error");
218  BEAST_EXPECT(result[jss::error_message] == "Ledger index too large");
219  }
220 
222  {
223  using namespace test::jtx;
224  Env env { *this };
225  Account const gw { "gateway" };
226  auto const USD = gw["USD"];
227  env.fund(XRP(100000), gw);
228  env.close();
229 
230  Json::Value jvParams;
231  jvParams[jss::ledger_hash] = "AB868A6CFEEC779C2FF845C0AF00A642259986AF40C01976A7F842B6918936C7";
232  jvParams[jss::ledger_index] = "1";
233  auto result = env.rpc ("json", "ledger_request", jvParams.toStyledString()) [jss::result];
234  BEAST_EXPECT(result[jss::error] == "invalidParams");
235  BEAST_EXPECT(result[jss::status] == "error");
236  BEAST_EXPECT(result[jss::error_message] == "Exactly one of ledger_hash and ledger_index can be set.");
237 
238  // the purpose in this test is to force the ledger expiration/out of
239  // date check to trigger
240  env.timeKeeper().adjustCloseTime(weeks{3});
241  result = env.rpc ( "ledger_request", "1" ) [jss::result];
242  BEAST_EXPECT(result[jss::error] == "noCurrent");
243  BEAST_EXPECT(result[jss::status] == "error");
244  BEAST_EXPECT(result[jss::error_message] == "Current ledger is unavailable.");
245 
246  }
247 
249  {
250  using namespace test::jtx;
251  using namespace std::chrono_literals;
252  Env env {*this};
253  Account const gw {"gateway"};
254  env.app().getLedgerMaster().tune(0, 1h);
255  auto const USD = gw["USD"];
256  env.fund(XRP(100000), gw);
257 
258  int const max_limit = 256;
259 
260  for (auto i = 0; i < max_limit + 10; i++)
261  {
262  Account const bob {std::string("bob") + std::to_string(i)};
263  env.fund(XRP(1000), bob);
264  env.close();
265  }
266 
267  auto result = env.rpc ( "ledger_request", "1" ) [jss::result];
268  BEAST_EXPECT(result[jss::ledger][jss::ledger_index] == "1");
269  BEAST_EXPECT(result[jss::ledger][jss::total_coins] == "100000000000000000");
270  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
271  BEAST_EXPECT(result[jss::ledger][jss::ledger_hash] == "AB868A6CFEEC779C2FF845C0AF00A642259986AF40C01976A7F842B6918936C7");
272  BEAST_EXPECT(result[jss::ledger][jss::parent_hash] == "0000000000000000000000000000000000000000000000000000000000000000");
273  BEAST_EXPECT(result[jss::ledger][jss::account_hash] == "A21ED30C04C88046FC61DB9DC19375EEDBD365FD8C17286F27127DF804E9CAA6");
274  BEAST_EXPECT(result[jss::ledger][jss::transaction_hash] == "0000000000000000000000000000000000000000000000000000000000000000");
275  }
276 
278  {
279  using namespace test::jtx;
280  Env env { *this, envconfig(no_admin) };
281  Account const gw { "gateway" };
282  auto const USD = gw["USD"];
283  env.fund(XRP(100000), gw);
284  env.close();
285 
286  auto const result = env.rpc ( "ledger_request", "1" ) [jss::result];
287  // The current HTTP/S ServerHandler returns an HTTP 403 error code here
288  // rather than a noPermission JSON error. The JSONRPCClient just eats that
289  // error and returns an null result.
290  BEAST_EXPECT(result.type() == Json::nullValue);
291 
292  }
293 
294  void run () override
295  {
297  testEvolution();
298  testBadInput();
300  testNonAdmin();
301  }
302 };
303 
304 BEAST_DEFINE_TESTSUITE(LedgerRequestRPC,app,ripple);
305 
306 } // RPC
307 } // ripple
308 
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:30
Json::Value::toStyledString
std::string toStyledString() const
Definition: json_value.cpp:1081
ripple::RPC::LedgerRequestRPC_test::testNonAdmin
void testNonAdmin()
Definition: LedgerRequestRPC_test.cpp:277
ripple::RPC::contains_error
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:196
std::to_string
T to_string(T... args)
ripple::RPC::LedgerRequestRPC_test::testEvolution
void testEvolution()
Definition: LedgerRequestRPC_test.cpp:148
ripple::RPC::LedgerRequestRPC_test::run
void run() override
Definition: LedgerRequestRPC_test.cpp:294
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:34
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:38
ripple::FeatureBitset
Definition: Feature.h:153
ripple::RPC::LedgerRequestRPC_test::testBadInput
void testBadInput()
Definition: LedgerRequestRPC_test.cpp:221
ripple::RPC::LedgerRequestRPC_test::testMoreThan256Closed
void testMoreThan256Closed()
Definition: LedgerRequestRPC_test.cpp:248
Json::Value
Represents a JSON value.
Definition: json_value.h:141