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