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/basics/Log.h>
30#include <xrpl/protocol/ErrorCodes.h>
31#include <xrpl/protocol/jss.h>
32#include <xrpl/protocol/st.h>
51 FeeLevel64 const expectedMin{expectedMinFeeLevel};
52 FeeLevel64 const expectedMed{expectedMedFeeLevel};
54 using namespace std::string_literals;
65 metrics.txCount == expectedCount
73 metrics.txQMaxSize == expectedMaxCount
82 metrics.txInLedger == expectedInLedger
90 metrics.txPerLedger == expectedPerLedger
98 metrics.minProcessingFeeLevel == expectedMin
101 "minProcessingFeeLevel: "s +
107 metrics.medFeeLevel == expectedMed
116 auto const expectedCurFeeLevel = expectedInLedger > expectedPerLedger
117 ? expectedMed * expectedInLedger * expectedInLedger /
118 (expectedPerLedger * expectedPerLedger)
119 : metrics.referenceFeeLevel;
121 metrics.openLedgerFeeLevel == expectedCurFeeLevel
124 "openLedgerFeeLevel: "s +
135 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
144 auto const& view = *env.
current();
146 auto const base = [&view]() {
147 auto base = view.fees().base;
154 return fee(
toDrops(metrics.openLedgerFeeLevel, base) + 1);
163 auto& section = p->section(
"transaction_queue");
164 section.set(
"ledgers_in_queue",
"2");
165 section.set(
"minimum_queue_size",
"2");
166 section.set(
"min_ledgers_to_compute_size_limit",
"3");
167 section.set(
"max_ledger_counts_to_store",
"100");
168 section.set(
"retry_sequence_percent",
"25");
169 section.set(
"normal_consensus_increase_percent",
"0");
171 for (
auto const& [k, v] : extraTxQ)
176 if (!extraVoting.
empty())
178 auto& votingSection = p->section(
"voting");
179 for (
auto const& [k, v] : extraVoting)
181 votingSection.set(k, v);
185 p->section(
"validation_seed")
186 .legacy(
"shUwVw52ofnCUX5m7kPTKzJdr4HEH");
204 for (
auto i = env.
current()->seq(); i <= 257; ++i)
211 auto const flagMaxQueue = ledgersInQueue * flagPerLedger;
212 checkMetrics(__LINE__, env, 0, flagMaxQueue, 0, flagPerLedger, 256);
221 using namespace std::chrono_literals;
223 checkMetrics(__LINE__, env, 0, flagMaxQueue, 0, expectedPerLedger, 256);
224 auto const fees = env.
current()->fees();
240 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
244 auto charlie =
Account(
"charlie");
256 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
260 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
264 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
268 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
272 checkMetrics(__LINE__, env, 2, std::nullopt, 5, 3, 256);
390 checkMetrics(__LINE__, env, 2, 8, 5, 4, 256, 256 * 700);
426 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
440 metrics.txPerLedger + 1,
451 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
459 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
466 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
478 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
708 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
712 auto USD = gw[
"USD"];
714 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
718 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
745 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
749 auto charlie =
Account(
"charlie");
755 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
759 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
766 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
770 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
774 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
778 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
782 checkMetrics(__LINE__, env, 2, std::nullopt, 4, 2, 256);
786 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 2, 256);
802 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
806 auto charlie =
Account(
"charlie");
809 auto felicia =
Account(
"felicia");
813 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
823 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
827 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
832 json(R
"({"LastLedgerSequence":7})"),
842 checkMetrics(__LINE__, env, 5, std::nullopt, 3, 2, 256);
849 aliceStat.begin()->lastValid &&
850 *aliceStat.begin()->lastValid == 8);
851 BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker());
853 auto bobStat = txQ.getAccountTxs(bob.id());
856 bobStat.begin()->feeLevel ==
FeeLevel64{7000 * 256 / 10});
858 BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker());
877 checkMetrics(__LINE__, env, 1, 8, 5, 4, 256, 700 * 256);
888 checkMetrics(__LINE__, env, 8, 8, 5, 4, 257, 700 * 256);
894 checkMetrics(__LINE__, env, 1, 10, 6, 5, 256, 700 * 256);
900 checkMetrics(__LINE__, env, 0, 12, 1, 6, 256, 800 * 256);
912 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
920 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
932 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
935 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
939 checkMetrics(__LINE__, env, 2, std::nullopt, 3, 2, 256);
949 auto seqAlice = env.
seq(alice);
950 for (
int i = 0; i < 4; ++i)
953 feeAlice = (feeAlice + 1) * 125 / 100;
959 auto const seqBob = env.
seq(bob);
964 auto feeCarol = feeAlice;
965 auto seqCarol = env.
seq(carol);
966 for (
int i = 0; i < 4; ++i)
969 feeCarol = (feeCarol + 1) * 125 / 100;
1005 using namespace jtx;
1010 auto alice =
Account(
"alice");
1032 using namespace jtx;
1035 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
1037 auto alice =
Account(
"alice");
1042 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1046 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
1050 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
1054 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
1058 auto const& jt = env.
jt(
noop(alice));
1072 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
1083 using namespace jtx;
1089 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1090 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1092 auto alice =
Account(
"alice");
1094 auto charlie =
Account(
"charlie");
1095 auto daria =
Account(
"daria");
1101 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1104 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1109 checkMetrics(__LINE__, env, 0, initQueueMax, 4, 3, 256);
1113 checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1115 auto aliceSeq = env.
seq(alice);
1116 auto bobSeq = env.
seq(bob);
1117 auto charlieSeq = env.
seq(charlie);
1121 checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1125 checkMetrics(__LINE__, env, 2, initQueueMax, 4, 3, 256);
1129 checkMetrics(__LINE__, env, 3, initQueueMax, 4, 3, 256);
1133 checkMetrics(__LINE__, env, 4, initQueueMax, 4, 3, 256);
1137 checkMetrics(__LINE__, env, 5, initQueueMax, 4, 3, 256);
1142 checkMetrics(__LINE__, env, 6, initQueueMax, 4, 3, 256);
1162 aliceSeq = env.
seq(alice);
1163 auto lastLedgerSeq = env.
current()->info().seq + 2;
1164 for (
auto i = 0; i < 7; i++)
1168 json(jss::LastLedgerSequence, lastLedgerSeq + i),
1178 auto const& baseFee = env.
current()->fees().base;
1179 auto seq = env.
seq(alice);
1181 for (
auto const& tx : aliceStat)
1188 (tx.consequences.fee() ==
drops(aliceFee) &&
1189 tx.consequences.potentialSpend() ==
drops(0) &&
1190 !tx.consequences.isBlocker()) ||
1191 tx.seqProxy.value() == env.
seq(alice) + 6);
1201 json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1234 aliceSeq = env.
seq(alice) + 2;
1253 aliceSeq = env.
seq(alice) + 1;
1260 env.
le(alice)->getFieldAmount(sfBalance).xrp().drops() - (62);
1303 bobSeq = env.
seq(bob);
1305 for (
int i = 0; i < 10; ++i)
1320 env.
le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10 - 1);
1334 env.
le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10);
1353 using namespace jtx;
1357 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"4"}}));
1359 auto alice =
Account(
"alice");
1361 auto charlie =
Account(
"charlie");
1362 auto daria =
Account(
"daria");
1372 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 4, 256);
1376 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 4, 256);
1398 auto aliceSeq = env.
seq(alice);
1399 auto bobSeq = env.
seq(bob);
1400 auto charlieSeq = env.
seq(charlie);
1401 auto dariaSeq = env.
seq(daria);
1402 auto elmoSeq = env.
seq(elmo);
1403 auto fredSeq = env.
seq(fred);
1404 auto gwenSeq = env.
seq(gwen);
1405 auto hankSeq = env.
seq(hank);
1446 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1447 gwenSeq + hankSeq + 6 ==
1448 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1449 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1451 using namespace std::string_literals;
1453 aliceSeq == env.
seq(alice),
1457 bobSeq + 1 == env.
seq(bob),
1461 charlieSeq + 2 == env.
seq(charlie),
1465 dariaSeq + 1 == env.
seq(daria),
1469 elmoSeq + 1 == env.
seq(elmo),
1473 fredSeq == env.
seq(fred),
1477 gwenSeq == env.
seq(gwen),
1481 hankSeq + 1 == env.
seq(hank),
1496 auto getTxsQueued = [&]() {
1499 for (
auto const& tx : txs)
1501 ++
result[tx.txn->at(sfAccount)];
1505 auto qTxCount1 = getTxsQueued();
1510 seq(aliceSeq + qTxCount1[alice.id()]++),
1515 seq(charlieSeq + qTxCount1[charlie.id()]++),
1519 seq(dariaSeq + qTxCount1[daria.id()]++),
1532 seq(aliceSeq + qTxCount1[alice.id()]++),
1544 auto qTxCount2 = getTxsQueued();
1550 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1551 gwenSeq + hankSeq + 7 ==
1552 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1553 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1556 aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] ==
1561 bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.
seq(bob),
1565 charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] ==
1570 dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] ==
1575 elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] ==
1580 fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] ==
1585 gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] ==
1590 hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] ==
1599 using namespace jtx;
1602 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"1"}}));
1604 auto alice =
Account(
"alice");
1608 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 1, 256);
1611 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 1, 256);
1614 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1620 json(R
"({"AccountTxnID": "0"})"),
1623 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1638 using namespace jtx;
1639 using namespace std::string_literals;
1646 {{
"minimum_txn_in_ledger_standalone",
"2"},
1647 {
"minimum_txn_in_ledger",
"5"},
1648 {
"target_txn_in_ledger",
"4"},
1649 {
"maximum_txn_in_ledger",
"5"}}));
1651 auto alice =
Account(
"alice");
1653 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1656 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 2, 256);
1658 for (
int i = 0; i < 10; ++i)
1661 checkMetrics(__LINE__, env, 0, std::nullopt, 11, 2, 256);
1673 {{
"minimum_txn_in_ledger",
"200"},
1674 {
"minimum_txn_in_ledger_standalone",
"200"},
1675 {
"target_txn_in_ledger",
"4"},
1676 {
"maximum_txn_in_ledger",
"5"}}));
1684 "The minimum number of low-fee transactions allowed "
1685 "per ledger (minimum_txn_in_ledger) exceeds "
1686 "the maximum number of low-fee transactions allowed per "
1687 "ledger (maximum_txn_in_ledger)."s);
1694 {{
"minimum_txn_in_ledger",
"200"},
1695 {
"minimum_txn_in_ledger_standalone",
"2"},
1696 {
"target_txn_in_ledger",
"4"},
1697 {
"maximum_txn_in_ledger",
"5"}}));
1705 "The minimum number of low-fee transactions allowed "
1706 "per ledger (minimum_txn_in_ledger) exceeds "
1707 "the maximum number of low-fee transactions allowed per "
1708 "ledger (maximum_txn_in_ledger)."s);
1715 {{
"minimum_txn_in_ledger",
"2"},
1716 {
"minimum_txn_in_ledger_standalone",
"200"},
1717 {
"target_txn_in_ledger",
"4"},
1718 {
"maximum_txn_in_ledger",
"5"}}));
1726 "The minimum number of low-fee transactions allowed "
1727 "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1728 "the maximum number of low-fee transactions allowed per "
1729 "ledger (maximum_txn_in_ledger)."s);
1736 using namespace jtx;
1737 testcase(
"unexpected balance change");
1742 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1743 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1745 auto alice =
Account(
"alice");
1751 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1755 checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
1759 checkMetrics(__LINE__, env, 0, initQueueMax, 2, 3, 256);
1760 auto USD = bob[
"USD"];
1763 checkMetrics(__LINE__, env, 0, initQueueMax, 3, 3, 256);
1774 auto aliceSeq = env.
seq(alice);
1818 for (
int i = 0; i < 9; ++i)
1833 using namespace jtx;
1836 auto alice =
Account(
"alice");
1838 auto charlie =
Account(
"charlie");
1839 auto daria =
Account(
"daria");
1843 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1847 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1851 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1859 env(
regkey(alice, charlie));
1860 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1863 auto const aliceSeq = env.
seq(alice);
1879 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1886 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
1898 auto const aliceSeq = env.
seq(alice);
1913 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
1939 auto const aliceSeq = env.
seq(alice);
1963 using namespace jtx;
1966 auto alice =
Account(
"alice");
1968 auto charlie =
Account(
"charlie");
1969 auto daria =
Account(
"daria");
1973 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1977 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1982 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1992 env(
regkey(alice, charlie));
1993 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1996 auto const aliceSeq = env.
seq(alice);
2012 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
2016 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
2023 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
2040 auto const aliceSeq = env.
seq(alice);
2065 env(
signers(alice, 2, {{bob}, {charlie}, {daria}}),
2125 using namespace jtx;
2126 testcase(
"In-flight balance checks");
2131 {{
"minimum_txn_in_ledger_standalone",
"3"}},
2132 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
2134 auto alice =
Account(
"alice");
2135 auto charlie =
Account(
"charlie");
2146 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
2150 checkMetrics(__LINE__, env, 0, initQueueMax, 0, limit, 256);
2153 checkMetrics(__LINE__, env, 0, initQueueMax, limit + 1, limit, 256);
2155 auto USD = gw[
"USD"];
2156 auto BUX = gw[
"BUX"];
2160 auto aliceSeq = env.
seq(alice);
2161 auto aliceBal = env.
balance(alice);
2168 checkMetrics(__LINE__, env, 1, initQueueMax, limit + 1, limit, 256);
2173 checkMetrics(__LINE__, env, 2, initQueueMax, limit + 1, limit, 256);
2177 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2189 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2190 aliceSeq = env.
seq(alice);
2191 aliceBal = env.
balance(alice);
2197 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2202 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2210 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2214 checkMetrics(__LINE__, env, 0, limit * 2, 3, limit, 256);
2226 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2227 aliceSeq = env.
seq(alice);
2228 aliceBal = env.
balance(alice);
2235 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2243 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2247 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2259 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2260 aliceSeq = env.
seq(alice);
2261 aliceBal = env.
balance(alice);
2269 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2273 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2285 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2287 aliceSeq = env.
seq(alice);
2288 aliceBal = env.
balance(alice);
2298 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2302 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2312 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2314 aliceSeq = env.
seq(alice);
2315 aliceBal = env.
balance(alice);
2323 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2327 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2335 auto const amount = USD(500000);
2336 env(
trust(alice, USD(50000000)));
2337 env(
trust(charlie, USD(50000000)));
2338 checkMetrics(__LINE__, env, 0, limit * 2, 4, limit, 256);
2343 env(
pay(gw, alice, amount));
2344 checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2350 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2352 aliceSeq = env.
seq(alice);
2353 aliceBal = env.
balance(alice);
2354 auto aliceUSD = env.
balance(alice, USD);
2358 env(
pay(alice, charlie, amount),
queued);
2363 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2367 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2381 env(
offer(gw,
XRP(500000), USD(50000)));
2387 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2389 aliceSeq = env.
seq(alice);
2390 aliceBal = env.
balance(alice);
2391 auto charlieUSD = env.
balance(charlie, USD);
2403 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2407 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2414 balance(charlie, charlieUSD + USD(1000)),
2422 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2424 aliceSeq = env.
seq(alice);
2425 aliceBal = env.
balance(alice);
2426 charlieUSD = env.
balance(charlie, USD);
2437 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2441 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2448 balance(charlie, charlieUSD + USD(500)),
2458 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2460 aliceSeq = env.
seq(alice);
2461 aliceBal = env.
balance(alice);
2468 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2472 checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2479 using namespace jtx;
2484 auto const alice =
Account(
"alice");
2503 auto USD = alice[
"USD"];
2545 using namespace jtx;
2546 testcase(
"acct in queue but empty");
2548 auto alice =
Account(
"alice");
2550 auto charlie =
Account(
"charlie");
2554 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2558 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
2562 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 3, 256);
2566 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
2570 checkMetrics(__LINE__, env, 0, std::nullopt, 5, 3, 256);
2574 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
2642 using namespace jtx;
2647 auto fee = env.
rpc(
"fee");
2654 result.isMember(jss::ledger_current_index) &&
2655 result[jss::ledger_current_index] == 3);
2667 auto const& levels =
result[jss::levels];
2683 result.isMember(jss::ledger_current_index) &&
2684 result[jss::ledger_current_index] == 4);
2695 auto const& levels =
result[jss::levels];
2717 using namespace jtx;
2718 testcase(
"expiration replacement");
2723 {{
"minimum_txn_in_ledger_standalone",
"1"},
2724 {
"ledgers_in_queue",
"10"},
2725 {
"maximum_txn_per_account",
"20"}}));
2728 auto const alice =
Account(
"alice");
2729 auto const bob =
Account(
"bob");
2732 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2734 auto const aliceSeq = env.
seq(alice);
2738 json(R
"({"LastLedgerSequence":5})"),
2742 json(R"({"LastLedgerSequence":5})"),
2746 json(R"({"LastLedgerSequence":10})"),
2750 json(R"({"LastLedgerSequence":11})"),
2752 checkMetrics(__LINE__, env, 4, std::nullopt, 2, 1, 256);
2753 auto const bobSeq = env.
seq(bob);
2757 for (
int i = 0; i < 3 + 4 + 5; ++i)
2761 checkMetrics(__LINE__, env, 4 + 3 + 4 + 5, std::nullopt, 2, 1, 256);
2815 using namespace jtx;
2816 testcase(
"full queue gap handling");
2821 {{
"minimum_txn_in_ledger_standalone",
"1"},
2822 {
"ledgers_in_queue",
"10"},
2823 {
"maximum_txn_per_account",
"11"}}));
2828 auto const alice =
Account(
"alice");
2829 auto const bob =
Account(
"bob");
2832 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2834 auto const aliceSeq = env.
seq(alice);
2845 json(R
"({"LastLedgerSequence":11})"),
2849 json(R"({"LastLedgerSequence":11})"),
2853 json(R"({"LastLedgerSequence":11})"),
2857 json(R"({"LastLedgerSequence":11})"),
2861 json(R"({"LastLedgerSequence":11})"),
2865 json(R"({"LastLedgerSequence": 5})"),
2869 json(R"({"LastLedgerSequence": 5})"),
2873 json(R"({"LastLedgerSequence": 5})"),
2877 json(R"({"LastLedgerSequence":11})"),
2879 checkMetrics(__LINE__, env, 10, std::nullopt, 2, 1, 256);
2881 auto const bobSeq = env.
seq(bob);
2885 for (
int i = 0; i < 2 + 4 + 5; ++i)
2889 checkMetrics(__LINE__, env, 10 + 2 + 4 + 5, std::nullopt, 2, 1, 256);
2972 testcase(
"Autofilled sequence should account for TxQ");
2973 using namespace jtx;
2974 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"6"}}));
2978 auto const alice =
Account(
"alice");
2979 auto const bob =
Account(
"bob");
2980 env.
fund(
XRP(100000), alice, bob);
2983 checkMetrics(__LINE__, env, 0, std::nullopt, 7, 6, 256);
2986 auto const aliceSeq = env.
seq(alice);
2987 auto const lastLedgerSeq = env.
current()->info().seq + 2;
2990 for (
int i = 0; i < 5; ++i)
2997 json(jss::LastLedgerSequence, lastLedgerSeq),
3003 checkMetrics(__LINE__, env, 5, std::nullopt, 7, 6, 256);
3005 auto aliceStat = txQ.getAccountTxs(alice.id());
3008 for (
auto const& tx : aliceStat)
3012 if (
seq.value() == aliceSeq + 2)
3015 tx.lastValid && *tx.lastValid == lastLedgerSeq);
3026 for (
int i = 0; i < 8; ++i)
3028 checkMetrics(__LINE__, env, 13, std::nullopt, 7, 6, 256);
3035 for (
int i = 0; i < 9; ++i)
3042 for (
int i = 0; i < 10; ++i)
3049 auto bobStat = txQ.getAccountTxs(bob.id());
3055 auto aliceStat = txQ.getAccountTxs(alice.id());
3056 auto seq = aliceSeq;
3058 for (
auto const& tx : aliceStat)
3061 if (
seq == aliceSeq + 2)
3074 auto aliceStat = txQ.getAccountTxs(alice.id());
3075 auto seq = aliceSeq;
3077 for (
auto const& tx : aliceStat)
3090 auto bobStat = txQ.getAccountTxs(bob.id());
3094 auto aliceStat = txQ.getAccountTxs(alice.id());
3102 using namespace jtx;
3105 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3109 env.
fund(
XRP(1000000), alice);
3112 auto const withQueue =
3113 R
"({ "account": ")" + alice.human() + R"(", "queue": true })";
3116 R"(", "queue": true, "ledger_index": 3 })";
3123 info.isMember(jss::result) &&
3124 info[jss::result].isMember(jss::account_data));
3129 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3131 info.isMember(jss::result) &&
3132 info[jss::result].isMember(jss::account_data));
3151 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3153 info.isMember(jss::result) &&
3154 info[jss::result].isMember(jss::account_data));
3155 auto const&
result = info[jss::result];
3176 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3178 info.isMember(jss::result) &&
3179 info[jss::result].isMember(jss::account_data));
3180 auto const&
result = info[jss::result];
3193 data[jss::Sequence].asUInt() +
3204 auto const& item =
queued[i];
3214 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3229 json(jss::LastLedgerSequence, 10),
3234 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3236 info.isMember(jss::result) &&
3237 info[jss::result].isMember(jss::account_data));
3238 auto const&
result = info[jss::result];
3239 auto const&
data =
result[jss::account_data];
3251 data[jss::Sequence].asUInt() +
3262 auto const& item =
queued[i];
3271 if (i ==
queued.size() - 1)
3279 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3290 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3292 info.isMember(jss::result) &&
3293 info[jss::result].isMember(jss::account_data));
3294 auto const&
result = info[jss::result];
3295 auto const&
data =
result[jss::account_data];
3307 data[jss::Sequence].asUInt() +
3318 auto const& item =
queued[i];
3322 if (i ==
queued.size() - 1)
3350 info.isMember(jss::result) &&
3360 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3362 info.isMember(jss::result) &&
3363 info[jss::result].isMember(jss::account_data));
3364 auto const&
result = info[jss::result];
3381 using namespace jtx;
3384 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
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)
3439 auto const server_info = env.
rpc(
"server_info");
3441 server_info.isMember(jss::result) &&
3442 server_info[jss::result].isMember(jss::info));
3443 auto const& info = server_info[jss::result][jss::info];
3446 info.isMember(jss::load_factor) &&
3447 info[jss::load_factor] > 888.88 &&
3448 info[jss::load_factor] < 888.89);
3450 info.isMember(jss::load_factor_server) &&
3451 info[jss::load_factor_server] == 1);
3455 info.isMember(jss::load_factor_fee_escalation) &&
3456 info[jss::load_factor_fee_escalation] > 888.88 &&
3457 info[jss::load_factor_fee_escalation] < 888.89);
3460 auto const server_state = env.
rpc(
"server_state");
3461 auto const& state = server_state[jss::result][jss::state];
3463 state.isMember(jss::load_factor) &&
3464 state[jss::load_factor] == 227555);
3466 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3468 state.isMember(jss::load_factor_server) &&
3469 state[jss::load_factor_server] == 256);
3471 state.isMember(jss::load_factor_fee_escalation) &&
3472 state[jss::load_factor_fee_escalation] == 227555);
3474 state.isMember(jss::load_factor_fee_queue) &&
3475 state[jss::load_factor_fee_queue] == 256);
3477 state.isMember(jss::load_factor_fee_reference) &&
3478 state[jss::load_factor_fee_reference] == 256);
3484 auto const server_info = env.
rpc(
"server_info");
3486 server_info.isMember(jss::result) &&
3487 server_info[jss::result].isMember(jss::info));
3488 auto const& info = server_info[jss::result][jss::info];
3491 info.isMember(jss::load_factor) &&
3492 info[jss::load_factor] == 1000);
3496 info.isMember(jss::load_factor_net) &&
3497 info[jss::load_factor_net] == 1000);
3499 info.isMember(jss::load_factor_fee_escalation) &&
3500 info[jss::load_factor_fee_escalation] > 888.88 &&
3501 info[jss::load_factor_fee_escalation] < 888.89);
3504 auto const server_state = env.
rpc(
"server_state");
3505 auto const& state = server_state[jss::result][jss::state];
3507 state.isMember(jss::load_factor) &&
3508 state[jss::load_factor] == 256000);
3510 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3512 state.isMember(jss::load_factor_server) &&
3513 state[jss::load_factor_server] == 256000);
3515 state.isMember(jss::load_factor_fee_escalation) &&
3516 state[jss::load_factor_fee_escalation] == 227555);
3518 state.isMember(jss::load_factor_fee_queue) &&
3519 state[jss::load_factor_fee_queue] == 256);
3521 state.isMember(jss::load_factor_fee_reference) &&
3522 state[jss::load_factor_fee_reference] == 256);
3528 for (
int i = 0; i < 5; ++i)
3533 auto const server_info = env.
rpc(
"server_info");
3535 server_info.isMember(jss::result) &&
3536 server_info[jss::result].isMember(jss::info));
3537 auto const& info = server_info[jss::result][jss::info];
3540 info.isMember(jss::load_factor) &&
3541 info[jss::load_factor] > 888.88 &&
3542 info[jss::load_factor] < 888.89);
3547 info.isMember(jss::load_factor_server) &&
3548 info[jss::load_factor_server] > 1.245 &&
3549 info[jss::load_factor_server] < 2.4415);
3551 info.isMember(jss::load_factor_local) &&
3552 info[jss::load_factor_local] > 1.245 &&
3553 info[jss::load_factor_local] < 2.4415);
3556 info.isMember(jss::load_factor_fee_escalation) &&
3557 info[jss::load_factor_fee_escalation] > 888.88 &&
3558 info[jss::load_factor_fee_escalation] < 888.89);
3561 auto const server_state = env.
rpc(
"server_state");
3562 auto const& state = server_state[jss::result][jss::state];
3564 state.isMember(jss::load_factor) &&
3565 state[jss::load_factor] == 227555);
3567 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3572 state.isMember(jss::load_factor_server) &&
3573 state[jss::load_factor_server] >= 320 &&
3574 state[jss::load_factor_server] <= 625);
3576 state.isMember(jss::load_factor_fee_escalation) &&
3577 state[jss::load_factor_fee_escalation] == 227555);
3579 state.isMember(jss::load_factor_fee_queue) &&
3580 state[jss::load_factor_fee_queue] == 256);
3582 state.isMember(jss::load_factor_fee_reference) &&
3583 state[jss::load_factor_fee_reference] == 256);
3589 auto const server_info = env.
rpc(
"server_info");
3591 server_info.isMember(jss::result) &&
3592 server_info[jss::result].isMember(jss::info));
3593 auto const& info = server_info[jss::result][jss::info];
3600 info.isMember(jss::load_factor) &&
3601 info[jss::load_factor] > 1.245 &&
3602 info[jss::load_factor] < 2.4415);
3605 info.isMember(jss::load_factor_local) &&
3606 info[jss::load_factor_local] > 1.245 &&
3607 info[jss::load_factor_local] < 2.4415);
3609 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3612 auto const server_state = env.
rpc(
"server_state");
3613 auto const& state = server_state[jss::result][jss::state];
3615 state.isMember(jss::load_factor) &&
3616 state[jss::load_factor] >= 320 &&
3617 state[jss::load_factor] <= 625);
3619 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3624 state.isMember(jss::load_factor_server) &&
3625 state[jss::load_factor_server] >= 320 &&
3626 state[jss::load_factor_server] <= 625);
3628 state.isMember(jss::load_factor_fee_escalation) &&
3629 state[jss::load_factor_fee_escalation] == 256);
3631 state.isMember(jss::load_factor_fee_queue) &&
3632 state[jss::load_factor_fee_queue] == 256);
3634 state.isMember(jss::load_factor_fee_reference) &&
3635 state[jss::load_factor_fee_reference] == 256);
3642 using namespace jtx;
3645 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3649 stream[jss::streams].append(
"server");
3652 auto jv = wsc->invoke(
"subscribe", stream);
3656 Account a{
"a"}, b{
"b"}, c{
"c"}, d{
"d"}, e{
"e"}, f{
"f"}, g{
"g"}, h{
"h"},
3661 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
3664 using namespace std::chrono_literals;
3666 return jv[jss::type] ==
"serverStatus" &&
3667 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3668 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3669 jv.isMember(jss::load_factor_server) &&
3670 jv[jss::load_factor_server] == 256 &&
3671 jv.isMember(jss::load_factor_fee_escalation) &&
3672 jv[jss::load_factor_fee_escalation] == 256 &&
3673 jv.isMember(jss::load_factor_fee_queue) &&
3674 jv[jss::load_factor_fee_queue] == 256 &&
3675 jv.isMember(jss::load_factor_fee_reference) &&
3676 jv[jss::load_factor_fee_reference] == 256;
3680 return jv[jss::type] ==
"serverStatus" &&
3681 jv.isMember(jss::load_factor) &&
3682 jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3683 jv[jss::load_base] == 256 &&
3684 jv.isMember(jss::load_factor_server) &&
3685 jv[jss::load_factor_server] == 256 &&
3686 jv.isMember(jss::load_factor_fee_escalation) &&
3687 jv[jss::load_factor_fee_escalation] == 227555 &&
3688 jv.isMember(jss::load_factor_fee_queue) &&
3689 jv[jss::load_factor_fee_queue] == 256 &&
3690 jv.isMember(jss::load_factor_fee_reference) &&
3691 jv[jss::load_factor_fee_reference] == 256;
3698 return jv[jss::type] ==
"serverStatus" &&
3699 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3700 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3701 jv.isMember(jss::load_factor_server) &&
3702 jv[jss::load_factor_server] == 256 &&
3703 jv.isMember(jss::load_factor_fee_escalation) &&
3704 jv[jss::load_factor_fee_escalation] == 256 &&
3705 jv.isMember(jss::load_factor_fee_queue) &&
3706 jv[jss::load_factor_fee_queue] == 256 &&
3707 jv.isMember(jss::load_factor_fee_reference) &&
3708 jv[jss::load_factor_fee_reference] == 256;
3729 return jv[jss::type] ==
"serverStatus" &&
3730 jv.isMember(jss::load_factor) &&
3731 jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3732 jv[jss::load_base] == 256 &&
3733 jv.isMember(jss::load_factor_server) &&
3734 jv[jss::load_factor_server] == 256 &&
3735 jv.isMember(jss::load_factor_fee_escalation) &&
3736 jv[jss::load_factor_fee_escalation] == 200000 &&
3737 jv.isMember(jss::load_factor_fee_queue) &&
3738 jv[jss::load_factor_fee_queue] == 256 &&
3739 jv.isMember(jss::load_factor_fee_reference) &&
3740 jv[jss::load_factor_fee_reference] == 256;
3746 return jv[jss::type] ==
"serverStatus" &&
3747 jv.isMember(jss::load_factor) &&
3748 jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3749 jv[jss::load_base] == 256 &&
3750 jv.isMember(jss::load_factor_server) &&
3751 jv[jss::load_factor_server] == 256 &&
3752 jv.isMember(jss::load_factor_fee_escalation) &&
3753 jv[jss::load_factor_fee_escalation] == 184320 &&
3754 jv.isMember(jss::load_factor_fee_queue) &&
3755 jv[jss::load_factor_fee_queue] == 256 &&
3756 jv.isMember(jss::load_factor_fee_reference) &&
3757 jv[jss::load_factor_fee_reference] == 256;
3763 return jv[jss::type] ==
"serverStatus" &&
3764 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3765 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3766 jv.isMember(jss::load_factor_server) &&
3767 jv[jss::load_factor_server] == 256 &&
3768 jv.isMember(jss::load_factor_fee_escalation) &&
3769 jv[jss::load_factor_fee_escalation] == 256 &&
3770 jv.isMember(jss::load_factor_fee_queue) &&
3771 jv[jss::load_factor_fee_queue] == 256 &&
3772 jv.isMember(jss::load_factor_fee_reference) &&
3773 jv[jss::load_factor_fee_reference] == 256;
3777 return jv[jss::type] ==
"serverStatus";
3780 auto jv = wsc->invoke(
"unsubscribe", stream);
3787 using namespace jtx;
3790 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3791 auto alice =
Account(
"alice");
3794 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
3795 env.
fund(
XRP(50000000), alice, bob);
3802 auto totalFactor = 0;
3805 numToClear.emplace(metrics.txCount + 1);
3806 for (
int i = 0; i < *numToClear; ++i)
3809 totalFactor += inLedger * inLedger;
3812 metrics.medFeeLevel * totalFactor /
3813 (metrics.txPerLedger * metrics.txPerLedger),
3823 testcase(
"straightfoward positive case");
3826 auto aliceSeq = env.
seq(alice);
3827 for (
int i = 0; i < 2; ++i)
3840 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
3853 checkMetrics(__LINE__, env, 4, std::nullopt, 4, 3, 256);
3858 calcTotalFee(100 * 2 + 8889 + 60911);
3861 env(
noop(alice),
fee(totalFee2),
seq(aliceSeq++));
3863 checkMetrics(__LINE__, env, 0, std::nullopt, 9, 3, 256);
3866 testcase(
"replace last tx with enough to clear queue");
3869 auto aliceSeq = env.
seq(alice);
3870 for (
int i = 0; i < 2; ++i)
3883 checkMetrics(__LINE__, env, 3, std::nullopt, 9, 3, 256);
3889 calcTotalFee(100 * 2, metrics.txCount);
3893 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3896 checkMetrics(__LINE__, env, 0, std::nullopt, 12, 3, 256);
3902 testcase(
"replace middle tx with enough to clear queue");
3906 auto aliceSeq = env.
seq(alice);
3907 for (
int i = 0; i < 5; ++i)
3919 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3922 auto const aliceQueue =
3926 for (
auto const& tx : aliceQueue)
3938 testcase(
"clear queue failure (load)");
3942 auto aliceSeq = env.
seq(alice);
3943 for (
int i = 0; i < 2; ++i)
3947 for (
int i = 0; i < 2; ++i)
3956 std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
3961 feeTrack.setRemoteFee(origFee * 5);
3974 feeTrack.setRemoteFee(origFee);
3993 using namespace jtx;
3994 using namespace std::chrono_literals;
4001 {{
"minimum_txn_in_ledger_standalone",
"3"},
4002 {
"normal_consensus_increase_percent",
"25"},
4003 {
"slow_consensus_decrease_percent",
"50"},
4004 {
"target_txn_in_ledger",
"10"},
4005 {
"maximum_txn_per_account",
"200"}}));
4006 auto alice =
Account(
"alice");
4008 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4009 env.
fund(
XRP(50000000), alice);
4012 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4013 auto seqAlice = env.
seq(alice);
4015 for (
int i = 0; i < txCount; ++i)
4017 checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4059 env.
close(env.
now() + 5s, 10000ms);
4064 env.
close(env.
now() + 5s, 10000ms);
4069 env.
close(env.
now() + 5s, 10000ms);
4076 env.
close(env.
now() + 5s, 10000ms);
4087 {{
"minimum_txn_in_ledger_standalone",
"3"},
4088 {
"normal_consensus_increase_percent",
"150"},
4089 {
"slow_consensus_decrease_percent",
"150"},
4090 {
"target_txn_in_ledger",
"10"},
4091 {
"maximum_txn_per_account",
"200"}}));
4092 auto alice =
Account(
"alice");
4094 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4095 env.
fund(
XRP(50000000), alice);
4098 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4099 auto seqAlice = env.
seq(alice);
4101 for (
int i = 0; i < txCount; ++i)
4103 checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4120 env.
close(env.
now() + 5s, 10000ms);
4141 testcase(
"Sequence in queue and open ledger");
4142 using namespace jtx;
4144 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4146 auto const alice =
Account(
"alice");
4152 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4156 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4159 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4162 auto const aliceSeq = env.
seq(alice);
4164 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4180 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4186 checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4191 checkMetrics(__LINE__, env, 3, std::nullopt, 6, 3, 256);
4208 testcase(
"Ticket in queue and open ledger");
4209 using namespace jtx;
4211 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4213 auto alice =
Account(
"alice");
4219 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4223 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4231 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4236 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4244 auto const tx = env.
jt(
4252 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4259 checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4265 checkMetrics(__LINE__, env, 1, std::nullopt, 7, 3, 256);
4270 checkMetrics(__LINE__, env, 2, std::nullopt, 7, 3, 256);
4286 checkMetrics(__LINE__, env, 2, std::nullopt, 8, 3, 256);
4305 using namespace jtx;
4315 {{
"minimum_txn_in_ledger_standalone",
"1"},
4316 {
"ledgers_in_queue",
"5"},
4317 {
"maximum_txn_per_account",
"10"}},
4318 {{
"account_reserve",
"1000"}, {
"owner_reserve",
"50"}});
4320 Env env(*
this, std::move(cfg));
4322 env.fund(
XRP(10000), alice);
4324 env.fund(
XRP(10000), bob);
4326 env.fund(
XRP(10000), carol);
4328 env.fund(
XRP(10000), daria);
4330 env.fund(
XRP(10000), ellie);
4332 env.fund(
XRP(10000), fiona);
4338 for (i = 0; i <= 257; ++i)
4346 __LINE__, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger, 256);
4351 using namespace std::chrono_literals;
4352 auto closeDuration = 80min;
4353 for (i = 0; i <= 255; ++i)
4354 env.close(closeDuration);
4362 5 * expectedPerLedger,
4363 expectedPerLedger + 1,
4368 auto seqAlice = env.seq(alice);
4369 auto seqBob = env.seq(bob);
4370 auto seqCarol = env.seq(carol);
4371 auto seqDaria = env.seq(daria);
4372 auto seqEllie = env.seq(ellie);
4373 auto seqFiona = env.seq(fiona);
4376 for (
int i = 0; i < 10; ++i)
4390 5 * expectedPerLedger,
4391 expectedPerLedger + 1,
4406 env.close(closeDuration);
4407 auto expectedInLedger = expectedInQueue;
4409 (expectedInQueue > expectedPerLedger + 2
4410 ? expectedInQueue - (expectedPerLedger + 2)
4412 expectedInLedger -= expectedInQueue;
4413 ++expectedPerLedger;
4418 5 * expectedPerLedger,
4423 auto const expectedPerAccount = expectedInQueue / 6;
4424 auto const expectedRemainder = expectedInQueue % 6;
4425 BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4428 seqBob - expectedPerAccount -
4429 (expectedRemainder > 4 ? 1 : 0));
4432 seqCarol - expectedPerAccount -
4433 (expectedRemainder > 3 ? 1 : 0));
4436 seqDaria - expectedPerAccount -
4437 (expectedRemainder > 2 ? 1 : 0));
4440 seqEllie - expectedPerAccount -
4441 (expectedRemainder > 1 ? 1 : 0));
4444 seqFiona - expectedPerAccount -
4445 (expectedRemainder > 0 ? 1 : 0));
4447 }
while (expectedInQueue > 0);
4460 testcase(
"Queue full drop penalty");
4461 using namespace jtx;
4477 int const medFee = 100;
4478 int const hiFee = 1000;
4481 {{
"minimum_txn_in_ledger_standalone",
"5"},
4482 {
"ledgers_in_queue",
"5"},
4483 {
"maximum_txn_per_account",
"30"},
4484 {
"minimum_queue_size",
"50"}});
4486 Env env(*
this, std::move(cfg));
4490 env.fund(
XRP(10000),
noripple(alice, bob, carol, daria, ellie, fiona));
4506 auto seqAlice = env.seq(alice);
4507 auto const seqSaveAlice = seqAlice;
4512 json(R
"({"LastLedgerSequence": 7})"),
4522 json(R
"({"LastLedgerSequence": 7})"),
4535 auto seqCarol = env.seq(carol);
4536 auto seqDaria = env.seq(daria);
4537 auto seqEllie = env.seq(ellie);
4538 auto seqFiona = env.seq(fiona);
4540 for (
int i = 0; i < 7; ++i)
4554 for (
int i = 0; i < 3; ++i)
4567 for (
int i = 0; i < 3; ++i)
4588 for (
int i = 0; i < 4; ++i)
4607 for (
int i = 0; i < 30; ++i)
4608 env.app().getFeeTrack().raiseLocalFee();
4618 while (env.app().getFeeTrack().lowerLocalFee())
4644 seqAlice = seqSaveAlice;
4691 using namespace jtx;
4695 auto USD = gw[
"USD"];
4698 {{
"minimum_txn_in_ledger_standalone",
"5"},
4699 {
"ledgers_in_queue",
"5"},
4700 {
"maximum_txn_per_account",
"30"},
4701 {
"minimum_queue_size",
"50"}});
4703 Env env(*
this, std::move(cfg));
4715 auto const aliceSeq = env.seq(alice);
4718 env(
offer(alice, USD(1000),
XRP(1001)),
4724 env(
offer(alice, USD(1000),
XRP(1002)),
4726 json(jss::OfferSequence, aliceSeq),
4742 auto const aliceTkt = env.seq(alice);
4750 auto const aliceSeq = env.seq(alice);
4751 env(
offer(alice, USD(1000),
XRP(1000)),
4755 env(
offer(alice, USD(1000),
XRP(1001)),
4765 env(
offer(alice, USD(1000),
XRP(1002)),
4767 json(jss::OfferSequence, aliceTkt + 4),
4777 env(
offer(alice, USD(1000),
XRP(1001)),
4782 env(
offer(alice, USD(1000),
XRP(1002)),
4784 json(jss::OfferSequence, aliceSeq),
4804 using namespace jtx;
4812 {{
"minimum_txn_in_ledger_standalone",
"3"}},
4813 {{
"reference_fee",
"0"},
4814 {
"account_reserve",
"0"},
4815 {
"owner_reserve",
"0"}}));
4819 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4822 auto const initQueueMax =
initFee(env, 3, 2, 0, 0, 0);
4827 auto const fee = env.
rpc(
"fee");
4835 auto const& levels =
result[jss::levels];
4837 levels.isMember(jss::median_level) &&
4838 levels[jss::median_level] ==
"128000");
4840 levels.isMember(jss::minimum_level) &&
4841 levels[jss::minimum_level] ==
"256");
4843 levels.isMember(jss::open_ledger_level) &&
4844 levels[jss::open_ledger_level] ==
"256");
4846 levels.isMember(jss::reference_level) &&
4847 levels[jss::reference_level] ==
"256");
4851 drops.isMember(jss::base_fee) &&
4852 drops[jss::base_fee] ==
"0");
4854 drops.isMember(jss::median_fee) &&
4855 drops[jss::median_fee] ==
"0");
4857 drops.isMember(jss::minimum_fee) &&
4858 drops[jss::minimum_fee] ==
"0");
4860 drops.isMember(jss::open_ledger_fee) &&
4861 drops[jss::open_ledger_fee] ==
"0");
4865 checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
4871 checkMetrics(__LINE__, env, 0, initQueueMax, 1, 3, 256);
4885 auto aliceSeq = env.
seq(alice);
4895 auto const fee = env.
rpc(
"fee");
4903 auto const& levels =
result[jss::levels];
4905 levels.isMember(jss::median_level) &&
4906 levels[jss::median_level] ==
"128000");
4908 levels.isMember(jss::minimum_level) &&
4909 levels[jss::minimum_level] ==
"256");
4911 levels.isMember(jss::open_ledger_level) &&
4912 levels[jss::open_ledger_level] ==
"355555");
4914 levels.isMember(jss::reference_level) &&
4915 levels[jss::reference_level] ==
"256");
4919 drops.isMember(jss::base_fee) &&
4920 drops[jss::base_fee] ==
"0");
4922 drops.isMember(jss::median_fee) &&
4923 drops[jss::median_fee] ==
"0");
4925 drops.isMember(jss::minimum_fee) &&
4926 drops[jss::minimum_fee] ==
"0");
4928 drops.isMember(jss::open_ledger_fee) &&
4929 drops[jss::open_ledger_fee] ==
"1389");
4991BEAST_DEFINE_TESTSUITE_PRIO(TxQPosNegFlows, app,
ripple, 1);
4992BEAST_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.