21#include <test/jtx/TestSuite.h>
22#include <test/jtx/WSClient.h>
23#include <test/jtx/envconfig.h>
24#include <test/jtx/ticket.h>
25#include <xrpld/app/main/Application.h>
26#include <xrpld/app/misc/LoadFeeTrack.h>
27#include <xrpld/app/misc/TxQ.h>
28#include <xrpld/app/tx/apply.h>
29#include <xrpl/protocol/ErrorCodes.h>
30#include <xrpl/protocol/jss.h>
31#include <xrpl/protocol/st.h>
50 FeeLevel64 const expectedMin{expectedMinFeeLevel};
51 FeeLevel64 const expectedMed{expectedMedFeeLevel};
53 using namespace std::string_literals;
64 metrics.txCount == expectedCount
72 metrics.txQMaxSize == expectedMaxCount
81 metrics.txInLedger == expectedInLedger
89 metrics.txPerLedger == expectedPerLedger
97 metrics.minProcessingFeeLevel == expectedMin
100 "minProcessingFeeLevel: "s +
106 metrics.medFeeLevel == expectedMed
115 auto const expectedCurFeeLevel = expectedInLedger > expectedPerLedger
116 ? expectedMed * expectedInLedger * expectedInLedger /
117 (expectedPerLedger * expectedPerLedger)
118 : metrics.referenceFeeLevel;
120 metrics.openLedgerFeeLevel == expectedCurFeeLevel
123 "openLedgerFeeLevel: "s +
134 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
143 auto const& view = *env.
current();
145 auto const base = [&view]() {
146 auto base = view.fees().base;
153 return fee(
toDrops(metrics.openLedgerFeeLevel, base) + 1);
162 auto& section = p->section(
"transaction_queue");
163 section.set(
"ledgers_in_queue",
"2");
164 section.set(
"minimum_queue_size",
"2");
165 section.set(
"min_ledgers_to_compute_size_limit",
"3");
166 section.set(
"max_ledger_counts_to_store",
"100");
167 section.set(
"retry_sequence_percent",
"25");
168 section.set(
"normal_consensus_increase_percent",
"0");
170 for (
auto const& [k, v] : extraTxQ)
175 if (!extraVoting.
empty())
177 auto& votingSection = p->section(
"voting");
178 for (
auto const& [k, v] : extraVoting)
180 votingSection.set(k, v);
184 p->section(
"validation_seed")
185 .legacy(
"shUwVw52ofnCUX5m7kPTKzJdr4HEH");
203 for (
auto i = env.
current()->seq(); i <= 257; ++i)
210 auto const flagMaxQueue = ledgersInQueue * flagPerLedger;
211 checkMetrics(__LINE__, env, 0, flagMaxQueue, 0, flagPerLedger, 256);
220 using namespace std::chrono_literals;
222 checkMetrics(__LINE__, env, 0, flagMaxQueue, 0, expectedPerLedger, 256);
223 auto const fees = env.
current()->fees();
239 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
243 auto charlie =
Account(
"charlie");
255 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
259 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
263 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
267 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
271 checkMetrics(__LINE__, env, 2, std::nullopt, 5, 3, 256);
389 checkMetrics(__LINE__, env, 2, 8, 5, 4, 256, 256 * 700);
425 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
439 metrics.txPerLedger + 1,
450 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
458 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
465 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
477 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
707 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
711 auto USD = gw[
"USD"];
713 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
717 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
744 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
748 auto charlie =
Account(
"charlie");
754 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
758 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
765 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
769 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
773 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
777 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
781 checkMetrics(__LINE__, env, 2, std::nullopt, 4, 2, 256);
785 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 2, 256);
801 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
805 auto charlie =
Account(
"charlie");
808 auto felicia =
Account(
"felicia");
812 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
822 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
826 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
831 json(R
"({"LastLedgerSequence":7})"),
841 checkMetrics(__LINE__, env, 5, std::nullopt, 3, 2, 256);
848 aliceStat.begin()->lastValid &&
849 *aliceStat.begin()->lastValid == 8);
850 BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker());
852 auto bobStat = txQ.getAccountTxs(bob.id());
855 bobStat.begin()->feeLevel ==
FeeLevel64{7000 * 256 / 10});
857 BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker());
876 checkMetrics(__LINE__, env, 1, 8, 5, 4, 256, 700 * 256);
887 checkMetrics(__LINE__, env, 8, 8, 5, 4, 257, 700 * 256);
893 checkMetrics(__LINE__, env, 1, 10, 6, 5, 256, 700 * 256);
899 checkMetrics(__LINE__, env, 0, 12, 1, 6, 256, 800 * 256);
911 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
919 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
931 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
934 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
938 checkMetrics(__LINE__, env, 2, std::nullopt, 3, 2, 256);
948 auto seqAlice = env.
seq(alice);
949 for (
int i = 0; i < 4; ++i)
952 feeAlice = (feeAlice + 1) * 125 / 100;
958 auto const seqBob = env.
seq(bob);
963 auto feeCarol = feeAlice;
964 auto seqCarol = env.
seq(carol);
965 for (
int i = 0; i < 4; ++i)
968 feeCarol = (feeCarol + 1) * 125 / 100;
1004 using namespace jtx;
1009 auto alice =
Account(
"alice");
1031 using namespace jtx;
1034 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
1036 auto alice =
Account(
"alice");
1041 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1045 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
1049 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
1053 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
1057 auto const& jt = env.
jt(
noop(alice));
1071 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
1082 using namespace jtx;
1088 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1089 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1091 auto alice =
Account(
"alice");
1093 auto charlie =
Account(
"charlie");
1094 auto daria =
Account(
"daria");
1100 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1103 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1108 checkMetrics(__LINE__, env, 0, initQueueMax, 4, 3, 256);
1112 checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1114 auto aliceSeq = env.
seq(alice);
1115 auto bobSeq = env.
seq(bob);
1116 auto charlieSeq = env.
seq(charlie);
1120 checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1124 checkMetrics(__LINE__, env, 2, initQueueMax, 4, 3, 256);
1128 checkMetrics(__LINE__, env, 3, initQueueMax, 4, 3, 256);
1132 checkMetrics(__LINE__, env, 4, initQueueMax, 4, 3, 256);
1136 checkMetrics(__LINE__, env, 5, initQueueMax, 4, 3, 256);
1141 checkMetrics(__LINE__, env, 6, initQueueMax, 4, 3, 256);
1161 aliceSeq = env.
seq(alice);
1162 auto lastLedgerSeq = env.
current()->info().seq + 2;
1163 for (
auto i = 0; i < 7; i++)
1167 json(jss::LastLedgerSequence, lastLedgerSeq + i),
1177 auto const& baseFee = env.
current()->fees().base;
1178 auto seq = env.
seq(alice);
1180 for (
auto const& tx : aliceStat)
1187 (tx.consequences.fee() ==
drops(aliceFee) &&
1188 tx.consequences.potentialSpend() ==
drops(0) &&
1189 !tx.consequences.isBlocker()) ||
1190 tx.seqProxy.value() == env.
seq(alice) + 6);
1200 json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1233 aliceSeq = env.
seq(alice) + 2;
1252 aliceSeq = env.
seq(alice) + 1;
1259 env.
le(alice)->getFieldAmount(sfBalance).xrp().drops() - (62);
1302 bobSeq = env.
seq(bob);
1304 for (
int i = 0; i < 10; ++i)
1319 env.
le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10 - 1);
1333 env.
le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10);
1352 using namespace jtx;
1356 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"4"}}));
1358 auto alice =
Account(
"alice");
1360 auto charlie =
Account(
"charlie");
1361 auto daria =
Account(
"daria");
1371 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 4, 256);
1375 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 4, 256);
1397 auto aliceSeq = env.
seq(alice);
1398 auto bobSeq = env.
seq(bob);
1399 auto charlieSeq = env.
seq(charlie);
1400 auto dariaSeq = env.
seq(daria);
1401 auto elmoSeq = env.
seq(elmo);
1402 auto fredSeq = env.
seq(fred);
1403 auto gwenSeq = env.
seq(gwen);
1404 auto hankSeq = env.
seq(hank);
1445 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1446 gwenSeq + hankSeq + 6 ==
1447 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1448 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1450 using namespace std::string_literals;
1452 aliceSeq == env.
seq(alice),
1456 bobSeq + 1 == env.
seq(bob),
1460 charlieSeq + 2 == env.
seq(charlie),
1464 dariaSeq + 1 == env.
seq(daria),
1468 elmoSeq + 1 == env.
seq(elmo),
1472 fredSeq == env.
seq(fred),
1476 gwenSeq == env.
seq(gwen),
1480 hankSeq + 1 == env.
seq(hank),
1495 auto getTxsQueued = [&]() {
1498 for (
auto const& tx : txs)
1500 ++
result[tx.txn->at(sfAccount)];
1504 auto qTxCount1 = getTxsQueued();
1509 seq(aliceSeq + qTxCount1[alice.id()]++),
1514 seq(charlieSeq + qTxCount1[charlie.id()]++),
1518 seq(dariaSeq + qTxCount1[daria.id()]++),
1531 seq(aliceSeq + qTxCount1[alice.id()]++),
1543 auto qTxCount2 = getTxsQueued();
1549 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1550 gwenSeq + hankSeq + 7 ==
1551 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1552 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1555 aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] ==
1560 bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.
seq(bob),
1564 charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] ==
1569 dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] ==
1574 elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] ==
1579 fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] ==
1584 gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] ==
1589 hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] ==
1598 using namespace jtx;
1601 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"1"}}));
1603 auto alice =
Account(
"alice");
1607 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 1, 256);
1610 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 1, 256);
1613 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1619 json(R
"({"AccountTxnID": "0"})"),
1622 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1637 using namespace jtx;
1638 using namespace std::string_literals;
1645 {{
"minimum_txn_in_ledger_standalone",
"2"},
1646 {
"minimum_txn_in_ledger",
"5"},
1647 {
"target_txn_in_ledger",
"4"},
1648 {
"maximum_txn_in_ledger",
"5"}}));
1650 auto alice =
Account(
"alice");
1652 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1655 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 2, 256);
1657 for (
int i = 0; i < 10; ++i)
1660 checkMetrics(__LINE__, env, 0, std::nullopt, 11, 2, 256);
1672 {{
"minimum_txn_in_ledger",
"200"},
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) exceeds "
1685 "the maximum number of low-fee transactions allowed per "
1686 "ledger (maximum_txn_in_ledger)."s);
1693 {{
"minimum_txn_in_ledger",
"200"},
1694 {
"minimum_txn_in_ledger_standalone",
"2"},
1695 {
"target_txn_in_ledger",
"4"},
1696 {
"maximum_txn_in_ledger",
"5"}}));
1704 "The minimum number of low-fee transactions allowed "
1705 "per ledger (minimum_txn_in_ledger) exceeds "
1706 "the maximum number of low-fee transactions allowed per "
1707 "ledger (maximum_txn_in_ledger)."s);
1714 {{
"minimum_txn_in_ledger",
"2"},
1715 {
"minimum_txn_in_ledger_standalone",
"200"},
1716 {
"target_txn_in_ledger",
"4"},
1717 {
"maximum_txn_in_ledger",
"5"}}));
1725 "The minimum number of low-fee transactions allowed "
1726 "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1727 "the maximum number of low-fee transactions allowed per "
1728 "ledger (maximum_txn_in_ledger)."s);
1735 using namespace jtx;
1736 testcase(
"unexpected balance change");
1741 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1742 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1744 auto alice =
Account(
"alice");
1750 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1754 checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
1758 checkMetrics(__LINE__, env, 0, initQueueMax, 2, 3, 256);
1759 auto USD = bob[
"USD"];
1762 checkMetrics(__LINE__, env, 0, initQueueMax, 3, 3, 256);
1773 auto aliceSeq = env.
seq(alice);
1817 for (
int i = 0; i < 9; ++i)
1832 using namespace jtx;
1835 auto alice =
Account(
"alice");
1837 auto charlie =
Account(
"charlie");
1838 auto daria =
Account(
"daria");
1842 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1846 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1850 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1858 env(
regkey(alice, charlie));
1859 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1862 auto const aliceSeq = env.
seq(alice);
1878 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1885 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
1897 auto const aliceSeq = env.
seq(alice);
1912 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1938 auto const aliceSeq = env.
seq(alice);
1962 using namespace jtx;
1965 auto alice =
Account(
"alice");
1967 auto charlie =
Account(
"charlie");
1968 auto daria =
Account(
"daria");
1972 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1976 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1981 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1991 env(
regkey(alice, charlie));
1992 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1995 auto const aliceSeq = env.
seq(alice);
2011 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
2015 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
2022 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
2039 auto const aliceSeq = env.
seq(alice);
2064 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
2124 using namespace jtx;
2125 testcase(
"In-flight balance checks");
2130 {{
"minimum_txn_in_ledger_standalone",
"3"}},
2131 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
2133 auto alice =
Account(
"alice");
2134 auto charlie =
Account(
"charlie");
2145 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
2149 checkMetrics(__LINE__, env, 0, initQueueMax, 0, limit, 256);
2152 checkMetrics(__LINE__, env, 0, initQueueMax, limit + 1, limit, 256);
2154 auto USD = gw[
"USD"];
2155 auto BUX = gw[
"BUX"];
2159 auto aliceSeq = env.
seq(alice);
2160 auto aliceBal = env.
balance(alice);
2167 checkMetrics(__LINE__, env, 1, initQueueMax, limit + 1, limit, 256);
2172 checkMetrics(__LINE__, env, 2, initQueueMax, limit + 1, limit, 256);
2176 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2188 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2189 aliceSeq = env.
seq(alice);
2190 aliceBal = env.
balance(alice);
2196 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2201 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2209 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2213 checkMetrics(__LINE__, env, 0, limit * 2, 3, limit, 256);
2225 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2226 aliceSeq = env.
seq(alice);
2227 aliceBal = env.
balance(alice);
2234 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2242 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2246 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2258 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2259 aliceSeq = env.
seq(alice);
2260 aliceBal = env.
balance(alice);
2268 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2272 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2284 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2286 aliceSeq = env.
seq(alice);
2287 aliceBal = env.
balance(alice);
2297 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2301 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2311 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2313 aliceSeq = env.
seq(alice);
2314 aliceBal = env.
balance(alice);
2322 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2326 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2334 auto const amount = USD(500000);
2335 env(
trust(alice, USD(50000000)));
2336 env(
trust(charlie, USD(50000000)));
2337 checkMetrics(__LINE__, env, 0, limit * 2, 4, limit, 256);
2342 env(
pay(gw, alice, amount));
2343 checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2349 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2351 aliceSeq = env.
seq(alice);
2352 aliceBal = env.
balance(alice);
2353 auto aliceUSD = env.
balance(alice, USD);
2357 env(
pay(alice, charlie, amount),
queued);
2362 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2366 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2380 env(
offer(gw,
XRP(500000), USD(50000)));
2386 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2388 aliceSeq = env.
seq(alice);
2389 aliceBal = env.
balance(alice);
2390 auto charlieUSD = env.
balance(charlie, USD);
2402 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2406 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2413 balance(charlie, charlieUSD + USD(1000)),
2421 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2423 aliceSeq = env.
seq(alice);
2424 aliceBal = env.
balance(alice);
2425 charlieUSD = env.
balance(charlie, USD);
2436 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2440 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2447 balance(charlie, charlieUSD + USD(500)),
2457 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2459 aliceSeq = env.
seq(alice);
2460 aliceBal = env.
balance(alice);
2467 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2471 checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2478 using namespace jtx;
2483 auto const alice =
Account(
"alice");
2502 auto USD = alice[
"USD"];
2544 using namespace jtx;
2545 testcase(
"acct in queue but empty");
2547 auto alice =
Account(
"alice");
2549 auto charlie =
Account(
"charlie");
2553 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2557 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
2561 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 3, 256);
2565 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
2569 checkMetrics(__LINE__, env, 0, std::nullopt, 5, 3, 256);
2573 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
2641 using namespace jtx;
2646 auto fee = env.
rpc(
"fee");
2653 result.isMember(jss::ledger_current_index) &&
2654 result[jss::ledger_current_index] == 3);
2666 auto const& levels =
result[jss::levels];
2682 result.isMember(jss::ledger_current_index) &&
2683 result[jss::ledger_current_index] == 4);
2694 auto const& levels =
result[jss::levels];
2716 using namespace jtx;
2717 testcase(
"expiration replacement");
2722 {{
"minimum_txn_in_ledger_standalone",
"1"},
2723 {
"ledgers_in_queue",
"10"},
2724 {
"maximum_txn_per_account",
"20"}}));
2727 auto const alice =
Account(
"alice");
2728 auto const bob =
Account(
"bob");
2731 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2733 auto const aliceSeq = env.
seq(alice);
2737 json(R
"({"LastLedgerSequence":5})"),
2741 json(R"({"LastLedgerSequence":5})"),
2745 json(R"({"LastLedgerSequence":10})"),
2749 json(R"({"LastLedgerSequence":11})"),
2751 checkMetrics(__LINE__, env, 4, std::nullopt, 2, 1, 256);
2752 auto const bobSeq = env.
seq(bob);
2756 for (
int i = 0; i < 3 + 4 + 5; ++i)
2760 checkMetrics(__LINE__, env, 4 + 3 + 4 + 5, std::nullopt, 2, 1, 256);
2814 using namespace jtx;
2815 testcase(
"full queue gap handling");
2820 {{
"minimum_txn_in_ledger_standalone",
"1"},
2821 {
"ledgers_in_queue",
"10"},
2822 {
"maximum_txn_per_account",
"11"}}));
2827 auto const alice =
Account(
"alice");
2828 auto const bob =
Account(
"bob");
2831 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2833 auto const aliceSeq = env.
seq(alice);
2844 json(R
"({"LastLedgerSequence":11})"),
2848 json(R"({"LastLedgerSequence":11})"),
2852 json(R"({"LastLedgerSequence":11})"),
2856 json(R"({"LastLedgerSequence":11})"),
2860 json(R"({"LastLedgerSequence":11})"),
2864 json(R"({"LastLedgerSequence": 5})"),
2868 json(R"({"LastLedgerSequence": 5})"),
2872 json(R"({"LastLedgerSequence": 5})"),
2876 json(R"({"LastLedgerSequence":11})"),
2878 checkMetrics(__LINE__, env, 10, std::nullopt, 2, 1, 256);
2880 auto const bobSeq = env.
seq(bob);
2884 for (
int i = 0; i < 2 + 4 + 5; ++i)
2888 checkMetrics(__LINE__, env, 10 + 2 + 4 + 5, std::nullopt, 2, 1, 256);
2971 testcase(
"Autofilled sequence should account for TxQ");
2972 using namespace jtx;
2973 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"6"}}));
2977 auto const alice =
Account(
"alice");
2978 auto const bob =
Account(
"bob");
2979 env.
fund(
XRP(100000), alice, bob);
2982 checkMetrics(__LINE__, env, 0, std::nullopt, 7, 6, 256);
2985 auto const aliceSeq = env.
seq(alice);
2986 auto const lastLedgerSeq = env.
current()->info().seq + 2;
2989 for (
int i = 0; i < 5; ++i)
2996 json(jss::LastLedgerSequence, lastLedgerSeq),
3002 checkMetrics(__LINE__, env, 5, std::nullopt, 7, 6, 256);
3004 auto aliceStat = txQ.getAccountTxs(alice.id());
3007 for (
auto const& tx : aliceStat)
3011 if (
seq.value() == aliceSeq + 2)
3014 tx.lastValid && *tx.lastValid == lastLedgerSeq);
3025 for (
int i = 0; i < 8; ++i)
3027 checkMetrics(__LINE__, env, 13, std::nullopt, 7, 6, 256);
3034 for (
int i = 0; i < 9; ++i)
3041 for (
int i = 0; i < 10; ++i)
3048 auto bobStat = txQ.getAccountTxs(bob.id());
3054 auto aliceStat = txQ.getAccountTxs(alice.id());
3055 auto seq = aliceSeq;
3057 for (
auto const& tx : aliceStat)
3060 if (
seq == aliceSeq + 2)
3073 auto aliceStat = txQ.getAccountTxs(alice.id());
3074 auto seq = aliceSeq;
3076 for (
auto const& tx : aliceStat)
3089 auto bobStat = txQ.getAccountTxs(bob.id());
3093 auto aliceStat = txQ.getAccountTxs(alice.id());
3101 using namespace jtx;
3104 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3108 env.
fund(
XRP(1000000), alice);
3111 auto const withQueue =
3112 R
"({ "account": ")" + alice.human() + R"(", "queue": true })";
3115 R"(", "queue": true, "ledger_index": 3 })";
3122 info.isMember(jss::result) &&
3123 info[jss::result].isMember(jss::account_data));
3128 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3130 info.isMember(jss::result) &&
3131 info[jss::result].isMember(jss::account_data));
3150 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3152 info.isMember(jss::result) &&
3153 info[jss::result].isMember(jss::account_data));
3154 auto const&
result = info[jss::result];
3175 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3177 info.isMember(jss::result) &&
3178 info[jss::result].isMember(jss::account_data));
3179 auto const&
result = info[jss::result];
3192 data[jss::Sequence].asUInt() +
3203 auto const& item =
queued[i];
3213 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3228 json(jss::LastLedgerSequence, 10),
3233 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3235 info.isMember(jss::result) &&
3236 info[jss::result].isMember(jss::account_data));
3237 auto const&
result = info[jss::result];
3238 auto const&
data =
result[jss::account_data];
3250 data[jss::Sequence].asUInt() +
3261 auto const& item =
queued[i];
3270 if (i ==
queued.size() - 1)
3278 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3289 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3291 info.isMember(jss::result) &&
3292 info[jss::result].isMember(jss::account_data));
3293 auto const&
result = info[jss::result];
3294 auto const&
data =
result[jss::account_data];
3306 data[jss::Sequence].asUInt() +
3317 auto const& item =
queued[i];
3321 if (i ==
queued.size() - 1)
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"}}));
3387 env.
fund(
XRP(1000000), alice);
3391 auto const server_info = env.
rpc(
"server_info");
3393 server_info.isMember(jss::result) &&
3394 server_info[jss::result].isMember(jss::info));
3395 auto const& info = server_info[jss::result][jss::info];
3397 info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
3401 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3404 auto const server_state = env.
rpc(
"server_state");
3405 auto const& state = server_state[jss::result][jss::state];
3407 state.isMember(jss::load_factor) &&
3408 state[jss::load_factor] == 256);
3410 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3412 state.isMember(jss::load_factor_server) &&
3413 state[jss::load_factor_server] == 256);
3415 state.isMember(jss::load_factor_fee_escalation) &&
3416 state[jss::load_factor_fee_escalation] == 256);
3418 state.isMember(jss::load_factor_fee_queue) &&
3419 state[jss::load_factor_fee_queue] == 256);
3421 state.isMember(jss::load_factor_fee_reference) &&
3422 state[jss::load_factor_fee_reference] == 256);
3430 auto aliceSeq = env.
seq(alice);
3432 for (
auto i = 0; i < 4; ++i)
3438 auto const server_info = env.
rpc(
"server_info");
3440 server_info.isMember(jss::result) &&
3441 server_info[jss::result].isMember(jss::info));
3442 auto const& info = server_info[jss::result][jss::info];
3445 info.isMember(jss::load_factor) &&
3446 info[jss::load_factor] > 888.88 &&
3447 info[jss::load_factor] < 888.89);
3449 info.isMember(jss::load_factor_server) &&
3450 info[jss::load_factor_server] == 1);
3454 info.isMember(jss::load_factor_fee_escalation) &&
3455 info[jss::load_factor_fee_escalation] > 888.88 &&
3456 info[jss::load_factor_fee_escalation] < 888.89);
3459 auto const server_state = env.
rpc(
"server_state");
3460 auto const& state = server_state[jss::result][jss::state];
3462 state.isMember(jss::load_factor) &&
3463 state[jss::load_factor] == 227555);
3465 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3467 state.isMember(jss::load_factor_server) &&
3468 state[jss::load_factor_server] == 256);
3470 state.isMember(jss::load_factor_fee_escalation) &&
3471 state[jss::load_factor_fee_escalation] == 227555);
3473 state.isMember(jss::load_factor_fee_queue) &&
3474 state[jss::load_factor_fee_queue] == 256);
3476 state.isMember(jss::load_factor_fee_reference) &&
3477 state[jss::load_factor_fee_reference] == 256);
3483 auto const server_info = env.
rpc(
"server_info");
3485 server_info.isMember(jss::result) &&
3486 server_info[jss::result].isMember(jss::info));
3487 auto const& info = server_info[jss::result][jss::info];
3490 info.isMember(jss::load_factor) &&
3491 info[jss::load_factor] == 1000);
3495 info.isMember(jss::load_factor_net) &&
3496 info[jss::load_factor_net] == 1000);
3498 info.isMember(jss::load_factor_fee_escalation) &&
3499 info[jss::load_factor_fee_escalation] > 888.88 &&
3500 info[jss::load_factor_fee_escalation] < 888.89);
3503 auto const server_state = env.
rpc(
"server_state");
3504 auto const& state = server_state[jss::result][jss::state];
3506 state.isMember(jss::load_factor) &&
3507 state[jss::load_factor] == 256000);
3509 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3511 state.isMember(jss::load_factor_server) &&
3512 state[jss::load_factor_server] == 256000);
3514 state.isMember(jss::load_factor_fee_escalation) &&
3515 state[jss::load_factor_fee_escalation] == 227555);
3517 state.isMember(jss::load_factor_fee_queue) &&
3518 state[jss::load_factor_fee_queue] == 256);
3520 state.isMember(jss::load_factor_fee_reference) &&
3521 state[jss::load_factor_fee_reference] == 256);
3527 for (
int i = 0; i < 5; ++i)
3532 auto const server_info = env.
rpc(
"server_info");
3534 server_info.isMember(jss::result) &&
3535 server_info[jss::result].isMember(jss::info));
3536 auto const& info = server_info[jss::result][jss::info];
3539 info.isMember(jss::load_factor) &&
3540 info[jss::load_factor] > 888.88 &&
3541 info[jss::load_factor] < 888.89);
3546 info.isMember(jss::load_factor_server) &&
3547 info[jss::load_factor_server] > 1.245 &&
3548 info[jss::load_factor_server] < 2.4415);
3550 info.isMember(jss::load_factor_local) &&
3551 info[jss::load_factor_local] > 1.245 &&
3552 info[jss::load_factor_local] < 2.4415);
3555 info.isMember(jss::load_factor_fee_escalation) &&
3556 info[jss::load_factor_fee_escalation] > 888.88 &&
3557 info[jss::load_factor_fee_escalation] < 888.89);
3560 auto const server_state = env.
rpc(
"server_state");
3561 auto const& state = server_state[jss::result][jss::state];
3563 state.isMember(jss::load_factor) &&
3564 state[jss::load_factor] == 227555);
3566 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3571 state.isMember(jss::load_factor_server) &&
3572 state[jss::load_factor_server] >= 320 &&
3573 state[jss::load_factor_server] <= 625);
3575 state.isMember(jss::load_factor_fee_escalation) &&
3576 state[jss::load_factor_fee_escalation] == 227555);
3578 state.isMember(jss::load_factor_fee_queue) &&
3579 state[jss::load_factor_fee_queue] == 256);
3581 state.isMember(jss::load_factor_fee_reference) &&
3582 state[jss::load_factor_fee_reference] == 256);
3588 auto const server_info = env.
rpc(
"server_info");
3590 server_info.isMember(jss::result) &&
3591 server_info[jss::result].isMember(jss::info));
3592 auto const& info = server_info[jss::result][jss::info];
3599 info.isMember(jss::load_factor) &&
3600 info[jss::load_factor] > 1.245 &&
3601 info[jss::load_factor] < 2.4415);
3604 info.isMember(jss::load_factor_local) &&
3605 info[jss::load_factor_local] > 1.245 &&
3606 info[jss::load_factor_local] < 2.4415);
3608 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3611 auto const server_state = env.
rpc(
"server_state");
3612 auto const& state = server_state[jss::result][jss::state];
3614 state.isMember(jss::load_factor) &&
3615 state[jss::load_factor] >= 320 &&
3616 state[jss::load_factor] <= 625);
3618 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3623 state.isMember(jss::load_factor_server) &&
3624 state[jss::load_factor_server] >= 320 &&
3625 state[jss::load_factor_server] <= 625);
3627 state.isMember(jss::load_factor_fee_escalation) &&
3628 state[jss::load_factor_fee_escalation] == 256);
3630 state.isMember(jss::load_factor_fee_queue) &&
3631 state[jss::load_factor_fee_queue] == 256);
3633 state.isMember(jss::load_factor_fee_reference) &&
3634 state[jss::load_factor_fee_reference] == 256);
3641 using namespace jtx;
3644 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3648 stream[jss::streams].append(
"server");
3651 auto jv = wsc->invoke(
"subscribe", stream);
3655 Account a{
"a"}, b{
"b"}, c{
"c"}, d{
"d"}, e{
"e"}, f{
"f"}, g{
"g"}, h{
"h"},
3660 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
3663 using namespace std::chrono_literals;
3665 return jv[jss::type] ==
"serverStatus" &&
3666 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3667 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3668 jv.isMember(jss::load_factor_server) &&
3669 jv[jss::load_factor_server] == 256 &&
3670 jv.isMember(jss::load_factor_fee_escalation) &&
3671 jv[jss::load_factor_fee_escalation] == 256 &&
3672 jv.isMember(jss::load_factor_fee_queue) &&
3673 jv[jss::load_factor_fee_queue] == 256 &&
3674 jv.isMember(jss::load_factor_fee_reference) &&
3675 jv[jss::load_factor_fee_reference] == 256;
3679 return jv[jss::type] ==
"serverStatus" &&
3680 jv.isMember(jss::load_factor) &&
3681 jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3682 jv[jss::load_base] == 256 &&
3683 jv.isMember(jss::load_factor_server) &&
3684 jv[jss::load_factor_server] == 256 &&
3685 jv.isMember(jss::load_factor_fee_escalation) &&
3686 jv[jss::load_factor_fee_escalation] == 227555 &&
3687 jv.isMember(jss::load_factor_fee_queue) &&
3688 jv[jss::load_factor_fee_queue] == 256 &&
3689 jv.isMember(jss::load_factor_fee_reference) &&
3690 jv[jss::load_factor_fee_reference] == 256;
3697 return jv[jss::type] ==
"serverStatus" &&
3698 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3699 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3700 jv.isMember(jss::load_factor_server) &&
3701 jv[jss::load_factor_server] == 256 &&
3702 jv.isMember(jss::load_factor_fee_escalation) &&
3703 jv[jss::load_factor_fee_escalation] == 256 &&
3704 jv.isMember(jss::load_factor_fee_queue) &&
3705 jv[jss::load_factor_fee_queue] == 256 &&
3706 jv.isMember(jss::load_factor_fee_reference) &&
3707 jv[jss::load_factor_fee_reference] == 256;
3728 return jv[jss::type] ==
"serverStatus" &&
3729 jv.isMember(jss::load_factor) &&
3730 jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3731 jv[jss::load_base] == 256 &&
3732 jv.isMember(jss::load_factor_server) &&
3733 jv[jss::load_factor_server] == 256 &&
3734 jv.isMember(jss::load_factor_fee_escalation) &&
3735 jv[jss::load_factor_fee_escalation] == 200000 &&
3736 jv.isMember(jss::load_factor_fee_queue) &&
3737 jv[jss::load_factor_fee_queue] == 256 &&
3738 jv.isMember(jss::load_factor_fee_reference) &&
3739 jv[jss::load_factor_fee_reference] == 256;
3745 return jv[jss::type] ==
"serverStatus" &&
3746 jv.isMember(jss::load_factor) &&
3747 jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3748 jv[jss::load_base] == 256 &&
3749 jv.isMember(jss::load_factor_server) &&
3750 jv[jss::load_factor_server] == 256 &&
3751 jv.isMember(jss::load_factor_fee_escalation) &&
3752 jv[jss::load_factor_fee_escalation] == 184320 &&
3753 jv.isMember(jss::load_factor_fee_queue) &&
3754 jv[jss::load_factor_fee_queue] == 256 &&
3755 jv.isMember(jss::load_factor_fee_reference) &&
3756 jv[jss::load_factor_fee_reference] == 256;
3762 return jv[jss::type] ==
"serverStatus" &&
3763 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3764 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3765 jv.isMember(jss::load_factor_server) &&
3766 jv[jss::load_factor_server] == 256 &&
3767 jv.isMember(jss::load_factor_fee_escalation) &&
3768 jv[jss::load_factor_fee_escalation] == 256 &&
3769 jv.isMember(jss::load_factor_fee_queue) &&
3770 jv[jss::load_factor_fee_queue] == 256 &&
3771 jv.isMember(jss::load_factor_fee_reference) &&
3772 jv[jss::load_factor_fee_reference] == 256;
3776 return jv[jss::type] ==
"serverStatus";
3779 auto jv = wsc->invoke(
"unsubscribe", stream);
3786 using namespace jtx;
3789 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3790 auto alice =
Account(
"alice");
3793 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
3794 env.
fund(
XRP(50000000), alice, bob);
3801 auto totalFactor = 0;
3804 numToClear.emplace(metrics.txCount + 1);
3805 for (
int i = 0; i < *numToClear; ++i)
3808 totalFactor += inLedger * inLedger;
3811 metrics.medFeeLevel * totalFactor /
3812 (metrics.txPerLedger * metrics.txPerLedger),
3822 testcase(
"straightfoward positive case");
3825 auto aliceSeq = env.
seq(alice);
3826 for (
int i = 0; i < 2; ++i)
3839 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
3852 checkMetrics(__LINE__, env, 4, std::nullopt, 4, 3, 256);
3857 calcTotalFee(100 * 2 + 8889 + 60911);
3860 env(
noop(alice),
fee(totalFee2),
seq(aliceSeq++));
3862 checkMetrics(__LINE__, env, 0, std::nullopt, 9, 3, 256);
3865 testcase(
"replace last tx with enough to clear queue");
3868 auto aliceSeq = env.
seq(alice);
3869 for (
int i = 0; i < 2; ++i)
3882 checkMetrics(__LINE__, env, 3, std::nullopt, 9, 3, 256);
3888 calcTotalFee(100 * 2, metrics.txCount);
3892 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3895 checkMetrics(__LINE__, env, 0, std::nullopt, 12, 3, 256);
3901 testcase(
"replace middle tx with enough to clear queue");
3905 auto aliceSeq = env.
seq(alice);
3906 for (
int i = 0; i < 5; ++i)
3918 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3921 auto const aliceQueue =
3925 for (
auto const& tx : aliceQueue)
3937 testcase(
"clear queue failure (load)");
3941 auto aliceSeq = env.
seq(alice);
3942 for (
int i = 0; i < 2; ++i)
3946 for (
int i = 0; i < 2; ++i)
3955 std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
3960 feeTrack.setRemoteFee(origFee * 5);
3973 feeTrack.setRemoteFee(origFee);
3992 using namespace jtx;
3993 using namespace std::chrono_literals;
4000 {{
"minimum_txn_in_ledger_standalone",
"3"},
4001 {
"normal_consensus_increase_percent",
"25"},
4002 {
"slow_consensus_decrease_percent",
"50"},
4003 {
"target_txn_in_ledger",
"10"},
4004 {
"maximum_txn_per_account",
"200"}}));
4005 auto alice =
Account(
"alice");
4007 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4008 env.
fund(
XRP(50000000), alice);
4011 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4012 auto seqAlice = env.
seq(alice);
4014 for (
int i = 0; i < txCount; ++i)
4016 checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4058 env.
close(env.
now() + 5s, 10000ms);
4063 env.
close(env.
now() + 5s, 10000ms);
4068 env.
close(env.
now() + 5s, 10000ms);
4075 env.
close(env.
now() + 5s, 10000ms);
4086 {{
"minimum_txn_in_ledger_standalone",
"3"},
4087 {
"normal_consensus_increase_percent",
"150"},
4088 {
"slow_consensus_decrease_percent",
"150"},
4089 {
"target_txn_in_ledger",
"10"},
4090 {
"maximum_txn_per_account",
"200"}}));
4091 auto alice =
Account(
"alice");
4093 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4094 env.
fund(
XRP(50000000), alice);
4097 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4098 auto seqAlice = env.
seq(alice);
4100 for (
int i = 0; i < txCount; ++i)
4102 checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4119 env.
close(env.
now() + 5s, 10000ms);
4140 testcase(
"Sequence in queue and open ledger");
4141 using namespace jtx;
4143 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4145 auto const alice =
Account(
"alice");
4151 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4155 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4158 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4161 auto const aliceSeq = env.
seq(alice);
4163 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4179 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4185 checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4190 checkMetrics(__LINE__, env, 3, std::nullopt, 6, 3, 256);
4207 testcase(
"Ticket in queue and open ledger");
4208 using namespace jtx;
4210 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4212 auto alice =
Account(
"alice");
4218 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4222 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4230 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4235 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4243 auto const tx = env.
jt(
4251 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4258 checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4264 checkMetrics(__LINE__, env, 1, std::nullopt, 7, 3, 256);
4269 checkMetrics(__LINE__, env, 2, std::nullopt, 7, 3, 256);
4285 checkMetrics(__LINE__, env, 2, std::nullopt, 8, 3, 256);
4304 using namespace jtx;
4314 {{
"minimum_txn_in_ledger_standalone",
"1"},
4315 {
"ledgers_in_queue",
"5"},
4316 {
"maximum_txn_per_account",
"10"}},
4317 {{
"account_reserve",
"1000"}, {
"owner_reserve",
"50"}});
4319 Env env(*
this, std::move(cfg));
4321 env.fund(
XRP(10000), alice);
4323 env.fund(
XRP(10000), bob);
4325 env.fund(
XRP(10000), carol);
4327 env.fund(
XRP(10000), daria);
4329 env.fund(
XRP(10000), ellie);
4331 env.fund(
XRP(10000), fiona);
4337 for (i = 0; i <= 257; ++i)
4345 __LINE__, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger, 256);
4350 using namespace std::chrono_literals;
4351 auto closeDuration = 80min;
4352 for (i = 0; i <= 255; ++i)
4353 env.close(closeDuration);
4361 5 * expectedPerLedger,
4362 expectedPerLedger + 1,
4367 auto seqAlice = env.seq(alice);
4368 auto seqBob = env.seq(bob);
4369 auto seqCarol = env.seq(carol);
4370 auto seqDaria = env.seq(daria);
4371 auto seqEllie = env.seq(ellie);
4372 auto seqFiona = env.seq(fiona);
4375 for (
int i = 0; i < 10; ++i)
4389 5 * expectedPerLedger,
4390 expectedPerLedger + 1,
4405 env.close(closeDuration);
4406 auto expectedInLedger = expectedInQueue;
4408 (expectedInQueue > expectedPerLedger + 2
4409 ? expectedInQueue - (expectedPerLedger + 2)
4411 expectedInLedger -= expectedInQueue;
4412 ++expectedPerLedger;
4417 5 * expectedPerLedger,
4422 auto const expectedPerAccount = expectedInQueue / 6;
4423 auto const expectedRemainder = expectedInQueue % 6;
4424 BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4427 seqBob - expectedPerAccount -
4428 (expectedRemainder > 4 ? 1 : 0));
4431 seqCarol - expectedPerAccount -
4432 (expectedRemainder > 3 ? 1 : 0));
4435 seqDaria - expectedPerAccount -
4436 (expectedRemainder > 2 ? 1 : 0));
4439 seqEllie - expectedPerAccount -
4440 (expectedRemainder > 1 ? 1 : 0));
4443 seqFiona - expectedPerAccount -
4444 (expectedRemainder > 0 ? 1 : 0));
4446 }
while (expectedInQueue > 0);
4459 testcase(
"Queue full drop penalty");
4460 using namespace jtx;
4476 int const medFee = 100;
4477 int const hiFee = 1000;
4480 {{
"minimum_txn_in_ledger_standalone",
"5"},
4481 {
"ledgers_in_queue",
"5"},
4482 {
"maximum_txn_per_account",
"30"},
4483 {
"minimum_queue_size",
"50"}});
4485 Env env(*
this, std::move(cfg));
4489 env.fund(
XRP(10000),
noripple(alice, bob, carol, daria, ellie, fiona));
4505 auto seqAlice = env.seq(alice);
4506 auto const seqSaveAlice = seqAlice;
4511 json(R
"({"LastLedgerSequence": 7})"),
4521 json(R
"({"LastLedgerSequence": 7})"),
4534 auto seqCarol = env.seq(carol);
4535 auto seqDaria = env.seq(daria);
4536 auto seqEllie = env.seq(ellie);
4537 auto seqFiona = env.seq(fiona);
4539 for (
int i = 0; i < 7; ++i)
4553 for (
int i = 0; i < 3; ++i)
4566 for (
int i = 0; i < 3; ++i)
4587 for (
int i = 0; i < 4; ++i)
4606 for (
int i = 0; i < 30; ++i)
4607 env.app().getFeeTrack().raiseLocalFee();
4617 while (env.app().getFeeTrack().lowerLocalFee())
4643 seqAlice = seqSaveAlice;
4690 using namespace jtx;
4694 auto USD = gw[
"USD"];
4697 {{
"minimum_txn_in_ledger_standalone",
"5"},
4698 {
"ledgers_in_queue",
"5"},
4699 {
"maximum_txn_per_account",
"30"},
4700 {
"minimum_queue_size",
"50"}});
4702 Env env(*
this, std::move(cfg));
4714 auto const aliceSeq = env.seq(alice);
4717 env(
offer(alice, USD(1000),
XRP(1001)),
4723 env(
offer(alice, USD(1000),
XRP(1002)),
4725 json(jss::OfferSequence, aliceSeq),
4741 auto const aliceTkt = env.seq(alice);
4749 auto const aliceSeq = env.seq(alice);
4750 env(
offer(alice, USD(1000),
XRP(1000)),
4754 env(
offer(alice, USD(1000),
XRP(1001)),
4764 env(
offer(alice, USD(1000),
XRP(1002)),
4766 json(jss::OfferSequence, aliceTkt + 4),
4776 env(
offer(alice, USD(1000),
XRP(1001)),
4781 env(
offer(alice, USD(1000),
XRP(1002)),
4783 json(jss::OfferSequence, aliceSeq),
4803 using namespace jtx;
4811 {{
"minimum_txn_in_ledger_standalone",
"3"}},
4812 {{
"reference_fee",
"0"},
4813 {
"account_reserve",
"0"},
4814 {
"owner_reserve",
"0"}}));
4818 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4821 auto const initQueueMax =
initFee(env, 3, 2, 0, 0, 0);
4826 auto const fee = env.
rpc(
"fee");
4834 auto const& levels =
result[jss::levels];
4836 levels.isMember(jss::median_level) &&
4837 levels[jss::median_level] ==
"128000");
4839 levels.isMember(jss::minimum_level) &&
4840 levels[jss::minimum_level] ==
"256");
4842 levels.isMember(jss::open_ledger_level) &&
4843 levels[jss::open_ledger_level] ==
"256");
4845 levels.isMember(jss::reference_level) &&
4846 levels[jss::reference_level] ==
"256");
4850 drops.isMember(jss::base_fee) &&
4851 drops[jss::base_fee] ==
"0");
4853 drops.isMember(jss::median_fee) &&
4854 drops[jss::median_fee] ==
"0");
4856 drops.isMember(jss::minimum_fee) &&
4857 drops[jss::minimum_fee] ==
"0");
4859 drops.isMember(jss::open_ledger_fee) &&
4860 drops[jss::open_ledger_fee] ==
"0");
4864 checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
4870 checkMetrics(__LINE__, env, 0, initQueueMax, 1, 3, 256);
4884 auto aliceSeq = env.
seq(alice);
4894 auto const fee = env.
rpc(
"fee");
4902 auto const& levels =
result[jss::levels];
4904 levels.isMember(jss::median_level) &&
4905 levels[jss::median_level] ==
"128000");
4907 levels.isMember(jss::minimum_level) &&
4908 levels[jss::minimum_level] ==
"256");
4910 levels.isMember(jss::open_ledger_level) &&
4911 levels[jss::open_ledger_level] ==
"355555");
4913 levels.isMember(jss::reference_level) &&
4914 levels[jss::reference_level] ==
"256");
4918 drops.isMember(jss::base_fee) &&
4919 drops[jss::base_fee] ==
"0");
4921 drops.isMember(jss::median_fee) &&
4922 drops[jss::median_fee] ==
"0");
4924 drops.isMember(jss::minimum_fee) &&
4925 drops[jss::minimum_fee] ==
"0");
4927 drops.isMember(jss::open_ledger_fee) &&
4928 drops[jss::open_ledger_fee] ==
"1389");
4990BEAST_DEFINE_TESTSUITE_PRIO(TxQPosNegFlows, app,
ripple, 1);
4991BEAST_DEFINE_TESTSUITE_PRIO(TxQMetaInfo, app,
ripple, 1);
A generic endpoint for log messages.
void pass()
Record a successful test condition.
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.
checkMetrics(__LINE__, env, 0, 8, 4, 4, 256)
BEAST_EXPECT(queue_data[jss::highest_sequence]==data[jss::Sequence].asUInt()+queue_data[jss::txn_count].asUInt() - 1)
envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams)
envs(noop(alice), fee(100), seq(none), ter(telCAN_NOT_QUEUE_BLOCKED))(submitParams)
envs(fset(alice, asfAccountTxnID), fee(100), seq(none), json(jss::LastLedgerSequence, 10), ter(terQUEUED))(submitParams)
void testSignAndSubmitSequence()
void testQueueFullDropPenalty()
BEAST_EXPECT(queue_data[jss::txn_count]==0)
void testFullQueueGapFill()
void testServerSubscribe()
auto const prevLedgerWithQueue
checkMetrics(__LINE__, env, 1, 8, 5, 4, 256)
BEAST_EXPECT(queue_data.isObject())
BEAST_EXPECT(!queue_data.isMember(jss::transactions))
static std::unique_ptr< Config > makeConfig(std::map< std::string, std::string > extraTxQ={}, std::map< std::string, std::string > extraVoting={})
void checkMetrics(int line, 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, std::uint64_t expectedMedFeeLevel=256 *500)
void testZeroReferenceFee()
void testInFlightBalance()
void testInLedgerTicket()
checkMetrics(__LINE__, env, 0, 6, 4, 3, 256)
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()
BEAST_EXPECT(queue_data.isMember(jss::transactions))
BEAST_EXPECT(queue_data[jss::max_spend_drops_total]=="100")
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])
checkMetrics(__LINE__, env, 0, 6, 0, 3, 256)
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)
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])
checkMetrics(__LINE__, env, 0, 10, 0, 5, 256)
void testFailInPreclaim()
BEAST_EXPECT(queue_data[jss::max_spend_drops_total]=="400")
BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued))
checkMetrics(__LINE__, env, 4, 6, 4, 3, 256)
BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence))
void testClearQueuedAccountTxs()
auto openLedgerFee(jtx::Env &env)
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))
checkMetrics(__LINE__, env, 0, 10, 2, 5, 256)
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::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
void require(Args const &... args)
Check a set of requirements.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
void postconditions(JTx const &jt, ParsedResult const &parsed, Json::Value const &jr=Json::Value())
Check expected postconditions of JTx submission.
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
NetClock::time_point now()
Returns the current network time.
beast::Journal const journal
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
void memoize(Account const &account)
Associate AccountID with account.
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Match the number of items in the account's owner directory.
Check a set of conditions.
Sets the SendMax on a JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
Set a ticket sequence on a JTx.
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
std::size_t numUpVotedAmendments()
Amendments that this server will vote for by default.
Json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
owner_count< ltRIPPLE_STATE > lines
Match the number of trust lines in the account's owner directory.
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Json::Value signers(Account const &account, std::uint32_t quorum, std::vector< signer > const &v)
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Json::Value noop(Account const &account)
The null transaction.
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)
FeeLevel64 referenceFeeLevel
Reference transaction fee level.
std::size_t txInLedger
Number of transactions currently in the open ledger.
Used by parseResult() and postConditions()
Set the sequence number on a JTx.