rippled
Loading...
Searching...
No Matches
LedgerData_test.cpp
1#include <test/jtx.h>
2
3#include <xrpl/basics/StringUtilities.h>
4#include <xrpl/protocol/jss.h>
5
6namespace xrpl {
7
9{
10public:
11 // test helper
12 static bool
14 {
15 return val.isMember(jss::marker) && val[jss::marker].isString() &&
16 !val[jss::marker].asString().empty();
17 }
18
19 void
21 {
22 using namespace test::jtx;
23 Env env{*this, asAdmin ? envconfig() : envconfig(no_admin)};
24 Account const gw{"gateway"};
25 auto const USD = gw["USD"];
26 env.fund(XRP(100000), gw);
27
28 int const max_limit = 256; // would be 2048 for binary requests, no
29 // need to test that here
30
31 for (auto i = 0; i < max_limit + 10; i++)
32 {
33 Account const bob{std::string("bob") + std::to_string(i)};
34 env.fund(XRP(1000), bob);
35 }
36 // Note that calls to env.close() fail without admin permission.
37 if (asAdmin)
38 env.close();
39
40 // with no limit specified, we get the max_limit if the total number of
41 // accounts is greater than max, which it is here
42 Json::Value jvParams;
43 jvParams[jss::ledger_index] = "current";
44 jvParams[jss::binary] = false;
45 {
46 auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
47 BEAST_EXPECT(
48 jrr[jss::ledger_current_index].isIntegral() &&
49 jrr[jss::ledger_current_index].asInt() > 0);
50 BEAST_EXPECT(checkMarker(jrr));
51 BEAST_EXPECT(checkArraySize(jrr[jss::state], max_limit));
52 }
53
54 // check limits values around the max_limit (+/- 1)
55 for (auto delta = -1; delta <= 1; delta++)
56 {
57 jvParams[jss::limit] = max_limit + delta;
58 auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
59 BEAST_EXPECT(checkArraySize(
60 jrr[jss::state], (delta > 0 && !asAdmin) ? max_limit : max_limit + delta));
61 }
62 }
63
64 void
66 {
67 using namespace test::jtx;
68 Env env{*this, envconfig(no_admin)};
69 Account const gw{"gateway"};
70 auto const USD = gw["USD"];
71 env.fund(XRP(100000), gw);
72
73 int const num_accounts = 10;
74
75 for (auto i = 0; i < num_accounts; i++)
76 {
77 Account const bob{std::string("bob") + std::to_string(i)};
78 env.fund(XRP(1000), bob);
79 }
80
81 // with no limit specified, we should get all of our fund entries
82 // plus three more related to the gateway setup
83 Json::Value jvParams;
84 jvParams[jss::ledger_index] = "current";
85 jvParams[jss::binary] = true;
86 auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
87 BEAST_EXPECT(
88 jrr[jss::ledger_current_index].isIntegral() &&
89 jrr[jss::ledger_current_index].asInt() > 0);
90 BEAST_EXPECT(!jrr.isMember(jss::marker));
91 BEAST_EXPECT(checkArraySize(jrr[jss::state], num_accounts + 4));
92 }
93
94 void
96 {
97 using namespace test::jtx;
98 Env env{*this};
99 Account const gw{"gateway"};
100 auto const USD = gw["USD"];
101 Account const bob{"bob"};
102
103 env.fund(XRP(10000), gw, bob);
104 env.trust(USD(1000), bob);
105
106 {
107 // bad limit
108 Json::Value jvParams;
109 jvParams[jss::limit] = "0"; // NOT an integer
110 auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
111 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
112 BEAST_EXPECT(jrr[jss::status] == "error");
113 BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'limit', not integer.");
114 }
115
116 {
117 // invalid marker
118 Json::Value jvParams;
119 jvParams[jss::marker] = "NOT_A_MARKER";
120 auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
121 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
122 BEAST_EXPECT(jrr[jss::status] == "error");
123 BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'marker', not valid.");
124 }
125
126 {
127 // invalid marker - not a string
128 Json::Value jvParams;
129 jvParams[jss::marker] = 1;
130 auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
131 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
132 BEAST_EXPECT(jrr[jss::status] == "error");
133 BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'marker', not valid.");
134 }
135
136 {
137 // ask for a bad ledger index
138 Json::Value jvParams;
139 jvParams[jss::ledger_index] = 10u;
140 auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
141 BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
142 BEAST_EXPECT(jrr[jss::status] == "error");
143 BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
144 }
145 }
146
147 void
149 {
150 using namespace test::jtx;
151 Env env{*this, envconfig(no_admin)};
152 Account const gw{"gateway"};
153 auto const USD = gw["USD"];
154 env.fund(XRP(100000), gw);
155
156 int const num_accounts = 20;
157
158 for (auto i = 0; i < num_accounts; i++)
159 {
160 Account const bob{std::string("bob") + std::to_string(i)};
161 env.fund(XRP(1000), bob);
162 }
163
164 // with no limit specified, we should get all of our fund entries
165 // plus three more related to the gateway setup
166 Json::Value jvParams;
167 jvParams[jss::ledger_index] = "current";
168 jvParams[jss::binary] = false;
169 auto jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
170 auto const total_count = jrr[jss::state].size();
171
172 // now make request with a limit and loop until we get all
173 jvParams[jss::limit] = 5;
174 jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
175 BEAST_EXPECT(checkMarker(jrr));
176 auto running_total = jrr[jss::state].size();
177 while (jrr.isMember(jss::marker))
178 {
179 jvParams[jss::marker] = jrr[jss::marker];
180 jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
181 running_total += jrr[jss::state].size();
182 }
183 BEAST_EXPECT(running_total == total_count);
184 }
185
186 void
188 {
189 using namespace test::jtx;
190 Env env{*this};
191 env.fund(XRP(100000), "alice");
192 env.close();
193
194 // Ledger header should be present in the first query
195 {
196 // Closed ledger with non binary form
197 Json::Value jvParams;
198 jvParams[jss::ledger_index] = "closed";
199 auto jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
200 if (BEAST_EXPECT(jrr.isMember(jss::ledger)))
201 {
202 BEAST_EXPECT(
203 jrr[jss::ledger][jss::ledger_hash] == to_string(env.closed()->header().hash));
204 }
205 }
206 {
207 // Closed ledger with binary form
208 Json::Value jvParams;
209 jvParams[jss::ledger_index] = "closed";
210 jvParams[jss::binary] = true;
211 auto jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
212 if (BEAST_EXPECT(jrr.isMember(jss::ledger)))
213 {
214 auto data = strUnHex(jrr[jss::ledger][jss::ledger_data].asString());
215 if (BEAST_EXPECT(data); data.has_value())
216 {
217 Serializer s(data->data(), data->size());
218 std::uint32_t seq = 0;
219 BEAST_EXPECT(s.getInteger<std::uint32_t>(seq, 0));
220 BEAST_EXPECT(seq == 3);
221 }
222 }
223 }
224 {
225 // Current ledger with binary form
226 Json::Value jvParams;
227 jvParams[jss::binary] = true;
228 auto jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
229 BEAST_EXPECT(jrr.isMember(jss::ledger));
230 BEAST_EXPECT(!jrr[jss::ledger].isMember(jss::ledger_data));
231 }
232 }
233
234 void
236 {
237 // Put a bunch of different LedgerEntryTypes into a ledger
238 using namespace test::jtx;
239
240 // Make sure fixInnerObjTemplate2 doesn't break amendments.
241 for (FeatureBitset const& features :
242 {testable_amendments() - fixInnerObjTemplate2,
243 testable_amendments() | fixInnerObjTemplate2})
244 {
245 using namespace std::chrono;
246 Env env{*this, envconfig(validator, ""), features};
247
248 Account const gw{"gateway"};
249 auto const USD = gw["USD"];
250 env.fund(XRP(100000), gw);
251
252 auto makeRequest = [&env](Json::StaticString const& type) {
253 Json::Value jvParams;
254 jvParams[jss::ledger_index] = "current";
255 jvParams[jss::type] = type;
256 return env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
257 };
258
259 // Assert that state is an empty array.
260 for (auto const& type :
261 {jss::amendments,
262 jss::check,
263 jss::directory,
264 jss::offer,
265 jss::signer_list,
266 jss::state,
267 jss::ticket,
268 jss::escrow,
269 jss::payment_channel,
270 jss::deposit_preauth})
271 {
272 auto const jrr = makeRequest(type);
273 BEAST_EXPECT(checkArraySize(jrr[jss::state], 0));
274 }
275
276 int const num_accounts = 10;
277
278 for (auto i = 0; i < num_accounts; i++)
279 {
280 Account const bob{std::string("bob") + std::to_string(i)};
281 env.fund(XRP(1000), bob);
282 }
283 env(offer(Account{"bob0"}, USD(100), XRP(100)));
284 env.trust(Account{"bob2"}["USD"](100), Account{"bob3"});
285
286 auto majorities = getMajorityAmendments(*env.closed());
287 for (int i = 0; i <= 256; ++i)
288 {
289 env.close();
290 majorities = getMajorityAmendments(*env.closed());
291 if (!majorities.empty())
292 break;
293 }
294
295 env(signers(Account{"bob0"}, 1, {{Account{"bob1"}, 1}, {Account{"bob2"}, 1}}));
296 env(ticket::create(env.master, 1));
297
298 {
299 Json::Value jv;
300 jv[jss::TransactionType] = jss::EscrowCreate;
301 jv[jss::Account] = Account{"bob5"}.human();
302 jv[jss::Destination] = Account{"bob6"}.human();
303 jv[jss::Amount] = XRP(50).value().getJson(JsonOptions::none);
304 jv[sfFinishAfter.fieldName] =
305 NetClock::time_point{env.now() + 10s}.time_since_epoch().count();
306 env(jv);
307 }
308
309 {
310 Json::Value jv;
311 jv[jss::TransactionType] = jss::PaymentChannelCreate;
312 jv[jss::Account] = Account{"bob6"}.human();
313 jv[jss::Destination] = Account{"bob7"}.human();
314 jv[jss::Amount] = XRP(100).value().getJson(JsonOptions::none);
315 jv[jss::SettleDelay] = NetClock::duration{10s}.count();
316 jv[sfPublicKey.fieldName] = strHex(Account{"bob6"}.pk().slice());
317 jv[sfCancelAfter.fieldName] =
318 NetClock::time_point{env.now() + 300s}.time_since_epoch().count();
319 env(jv);
320 }
321
322 env(check::create("bob6", "bob7", XRP(100)));
323
324 // bob9 DepositPreauths bob4 and bob8.
325 env(deposit::auth(Account{"bob9"}, Account{"bob4"}));
326 env(deposit::auth(Account{"bob9"}, Account{"bob8"}));
327 env.close();
328
329 // Now fetch each type
330
331 { // jvParams[jss::type] = "account";
332 auto const jrr = makeRequest(jss::account);
333 BEAST_EXPECT(checkArraySize(jrr[jss::state], 12));
334 for (auto const& j : jrr[jss::state])
335 BEAST_EXPECT(j["LedgerEntryType"] == jss::AccountRoot);
336 }
337
338 { // jvParams[jss::type] = "amendments";
339 auto const jrr = makeRequest(jss::amendments);
340 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
341 for (auto const& j : jrr[jss::state])
342 BEAST_EXPECT(j["LedgerEntryType"] == jss::Amendments);
343 }
344
345 { // jvParams[jss::type] = "check";
346 auto const jrr = makeRequest(jss::check);
347 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
348 for (auto const& j : jrr[jss::state])
349 BEAST_EXPECT(j["LedgerEntryType"] == jss::Check);
350 }
351
352 { // jvParams[jss::type] = "directory";
353 auto const jrr = makeRequest(jss::directory);
354 BEAST_EXPECT(checkArraySize(jrr[jss::state], 9));
355 for (auto const& j : jrr[jss::state])
356 BEAST_EXPECT(j["LedgerEntryType"] == jss::DirectoryNode);
357 }
358
359 { // jvParams[jss::type] = "fee";
360 auto const jrr = makeRequest(jss::fee);
361 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
362 for (auto const& j : jrr[jss::state])
363 BEAST_EXPECT(j["LedgerEntryType"] == jss::FeeSettings);
364 }
365
366 { // jvParams[jss::type] = "hashes";
367 auto const jrr = makeRequest(jss::hashes);
368 BEAST_EXPECT(checkArraySize(jrr[jss::state], 2));
369 for (auto const& j : jrr[jss::state])
370 BEAST_EXPECT(j["LedgerEntryType"] == jss::LedgerHashes);
371 }
372
373 { // jvParams[jss::type] = "offer";
374 auto const jrr = makeRequest(jss::offer);
375 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
376 for (auto const& j : jrr[jss::state])
377 BEAST_EXPECT(j["LedgerEntryType"] == jss::Offer);
378 }
379
380 { // jvParams[jss::type] = "signer_list";
381 auto const jrr = makeRequest(jss::signer_list);
382 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
383 for (auto const& j : jrr[jss::state])
384 BEAST_EXPECT(j["LedgerEntryType"] == jss::SignerList);
385 }
386
387 { // jvParams[jss::type] = "state";
388 auto const jrr = makeRequest(jss::state);
389 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
390 for (auto const& j : jrr[jss::state])
391 BEAST_EXPECT(j["LedgerEntryType"] == jss::RippleState);
392 }
393
394 { // jvParams[jss::type] = "ticket";
395 auto const jrr = makeRequest(jss::ticket);
396 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
397 for (auto const& j : jrr[jss::state])
398 BEAST_EXPECT(j["LedgerEntryType"] == jss::Ticket);
399 }
400
401 { // jvParams[jss::type] = "escrow";
402 auto const jrr = makeRequest(jss::escrow);
403 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
404 for (auto const& j : jrr[jss::state])
405 BEAST_EXPECT(j["LedgerEntryType"] == jss::Escrow);
406 }
407
408 { // jvParams[jss::type] = "payment_channel";
409 auto const jrr = makeRequest(jss::payment_channel);
410 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
411 for (auto const& j : jrr[jss::state])
412 BEAST_EXPECT(j["LedgerEntryType"] == jss::PayChannel);
413 }
414
415 { // jvParams[jss::type] = "deposit_preauth";
416 auto const jrr = makeRequest(jss::deposit_preauth);
417 BEAST_EXPECT(checkArraySize(jrr[jss::state], 2));
418 for (auto const& j : jrr[jss::state])
419 BEAST_EXPECT(j["LedgerEntryType"] == jss::DepositPreauth);
420 }
421
422 { // jvParams[jss::type] = "misspelling";
423 Json::Value jvParams;
424 jvParams[jss::ledger_index] = "current";
425 jvParams[jss::type] = "misspelling";
426 auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
427 BEAST_EXPECT(jrr.isMember("error"));
428 BEAST_EXPECT(jrr["error"] == "invalidParams");
429 BEAST_EXPECT(jrr["error_message"] == "Invalid field 'type'.");
430 }
431 }
432 }
433
434 void
445};
446
447BEAST_DEFINE_TESTSUITE_PRIO(LedgerData, rpc, xrpl, 1);
448
449} // namespace xrpl
Lightweight wrapper to tag static string.
Definition json_value.h:44
Represents a JSON value.
Definition json_value.h:130
UInt size() const
Number of values in array or object.
bool isString() const
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
A testsuite class.
Definition suite.h:51
void run() override
Runs the suite.
static bool checkMarker(Json::Value const &val)
void testCurrentLedgerToLimits(bool asAdmin)
bool getInteger(Integer &number, int offset)
Definition Serializer.h:135
T empty(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:10
auto makeRequest(bool crawlPublic, bool comprEnabled, bool ledgerReplayEnabled, bool txReduceRelayEnabled, bool vpReduceRelayEnabled) -> request_type
Make outbound http request.
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition View.cpp:210
T time_since_epoch(T... args)
T to_string(T... args)