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>
27#include <xrpld/app/misc/TxQ.h>
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>
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);
54 jv[jss::error_message] ==
"");
56 else if (BEAST_EXPECT(jv.
isMember(jss::error_message)))
57 BEAST_EXPECT(jv[jss::error_message] == msg);
74 using namespace test::jtx;
79 BEAST_EXPECT(env.current()->info().seq == 4);
84 jvParams[jss::ledger_index] = 1;
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");
93 jvParams[jss::ledger_index] =
"1";
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");
102 auto const jrr = env.rpc(
"ledger",
"current")[jss::result];
103 BEAST_EXPECT(jrr[jss::ledger][jss::closed] ==
false);
105 jrr[jss::ledger][jss::ledger_index] ==
108 jrr[jss::ledger_current_index] == env.current()->info().seq);
116 using namespace test::jtx;
119 auto const USD = gw[
"USD"];
122 env.fund(
XRP(10000), gw, bob);
124 env.trust(USD(1000), bob);
130 jvParams[jss::ledger_index] =
"potato";
132 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
139 jvParams[jss::ledger_index] = -1;
141 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
148 jvParams[jss::ledger_index] = 10u;
150 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
156 auto const jrr = env.rpc(
"ledger",
"arbitrary_text")[jss::result];
163 jvParams[jss::ledger_index] =
"validated";
164 jvParams[jss::queue] =
true;
166 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
173 env.rpc(
"json",
"ledger",
"{ \"ledger_index\" : 2e15 }");
175 BEAST_EXPECT(ret[jss::error_message] ==
"Invalid parameters.");
180 auto const ret = env.rpc(
181 "json",
"ledger",
"{ \"ledger_index\" : 1000000000000000 }");
190 using namespace test::jtx;
195 BEAST_EXPECT(env.current()->info().seq == 4);
198 auto const jrr = env.rpc(
"ledger_current")[jss::result];
200 jrr[jss::ledger_current_index] == env.current()->info().seq);
207 testcase(
"Ledger Request, Full Option");
208 using namespace test::jtx;
215 jvParams[jss::ledger_index] = 3u;
216 jvParams[jss::full] =
true;
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);
227 testcase(
"Ledger Request, Full Option Without Admin");
228 using namespace test::jtx;
235 jvParams[jss::ledger_index] = 1u;
236 jvParams[jss::full] =
true;
238 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
240 jrr,
"noPermission",
"You don't have permission for this command.");
246 testcase(
"Ledger Request, Accounts Option");
247 using namespace test::jtx;
254 jvParams[jss::ledger_index] = 3u;
255 jvParams[jss::accounts] =
true;
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);
271 using namespace test::jtx;
274 cfg->FEES.reference_fee = 10;
278 env.fund(
XRP(10000),
"alice");
280 env.fund(
XRP(10000),
"bob");
282 env.fund(
XRP(10000),
"jim");
284 env.fund(
XRP(10000),
"jill");
289 jvParams[jss::ledger] =
"closed";
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");
298 jvParams[jss::ledger] =
"validated";
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");
307 jvParams[jss::ledger] =
"current";
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");
316 jvParams[jss::ledger] =
"invalid";
320 boost::lexical_cast<std::string>(jvParams))[jss::result];
321 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
322 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerIndexMalformed");
325 jvParams[jss::ledger] = 4;
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");
335 jvParams[jss::ledger] = 20;
339 boost::lexical_cast<std::string>(jvParams))[jss::result];
340 BEAST_EXPECT(jrr[jss::error] ==
"lgrNotFound");
341 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerNotFound");
346 "E86DE7F3D7A4D9CE17EF7C8BA08A8F4D"
347 "8F643B9552F0D895A31CDA78F541DE4E"};
350 jvParams[jss::ledger_hash] = hash3;
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");
360 jvParams[jss::ledger_hash] =
"DEADBEEF" + hash3;
364 boost::lexical_cast<std::string>(jvParams))[jss::result];
365 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
366 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerHashMalformed");
369 jvParams[jss::ledger_hash] = 2;
373 boost::lexical_cast<std::string>(jvParams))[jss::result];
374 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
375 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerHashNotString");
378 jvParams[jss::ledger_hash] =
379 "2E81FC6EC0DD943197EGC7E3FBE9AE30"
380 "7F2775F2F7485BB37307984C3C0F2340";
384 boost::lexical_cast<std::string>(jvParams))[jss::result];
385 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
386 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerHashMalformed");
389 jvParams[jss::ledger_hash] =
390 "8C3EEDB3124D92E49E75D81A8826A2E6"
391 "5A75FD71FC3FD6F36FEB803C5F1D812D";
395 boost::lexical_cast<std::string>(jvParams))[jss::result];
396 BEAST_EXPECT(jrr[jss::error] ==
"lgrNotFound");
397 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerNotFound");
403 jvParams[jss::ledger_index] =
"closed";
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));
413 jvParams[jss::ledger_index] =
"validated";
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");
422 jvParams[jss::ledger_index] =
"current";
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));
432 jvParams[jss::ledger_index] =
"invalid";
436 boost::lexical_cast<std::string>(jvParams))[jss::result];
437 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
438 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerIndexMalformed");
441 for (
auto i : {1, 2, 3, 4, 5, 6})
443 jvParams[jss::ledger_index] = i;
447 boost::lexical_cast<std::string>(jvParams))[jss::result];
448 BEAST_EXPECT(jrr.isMember(jss::ledger));
450 BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
456 jvParams[jss::ledger_index] = 7;
460 boost::lexical_cast<std::string>(jvParams))[jss::result];
461 BEAST_EXPECT(jrr[jss::error] ==
"lgrNotFound");
462 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerNotFound");
469 testcase(
"Ledger with queueing disabled");
470 using namespace test::jtx;
474 jv[jss::ledger_index] =
"current";
475 jv[jss::queue] =
true;
476 jv[jss::expand] =
true;
478 auto jrr = env.rpc(
"json",
"ledger",
to_string(jv))[jss::result];
479 BEAST_EXPECT(!jrr.isMember(jss::queue_data));
485 testcase(
"Ledger with Queued Transactions");
486 using namespace test::jtx;
488 auto& section = cfg->section(
"transaction_queue");
489 section.set(
"minimum_txn_in_ledger_standalone",
"3");
490 section.set(
"normal_consensus_increase_percent",
"0");
494 cfg->FEES.reference_fee = 10;
495 Env env(*
this, std::move(cfg));
498 jv[jss::ledger_index] =
"current";
499 jv[jss::queue] =
true;
500 jv[jss::expand] =
true;
504 Account const charlie{
"charlie"};
513 auto jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
514 BEAST_EXPECT(!jrr.isMember(jss::queue_data));
520 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
525 BEAST_EXPECT(env.
current()->info().seq == 5);
528 auto aliceSeq = env.
seq(alice);
529 env(
pay(alice,
"george",
XRP(1000)),
530 json(R
"({"LastLedgerSequence":7})"),
532 env(offer(alice, XRP(50000), alice["USD"](5000)),
537 auto batch = [&env](
Account a) {
538 auto aSeq = env.
seq(a);
540 for (
int i = 0; i < 10; ++i)
551 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
552 BEAST_EXPECT(jrr[jss::queue_data].size() == 33);
558 BEAST_EXPECT(env.
current()->info().seq == 8);
560 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
561 BEAST_EXPECT(jrr[jss::queue_data].size() == 11);
565 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
567 auto const& parentHash = env.
current()->info().parentHash;
568 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
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();
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 const auto txid0 = tx[jss::hash].asString();
596 BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
604 jv[jss::expand] =
false;
606 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
607 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
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();
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);
629 BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
634 jv[jss::expand] =
true;
635 jv[jss::binary] =
true;
637 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
638 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
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));
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));
659 for (
int i = 0; i != 9; ++i)
664 jv[jss::expand] =
false;
665 jv[jss::binary] =
false;
667 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
669 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
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();
684 jv[jss::full] =
true;
686 jrr = env.
rpc(
"json",
"ledger",
to_string(jv))[jss::result];
687 if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
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);
706 testcase(
"Ledger Request, Accounts Hashes");
707 using namespace test::jtx;
716 jvParams[jss::ledger_index] = 3u;
717 jvParams[jss::accounts] =
true;
718 jvParams[jss::expand] =
true;
719 jvParams[jss::type] =
"hashes";
721 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
722 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
723 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
724 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
726 jrr[jss::ledger][jss::accountState][0u][
"LedgerEntryType"] ==
728 index = jrr[jss::ledger][jss::accountState][0u][
"index"].asString();
732 jvParams[jss::ledger_index] = 3u;
733 jvParams[jss::accounts] =
true;
734 jvParams[jss::expand] =
false;
735 jvParams[jss::type] =
"hashes";
737 env.rpc(
"json",
"ledger",
to_string(jvParams))[jss::result];
738 BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
739 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
740 BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
741 BEAST_EXPECT(jrr[jss::ledger][jss::accountState][0u] == index);
762BEAST_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.