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();
115 for (
auto i = env.
current()->seq(); i <= 257; ++i)
122 auto const flagMaxQueue = ledgersInQueue * flagPerLedger;
123 checkMetrics(*
this, env, 0, flagMaxQueue, 0, flagPerLedger);
132 using namespace std::chrono_literals;
134 checkMetrics(*
this, env, 0, flagMaxQueue, 0, expectedPerLedger);
135 auto const fees = env.
current()->fees();
151 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
155 auto charlie =
Account(
"charlie");
164 auto const baseFee = env.
current()->fees().base.drops();
260 constexpr auto largeFeeMultiplier = 700;
261 auto const largeFee = baseFee * largeFeeMultiplier;
265 env(
noop(hank),
fee(largeFee));
266 env(
noop(gwen),
fee(largeFee));
267 env(
noop(fred),
fee(largeFee));
268 env(
noop(elmo),
fee(largeFee));
344 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
358 metrics.txPerLedger + 1,
359 metrics.txPerLedger);
368 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
373 auto const baseFee = env.
current()->fees().base.drops();
426 checkMetrics(*
this, env, 8, 8, 5, 4, expectedMinFeeLevel);
589 fee(baseFee * 2.1 * 1.25 - 1),
593 fee(baseFee * 2.1 * 1.25 + 1),
599 fee(baseFee * 2.2 * 1.25 - 1),
603 fee(baseFee * 2.2 * 1.25 + 1),
627 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
631 auto USD = gw[
"USD"];
664 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
668 auto charlie =
Account(
"charlie");
671 auto const baseFee = env.
current()->fees().base.drops();
720 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
724 auto charlie =
Account(
"charlie");
727 auto felicia =
Account(
"felicia");
730 auto const baseFee = env.
current()->fees().base.drops();
751 json(R
"({"LastLedgerSequence":7})"),
756 constexpr auto largeFeeMultiplier = 700;
757 auto const largeFee = baseFee * largeFeeMultiplier;
772 aliceStat.begin()->lastValid &&
773 *aliceStat.begin()->lastValid == 8);
774 BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker());
776 auto bobStat = txQ.getAccountTxs(bob.id());
779 bobStat.begin()->feeLevel ==
780 FeeLevel64{baseFeeLevel.fee() * largeFeeMultiplier});
782 BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker());
806 constexpr auto anotherLargeFeeMultiplier = 800;
807 auto const anotherLargeFee = baseFee * anotherLargeFeeMultiplier;
846 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
853 auto const baseFee = env.
current()->fees().base.drops();
883 constexpr auto aliceFeeMultiplier = 3;
884 auto feeAlice = baseFee * aliceFeeMultiplier;
885 auto seqAlice = env.
seq(alice);
886 for (
int i = 0; i < 4; ++i)
889 feeAlice = (feeAlice + 1) * 125 / 100;
895 auto const seqBob = env.
seq(bob);
900 auto feeCarol = feeAlice;
901 auto seqCarol = env.
seq(carol);
902 for (
int i = 0; i < 4; ++i)
905 feeCarol = (feeCarol + 1) * 125 / 100;
973 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
996 auto const& jt = env.
jt(
noop(alice));
1021 using namespace jtx;
1027 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1028 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1030 auto alice =
Account(
"alice");
1032 auto charlie =
Account(
"charlie");
1033 auto daria =
Account(
"daria");
1040 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1051 auto aliceSeq = env.
seq(alice);
1052 auto bobSeq = env.
seq(bob);
1053 auto charlieSeq = env.
seq(charlie);
1098 aliceSeq = env.
seq(alice);
1099 auto lastLedgerSeq = env.
current()->info().seq + 2;
1100 for (
auto i = 0; i < 7; i++)
1104 json(jss::LastLedgerSequence, lastLedgerSeq + i),
1114 auto const& baseFee = env.
current()->fees().base;
1115 auto seq = env.
seq(alice);
1117 for (
auto const& tx : aliceStat)
1124 (tx.consequences.fee() ==
drops(aliceFee) &&
1125 tx.consequences.potentialSpend() ==
drops(0) &&
1126 !tx.consequences.isBlocker()) ||
1127 tx.seqProxy.value() == env.
seq(alice) + 6);
1137 json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1170 aliceSeq = env.
seq(alice) + 2;
1189 aliceSeq = env.
seq(alice) + 1;
1196 env.
le(alice)->getFieldAmount(sfBalance).xrp().drops() - (62);
1239 bobSeq = env.
seq(bob);
1241 for (
int i = 0; i < 10; ++i)
1256 env.
le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10 - 1);
1270 env.
le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10);
1289 using namespace jtx;
1293 auto cfg =
makeConfig({{
"minimum_txn_in_ledger_standalone",
"4"}});
1294 cfg->FEES.reference_fee = 10;
1295 Env env(*
this, std::move(cfg));
1297 auto alice =
Account(
"alice");
1299 auto charlie =
Account(
"charlie");
1300 auto daria =
Account(
"daria");
1336 auto aliceSeq = env.
seq(alice);
1337 auto bobSeq = env.
seq(bob);
1338 auto charlieSeq = env.
seq(charlie);
1339 auto dariaSeq = env.
seq(daria);
1340 auto elmoSeq = env.
seq(elmo);
1341 auto fredSeq = env.
seq(fred);
1342 auto gwenSeq = env.
seq(gwen);
1343 auto hankSeq = env.
seq(hank);
1385 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1386 gwenSeq + hankSeq + 6 ==
1387 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1388 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1390 using namespace std::string_literals;
1392 aliceSeq == env.
seq(alice),
1396 bobSeq + 1 == env.
seq(bob),
1400 charlieSeq + 2 == env.
seq(charlie),
1404 dariaSeq + 1 == env.
seq(daria),
1408 elmoSeq + 1 == env.
seq(elmo),
1412 fredSeq == env.
seq(fred),
1416 gwenSeq == env.
seq(gwen),
1420 hankSeq + 1 == env.
seq(hank),
1435 auto getTxsQueued = [&]() {
1438 for (
auto const& tx : txs)
1440 ++
result[tx.txn->at(sfAccount)];
1444 auto qTxCount1 = getTxsQueued();
1449 seq(aliceSeq + qTxCount1[alice.id()]++),
1454 seq(charlieSeq + qTxCount1[charlie.id()]++),
1458 seq(dariaSeq + qTxCount1[daria.id()]++),
1473 seq(aliceSeq + qTxCount1[alice.id()]++),
1485 auto qTxCount2 = getTxsQueued();
1491 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1492 gwenSeq + hankSeq + 7 ==
1493 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1494 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1497 aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] ==
1502 bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.
seq(bob),
1506 charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] ==
1511 dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] ==
1516 elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] ==
1521 fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] ==
1526 gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] ==
1531 hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] ==
1540 using namespace jtx;
1543 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"1"}}));
1545 auto alice =
Account(
"alice");
1559 json(R
"({"AccountTxnID": "0"})"),
1577 using namespace jtx;
1578 using namespace std::string_literals;
1585 {{
"minimum_txn_in_ledger_standalone",
"2"},
1586 {
"minimum_txn_in_ledger",
"5"},
1587 {
"target_txn_in_ledger",
"4"},
1588 {
"maximum_txn_in_ledger",
"5"}}));
1589 auto const baseFee = env.
current()->fees().base.drops();
1591 auto alice =
Account(
"alice");
1599 for (
int i = 0; i < 10; ++i)
1607 double const feeMultiplier =
1608 static_cast<double>(cost.drops()) / baseFee;
1630 {{
"minimum_txn_in_ledger",
"200"},
1631 {
"minimum_txn_in_ledger_standalone",
"200"},
1632 {
"target_txn_in_ledger",
"4"},
1633 {
"maximum_txn_in_ledger",
"5"}}));
1641 "The minimum number of low-fee transactions allowed "
1642 "per ledger (minimum_txn_in_ledger) exceeds "
1643 "the maximum number of low-fee transactions allowed per "
1644 "ledger (maximum_txn_in_ledger)."s);
1651 {{
"minimum_txn_in_ledger",
"200"},
1652 {
"minimum_txn_in_ledger_standalone",
"2"},
1653 {
"target_txn_in_ledger",
"4"},
1654 {
"maximum_txn_in_ledger",
"5"}}));
1662 "The minimum number of low-fee transactions allowed "
1663 "per ledger (minimum_txn_in_ledger) exceeds "
1664 "the maximum number of low-fee transactions allowed per "
1665 "ledger (maximum_txn_in_ledger)."s);
1672 {{
"minimum_txn_in_ledger",
"2"},
1673 {
"minimum_txn_in_ledger_standalone",
"200"},
1674 {
"target_txn_in_ledger",
"4"},
1675 {
"maximum_txn_in_ledger",
"5"}}));
1683 "The minimum number of low-fee transactions allowed "
1684 "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1685 "the maximum number of low-fee transactions allowed per "
1686 "ledger (maximum_txn_in_ledger)."s);
1693 using namespace jtx;
1694 testcase(
"unexpected balance change");
1699 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1700 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1702 auto alice =
Account(
"alice");
1708 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1715 auto USD = bob[
"USD"];
1729 auto aliceSeq = env.
seq(alice);
1773 for (
int i = 0; i < 9; ++i)
1788 using namespace jtx;
1791 auto alice =
Account(
"alice");
1793 auto charlie =
Account(
"charlie");
1794 auto daria =
Account(
"daria");
1798 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1799 auto const baseFee = env.
current()->fees().base.drops();
1813 env(
regkey(alice, charlie));
1817 auto const aliceSeq = env.
seq(alice);
1833 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1852 auto const aliceSeq = env.
seq(alice);
1870 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1896 auto const aliceSeq = env.
seq(alice);
1920 using namespace jtx;
1923 auto alice =
Account(
"alice");
1925 auto charlie =
Account(
"charlie");
1926 auto daria =
Account(
"daria");
1930 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1931 auto const baseFee = env.
current()->fees().base.drops();
1948 env(
regkey(alice, charlie));
1952 auto const aliceSeq = env.
seq(alice);
1968 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1972 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1996 auto const aliceSeq = env.
seq(alice);
2026 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
2086 using namespace jtx;
2087 testcase(
"In-flight balance checks");
2092 {{
"minimum_txn_in_ledger_standalone",
"3"}},
2093 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
2095 auto alice =
Account(
"alice");
2096 auto charlie =
Account(
"charlie");
2107 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
2114 checkMetrics(*
this, env, 0, initQueueMax, limit + 1, limit);
2116 auto USD = gw[
"USD"];
2117 auto BUX = gw[
"BUX"];
2121 auto aliceSeq = env.
seq(alice);
2122 auto aliceBal = env.
balance(alice);
2129 checkMetrics(*
this, env, 1, initQueueMax, limit + 1, limit);
2134 checkMetrics(*
this, env, 2, initQueueMax, limit + 1, limit);
2150 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2151 aliceSeq = env.
seq(alice);
2152 aliceBal = env.
balance(alice);
2158 checkMetrics(*
this, env, 1, limit * 2, limit + 1, limit);
2163 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2171 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2187 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2188 aliceSeq = env.
seq(alice);
2189 aliceBal = env.
balance(alice);
2196 checkMetrics(*
this, env, 1, limit * 2, limit + 1, limit);
2204 checkMetrics(*
this, env, 1, limit * 2, limit + 1, limit);
2220 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2221 aliceSeq = env.
seq(alice);
2222 aliceBal = env.
balance(alice);
2230 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2246 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2248 aliceSeq = env.
seq(alice);
2249 aliceBal = env.
balance(alice);
2259 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2273 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2275 aliceSeq = env.
seq(alice);
2276 aliceBal = env.
balance(alice);
2284 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2296 auto const amount = USD(500000);
2297 env(
trust(alice, USD(50000000)));
2298 env(
trust(charlie, USD(50000000)));
2304 env(
pay(gw, alice, amount));
2311 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2313 aliceSeq = env.
seq(alice);
2314 aliceBal = env.
balance(alice);
2315 auto aliceUSD = env.
balance(alice, USD);
2319 env(
pay(alice, charlie, amount),
queued);
2324 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2342 env(
offer(gw,
XRP(500000), USD(50000)));
2348 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2350 aliceSeq = env.
seq(alice);
2351 aliceBal = env.
balance(alice);
2352 auto charlieUSD = env.
balance(charlie, USD);
2364 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2375 balance(charlie, charlieUSD + USD(1000)),
2383 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2385 aliceSeq = env.
seq(alice);
2386 aliceBal = env.
balance(alice);
2387 charlieUSD = env.
balance(charlie, USD);
2398 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2409 balance(charlie, charlieUSD + USD(500)),
2419 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2421 aliceSeq = env.
seq(alice);
2422 aliceBal = env.
balance(alice);
2429 checkMetrics(*
this, env, 1, limit * 2, limit + 1, limit);
2440 using namespace jtx;
2445 auto const alice =
Account(
"alice");
2464 auto USD = alice[
"USD"];
2506 using namespace jtx;
2507 testcase(
"acct in queue but empty");
2509 auto alice =
Account(
"alice");
2511 auto charlie =
Account(
"charlie");
2515 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2516 auto const baseFee = env.
current()->fees().base.drops();
2544 env(
noop(bob),
fee(baseFee * 100));
2545 env(
noop(bob),
fee(baseFee * 100));
2546 env(
noop(bob),
fee(baseFee * 100));
2547 env(
noop(bob),
fee(baseFee * 100));
2548 env(
noop(bob),
fee(baseFee * 100));
2574 checkMetrics(*
this, env, 10, 10, 6, 5, expectedFeeLevel + 1);
2597 seq(charlieSeq - 1),
2601 seq(charlieSeq + 1),
2612 using namespace jtx;
2617 auto fee = env.
rpc(
"fee");
2624 result.isMember(jss::ledger_current_index) &&
2625 result[jss::ledger_current_index] == 3);
2637 auto const& levels =
result[jss::levels];
2653 result.isMember(jss::ledger_current_index) &&
2654 result[jss::ledger_current_index] == 4);
2665 auto const& levels =
result[jss::levels];
2687 using namespace jtx;
2688 testcase(
"expiration replacement");
2693 {{
"minimum_txn_in_ledger_standalone",
"1"},
2694 {
"ledgers_in_queue",
"10"},
2695 {
"maximum_txn_per_account",
"20"}}));
2697 auto const baseFee = env.
current()->fees().base.drops();
2700 auto const alice =
Account(
"alice");
2701 auto const bob =
Account(
"bob");
2706 auto const aliceSeq = env.
seq(alice);
2710 json(R
"({"LastLedgerSequence":5})"),
2714 json(R"({"LastLedgerSequence":5})"),
2718 json(R"({"LastLedgerSequence":10})"),
2722 json(R"({"LastLedgerSequence":11})"),
2725 auto const bobSeq = env.
seq(bob);
2729 for (
int i = 0; i < 3 + 4 + 5; ++i)
2787 using namespace jtx;
2788 testcase(
"full queue gap handling");
2791 {{
"minimum_txn_in_ledger_standalone",
"1"},
2792 {
"ledgers_in_queue",
"10"},
2793 {
"maximum_txn_per_account",
"11"}});
2794 cfg->FEES.reference_fee = 10;
2795 Env env(*
this, std::move(cfg));
2797 auto const baseFee = env.
current()->fees().base.drops();
2802 auto const alice =
Account(
"alice");
2803 auto const bob =
Account(
"bob");
2808 auto const aliceSeq = env.
seq(alice);
2815 fee(baseFee * 20 + 1),
2819 json(R
"({"LastLedgerSequence":11})"),
2823 json(R"({"LastLedgerSequence":11})"),
2827 json(R"({"LastLedgerSequence":11})"),
2831 json(R"({"LastLedgerSequence":11})"),
2835 json(R"({"LastLedgerSequence":11})"),
2839 json(R"({"LastLedgerSequence": 5})"),
2843 json(R"({"LastLedgerSequence": 5})"),
2847 json(R"({"LastLedgerSequence": 5})"),
2851 json(R"({"LastLedgerSequence":11})"),
2855 auto const bobSeq = env.
seq(bob);
2859 for (
int i = 0; i < 2 + 4 + 5; ++i)
2946 testcase(
"Autofilled sequence should account for TxQ");
2947 using namespace jtx;
2948 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"6"}}));
2949 auto const baseFee = env.
current()->fees().base.drops();
2953 auto const alice =
Account(
"alice");
2954 auto const bob =
Account(
"bob");
2955 env.
fund(
XRP(100000), alice, bob);
2961 auto const aliceSeq = env.
seq(alice);
2962 auto const lastLedgerSeq = env.
current()->info().seq + 2;
2965 for (
int i = 0; i < 5; ++i)
2972 json(jss::LastLedgerSequence, lastLedgerSeq),
2981 auto aliceStat = txQ.getAccountTxs(alice.id());
2984 for (
auto const& tx : aliceStat)
2988 tx.feeLevel ==
FeeLevel64{baseFeeLevel.fee() * 100});
2989 if (
seq.value() == aliceSeq + 2)
2992 tx.lastValid && *tx.lastValid == lastLedgerSeq);
3003 for (
int i = 0; i < 8; ++i)
3012 for (
int i = 0; i < 9; ++i)
3019 for (
int i = 0; i < 10; ++i)
3026 auto bobStat = txQ.getAccountTxs(bob.id());
3032 auto aliceStat = txQ.getAccountTxs(alice.id());
3033 auto seq = aliceSeq;
3035 for (
auto const& tx : aliceStat)
3038 if (
seq == aliceSeq + 2)
3043 tx.feeLevel ==
FeeLevel64{baseFeeLevel.fee() * 100});
3053 auto aliceStat = txQ.getAccountTxs(alice.id());
3054 auto seq = aliceSeq;
3056 for (
auto const& tx : aliceStat)
3069 auto bobStat = txQ.getAccountTxs(bob.id());
3073 auto aliceStat = txQ.getAccountTxs(alice.id());
3081 using namespace jtx;
3084 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3085 auto const baseFee = env.
current()->fees().base.drops();
3089 env.
fund(
XRP(1000000), alice);
3092 auto const withQueue =
3093 R
"({ "account": ")" + alice.human() + R"(", "queue": true })";
3096 R"(", "queue": true, "ledger_index": 3 })";
3103 info.isMember(jss::result) &&
3104 info[jss::result].isMember(jss::account_data));
3109 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3111 info.isMember(jss::result) &&
3112 info[jss::result].isMember(jss::account_data));
3131 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3133 info.isMember(jss::result) &&
3134 info[jss::result].isMember(jss::account_data));
3135 auto const&
result = info[jss::result];
3160 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3162 info.isMember(jss::result) &&
3163 info[jss::result].isMember(jss::account_data));
3164 auto const&
result = info[jss::result];
3177 data[jss::Sequence].asUInt() +
3190 auto const& item =
queued[i];
3193 item[jss::fee_level] ==
3203 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3218 json(jss::LastLedgerSequence, 10),
3223 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3225 info.isMember(jss::result) &&
3226 info[jss::result].isMember(jss::account_data));
3227 auto const&
result = info[jss::result];
3228 auto const&
data =
result[jss::account_data];
3240 data[jss::Sequence].asUInt() +
3253 auto const& item =
queued[i];
3256 item[jss::fee_level] ==
3265 if (i ==
queued.size() - 1)
3273 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3287 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3289 info.isMember(jss::result) &&
3290 info[jss::result].isMember(jss::account_data));
3291 auto const&
result = info[jss::result];
3292 auto const&
data =
result[jss::account_data];
3304 data[jss::Sequence].asUInt() +
3317 auto const& item =
queued[i];
3320 item[jss::fee_level] ==
3323 if (i ==
queued.size() - 1)
3330 item[jss::max_spend_drops] ==
3344 item[jss::max_spend_drops] ==
3357 info.isMember(jss::result) &&
3367 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3369 info.isMember(jss::result) &&
3370 info[jss::result].isMember(jss::account_data));
3371 auto const&
result = info[jss::result];
3388 using namespace jtx;
3391 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3392 auto const baseFee = env.
current()->fees().base.drops();
3396 env.
fund(
XRP(1000000), alice);
3400 auto const server_info = env.
rpc(
"server_info");
3402 server_info.isMember(jss::result) &&
3403 server_info[jss::result].isMember(jss::info));
3404 auto const& info = server_info[jss::result][jss::info];
3406 info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
3410 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3413 auto const server_state = env.
rpc(
"server_state");
3414 auto const& state = server_state[jss::result][jss::state];
3416 state.isMember(jss::load_factor) &&
3417 state[jss::load_factor] == 256);
3419 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3421 state.isMember(jss::load_factor_server) &&
3422 state[jss::load_factor_server] == 256);
3424 state.isMember(jss::load_factor_fee_escalation) &&
3425 state[jss::load_factor_fee_escalation] == 256);
3427 state.isMember(jss::load_factor_fee_queue) &&
3428 state[jss::load_factor_fee_queue] == 256);
3430 state.isMember(jss::load_factor_fee_reference) &&
3431 state[jss::load_factor_fee_reference] == 256);
3439 auto aliceSeq = env.
seq(alice);
3441 for (
auto i = 0; i < 4; ++i)
3450 auto const server_info = env.
rpc(
"server_info");
3452 server_info.isMember(jss::result) &&
3453 server_info[jss::result].isMember(jss::info));
3454 auto const& info = server_info[jss::result][jss::info];
3457 info.isMember(jss::load_factor) &&
3458 info[jss::load_factor] > 888.88 &&
3459 info[jss::load_factor] < 888.89);
3461 info.isMember(jss::load_factor_server) &&
3462 info[jss::load_factor_server] == 1);
3466 info.isMember(jss::load_factor_fee_escalation) &&
3467 info[jss::load_factor_fee_escalation] > 888.88 &&
3468 info[jss::load_factor_fee_escalation] < 888.89);
3471 auto const server_state = env.
rpc(
"server_state");
3472 auto const& state = server_state[jss::result][jss::state];
3474 state.isMember(jss::load_factor) &&
3475 state[jss::load_factor] == 227555);
3477 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3479 state.isMember(jss::load_factor_server) &&
3480 state[jss::load_factor_server] == 256);
3482 state.isMember(jss::load_factor_fee_escalation) &&
3483 state[jss::load_factor_fee_escalation] == 227555);
3485 state.isMember(jss::load_factor_fee_queue) &&
3486 state[jss::load_factor_fee_queue] == 256);
3488 state.isMember(jss::load_factor_fee_reference) &&
3489 state[jss::load_factor_fee_reference] == 256);
3495 auto const server_info = env.
rpc(
"server_info");
3497 server_info.isMember(jss::result) &&
3498 server_info[jss::result].isMember(jss::info));
3499 auto const& info = server_info[jss::result][jss::info];
3502 info.isMember(jss::load_factor) &&
3503 info[jss::load_factor] == 1000);
3507 info.isMember(jss::load_factor_net) &&
3508 info[jss::load_factor_net] == 1000);
3510 info.isMember(jss::load_factor_fee_escalation) &&
3511 info[jss::load_factor_fee_escalation] > 888.88 &&
3512 info[jss::load_factor_fee_escalation] < 888.89);
3515 auto const server_state = env.
rpc(
"server_state");
3516 auto const& state = server_state[jss::result][jss::state];
3518 state.isMember(jss::load_factor) &&
3519 state[jss::load_factor] == 256000);
3521 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3523 state.isMember(jss::load_factor_server) &&
3524 state[jss::load_factor_server] == 256000);
3526 state.isMember(jss::load_factor_fee_escalation) &&
3527 state[jss::load_factor_fee_escalation] == 227555);
3529 state.isMember(jss::load_factor_fee_queue) &&
3530 state[jss::load_factor_fee_queue] == 256);
3532 state.isMember(jss::load_factor_fee_reference) &&
3533 state[jss::load_factor_fee_reference] == 256);
3539 for (
int i = 0; i < 5; ++i)
3544 auto const server_info = env.
rpc(
"server_info");
3546 server_info.isMember(jss::result) &&
3547 server_info[jss::result].isMember(jss::info));
3548 auto const& info = server_info[jss::result][jss::info];
3551 info.isMember(jss::load_factor) &&
3552 info[jss::load_factor] > 888.88 &&
3553 info[jss::load_factor] < 888.89);
3558 info.isMember(jss::load_factor_server) &&
3559 info[jss::load_factor_server] > 1.245 &&
3560 info[jss::load_factor_server] < 2.4415);
3562 info.isMember(jss::load_factor_local) &&
3563 info[jss::load_factor_local] > 1.245 &&
3564 info[jss::load_factor_local] < 2.4415);
3567 info.isMember(jss::load_factor_fee_escalation) &&
3568 info[jss::load_factor_fee_escalation] > 888.88 &&
3569 info[jss::load_factor_fee_escalation] < 888.89);
3572 auto const server_state = env.
rpc(
"server_state");
3573 auto const& state = server_state[jss::result][jss::state];
3575 state.isMember(jss::load_factor) &&
3576 state[jss::load_factor] == 227555);
3578 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3583 state.isMember(jss::load_factor_server) &&
3584 state[jss::load_factor_server] >= 320 &&
3585 state[jss::load_factor_server] <= 625);
3587 state.isMember(jss::load_factor_fee_escalation) &&
3588 state[jss::load_factor_fee_escalation] == 227555);
3590 state.isMember(jss::load_factor_fee_queue) &&
3591 state[jss::load_factor_fee_queue] == 256);
3593 state.isMember(jss::load_factor_fee_reference) &&
3594 state[jss::load_factor_fee_reference] == 256);
3600 auto const server_info = env.
rpc(
"server_info");
3602 server_info.isMember(jss::result) &&
3603 server_info[jss::result].isMember(jss::info));
3604 auto const& info = server_info[jss::result][jss::info];
3611 info.isMember(jss::load_factor) &&
3612 info[jss::load_factor] > 1.245 &&
3613 info[jss::load_factor] < 2.4415);
3616 info.isMember(jss::load_factor_local) &&
3617 info[jss::load_factor_local] > 1.245 &&
3618 info[jss::load_factor_local] < 2.4415);
3620 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3623 auto const server_state = env.
rpc(
"server_state");
3624 auto const& state = server_state[jss::result][jss::state];
3626 state.isMember(jss::load_factor) &&
3627 state[jss::load_factor] >= 320 &&
3628 state[jss::load_factor] <= 625);
3630 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3635 state.isMember(jss::load_factor_server) &&
3636 state[jss::load_factor_server] >= 320 &&
3637 state[jss::load_factor_server] <= 625);
3639 state.isMember(jss::load_factor_fee_escalation) &&
3640 state[jss::load_factor_fee_escalation] == 256);
3642 state.isMember(jss::load_factor_fee_queue) &&
3643 state[jss::load_factor_fee_queue] == 256);
3645 state.isMember(jss::load_factor_fee_reference) &&
3646 state[jss::load_factor_fee_reference] == 256);
3653 using namespace jtx;
3656 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3657 auto const baseFee = env.
current()->fees().base.drops();
3661 stream[jss::streams].append(
"server");
3664 auto jv = wsc->invoke(
"subscribe", stream);
3668 Account a{
"a"}, b{
"b"}, c{
"c"}, d{
"d"}, e{
"e"}, f{
"f"}, g{
"g"}, h{
"h"},
3676 using namespace std::chrono_literals;
3678 return jv[jss::type] ==
"serverStatus" &&
3679 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3680 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3681 jv.isMember(jss::load_factor_server) &&
3682 jv[jss::load_factor_server] == 256 &&
3683 jv.isMember(jss::load_factor_fee_escalation) &&
3684 jv[jss::load_factor_fee_escalation] == 256 &&
3685 jv.isMember(jss::load_factor_fee_queue) &&
3686 jv[jss::load_factor_fee_queue] == 256 &&
3687 jv.isMember(jss::load_factor_fee_reference) &&
3688 jv[jss::load_factor_fee_reference] == 256;
3692 return jv[jss::type] ==
"serverStatus" &&
3693 jv.isMember(jss::load_factor) &&
3694 jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3695 jv[jss::load_base] == 256 &&
3696 jv.isMember(jss::load_factor_server) &&
3697 jv[jss::load_factor_server] == 256 &&
3698 jv.isMember(jss::load_factor_fee_escalation) &&
3699 jv[jss::load_factor_fee_escalation] == 227555 &&
3700 jv.isMember(jss::load_factor_fee_queue) &&
3701 jv[jss::load_factor_fee_queue] == 256 &&
3702 jv.isMember(jss::load_factor_fee_reference) &&
3703 jv[jss::load_factor_fee_reference] == 256;
3710 return jv[jss::type] ==
"serverStatus" &&
3711 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3712 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3713 jv.isMember(jss::load_factor_server) &&
3714 jv[jss::load_factor_server] == 256 &&
3715 jv.isMember(jss::load_factor_fee_escalation) &&
3716 jv[jss::load_factor_fee_escalation] == 256 &&
3717 jv.isMember(jss::load_factor_fee_queue) &&
3718 jv[jss::load_factor_fee_queue] == 256 &&
3719 jv.isMember(jss::load_factor_fee_reference) &&
3720 jv[jss::load_factor_fee_reference] == 256;
3741 return jv[jss::type] ==
"serverStatus" &&
3742 jv.isMember(jss::load_factor) &&
3743 jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3744 jv[jss::load_base] == 256 &&
3745 jv.isMember(jss::load_factor_server) &&
3746 jv[jss::load_factor_server] == 256 &&
3747 jv.isMember(jss::load_factor_fee_escalation) &&
3748 jv[jss::load_factor_fee_escalation] == 200000 &&
3749 jv.isMember(jss::load_factor_fee_queue) &&
3750 jv[jss::load_factor_fee_queue] == 256 &&
3751 jv.isMember(jss::load_factor_fee_reference) &&
3752 jv[jss::load_factor_fee_reference] == 256;
3758 return jv[jss::type] ==
"serverStatus" &&
3759 jv.isMember(jss::load_factor) &&
3760 jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3761 jv[jss::load_base] == 256 &&
3762 jv.isMember(jss::load_factor_server) &&
3763 jv[jss::load_factor_server] == 256 &&
3764 jv.isMember(jss::load_factor_fee_escalation) &&
3765 jv[jss::load_factor_fee_escalation] == 184320 &&
3766 jv.isMember(jss::load_factor_fee_queue) &&
3767 jv[jss::load_factor_fee_queue] == 256 &&
3768 jv.isMember(jss::load_factor_fee_reference) &&
3769 jv[jss::load_factor_fee_reference] == 256;
3775 return jv[jss::type] ==
"serverStatus" &&
3776 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3777 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3778 jv.isMember(jss::load_factor_server) &&
3779 jv[jss::load_factor_server] == 256 &&
3780 jv.isMember(jss::load_factor_fee_escalation) &&
3781 jv[jss::load_factor_fee_escalation] == 256 &&
3782 jv.isMember(jss::load_factor_fee_queue) &&
3783 jv[jss::load_factor_fee_queue] == 256 &&
3784 jv.isMember(jss::load_factor_fee_reference) &&
3785 jv[jss::load_factor_fee_reference] == 256;
3789 return jv[jss::type] ==
"serverStatus";
3792 auto jv = wsc->invoke(
"unsubscribe", stream);
3799 using namespace jtx;
3802 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3803 auto const baseFee = env.
current()->fees().base.drops();
3804 auto alice =
Account(
"alice");
3808 env.
fund(
XRP(50000000), alice, bob);
3815 auto totalFactor = 0;
3818 numToClear.emplace(metrics.txCount + 1);
3819 for (
int i = 0; i < *numToClear; ++i)
3822 totalFactor += inLedger * inLedger;
3825 auto const den = (metrics.txPerLedger * metrics.txPerLedger);
3827 (metrics.medFeeLevel * totalFactor +
FeeLevel64{den - 1}) / den;
3838 testcase(
"straightfoward positive case");
3841 auto aliceSeq = env.
seq(alice);
3843 for (
int i = 0; i < 2; ++i)
3849 totalPaid += baseFee * 10;
3877 totalPaid += totalFee;
3878 totalFee = calcTotalFee(totalPaid);
3881 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3886 testcase(
"replace last tx with enough to clear queue");
3889 auto aliceSeq = env.
seq(alice);
3891 for (
int i = 0; i < 2; ++i)
3897 totalPaid += baseFee * 10;
3914 calcTotalFee(totalPaid, metrics.txCount);
3917 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3926 testcase(
"replace middle tx with enough to clear queue");
3930 auto aliceSeq = env.
seq(alice);
3931 for (
int i = 0; i < 5; ++i)
3942 uint64_t const totalFee = calcTotalFee(baseFee * 10 * 2, 3);
3945 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3948 auto const aliceQueue =
3952 for (
auto const& tx : aliceQueue)
3956 tx.feeLevel ==
FeeLevel64{baseFeeLevel.fee() * 10});
3965 testcase(
"clear queue failure (load)");
3969 auto aliceSeq = env.
seq(alice);
3971 for (
int i = 0; i < 2; ++i)
3977 totalPaid += baseFee * 20;
3979 for (
int i = 0; i < 2; ++i)
3985 totalPaid += baseFee * 2.2;
3996 feeTrack.setRemoteFee(origFee * 5);
4009 feeTrack.setRemoteFee(origFee);
4028 using namespace jtx;
4029 using namespace std::chrono_literals;
4036 {{
"minimum_txn_in_ledger_standalone",
"3"},
4037 {
"normal_consensus_increase_percent",
"25"},
4038 {
"slow_consensus_decrease_percent",
"50"},
4039 {
"target_txn_in_ledger",
"10"},
4040 {
"maximum_txn_per_account",
"200"}}));
4041 auto alice =
Account(
"alice");
4044 env.
fund(
XRP(50000000), alice);
4048 auto seqAlice = env.
seq(alice);
4050 for (
int i = 0; i < txCount; ++i)
4094 env.
close(env.
now() + 5s, 10000ms);
4099 env.
close(env.
now() + 5s, 10000ms);
4104 env.
close(env.
now() + 5s, 10000ms);
4111 env.
close(env.
now() + 5s, 10000ms);
4122 {{
"minimum_txn_in_ledger_standalone",
"3"},
4123 {
"normal_consensus_increase_percent",
"150"},
4124 {
"slow_consensus_decrease_percent",
"150"},
4125 {
"target_txn_in_ledger",
"10"},
4126 {
"maximum_txn_per_account",
"200"}}));
4127 auto alice =
Account(
"alice");
4130 env.
fund(
XRP(50000000), alice);
4134 auto seqAlice = env.
seq(alice);
4136 for (
int i = 0; i < txCount; ++i)
4155 env.
close(env.
now() + 5s, 10000ms);
4176 testcase(
"Sequence in queue and open ledger");
4177 using namespace jtx;
4179 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4181 auto const alice =
Account(
"alice");
4195 auto const aliceSeq = env.
seq(alice);
4241 testcase(
"Ticket in queue and open ledger");
4242 using namespace jtx;
4244 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4246 auto alice =
Account(
"alice");
4275 auto const tx = env.
jt(
4338 using namespace jtx;
4348 {{
"minimum_txn_in_ledger_standalone",
"1"},
4349 {
"ledgers_in_queue",
"5"},
4350 {
"maximum_txn_per_account",
"10"}},
4351 {{
"account_reserve",
"1000"}, {
"owner_reserve",
"50"}});
4353 auto& votingSection = cfg->section(
"voting");
4359 "reference_fee",
std::to_string(cfg->FEES.reference_fee.drops()));
4361 Env env(*
this, std::move(cfg));
4379 for (i = 0; i <= 257; ++i)
4387 *
this, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger);
4392 using namespace std::chrono_literals;
4393 auto closeDuration = 80min;
4394 for (i = 0; i <= 255; ++i)
4396 env.
close(closeDuration);
4399 auto const baseFee = env.
current()->fees().base.drops();
4406 5 * expectedPerLedger,
4407 expectedPerLedger + 1,
4411 auto seqAlice = env.
seq(alice);
4412 auto seqBob = env.
seq(bob);
4413 auto seqCarol = env.
seq(carol);
4414 auto seqDaria = env.
seq(daria);
4415 auto seqEllie = env.
seq(ellie);
4416 auto seqFiona = env.
seq(fiona);
4419 int txFee{
static_cast<int>(baseFee * 9)};
4420 auto prepareFee = [&](
uint64_t multiplier) {
4421 return fee(txFee - multiplier * baseFee / 10);
4425 for (
int i = 0; i < 10; ++i)
4429 prepareFee(++multiplier),
4433 prepareFee(++multiplier),
4437 prepareFee(++multiplier),
4441 prepareFee(++multiplier),
4445 prepareFee(++multiplier),
4449 prepareFee(++multiplier),
4457 5 * expectedPerLedger,
4458 expectedPerLedger + 1,
4472 env.
close(closeDuration);
4473 auto expectedInLedger = expectedInQueue;
4475 (expectedInQueue > expectedPerLedger + 2
4476 ? expectedInQueue - (expectedPerLedger + 2)
4478 expectedInLedger -= expectedInQueue;
4479 ++expectedPerLedger;
4484 5 * expectedPerLedger,
4488 auto const expectedPerAccount = expectedInQueue / 6;
4489 auto const expectedRemainder = expectedInQueue % 6;
4493 seqBob - expectedPerAccount -
4494 (expectedRemainder > 4 ? 1 : 0));
4497 seqCarol - expectedPerAccount -
4498 (expectedRemainder > 3 ? 1 : 0));
4501 seqDaria - expectedPerAccount -
4502 (expectedRemainder > 2 ? 1 : 0));
4505 seqEllie - expectedPerAccount -
4506 (expectedRemainder > 1 ? 1 : 0));
4509 seqFiona - expectedPerAccount -
4510 (expectedRemainder > 0 ? 1 : 0));
4512 }
while (expectedInQueue > 0);
4525 testcase(
"Queue full drop penalty");
4526 using namespace jtx;
4540 {{
"minimum_txn_in_ledger_standalone",
"5"},
4541 {
"ledgers_in_queue",
"5"},
4542 {
"maximum_txn_per_account",
"30"},
4543 {
"minimum_queue_size",
"50"}});
4545 Env env(*
this, std::move(cfg));
4546 auto const baseFee = env.current()->fees().base.drops();
4551 int const medFee = baseFee * 10;
4552 int const hiFee = baseFee * 100;
4556 env.fund(
XRP(10000),
noripple(alice, bob, carol, daria, ellie, fiona));
4572 auto seqAlice = env.seq(alice);
4573 auto const seqSaveAlice = seqAlice;
4574 int feeDrops = baseFee * 4;
4578 json(R
"({"LastLedgerSequence": 7})"),
4588 json(R
"({"LastLedgerSequence": 7})"),
4601 auto seqCarol = env.seq(carol);
4602 auto seqDaria = env.seq(daria);
4603 auto seqEllie = env.seq(ellie);
4604 auto seqFiona = env.seq(fiona);
4606 for (
int i = 0; i < 7; ++i)
4620 for (
int i = 0; i < 3; ++i)
4633 for (
int i = 0; i < 3; ++i)
4654 for (
int i = 0; i < 4; ++i)
4673 for (
int i = 0; i < 30; ++i)
4674 env.app().getFeeTrack().raiseLocalFee();
4684 while (env.app().getFeeTrack().lowerLocalFee())
4710 seqAlice = seqSaveAlice;
4763 using namespace jtx;
4767 auto USD = gw[
"USD"];
4770 {{
"minimum_txn_in_ledger_standalone",
"5"},
4771 {
"ledgers_in_queue",
"5"},
4772 {
"maximum_txn_per_account",
"30"},
4773 {
"minimum_queue_size",
"50"}});
4775 Env env(*
this, std::move(cfg));
4787 auto const aliceSeq = env.seq(alice);
4790 env(
offer(alice, USD(1000),
XRP(1001)),
4796 env(
offer(alice, USD(1000),
XRP(1002)),
4798 json(jss::OfferSequence, aliceSeq),
4814 auto const aliceTkt = env.seq(alice);
4822 auto const aliceSeq = env.seq(alice);
4823 env(
offer(alice, USD(1000),
XRP(1000)),
4827 env(
offer(alice, USD(1000),
XRP(1001)),
4837 env(
offer(alice, USD(1000),
XRP(1002)),
4839 json(jss::OfferSequence, aliceTkt + 4),
4849 env(
offer(alice, USD(1000),
XRP(1001)),
4854 env(
offer(alice, USD(1000),
XRP(1002)),
4856 json(jss::OfferSequence, aliceSeq),
4876 using namespace jtx;
4884 {{
"minimum_txn_in_ledger_standalone",
"3"}},
4885 {{
"reference_fee",
"0"},
4886 {
"account_reserve",
"0"},
4887 {
"owner_reserve",
"0"}}));
4892 auto const initQueueMax =
initFee(env, 3, 2, 0, 0, 0);
4897 auto const fee = env.
rpc(
"fee");
4905 auto const& levels =
result[jss::levels];
4907 levels.isMember(jss::median_level) &&
4908 levels[jss::median_level] ==
"128000");
4910 levels.isMember(jss::minimum_level) &&
4911 levels[jss::minimum_level] ==
"256");
4913 levels.isMember(jss::open_ledger_level) &&
4914 levels[jss::open_ledger_level] ==
"256");
4916 levels.isMember(jss::reference_level) &&
4917 levels[jss::reference_level] ==
"256");
4921 drops.isMember(jss::base_fee) &&
4922 drops[jss::base_fee] ==
"0");
4924 drops.isMember(jss::median_fee) &&
4925 drops[jss::median_fee] ==
"0");
4927 drops.isMember(jss::minimum_fee) &&
4928 drops[jss::minimum_fee] ==
"0");
4930 drops.isMember(jss::open_ledger_fee) &&
4931 drops[jss::open_ledger_fee] ==
"0");
4955 auto aliceSeq = env.
seq(alice);
4965 auto const fee = env.
rpc(
"fee");
4973 auto const& levels =
result[jss::levels];
4975 levels.isMember(jss::median_level) &&
4976 levels[jss::median_level] ==
"128000");
4978 levels.isMember(jss::minimum_level) &&
4979 levels[jss::minimum_level] ==
"256");
4981 levels.isMember(jss::open_ledger_level) &&
4982 levels[jss::open_ledger_level] ==
"355555");
4984 levels.isMember(jss::reference_level) &&
4985 levels[jss::reference_level] ==
"256");
4989 drops.isMember(jss::base_fee) &&
4990 drops[jss::base_fee] ==
"0");
4992 drops.isMember(jss::median_fee) &&
4993 drops[jss::median_fee] ==
"0");
4995 drops.isMember(jss::minimum_fee) &&
4996 drops[jss::minimum_fee] ==
"0");
4998 drops.isMember(jss::open_ledger_fee) &&
4999 drops[jss::open_ledger_fee] ==
"1389");
5061BEAST_DEFINE_TESTSUITE_PRIO(TxQPosNegFlows, app,
ripple, 1);
5062BEAST_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.
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))
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.
constexpr value_type fee() const
Returns the number of drops.
@ 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.
static increment_t const increment
std::unique_ptr< Config > makeConfig(std::map< std::string, std::string > extraTxQ={}, std::map< std::string, std::string > extraVoting={})
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.
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.