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