21#include <test/jtx/TestHelpers.h>
22#include <test/jtx/TestSuite.h>
23#include <test/jtx/WSClient.h>
24#include <test/jtx/envconfig.h>
25#include <test/jtx/ticket.h>
27#include <xrpld/app/main/Application.h>
28#include <xrpld/app/misc/LoadFeeTrack.h>
29#include <xrpld/app/misc/TxQ.h>
30#include <xrpld/app/tx/apply.h>
32#include <xrpl/protocol/ErrorCodes.h>
33#include <xrpl/protocol/jss.h>
34#include <xrpl/protocol/st.h>
50 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
59 auto const& view = *env.
current();
60 auto const base = [&view]() {
61 auto base = view.fees().base;
69 return toDrops(metrics.openLedgerFeeLevel, base) + 1;
82 return txs.begin()->feeLevel.fee();
108 auto& section = p->section(
"transaction_queue");
109 section.set(
"ledgers_in_queue",
"2");
110 section.set(
"minimum_queue_size",
"2");
111 section.set(
"min_ledgers_to_compute_size_limit",
"3");
112 section.set(
"max_ledger_counts_to_store",
"100");
113 section.set(
"retry_sequence_percent",
"25");
114 section.set(
"normal_consensus_increase_percent",
"0");
116 for (
auto const& [k, v] : extraTxQ)
121 if (!extraVoting.
empty())
123 auto& votingSection = p->section(
"voting");
124 for (
auto const& [k, v] : extraVoting)
126 votingSection.set(k, v);
130 p->section(
"validation_seed")
131 .legacy(
"shUwVw52ofnCUX5m7kPTKzJdr4HEH");
149 for (
auto i = env.
current()->seq(); i <= 257; ++i)
156 auto const flagMaxQueue = ledgersInQueue * flagPerLedger;
157 checkMetrics(*
this, env, 0, flagMaxQueue, 0, flagPerLedger);
166 using namespace std::chrono_literals;
168 checkMetrics(*
this, env, 0, flagMaxQueue, 0, expectedPerLedger);
169 auto const fees = env.
current()->fees();
185 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
189 auto charlie =
Account(
"charlie");
198 auto const baseFee = env.
current()->fees().base.drops();
294 constexpr auto largeFeeMultiplier = 700;
295 auto const largeFee = baseFee * largeFeeMultiplier;
299 env(
noop(hank),
fee(largeFee));
300 env(
noop(gwen),
fee(largeFee));
301 env(
noop(fred),
fee(largeFee));
302 env(
noop(elmo),
fee(largeFee));
378 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
392 metrics.txPerLedger + 1,
393 metrics.txPerLedger);
402 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
407 auto const baseFee = env.
current()->fees().base.drops();
460 checkMetrics(*
this, env, 8, 8, 5, 4, expectedMinFeeLevel);
623 fee(baseFee * 2.1 * 1.25 - 1),
627 fee(baseFee * 2.1 * 1.25 + 1),
633 fee(baseFee * 2.2 * 1.25 - 1),
637 fee(baseFee * 2.2 * 1.25 + 1),
661 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
665 auto USD = gw[
"USD"];
698 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
702 auto charlie =
Account(
"charlie");
705 auto const baseFee = env.
current()->fees().base.drops();
754 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
758 auto charlie =
Account(
"charlie");
761 auto felicia =
Account(
"felicia");
764 auto const baseFee = env.
current()->fees().base.drops();
785 json(R
"({"LastLedgerSequence":7})"),
790 constexpr auto largeFeeMultiplier = 700;
791 auto const largeFee = baseFee * largeFeeMultiplier;
806 aliceStat.begin()->lastValid &&
807 *aliceStat.begin()->lastValid == 8);
808 BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker());
810 auto bobStat = txQ.getAccountTxs(bob.id());
813 bobStat.begin()->feeLevel ==
814 FeeLevel64{baseFeeLevel.fee() * largeFeeMultiplier});
816 BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker());
840 constexpr auto anotherLargeFeeMultiplier = 800;
841 auto const anotherLargeFee = baseFee * anotherLargeFeeMultiplier;
880 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
887 auto const baseFee = env.
current()->fees().base.drops();
917 constexpr auto aliceFeeMultiplier = 3;
918 auto feeAlice = baseFee * aliceFeeMultiplier;
919 auto seqAlice = env.
seq(alice);
920 for (
int i = 0; i < 4; ++i)
923 feeAlice = (feeAlice + 1) * 125 / 100;
929 auto const seqBob = env.
seq(bob);
934 auto feeCarol = feeAlice;
935 auto seqCarol = env.
seq(carol);
936 for (
int i = 0; i < 4; ++i)
939 feeCarol = (feeCarol + 1) * 125 / 100;
1004 using namespace jtx;
1007 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
1009 auto alice =
Account(
"alice");
1030 auto const& jt = env.
jt(
noop(alice));
1055 using namespace jtx;
1061 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1062 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1064 auto alice =
Account(
"alice");
1066 auto charlie =
Account(
"charlie");
1067 auto daria =
Account(
"daria");
1074 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1085 auto aliceSeq = env.
seq(alice);
1086 auto bobSeq = env.
seq(bob);
1087 auto charlieSeq = env.
seq(charlie);
1132 aliceSeq = env.
seq(alice);
1133 auto lastLedgerSeq = env.
current()->info().seq + 2;
1134 for (
auto i = 0; i < 7; i++)
1138 json(jss::LastLedgerSequence, lastLedgerSeq + i),
1148 auto const& baseFee = env.
current()->fees().base;
1149 auto seq = env.
seq(alice);
1151 for (
auto const& tx : aliceStat)
1158 (tx.consequences.fee() ==
drops(aliceFee) &&
1159 tx.consequences.potentialSpend() ==
drops(0) &&
1160 !tx.consequences.isBlocker()) ||
1161 tx.seqProxy.value() == env.
seq(alice) + 6);
1171 json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1204 aliceSeq = env.
seq(alice) + 2;
1223 aliceSeq = env.
seq(alice) + 1;
1230 env.
le(alice)->getFieldAmount(sfBalance).xrp().drops() - (62);
1273 bobSeq = env.
seq(bob);
1275 for (
int i = 0; i < 10; ++i)
1290 env.
le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10 - 1);
1304 env.
le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10);
1323 using namespace jtx;
1327 auto cfg =
makeConfig({{
"minimum_txn_in_ledger_standalone",
"4"}});
1328 cfg->FEES.reference_fee = 10;
1329 Env env(*
this, std::move(cfg));
1331 auto alice =
Account(
"alice");
1333 auto charlie =
Account(
"charlie");
1334 auto daria =
Account(
"daria");
1370 auto aliceSeq = env.
seq(alice);
1371 auto bobSeq = env.
seq(bob);
1372 auto charlieSeq = env.
seq(charlie);
1373 auto dariaSeq = env.
seq(daria);
1374 auto elmoSeq = env.
seq(elmo);
1375 auto fredSeq = env.
seq(fred);
1376 auto gwenSeq = env.
seq(gwen);
1377 auto hankSeq = env.
seq(hank);
1419 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1420 gwenSeq + hankSeq + 6 ==
1421 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1422 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1424 using namespace std::string_literals;
1426 aliceSeq == env.
seq(alice),
1430 bobSeq + 1 == env.
seq(bob),
1434 charlieSeq + 2 == env.
seq(charlie),
1438 dariaSeq + 1 == env.
seq(daria),
1442 elmoSeq + 1 == env.
seq(elmo),
1446 fredSeq == env.
seq(fred),
1450 gwenSeq == env.
seq(gwen),
1454 hankSeq + 1 == env.
seq(hank),
1469 auto getTxsQueued = [&]() {
1472 for (
auto const& tx : txs)
1474 ++
result[tx.txn->at(sfAccount)];
1478 auto qTxCount1 = getTxsQueued();
1483 seq(aliceSeq + qTxCount1[alice.id()]++),
1488 seq(charlieSeq + qTxCount1[charlie.id()]++),
1492 seq(dariaSeq + qTxCount1[daria.id()]++),
1507 seq(aliceSeq + qTxCount1[alice.id()]++),
1519 auto qTxCount2 = getTxsQueued();
1525 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1526 gwenSeq + hankSeq + 7 ==
1527 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1528 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1531 aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] ==
1536 bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.
seq(bob),
1540 charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] ==
1545 dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] ==
1550 elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] ==
1555 fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] ==
1560 gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] ==
1565 hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] ==
1574 using namespace jtx;
1577 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"1"}}));
1579 auto alice =
Account(
"alice");
1593 json(R
"({"AccountTxnID": "0"})"),
1611 using namespace jtx;
1612 using namespace std::string_literals;
1619 {{
"minimum_txn_in_ledger_standalone",
"2"},
1620 {
"minimum_txn_in_ledger",
"5"},
1621 {
"target_txn_in_ledger",
"4"},
1622 {
"maximum_txn_in_ledger",
"5"}}));
1623 auto const baseFee = env.
current()->fees().base.drops();
1625 auto alice =
Account(
"alice");
1633 for (
int i = 0; i < 10; ++i)
1641 double const feeMultiplier =
1642 static_cast<double>(cost.drops()) / baseFee;
1664 {{
"minimum_txn_in_ledger",
"200"},
1665 {
"minimum_txn_in_ledger_standalone",
"200"},
1666 {
"target_txn_in_ledger",
"4"},
1667 {
"maximum_txn_in_ledger",
"5"}}));
1675 "The minimum number of low-fee transactions allowed "
1676 "per ledger (minimum_txn_in_ledger) exceeds "
1677 "the maximum number of low-fee transactions allowed per "
1678 "ledger (maximum_txn_in_ledger)."s);
1685 {{
"minimum_txn_in_ledger",
"200"},
1686 {
"minimum_txn_in_ledger_standalone",
"2"},
1687 {
"target_txn_in_ledger",
"4"},
1688 {
"maximum_txn_in_ledger",
"5"}}));
1696 "The minimum number of low-fee transactions allowed "
1697 "per ledger (minimum_txn_in_ledger) exceeds "
1698 "the maximum number of low-fee transactions allowed per "
1699 "ledger (maximum_txn_in_ledger)."s);
1706 {{
"minimum_txn_in_ledger",
"2"},
1707 {
"minimum_txn_in_ledger_standalone",
"200"},
1708 {
"target_txn_in_ledger",
"4"},
1709 {
"maximum_txn_in_ledger",
"5"}}));
1717 "The minimum number of low-fee transactions allowed "
1718 "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1719 "the maximum number of low-fee transactions allowed per "
1720 "ledger (maximum_txn_in_ledger)."s);
1727 using namespace jtx;
1728 testcase(
"unexpected balance change");
1733 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1734 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1736 auto alice =
Account(
"alice");
1742 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1749 auto USD = bob[
"USD"];
1763 auto aliceSeq = env.
seq(alice);
1807 for (
int i = 0; i < 9; ++i)
1822 using namespace jtx;
1825 auto alice =
Account(
"alice");
1827 auto charlie =
Account(
"charlie");
1828 auto daria =
Account(
"daria");
1832 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1833 auto const baseFee = env.
current()->fees().base.drops();
1847 env(
regkey(alice, charlie));
1851 auto const aliceSeq = env.
seq(alice);
1867 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1886 auto const aliceSeq = env.
seq(alice);
1904 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1930 auto const aliceSeq = env.
seq(alice);
1954 using namespace jtx;
1957 auto alice =
Account(
"alice");
1959 auto charlie =
Account(
"charlie");
1960 auto daria =
Account(
"daria");
1964 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1965 auto const baseFee = env.
current()->fees().base.drops();
1982 env(
regkey(alice, charlie));
1986 auto const aliceSeq = env.
seq(alice);
2002 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
2006 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
2030 auto const aliceSeq = env.
seq(alice);
2060 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
2120 using namespace jtx;
2121 testcase(
"In-flight balance checks");
2126 {{
"minimum_txn_in_ledger_standalone",
"3"}},
2127 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
2129 auto alice =
Account(
"alice");
2130 auto charlie =
Account(
"charlie");
2141 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
2148 checkMetrics(*
this, env, 0, initQueueMax, limit + 1, limit);
2150 auto USD = gw[
"USD"];
2151 auto BUX = gw[
"BUX"];
2155 auto aliceSeq = env.
seq(alice);
2156 auto aliceBal = env.
balance(alice);
2163 checkMetrics(*
this, env, 1, initQueueMax, limit + 1, limit);
2168 checkMetrics(*
this, env, 2, initQueueMax, limit + 1, limit);
2184 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2185 aliceSeq = env.
seq(alice);
2186 aliceBal = env.
balance(alice);
2192 checkMetrics(*
this, env, 1, limit * 2, limit + 1, limit);
2197 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2205 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2221 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2222 aliceSeq = env.
seq(alice);
2223 aliceBal = env.
balance(alice);
2230 checkMetrics(*
this, env, 1, limit * 2, limit + 1, limit);
2238 checkMetrics(*
this, env, 1, limit * 2, limit + 1, limit);
2254 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2255 aliceSeq = env.
seq(alice);
2256 aliceBal = env.
balance(alice);
2264 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2280 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2282 aliceSeq = env.
seq(alice);
2283 aliceBal = env.
balance(alice);
2293 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2307 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2309 aliceSeq = env.
seq(alice);
2310 aliceBal = env.
balance(alice);
2318 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2330 auto const amount = USD(500000);
2331 env(
trust(alice, USD(50000000)));
2332 env(
trust(charlie, USD(50000000)));
2338 env(
pay(gw, alice, amount));
2345 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2347 aliceSeq = env.
seq(alice);
2348 aliceBal = env.
balance(alice);
2349 auto aliceUSD = env.
balance(alice, USD);
2353 env(
pay(alice, charlie, amount),
queued);
2358 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2376 env(
offer(gw,
XRP(500000), USD(50000)));
2382 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2384 aliceSeq = env.
seq(alice);
2385 aliceBal = env.
balance(alice);
2386 auto charlieUSD = env.
balance(charlie, USD);
2398 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2409 balance(charlie, charlieUSD + USD(1000)),
2417 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2419 aliceSeq = env.
seq(alice);
2420 aliceBal = env.
balance(alice);
2421 charlieUSD = env.
balance(charlie, USD);
2432 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2443 balance(charlie, charlieUSD + USD(500)),
2453 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2455 aliceSeq = env.
seq(alice);
2456 aliceBal = env.
balance(alice);
2463 checkMetrics(*
this, env, 1, limit * 2, limit + 1, limit);
2474 using namespace jtx;
2479 auto const alice =
Account(
"alice");
2498 auto USD = alice[
"USD"];
2540 using namespace jtx;
2541 testcase(
"acct in queue but empty");
2543 auto alice =
Account(
"alice");
2545 auto charlie =
Account(
"charlie");
2549 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2550 auto const baseFee = env.
current()->fees().base.drops();
2578 env(
noop(bob),
fee(baseFee * 100));
2579 env(
noop(bob),
fee(baseFee * 100));
2580 env(
noop(bob),
fee(baseFee * 100));
2581 env(
noop(bob),
fee(baseFee * 100));
2582 env(
noop(bob),
fee(baseFee * 100));
2608 checkMetrics(*
this, env, 10, 10, 6, 5, expectedFeeLevel + 1);
2631 seq(charlieSeq - 1),
2635 seq(charlieSeq + 1),
2646 using namespace jtx;
2651 auto fee = env.
rpc(
"fee");
2658 result.isMember(jss::ledger_current_index) &&
2659 result[jss::ledger_current_index] == 3);
2671 auto const& levels =
result[jss::levels];
2687 result.isMember(jss::ledger_current_index) &&
2688 result[jss::ledger_current_index] == 4);
2699 auto const& levels =
result[jss::levels];
2721 using namespace jtx;
2722 testcase(
"expiration replacement");
2727 {{
"minimum_txn_in_ledger_standalone",
"1"},
2728 {
"ledgers_in_queue",
"10"},
2729 {
"maximum_txn_per_account",
"20"}}));
2731 auto const baseFee = env.
current()->fees().base.drops();
2734 auto const alice =
Account(
"alice");
2735 auto const bob =
Account(
"bob");
2740 auto const aliceSeq = env.
seq(alice);
2744 json(R
"({"LastLedgerSequence":5})"),
2748 json(R"({"LastLedgerSequence":5})"),
2752 json(R"({"LastLedgerSequence":10})"),
2756 json(R"({"LastLedgerSequence":11})"),
2759 auto const bobSeq = env.
seq(bob);
2763 for (
int i = 0; i < 3 + 4 + 5; ++i)
2767 checkMetrics(*
this, env, 4 + 3 + 4 + 5, std::nullopt, 2, 1);
2821 using namespace jtx;
2822 testcase(
"full queue gap handling");
2825 {{
"minimum_txn_in_ledger_standalone",
"1"},
2826 {
"ledgers_in_queue",
"10"},
2827 {
"maximum_txn_per_account",
"11"}});
2828 cfg->FEES.reference_fee = 10;
2829 Env env(*
this, std::move(cfg));
2831 auto const baseFee = env.
current()->fees().base.drops();
2836 auto const alice =
Account(
"alice");
2837 auto const bob =
Account(
"bob");
2842 auto const aliceSeq = env.
seq(alice);
2849 fee(baseFee * 20 + 1),
2853 json(R
"({"LastLedgerSequence":11})"),
2857 json(R"({"LastLedgerSequence":11})"),
2861 json(R"({"LastLedgerSequence":11})"),
2865 json(R"({"LastLedgerSequence":11})"),
2869 json(R"({"LastLedgerSequence":11})"),
2873 json(R"({"LastLedgerSequence": 5})"),
2877 json(R"({"LastLedgerSequence": 5})"),
2881 json(R"({"LastLedgerSequence": 5})"),
2885 json(R"({"LastLedgerSequence":11})"),
2889 auto const bobSeq = env.
seq(bob);
2893 for (
int i = 0; i < 2 + 4 + 5; ++i)
2897 checkMetrics(*
this, env, 10 + 2 + 4 + 5, std::nullopt, 2, 1);
2980 testcase(
"Autofilled sequence should account for TxQ");
2981 using namespace jtx;
2982 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"6"}}));
2983 auto const baseFee = env.
current()->fees().base.drops();
2987 auto const alice =
Account(
"alice");
2988 auto const bob =
Account(
"bob");
2989 env.
fund(
XRP(100000), alice, bob);
2995 auto const aliceSeq = env.
seq(alice);
2996 auto const lastLedgerSeq = env.
current()->info().seq + 2;
2999 for (
int i = 0; i < 5; ++i)
3006 json(jss::LastLedgerSequence, lastLedgerSeq),
3015 auto aliceStat = txQ.getAccountTxs(alice.id());
3018 for (
auto const& tx : aliceStat)
3022 tx.feeLevel ==
FeeLevel64{baseFeeLevel.fee() * 100});
3023 if (
seq.value() == aliceSeq + 2)
3026 tx.lastValid && *tx.lastValid == lastLedgerSeq);
3037 for (
int i = 0; i < 8; ++i)
3046 for (
int i = 0; i < 9; ++i)
3053 for (
int i = 0; i < 10; ++i)
3060 auto bobStat = txQ.getAccountTxs(bob.id());
3066 auto aliceStat = txQ.getAccountTxs(alice.id());
3067 auto seq = aliceSeq;
3069 for (
auto const& tx : aliceStat)
3072 if (
seq == aliceSeq + 2)
3077 tx.feeLevel ==
FeeLevel64{baseFeeLevel.fee() * 100});
3087 auto aliceStat = txQ.getAccountTxs(alice.id());
3088 auto seq = aliceSeq;
3090 for (
auto const& tx : aliceStat)
3103 auto bobStat = txQ.getAccountTxs(bob.id());
3107 auto aliceStat = txQ.getAccountTxs(alice.id());
3115 using namespace jtx;
3118 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3119 auto const baseFee = env.
current()->fees().base.drops();
3123 env.
fund(
XRP(1000000), alice);
3126 auto const withQueue =
3127 R
"({ "account": ")" + alice.human() + R"(", "queue": true })";
3130 R"(", "queue": true, "ledger_index": 3 })";
3137 info.isMember(jss::result) &&
3138 info[jss::result].isMember(jss::account_data));
3143 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3145 info.isMember(jss::result) &&
3146 info[jss::result].isMember(jss::account_data));
3165 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3167 info.isMember(jss::result) &&
3168 info[jss::result].isMember(jss::account_data));
3169 auto const&
result = info[jss::result];
3194 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3196 info.isMember(jss::result) &&
3197 info[jss::result].isMember(jss::account_data));
3198 auto const&
result = info[jss::result];
3211 data[jss::Sequence].asUInt() +
3224 auto const& item =
queued[i];
3227 item[jss::fee_level] ==
3237 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3252 json(jss::LastLedgerSequence, 10),
3257 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3259 info.isMember(jss::result) &&
3260 info[jss::result].isMember(jss::account_data));
3261 auto const&
result = info[jss::result];
3262 auto const&
data =
result[jss::account_data];
3274 data[jss::Sequence].asUInt() +
3287 auto const& item =
queued[i];
3290 item[jss::fee_level] ==
3299 if (i ==
queued.size() - 1)
3307 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3321 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3323 info.isMember(jss::result) &&
3324 info[jss::result].isMember(jss::account_data));
3325 auto const&
result = info[jss::result];
3326 auto const&
data =
result[jss::account_data];
3338 data[jss::Sequence].asUInt() +
3351 auto const& item =
queued[i];
3354 item[jss::fee_level] ==
3357 if (i ==
queued.size() - 1)
3364 item[jss::max_spend_drops] ==
3378 item[jss::max_spend_drops] ==
3391 info.isMember(jss::result) &&
3401 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3403 info.isMember(jss::result) &&
3404 info[jss::result].isMember(jss::account_data));
3405 auto const&
result = info[jss::result];
3422 using namespace jtx;
3425 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3426 auto const baseFee = env.
current()->fees().base.drops();
3430 env.
fund(
XRP(1000000), alice);
3434 auto const server_info = env.
rpc(
"server_info");
3436 server_info.isMember(jss::result) &&
3437 server_info[jss::result].isMember(jss::info));
3438 auto const& info = server_info[jss::result][jss::info];
3440 info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
3444 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3447 auto const server_state = env.
rpc(
"server_state");
3448 auto const& state = server_state[jss::result][jss::state];
3450 state.isMember(jss::load_factor) &&
3451 state[jss::load_factor] == 256);
3453 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3455 state.isMember(jss::load_factor_server) &&
3456 state[jss::load_factor_server] == 256);
3458 state.isMember(jss::load_factor_fee_escalation) &&
3459 state[jss::load_factor_fee_escalation] == 256);
3461 state.isMember(jss::load_factor_fee_queue) &&
3462 state[jss::load_factor_fee_queue] == 256);
3464 state.isMember(jss::load_factor_fee_reference) &&
3465 state[jss::load_factor_fee_reference] == 256);
3473 auto aliceSeq = env.
seq(alice);
3475 for (
auto i = 0; i < 4; ++i)
3484 auto const server_info = env.
rpc(
"server_info");
3486 server_info.isMember(jss::result) &&
3487 server_info[jss::result].isMember(jss::info));
3488 auto const& info = server_info[jss::result][jss::info];
3491 info.isMember(jss::load_factor) &&
3492 info[jss::load_factor] > 888.88 &&
3493 info[jss::load_factor] < 888.89);
3495 info.isMember(jss::load_factor_server) &&
3496 info[jss::load_factor_server] == 1);
3500 info.isMember(jss::load_factor_fee_escalation) &&
3501 info[jss::load_factor_fee_escalation] > 888.88 &&
3502 info[jss::load_factor_fee_escalation] < 888.89);
3505 auto const server_state = env.
rpc(
"server_state");
3506 auto const& state = server_state[jss::result][jss::state];
3508 state.isMember(jss::load_factor) &&
3509 state[jss::load_factor] == 227555);
3511 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3513 state.isMember(jss::load_factor_server) &&
3514 state[jss::load_factor_server] == 256);
3516 state.isMember(jss::load_factor_fee_escalation) &&
3517 state[jss::load_factor_fee_escalation] == 227555);
3519 state.isMember(jss::load_factor_fee_queue) &&
3520 state[jss::load_factor_fee_queue] == 256);
3522 state.isMember(jss::load_factor_fee_reference) &&
3523 state[jss::load_factor_fee_reference] == 256);
3529 auto const server_info = env.
rpc(
"server_info");
3531 server_info.isMember(jss::result) &&
3532 server_info[jss::result].isMember(jss::info));
3533 auto const& info = server_info[jss::result][jss::info];
3536 info.isMember(jss::load_factor) &&
3537 info[jss::load_factor] == 1000);
3541 info.isMember(jss::load_factor_net) &&
3542 info[jss::load_factor_net] == 1000);
3544 info.isMember(jss::load_factor_fee_escalation) &&
3545 info[jss::load_factor_fee_escalation] > 888.88 &&
3546 info[jss::load_factor_fee_escalation] < 888.89);
3549 auto const server_state = env.
rpc(
"server_state");
3550 auto const& state = server_state[jss::result][jss::state];
3552 state.isMember(jss::load_factor) &&
3553 state[jss::load_factor] == 256000);
3555 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3557 state.isMember(jss::load_factor_server) &&
3558 state[jss::load_factor_server] == 256000);
3560 state.isMember(jss::load_factor_fee_escalation) &&
3561 state[jss::load_factor_fee_escalation] == 227555);
3563 state.isMember(jss::load_factor_fee_queue) &&
3564 state[jss::load_factor_fee_queue] == 256);
3566 state.isMember(jss::load_factor_fee_reference) &&
3567 state[jss::load_factor_fee_reference] == 256);
3573 for (
int i = 0; i < 5; ++i)
3578 auto const server_info = env.
rpc(
"server_info");
3580 server_info.isMember(jss::result) &&
3581 server_info[jss::result].isMember(jss::info));
3582 auto const& info = server_info[jss::result][jss::info];
3585 info.isMember(jss::load_factor) &&
3586 info[jss::load_factor] > 888.88 &&
3587 info[jss::load_factor] < 888.89);
3592 info.isMember(jss::load_factor_server) &&
3593 info[jss::load_factor_server] > 1.245 &&
3594 info[jss::load_factor_server] < 2.4415);
3596 info.isMember(jss::load_factor_local) &&
3597 info[jss::load_factor_local] > 1.245 &&
3598 info[jss::load_factor_local] < 2.4415);
3601 info.isMember(jss::load_factor_fee_escalation) &&
3602 info[jss::load_factor_fee_escalation] > 888.88 &&
3603 info[jss::load_factor_fee_escalation] < 888.89);
3606 auto const server_state = env.
rpc(
"server_state");
3607 auto const& state = server_state[jss::result][jss::state];
3609 state.isMember(jss::load_factor) &&
3610 state[jss::load_factor] == 227555);
3612 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3617 state.isMember(jss::load_factor_server) &&
3618 state[jss::load_factor_server] >= 320 &&
3619 state[jss::load_factor_server] <= 625);
3621 state.isMember(jss::load_factor_fee_escalation) &&
3622 state[jss::load_factor_fee_escalation] == 227555);
3624 state.isMember(jss::load_factor_fee_queue) &&
3625 state[jss::load_factor_fee_queue] == 256);
3627 state.isMember(jss::load_factor_fee_reference) &&
3628 state[jss::load_factor_fee_reference] == 256);
3634 auto const server_info = env.
rpc(
"server_info");
3636 server_info.isMember(jss::result) &&
3637 server_info[jss::result].isMember(jss::info));
3638 auto const& info = server_info[jss::result][jss::info];
3645 info.isMember(jss::load_factor) &&
3646 info[jss::load_factor] > 1.245 &&
3647 info[jss::load_factor] < 2.4415);
3650 info.isMember(jss::load_factor_local) &&
3651 info[jss::load_factor_local] > 1.245 &&
3652 info[jss::load_factor_local] < 2.4415);
3654 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3657 auto const server_state = env.
rpc(
"server_state");
3658 auto const& state = server_state[jss::result][jss::state];
3660 state.isMember(jss::load_factor) &&
3661 state[jss::load_factor] >= 320 &&
3662 state[jss::load_factor] <= 625);
3664 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3669 state.isMember(jss::load_factor_server) &&
3670 state[jss::load_factor_server] >= 320 &&
3671 state[jss::load_factor_server] <= 625);
3673 state.isMember(jss::load_factor_fee_escalation) &&
3674 state[jss::load_factor_fee_escalation] == 256);
3676 state.isMember(jss::load_factor_fee_queue) &&
3677 state[jss::load_factor_fee_queue] == 256);
3679 state.isMember(jss::load_factor_fee_reference) &&
3680 state[jss::load_factor_fee_reference] == 256);
3687 using namespace jtx;
3690 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3691 auto const baseFee = env.
current()->fees().base.drops();
3695 stream[jss::streams].append(
"server");
3698 auto jv = wsc->invoke(
"subscribe", stream);
3702 Account a{
"a"}, b{
"b"}, c{
"c"}, d{
"d"}, e{
"e"}, f{
"f"}, g{
"g"}, h{
"h"},
3710 using namespace std::chrono_literals;
3712 return jv[jss::type] ==
"serverStatus" &&
3713 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3714 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3715 jv.isMember(jss::load_factor_server) &&
3716 jv[jss::load_factor_server] == 256 &&
3717 jv.isMember(jss::load_factor_fee_escalation) &&
3718 jv[jss::load_factor_fee_escalation] == 256 &&
3719 jv.isMember(jss::load_factor_fee_queue) &&
3720 jv[jss::load_factor_fee_queue] == 256 &&
3721 jv.isMember(jss::load_factor_fee_reference) &&
3722 jv[jss::load_factor_fee_reference] == 256;
3726 return jv[jss::type] ==
"serverStatus" &&
3727 jv.isMember(jss::load_factor) &&
3728 jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3729 jv[jss::load_base] == 256 &&
3730 jv.isMember(jss::load_factor_server) &&
3731 jv[jss::load_factor_server] == 256 &&
3732 jv.isMember(jss::load_factor_fee_escalation) &&
3733 jv[jss::load_factor_fee_escalation] == 227555 &&
3734 jv.isMember(jss::load_factor_fee_queue) &&
3735 jv[jss::load_factor_fee_queue] == 256 &&
3736 jv.isMember(jss::load_factor_fee_reference) &&
3737 jv[jss::load_factor_fee_reference] == 256;
3744 return jv[jss::type] ==
"serverStatus" &&
3745 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3746 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3747 jv.isMember(jss::load_factor_server) &&
3748 jv[jss::load_factor_server] == 256 &&
3749 jv.isMember(jss::load_factor_fee_escalation) &&
3750 jv[jss::load_factor_fee_escalation] == 256 &&
3751 jv.isMember(jss::load_factor_fee_queue) &&
3752 jv[jss::load_factor_fee_queue] == 256 &&
3753 jv.isMember(jss::load_factor_fee_reference) &&
3754 jv[jss::load_factor_fee_reference] == 256;
3775 return jv[jss::type] ==
"serverStatus" &&
3776 jv.isMember(jss::load_factor) &&
3777 jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3778 jv[jss::load_base] == 256 &&
3779 jv.isMember(jss::load_factor_server) &&
3780 jv[jss::load_factor_server] == 256 &&
3781 jv.isMember(jss::load_factor_fee_escalation) &&
3782 jv[jss::load_factor_fee_escalation] == 200000 &&
3783 jv.isMember(jss::load_factor_fee_queue) &&
3784 jv[jss::load_factor_fee_queue] == 256 &&
3785 jv.isMember(jss::load_factor_fee_reference) &&
3786 jv[jss::load_factor_fee_reference] == 256;
3792 return jv[jss::type] ==
"serverStatus" &&
3793 jv.isMember(jss::load_factor) &&
3794 jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3795 jv[jss::load_base] == 256 &&
3796 jv.isMember(jss::load_factor_server) &&
3797 jv[jss::load_factor_server] == 256 &&
3798 jv.isMember(jss::load_factor_fee_escalation) &&
3799 jv[jss::load_factor_fee_escalation] == 184320 &&
3800 jv.isMember(jss::load_factor_fee_queue) &&
3801 jv[jss::load_factor_fee_queue] == 256 &&
3802 jv.isMember(jss::load_factor_fee_reference) &&
3803 jv[jss::load_factor_fee_reference] == 256;
3809 return jv[jss::type] ==
"serverStatus" &&
3810 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3811 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3812 jv.isMember(jss::load_factor_server) &&
3813 jv[jss::load_factor_server] == 256 &&
3814 jv.isMember(jss::load_factor_fee_escalation) &&
3815 jv[jss::load_factor_fee_escalation] == 256 &&
3816 jv.isMember(jss::load_factor_fee_queue) &&
3817 jv[jss::load_factor_fee_queue] == 256 &&
3818 jv.isMember(jss::load_factor_fee_reference) &&
3819 jv[jss::load_factor_fee_reference] == 256;
3823 return jv[jss::type] ==
"serverStatus";
3826 auto jv = wsc->invoke(
"unsubscribe", stream);
3833 using namespace jtx;
3836 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3837 auto const baseFee = env.
current()->fees().base.drops();
3838 auto alice =
Account(
"alice");
3842 env.
fund(
XRP(50000000), alice, bob);
3849 auto totalFactor = 0;
3852 numToClear.emplace(metrics.txCount + 1);
3853 for (
int i = 0; i < *numToClear; ++i)
3856 totalFactor += inLedger * inLedger;
3859 auto const den = (metrics.txPerLedger * metrics.txPerLedger);
3861 (metrics.medFeeLevel * totalFactor +
FeeLevel64{den - 1}) / den;
3872 testcase(
"straightfoward positive case");
3875 auto aliceSeq = env.
seq(alice);
3877 for (
int i = 0; i < 2; ++i)
3883 totalPaid += baseFee * 10;
3911 totalPaid += totalFee;
3912 totalFee = calcTotalFee(totalPaid);
3915 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3920 testcase(
"replace last tx with enough to clear queue");
3923 auto aliceSeq = env.
seq(alice);
3925 for (
int i = 0; i < 2; ++i)
3931 totalPaid += baseFee * 10;
3948 calcTotalFee(totalPaid, metrics.txCount);
3951 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3960 testcase(
"replace middle tx with enough to clear queue");
3964 auto aliceSeq = env.
seq(alice);
3965 for (
int i = 0; i < 5; ++i)
3976 uint64_t const totalFee = calcTotalFee(baseFee * 10 * 2, 3);
3979 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3982 auto const aliceQueue =
3986 for (
auto const& tx : aliceQueue)
3990 tx.feeLevel ==
FeeLevel64{baseFeeLevel.fee() * 10});
3999 testcase(
"clear queue failure (load)");
4003 auto aliceSeq = env.
seq(alice);
4005 for (
int i = 0; i < 2; ++i)
4011 totalPaid += baseFee * 20;
4013 for (
int i = 0; i < 2; ++i)
4019 totalPaid += baseFee * 2.2;
4030 feeTrack.setRemoteFee(origFee * 5);
4043 feeTrack.setRemoteFee(origFee);
4062 using namespace jtx;
4063 using namespace std::chrono_literals;
4070 {{
"minimum_txn_in_ledger_standalone",
"3"},
4071 {
"normal_consensus_increase_percent",
"25"},
4072 {
"slow_consensus_decrease_percent",
"50"},
4073 {
"target_txn_in_ledger",
"10"},
4074 {
"maximum_txn_per_account",
"200"}}));
4075 auto alice =
Account(
"alice");
4078 env.
fund(
XRP(50000000), alice);
4082 auto seqAlice = env.
seq(alice);
4084 for (
int i = 0; i < txCount; ++i)
4128 env.
close(env.
now() + 5s, 10000ms);
4133 env.
close(env.
now() + 5s, 10000ms);
4138 env.
close(env.
now() + 5s, 10000ms);
4145 env.
close(env.
now() + 5s, 10000ms);
4156 {{
"minimum_txn_in_ledger_standalone",
"3"},
4157 {
"normal_consensus_increase_percent",
"150"},
4158 {
"slow_consensus_decrease_percent",
"150"},
4159 {
"target_txn_in_ledger",
"10"},
4160 {
"maximum_txn_per_account",
"200"}}));
4161 auto alice =
Account(
"alice");
4164 env.
fund(
XRP(50000000), alice);
4168 auto seqAlice = env.
seq(alice);
4170 for (
int i = 0; i < txCount; ++i)
4189 env.
close(env.
now() + 5s, 10000ms);
4210 testcase(
"Sequence in queue and open ledger");
4211 using namespace jtx;
4213 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4215 auto const alice =
Account(
"alice");
4229 auto const aliceSeq = env.
seq(alice);
4275 testcase(
"Ticket in queue and open ledger");
4276 using namespace jtx;
4278 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4280 auto alice =
Account(
"alice");
4309 auto const tx = env.
jt(
4372 using namespace jtx;
4382 {{
"minimum_txn_in_ledger_standalone",
"1"},
4383 {
"ledgers_in_queue",
"5"},
4384 {
"maximum_txn_per_account",
"10"}},
4385 {{
"account_reserve",
"1000"}, {
"owner_reserve",
"50"}});
4387 auto& votingSection = cfg->section(
"voting");
4393 "reference_fee",
std::to_string(cfg->FEES.reference_fee.drops()));
4395 Env env(*
this, std::move(cfg));
4413 for (i = 0; i <= 257; ++i)
4421 *
this, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger);
4426 using namespace std::chrono_literals;
4427 auto closeDuration = 80min;
4428 for (i = 0; i <= 255; ++i)
4430 env.
close(closeDuration);
4433 auto const baseFee = env.
current()->fees().base.drops();
4440 5 * expectedPerLedger,
4441 expectedPerLedger + 1,
4445 auto seqAlice = env.
seq(alice);
4446 auto seqBob = env.
seq(bob);
4447 auto seqCarol = env.
seq(carol);
4448 auto seqDaria = env.
seq(daria);
4449 auto seqEllie = env.
seq(ellie);
4450 auto seqFiona = env.
seq(fiona);
4453 int txFee{
static_cast<int>(baseFee * 9)};
4454 auto prepareFee = [&](
uint64_t multiplier) {
4455 return fee(txFee - multiplier * baseFee / 10);
4459 for (
int i = 0; i < 10; ++i)
4463 prepareFee(++multiplier),
4467 prepareFee(++multiplier),
4471 prepareFee(++multiplier),
4475 prepareFee(++multiplier),
4479 prepareFee(++multiplier),
4483 prepareFee(++multiplier),
4491 5 * expectedPerLedger,
4492 expectedPerLedger + 1,
4506 env.
close(closeDuration);
4507 auto expectedInLedger = expectedInQueue;
4509 (expectedInQueue > expectedPerLedger + 2
4510 ? expectedInQueue - (expectedPerLedger + 2)
4512 expectedInLedger -= expectedInQueue;
4513 ++expectedPerLedger;
4518 5 * expectedPerLedger,
4522 auto const expectedPerAccount = expectedInQueue / 6;
4523 auto const expectedRemainder = expectedInQueue % 6;
4527 seqBob - expectedPerAccount -
4528 (expectedRemainder > 4 ? 1 : 0));
4531 seqCarol - expectedPerAccount -
4532 (expectedRemainder > 3 ? 1 : 0));
4535 seqDaria - expectedPerAccount -
4536 (expectedRemainder > 2 ? 1 : 0));
4539 seqEllie - expectedPerAccount -
4540 (expectedRemainder > 1 ? 1 : 0));
4543 seqFiona - expectedPerAccount -
4544 (expectedRemainder > 0 ? 1 : 0));
4546 }
while (expectedInQueue > 0);
4559 testcase(
"Queue full drop penalty");
4560 using namespace jtx;
4574 {{
"minimum_txn_in_ledger_standalone",
"5"},
4575 {
"ledgers_in_queue",
"5"},
4576 {
"maximum_txn_per_account",
"30"},
4577 {
"minimum_queue_size",
"50"}});
4579 Env env(*
this, std::move(cfg));
4580 auto const baseFee = env.current()->fees().base.drops();
4585 int const medFee = baseFee * 10;
4586 int const hiFee = baseFee * 100;
4590 env.fund(
XRP(10000),
noripple(alice, bob, carol, daria, ellie, fiona));
4606 auto seqAlice = env.seq(alice);
4607 auto const seqSaveAlice = seqAlice;
4608 int feeDrops = baseFee * 4;
4612 json(R
"({"LastLedgerSequence": 7})"),
4622 json(R
"({"LastLedgerSequence": 7})"),
4635 auto seqCarol = env.seq(carol);
4636 auto seqDaria = env.seq(daria);
4637 auto seqEllie = env.seq(ellie);
4638 auto seqFiona = env.seq(fiona);
4640 for (
int i = 0; i < 7; ++i)
4654 for (
int i = 0; i < 3; ++i)
4667 for (
int i = 0; i < 3; ++i)
4688 for (
int i = 0; i < 4; ++i)
4707 for (
int i = 0; i < 30; ++i)
4708 env.app().getFeeTrack().raiseLocalFee();
4718 while (env.app().getFeeTrack().lowerLocalFee())
4744 seqAlice = seqSaveAlice;
4797 using namespace jtx;
4801 auto USD = gw[
"USD"];
4804 {{
"minimum_txn_in_ledger_standalone",
"5"},
4805 {
"ledgers_in_queue",
"5"},
4806 {
"maximum_txn_per_account",
"30"},
4807 {
"minimum_queue_size",
"50"}});
4809 Env env(*
this, std::move(cfg));
4821 auto const aliceSeq = env.seq(alice);
4824 env(
offer(alice, USD(1000),
XRP(1001)),
4830 env(
offer(alice, USD(1000),
XRP(1002)),
4832 json(jss::OfferSequence, aliceSeq),
4848 auto const aliceTkt = env.seq(alice);
4856 auto const aliceSeq = env.seq(alice);
4857 env(
offer(alice, USD(1000),
XRP(1000)),
4861 env(
offer(alice, USD(1000),
XRP(1001)),
4871 env(
offer(alice, USD(1000),
XRP(1002)),
4873 json(jss::OfferSequence, aliceTkt + 4),
4883 env(
offer(alice, USD(1000),
XRP(1001)),
4888 env(
offer(alice, USD(1000),
XRP(1002)),
4890 json(jss::OfferSequence, aliceSeq),
4910 using namespace jtx;
4918 {{
"minimum_txn_in_ledger_standalone",
"3"}},
4919 {{
"reference_fee",
"0"},
4920 {
"account_reserve",
"0"},
4921 {
"owner_reserve",
"0"}}));
4926 auto const initQueueMax =
initFee(env, 3, 2, 0, 0, 0);
4931 auto const fee = env.
rpc(
"fee");
4939 auto const& levels =
result[jss::levels];
4941 levels.isMember(jss::median_level) &&
4942 levels[jss::median_level] ==
"128000");
4944 levels.isMember(jss::minimum_level) &&
4945 levels[jss::minimum_level] ==
"256");
4947 levels.isMember(jss::open_ledger_level) &&
4948 levels[jss::open_ledger_level] ==
"256");
4950 levels.isMember(jss::reference_level) &&
4951 levels[jss::reference_level] ==
"256");
4955 drops.isMember(jss::base_fee) &&
4956 drops[jss::base_fee] ==
"0");
4958 drops.isMember(jss::median_fee) &&
4959 drops[jss::median_fee] ==
"0");
4961 drops.isMember(jss::minimum_fee) &&
4962 drops[jss::minimum_fee] ==
"0");
4964 drops.isMember(jss::open_ledger_fee) &&
4965 drops[jss::open_ledger_fee] ==
"0");
4989 auto aliceSeq = env.
seq(alice);
4999 auto const fee = env.
rpc(
"fee");
5007 auto const& levels =
result[jss::levels];
5009 levels.isMember(jss::median_level) &&
5010 levels[jss::median_level] ==
"128000");
5012 levels.isMember(jss::minimum_level) &&
5013 levels[jss::minimum_level] ==
"256");
5015 levels.isMember(jss::open_ledger_level) &&
5016 levels[jss::open_ledger_level] ==
"355555");
5018 levels.isMember(jss::reference_level) &&
5019 levels[jss::reference_level] ==
"256");
5023 drops.isMember(jss::base_fee) &&
5024 drops[jss::base_fee] ==
"0");
5026 drops.isMember(jss::median_fee) &&
5027 drops[jss::median_fee] ==
"0");
5029 drops.isMember(jss::minimum_fee) &&
5030 drops[jss::minimum_fee] ==
"0");
5032 drops.isMember(jss::open_ledger_fee) &&
5033 drops[jss::open_ledger_fee] ==
"1389");
5095BEAST_DEFINE_TESTSUITE_PRIO(TxQPosNegFlows, app,
ripple, 1);
5096BEAST_DEFINE_TESTSUITE_PRIO(TxQMetaInfo, app,
ripple, 1);
A generic endpoint for log messages.
testcase_t testcase
Memberspace for declaring test cases.
void fail(String const &reason, char const *file, int line)
Record a failure.
virtual Config & config()=0
virtual LoadFeeTrack & getFeeTrack()=0
virtual OpenLedger & openLedger()=0
void setRemoteFee(std::uint32_t f)
std::uint32_t getRemoteFee() const
std::uint32_t getLoadFactor() const
bool modify(modify_type const &f)
Modify the open ledger.
Writable ledger view that accumulates state and tx changes.
A type that represents either a sequence value or a ticket value.
static constexpr SeqProxy sequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
std::vector< TxDetails > getTxs() const
Returns information about all transactions currently in the queue.
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
std::vector< TxDetails > getAccountTxs(AccountID const &account) const
Returns information about the transactions currently in the queue for the account.
constexpr value_type drops() const
Returns the number of drops.
constexpr value_type fee() const
Returns the number of drops.
BEAST_EXPECT(queue_data[jss::highest_sequence]==data[jss::Sequence].asUInt()+queue_data[jss::txn_count].asUInt() - 1)
auto calcMedFeeLevel(FeeLevel64 const feeLevel)
void testSignAndSubmitSequence()
void testQueueFullDropPenalty()
BEAST_EXPECT(queue_data[jss::txn_count]==0)
void testFullQueueGapFill()
void testServerSubscribe()
auto const prevLedgerWithQueue
BEAST_EXPECT(queue_data.isObject())
BEAST_EXPECT(!queue_data.isMember(jss::transactions))
static std::unique_ptr< Config > makeConfig(std::map< std::string, std::string > extraTxQ={}, std::map< std::string, std::string > extraVoting={})
void testZeroReferenceFee()
envs(noop(alice), fee(baseFee *10), seq(none), ter(terQUEUED))(submitParams)
void testInFlightBalance()
void testInLedgerTicket()
auto calcMedFeeLevel(FeeLevel64 const feeLevel1, FeeLevel64 const feeLevel2)
void testCancelQueuedOffers()
BEAST_EXPECT(info.isMember(jss::result) &&RPC::contains_error(info[jss::result]))
void testReexecutePreflight()
BEAST_EXPECT(queue_data[jss::auth_change_queued]==true)
void testExpirationReplacement()
envs(noop(alice), fee(baseFee *10), seq(none), ter(telCAN_NOT_QUEUE_BLOCKED))(submitParams)
BEAST_EXPECT(queue_data.isMember(jss::transactions))
static constexpr FeeLevel64 baseFeeLevel
BEAST_EXPECT(queue_data[jss::max_spend_drops_total]==std::to_string(baseFee *10))
BEAST_EXPECT(info.isMember(jss::result) &&info[jss::result].isMember(jss::account_data))
BEAST_EXPECT(queue_data[jss::txn_count]==4)
BEAST_EXPECT(queue_data[jss::lowest_sequence]==data[jss::Sequence])
BEAST_EXPECT(env.current() ->info().seq > 3)
BEAST_EXPECT(result.isMember(jss::queue_data))
envs(noop(alice), seq(none))(submitParams)
BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data))
void fillQueue(jtx::Env &env, jtx::Account const &account)
BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total))
BEAST_EXPECT(queue_data[jss::auth_change_queued]==false)
static constexpr FeeLevel64 minEscalationFeeLevel
BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total))
BEAST_EXPECT(queue_data[jss::auth_change_queued].asBool())
std::size_t initFee(jtx::Env &env, std::size_t expectedPerLedger, std::size_t ledgersInQueue, std::uint32_t base, std::uint32_t reserve, std::uint32_t increment)
BEAST_EXPECT(queued.size()==queue_data[jss::txn_count])
auto openLedgerCost(jtx::Env &env)
auto txFeeLevelByAccount(jtx::Env &env, jtx::Account const &account)
void testFailInPreclaim()
BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued))
BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence))
void testClearQueuedAccountTxs()
envs(fset(alice, asfAccountTxnID), fee(baseFee *10), seq(none), json(jss::LastLedgerSequence, 10), ter(terQUEUED))(submitParams)
BEAST_EXPECT(queue_data[jss::max_spend_drops_total]==std::to_string(baseFee *40))
BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence))
BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence))
void run() override
Runs the suite.
BEAST_EXPECT(queue_data.isMember(jss::highest_sequence))
void testAcctInQueueButEmpty()
BEAST_EXPECT(queue_data.isMember(jss::txn_count))
BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued))
void testBlockersTicket()
BEAST_EXPECT(queue_data[jss::txn_count]==1)
void testUnexpectedBalanceChange()
void testMultiTxnPerAccount()
Immutable cryptographic account descriptor.
static Account const master
The master account.
A transaction testing environment wrapper.
A transaction testing environment.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
void require(Args const &... args)
Check a set of requirements.
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.
void postconditions(JTx const &jt, ParsedResult const &parsed, Json::Value const &jr=Json::Value())
Check expected postconditions of JTx submission.
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
NetClock::time_point now()
Returns the current network time.
beast::Journal const journal
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)
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
void memoize(Account const &account)
Associate AccountID with account.
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Match the number of items in the account's owner directory.
Check a set of conditions.
Sets the SendMax on a JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
Set a ticket sequence on a JTx.
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
std::size_t numUpVotedAmendments()
Amendments that this server will vote for by default.
Json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
owner_count< ltRIPPLE_STATE > lines
Match the number of trust lines in the account's owner directory.
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Json::Value signers(Account const &account, std::uint32_t quorum, std::vector< signer > const &v)
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
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
void checkMetrics(Suite &test, jtx::Env &env, std::size_t expectedCount, std::optional< std::size_t > expectedMaxCount, std::size_t expectedInLedger, std::size_t expectedPerLedger, std::uint64_t expectedMinFeeLevel=baseFeeLevel.fee(), std::uint64_t expectedMedFeeLevel=minEscalationFeeLevel.fee(), source_location const location=source_location::current())
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
owner_count< ltTICKET > tickets
Match the number of tickets on the account.
XRP_t const XRP
Converts to XRP Issue or STAmount.
Json::Value offer_cancel(Account const &account, std::uint32_t offerSeq)
Cancel an offer.
static XRPAmount reserve(jtx::Env &env, std::uint32_t count)
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpc_version, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
PreflightResult preflight(Application &app, Rules const &rules, STTx const &tx, ApplyFlags flags, beast::Journal j)
Gate a transaction based on static information.
@ telCAN_NOT_QUEUE_BLOCKED
@ telCAN_NOT_QUEUE_BALANCE
@ telCAN_NOT_QUEUE_BLOCKS
constexpr std::uint32_t asfAccountTxnID
FeeLevel64 toFeeLevel(XRPAmount const &drops, XRPAmount const &baseFee)
ApplyResult apply(Application &app, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
majorityAmendments_t getMajorityAmendments(ReadView const &view)
XRPAmount toDrops(FeeLevel< T > const &level, XRPAmount baseFee)
std::size_t txInLedger
Number of transactions currently in the open ledger.
Used by parseResult() and postConditions()
Set the sequence number on a JTx.