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