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