20 #include <ripple/app/main/Application.h>
21 #include <ripple/app/misc/LoadFeeTrack.h>
22 #include <ripple/app/misc/TxQ.h>
23 #include <ripple/app/tx/apply.h>
24 #include <ripple/basics/Log.h>
25 #include <ripple/basics/mulDiv.h>
26 #include <ripple/protocol/ErrorCodes.h>
27 #include <ripple/protocol/jss.h>
28 #include <ripple/protocol/st.h>
30 #include <test/jtx/TestSuite.h>
31 #include <test/jtx/WSClient.h>
32 #include <test/jtx/envconfig.h>
33 #include <test/jtx/ticket.h>
52 FeeLevel64 const expectedMin{expectedMinFeeLevel};
53 FeeLevel64 const expectedMed{expectedMedFeeLevel};
55 using namespace std::string_literals;
66 metrics.txCount == expectedCount
74 metrics.txQMaxSize == expectedMaxCount
83 metrics.txInLedger == expectedInLedger
91 metrics.txPerLedger == expectedPerLedger
99 metrics.minProcessingFeeLevel == expectedMin
102 "minProcessingFeeLevel: "s +
108 metrics.medFeeLevel == expectedMed
117 auto const expectedCurFeeLevel = expectedInLedger > expectedPerLedger
118 ? expectedMed * expectedInLedger * expectedInLedger /
119 (expectedPerLedger * expectedPerLedger)
120 : metrics.referenceFeeLevel;
122 metrics.openLedgerFeeLevel == expectedCurFeeLevel
125 "openLedgerFeeLevel: "s +
136 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
145 auto const& view = *env.
current();
149 return fee(
toDrops(metrics.openLedgerFeeLevel, view.fees().base) + 1);
158 auto& section = p->section(
"transaction_queue");
159 section.set(
"ledgers_in_queue",
"2");
160 section.set(
"minimum_queue_size",
"2");
161 section.set(
"min_ledgers_to_compute_size_limit",
"3");
162 section.set(
"max_ledger_counts_to_store",
"100");
163 section.set(
"retry_sequence_percent",
"25");
164 section.set(
"normal_consensus_increase_percent",
"0");
166 for (
auto const& [k, v] : extraTxQ)
171 if (!extraVoting.
empty())
173 auto& votingSection = p->section(
"voting");
174 for (
auto const& [k, v] : extraVoting)
176 votingSection.set(k, v);
180 p->section(
"validation_seed")
181 .legacy(
"shUwVw52ofnCUX5m7kPTKzJdr4HEH");
200 for (
auto i = env.
current()->seq(); i <= 257; ++i)
207 auto const flagMaxQueue = ledgersInQueue * flagPerLedger;
208 checkMetrics(__LINE__, env, 0, flagMaxQueue, 0, flagPerLedger, 256);
217 using namespace std::chrono_literals;
219 checkMetrics(__LINE__, env, 0, flagMaxQueue, 0, expectedPerLedger, 256);
220 auto const fees = env.
current()->fees();
235 testcase(
"queue sequence");
237 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
241 auto charlie =
Account(
"charlie");
253 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
257 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
261 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
265 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
269 checkMetrics(__LINE__, env, 2, std::nullopt, 5, 3, 256);
387 checkMetrics(__LINE__, env, 2, 8, 5, 4, 256, 256 * 700);
423 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
437 metrics.txPerLedger + 1,
446 testcase(
"queue ticket");
448 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
456 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
463 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
470 env(ticket::create(alice, 250),
seq(tkt1 - 1),
queued);
475 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
703 testcase(
"queue tec");
705 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
709 auto USD = gw[
"USD"];
711 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
715 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
740 testcase(
"local tx retry");
742 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
746 auto charlie =
Account(
"charlie");
752 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
756 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
763 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
767 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
771 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
775 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
779 checkMetrics(__LINE__, env, 2, std::nullopt, 4, 2, 256);
783 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 2, 256);
797 testcase(
"last ledger sequence");
799 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
803 auto charlie =
Account(
"charlie");
806 auto felicia =
Account(
"felicia");
810 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
820 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
824 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
829 json(R
"({"LastLedgerSequence":7})"),
839 checkMetrics(__LINE__, env, 5, std::nullopt, 3, 2, 256);
846 aliceStat.begin()->lastValid &&
847 *aliceStat.begin()->lastValid == 8);
848 BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker());
850 auto bobStat = txQ.getAccountTxs(bob.id());
853 bobStat.begin()->feeLevel ==
FeeLevel64{7000 * 256 / 10});
855 BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker());
874 checkMetrics(__LINE__, env, 1, 8, 5, 4, 256, 700 * 256);
885 checkMetrics(__LINE__, env, 8, 8, 5, 4, 257, 700 * 256);
891 checkMetrics(__LINE__, env, 1, 10, 6, 5, 256, 700 * 256);
897 checkMetrics(__LINE__, env, 0, 12, 1, 6, 256, 800 * 256);
907 testcase(
"zero transaction fee");
909 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
917 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
929 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
932 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
936 checkMetrics(__LINE__, env, 2, std::nullopt, 3, 2, 256);
946 auto seqAlice = env.
seq(alice);
947 for (
int i = 0; i < 4; ++i)
950 feeAlice = (feeAlice + 1) * 125 / 100;
956 auto const seqBob = env.
seq(bob);
961 auto feeCarol = feeAlice;
962 auto seqCarol = env.
seq(carol);
963 for (
int i = 0; i < 4; ++i)
966 feeCarol = (feeCarol + 1) * 125 / 100;
1002 using namespace jtx;
1005 testcase(
"fail in preclaim");
1007 auto alice =
Account(
"alice");
1026 using namespace jtx;
1027 testcase(
"queued tx fails");
1029 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
1031 auto alice =
Account(
"alice");
1036 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1040 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
1044 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
1048 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
1052 auto const& jt = env.
jt(
noop(alice));
1066 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
1077 using namespace jtx;
1078 testcase(
"multi tx per account");
1083 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1084 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1086 auto alice =
Account(
"alice");
1088 auto charlie =
Account(
"charlie");
1089 auto daria =
Account(
"daria");
1095 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1098 auto const initQueueMax =
initFee(env, 3, 2, 10, 10, 200, 50);
1103 checkMetrics(__LINE__, env, 0, initQueueMax, 4, 3, 256);
1107 checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1109 auto aliceSeq = env.
seq(alice);
1110 auto bobSeq = env.
seq(bob);
1111 auto charlieSeq = env.
seq(charlie);
1115 checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1119 checkMetrics(__LINE__, env, 2, initQueueMax, 4, 3, 256);
1123 checkMetrics(__LINE__, env, 3, initQueueMax, 4, 3, 256);
1127 checkMetrics(__LINE__, env, 4, initQueueMax, 4, 3, 256);
1131 checkMetrics(__LINE__, env, 5, initQueueMax, 4, 3, 256);
1136 checkMetrics(__LINE__, env, 6, initQueueMax, 4, 3, 256);
1156 aliceSeq = env.
seq(alice);
1157 auto lastLedgerSeq = env.
current()->info().seq + 2;
1158 for (
auto i = 0; i < 7; i++)
1162 json(jss::LastLedgerSequence, lastLedgerSeq + i),
1172 auto const& baseFee = env.
current()->fees().base;
1173 auto seq = env.
seq(alice);
1175 for (
auto const& tx : aliceStat)
1182 (tx.consequences.fee() ==
drops(aliceFee) &&
1183 tx.consequences.potentialSpend() ==
drops(0) &&
1184 !tx.consequences.isBlocker()) ||
1185 tx.seqProxy.value() == env.
seq(alice) + 6);
1195 json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1228 aliceSeq = env.
seq(alice) + 2;
1247 aliceSeq = env.
seq(alice) + 1;
1254 env.
le(alice)->getFieldAmount(
sfBalance).xrp().drops() - (62);
1297 bobSeq = env.
seq(bob);
1299 for (
int i = 0; i < 10; ++i)
1314 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10 - 1);
1328 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10);
1347 using namespace jtx;
1348 using namespace std::chrono;
1349 testcase("tie breaking");
1351 Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "4"}}));
1353 auto alice = Account("alice");
1354 auto bob = Account("bob");
1355 auto charlie = Account("charlie");
1356 auto daria = Account("daria");
1357 auto elmo = Account("elmo");
1358 auto fred = Account("fred");
1359 auto gwen = Account("gwen");
1360 auto hank = Account("hank");
1362 auto queued = ter(terQUEUED);
1364 BEAST_EXPECT(env.current()->fees().base == 10);
1366 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 4, 256);
1368 // Create several accounts while the fee is cheap so they all apply.
1369 env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
1370 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 4, 256);
1373 checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
1375 env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
1376 checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
1379 checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
1383 // Stuff the ledger and queue so we can verify that
1384 // stuff gets kicked out.
1390 checkMetrics(__LINE__, env, 0, 8, 5, 4, 256);
1392 auto aliceSeq = env.seq(alice);
1393 auto bobSeq = env.seq(bob);
1394 auto charlieSeq = env.seq(charlie);
1395 auto dariaSeq = env.seq(daria);
1396 auto elmoSeq = env.seq(elmo);
1397 auto fredSeq = env.seq(fred);
1398 auto gwenSeq = env.seq(gwen);
1399 auto hankSeq = env.seq(hank);
1401 // This time, use identical fees.
1403 // All of these get into the queue, but one gets dropped when the
1404 // higher fee one is added later. Which one depends on ordering.
1405 env(noop(alice), fee(15), queued);
1406 env(noop(bob), fee(15), queued);
1407 env(noop(charlie), fee(15), queued);
1408 env(noop(daria), fee(15), queued);
1409 env(noop(elmo), fee(15), queued);
1410 env(noop(fred), fee(15), queued);
1411 env(noop(gwen), fee(15), queued);
1412 env(noop(hank), fee(15), queued);
1414 // Queue is full now. Minimum fee now reflects the
1415 // lowest fee in the queue.
1416 checkMetrics(__LINE__, env, 8, 8, 5, 4, 385);
1418 // Try to add another transaction with the default (low) fee,
1419 // it should fail because it can't replace the one already
1440 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1441 gwenSeq + hankSeq + 6 ==
1442 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1443 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1445 using namespace std::string_literals;
1447 aliceSeq + 1 == env.
seq(alice),
1451 bobSeq + 1 == env.
seq(bob),
1455 charlieSeq + 2 == env.
seq(charlie),
1459 dariaSeq == env.
seq(daria),
1463 elmoSeq + 1 == env.
seq(elmo),
1467 fredSeq == env.
seq(fred),
1471 gwenSeq + 1 == env.
seq(gwen),
1475 hankSeq == env.
seq(hank),
1490 auto getTxsQueued = [&]() {
1493 for (
auto const& tx : txs)
1499 auto qTxCount1 = getTxsQueued();
1504 seq(aliceSeq + qTxCount1[alice.id()]++),
1507 env(noop(bob), seq(bobSeq + qTxCount1[bob.id()]++), fee(15),
queued);
1509 seq(charlieSeq + qTxCount1[charlie.id()]++),
1513 seq(dariaSeq + qTxCount1[daria.id()]++),
1516 env(noop(elmo), seq(elmoSeq + qTxCount1[elmo.id()]++), fee(15),
queued);
1517 env(noop(fred), seq(fredSeq + qTxCount1[fred.id()]++), fee(15),
queued);
1518 env(noop(gwen), seq(gwenSeq + qTxCount1[gwen.id()]++), fee(15),
queued);
1526 seq(aliceSeq + qTxCount1[alice.id()]++),
1538 auto qTxCount2 = getTxsQueued();
1544 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1545 gwenSeq + hankSeq + 7 ==
1546 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1547 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1550 aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] ==
1555 bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.
seq(bob),
1559 charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] ==
1564 dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] ==
1569 elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] ==
1574 fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] ==
1579 gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] ==
1584 hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] ==
1593 using namespace jtx;
1594 testcase(
"acct tx id");
1596 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"1"}}));
1598 auto alice =
Account(
"alice");
1602 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 1, 256);
1605 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 1, 256);
1608 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1614 json(R
"({"AccountTxnID": "0"})"),
1617 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1632 using namespace jtx;
1633 using namespace std::string_literals;
1634 testcase(
"maximum tx");
1640 {{
"minimum_txn_in_ledger_standalone",
"2"},
1641 {
"minimum_txn_in_ledger",
"5"},
1642 {
"target_txn_in_ledger",
"4"},
1643 {
"maximum_txn_in_ledger",
"5"}}));
1645 auto alice =
Account(
"alice");
1647 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1650 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 2, 256);
1652 for (
int i = 0; i < 10; ++i)
1655 checkMetrics(__LINE__, env, 0, std::nullopt, 11, 2, 256);
1667 {{
"minimum_txn_in_ledger",
"200"},
1668 {
"minimum_txn_in_ledger_standalone",
"200"},
1669 {
"target_txn_in_ledger",
"4"},
1670 {
"maximum_txn_in_ledger",
"5"}}));
1678 "The minimum number of low-fee transactions allowed "
1679 "per ledger (minimum_txn_in_ledger) exceeds "
1680 "the maximum number of low-fee transactions allowed per "
1681 "ledger (maximum_txn_in_ledger)."s);
1688 {{
"minimum_txn_in_ledger",
"200"},
1689 {
"minimum_txn_in_ledger_standalone",
"2"},
1690 {
"target_txn_in_ledger",
"4"},
1691 {
"maximum_txn_in_ledger",
"5"}}));
1699 "The minimum number of low-fee transactions allowed "
1700 "per ledger (minimum_txn_in_ledger) exceeds "
1701 "the maximum number of low-fee transactions allowed per "
1702 "ledger (maximum_txn_in_ledger)."s);
1709 {{
"minimum_txn_in_ledger",
"2"},
1710 {
"minimum_txn_in_ledger_standalone",
"200"},
1711 {
"target_txn_in_ledger",
"4"},
1712 {
"maximum_txn_in_ledger",
"5"}}));
1720 "The minimum number of low-fee transactions allowed "
1721 "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1722 "the maximum number of low-fee transactions allowed per "
1723 "ledger (maximum_txn_in_ledger)."s);
1730 using namespace jtx;
1731 testcase(
"unexpected balance change");
1736 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1737 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1739 auto alice =
Account(
"alice");
1745 auto const initQueueMax =
initFee(env, 3, 2, 10, 10, 200, 50);
1749 checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
1753 checkMetrics(__LINE__, env, 0, initQueueMax, 2, 3, 256);
1754 auto USD = bob[
"USD"];
1757 checkMetrics(__LINE__, env, 0, initQueueMax, 3, 3, 256);
1768 auto aliceSeq = env.
seq(alice);
1777 env(offer(bob,
drops(5000), USD(5000)),
1812 for (
int i = 0; i < 9; ++i)
1827 using namespace jtx;
1828 testcase(
"blockers sequence");
1830 auto alice =
Account(
"alice");
1832 auto charlie =
Account(
"charlie");
1833 auto daria =
Account(
"daria");
1837 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1841 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1845 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1853 env(
regkey(alice, charlie));
1854 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1857 auto const aliceSeq = env.
seq(alice);
1873 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1880 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
1892 auto const aliceSeq = env.
seq(alice);
1907 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1933 auto const aliceSeq = env.
seq(alice);
1957 using namespace jtx;
1958 testcase(
"blockers ticket");
1960 auto alice =
Account(
"alice");
1962 auto charlie =
Account(
"charlie");
1963 auto daria =
Account(
"daria");
1967 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1971 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1976 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1984 env(ticket::create(alice, 250),
seq(tkt - 1));
1986 env(
regkey(alice, charlie));
1987 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1990 auto const aliceSeq = env.
seq(alice);
2006 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2010 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2017 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
2034 auto const aliceSeq = env.
seq(alice);
2059 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2119 using namespace jtx;
2120 testcase(
"In-flight balance checks");
2125 {{
"minimum_txn_in_ledger_standalone",
"3"}},
2126 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
2128 auto alice =
Account(
"alice");
2129 auto charlie =
Account(
"charlie");
2140 auto const initQueueMax =
initFee(env, 3, 2, 10, 10, 200, 50);
2144 checkMetrics(__LINE__, env, 0, initQueueMax, 0, limit, 256);
2147 checkMetrics(__LINE__, env, 0, initQueueMax, limit + 1, limit, 256);
2149 auto USD = gw[
"USD"];
2150 auto BUX = gw[
"BUX"];
2154 auto aliceSeq = env.
seq(alice);
2155 auto aliceBal = env.
balance(alice);
2161 env(offer(alice, BUX(5000),
XRP(50000)),
queued);
2162 checkMetrics(__LINE__, env, 1, initQueueMax, limit + 1, limit, 256);
2167 checkMetrics(__LINE__, env, 2, initQueueMax, limit + 1, limit, 256);
2171 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2183 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2184 aliceSeq = env.
seq(alice);
2185 aliceBal = env.
balance(alice);
2191 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2196 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2204 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2208 checkMetrics(__LINE__, env, 0, limit * 2, 3, limit, 256);
2220 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2221 aliceSeq = env.
seq(alice);
2222 aliceBal = env.
balance(alice);
2229 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2237 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2241 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2253 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2254 aliceSeq = env.
seq(alice);
2255 aliceBal = env.
balance(alice);
2259 env(offer(alice, BUX(50),
XRP(500)),
queued);
2263 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2267 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2279 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2281 aliceSeq = env.
seq(alice);
2282 aliceBal = env.
balance(alice);
2292 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2296 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2306 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2308 aliceSeq = env.
seq(alice);
2309 aliceBal = env.
balance(alice);
2317 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2321 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2329 auto const amount = USD(500000);
2330 env(
trust(alice, USD(50000000)));
2331 env(
trust(charlie, USD(50000000)));
2332 checkMetrics(__LINE__, env, 0, limit * 2, 4, limit, 256);
2337 env(
pay(gw, alice, amount));
2338 checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2344 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2346 aliceSeq = env.
seq(alice);
2347 aliceBal = env.
balance(alice);
2348 auto aliceUSD = env.
balance(alice, USD);
2352 env(
pay(alice, charlie, amount),
queued);
2357 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2361 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2375 env(offer(gw,
XRP(500000), USD(50000)));
2381 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2383 aliceSeq = env.
seq(alice);
2384 aliceBal = env.
balance(alice);
2385 auto charlieUSD = env.
balance(charlie, USD);
2397 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2401 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2408 balance(charlie, charlieUSD + USD(1000)),
2416 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2418 aliceSeq = env.
seq(alice);
2419 aliceBal = env.
balance(alice);
2420 charlieUSD = env.
balance(charlie, USD);
2431 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2435 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2442 balance(charlie, charlieUSD + USD(500)),
2452 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2454 aliceSeq = env.
seq(alice);
2455 aliceBal = env.
balance(alice);
2462 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2466 checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2473 using namespace jtx;
2475 testcase(
"consequences");
2478 auto const alice =
Account(
"alice");
2497 auto USD = alice[
"USD"];
2514 auto const jtx = env.
jt(ticket::create(alice, 1),
seq(1),
fee(10));
2539 using namespace jtx;
2540 testcase(
"acct in queue but empty");
2542 auto alice =
Account(
"alice");
2544 auto charlie =
Account(
"charlie");
2548 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2552 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
2556 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 3, 256);
2560 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
2564 checkMetrics(__LINE__, env, 0, std::nullopt, 5, 3, 256);
2568 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
2636 using namespace jtx;
2641 auto fee = env.
rpc(
"fee");
2648 result.isMember(jss::ledger_current_index) &&
2649 result[jss::ledger_current_index] == 3);
2661 auto const& levels =
result[jss::levels];
2677 result.isMember(jss::ledger_current_index) &&
2678 result[jss::ledger_current_index] == 4);
2689 auto const& levels =
result[jss::levels];
2711 using namespace jtx;
2712 testcase(
"expiration replacement");
2717 {{
"minimum_txn_in_ledger_standalone",
"1"},
2718 {
"ledgers_in_queue",
"10"},
2719 {
"maximum_txn_per_account",
"20"}}));
2722 auto const alice =
Account(
"alice");
2723 auto const bob =
Account(
"bob");
2726 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2728 auto const aliceSeq = env.
seq(alice);
2732 json(R
"({"LastLedgerSequence":5})"),
2736 json(R"({"LastLedgerSequence":5})"),
2740 json(R"({"LastLedgerSequence":10})"),
2744 json(R"({"LastLedgerSequence":11})"),
2746 checkMetrics(__LINE__, env, 4, std::nullopt, 2, 1, 256);
2747 auto const bobSeq = env.
seq(bob);
2751 for (
int i = 0; i < 3 + 4 + 5; ++i)
2755 checkMetrics(__LINE__, env, 4 + 3 + 4 + 5, std::nullopt, 2, 1, 256);
2803 using namespace jtx;
2804 testcase(
"full queue gap handling");
2809 {{
"minimum_txn_in_ledger_standalone",
"1"},
2810 {
"ledgers_in_queue",
"10"},
2811 {
"maximum_txn_per_account",
"11"}}));
2816 auto const alice =
Account(
"alice");
2817 auto const bob =
Account(
"bob");
2820 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2822 auto const aliceSeq = env.
seq(alice);
2827 env(ticket::create(alice, 11),
2833 json(R
"({"LastLedgerSequence":11})"),
2837 json(R"({"LastLedgerSequence":11})"),
2841 json(R"({"LastLedgerSequence":11})"),
2845 json(R"({"LastLedgerSequence":11})"),
2849 json(R"({"LastLedgerSequence":11})"),
2853 json(R"({"LastLedgerSequence": 5})"),
2857 json(R"({"LastLedgerSequence": 5})"),
2861 json(R"({"LastLedgerSequence": 5})"),
2865 json(R"({"LastLedgerSequence":11})"),
2867 checkMetrics(__LINE__, env, 10, std::nullopt, 2, 1, 256);
2869 auto const bobSeq = env.
seq(bob);
2873 for (
int i = 0; i < 2 + 4 + 5; ++i)
2877 checkMetrics(__LINE__, env, 10 + 2 + 4 + 5, std::nullopt, 2, 1, 256);
2960 testcase(
"Autofilled sequence should account for TxQ");
2961 using namespace jtx;
2962 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"6"}}));
2966 auto const alice =
Account(
"alice");
2967 auto const bob =
Account(
"bob");
2968 env.
fund(
XRP(100000), alice, bob);
2971 checkMetrics(__LINE__, env, 0, std::nullopt, 7, 6, 256);
2974 auto const aliceSeq = env.
seq(alice);
2975 auto const lastLedgerSeq = env.
current()->info().seq + 2;
2978 for (
int i = 0; i < 5; ++i)
2985 json(jss::LastLedgerSequence, lastLedgerSeq),
2991 checkMetrics(__LINE__, env, 5, std::nullopt, 7, 6, 256);
2993 auto aliceStat = txQ.getAccountTxs(alice.id());
2996 for (
auto const& tx : aliceStat)
3000 if (
seq.value() == aliceSeq + 2)
3003 tx.lastValid && *tx.lastValid == lastLedgerSeq);
3014 for (
int i = 0; i < 8; ++i)
3016 checkMetrics(__LINE__, env, 13, std::nullopt, 7, 6, 256);
3023 for (
int i = 0; i < 9; ++i)
3030 for (
int i = 0; i < 10; ++i)
3037 auto bobStat = txQ.getAccountTxs(bob.id());
3043 auto aliceStat = txQ.getAccountTxs(alice.id());
3044 auto seq = aliceSeq;
3046 for (
auto const& tx : aliceStat)
3049 if (
seq == aliceSeq + 2)
3062 auto aliceStat = txQ.getAccountTxs(alice.id());
3063 auto seq = aliceSeq;
3065 for (
auto const& tx : aliceStat)
3078 auto bobStat = txQ.getAccountTxs(bob.id());
3082 auto aliceStat = txQ.getAccountTxs(alice.id());
3090 using namespace jtx;
3091 testcase(
"account info");
3093 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3097 env.
fund(
XRP(1000000), alice);
3100 auto const withQueue =
3101 R
"({ "account": ")" + alice.human() + R"(", "queue": true })";
3104 R"(", "queue": true, "ledger_index": 3 })";
3111 info.isMember(jss::result) &&
3112 info[jss::result].isMember(jss::account_data));
3113 BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data));
3117 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3119 info.isMember(jss::result) &&
3120 info[jss::result].isMember(jss::account_data));
3139 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3141 info.isMember(jss::result) &&
3142 info[jss::result].isMember(jss::account_data));
3143 auto const&
result = info[jss::result];
3164 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3166 info.isMember(jss::result) &&
3167 info[jss::result].isMember(jss::account_data));
3168 auto const&
result = info[jss::result];
3181 data[jss::Sequence].asUInt() +
3192 auto const& item =
queued[i];
3202 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3217 json(jss::LastLedgerSequence, 10),
3222 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3224 info.isMember(jss::result) &&
3225 info[jss::result].isMember(jss::account_data));
3226 auto const&
result = info[jss::result];
3227 auto const&
data =
result[jss::account_data];
3239 data[jss::Sequence].asUInt() +
3250 auto const& item =
queued[i];
3259 if (i ==
queued.size() - 1)
3267 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3278 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3280 info.isMember(jss::result) &&
3281 info[jss::result].isMember(jss::account_data));
3282 auto const&
result = info[jss::result];
3283 auto const&
data =
result[jss::account_data];
3295 data[jss::Sequence].asUInt() +
3306 auto const& item =
queued[i];
3310 if (i ==
queued.size() - 1)
3338 info.isMember(jss::result) &&
3348 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3350 info.isMember(jss::result) &&
3351 info[jss::result].isMember(jss::account_data));
3352 auto const&
result = info[jss::result];
3369 using namespace jtx;
3370 testcase(
"server info");
3372 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3376 env.
fund(
XRP(1000000), alice);
3380 auto const server_info = env.
rpc(
"server_info");
3382 server_info.isMember(jss::result) &&
3383 server_info[jss::result].isMember(jss::info));
3384 auto const& info = server_info[jss::result][jss::info];
3386 info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
3390 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3393 auto const server_state = env.
rpc(
"server_state");
3394 auto const& state = server_state[jss::result][jss::state];
3396 state.isMember(jss::load_factor) &&
3397 state[jss::load_factor] == 256);
3399 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3401 state.isMember(jss::load_factor_server) &&
3402 state[jss::load_factor_server] == 256);
3404 state.isMember(jss::load_factor_fee_escalation) &&
3405 state[jss::load_factor_fee_escalation] == 256);
3407 state.isMember(jss::load_factor_fee_queue) &&
3408 state[jss::load_factor_fee_queue] == 256);
3410 state.isMember(jss::load_factor_fee_reference) &&
3411 state[jss::load_factor_fee_reference] == 256);
3419 auto aliceSeq = env.
seq(alice);
3421 for (
auto i = 0; i < 4; ++i)
3427 auto const server_info = env.
rpc(
"server_info");
3429 server_info.isMember(jss::result) &&
3430 server_info[jss::result].isMember(jss::info));
3431 auto const& info = server_info[jss::result][jss::info];
3434 info.isMember(jss::load_factor) &&
3435 info[jss::load_factor] > 888.88 &&
3436 info[jss::load_factor] < 888.89);
3438 info.isMember(jss::load_factor_server) &&
3439 info[jss::load_factor_server] == 1);
3443 info.isMember(jss::load_factor_fee_escalation) &&
3444 info[jss::load_factor_fee_escalation] > 888.88 &&
3445 info[jss::load_factor_fee_escalation] < 888.89);
3448 auto const server_state = env.
rpc(
"server_state");
3449 auto const& state = server_state[jss::result][jss::state];
3451 state.isMember(jss::load_factor) &&
3452 state[jss::load_factor] == 227555);
3454 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3456 state.isMember(jss::load_factor_server) &&
3457 state[jss::load_factor_server] == 256);
3459 state.isMember(jss::load_factor_fee_escalation) &&
3460 state[jss::load_factor_fee_escalation] == 227555);
3462 state.isMember(jss::load_factor_fee_queue) &&
3463 state[jss::load_factor_fee_queue] == 256);
3465 state.isMember(jss::load_factor_fee_reference) &&
3466 state[jss::load_factor_fee_reference] == 256);
3472 auto const server_info = env.
rpc(
"server_info");
3474 server_info.isMember(jss::result) &&
3475 server_info[jss::result].isMember(jss::info));
3476 auto const& info = server_info[jss::result][jss::info];
3479 info.isMember(jss::load_factor) &&
3480 info[jss::load_factor] == 1000);
3484 info.isMember(jss::load_factor_net) &&
3485 info[jss::load_factor_net] == 1000);
3487 info.isMember(jss::load_factor_fee_escalation) &&
3488 info[jss::load_factor_fee_escalation] > 888.88 &&
3489 info[jss::load_factor_fee_escalation] < 888.89);
3492 auto const server_state = env.
rpc(
"server_state");
3493 auto const& state = server_state[jss::result][jss::state];
3495 state.isMember(jss::load_factor) &&
3496 state[jss::load_factor] == 256000);
3498 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3500 state.isMember(jss::load_factor_server) &&
3501 state[jss::load_factor_server] == 256000);
3503 state.isMember(jss::load_factor_fee_escalation) &&
3504 state[jss::load_factor_fee_escalation] == 227555);
3506 state.isMember(jss::load_factor_fee_queue) &&
3507 state[jss::load_factor_fee_queue] == 256);
3509 state.isMember(jss::load_factor_fee_reference) &&
3510 state[jss::load_factor_fee_reference] == 256);
3516 for (
int i = 0; i < 5; ++i)
3521 auto const server_info = env.
rpc(
"server_info");
3523 server_info.isMember(jss::result) &&
3524 server_info[jss::result].isMember(jss::info));
3525 auto const& info = server_info[jss::result][jss::info];
3528 info.isMember(jss::load_factor) &&
3529 info[jss::load_factor] > 888.88 &&
3530 info[jss::load_factor] < 888.89);
3535 info.isMember(jss::load_factor_server) &&
3536 info[jss::load_factor_server] > 1.245 &&
3537 info[jss::load_factor_server] < 2.4415);
3539 info.isMember(jss::load_factor_local) &&
3540 info[jss::load_factor_local] > 1.245 &&
3541 info[jss::load_factor_local] < 2.4415);
3544 info.isMember(jss::load_factor_fee_escalation) &&
3545 info[jss::load_factor_fee_escalation] > 888.88 &&
3546 info[jss::load_factor_fee_escalation] < 888.89);
3549 auto const server_state = env.
rpc(
"server_state");
3550 auto const& state = server_state[jss::result][jss::state];
3552 state.isMember(jss::load_factor) &&
3553 state[jss::load_factor] == 227555);
3555 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3560 state.isMember(jss::load_factor_server) &&
3561 state[jss::load_factor_server] >= 320 &&
3562 state[jss::load_factor_server] <= 625);
3564 state.isMember(jss::load_factor_fee_escalation) &&
3565 state[jss::load_factor_fee_escalation] == 227555);
3567 state.isMember(jss::load_factor_fee_queue) &&
3568 state[jss::load_factor_fee_queue] == 256);
3570 state.isMember(jss::load_factor_fee_reference) &&
3571 state[jss::load_factor_fee_reference] == 256);
3577 auto const server_info = env.
rpc(
"server_info");
3579 server_info.isMember(jss::result) &&
3580 server_info[jss::result].isMember(jss::info));
3581 auto const& info = server_info[jss::result][jss::info];
3588 info.isMember(jss::load_factor) &&
3589 info[jss::load_factor] > 1.245 &&
3590 info[jss::load_factor] < 2.4415);
3593 info.isMember(jss::load_factor_local) &&
3594 info[jss::load_factor_local] > 1.245 &&
3595 info[jss::load_factor_local] < 2.4415);
3597 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3600 auto const server_state = env.
rpc(
"server_state");
3601 auto const& state = server_state[jss::result][jss::state];
3603 state.isMember(jss::load_factor) &&
3604 state[jss::load_factor] >= 320 &&
3605 state[jss::load_factor] <= 625);
3607 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3612 state.isMember(jss::load_factor_server) &&
3613 state[jss::load_factor_server] >= 320 &&
3614 state[jss::load_factor_server] <= 625);
3616 state.isMember(jss::load_factor_fee_escalation) &&
3617 state[jss::load_factor_fee_escalation] == 256);
3619 state.isMember(jss::load_factor_fee_queue) &&
3620 state[jss::load_factor_fee_queue] == 256);
3622 state.isMember(jss::load_factor_fee_reference) &&
3623 state[jss::load_factor_fee_reference] == 256);
3630 using namespace jtx;
3631 testcase(
"server subscribe");
3633 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3637 stream[jss::streams].append(
"server");
3640 auto jv = wsc->invoke(
"subscribe", stream);
3644 Account a{
"a"}, b{
"b"}, c{
"c"}, d{
"d"}, e{
"e"}, f{
"f"}, g{
"g"}, h{
"h"},
3649 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
3652 using namespace std::chrono_literals;
3654 return jv[jss::type] ==
"serverStatus" &&
3655 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3656 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3657 jv.isMember(jss::load_factor_server) &&
3658 jv[jss::load_factor_server] == 256 &&
3659 jv.isMember(jss::load_factor_fee_escalation) &&
3660 jv[jss::load_factor_fee_escalation] == 256 &&
3661 jv.isMember(jss::load_factor_fee_queue) &&
3662 jv[jss::load_factor_fee_queue] == 256 &&
3663 jv.isMember(jss::load_factor_fee_reference) &&
3664 jv[jss::load_factor_fee_reference] == 256;
3668 return jv[jss::type] ==
"serverStatus" &&
3669 jv.isMember(jss::load_factor) &&
3670 jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3671 jv[jss::load_base] == 256 &&
3672 jv.isMember(jss::load_factor_server) &&
3673 jv[jss::load_factor_server] == 256 &&
3674 jv.isMember(jss::load_factor_fee_escalation) &&
3675 jv[jss::load_factor_fee_escalation] == 227555 &&
3676 jv.isMember(jss::load_factor_fee_queue) &&
3677 jv[jss::load_factor_fee_queue] == 256 &&
3678 jv.isMember(jss::load_factor_fee_reference) &&
3679 jv[jss::load_factor_fee_reference] == 256;
3686 return jv[jss::type] ==
"serverStatus" &&
3687 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3688 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3689 jv.isMember(jss::load_factor_server) &&
3690 jv[jss::load_factor_server] == 256 &&
3691 jv.isMember(jss::load_factor_fee_escalation) &&
3692 jv[jss::load_factor_fee_escalation] == 256 &&
3693 jv.isMember(jss::load_factor_fee_queue) &&
3694 jv[jss::load_factor_fee_queue] == 256 &&
3695 jv.isMember(jss::load_factor_fee_reference) &&
3696 jv[jss::load_factor_fee_reference] == 256;
3717 return jv[jss::type] ==
"serverStatus" &&
3718 jv.isMember(jss::load_factor) &&
3719 jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3720 jv[jss::load_base] == 256 &&
3721 jv.isMember(jss::load_factor_server) &&
3722 jv[jss::load_factor_server] == 256 &&
3723 jv.isMember(jss::load_factor_fee_escalation) &&
3724 jv[jss::load_factor_fee_escalation] == 200000 &&
3725 jv.isMember(jss::load_factor_fee_queue) &&
3726 jv[jss::load_factor_fee_queue] == 256 &&
3727 jv.isMember(jss::load_factor_fee_reference) &&
3728 jv[jss::load_factor_fee_reference] == 256;
3734 return jv[jss::type] ==
"serverStatus" &&
3735 jv.isMember(jss::load_factor) &&
3736 jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3737 jv[jss::load_base] == 256 &&
3738 jv.isMember(jss::load_factor_server) &&
3739 jv[jss::load_factor_server] == 256 &&
3740 jv.isMember(jss::load_factor_fee_escalation) &&
3741 jv[jss::load_factor_fee_escalation] == 184320 &&
3742 jv.isMember(jss::load_factor_fee_queue) &&
3743 jv[jss::load_factor_fee_queue] == 256 &&
3744 jv.isMember(jss::load_factor_fee_reference) &&
3745 jv[jss::load_factor_fee_reference] == 256;
3751 return jv[jss::type] ==
"serverStatus" &&
3752 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3753 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3754 jv.isMember(jss::load_factor_server) &&
3755 jv[jss::load_factor_server] == 256 &&
3756 jv.isMember(jss::load_factor_fee_escalation) &&
3757 jv[jss::load_factor_fee_escalation] == 256 &&
3758 jv.isMember(jss::load_factor_fee_queue) &&
3759 jv[jss::load_factor_fee_queue] == 256 &&
3760 jv.isMember(jss::load_factor_fee_reference) &&
3761 jv[jss::load_factor_fee_reference] == 256;
3765 return jv[jss::type] ==
"serverStatus";
3768 auto jv = wsc->invoke(
"unsubscribe", stream);
3775 using namespace jtx;
3776 testcase(
"clear queued acct txs");
3778 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3779 auto alice =
Account(
"alice");
3782 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
3783 env.
fund(
XRP(50000000), alice, bob);
3790 auto totalFactor = 0;
3793 numToClear.emplace(metrics.txCount + 1);
3794 for (
int i = 0; i < *numToClear; ++i)
3797 totalFactor += inLedger * inLedger;
3800 metrics.medFeeLevel * totalFactor /
3801 (metrics.txPerLedger * metrics.txPerLedger),
3811 testcase(
"straightfoward positive case");
3814 auto aliceSeq = env.
seq(alice);
3815 for (
int i = 0; i < 2; ++i)
3828 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
3841 checkMetrics(__LINE__, env, 4, std::nullopt, 4, 3, 256);
3846 calcTotalFee(100 * 2 + 8889 + 60911);
3849 env(
noop(alice),
fee(totalFee2),
seq(aliceSeq++));
3851 checkMetrics(__LINE__, env, 0, std::nullopt, 9, 3, 256);
3854 testcase(
"replace last tx with enough to clear queue");
3857 auto aliceSeq = env.
seq(alice);
3858 for (
int i = 0; i < 2; ++i)
3871 checkMetrics(__LINE__, env, 3, std::nullopt, 9, 3, 256);
3877 calcTotalFee(100 * 2, metrics.txCount);
3881 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3884 checkMetrics(__LINE__, env, 0, std::nullopt, 12, 3, 256);
3890 testcase(
"replace middle tx with enough to clear queue");
3894 auto aliceSeq = env.
seq(alice);
3895 for (
int i = 0; i < 5; ++i)
3907 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3910 auto const aliceQueue =
3914 for (
auto const& tx : aliceQueue)
3926 testcase(
"clear queue failure (load)");
3930 auto aliceSeq = env.
seq(alice);
3931 for (
int i = 0; i < 2; ++i)
3935 for (
int i = 0; i < 2; ++i)
3944 std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
3949 feeTrack.setRemoteFee(origFee * 5);
3962 feeTrack.setRemoteFee(origFee);
3981 using namespace jtx;
3982 using namespace std::chrono_literals;
3983 testcase(
"scaling");
3989 {{
"minimum_txn_in_ledger_standalone",
"3"},
3990 {
"normal_consensus_increase_percent",
"25"},
3991 {
"slow_consensus_decrease_percent",
"50"},
3992 {
"target_txn_in_ledger",
"10"},
3993 {
"maximum_txn_per_account",
"200"}}));
3994 auto alice =
Account(
"alice");
3996 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
3997 env.
fund(
XRP(50000000), alice);
4000 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4001 auto seqAlice = env.
seq(alice);
4003 for (
int i = 0; i < txCount; ++i)
4005 checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4047 env.
close(env.
now() + 5s, 10000ms);
4052 env.
close(env.
now() + 5s, 10000ms);
4057 env.
close(env.
now() + 5s, 10000ms);
4064 env.
close(env.
now() + 5s, 10000ms);
4075 {{
"minimum_txn_in_ledger_standalone",
"3"},
4076 {
"normal_consensus_increase_percent",
"150"},
4077 {
"slow_consensus_decrease_percent",
"150"},
4078 {
"target_txn_in_ledger",
"10"},
4079 {
"maximum_txn_per_account",
"200"}}));
4080 auto alice =
Account(
"alice");
4082 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4083 env.
fund(
XRP(50000000), alice);
4086 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4087 auto seqAlice = env.
seq(alice);
4089 for (
int i = 0; i < txCount; ++i)
4091 checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4108 env.
close(env.
now() + 5s, 10000ms);
4129 testcase(
"Sequence in queue and open ledger");
4130 using namespace jtx;
4132 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4134 auto const alice =
Account(
"alice");
4140 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4144 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4147 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4150 auto const aliceSeq = env.
seq(alice);
4152 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4168 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4174 checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4179 checkMetrics(__LINE__, env, 3, std::nullopt, 6, 3, 256);
4196 testcase(
"Ticket in queue and open ledger");
4197 using namespace jtx;
4199 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4201 auto alice =
Account(
"alice");
4207 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4211 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4215 env(ticket::create(alice, 4));
4219 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4224 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4232 auto const tx = env.
jt(
4240 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4247 checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4253 checkMetrics(__LINE__, env, 1, std::nullopt, 7, 3, 256);
4258 checkMetrics(__LINE__, env, 2, std::nullopt, 7, 3, 256);
4274 checkMetrics(__LINE__, env, 2, std::nullopt, 8, 3, 256);
4292 testcase(
"Re-execute preflight");
4293 using namespace jtx;
4303 {{
"minimum_txn_in_ledger_standalone",
"1"},
4304 {
"ledgers_in_queue",
"5"},
4305 {
"maximum_txn_per_account",
"10"}},
4306 {{
"account_reserve",
"1000"}, {
"owner_reserve",
"50"}});
4308 Env env(*
this, std::move(cfg));
4310 env.fund(
XRP(10000), alice);
4312 env.fund(
XRP(10000), bob);
4314 env.fund(
XRP(10000), carol);
4316 env.fund(
XRP(10000), daria);
4318 env.fund(
XRP(10000), ellie);
4320 env.fund(
XRP(10000), fiona);
4326 for (i = 0; i <= 257; ++i)
4334 __LINE__, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger, 256);
4339 using namespace std::chrono_literals;
4340 auto closeDuration = 80min;
4341 for (i = 0; i <= 255; ++i)
4342 env.close(closeDuration);
4350 5 * expectedPerLedger,
4351 expectedPerLedger + 1,
4356 auto seqAlice = env.seq(alice);
4357 auto seqBob = env.seq(bob);
4358 auto seqCarol = env.seq(carol);
4359 auto seqDaria = env.seq(daria);
4360 auto seqEllie = env.seq(ellie);
4361 auto seqFiona = env.seq(fiona);
4364 for (
int i = 0; i < 10; ++i)
4378 5 * expectedPerLedger,
4379 expectedPerLedger + 1,
4394 env.close(closeDuration);
4395 auto expectedInLedger = expectedInQueue;
4397 (expectedInQueue > expectedPerLedger + 2
4398 ? expectedInQueue - (expectedPerLedger + 2)
4400 expectedInLedger -= expectedInQueue;
4401 ++expectedPerLedger;
4406 5 * expectedPerLedger,
4411 auto const expectedPerAccount = expectedInQueue / 6;
4412 auto const expectedRemainder = expectedInQueue % 6;
4413 BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4416 seqBob - expectedPerAccount -
4417 (expectedRemainder > 4 ? 1 : 0));
4420 seqCarol - expectedPerAccount -
4421 (expectedRemainder > 3 ? 1 : 0));
4424 seqDaria - expectedPerAccount -
4425 (expectedRemainder > 2 ? 1 : 0));
4428 seqEllie - expectedPerAccount -
4429 (expectedRemainder > 1 ? 1 : 0));
4432 seqFiona - expectedPerAccount -
4433 (expectedRemainder > 0 ? 1 : 0));
4435 }
while (expectedInQueue > 0);
4448 testcase(
"Queue full drop penalty");
4449 using namespace jtx;
4465 int const medFee = 100;
4466 int const hiFee = 1000;
4469 {{
"minimum_txn_in_ledger_standalone",
"5"},
4470 {
"ledgers_in_queue",
"5"},
4471 {
"maximum_txn_per_account",
"30"},
4472 {
"minimum_queue_size",
"50"}});
4474 Env env(*
this, std::move(cfg));
4478 env.fund(
XRP(10000),
noripple(alice, bob, carol, daria, ellie, fiona));
4483 env(ticket::create(bob, 10));
4494 auto seqAlice = env.seq(alice);
4495 auto const seqSaveAlice = seqAlice;
4500 json(R
"({"LastLedgerSequence": 7})"),
4510 json(R
"({"LastLedgerSequence": 7})"),
4523 auto seqCarol = env.seq(carol);
4524 auto seqDaria = env.seq(daria);
4525 auto seqEllie = env.seq(ellie);
4526 auto seqFiona = env.seq(fiona);
4528 for (
int i = 0; i < 7; ++i)
4542 for (
int i = 0; i < 3; ++i)
4555 for (
int i = 0; i < 3; ++i)
4576 for (
int i = 0; i < 4; ++i)
4595 for (
int i = 0; i < 30; ++i)
4596 env.app().getFeeTrack().raiseLocalFee();
4606 while (env.app().getFeeTrack().lowerLocalFee())
4632 seqAlice = seqSaveAlice;
4678 testcase(
"Cancel queued offers");
4679 using namespace jtx;
4683 auto USD = gw[
"USD"];
4686 {{
"minimum_txn_in_ledger_standalone",
"5"},
4687 {
"ledgers_in_queue",
"5"},
4688 {
"maximum_txn_per_account",
"30"},
4689 {
"minimum_queue_size",
"50"}});
4691 Env env(*
this, std::move(cfg));
4703 auto const aliceSeq = env.seq(alice);
4706 env(offer(alice, USD(1000),
XRP(1001)),
4712 env(offer(alice, USD(1000),
XRP(1002)),
4714 json(jss::OfferSequence, aliceSeq),
4730 auto const aliceTkt = env.seq(alice);
4731 env(ticket::create(alice, 6));
4738 auto const aliceSeq = env.seq(alice);
4739 env(offer(alice, USD(1000),
XRP(1000)),
4743 env(offer(alice, USD(1000),
XRP(1001)),
4753 env(offer(alice, USD(1000),
XRP(1002)),
4755 json(jss::OfferSequence, aliceTkt + 4),
4765 env(offer(alice, USD(1000),
XRP(1001)),
4770 env(offer(alice, USD(1000),
XRP(1002)),
4772 json(jss::OfferSequence, aliceSeq),