21#include <test/jtx/Oracle.h>
22#include <test/jtx/attester.h>
23#include <test/jtx/multisign.h>
24#include <test/jtx/xchain_bridge.h>
26#include <xrpld/app/misc/TxQ.h>
28#include <xrpl/beast/unit_test.h>
29#include <xrpl/json/json_value.h>
30#include <xrpl/protocol/ErrorCodes.h>
31#include <xrpl/protocol/jss.h>
45 if (BEAST_EXPECT(jv.
isMember(jss::status)))
46 BEAST_EXPECT(jv[jss::status] ==
"error");
47 if (BEAST_EXPECT(jv.
isMember(jss::error)))
48 BEAST_EXPECT(jv[jss::error] == err);
53 jv[jss::error_message] ==
"");
55 else if (BEAST_EXPECT(jv.
isMember(jss::error_message)))
56 BEAST_EXPECT(jv[jss::error_message] == msg);
73 using namespace test::jtx;
78 BEAST_EXPECT(env.current()->info().seq == 4);
83 jvParams[jss::ledger_index] = 1;
85 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
86 BEAST_EXPECT(jrr[jss::ledger][jss::closed] ==
true);
87 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"1");
92 jvParams[jss::ledger_index] =
"1";
94 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
95 BEAST_EXPECT(jrr[jss::ledger][jss::closed] ==
true);
96 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"1");
101 auto const jrr = env.rpc(
"ledger",
"current")[jss::result];
102 BEAST_EXPECT(jrr[jss::ledger][jss::closed] ==
false);
104 jrr[jss::ledger][jss::ledger_index] ==
107 jrr[jss::ledger_current_index] == env.current()->info().seq);
115 using namespace test::jtx;
118 auto const USD = gw[
"USD"];
121 env.fund(
XRP(10000), gw, bob);
123 env.trust(USD(1000), bob);
129 jvParams[jss::ledger_index] =
"potato";
131 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
138 jvParams[jss::ledger_index] = -1;
140 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
147 jvParams[jss::ledger_index] = 10u;
149 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
155 auto const jrr = env.rpc(
"ledger",
"arbitrary_text")[jss::result];
162 jvParams[jss::ledger_index] =
"validated";
163 jvParams[jss::queue] =
true;
165 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
172 env.rpc(
"json",
"ledger",
"{ \"ledger_index\" : 2e15 }");
174 BEAST_EXPECT(ret[jss::error_message] ==
"Invalid parameters.");
179 auto const ret = env.rpc(
180 "json",
"ledger",
"{ \"ledger_index\" : 1000000000000000 }");
189 using namespace test::jtx;
194 BEAST_EXPECT(env.current()->info().seq == 4);
197 auto const jrr = env.rpc(
"ledger_current")[jss::result];
199 jrr[jss::ledger_current_index] == env.current()->info().seq);
206 testcase(
"Ledger Request, Full Option");
207 using namespace test::jtx;
214 jvParams[jss::ledger_index] = 3u;
215 jvParams[jss::full] =
true;
217 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
218 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
219 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
220 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 3u);
226 testcase(
"Ledger Request, Full Option Without Admin");
227 using namespace test::jtx;
234 jvParams[jss::ledger_index] = 1u;
235 jvParams[jss::full] =
true;
237 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
239 jrr,
"noPermission",
"You don't have permission for this command.");
245 testcase(
"Ledger Request, Accounts Option");
246 using namespace test::jtx;
253 jvParams[jss::ledger_index] = 3u;
254 jvParams[jss::accounts] =
true;
256 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
257 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
258 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
259 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 3u);
270 using namespace test::jtx;
273 cfg->FEES.reference_fee = 10;
277 env.fund(
XRP(10000),
"alice");
279 env.fund(
XRP(10000),
"bob");
281 env.fund(
XRP(10000),
"jim");
283 env.fund(
XRP(10000),
"jill");
288 jvParams[jss::ledger] =
"closed";
292 boost::lexical_cast<std::string>(jvParams))[jss::result];
293 BEAST_EXPECT(jrr.isMember(jss::ledger));
294 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
295 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"5");
297 jvParams[jss::ledger] =
"validated";
301 boost::lexical_cast<std::string>(jvParams))[jss::result];
302 BEAST_EXPECT(jrr.isMember(jss::ledger));
303 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
304 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"5");
306 jvParams[jss::ledger] =
"current";
310 boost::lexical_cast<std::string>(jvParams))[jss::result];
311 BEAST_EXPECT(jrr.isMember(jss::ledger));
312 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"6");
315 jvParams[jss::ledger] =
"invalid";
319 boost::lexical_cast<std::string>(jvParams))[jss::result];
320 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
321 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerIndexMalformed");
324 jvParams[jss::ledger] = 4;
328 boost::lexical_cast<std::string>(jvParams))[jss::result];
329 BEAST_EXPECT(jrr.isMember(jss::ledger));
330 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
331 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"4");
334 jvParams[jss::ledger] = 20;
338 boost::lexical_cast<std::string>(jvParams))[jss::result];
339 BEAST_EXPECT(jrr[jss::error] ==
"lgrNotFound");
340 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerNotFound");
345 "E86DE7F3D7A4D9CE17EF7C8BA08A8F4D"
346 "8F643B9552F0D895A31CDA78F541DE4E"};
349 jvParams[jss::ledger_hash] = hash3;
353 boost::lexical_cast<std::string>(jvParams))[jss::result];
354 BEAST_EXPECT(jrr.isMember(jss::ledger));
355 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
356 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"3");
359 jvParams[jss::ledger_hash] =
"DEADBEEF" + hash3;
363 boost::lexical_cast<std::string>(jvParams))[jss::result];
364 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
365 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerHashMalformed");
368 jvParams[jss::ledger_hash] = 2;
372 boost::lexical_cast<std::string>(jvParams))[jss::result];
373 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
374 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerHashNotString");
377 jvParams[jss::ledger_hash] =
378 "2E81FC6EC0DD943197EGC7E3FBE9AE30"
379 "7F2775F2F7485BB37307984C3C0F2340";
383 boost::lexical_cast<std::string>(jvParams))[jss::result];
384 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
385 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerHashMalformed");
388 jvParams[jss::ledger_hash] =
389 "8C3EEDB3124D92E49E75D81A8826A2E6"
390 "5A75FD71FC3FD6F36FEB803C5F1D812D";
394 boost::lexical_cast<std::string>(jvParams))[jss::result];
395 BEAST_EXPECT(jrr[jss::error] ==
"lgrNotFound");
396 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerNotFound");
402 jvParams[jss::ledger_index] =
"closed";
406 boost::lexical_cast<std::string>(jvParams))[jss::result];
407 BEAST_EXPECT(jrr.isMember(jss::ledger));
408 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
409 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"5");
410 BEAST_EXPECT(jrr.isMember(jss::ledger_index));
412 jvParams[jss::ledger_index] =
"validated";
416 boost::lexical_cast<std::string>(jvParams))[jss::result];
417 BEAST_EXPECT(jrr.isMember(jss::ledger));
418 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
419 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"5");
421 jvParams[jss::ledger_index] =
"current";
425 boost::lexical_cast<std::string>(jvParams))[jss::result];
426 BEAST_EXPECT(jrr.isMember(jss::ledger));
427 BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] ==
"6");
428 BEAST_EXPECT(jrr.isMember(jss::ledger_current_index));
431 jvParams[jss::ledger_index] =
"invalid";
435 boost::lexical_cast<std::string>(jvParams))[jss::result];
436 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
437 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerIndexMalformed");
440 for (
auto i : {1, 2, 3, 4, 5, 6})
442 jvParams[jss::ledger_index] = i;
446 boost::lexical_cast<std::string>(jvParams))[jss::result];
447 BEAST_EXPECT(jrr.isMember(jss::ledger));
449 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
455 jvParams[jss::ledger_index] = 7;
459 boost::lexical_cast<std::string>(jvParams))[jss::result];
460 BEAST_EXPECT(jrr[jss::error] ==
"lgrNotFound");
461 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerNotFound");
468 testcase(
"Ledger with queueing disabled");
469 using namespace test::jtx;
473 jv[jss::ledger_index] =
"current";
474 jv[jss::queue] =
true;
475 jv[jss::expand] =
true;
477 auto jrr = env.rpc(
"json",
"ledger",
to_string(jv))[jss::result];
478 BEAST_EXPECT(!jrr.isMember(jss::queue_data));
484 testcase(
"Ledger with Queued Transactions");
485 using namespace test::jtx;
487 auto& section = cfg->section(
"transaction_queue");
488 section.set(
"minimum_txn_in_ledger_standalone",
"3");
489 section.set(
"normal_consensus_increase_percent",
"0");
493 cfg->FEES.reference_fee = 10;
494 Env env(*
this, std::move(cfg));
497 jv[jss::ledger_index] =
"current";
498 jv[jss::queue] =
true;
499 jv[jss::expand] =
true;
503 Account const charlie{
"charlie"};
512 auto jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
513 BEAST_EXPECT(!jrr.isMember(jss::queue_data));
519 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
524 BEAST_EXPECT(env.
current()->info().seq == 5);
527 auto aliceSeq = env.
seq(alice);
528 env(
pay(alice,
"george",
XRP(1000)),
529 json(R
"({"LastLedgerSequence":7})"),
531 env(offer(alice, XRP(50000), alice["USD"](5000)),
536 auto batch = [&env](
Account a) {
537 auto aSeq = env.
seq(a);
539 for (
int i = 0; i < 10; ++i)
550 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
551 BEAST_EXPECT(jrr[jss::queue_data].size() == 33);
557 BEAST_EXPECT(env.
current()->info().seq == 8);
559 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
560 BEAST_EXPECT(jrr[jss::queue_data].size() == 11);
564 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
566 auto const& parentHash = env.
current()->info().parentHash;
567 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
570 auto const& txj = jrr[jss::queue_data][1u];
571 BEAST_EXPECT(txj[jss::account] == alice.human());
572 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
573 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
574 BEAST_EXPECT(txj[
"retries_remaining"] == 10);
575 BEAST_EXPECT(txj.isMember(jss::tx));
576 auto const& tx = txj[jss::tx];
577 BEAST_EXPECT(tx[jss::Account] == alice.human());
578 BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
579 return tx[jss::hash].asString();
582 auto const& txj = jrr[jss::queue_data][0u];
583 BEAST_EXPECT(txj[jss::account] == alice.human());
584 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
585 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
586 BEAST_EXPECT(txj[
"retries_remaining"] == 10);
587 BEAST_EXPECT(txj.isMember(jss::tx));
588 auto const& tx = txj[jss::tx];
589 BEAST_EXPECT(tx[jss::Account] == alice.human());
590 BEAST_EXPECT(tx[jss::TransactionType] == jss::OfferCreate);
591 const auto txid0 = tx[jss::hash].asString();
595 BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
603 jv[jss::expand] =
false;
605 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
606 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
608 auto const& parentHash = env.
current()->info().parentHash;
609 auto const txid1 = [&]() {
610 auto const& txj = jrr[jss::queue_data][1u];
611 BEAST_EXPECT(txj[jss::account] == alice.human());
612 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
613 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
614 BEAST_EXPECT(txj.isMember(jss::tx));
615 return txj[jss::tx].asString();
617 auto const& txj = jrr[jss::queue_data][0u];
618 BEAST_EXPECT(txj[jss::account] == alice.human());
619 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
620 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
621 BEAST_EXPECT(txj[
"retries_remaining"] == 9);
622 BEAST_EXPECT(txj[
"last_result"] ==
"terPRE_SEQ");
623 BEAST_EXPECT(txj.isMember(jss::tx));
624 BEAST_EXPECT(txj[jss::tx] == txid0);
628 BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
633 jv[jss::expand] =
true;
634 jv[jss::binary] =
true;
636 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
637 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
639 auto const& txj = jrr[jss::queue_data][1u];
640 BEAST_EXPECT(txj[jss::account] == alice.human());
641 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
642 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
643 BEAST_EXPECT(txj[
"retries_remaining"] == 8);
644 BEAST_EXPECT(txj[
"last_result"] ==
"terPRE_SEQ");
645 BEAST_EXPECT(txj.isMember(jss::tx));
646 BEAST_EXPECT(txj[jss::tx].isMember(jss::tx_blob));
648 auto const& txj2 = jrr[jss::queue_data][0u];
649 BEAST_EXPECT(txj2[jss::account] == alice.human());
650 BEAST_EXPECT(txj2[jss::fee_level] ==
"256");
651 BEAST_EXPECT(txj2[
"preflight_result"] ==
"tesSUCCESS");
652 BEAST_EXPECT(txj2[
"retries_remaining"] == 10);
653 BEAST_EXPECT(!txj2.isMember(
"last_result"));
654 BEAST_EXPECT(txj2.isMember(jss::tx));
655 BEAST_EXPECT(txj2[jss::tx].isMember(jss::tx_blob));
658 for (
int i = 0; i != 9; ++i)
663 jv[jss::expand] =
false;
664 jv[jss::binary] =
false;
666 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
668 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
670 auto const& txj = jrr[jss::queue_data][0u];
671 BEAST_EXPECT(txj[jss::account] == alice.human());
672 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
673 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
674 BEAST_EXPECT(txj[
"retries_remaining"] == 1);
675 BEAST_EXPECT(txj[
"last_result"] ==
"terPRE_SEQ");
676 BEAST_EXPECT(txj.isMember(jss::tx));
677 BEAST_EXPECT(txj[jss::tx] != txid0);
678 return txj[jss::tx].asString();
683 jv[jss::full] =
true;
685 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
686 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
688 auto const& txj = jrr[jss::queue_data][0u];
689 BEAST_EXPECT(txj[jss::account] == alice.human());
690 BEAST_EXPECT(txj[jss::fee_level] ==
"256");
691 BEAST_EXPECT(txj[
"preflight_result"] ==
"tesSUCCESS");
692 BEAST_EXPECT(txj[
"retries_remaining"] == 1);
693 BEAST_EXPECT(txj[
"last_result"] ==
"terPRE_SEQ");
694 BEAST_EXPECT(txj.isMember(jss::tx));
695 auto const& tx = txj[jss::tx];
696 BEAST_EXPECT(tx[jss::Account] == alice.human());
697 BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
698 BEAST_EXPECT(tx[jss::hash] == txid2);
705 testcase(
"Ledger Request, Accounts Hashes");
706 using namespace test::jtx;
715 jvParams[jss::ledger_index] = 3u;
716 jvParams[jss::accounts] =
true;
717 jvParams[jss::expand] =
true;
718 jvParams[jss::type] =
"hashes";
720 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
721 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
722 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
723 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
725 jrr[jss::ledger][jss::accountState][0u][
"LedgerEntryType"] ==
727 index = jrr[jss::ledger][jss::accountState][0u][
"index"].asString();
731 jvParams[jss::ledger_index] = 3u;
732 jvParams[jss::accounts] =
true;
733 jvParams[jss::expand] =
false;
734 jvParams[jss::type] =
"hashes";
736 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
737 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
738 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
739 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
740 BEAST_EXPECT(jrr[jss::ledger][jss::accountState][0u] == index);
761BEAST_DEFINE_TESTSUITE(LedgerRPC, app,
ripple);
bool isMember(const char *key) const
Return true if the object has a member named key.
testcase_t testcase
Memberspace for declaring test cases.
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
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)
void testLedgerFullNonAdmin()
void testLedgerAccounts()
void testLedgerAccountsOption()
Immutable cryptographic account descriptor.
A transaction testing environment.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Set the expected result code for a JTx The test will fail if the code doesn't match.
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
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
XRP_t const XRP
Converts to XRP Issue or STAmount.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::string to_string(base_uint< Bits, Tag > const &a)
Set the sequence number on a JTx.