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