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