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