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