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",
67 "ledger_data",
68 boost::lexical_cast<std::string>(jvParams))[jss::result];
69 BEAST_EXPECT(
70 jrr[jss::ledger_current_index].isIntegral() &&
71 jrr[jss::ledger_current_index].asInt() > 0);
72 BEAST_EXPECT(checkMarker(jrr));
73 BEAST_EXPECT(checkArraySize(jrr[jss::state], max_limit));
74 }
75
76 // check limits values around the max_limit (+/- 1)
77 for (auto delta = -1; delta <= 1; delta++)
78 {
79 jvParams[jss::limit] = max_limit + delta;
80 auto const jrr = env.rpc(
81 "json",
82 "ledger_data",
83 boost::lexical_cast<std::string>(jvParams))[jss::result];
84 BEAST_EXPECT(checkArraySize(
85 jrr[jss::state],
86 (delta > 0 && !asAdmin) ? max_limit : max_limit + delta));
87 }
88 }
89
90 void
92 {
93 using namespace test::jtx;
94 Env env{*this, envconfig(no_admin)};
95 Account const gw{"gateway"};
96 auto const USD = gw["USD"];
97 env.fund(XRP(100000), gw);
98
99 int const num_accounts = 10;
100
101 for (auto i = 0; i < num_accounts; i++)
102 {
103 Account const bob{std::string("bob") + std::to_string(i)};
104 env.fund(XRP(1000), bob);
105 }
106
107 // with no limit specified, we should get all of our fund entries
108 // plus three more related to the gateway setup
109 Json::Value jvParams;
110 jvParams[jss::ledger_index] = "current";
111 jvParams[jss::binary] = true;
112 auto const jrr = env.rpc(
113 "json",
114 "ledger_data",
115 boost::lexical_cast<std::string>(jvParams))[jss::result];
116 BEAST_EXPECT(
117 jrr[jss::ledger_current_index].isIntegral() &&
118 jrr[jss::ledger_current_index].asInt() > 0);
119 BEAST_EXPECT(!jrr.isMember(jss::marker));
120 BEAST_EXPECT(checkArraySize(jrr[jss::state], num_accounts + 4));
121 }
122
123 void
125 {
126 using namespace test::jtx;
127 Env env{*this};
128 Account const gw{"gateway"};
129 auto const USD = gw["USD"];
130 Account const bob{"bob"};
131
132 env.fund(XRP(10000), gw, bob);
133 env.trust(USD(1000), bob);
134
135 {
136 // bad limit
137 Json::Value jvParams;
138 jvParams[jss::limit] = "0"; // NOT an integer
139 auto const jrr = env.rpc(
140 "json",
141 "ledger_data",
142 boost::lexical_cast<std::string>(jvParams))[jss::result];
143 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
144 BEAST_EXPECT(jrr[jss::status] == "error");
145 BEAST_EXPECT(
146 jrr[jss::error_message] ==
147 "Invalid field 'limit', not integer.");
148 }
149
150 {
151 // invalid marker
152 Json::Value jvParams;
153 jvParams[jss::marker] = "NOT_A_MARKER";
154 auto const jrr = env.rpc(
155 "json",
156 "ledger_data",
157 boost::lexical_cast<std::string>(jvParams))[jss::result];
158 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
159 BEAST_EXPECT(jrr[jss::status] == "error");
160 BEAST_EXPECT(
161 jrr[jss::error_message] ==
162 "Invalid field 'marker', not valid.");
163 }
164
165 {
166 // invalid marker - not a string
167 Json::Value jvParams;
168 jvParams[jss::marker] = 1;
169 auto const jrr = env.rpc(
170 "json",
171 "ledger_data",
172 boost::lexical_cast<std::string>(jvParams))[jss::result];
173 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
174 BEAST_EXPECT(jrr[jss::status] == "error");
175 BEAST_EXPECT(
176 jrr[jss::error_message] ==
177 "Invalid field 'marker', not valid.");
178 }
179
180 {
181 // ask for a bad ledger index
182 Json::Value jvParams;
183 jvParams[jss::ledger_index] = 10u;
184 auto const jrr = env.rpc(
185 "json",
186 "ledger_data",
187 boost::lexical_cast<std::string>(jvParams))[jss::result];
188 BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
189 BEAST_EXPECT(jrr[jss::status] == "error");
190 BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
191 }
192 }
193
194 void
196 {
197 using namespace test::jtx;
198 Env env{*this, envconfig(no_admin)};
199 Account const gw{"gateway"};
200 auto const USD = gw["USD"];
201 env.fund(XRP(100000), gw);
202
203 int const num_accounts = 20;
204
205 for (auto i = 0; i < num_accounts; i++)
206 {
207 Account const bob{std::string("bob") + std::to_string(i)};
208 env.fund(XRP(1000), bob);
209 }
210
211 // with no limit specified, we should get all of our fund entries
212 // plus three more related to the gateway setup
213 Json::Value jvParams;
214 jvParams[jss::ledger_index] = "current";
215 jvParams[jss::binary] = false;
216 auto jrr = env.rpc(
217 "json",
218 "ledger_data",
219 boost::lexical_cast<std::string>(jvParams))[jss::result];
220 auto const total_count = jrr[jss::state].size();
221
222 // now make request with a limit and loop until we get all
223 jvParams[jss::limit] = 5;
224 jrr = env.rpc(
225 "json",
226 "ledger_data",
227 boost::lexical_cast<std::string>(jvParams))[jss::result];
228 BEAST_EXPECT(checkMarker(jrr));
229 auto running_total = jrr[jss::state].size();
230 while (jrr.isMember(jss::marker))
231 {
232 jvParams[jss::marker] = jrr[jss::marker];
233 jrr = env.rpc(
234 "json",
235 "ledger_data",
236 boost::lexical_cast<std::string>(jvParams))[jss::result];
237 running_total += jrr[jss::state].size();
238 }
239 BEAST_EXPECT(running_total == total_count);
240 }
241
242 void
244 {
245 using namespace test::jtx;
246 Env env{*this};
247 env.fund(XRP(100000), "alice");
248 env.close();
249
250 // Ledger header should be present in the first query
251 {
252 // Closed ledger with non binary form
253 Json::Value jvParams;
254 jvParams[jss::ledger_index] = "closed";
255 auto jrr = env.rpc(
256 "json",
257 "ledger_data",
258 boost::lexical_cast<std::string>(jvParams))[jss::result];
259 if (BEAST_EXPECT(jrr.isMember(jss::ledger)))
260 BEAST_EXPECT(
261 jrr[jss::ledger][jss::ledger_hash] ==
262 to_string(env.closed()->info().hash));
263 }
264 {
265 // Closed ledger with binary form
266 Json::Value jvParams;
267 jvParams[jss::ledger_index] = "closed";
268 jvParams[jss::binary] = true;
269 auto jrr = env.rpc(
270 "json",
271 "ledger_data",
272 boost::lexical_cast<std::string>(jvParams))[jss::result];
273 if (BEAST_EXPECT(jrr.isMember(jss::ledger)))
274 {
275 auto data =
276 strUnHex(jrr[jss::ledger][jss::ledger_data].asString());
277 if (BEAST_EXPECT(data))
278 {
279 Serializer s(data->data(), data->size());
280 std::uint32_t seq = 0;
281 BEAST_EXPECT(s.getInteger<std::uint32_t>(seq, 0));
282 BEAST_EXPECT(seq == 3);
283 }
284 }
285 }
286 {
287 // Current ledger with binary form
288 Json::Value jvParams;
289 jvParams[jss::binary] = true;
290 auto jrr = env.rpc(
291 "json",
292 "ledger_data",
293 boost::lexical_cast<std::string>(jvParams))[jss::result];
294 BEAST_EXPECT(jrr.isMember(jss::ledger));
295 BEAST_EXPECT(!jrr[jss::ledger].isMember(jss::ledger_data));
296 }
297 }
298
299 void
301 {
302 // Put a bunch of different LedgerEntryTypes into a ledger
303 using namespace test::jtx;
304
305 // Make sure fixInnerObjTemplate2 doesn't break amendments.
306 for (FeatureBitset const& features :
307 {testable_amendments() - fixInnerObjTemplate2,
308 testable_amendments() | fixInnerObjTemplate2})
309 {
310 using namespace std::chrono;
311 Env env{*this, envconfig(validator, ""), features};
312
313 Account const gw{"gateway"};
314 auto const USD = gw["USD"];
315 env.fund(XRP(100000), gw);
316
317 auto makeRequest = [&env](Json::StaticString const& type) {
318 Json::Value jvParams;
319 jvParams[jss::ledger_index] = "current";
320 jvParams[jss::type] = type;
321 return env.rpc(
322 "json",
323 "ledger_data",
324 boost::lexical_cast<std::string>(jvParams))[jss::result];
325 };
326
327 // Assert that state is an empty array.
328 for (auto const& type :
329 {jss::amendments,
330 jss::check,
331 jss::directory,
332 jss::offer,
333 jss::signer_list,
334 jss::state,
335 jss::ticket,
336 jss::escrow,
337 jss::payment_channel,
338 jss::deposit_preauth})
339 {
340 auto const jrr = makeRequest(type);
341 BEAST_EXPECT(checkArraySize(jrr[jss::state], 0));
342 }
343
344 int const num_accounts = 10;
345
346 for (auto i = 0; i < num_accounts; i++)
347 {
348 Account const bob{std::string("bob") + std::to_string(i)};
349 env.fund(XRP(1000), bob);
350 }
351 env(offer(Account{"bob0"}, USD(100), XRP(100)));
352 env.trust(Account{"bob2"}["USD"](100), Account{"bob3"});
353
354 auto majorities = getMajorityAmendments(*env.closed());
355 for (int i = 0; i <= 256; ++i)
356 {
357 env.close();
358 majorities = getMajorityAmendments(*env.closed());
359 if (!majorities.empty())
360 break;
361 }
362
363 env(signers(
364 Account{"bob0"},
365 1,
366 {{Account{"bob1"}, 1}, {Account{"bob2"}, 1}}));
367 env(ticket::create(env.master, 1));
368
369 {
370 Json::Value jv;
371 jv[jss::TransactionType] = jss::EscrowCreate;
372 jv[jss::Account] = Account{"bob5"}.human();
373 jv[jss::Destination] = Account{"bob6"}.human();
374 jv[jss::Amount] = XRP(50).value().getJson(JsonOptions::none);
375 jv[sfFinishAfter.fieldName] =
376 NetClock::time_point{env.now() + 10s}
378 .count();
379 env(jv);
380 }
381
382 {
383 Json::Value jv;
384 jv[jss::TransactionType] = jss::PaymentChannelCreate;
385 jv[jss::Account] = Account{"bob6"}.human();
386 jv[jss::Destination] = Account{"bob7"}.human();
387 jv[jss::Amount] = XRP(100).value().getJson(JsonOptions::none);
388 jv[jss::SettleDelay] = NetClock::duration{10s}.count();
389 jv[sfPublicKey.fieldName] =
390 strHex(Account{"bob6"}.pk().slice());
391 jv[sfCancelAfter.fieldName] =
392 NetClock::time_point{env.now() + 300s}
394 .count();
395 env(jv);
396 }
397
398 env(check::create("bob6", "bob7", XRP(100)));
399
400 // bob9 DepositPreauths bob4 and bob8.
401 env(deposit::auth(Account{"bob9"}, Account{"bob4"}));
402 env(deposit::auth(Account{"bob9"}, Account{"bob8"}));
403 env.close();
404
405 // Now fetch each type
406
407 { // jvParams[jss::type] = "account";
408 auto const jrr = makeRequest(jss::account);
409 BEAST_EXPECT(checkArraySize(jrr[jss::state], 12));
410 for (auto const& j : jrr[jss::state])
411 BEAST_EXPECT(j["LedgerEntryType"] == jss::AccountRoot);
412 }
413
414 { // jvParams[jss::type] = "amendments";
415 auto const jrr = makeRequest(jss::amendments);
416 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
417 for (auto const& j : jrr[jss::state])
418 BEAST_EXPECT(j["LedgerEntryType"] == jss::Amendments);
419 }
420
421 { // jvParams[jss::type] = "check";
422 auto const jrr = makeRequest(jss::check);
423 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
424 for (auto const& j : jrr[jss::state])
425 BEAST_EXPECT(j["LedgerEntryType"] == jss::Check);
426 }
427
428 { // jvParams[jss::type] = "directory";
429 auto const jrr = makeRequest(jss::directory);
430 BEAST_EXPECT(checkArraySize(jrr[jss::state], 9));
431 for (auto const& j : jrr[jss::state])
432 BEAST_EXPECT(j["LedgerEntryType"] == jss::DirectoryNode);
433 }
434
435 { // jvParams[jss::type] = "fee";
436 auto const jrr = makeRequest(jss::fee);
437 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
438 for (auto const& j : jrr[jss::state])
439 BEAST_EXPECT(j["LedgerEntryType"] == jss::FeeSettings);
440 }
441
442 { // jvParams[jss::type] = "hashes";
443 auto const jrr = makeRequest(jss::hashes);
444 BEAST_EXPECT(checkArraySize(jrr[jss::state], 2));
445 for (auto const& j : jrr[jss::state])
446 BEAST_EXPECT(j["LedgerEntryType"] == jss::LedgerHashes);
447 }
448
449 { // jvParams[jss::type] = "offer";
450 auto const jrr = makeRequest(jss::offer);
451 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
452 for (auto const& j : jrr[jss::state])
453 BEAST_EXPECT(j["LedgerEntryType"] == jss::Offer);
454 }
455
456 { // jvParams[jss::type] = "signer_list";
457 auto const jrr = makeRequest(jss::signer_list);
458 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
459 for (auto const& j : jrr[jss::state])
460 BEAST_EXPECT(j["LedgerEntryType"] == jss::SignerList);
461 }
462
463 { // jvParams[jss::type] = "state";
464 auto const jrr = makeRequest(jss::state);
465 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
466 for (auto const& j : jrr[jss::state])
467 BEAST_EXPECT(j["LedgerEntryType"] == jss::RippleState);
468 }
469
470 { // jvParams[jss::type] = "ticket";
471 auto const jrr = makeRequest(jss::ticket);
472 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
473 for (auto const& j : jrr[jss::state])
474 BEAST_EXPECT(j["LedgerEntryType"] == jss::Ticket);
475 }
476
477 { // jvParams[jss::type] = "escrow";
478 auto const jrr = makeRequest(jss::escrow);
479 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
480 for (auto const& j : jrr[jss::state])
481 BEAST_EXPECT(j["LedgerEntryType"] == jss::Escrow);
482 }
483
484 { // jvParams[jss::type] = "payment_channel";
485 auto const jrr = makeRequest(jss::payment_channel);
486 BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
487 for (auto const& j : jrr[jss::state])
488 BEAST_EXPECT(j["LedgerEntryType"] == jss::PayChannel);
489 }
490
491 { // jvParams[jss::type] = "deposit_preauth";
492 auto const jrr = makeRequest(jss::deposit_preauth);
493 BEAST_EXPECT(checkArraySize(jrr[jss::state], 2));
494 for (auto const& j : jrr[jss::state])
495 BEAST_EXPECT(j["LedgerEntryType"] == jss::DepositPreauth);
496 }
497
498 { // jvParams[jss::type] = "misspelling";
499 Json::Value jvParams;
500 jvParams[jss::ledger_index] = "current";
501 jvParams[jss::type] = "misspelling";
502 auto const jrr = env.rpc(
503 "json",
504 "ledger_data",
505 boost::lexical_cast<std::string>(jvParams))[jss::result];
506 BEAST_EXPECT(jrr.isMember("error"));
507 BEAST_EXPECT(jrr["error"] == "invalidParams");
508 BEAST_EXPECT(jrr["error_message"] == "Invalid field 'type'.");
509 }
510 }
511 }
512
513 void
524};
525
526BEAST_DEFINE_TESTSUITE_PRIO(LedgerData, rpc, ripple, 1);
527
528} // 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:935
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)