rippled
Loading...
Searching...
No Matches
LedgerRPC_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-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#include <test/jtx/Oracle.h>
22#include <test/jtx/attester.h>
23#include <test/jtx/delegate.h>
24#include <test/jtx/multisign.h>
25#include <test/jtx/xchain_bridge.h>
26
27#include <xrpld/app/misc/TxQ.h>
28
29#include <xrpl/beast/unit_test.h>
30#include <xrpl/json/json_value.h>
31#include <xrpl/protocol/ErrorCodes.h>
32#include <xrpl/protocol/jss.h>
33
34namespace ripple {
35
36namespace test {
37
39{
40 void
42 Json::Value const& jv,
43 std::string const& err,
44 std::string const& msg)
45 {
46 if (BEAST_EXPECT(jv.isMember(jss::status)))
47 BEAST_EXPECT(jv[jss::status] == "error");
48 if (BEAST_EXPECT(jv.isMember(jss::error)))
49 BEAST_EXPECT(jv[jss::error] == err);
50 if (msg.empty())
51 {
52 BEAST_EXPECT(
53 jv[jss::error_message] == Json::nullValue ||
54 jv[jss::error_message] == "");
55 }
56 else if (BEAST_EXPECT(jv.isMember(jss::error_message)))
57 BEAST_EXPECT(jv[jss::error_message] == msg);
58 }
59
60 // Corrupt a valid address by replacing the 10th character with '!'.
61 // '!' is not part of the ripple alphabet.
64 {
65 std::string ret = std::move(good);
66 ret.replace(10, 1, 1, '!');
67 return ret;
68 }
69
70 void
72 {
73 testcase("Basic Request");
74 using namespace test::jtx;
75
76 Env env{*this};
77
78 env.close();
79 BEAST_EXPECT(env.current()->info().seq == 4);
80
81 {
82 Json::Value jvParams;
83 // can be either numeric or quoted numeric
84 jvParams[jss::ledger_index] = 1;
85 auto const jrr =
86 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
87 BEAST_EXPECT(jrr[jss::ledger][jss::closed] == true);
88 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "1");
89 }
90
91 {
92 Json::Value jvParams;
93 jvParams[jss::ledger_index] = "1";
94 auto const jrr =
95 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
96 BEAST_EXPECT(jrr[jss::ledger][jss::closed] == true);
97 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "1");
98 }
99
100 {
101 // using current identifier
102 auto const jrr = env.rpc("ledger", "current")[jss::result];
103 BEAST_EXPECT(jrr[jss::ledger][jss::closed] == false);
104 BEAST_EXPECT(
105 jrr[jss::ledger][jss::ledger_index] ==
106 std::to_string(env.current()->info().seq));
107 BEAST_EXPECT(
108 jrr[jss::ledger_current_index] == env.current()->info().seq);
109 }
110 }
111
112 void
114 {
115 testcase("Bad Input");
116 using namespace test::jtx;
117 Env env{*this};
118 Account const gw{"gateway"};
119 auto const USD = gw["USD"];
120 Account const bob{"bob"};
121
122 env.fund(XRP(10000), gw, bob);
123 env.close();
124 env.trust(USD(1000), bob);
125 env.close();
126
127 {
128 // ask for an arbitrary string - index
129 Json::Value jvParams;
130 jvParams[jss::ledger_index] = "potato";
131 auto const jrr =
132 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
133 checkErrorValue(jrr, "invalidParams", "ledgerIndexMalformed");
134 }
135
136 {
137 // ask for a negative index
138 Json::Value jvParams;
139 jvParams[jss::ledger_index] = -1;
140 auto const jrr =
141 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
142 checkErrorValue(jrr, "invalidParams", "ledgerIndexMalformed");
143 }
144
145 {
146 // ask for a bad ledger index
147 Json::Value jvParams;
148 jvParams[jss::ledger_index] = 10u;
149 auto const jrr =
150 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
151 checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound");
152 }
153
154 {
155 // unrecognized string arg -- error
156 auto const jrr = env.rpc("ledger", "arbitrary_text")[jss::result];
157 checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound");
158 }
159
160 {
161 // Request queue for closed ledger
162 Json::Value jvParams;
163 jvParams[jss::ledger_index] = "validated";
164 jvParams[jss::queue] = true;
165 auto const jrr =
166 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
167 checkErrorValue(jrr, "invalidParams", "Invalid parameters.");
168 }
169
170 {
171 // Request a ledger with a very large (double) sequence.
172 auto const ret =
173 env.rpc("json", "ledger", "{ \"ledger_index\" : 2e15 }");
174 BEAST_EXPECT(RPC::contains_error(ret));
175 BEAST_EXPECT(ret[jss::error_message] == "Invalid parameters.");
176 }
177
178 {
179 // Request a ledger with very large (integer) sequence.
180 auto const ret = env.rpc(
181 "json", "ledger", "{ \"ledger_index\" : 1000000000000000 }");
182 checkErrorValue(ret, "invalidParams", "Invalid parameters.");
183 }
184 }
185
186 void
188 {
189 testcase("ledger_current Request");
190 using namespace test::jtx;
191
192 Env env{*this};
193
194 env.close();
195 BEAST_EXPECT(env.current()->info().seq == 4);
196
197 {
198 auto const jrr = env.rpc("ledger_current")[jss::result];
199 BEAST_EXPECT(
200 jrr[jss::ledger_current_index] == env.current()->info().seq);
201 }
202 }
203
204 void
206 {
207 testcase("Ledger Request, Full Option");
208 using namespace test::jtx;
209
210 Env env{*this};
211
212 env.close();
213
214 Json::Value jvParams;
215 jvParams[jss::ledger_index] = 3u;
216 jvParams[jss::full] = true;
217 auto const jrr =
218 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
219 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
220 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
221 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 3u);
222 }
223
224 void
226 {
227 testcase("Ledger Request, Full Option Without Admin");
228 using namespace test::jtx;
229
230 Env env{*this, envconfig(no_admin)};
231
232 // env.close();
233
234 Json::Value jvParams;
235 jvParams[jss::ledger_index] = 1u;
236 jvParams[jss::full] = true;
237 auto const jrr =
238 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
240 jrr, "noPermission", "You don't have permission for this command.");
241 }
242
243 void
245 {
246 testcase("Ledger Request, Accounts Option");
247 using namespace test::jtx;
248
249 Env env{*this};
250
251 env.close();
252
253 Json::Value jvParams;
254 jvParams[jss::ledger_index] = 3u;
255 jvParams[jss::accounts] = true;
256 auto const jrr =
257 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
258 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
259 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
260 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 3u);
261 }
262
267 void
269 {
270 testcase("Lookup ledger");
271 using namespace test::jtx;
272
273 auto cfg = envconfig();
274 cfg->FEES.reference_fee = 10;
275 Env env{
276 *this, std::move(cfg), FeatureBitset{}}; // hashes requested below
277 // assume no amendments
278 env.fund(XRP(10000), "alice");
279 env.close();
280 env.fund(XRP(10000), "bob");
281 env.close();
282 env.fund(XRP(10000), "jim");
283 env.close();
284 env.fund(XRP(10000), "jill");
285
286 {
287 // access via the legacy ledger field, keyword index values
288 Json::Value jvParams;
289 jvParams[jss::ledger] = "closed";
290 auto jrr = env.rpc(
291 "json",
292 "ledger",
293 boost::lexical_cast<std::string>(jvParams))[jss::result];
294 BEAST_EXPECT(jrr.isMember(jss::ledger));
295 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
296 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
297
298 jvParams[jss::ledger] = "validated";
299 jrr = env.rpc(
300 "json",
301 "ledger",
302 boost::lexical_cast<std::string>(jvParams))[jss::result];
303 BEAST_EXPECT(jrr.isMember(jss::ledger));
304 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
305 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
306
307 jvParams[jss::ledger] = "current";
308 jrr = env.rpc(
309 "json",
310 "ledger",
311 boost::lexical_cast<std::string>(jvParams))[jss::result];
312 BEAST_EXPECT(jrr.isMember(jss::ledger));
313 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
314
315 // ask for a bad ledger keyword
316 jvParams[jss::ledger] = "invalid";
317 jrr = env.rpc(
318 "json",
319 "ledger",
320 boost::lexical_cast<std::string>(jvParams))[jss::result];
321 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
322 BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
323
324 // numeric index
325 jvParams[jss::ledger] = 4;
326 jrr = env.rpc(
327 "json",
328 "ledger",
329 boost::lexical_cast<std::string>(jvParams))[jss::result];
330 BEAST_EXPECT(jrr.isMember(jss::ledger));
331 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
332 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "4");
333
334 // numeric index - out of range
335 jvParams[jss::ledger] = 20;
336 jrr = env.rpc(
337 "json",
338 "ledger",
339 boost::lexical_cast<std::string>(jvParams))[jss::result];
340 BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
341 BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
342 }
343
344 {
345 std::string const hash3{
346 "E86DE7F3D7A4D9CE17EF7C8BA08A8F4D"
347 "8F643B9552F0D895A31CDA78F541DE4E"};
348 // access via the ledger_hash field
349 Json::Value jvParams;
350 jvParams[jss::ledger_hash] = hash3;
351 auto jrr = env.rpc(
352 "json",
353 "ledger",
354 boost::lexical_cast<std::string>(jvParams))[jss::result];
355 BEAST_EXPECT(jrr.isMember(jss::ledger));
356 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
357 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "3");
358
359 // extra leading hex chars in hash are not allowed
360 jvParams[jss::ledger_hash] = "DEADBEEF" + hash3;
361 jrr = env.rpc(
362 "json",
363 "ledger",
364 boost::lexical_cast<std::string>(jvParams))[jss::result];
365 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
366 BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
367
368 // request with non-string ledger_hash
369 jvParams[jss::ledger_hash] = 2;
370 jrr = env.rpc(
371 "json",
372 "ledger",
373 boost::lexical_cast<std::string>(jvParams))[jss::result];
374 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
375 BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashNotString");
376
377 // malformed (non hex) hash
378 jvParams[jss::ledger_hash] =
379 "2E81FC6EC0DD943197EGC7E3FBE9AE30"
380 "7F2775F2F7485BB37307984C3C0F2340";
381 jrr = env.rpc(
382 "json",
383 "ledger",
384 boost::lexical_cast<std::string>(jvParams))[jss::result];
385 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
386 BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
387
388 // properly formed, but just doesn't exist
389 jvParams[jss::ledger_hash] =
390 "8C3EEDB3124D92E49E75D81A8826A2E6"
391 "5A75FD71FC3FD6F36FEB803C5F1D812D";
392 jrr = env.rpc(
393 "json",
394 "ledger",
395 boost::lexical_cast<std::string>(jvParams))[jss::result];
396 BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
397 BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
398 }
399
400 {
401 // access via the ledger_index field, keyword index values
402 Json::Value jvParams;
403 jvParams[jss::ledger_index] = "closed";
404 auto jrr = env.rpc(
405 "json",
406 "ledger",
407 boost::lexical_cast<std::string>(jvParams))[jss::result];
408 BEAST_EXPECT(jrr.isMember(jss::ledger));
409 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
410 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
411 BEAST_EXPECT(jrr.isMember(jss::ledger_index));
412
413 jvParams[jss::ledger_index] = "validated";
414 jrr = env.rpc(
415 "json",
416 "ledger",
417 boost::lexical_cast<std::string>(jvParams))[jss::result];
418 BEAST_EXPECT(jrr.isMember(jss::ledger));
419 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
420 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
421
422 jvParams[jss::ledger_index] = "current";
423 jrr = env.rpc(
424 "json",
425 "ledger",
426 boost::lexical_cast<std::string>(jvParams))[jss::result];
427 BEAST_EXPECT(jrr.isMember(jss::ledger));
428 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
429 BEAST_EXPECT(jrr.isMember(jss::ledger_current_index));
430
431 // ask for a bad ledger keyword
432 jvParams[jss::ledger_index] = "invalid";
433 jrr = env.rpc(
434 "json",
435 "ledger",
436 boost::lexical_cast<std::string>(jvParams))[jss::result];
437 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
438 BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
439
440 // numeric index
441 for (auto i : {1, 2, 3, 4, 5, 6})
442 {
443 jvParams[jss::ledger_index] = i;
444 jrr = env.rpc(
445 "json",
446 "ledger",
447 boost::lexical_cast<std::string>(jvParams))[jss::result];
448 BEAST_EXPECT(jrr.isMember(jss::ledger));
449 if (i < 6)
450 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
451 BEAST_EXPECT(
452 jrr[jss::ledger][jss::ledger_index] == std::to_string(i));
453 }
454
455 // numeric index - out of range
456 jvParams[jss::ledger_index] = 7;
457 jrr = env.rpc(
458 "json",
459 "ledger",
460 boost::lexical_cast<std::string>(jvParams))[jss::result];
461 BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
462 BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
463 }
464 }
465
466 void
468 {
469 testcase("Ledger with queueing disabled");
470 using namespace test::jtx;
471 Env env{*this};
472
473 Json::Value jv;
474 jv[jss::ledger_index] = "current";
475 jv[jss::queue] = true;
476 jv[jss::expand] = true;
477
478 auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
479 BEAST_EXPECT(!jrr.isMember(jss::queue_data));
480 }
481
482 void
484 {
485 testcase("Ledger with Queued Transactions");
486 using namespace test::jtx;
487 auto cfg = envconfig([](std::unique_ptr<Config> cfg) {
488 auto& section = cfg->section("transaction_queue");
489 section.set("minimum_txn_in_ledger_standalone", "3");
490 section.set("normal_consensus_increase_percent", "0");
491 return cfg;
492 });
493
494 cfg->FEES.reference_fee = 10;
495 Env env(*this, std::move(cfg));
496
497 Json::Value jv;
498 jv[jss::ledger_index] = "current";
499 jv[jss::queue] = true;
500 jv[jss::expand] = true;
501
502 Account const alice{"alice"};
503 Account const bob{"bob"};
504 Account const charlie{"charlie"};
505 Account const daria{"daria"};
506 env.fund(XRP(10000), alice);
507 env.fund(XRP(10000), bob);
508 env.close();
509 env.fund(XRP(10000), charlie);
510 env.fund(XRP(10000), daria);
511 env.close();
512
513 auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
514 BEAST_EXPECT(!jrr.isMember(jss::queue_data));
515
516 // Fill the open ledger
517 for (;;)
518 {
519 auto metrics = env.app().getTxQ().getMetrics(*env.current());
520 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
521 break;
522 env(noop(alice));
523 }
524
525 BEAST_EXPECT(env.current()->info().seq == 5);
526 // Put some txs in the queue
527 // Alice
528 auto aliceSeq = env.seq(alice);
529 env(pay(alice, "george", XRP(1000)),
530 json(R"({"LastLedgerSequence":7})"),
531 ter(terQUEUED));
532 env(offer(alice, XRP(50000), alice["USD"](5000)),
533 seq(aliceSeq + 1),
534 ter(terQUEUED));
535 env(noop(alice), seq(aliceSeq + 2), ter(terQUEUED));
536 // Bob
537 auto batch = [&env](Account a) {
538 auto aSeq = env.seq(a);
539 // Enough fee to get in front of alice in the queue
540 for (int i = 0; i < 10; ++i)
541 {
542 env(noop(a), fee(1000 + i), seq(aSeq + i), ter(terQUEUED));
543 }
544 };
545 batch(bob);
546 // Charlie
547 batch(charlie);
548 // Daria
549 batch(daria);
550
551 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
552 BEAST_EXPECT(jrr[jss::queue_data].size() == 33);
553
554 // Close enough ledgers so that alice's first tx expires.
555 env.close();
556 env.close();
557 env.close();
558 BEAST_EXPECT(env.current()->info().seq == 8);
559
560 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
561 BEAST_EXPECT(jrr[jss::queue_data].size() == 11);
562
563 env.close();
564
565 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
566 std::string const txid0 = [&]() {
567 auto const& parentHash = env.current()->info().parentHash;
568 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
569 {
570 std::string const txid1 = [&]() {
571 auto const& txj = jrr[jss::queue_data][1u];
572 BEAST_EXPECT(txj[jss::account] == alice.human());
573 BEAST_EXPECT(txj[jss::fee_level] == "256");
574 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
575 BEAST_EXPECT(txj["retries_remaining"] == 10);
576 BEAST_EXPECT(txj.isMember(jss::tx));
577 auto const& tx = txj[jss::tx];
578 BEAST_EXPECT(tx[jss::Account] == alice.human());
579 BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
580 return tx[jss::hash].asString();
581 }();
582
583 auto const& txj = jrr[jss::queue_data][0u];
584 BEAST_EXPECT(txj[jss::account] == alice.human());
585 BEAST_EXPECT(txj[jss::fee_level] == "256");
586 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
587 BEAST_EXPECT(txj["retries_remaining"] == 10);
588 BEAST_EXPECT(txj.isMember(jss::tx));
589 auto const& tx = txj[jss::tx];
590 BEAST_EXPECT(tx[jss::Account] == alice.human());
591 BEAST_EXPECT(tx[jss::TransactionType] == jss::OfferCreate);
592 auto const txid0 = tx[jss::hash].asString();
593 uint256 tx0, tx1;
594 BEAST_EXPECT(tx0.parseHex(txid0));
595 BEAST_EXPECT(tx1.parseHex(txid1));
596 BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
597 return txid0;
598 }
599 return std::string{};
600 }();
601
602 env.close();
603
604 jv[jss::expand] = false;
605
606 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
607 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
608 {
609 auto const& parentHash = env.current()->info().parentHash;
610 auto const txid1 = [&]() {
611 auto const& txj = jrr[jss::queue_data][1u];
612 BEAST_EXPECT(txj[jss::account] == alice.human());
613 BEAST_EXPECT(txj[jss::fee_level] == "256");
614 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
615 BEAST_EXPECT(txj.isMember(jss::tx));
616 return txj[jss::tx].asString();
617 }();
618 auto const& txj = jrr[jss::queue_data][0u];
619 BEAST_EXPECT(txj[jss::account] == alice.human());
620 BEAST_EXPECT(txj[jss::fee_level] == "256");
621 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
622 BEAST_EXPECT(txj["retries_remaining"] == 9);
623 BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
624 BEAST_EXPECT(txj.isMember(jss::tx));
625 BEAST_EXPECT(txj[jss::tx] == txid0);
626 uint256 tx0, tx1;
627 BEAST_EXPECT(tx0.parseHex(txid0));
628 BEAST_EXPECT(tx1.parseHex(txid1));
629 BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
630 }
631
632 env.close();
633
634 jv[jss::expand] = true;
635 jv[jss::binary] = true;
636
637 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
638 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
639 {
640 auto const& txj = jrr[jss::queue_data][1u];
641 BEAST_EXPECT(txj[jss::account] == alice.human());
642 BEAST_EXPECT(txj[jss::fee_level] == "256");
643 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
644 BEAST_EXPECT(txj["retries_remaining"] == 8);
645 BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
646 BEAST_EXPECT(txj.isMember(jss::tx));
647 BEAST_EXPECT(txj[jss::tx].isMember(jss::tx_blob));
648
649 auto const& txj2 = jrr[jss::queue_data][0u];
650 BEAST_EXPECT(txj2[jss::account] == alice.human());
651 BEAST_EXPECT(txj2[jss::fee_level] == "256");
652 BEAST_EXPECT(txj2["preflight_result"] == "tesSUCCESS");
653 BEAST_EXPECT(txj2["retries_remaining"] == 10);
654 BEAST_EXPECT(!txj2.isMember("last_result"));
655 BEAST_EXPECT(txj2.isMember(jss::tx));
656 BEAST_EXPECT(txj2[jss::tx].isMember(jss::tx_blob));
657 }
658
659 for (int i = 0; i != 9; ++i)
660 {
661 env.close();
662 }
663
664 jv[jss::expand] = false;
665 jv[jss::binary] = false;
666
667 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
668 std::string const txid2 = [&]() {
669 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
670 {
671 auto const& txj = jrr[jss::queue_data][0u];
672 BEAST_EXPECT(txj[jss::account] == alice.human());
673 BEAST_EXPECT(txj[jss::fee_level] == "256");
674 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
675 BEAST_EXPECT(txj["retries_remaining"] == 1);
676 BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
677 BEAST_EXPECT(txj.isMember(jss::tx));
678 BEAST_EXPECT(txj[jss::tx] != txid0);
679 return txj[jss::tx].asString();
680 }
681 return std::string{};
682 }();
683
684 jv[jss::full] = true;
685
686 jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
687 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
688 {
689 auto const& txj = jrr[jss::queue_data][0u];
690 BEAST_EXPECT(txj[jss::account] == alice.human());
691 BEAST_EXPECT(txj[jss::fee_level] == "256");
692 BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
693 BEAST_EXPECT(txj["retries_remaining"] == 1);
694 BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
695 BEAST_EXPECT(txj.isMember(jss::tx));
696 auto const& tx = txj[jss::tx];
697 BEAST_EXPECT(tx[jss::Account] == alice.human());
698 BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
699 BEAST_EXPECT(tx[jss::hash] == txid2);
700 }
701 }
702
703 void
705 {
706 testcase("Ledger Request, Accounts Hashes");
707 using namespace test::jtx;
708
709 Env env{*this};
710
711 env.close();
712
713 std::string index;
714 int hashesLedgerEntryIndex = -1;
715 {
716 Json::Value jvParams;
717 jvParams[jss::ledger_index] = 3u;
718 jvParams[jss::accounts] = true;
719 jvParams[jss::expand] = true;
720 jvParams[jss::type] = "hashes";
721 auto const jrr =
722 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
723 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
724 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
725
726 for (auto i = 0; i < jrr[jss::ledger][jss::accountState].size();
727 i++)
728 if (jrr[jss::ledger][jss::accountState][i]["LedgerEntryType"] ==
729 jss::LedgerHashes)
730 {
731 index = jrr[jss::ledger][jss::accountState][i]["index"]
732 .asString();
733 hashesLedgerEntryIndex = i;
734 }
735
736 for (auto const& object : jrr[jss::ledger][jss::accountState])
737 if (object["LedgerEntryType"] == jss::LedgerHashes)
738 index = object["index"].asString();
739
740 // jss::type is a deprecated field
741 BEAST_EXPECT(
742 jrr.isMember(jss::warnings) && jrr[jss::warnings].isArray() &&
743 jrr[jss::warnings].size() == 1 &&
744 jrr[jss::warnings][0u][jss::id].asInt() ==
746 }
747 {
748 Json::Value jvParams;
749 jvParams[jss::ledger_index] = 3u;
750 jvParams[jss::accounts] = true;
751 jvParams[jss::expand] = false;
752 jvParams[jss::type] = "hashes";
753 auto const jrr =
754 env.rpc("json", "ledger", to_string(jvParams))[jss::result];
755 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
756 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
757 BEAST_EXPECT(
758 hashesLedgerEntryIndex > 0 &&
759 jrr[jss::ledger][jss::accountState][hashesLedgerEntryIndex] ==
760 index);
761
762 // jss::type is a deprecated field
763 BEAST_EXPECT(
764 jrr.isMember(jss::warnings) && jrr[jss::warnings].isArray() &&
765 jrr[jss::warnings].size() == 1 &&
766 jrr[jss::warnings][0u][jss::id].asInt() ==
768 }
769 }
770
771public:
772 void
786};
787
788BEAST_DEFINE_TESTSUITE(LedgerRPC, rpc, ripple);
789
790} // namespace test
791} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
bool isMember(char const *key) const
Return true if the object has a member named key.
A testsuite class.
Definition suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:155
virtual TxQ & getTxQ()=0
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
Definition TxQ.cpp:1778
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:503
void checkErrorValue(Json::Value const &jv, std::string const &err, std::string const &msg)
void run() override
Runs the suite.
void testLookupLedger()
ledger RPC requests as a way to drive input options to lookupLedger.
std::string makeBadAddress(std::string good)
Immutable cryptographic account descriptor.
Definition Account.h:39
A transaction testing environment.
Definition Env.h:121
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition Env.cpp:268
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:331
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:121
Application & app()
Definition Env.h:261
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition Env.h:791
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:289
Set the fee on a JTx.
Definition fee.h:37
Inject raw JSON.
Definition jtx_json.h:33
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition rpc.h:35
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition ter.h:35
T empty(T... args)
@ nullValue
'null' value
Definition json_value.h:38
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
std::unique_ptr< Config > no_admin(std::unique_ptr< Config >)
adjust config so no admin ports are enabled
Definition envconfig.cpp:76
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:30
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:54
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Definition offer.cpp:29
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:111
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
@ warnRPC_FIELDS_DEPRECATED
Definition ErrorCodes.h:177
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
@ terQUEUED
Definition TER.h:225
T replace(T... args)
Set the sequence number on a JTx.
Definition seq.h:34
T to_string(T... args)