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();
754 constexpr auto largeFeeMultiplier = 700;
755 auto const largeFee = baseFee * largeFeeMultiplier;
770 aliceStat.begin()->lastValid &&
771 *aliceStat.begin()->lastValid == 8);
772 BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker());
774 auto bobStat = txQ.getAccountTxs(bob.id());
777 bobStat.begin()->feeLevel ==
778 FeeLevel64{baseFeeLevel.fee() * largeFeeMultiplier});
780 BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker());
804 constexpr auto anotherLargeFeeMultiplier = 800;
805 auto const anotherLargeFee = baseFee * anotherLargeFeeMultiplier;
844 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
851 auto const baseFee = env.
current()->fees().base.drops();
881 constexpr auto aliceFeeMultiplier = 3;
882 auto feeAlice = baseFee * aliceFeeMultiplier;
883 auto seqAlice = env.
seq(alice);
884 for (
int i = 0; i < 4; ++i)
887 feeAlice = (feeAlice + 1) * 125 / 100;
893 auto const seqBob = env.
seq(bob);
898 auto feeCarol = feeAlice;
899 auto seqCarol = env.
seq(carol);
900 for (
int i = 0; i < 4; ++i)
903 feeCarol = (feeCarol + 1) * 125 / 100;
971 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
994 auto const& jt = env.
jt(
noop(alice));
1019 using namespace jtx;
1025 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1026 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1028 auto alice =
Account(
"alice");
1030 auto charlie =
Account(
"charlie");
1031 auto daria =
Account(
"daria");
1038 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1049 auto aliceSeq = env.
seq(alice);
1050 auto bobSeq = env.
seq(bob);
1051 auto charlieSeq = env.
seq(charlie);
1096 aliceSeq = env.
seq(alice);
1097 auto lastLedgerSeq = env.
current()->info().seq + 2;
1098 for (
auto i = 0; i < 7; i++)
1102 json(jss::LastLedgerSequence, lastLedgerSeq + i),
1112 auto const& baseFee = env.
current()->fees().base;
1113 auto seq = env.
seq(alice);
1115 for (
auto const& tx : aliceStat)
1122 (tx.consequences.fee() ==
drops(aliceFee) &&
1123 tx.consequences.potentialSpend() ==
drops(0) &&
1124 !tx.consequences.isBlocker()) ||
1125 tx.seqProxy.value() == env.
seq(alice) + 6);
1135 json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1168 aliceSeq = env.
seq(alice) + 2;
1187 aliceSeq = env.
seq(alice) + 1;
1194 env.
le(alice)->getFieldAmount(sfBalance).xrp().drops() - (62);
1237 bobSeq = env.
seq(bob);
1239 for (
int i = 0; i < 10; ++i)
1254 env.
le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10 - 1);
1268 env.
le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10);
1287 using namespace jtx;
1291 auto cfg =
makeConfig({{
"minimum_txn_in_ledger_standalone",
"4"}});
1292 cfg->FEES.reference_fee = 10;
1293 Env env(*
this, std::move(cfg));
1295 auto alice =
Account(
"alice");
1297 auto charlie =
Account(
"charlie");
1298 auto daria =
Account(
"daria");
1334 auto aliceSeq = env.
seq(alice);
1335 auto bobSeq = env.
seq(bob);
1336 auto charlieSeq = env.
seq(charlie);
1337 auto dariaSeq = env.
seq(daria);
1338 auto elmoSeq = env.
seq(elmo);
1339 auto fredSeq = env.
seq(fred);
1340 auto gwenSeq = env.
seq(gwen);
1341 auto hankSeq = env.
seq(hank);
1383 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1384 gwenSeq + hankSeq + 6 ==
1385 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1386 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1388 using namespace std::string_literals;
1390 aliceSeq == env.
seq(alice),
1394 bobSeq + 1 == env.
seq(bob),
1398 charlieSeq + 2 == env.
seq(charlie),
1402 dariaSeq + 1 == env.
seq(daria),
1406 elmoSeq + 1 == env.
seq(elmo),
1410 fredSeq == env.
seq(fred),
1414 gwenSeq == env.
seq(gwen),
1418 hankSeq + 1 == env.
seq(hank),
1433 auto getTxsQueued = [&]() {
1436 for (
auto const& tx : txs)
1438 ++
result[tx.txn->at(sfAccount)];
1442 auto qTxCount1 = getTxsQueued();
1447 seq(aliceSeq + qTxCount1[alice.id()]++),
1452 seq(charlieSeq + qTxCount1[charlie.id()]++),
1456 seq(dariaSeq + qTxCount1[daria.id()]++),
1471 seq(aliceSeq + qTxCount1[alice.id()]++),
1483 auto qTxCount2 = getTxsQueued();
1489 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1490 gwenSeq + hankSeq + 7 ==
1491 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1492 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1495 aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] ==
1500 bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.
seq(bob),
1504 charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] ==
1509 dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] ==
1514 elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] ==
1519 fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] ==
1524 gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] ==
1529 hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] ==
1538 using namespace jtx;
1541 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"1"}}));
1543 auto alice =
Account(
"alice");
1557 json(R
"({"AccountTxnID": "0"})"),
1575 using namespace jtx;
1576 using namespace std::string_literals;
1583 {{
"minimum_txn_in_ledger_standalone",
"2"},
1584 {
"minimum_txn_in_ledger",
"5"},
1585 {
"target_txn_in_ledger",
"4"},
1586 {
"maximum_txn_in_ledger",
"5"}}));
1587 auto const baseFee = env.
current()->fees().base.drops();
1589 auto alice =
Account(
"alice");
1597 for (
int i = 0; i < 10; ++i)
1605 double const feeMultiplier =
1606 static_cast<double>(cost.drops()) / baseFee;
1628 {{
"minimum_txn_in_ledger",
"200"},
1629 {
"minimum_txn_in_ledger_standalone",
"200"},
1630 {
"target_txn_in_ledger",
"4"},
1631 {
"maximum_txn_in_ledger",
"5"}}));
1639 "The minimum number of low-fee transactions allowed "
1640 "per ledger (minimum_txn_in_ledger) exceeds "
1641 "the maximum number of low-fee transactions allowed per "
1642 "ledger (maximum_txn_in_ledger)."s);
1649 {{
"minimum_txn_in_ledger",
"200"},
1650 {
"minimum_txn_in_ledger_standalone",
"2"},
1651 {
"target_txn_in_ledger",
"4"},
1652 {
"maximum_txn_in_ledger",
"5"}}));
1660 "The minimum number of low-fee transactions allowed "
1661 "per ledger (minimum_txn_in_ledger) exceeds "
1662 "the maximum number of low-fee transactions allowed per "
1663 "ledger (maximum_txn_in_ledger)."s);
1670 {{
"minimum_txn_in_ledger",
"2"},
1671 {
"minimum_txn_in_ledger_standalone",
"200"},
1672 {
"target_txn_in_ledger",
"4"},
1673 {
"maximum_txn_in_ledger",
"5"}}));
1681 "The minimum number of low-fee transactions allowed "
1682 "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1683 "the maximum number of low-fee transactions allowed per "
1684 "ledger (maximum_txn_in_ledger)."s);
1691 using namespace jtx;
1692 testcase(
"unexpected balance change");
1697 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1698 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1700 auto alice =
Account(
"alice");
1706 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1713 auto USD = bob[
"USD"];
1727 auto aliceSeq = env.
seq(alice);
1771 for (
int i = 0; i < 9; ++i)
1786 using namespace jtx;
1789 auto alice =
Account(
"alice");
1791 auto charlie =
Account(
"charlie");
1792 auto daria =
Account(
"daria");
1796 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1797 auto const baseFee = env.
current()->fees().base.drops();
1811 env(
regkey(alice, charlie));
1815 auto const aliceSeq = env.
seq(alice);
1831 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1850 auto const aliceSeq = env.
seq(alice);
1868 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1894 auto const aliceSeq = env.
seq(alice);
1918 using namespace jtx;
1921 auto alice =
Account(
"alice");
1923 auto charlie =
Account(
"charlie");
1924 auto daria =
Account(
"daria");
1928 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1929 auto const baseFee = env.
current()->fees().base.drops();
1946 env(
regkey(alice, charlie));
1950 auto const aliceSeq = env.
seq(alice);
1966 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1970 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1994 auto const aliceSeq = env.
seq(alice);
2024 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
2084 using namespace jtx;
2085 testcase(
"In-flight balance checks");
2090 {{
"minimum_txn_in_ledger_standalone",
"3"}},
2091 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
2093 auto alice =
Account(
"alice");
2094 auto charlie =
Account(
"charlie");
2105 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
2112 checkMetrics(*
this, env, 0, initQueueMax, limit + 1, limit);
2114 auto USD = gw[
"USD"];
2115 auto BUX = gw[
"BUX"];
2119 auto aliceSeq = env.
seq(alice);
2120 auto aliceBal = env.
balance(alice);
2127 checkMetrics(*
this, env, 1, initQueueMax, limit + 1, limit);
2132 checkMetrics(*
this, env, 2, initQueueMax, limit + 1, limit);
2148 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2149 aliceSeq = env.
seq(alice);
2150 aliceBal = env.
balance(alice);
2156 checkMetrics(*
this, env, 1, limit * 2, limit + 1, limit);
2161 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2169 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2185 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2186 aliceSeq = env.
seq(alice);
2187 aliceBal = env.
balance(alice);
2194 checkMetrics(*
this, env, 1, limit * 2, limit + 1, limit);
2202 checkMetrics(*
this, env, 1, limit * 2, limit + 1, limit);
2218 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2219 aliceSeq = env.
seq(alice);
2220 aliceBal = env.
balance(alice);
2228 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2244 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2246 aliceSeq = env.
seq(alice);
2247 aliceBal = env.
balance(alice);
2257 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2271 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2273 aliceSeq = env.
seq(alice);
2274 aliceBal = env.
balance(alice);
2282 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2294 auto const amount = USD(500000);
2295 env(
trust(alice, USD(50000000)));
2296 env(
trust(charlie, USD(50000000)));
2302 env(
pay(gw, alice, amount));
2309 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2311 aliceSeq = env.
seq(alice);
2312 aliceBal = env.
balance(alice);
2313 auto aliceUSD = env.
balance(alice, USD);
2317 env(
pay(alice, charlie, amount),
queued);
2322 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2340 env(
offer(gw,
XRP(500000), USD(50000)));
2346 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2348 aliceSeq = env.
seq(alice);
2349 aliceBal = env.
balance(alice);
2350 auto charlieUSD = env.
balance(charlie, USD);
2362 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2373 balance(charlie, charlieUSD + USD(1000)),
2381 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2383 aliceSeq = env.
seq(alice);
2384 aliceBal = env.
balance(alice);
2385 charlieUSD = env.
balance(charlie, USD);
2396 checkMetrics(*
this, env, 2, limit * 2, limit + 1, limit);
2407 balance(charlie, charlieUSD + USD(500)),
2417 checkMetrics(*
this, env, 0, limit * 2, limit + 1, limit);
2419 aliceSeq = env.
seq(alice);
2420 aliceBal = env.
balance(alice);
2427 checkMetrics(*
this, env, 1, limit * 2, limit + 1, limit);
2438 using namespace jtx;
2443 auto const alice =
Account(
"alice");
2462 auto USD = alice[
"USD"];
2504 using namespace jtx;
2505 testcase(
"acct in queue but empty");
2507 auto alice =
Account(
"alice");
2509 auto charlie =
Account(
"charlie");
2513 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2514 auto const baseFee = env.
current()->fees().base.drops();
2542 env(
noop(bob),
fee(baseFee * 100));
2543 env(
noop(bob),
fee(baseFee * 100));
2544 env(
noop(bob),
fee(baseFee * 100));
2545 env(
noop(bob),
fee(baseFee * 100));
2546 env(
noop(bob),
fee(baseFee * 100));
2572 checkMetrics(*
this, env, 10, 10, 6, 5, expectedFeeLevel + 1);
2595 seq(charlieSeq - 1),
2599 seq(charlieSeq + 1),
2610 using namespace jtx;
2615 auto fee = env.
rpc(
"fee");
2622 result.isMember(jss::ledger_current_index) &&
2623 result[jss::ledger_current_index] == 3);
2635 auto const& levels =
result[jss::levels];
2651 result.isMember(jss::ledger_current_index) &&
2652 result[jss::ledger_current_index] == 4);
2663 auto const& levels =
result[jss::levels];
2685 using namespace jtx;
2686 testcase(
"expiration replacement");
2691 {{
"minimum_txn_in_ledger_standalone",
"1"},
2692 {
"ledgers_in_queue",
"10"},
2693 {
"maximum_txn_per_account",
"20"}}));
2695 auto const baseFee = env.
current()->fees().base.drops();
2698 auto const alice =
Account(
"alice");
2699 auto const bob =
Account(
"bob");
2704 auto const aliceSeq = env.
seq(alice);
2717 auto const bobSeq = env.
seq(bob);
2721 for (
int i = 0; i < 3 + 4 + 5; ++i)
2779 using namespace jtx;
2780 testcase(
"full queue gap handling");
2783 {{
"minimum_txn_in_ledger_standalone",
"1"},
2784 {
"ledgers_in_queue",
"10"},
2785 {
"maximum_txn_per_account",
"11"}});
2786 cfg->FEES.reference_fee = 10;
2787 Env env(*
this, std::move(cfg));
2789 auto const baseFee = env.
current()->fees().base.drops();
2794 auto const alice =
Account(
"alice");
2795 auto const bob =
Account(
"bob");
2800 auto const aliceSeq = env.
seq(alice);
2807 fee(baseFee * 20 + 1),
2847 auto const bobSeq = env.
seq(bob);
2851 for (
int i = 0; i < 2 + 4 + 5; ++i)
2938 testcase(
"Autofilled sequence should account for TxQ");
2939 using namespace jtx;
2940 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"6"}}));
2941 auto const baseFee = env.
current()->fees().base.drops();
2945 auto const alice =
Account(
"alice");
2946 auto const bob =
Account(
"bob");
2947 env.
fund(
XRP(100000), alice, bob);
2953 auto const aliceSeq = env.
seq(alice);
2954 auto const lastLedgerSeq = env.
current()->info().seq + 2;
2957 for (
int i = 0; i < 5; ++i)
2964 json(jss::LastLedgerSequence, lastLedgerSeq),
2973 auto aliceStat = txQ.getAccountTxs(alice.id());
2976 for (
auto const& tx : aliceStat)
2980 tx.feeLevel ==
FeeLevel64{baseFeeLevel.fee() * 100});
2981 if (
seq.value() == aliceSeq + 2)
2984 tx.lastValid && *tx.lastValid == lastLedgerSeq);
2995 for (
int i = 0; i < 8; ++i)
3004 for (
int i = 0; i < 9; ++i)
3011 for (
int i = 0; i < 10; ++i)
3018 auto bobStat = txQ.getAccountTxs(bob.id());
3024 auto aliceStat = txQ.getAccountTxs(alice.id());
3025 auto seq = aliceSeq;
3027 for (
auto const& tx : aliceStat)
3030 if (
seq == aliceSeq + 2)
3035 tx.feeLevel ==
FeeLevel64{baseFeeLevel.fee() * 100});
3045 auto aliceStat = txQ.getAccountTxs(alice.id());
3046 auto seq = aliceSeq;
3048 for (
auto const& tx : aliceStat)
3061 auto bobStat = txQ.getAccountTxs(bob.id());
3065 auto aliceStat = txQ.getAccountTxs(alice.id());
3073 using namespace jtx;
3076 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3077 auto const baseFee = env.
current()->fees().base.drops();
3081 env.
fund(
XRP(1000000), alice);
3084 auto const withQueue =
3085 R
"({ "account": ")" + alice.human() + R"(", "queue": true })";
3088 R"(", "queue": true, "ledger_index": 3 })";
3095 info.isMember(jss::result) &&
3096 info[jss::result].isMember(jss::account_data));
3101 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3103 info.isMember(jss::result) &&
3104 info[jss::result].isMember(jss::account_data));
3123 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3125 info.isMember(jss::result) &&
3126 info[jss::result].isMember(jss::account_data));
3127 auto const&
result = info[jss::result];
3152 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3154 info.isMember(jss::result) &&
3155 info[jss::result].isMember(jss::account_data));
3156 auto const&
result = info[jss::result];
3169 data[jss::Sequence].asUInt() +
3182 auto const& item =
queued[i];
3185 item[jss::fee_level] ==
3195 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3210 json(jss::LastLedgerSequence, 10),
3215 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3217 info.isMember(jss::result) &&
3218 info[jss::result].isMember(jss::account_data));
3219 auto const&
result = info[jss::result];
3220 auto const&
data =
result[jss::account_data];
3232 data[jss::Sequence].asUInt() +
3245 auto const& item =
queued[i];
3248 item[jss::fee_level] ==
3257 if (i ==
queued.size() - 1)
3265 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3279 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3281 info.isMember(jss::result) &&
3282 info[jss::result].isMember(jss::account_data));
3283 auto const&
result = info[jss::result];
3284 auto const&
data =
result[jss::account_data];
3296 data[jss::Sequence].asUInt() +
3309 auto const& item =
queued[i];
3312 item[jss::fee_level] ==
3315 if (i ==
queued.size() - 1)
3322 item[jss::max_spend_drops] ==
3336 item[jss::max_spend_drops] ==
3349 info.isMember(jss::result) &&
3359 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3361 info.isMember(jss::result) &&
3362 info[jss::result].isMember(jss::account_data));
3363 auto const&
result = info[jss::result];
3380 using namespace jtx;
3383 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3384 auto const baseFee = env.
current()->fees().base.drops();
3388 env.
fund(
XRP(1000000), alice);
3392 auto const server_info = env.
rpc(
"server_info");
3394 server_info.isMember(jss::result) &&
3395 server_info[jss::result].isMember(jss::info));
3396 auto const& info = server_info[jss::result][jss::info];
3398 info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
3402 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3405 auto const server_state = env.
rpc(
"server_state");
3406 auto const& state = server_state[jss::result][jss::state];
3408 state.isMember(jss::load_factor) &&
3409 state[jss::load_factor] == 256);
3411 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3413 state.isMember(jss::load_factor_server) &&
3414 state[jss::load_factor_server] == 256);
3416 state.isMember(jss::load_factor_fee_escalation) &&
3417 state[jss::load_factor_fee_escalation] == 256);
3419 state.isMember(jss::load_factor_fee_queue) &&
3420 state[jss::load_factor_fee_queue] == 256);
3422 state.isMember(jss::load_factor_fee_reference) &&
3423 state[jss::load_factor_fee_reference] == 256);
3431 auto aliceSeq = env.
seq(alice);
3433 for (
auto i = 0; i < 4; ++i)
3442 auto const server_info = env.
rpc(
"server_info");
3444 server_info.isMember(jss::result) &&
3445 server_info[jss::result].isMember(jss::info));
3446 auto const& info = server_info[jss::result][jss::info];
3449 info.isMember(jss::load_factor) &&
3450 info[jss::load_factor] > 888.88 &&
3451 info[jss::load_factor] < 888.89);
3453 info.isMember(jss::load_factor_server) &&
3454 info[jss::load_factor_server] == 1);
3458 info.isMember(jss::load_factor_fee_escalation) &&
3459 info[jss::load_factor_fee_escalation] > 888.88 &&
3460 info[jss::load_factor_fee_escalation] < 888.89);
3463 auto const server_state = env.
rpc(
"server_state");
3464 auto const& state = server_state[jss::result][jss::state];
3466 state.isMember(jss::load_factor) &&
3467 state[jss::load_factor] == 227555);
3469 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3471 state.isMember(jss::load_factor_server) &&
3472 state[jss::load_factor_server] == 256);
3474 state.isMember(jss::load_factor_fee_escalation) &&
3475 state[jss::load_factor_fee_escalation] == 227555);
3477 state.isMember(jss::load_factor_fee_queue) &&
3478 state[jss::load_factor_fee_queue] == 256);
3480 state.isMember(jss::load_factor_fee_reference) &&
3481 state[jss::load_factor_fee_reference] == 256);
3487 auto const server_info = env.
rpc(
"server_info");
3489 server_info.isMember(jss::result) &&
3490 server_info[jss::result].isMember(jss::info));
3491 auto const& info = server_info[jss::result][jss::info];
3494 info.isMember(jss::load_factor) &&
3495 info[jss::load_factor] == 1000);
3499 info.isMember(jss::load_factor_net) &&
3500 info[jss::load_factor_net] == 1000);
3502 info.isMember(jss::load_factor_fee_escalation) &&
3503 info[jss::load_factor_fee_escalation] > 888.88 &&
3504 info[jss::load_factor_fee_escalation] < 888.89);
3507 auto const server_state = env.
rpc(
"server_state");
3508 auto const& state = server_state[jss::result][jss::state];
3510 state.isMember(jss::load_factor) &&
3511 state[jss::load_factor] == 256000);
3513 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3515 state.isMember(jss::load_factor_server) &&
3516 state[jss::load_factor_server] == 256000);
3518 state.isMember(jss::load_factor_fee_escalation) &&
3519 state[jss::load_factor_fee_escalation] == 227555);
3521 state.isMember(jss::load_factor_fee_queue) &&
3522 state[jss::load_factor_fee_queue] == 256);
3524 state.isMember(jss::load_factor_fee_reference) &&
3525 state[jss::load_factor_fee_reference] == 256);
3531 for (
int i = 0; i < 5; ++i)
3536 auto const server_info = env.
rpc(
"server_info");
3538 server_info.isMember(jss::result) &&
3539 server_info[jss::result].isMember(jss::info));
3540 auto const& info = server_info[jss::result][jss::info];
3543 info.isMember(jss::load_factor) &&
3544 info[jss::load_factor] > 888.88 &&
3545 info[jss::load_factor] < 888.89);
3550 info.isMember(jss::load_factor_server) &&
3551 info[jss::load_factor_server] > 1.245 &&
3552 info[jss::load_factor_server] < 2.4415);
3554 info.isMember(jss::load_factor_local) &&
3555 info[jss::load_factor_local] > 1.245 &&
3556 info[jss::load_factor_local] < 2.4415);
3559 info.isMember(jss::load_factor_fee_escalation) &&
3560 info[jss::load_factor_fee_escalation] > 888.88 &&
3561 info[jss::load_factor_fee_escalation] < 888.89);
3564 auto const server_state = env.
rpc(
"server_state");
3565 auto const& state = server_state[jss::result][jss::state];
3567 state.isMember(jss::load_factor) &&
3568 state[jss::load_factor] == 227555);
3570 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3575 state.isMember(jss::load_factor_server) &&
3576 state[jss::load_factor_server] >= 320 &&
3577 state[jss::load_factor_server] <= 625);
3579 state.isMember(jss::load_factor_fee_escalation) &&
3580 state[jss::load_factor_fee_escalation] == 227555);
3582 state.isMember(jss::load_factor_fee_queue) &&
3583 state[jss::load_factor_fee_queue] == 256);
3585 state.isMember(jss::load_factor_fee_reference) &&
3586 state[jss::load_factor_fee_reference] == 256);
3592 auto const server_info = env.
rpc(
"server_info");
3594 server_info.isMember(jss::result) &&
3595 server_info[jss::result].isMember(jss::info));
3596 auto const& info = server_info[jss::result][jss::info];
3603 info.isMember(jss::load_factor) &&
3604 info[jss::load_factor] > 1.245 &&
3605 info[jss::load_factor] < 2.4415);
3608 info.isMember(jss::load_factor_local) &&
3609 info[jss::load_factor_local] > 1.245 &&
3610 info[jss::load_factor_local] < 2.4415);
3612 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3615 auto const server_state = env.
rpc(
"server_state");
3616 auto const& state = server_state[jss::result][jss::state];
3618 state.isMember(jss::load_factor) &&
3619 state[jss::load_factor] >= 320 &&
3620 state[jss::load_factor] <= 625);
3622 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3627 state.isMember(jss::load_factor_server) &&
3628 state[jss::load_factor_server] >= 320 &&
3629 state[jss::load_factor_server] <= 625);
3631 state.isMember(jss::load_factor_fee_escalation) &&
3632 state[jss::load_factor_fee_escalation] == 256);
3634 state.isMember(jss::load_factor_fee_queue) &&
3635 state[jss::load_factor_fee_queue] == 256);
3637 state.isMember(jss::load_factor_fee_reference) &&
3638 state[jss::load_factor_fee_reference] == 256);
3645 using namespace jtx;
3648 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3649 auto const baseFee = env.
current()->fees().base.drops();
3653 stream[jss::streams].append(
"server");
3656 auto jv = wsc->invoke(
"subscribe", stream);
3660 Account a{
"a"}, b{
"b"}, c{
"c"}, d{
"d"}, e{
"e"}, f{
"f"}, g{
"g"}, h{
"h"},
3668 using namespace std::chrono_literals;
3670 return jv[jss::type] ==
"serverStatus" &&
3671 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3672 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3673 jv.isMember(jss::load_factor_server) &&
3674 jv[jss::load_factor_server] == 256 &&
3675 jv.isMember(jss::load_factor_fee_escalation) &&
3676 jv[jss::load_factor_fee_escalation] == 256 &&
3677 jv.isMember(jss::load_factor_fee_queue) &&
3678 jv[jss::load_factor_fee_queue] == 256 &&
3679 jv.isMember(jss::load_factor_fee_reference) &&
3680 jv[jss::load_factor_fee_reference] == 256;
3684 return jv[jss::type] ==
"serverStatus" &&
3685 jv.isMember(jss::load_factor) &&
3686 jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3687 jv[jss::load_base] == 256 &&
3688 jv.isMember(jss::load_factor_server) &&
3689 jv[jss::load_factor_server] == 256 &&
3690 jv.isMember(jss::load_factor_fee_escalation) &&
3691 jv[jss::load_factor_fee_escalation] == 227555 &&
3692 jv.isMember(jss::load_factor_fee_queue) &&
3693 jv[jss::load_factor_fee_queue] == 256 &&
3694 jv.isMember(jss::load_factor_fee_reference) &&
3695 jv[jss::load_factor_fee_reference] == 256;
3702 return jv[jss::type] ==
"serverStatus" &&
3703 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3704 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3705 jv.isMember(jss::load_factor_server) &&
3706 jv[jss::load_factor_server] == 256 &&
3707 jv.isMember(jss::load_factor_fee_escalation) &&
3708 jv[jss::load_factor_fee_escalation] == 256 &&
3709 jv.isMember(jss::load_factor_fee_queue) &&
3710 jv[jss::load_factor_fee_queue] == 256 &&
3711 jv.isMember(jss::load_factor_fee_reference) &&
3712 jv[jss::load_factor_fee_reference] == 256;
3733 return jv[jss::type] ==
"serverStatus" &&
3734 jv.isMember(jss::load_factor) &&
3735 jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3736 jv[jss::load_base] == 256 &&
3737 jv.isMember(jss::load_factor_server) &&
3738 jv[jss::load_factor_server] == 256 &&
3739 jv.isMember(jss::load_factor_fee_escalation) &&
3740 jv[jss::load_factor_fee_escalation] == 200000 &&
3741 jv.isMember(jss::load_factor_fee_queue) &&
3742 jv[jss::load_factor_fee_queue] == 256 &&
3743 jv.isMember(jss::load_factor_fee_reference) &&
3744 jv[jss::load_factor_fee_reference] == 256;
3750 return jv[jss::type] ==
"serverStatus" &&
3751 jv.isMember(jss::load_factor) &&
3752 jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3753 jv[jss::load_base] == 256 &&
3754 jv.isMember(jss::load_factor_server) &&
3755 jv[jss::load_factor_server] == 256 &&
3756 jv.isMember(jss::load_factor_fee_escalation) &&
3757 jv[jss::load_factor_fee_escalation] == 184320 &&
3758 jv.isMember(jss::load_factor_fee_queue) &&
3759 jv[jss::load_factor_fee_queue] == 256 &&
3760 jv.isMember(jss::load_factor_fee_reference) &&
3761 jv[jss::load_factor_fee_reference] == 256;
3767 return jv[jss::type] ==
"serverStatus" &&
3768 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3769 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3770 jv.isMember(jss::load_factor_server) &&
3771 jv[jss::load_factor_server] == 256 &&
3772 jv.isMember(jss::load_factor_fee_escalation) &&
3773 jv[jss::load_factor_fee_escalation] == 256 &&
3774 jv.isMember(jss::load_factor_fee_queue) &&
3775 jv[jss::load_factor_fee_queue] == 256 &&
3776 jv.isMember(jss::load_factor_fee_reference) &&
3777 jv[jss::load_factor_fee_reference] == 256;
3781 return jv[jss::type] ==
"serverStatus";
3784 auto jv = wsc->invoke(
"unsubscribe", stream);
3791 using namespace jtx;
3794 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3795 auto const baseFee = env.
current()->fees().base.drops();
3796 auto alice =
Account(
"alice");
3800 env.
fund(
XRP(50000000), alice, bob);
3807 auto totalFactor = 0;
3810 numToClear.emplace(metrics.txCount + 1);
3811 for (
int i = 0; i < *numToClear; ++i)
3814 totalFactor += inLedger * inLedger;
3817 auto const den = (metrics.txPerLedger * metrics.txPerLedger);
3819 (metrics.medFeeLevel * totalFactor +
FeeLevel64{den - 1}) / den;
3830 testcase(
"straightfoward positive case");
3833 auto aliceSeq = env.
seq(alice);
3835 for (
int i = 0; i < 2; ++i)
3841 totalPaid += baseFee * 10;
3869 totalPaid += totalFee;
3870 totalFee = calcTotalFee(totalPaid);
3873 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3878 testcase(
"replace last tx with enough to clear queue");
3881 auto aliceSeq = env.
seq(alice);
3883 for (
int i = 0; i < 2; ++i)
3889 totalPaid += baseFee * 10;
3906 calcTotalFee(totalPaid, metrics.txCount);
3909 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3918 testcase(
"replace middle tx with enough to clear queue");
3922 auto aliceSeq = env.
seq(alice);
3923 for (
int i = 0; i < 5; ++i)
3934 uint64_t const totalFee = calcTotalFee(baseFee * 10 * 2, 3);
3937 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3940 auto const aliceQueue =
3944 for (
auto const& tx : aliceQueue)
3948 tx.feeLevel ==
FeeLevel64{baseFeeLevel.fee() * 10});
3957 testcase(
"clear queue failure (load)");
3961 auto aliceSeq = env.
seq(alice);
3963 for (
int i = 0; i < 2; ++i)
3969 totalPaid += baseFee * 20;
3971 for (
int i = 0; i < 2; ++i)
3977 totalPaid += baseFee * 2.2;
3988 feeTrack.setRemoteFee(origFee * 5);
4001 feeTrack.setRemoteFee(origFee);
4020 using namespace jtx;
4021 using namespace std::chrono_literals;
4028 {{
"minimum_txn_in_ledger_standalone",
"3"},
4029 {
"normal_consensus_increase_percent",
"25"},
4030 {
"slow_consensus_decrease_percent",
"50"},
4031 {
"target_txn_in_ledger",
"10"},
4032 {
"maximum_txn_per_account",
"200"}}));
4033 auto alice =
Account(
"alice");
4036 env.
fund(
XRP(50000000), alice);
4040 auto seqAlice = env.
seq(alice);
4042 for (
int i = 0; i < txCount; ++i)
4086 env.
close(env.
now() + 5s, 10000ms);
4091 env.
close(env.
now() + 5s, 10000ms);
4096 env.
close(env.
now() + 5s, 10000ms);
4103 env.
close(env.
now() + 5s, 10000ms);
4114 {{
"minimum_txn_in_ledger_standalone",
"3"},
4115 {
"normal_consensus_increase_percent",
"150"},
4116 {
"slow_consensus_decrease_percent",
"150"},
4117 {
"target_txn_in_ledger",
"10"},
4118 {
"maximum_txn_per_account",
"200"}}));
4119 auto alice =
Account(
"alice");
4122 env.
fund(
XRP(50000000), alice);
4126 auto seqAlice = env.
seq(alice);
4128 for (
int i = 0; i < txCount; ++i)
4147 env.
close(env.
now() + 5s, 10000ms);
4168 testcase(
"Sequence in queue and open ledger");
4169 using namespace jtx;
4171 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4173 auto const alice =
Account(
"alice");
4187 auto const aliceSeq = env.
seq(alice);
4233 testcase(
"Ticket in queue and open ledger");
4234 using namespace jtx;
4236 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4238 auto alice =
Account(
"alice");
4267 auto const tx = env.
jt(
4330 using namespace jtx;
4340 {{
"minimum_txn_in_ledger_standalone",
"1"},
4341 {
"ledgers_in_queue",
"5"},
4342 {
"maximum_txn_per_account",
"10"}},
4343 {{
"account_reserve",
"1000"}, {
"owner_reserve",
"50"}});
4345 auto& votingSection = cfg->section(
"voting");
4351 "reference_fee",
std::to_string(cfg->FEES.reference_fee.drops()));
4353 Env env(*
this, std::move(cfg));
4371 for (i = 0; i <= 257; ++i)
4379 *
this, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger);
4384 using namespace std::chrono_literals;
4385 auto closeDuration = 80min;
4386 for (i = 0; i <= 255; ++i)
4388 env.
close(closeDuration);
4391 auto const baseFee = env.
current()->fees().base.drops();
4398 5 * expectedPerLedger,
4399 expectedPerLedger + 1,
4403 auto seqAlice = env.
seq(alice);
4404 auto seqBob = env.
seq(bob);
4405 auto seqCarol = env.
seq(carol);
4406 auto seqDaria = env.
seq(daria);
4407 auto seqEllie = env.
seq(ellie);
4408 auto seqFiona = env.
seq(fiona);
4411 int txFee{
static_cast<int>(baseFee * 9)};
4412 auto prepareFee = [&](
uint64_t multiplier) {
4413 return fee(txFee - multiplier * baseFee / 10);
4417 for (
int i = 0; i < 10; ++i)
4421 prepareFee(++multiplier),
4425 prepareFee(++multiplier),
4429 prepareFee(++multiplier),
4433 prepareFee(++multiplier),
4437 prepareFee(++multiplier),
4441 prepareFee(++multiplier),
4449 5 * expectedPerLedger,
4450 expectedPerLedger + 1,
4464 env.
close(closeDuration);
4465 auto expectedInLedger = expectedInQueue;
4467 (expectedInQueue > expectedPerLedger + 2
4468 ? expectedInQueue - (expectedPerLedger + 2)
4470 expectedInLedger -= expectedInQueue;
4471 ++expectedPerLedger;
4476 5 * expectedPerLedger,
4480 auto const expectedPerAccount = expectedInQueue / 6;
4481 auto const expectedRemainder = expectedInQueue % 6;
4485 seqBob - expectedPerAccount -
4486 (expectedRemainder > 4 ? 1 : 0));
4489 seqCarol - expectedPerAccount -
4490 (expectedRemainder > 3 ? 1 : 0));
4493 seqDaria - expectedPerAccount -
4494 (expectedRemainder > 2 ? 1 : 0));
4497 seqEllie - expectedPerAccount -
4498 (expectedRemainder > 1 ? 1 : 0));
4501 seqFiona - expectedPerAccount -
4502 (expectedRemainder > 0 ? 1 : 0));
4504 }
while (expectedInQueue > 0);
4517 testcase(
"Queue full drop penalty");
4518 using namespace jtx;
4532 {{
"minimum_txn_in_ledger_standalone",
"5"},
4533 {
"ledgers_in_queue",
"5"},
4534 {
"maximum_txn_per_account",
"30"},
4535 {
"minimum_queue_size",
"50"}});
4537 Env env(*
this, std::move(cfg));
4538 auto const baseFee = env.current()->fees().base.drops();
4543 int const medFee = baseFee * 10;
4544 int const hiFee = baseFee * 100;
4548 env.fund(
XRP(10000),
noripple(alice, bob, carol, daria, ellie, fiona));
4564 auto seqAlice = env.seq(alice);
4565 auto const seqSaveAlice = seqAlice;
4566 int feeDrops = baseFee * 4;
4593 auto seqCarol = env.seq(carol);
4594 auto seqDaria = env.seq(daria);
4595 auto seqEllie = env.seq(ellie);
4596 auto seqFiona = env.seq(fiona);
4598 for (
int i = 0; i < 7; ++i)
4612 for (
int i = 0; i < 3; ++i)
4625 for (
int i = 0; i < 3; ++i)
4646 for (
int i = 0; i < 4; ++i)
4665 for (
int i = 0; i < 30; ++i)
4666 env.app().getFeeTrack().raiseLocalFee();
4676 while (env.app().getFeeTrack().lowerLocalFee())
4702 seqAlice = seqSaveAlice;
4755 using namespace jtx;
4759 auto USD = gw[
"USD"];
4762 {{
"minimum_txn_in_ledger_standalone",
"5"},
4763 {
"ledgers_in_queue",
"5"},
4764 {
"maximum_txn_per_account",
"30"},
4765 {
"minimum_queue_size",
"50"}});
4767 Env env(*
this, std::move(cfg));
4779 auto const aliceSeq = env.seq(alice);
4782 env(
offer(alice, USD(1000),
XRP(1001)),
4788 env(
offer(alice, USD(1000),
XRP(1002)),
4790 json(jss::OfferSequence, aliceSeq),
4806 auto const aliceTkt = env.seq(alice);
4814 auto const aliceSeq = env.seq(alice);
4815 env(
offer(alice, USD(1000),
XRP(1000)),
4819 env(
offer(alice, USD(1000),
XRP(1001)),
4829 env(
offer(alice, USD(1000),
XRP(1002)),
4831 json(jss::OfferSequence, aliceTkt + 4),
4841 env(
offer(alice, USD(1000),
XRP(1001)),
4846 env(
offer(alice, USD(1000),
XRP(1002)),
4848 json(jss::OfferSequence, aliceSeq),
4868 using namespace jtx;
4876 {{
"minimum_txn_in_ledger_standalone",
"3"}},
4877 {{
"reference_fee",
"0"},
4878 {
"account_reserve",
"0"},
4879 {
"owner_reserve",
"0"}}));
4884 auto const initQueueMax =
initFee(env, 3, 2, 0, 0, 0);
4889 auto const fee = env.
rpc(
"fee");
4897 auto const& levels =
result[jss::levels];
4899 levels.isMember(jss::median_level) &&
4900 levels[jss::median_level] ==
"128000");
4902 levels.isMember(jss::minimum_level) &&
4903 levels[jss::minimum_level] ==
"256");
4905 levels.isMember(jss::open_ledger_level) &&
4906 levels[jss::open_ledger_level] ==
"256");
4908 levels.isMember(jss::reference_level) &&
4909 levels[jss::reference_level] ==
"256");
4913 drops.isMember(jss::base_fee) &&
4914 drops[jss::base_fee] ==
"0");
4916 drops.isMember(jss::median_fee) &&
4917 drops[jss::median_fee] ==
"0");
4919 drops.isMember(jss::minimum_fee) &&
4920 drops[jss::minimum_fee] ==
"0");
4922 drops.isMember(jss::open_ledger_fee) &&
4923 drops[jss::open_ledger_fee] ==
"0");
4947 auto aliceSeq = env.
seq(alice);
4957 auto const fee = env.
rpc(
"fee");
4965 auto const& levels =
result[jss::levels];
4967 levels.isMember(jss::median_level) &&
4968 levels[jss::median_level] ==
"128000");
4970 levels.isMember(jss::minimum_level) &&
4971 levels[jss::minimum_level] ==
"256");
4973 levels.isMember(jss::open_ledger_level) &&
4974 levels[jss::open_ledger_level] ==
"355555");
4976 levels.isMember(jss::reference_level) &&
4977 levels[jss::reference_level] ==
"256");
4981 drops.isMember(jss::base_fee) &&
4982 drops[jss::base_fee] ==
"0");
4984 drops.isMember(jss::median_fee) &&
4985 drops[jss::median_fee] ==
"0");
4987 drops.isMember(jss::minimum_fee) &&
4988 drops[jss::minimum_fee] ==
"0");
4990 drops.isMember(jss::open_ledger_fee) &&
4991 drops[jss::open_ledger_fee] ==
"1389");
5053BEAST_DEFINE_TESTSUITE_PRIO(TxQPosNegFlows, app,
ripple, 1);
5054BEAST_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.