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();
147 auto const base = [&view]() {
148 auto base = view.fees().base;
155 return fee(
toDrops(metrics.openLedgerFeeLevel, base) + 1);
164 auto& section = p->section(
"transaction_queue");
165 section.set(
"ledgers_in_queue",
"2");
166 section.set(
"minimum_queue_size",
"2");
167 section.set(
"min_ledgers_to_compute_size_limit",
"3");
168 section.set(
"max_ledger_counts_to_store",
"100");
169 section.set(
"retry_sequence_percent",
"25");
170 section.set(
"normal_consensus_increase_percent",
"0");
172 for (
auto const& [k, v] : extraTxQ)
177 if (!extraVoting.
empty())
179 auto& votingSection = p->section(
"voting");
180 for (
auto const& [k, v] : extraVoting)
182 votingSection.set(k, v);
186 p->section(
"validation_seed")
187 .legacy(
"shUwVw52ofnCUX5m7kPTKzJdr4HEH");
205 for (
auto i = env.
current()->seq(); i <= 257; ++i)
212 auto const flagMaxQueue = ledgersInQueue * flagPerLedger;
213 checkMetrics(__LINE__, env, 0, flagMaxQueue, 0, flagPerLedger, 256);
222 using namespace std::chrono_literals;
224 checkMetrics(__LINE__, env, 0, flagMaxQueue, 0, expectedPerLedger, 256);
225 auto const fees = env.
current()->fees();
239 testcase(
"queue sequence");
241 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
245 auto charlie =
Account(
"charlie");
257 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
261 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
265 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
269 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
273 checkMetrics(__LINE__, env, 2, std::nullopt, 5, 3, 256);
391 checkMetrics(__LINE__, env, 2, 8, 5, 4, 256, 256 * 700);
427 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
441 metrics.txPerLedger + 1,
450 testcase(
"queue ticket");
452 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
460 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
467 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
474 env(ticket::create(alice, 250),
seq(tkt1 - 1),
queued);
479 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
707 testcase(
"queue tec");
709 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
713 auto USD = gw[
"USD"];
715 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
719 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
744 testcase(
"local tx retry");
746 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
750 auto charlie =
Account(
"charlie");
756 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
760 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
767 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
771 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
775 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
779 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
783 checkMetrics(__LINE__, env, 2, std::nullopt, 4, 2, 256);
787 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 2, 256);
801 testcase(
"last ledger sequence");
803 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
807 auto charlie =
Account(
"charlie");
810 auto felicia =
Account(
"felicia");
814 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
824 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
828 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
833 json(R
"({"LastLedgerSequence":7})"),
843 checkMetrics(__LINE__, env, 5, std::nullopt, 3, 2, 256);
850 aliceStat.begin()->lastValid &&
851 *aliceStat.begin()->lastValid == 8);
852 BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker());
854 auto bobStat = txQ.getAccountTxs(bob.id());
857 bobStat.begin()->feeLevel ==
FeeLevel64{7000 * 256 / 10});
859 BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker());
878 checkMetrics(__LINE__, env, 1, 8, 5, 4, 256, 700 * 256);
889 checkMetrics(__LINE__, env, 8, 8, 5, 4, 257, 700 * 256);
895 checkMetrics(__LINE__, env, 1, 10, 6, 5, 256, 700 * 256);
901 checkMetrics(__LINE__, env, 0, 12, 1, 6, 256, 800 * 256);
911 testcase(
"zero transaction fee");
913 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
921 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
933 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
936 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
940 checkMetrics(__LINE__, env, 2, std::nullopt, 3, 2, 256);
950 auto seqAlice = env.
seq(alice);
951 for (
int i = 0; i < 4; ++i)
954 feeAlice = (feeAlice + 1) * 125 / 100;
960 auto const seqBob = env.
seq(bob);
965 auto feeCarol = feeAlice;
966 auto seqCarol = env.
seq(carol);
967 for (
int i = 0; i < 4; ++i)
970 feeCarol = (feeCarol + 1) * 125 / 100;
1006 using namespace jtx;
1009 testcase(
"fail in preclaim");
1011 auto alice =
Account(
"alice");
1030 using namespace jtx;
1031 testcase(
"queued tx fails");
1033 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
1035 auto alice =
Account(
"alice");
1040 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1044 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
1048 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
1052 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
1056 auto const& jt = env.
jt(
noop(alice));
1070 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
1081 using namespace jtx;
1082 testcase(
"multi tx per account");
1087 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1088 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1090 auto alice =
Account(
"alice");
1092 auto charlie =
Account(
"charlie");
1093 auto daria =
Account(
"daria");
1099 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1102 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1107 checkMetrics(__LINE__, env, 0, initQueueMax, 4, 3, 256);
1111 checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1113 auto aliceSeq = env.
seq(alice);
1114 auto bobSeq = env.
seq(bob);
1115 auto charlieSeq = env.
seq(charlie);
1119 checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1123 checkMetrics(__LINE__, env, 2, initQueueMax, 4, 3, 256);
1127 checkMetrics(__LINE__, env, 3, initQueueMax, 4, 3, 256);
1131 checkMetrics(__LINE__, env, 4, initQueueMax, 4, 3, 256);
1135 checkMetrics(__LINE__, env, 5, initQueueMax, 4, 3, 256);
1140 checkMetrics(__LINE__, env, 6, initQueueMax, 4, 3, 256);
1160 aliceSeq = env.
seq(alice);
1161 auto lastLedgerSeq = env.
current()->info().seq + 2;
1162 for (
auto i = 0; i < 7; i++)
1166 json(jss::LastLedgerSequence, lastLedgerSeq + i),
1176 auto const& baseFee = env.
current()->fees().base;
1177 auto seq = env.
seq(alice);
1179 for (
auto const& tx : aliceStat)
1186 (tx.consequences.fee() ==
drops(aliceFee) &&
1187 tx.consequences.potentialSpend() ==
drops(0) &&
1188 !tx.consequences.isBlocker()) ||
1189 tx.seqProxy.value() == env.
seq(alice) + 6);
1199 json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1232 aliceSeq = env.
seq(alice) + 2;
1251 aliceSeq = env.
seq(alice) + 1;
1258 env.
le(alice)->getFieldAmount(
sfBalance).xrp().drops() - (62);
1301 bobSeq = env.
seq(bob);
1303 for (
int i = 0; i < 10; ++i)
1318 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10 - 1);
1332 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10);
1351 using namespace jtx;
1352 using namespace std::chrono;
1353 testcase("tie breaking");
1355 Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "4"}}));
1357 auto alice = Account("alice");
1358 auto bob = Account("bob");
1359 auto charlie = Account("charlie");
1360 auto daria = Account("daria");
1361 auto elmo = Account("elmo");
1362 auto fred = Account("fred");
1363 auto gwen = Account("gwen");
1364 auto hank = Account("hank");
1366 auto queued = ter(terQUEUED);
1368 BEAST_EXPECT(env.current()->fees().base == 10);
1370 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 4, 256);
1372 // Create several accounts while the fee is cheap so they all apply.
1373 env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
1374 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 4, 256);
1377 checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
1379 env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
1380 checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
1383 checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
1387 // Stuff the ledger and queue so we can verify that
1388 // stuff gets kicked out.
1394 checkMetrics(__LINE__, env, 0, 8, 5, 4, 256);
1396 auto aliceSeq = env.seq(alice);
1397 auto bobSeq = env.seq(bob);
1398 auto charlieSeq = env.seq(charlie);
1399 auto dariaSeq = env.seq(daria);
1400 auto elmoSeq = env.seq(elmo);
1401 auto fredSeq = env.seq(fred);
1402 auto gwenSeq = env.seq(gwen);
1403 auto hankSeq = env.seq(hank);
1405 // This time, use identical fees.
1407 // All of these get into the queue, but one gets dropped when the
1408 // higher fee one is added later. Which one depends on ordering.
1409 env(noop(alice), fee(15), queued);
1410 env(noop(bob), fee(15), queued);
1411 env(noop(charlie), fee(15), queued);
1412 env(noop(daria), fee(15), queued);
1413 env(noop(elmo), fee(15), queued);
1414 env(noop(fred), fee(15), queued);
1415 env(noop(gwen), fee(15), queued);
1416 env(noop(hank), fee(15), queued);
1418 // Queue is full now. Minimum fee now reflects the
1419 // lowest fee in the queue.
1420 checkMetrics(__LINE__, env, 8, 8, 5, 4, 385);
1422 // Try to add another transaction with the default (low) fee,
1423 // it should fail because it can't replace the
one already
1444 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1445 gwenSeq + hankSeq + 6 ==
1446 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1447 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1449 using namespace std::string_literals;
1451 aliceSeq == env.
seq(alice),
1455 bobSeq + 1 == env.
seq(bob),
1459 charlieSeq + 2 == env.
seq(charlie),
1463 dariaSeq + 1 == env.
seq(daria),
1467 elmoSeq + 1 == env.
seq(elmo),
1471 fredSeq == env.
seq(fred),
1475 gwenSeq == env.
seq(gwen),
1479 hankSeq + 1 == env.
seq(hank),
1494 auto getTxsQueued = [&]() {
1497 for (
auto const& tx : txs)
1503 auto qTxCount1 = getTxsQueued();
1508 seq(aliceSeq + qTxCount1[alice.id()]++),
1511 env(noop(bob), seq(bobSeq + qTxCount1[bob.id()]++), fee(15),
queued);
1513 seq(charlieSeq + qTxCount1[charlie.id()]++),
1517 seq(dariaSeq + qTxCount1[daria.id()]++),
1520 env(noop(elmo), seq(elmoSeq + qTxCount1[elmo.id()]++), fee(15),
queued);
1521 env(noop(fred), seq(fredSeq + qTxCount1[fred.id()]++), fee(15),
queued);
1522 env(noop(gwen), seq(gwenSeq + qTxCount1[gwen.id()]++), fee(15),
queued);
1530 seq(aliceSeq + qTxCount1[alice.id()]++),
1542 auto qTxCount2 = getTxsQueued();
1548 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1549 gwenSeq + hankSeq + 7 ==
1550 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1551 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1554 aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] ==
1559 bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.
seq(bob),
1563 charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] ==
1568 dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] ==
1573 elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] ==
1578 fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] ==
1583 gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] ==
1588 hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] ==
1597 using namespace jtx;
1598 testcase(
"acct tx id");
1600 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"1"}}));
1602 auto alice =
Account(
"alice");
1606 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 1, 256);
1609 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 1, 256);
1612 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1618 json(R
"({"AccountTxnID": "0"})"),
1621 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1636 using namespace jtx;
1637 using namespace std::string_literals;
1638 testcase(
"maximum tx");
1644 {{
"minimum_txn_in_ledger_standalone",
"2"},
1645 {
"minimum_txn_in_ledger",
"5"},
1646 {
"target_txn_in_ledger",
"4"},
1647 {
"maximum_txn_in_ledger",
"5"}}));
1649 auto alice =
Account(
"alice");
1651 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1654 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 2, 256);
1656 for (
int i = 0; i < 10; ++i)
1659 checkMetrics(__LINE__, env, 0, std::nullopt, 11, 2, 256);
1671 {{
"minimum_txn_in_ledger",
"200"},
1672 {
"minimum_txn_in_ledger_standalone",
"200"},
1673 {
"target_txn_in_ledger",
"4"},
1674 {
"maximum_txn_in_ledger",
"5"}}));
1682 "The minimum number of low-fee transactions allowed "
1683 "per ledger (minimum_txn_in_ledger) exceeds "
1684 "the maximum number of low-fee transactions allowed per "
1685 "ledger (maximum_txn_in_ledger)."s);
1692 {{
"minimum_txn_in_ledger",
"200"},
1693 {
"minimum_txn_in_ledger_standalone",
"2"},
1694 {
"target_txn_in_ledger",
"4"},
1695 {
"maximum_txn_in_ledger",
"5"}}));
1703 "The minimum number of low-fee transactions allowed "
1704 "per ledger (minimum_txn_in_ledger) exceeds "
1705 "the maximum number of low-fee transactions allowed per "
1706 "ledger (maximum_txn_in_ledger)."s);
1713 {{
"minimum_txn_in_ledger",
"2"},
1714 {
"minimum_txn_in_ledger_standalone",
"200"},
1715 {
"target_txn_in_ledger",
"4"},
1716 {
"maximum_txn_in_ledger",
"5"}}));
1724 "The minimum number of low-fee transactions allowed "
1725 "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1726 "the maximum number of low-fee transactions allowed per "
1727 "ledger (maximum_txn_in_ledger)."s);
1734 using namespace jtx;
1735 testcase(
"unexpected balance change");
1740 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1741 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1743 auto alice =
Account(
"alice");
1749 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1753 checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
1757 checkMetrics(__LINE__, env, 0, initQueueMax, 2, 3, 256);
1758 auto USD = bob[
"USD"];
1761 checkMetrics(__LINE__, env, 0, initQueueMax, 3, 3, 256);
1772 auto aliceSeq = env.
seq(alice);
1781 env(offer(bob,
drops(5000), USD(5000)),
1816 for (
int i = 0; i < 9; ++i)
1831 using namespace jtx;
1832 testcase(
"blockers sequence");
1834 auto alice =
Account(
"alice");
1836 auto charlie =
Account(
"charlie");
1837 auto daria =
Account(
"daria");
1841 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1845 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1849 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1857 env(
regkey(alice, charlie));
1858 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1861 auto const aliceSeq = env.
seq(alice);
1877 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1884 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
1896 auto const aliceSeq = env.
seq(alice);
1911 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1937 auto const aliceSeq = env.
seq(alice);
1961 using namespace jtx;
1962 testcase(
"blockers ticket");
1964 auto alice =
Account(
"alice");
1966 auto charlie =
Account(
"charlie");
1967 auto daria =
Account(
"daria");
1971 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1975 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1980 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1988 env(ticket::create(alice, 250),
seq(tkt - 1));
1990 env(
regkey(alice, charlie));
1991 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1994 auto const aliceSeq = env.
seq(alice);
2010 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2014 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2021 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
2038 auto const aliceSeq = env.
seq(alice);
2063 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2123 using namespace jtx;
2124 testcase(
"In-flight balance checks");
2129 {{
"minimum_txn_in_ledger_standalone",
"3"}},
2130 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
2132 auto alice =
Account(
"alice");
2133 auto charlie =
Account(
"charlie");
2144 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
2148 checkMetrics(__LINE__, env, 0, initQueueMax, 0, limit, 256);
2151 checkMetrics(__LINE__, env, 0, initQueueMax, limit + 1, limit, 256);
2153 auto USD = gw[
"USD"];
2154 auto BUX = gw[
"BUX"];
2158 auto aliceSeq = env.
seq(alice);
2159 auto aliceBal = env.
balance(alice);
2165 env(offer(alice, BUX(5000),
XRP(50000)),
queued);
2166 checkMetrics(__LINE__, env, 1, initQueueMax, limit + 1, limit, 256);
2171 checkMetrics(__LINE__, env, 2, initQueueMax, limit + 1, limit, 256);
2175 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2187 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2188 aliceSeq = env.
seq(alice);
2189 aliceBal = env.
balance(alice);
2195 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2200 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2208 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2212 checkMetrics(__LINE__, env, 0, limit * 2, 3, limit, 256);
2224 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2225 aliceSeq = env.
seq(alice);
2226 aliceBal = env.
balance(alice);
2233 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2241 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2245 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2257 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2258 aliceSeq = env.
seq(alice);
2259 aliceBal = env.
balance(alice);
2263 env(offer(alice, BUX(50),
XRP(500)),
queued);
2267 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2271 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2283 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2285 aliceSeq = env.
seq(alice);
2286 aliceBal = env.
balance(alice);
2296 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2300 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2310 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2312 aliceSeq = env.
seq(alice);
2313 aliceBal = env.
balance(alice);
2321 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2325 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2333 auto const amount = USD(500000);
2334 env(
trust(alice, USD(50000000)));
2335 env(
trust(charlie, USD(50000000)));
2336 checkMetrics(__LINE__, env, 0, limit * 2, 4, limit, 256);
2341 env(
pay(gw, alice, amount));
2342 checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2348 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2350 aliceSeq = env.
seq(alice);
2351 aliceBal = env.
balance(alice);
2352 auto aliceUSD = env.
balance(alice, USD);
2356 env(
pay(alice, charlie, amount),
queued);
2361 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2365 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2379 env(offer(gw,
XRP(500000), USD(50000)));
2385 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2387 aliceSeq = env.
seq(alice);
2388 aliceBal = env.
balance(alice);
2389 auto charlieUSD = env.
balance(charlie, USD);
2401 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2405 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2412 balance(charlie, charlieUSD + USD(1000)),
2420 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2422 aliceSeq = env.
seq(alice);
2423 aliceBal = env.
balance(alice);
2424 charlieUSD = env.
balance(charlie, USD);
2435 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2439 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2446 balance(charlie, charlieUSD + USD(500)),
2456 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2458 aliceSeq = env.
seq(alice);
2459 aliceBal = env.
balance(alice);
2466 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2470 checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2477 using namespace jtx;
2479 testcase(
"consequences");
2482 auto const alice =
Account(
"alice");
2501 auto USD = alice[
"USD"];
2518 auto const jtx = env.
jt(ticket::create(alice, 1),
seq(1),
fee(10));
2543 using namespace jtx;
2544 testcase(
"acct in queue but empty");
2546 auto alice =
Account(
"alice");
2548 auto charlie =
Account(
"charlie");
2552 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2556 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
2560 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 3, 256);
2564 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
2568 checkMetrics(__LINE__, env, 0, std::nullopt, 5, 3, 256);
2572 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
2640 using namespace jtx;
2645 auto fee = env.
rpc(
"fee");
2652 result.isMember(jss::ledger_current_index) &&
2653 result[jss::ledger_current_index] == 3);
2665 auto const& levels =
result[jss::levels];
2681 result.isMember(jss::ledger_current_index) &&
2682 result[jss::ledger_current_index] == 4);
2693 auto const& levels =
result[jss::levels];
2715 using namespace jtx;
2716 testcase(
"expiration replacement");
2721 {{
"minimum_txn_in_ledger_standalone",
"1"},
2722 {
"ledgers_in_queue",
"10"},
2723 {
"maximum_txn_per_account",
"20"}}));
2726 auto const alice =
Account(
"alice");
2727 auto const bob =
Account(
"bob");
2730 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2732 auto const aliceSeq = env.
seq(alice);
2736 json(R
"({"LastLedgerSequence":5})"),
2740 json(R"({"LastLedgerSequence":5})"),
2744 json(R"({"LastLedgerSequence":10})"),
2748 json(R"({"LastLedgerSequence":11})"),
2750 checkMetrics(__LINE__, env, 4, std::nullopt, 2, 1, 256);
2751 auto const bobSeq = env.
seq(bob);
2755 for (
int i = 0; i < 3 + 4 + 5; ++i)
2759 checkMetrics(__LINE__, env, 4 + 3 + 4 + 5, std::nullopt, 2, 1, 256);
2807 using namespace jtx;
2808 testcase(
"full queue gap handling");
2813 {{
"minimum_txn_in_ledger_standalone",
"1"},
2814 {
"ledgers_in_queue",
"10"},
2815 {
"maximum_txn_per_account",
"11"}}));
2820 auto const alice =
Account(
"alice");
2821 auto const bob =
Account(
"bob");
2824 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2826 auto const aliceSeq = env.
seq(alice);
2831 env(ticket::create(alice, 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":11})"),
2857 json(R"({"LastLedgerSequence": 5})"),
2861 json(R"({"LastLedgerSequence": 5})"),
2865 json(R"({"LastLedgerSequence": 5})"),
2869 json(R"({"LastLedgerSequence":11})"),
2871 checkMetrics(__LINE__, env, 10, std::nullopt, 2, 1, 256);
2873 auto const bobSeq = env.
seq(bob);
2877 for (
int i = 0; i < 2 + 4 + 5; ++i)
2881 checkMetrics(__LINE__, env, 10 + 2 + 4 + 5, std::nullopt, 2, 1, 256);
2964 testcase(
"Autofilled sequence should account for TxQ");
2965 using namespace jtx;
2966 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"6"}}));
2970 auto const alice =
Account(
"alice");
2971 auto const bob =
Account(
"bob");
2972 env.
fund(
XRP(100000), alice, bob);
2975 checkMetrics(__LINE__, env, 0, std::nullopt, 7, 6, 256);
2978 auto const aliceSeq = env.
seq(alice);
2979 auto const lastLedgerSeq = env.
current()->info().seq + 2;
2982 for (
int i = 0; i < 5; ++i)
2989 json(jss::LastLedgerSequence, lastLedgerSeq),
2995 checkMetrics(__LINE__, env, 5, std::nullopt, 7, 6, 256);
2997 auto aliceStat = txQ.getAccountTxs(alice.id());
3000 for (
auto const& tx : aliceStat)
3004 if (
seq.value() == aliceSeq + 2)
3007 tx.lastValid && *tx.lastValid == lastLedgerSeq);
3018 for (
int i = 0; i < 8; ++i)
3020 checkMetrics(__LINE__, env, 13, std::nullopt, 7, 6, 256);
3027 for (
int i = 0; i < 9; ++i)
3034 for (
int i = 0; i < 10; ++i)
3041 auto bobStat = txQ.getAccountTxs(bob.id());
3047 auto aliceStat = txQ.getAccountTxs(alice.id());
3048 auto seq = aliceSeq;
3050 for (
auto const& tx : aliceStat)
3053 if (
seq == aliceSeq + 2)
3066 auto aliceStat = txQ.getAccountTxs(alice.id());
3067 auto seq = aliceSeq;
3069 for (
auto const& tx : aliceStat)
3082 auto bobStat = txQ.getAccountTxs(bob.id());
3086 auto aliceStat = txQ.getAccountTxs(alice.id());
3094 using namespace jtx;
3095 testcase(
"account info");
3097 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3101 env.
fund(
XRP(1000000), alice);
3104 auto const withQueue =
3105 R
"({ "account": ")" + alice.human() + R"(", "queue": true })";
3108 R"(", "queue": true, "ledger_index": 3 })";
3115 info.isMember(jss::result) &&
3116 info[jss::result].isMember(jss::account_data));
3117 BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data));
3121 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3123 info.isMember(jss::result) &&
3124 info[jss::result].isMember(jss::account_data));
3143 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3145 info.isMember(jss::result) &&
3146 info[jss::result].isMember(jss::account_data));
3147 auto const&
result = info[jss::result];
3168 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3170 info.isMember(jss::result) &&
3171 info[jss::result].isMember(jss::account_data));
3172 auto const&
result = info[jss::result];
3185 data[jss::Sequence].asUInt() +
3196 auto const& item =
queued[i];
3206 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3221 json(jss::LastLedgerSequence, 10),
3226 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3228 info.isMember(jss::result) &&
3229 info[jss::result].isMember(jss::account_data));
3230 auto const&
result = info[jss::result];
3231 auto const&
data =
result[jss::account_data];
3243 data[jss::Sequence].asUInt() +
3254 auto const& item =
queued[i];
3263 if (i ==
queued.size() - 1)
3271 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3282 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3284 info.isMember(jss::result) &&
3285 info[jss::result].isMember(jss::account_data));
3286 auto const&
result = info[jss::result];
3287 auto const&
data =
result[jss::account_data];
3299 data[jss::Sequence].asUInt() +
3310 auto const& item =
queued[i];
3314 if (i ==
queued.size() - 1)
3342 info.isMember(jss::result) &&
3352 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3354 info.isMember(jss::result) &&
3355 info[jss::result].isMember(jss::account_data));
3356 auto const&
result = info[jss::result];
3373 using namespace jtx;
3374 testcase(
"server info");
3376 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3380 env.
fund(
XRP(1000000), alice);
3384 auto const server_info = env.
rpc(
"server_info");
3386 server_info.isMember(jss::result) &&
3387 server_info[jss::result].isMember(jss::info));
3388 auto const& info = server_info[jss::result][jss::info];
3390 info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
3394 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3397 auto const server_state = env.
rpc(
"server_state");
3398 auto const& state = server_state[jss::result][jss::state];
3400 state.isMember(jss::load_factor) &&
3401 state[jss::load_factor] == 256);
3403 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3405 state.isMember(jss::load_factor_server) &&
3406 state[jss::load_factor_server] == 256);
3408 state.isMember(jss::load_factor_fee_escalation) &&
3409 state[jss::load_factor_fee_escalation] == 256);
3411 state.isMember(jss::load_factor_fee_queue) &&
3412 state[jss::load_factor_fee_queue] == 256);
3414 state.isMember(jss::load_factor_fee_reference) &&
3415 state[jss::load_factor_fee_reference] == 256);
3423 auto aliceSeq = env.
seq(alice);
3425 for (
auto i = 0; i < 4; ++i)
3431 auto const server_info = env.
rpc(
"server_info");
3433 server_info.isMember(jss::result) &&
3434 server_info[jss::result].isMember(jss::info));
3435 auto const& info = server_info[jss::result][jss::info];
3438 info.isMember(jss::load_factor) &&
3439 info[jss::load_factor] > 888.88 &&
3440 info[jss::load_factor] < 888.89);
3442 info.isMember(jss::load_factor_server) &&
3443 info[jss::load_factor_server] == 1);
3447 info.isMember(jss::load_factor_fee_escalation) &&
3448 info[jss::load_factor_fee_escalation] > 888.88 &&
3449 info[jss::load_factor_fee_escalation] < 888.89);
3452 auto const server_state = env.
rpc(
"server_state");
3453 auto const& state = server_state[jss::result][jss::state];
3455 state.isMember(jss::load_factor) &&
3456 state[jss::load_factor] == 227555);
3458 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3460 state.isMember(jss::load_factor_server) &&
3461 state[jss::load_factor_server] == 256);
3463 state.isMember(jss::load_factor_fee_escalation) &&
3464 state[jss::load_factor_fee_escalation] == 227555);
3466 state.isMember(jss::load_factor_fee_queue) &&
3467 state[jss::load_factor_fee_queue] == 256);
3469 state.isMember(jss::load_factor_fee_reference) &&
3470 state[jss::load_factor_fee_reference] == 256);
3476 auto const server_info = env.
rpc(
"server_info");
3478 server_info.isMember(jss::result) &&
3479 server_info[jss::result].isMember(jss::info));
3480 auto const& info = server_info[jss::result][jss::info];
3483 info.isMember(jss::load_factor) &&
3484 info[jss::load_factor] == 1000);
3488 info.isMember(jss::load_factor_net) &&
3489 info[jss::load_factor_net] == 1000);
3491 info.isMember(jss::load_factor_fee_escalation) &&
3492 info[jss::load_factor_fee_escalation] > 888.88 &&
3493 info[jss::load_factor_fee_escalation] < 888.89);
3496 auto const server_state = env.
rpc(
"server_state");
3497 auto const& state = server_state[jss::result][jss::state];
3499 state.isMember(jss::load_factor) &&
3500 state[jss::load_factor] == 256000);
3502 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3504 state.isMember(jss::load_factor_server) &&
3505 state[jss::load_factor_server] == 256000);
3507 state.isMember(jss::load_factor_fee_escalation) &&
3508 state[jss::load_factor_fee_escalation] == 227555);
3510 state.isMember(jss::load_factor_fee_queue) &&
3511 state[jss::load_factor_fee_queue] == 256);
3513 state.isMember(jss::load_factor_fee_reference) &&
3514 state[jss::load_factor_fee_reference] == 256);
3520 for (
int i = 0; i < 5; ++i)
3525 auto const server_info = env.
rpc(
"server_info");
3527 server_info.isMember(jss::result) &&
3528 server_info[jss::result].isMember(jss::info));
3529 auto const& info = server_info[jss::result][jss::info];
3532 info.isMember(jss::load_factor) &&
3533 info[jss::load_factor] > 888.88 &&
3534 info[jss::load_factor] < 888.89);
3539 info.isMember(jss::load_factor_server) &&
3540 info[jss::load_factor_server] > 1.245 &&
3541 info[jss::load_factor_server] < 2.4415);
3543 info.isMember(jss::load_factor_local) &&
3544 info[jss::load_factor_local] > 1.245 &&
3545 info[jss::load_factor_local] < 2.4415);
3548 info.isMember(jss::load_factor_fee_escalation) &&
3549 info[jss::load_factor_fee_escalation] > 888.88 &&
3550 info[jss::load_factor_fee_escalation] < 888.89);
3553 auto const server_state = env.
rpc(
"server_state");
3554 auto const& state = server_state[jss::result][jss::state];
3556 state.isMember(jss::load_factor) &&
3557 state[jss::load_factor] == 227555);
3559 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3564 state.isMember(jss::load_factor_server) &&
3565 state[jss::load_factor_server] >= 320 &&
3566 state[jss::load_factor_server] <= 625);
3568 state.isMember(jss::load_factor_fee_escalation) &&
3569 state[jss::load_factor_fee_escalation] == 227555);
3571 state.isMember(jss::load_factor_fee_queue) &&
3572 state[jss::load_factor_fee_queue] == 256);
3574 state.isMember(jss::load_factor_fee_reference) &&
3575 state[jss::load_factor_fee_reference] == 256);
3581 auto const server_info = env.
rpc(
"server_info");
3583 server_info.isMember(jss::result) &&
3584 server_info[jss::result].isMember(jss::info));
3585 auto const& info = server_info[jss::result][jss::info];
3592 info.isMember(jss::load_factor) &&
3593 info[jss::load_factor] > 1.245 &&
3594 info[jss::load_factor] < 2.4415);
3597 info.isMember(jss::load_factor_local) &&
3598 info[jss::load_factor_local] > 1.245 &&
3599 info[jss::load_factor_local] < 2.4415);
3601 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3604 auto const server_state = env.
rpc(
"server_state");
3605 auto const& state = server_state[jss::result][jss::state];
3607 state.isMember(jss::load_factor) &&
3608 state[jss::load_factor] >= 320 &&
3609 state[jss::load_factor] <= 625);
3611 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3616 state.isMember(jss::load_factor_server) &&
3617 state[jss::load_factor_server] >= 320 &&
3618 state[jss::load_factor_server] <= 625);
3620 state.isMember(jss::load_factor_fee_escalation) &&
3621 state[jss::load_factor_fee_escalation] == 256);
3623 state.isMember(jss::load_factor_fee_queue) &&
3624 state[jss::load_factor_fee_queue] == 256);
3626 state.isMember(jss::load_factor_fee_reference) &&
3627 state[jss::load_factor_fee_reference] == 256);
3634 using namespace jtx;
3635 testcase(
"server subscribe");
3637 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3641 stream[jss::streams].append(
"server");
3644 auto jv = wsc->invoke(
"subscribe", stream);
3648 Account a{
"a"}, b{
"b"}, c{
"c"}, d{
"d"}, e{
"e"}, f{
"f"}, g{
"g"}, h{
"h"},
3653 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
3656 using namespace std::chrono_literals;
3658 return jv[jss::type] ==
"serverStatus" &&
3659 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3660 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3661 jv.isMember(jss::load_factor_server) &&
3662 jv[jss::load_factor_server] == 256 &&
3663 jv.isMember(jss::load_factor_fee_escalation) &&
3664 jv[jss::load_factor_fee_escalation] == 256 &&
3665 jv.isMember(jss::load_factor_fee_queue) &&
3666 jv[jss::load_factor_fee_queue] == 256 &&
3667 jv.isMember(jss::load_factor_fee_reference) &&
3668 jv[jss::load_factor_fee_reference] == 256;
3672 return jv[jss::type] ==
"serverStatus" &&
3673 jv.isMember(jss::load_factor) &&
3674 jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3675 jv[jss::load_base] == 256 &&
3676 jv.isMember(jss::load_factor_server) &&
3677 jv[jss::load_factor_server] == 256 &&
3678 jv.isMember(jss::load_factor_fee_escalation) &&
3679 jv[jss::load_factor_fee_escalation] == 227555 &&
3680 jv.isMember(jss::load_factor_fee_queue) &&
3681 jv[jss::load_factor_fee_queue] == 256 &&
3682 jv.isMember(jss::load_factor_fee_reference) &&
3683 jv[jss::load_factor_fee_reference] == 256;
3690 return jv[jss::type] ==
"serverStatus" &&
3691 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3692 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3693 jv.isMember(jss::load_factor_server) &&
3694 jv[jss::load_factor_server] == 256 &&
3695 jv.isMember(jss::load_factor_fee_escalation) &&
3696 jv[jss::load_factor_fee_escalation] == 256 &&
3697 jv.isMember(jss::load_factor_fee_queue) &&
3698 jv[jss::load_factor_fee_queue] == 256 &&
3699 jv.isMember(jss::load_factor_fee_reference) &&
3700 jv[jss::load_factor_fee_reference] == 256;
3721 return jv[jss::type] ==
"serverStatus" &&
3722 jv.isMember(jss::load_factor) &&
3723 jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3724 jv[jss::load_base] == 256 &&
3725 jv.isMember(jss::load_factor_server) &&
3726 jv[jss::load_factor_server] == 256 &&
3727 jv.isMember(jss::load_factor_fee_escalation) &&
3728 jv[jss::load_factor_fee_escalation] == 200000 &&
3729 jv.isMember(jss::load_factor_fee_queue) &&
3730 jv[jss::load_factor_fee_queue] == 256 &&
3731 jv.isMember(jss::load_factor_fee_reference) &&
3732 jv[jss::load_factor_fee_reference] == 256;
3738 return jv[jss::type] ==
"serverStatus" &&
3739 jv.isMember(jss::load_factor) &&
3740 jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3741 jv[jss::load_base] == 256 &&
3742 jv.isMember(jss::load_factor_server) &&
3743 jv[jss::load_factor_server] == 256 &&
3744 jv.isMember(jss::load_factor_fee_escalation) &&
3745 jv[jss::load_factor_fee_escalation] == 184320 &&
3746 jv.isMember(jss::load_factor_fee_queue) &&
3747 jv[jss::load_factor_fee_queue] == 256 &&
3748 jv.isMember(jss::load_factor_fee_reference) &&
3749 jv[jss::load_factor_fee_reference] == 256;
3755 return jv[jss::type] ==
"serverStatus" &&
3756 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3757 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3758 jv.isMember(jss::load_factor_server) &&
3759 jv[jss::load_factor_server] == 256 &&
3760 jv.isMember(jss::load_factor_fee_escalation) &&
3761 jv[jss::load_factor_fee_escalation] == 256 &&
3762 jv.isMember(jss::load_factor_fee_queue) &&
3763 jv[jss::load_factor_fee_queue] == 256 &&
3764 jv.isMember(jss::load_factor_fee_reference) &&
3765 jv[jss::load_factor_fee_reference] == 256;
3769 return jv[jss::type] ==
"serverStatus";
3772 auto jv = wsc->invoke(
"unsubscribe", stream);
3779 using namespace jtx;
3780 testcase(
"clear queued acct txs");
3782 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3783 auto alice =
Account(
"alice");
3786 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
3787 env.
fund(
XRP(50000000), alice, bob);
3794 auto totalFactor = 0;
3797 numToClear.emplace(metrics.txCount + 1);
3798 for (
int i = 0; i < *numToClear; ++i)
3801 totalFactor += inLedger * inLedger;
3804 metrics.medFeeLevel * totalFactor /
3805 (metrics.txPerLedger * metrics.txPerLedger),
3815 testcase(
"straightfoward positive case");
3818 auto aliceSeq = env.
seq(alice);
3819 for (
int i = 0; i < 2; ++i)
3832 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
3845 checkMetrics(__LINE__, env, 4, std::nullopt, 4, 3, 256);
3850 calcTotalFee(100 * 2 + 8889 + 60911);
3853 env(
noop(alice),
fee(totalFee2),
seq(aliceSeq++));
3855 checkMetrics(__LINE__, env, 0, std::nullopt, 9, 3, 256);
3858 testcase(
"replace last tx with enough to clear queue");
3861 auto aliceSeq = env.
seq(alice);
3862 for (
int i = 0; i < 2; ++i)
3875 checkMetrics(__LINE__, env, 3, std::nullopt, 9, 3, 256);
3881 calcTotalFee(100 * 2, metrics.txCount);
3885 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3888 checkMetrics(__LINE__, env, 0, std::nullopt, 12, 3, 256);
3894 testcase(
"replace middle tx with enough to clear queue");
3898 auto aliceSeq = env.
seq(alice);
3899 for (
int i = 0; i < 5; ++i)
3911 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3914 auto const aliceQueue =
3918 for (
auto const& tx : aliceQueue)
3930 testcase(
"clear queue failure (load)");
3934 auto aliceSeq = env.
seq(alice);
3935 for (
int i = 0; i < 2; ++i)
3939 for (
int i = 0; i < 2; ++i)
3948 std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
3953 feeTrack.setRemoteFee(origFee * 5);
3966 feeTrack.setRemoteFee(origFee);
3985 using namespace jtx;
3986 using namespace std::chrono_literals;
3987 testcase(
"scaling");
3993 {{
"minimum_txn_in_ledger_standalone",
"3"},
3994 {
"normal_consensus_increase_percent",
"25"},
3995 {
"slow_consensus_decrease_percent",
"50"},
3996 {
"target_txn_in_ledger",
"10"},
3997 {
"maximum_txn_per_account",
"200"}}));
3998 auto alice =
Account(
"alice");
4000 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4001 env.
fund(
XRP(50000000), alice);
4004 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4005 auto seqAlice = env.
seq(alice);
4007 for (
int i = 0; i < txCount; ++i)
4009 checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4051 env.
close(env.
now() + 5s, 10000ms);
4056 env.
close(env.
now() + 5s, 10000ms);
4061 env.
close(env.
now() + 5s, 10000ms);
4068 env.
close(env.
now() + 5s, 10000ms);
4079 {{
"minimum_txn_in_ledger_standalone",
"3"},
4080 {
"normal_consensus_increase_percent",
"150"},
4081 {
"slow_consensus_decrease_percent",
"150"},
4082 {
"target_txn_in_ledger",
"10"},
4083 {
"maximum_txn_per_account",
"200"}}));
4084 auto alice =
Account(
"alice");
4086 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4087 env.
fund(
XRP(50000000), alice);
4090 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4091 auto seqAlice = env.
seq(alice);
4093 for (
int i = 0; i < txCount; ++i)
4095 checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4112 env.
close(env.
now() + 5s, 10000ms);
4133 testcase(
"Sequence in queue and open ledger");
4134 using namespace jtx;
4136 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4138 auto const alice =
Account(
"alice");
4144 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4148 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4151 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4154 auto const aliceSeq = env.
seq(alice);
4156 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4172 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4178 checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4183 checkMetrics(__LINE__, env, 3, std::nullopt, 6, 3, 256);
4200 testcase(
"Ticket in queue and open ledger");
4201 using namespace jtx;
4203 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4205 auto alice =
Account(
"alice");
4211 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4215 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4219 env(ticket::create(alice, 4));
4223 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4228 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4236 auto const tx = env.
jt(
4244 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4251 checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4257 checkMetrics(__LINE__, env, 1, std::nullopt, 7, 3, 256);
4262 checkMetrics(__LINE__, env, 2, std::nullopt, 7, 3, 256);
4278 checkMetrics(__LINE__, env, 2, std::nullopt, 8, 3, 256);
4296 testcase(
"Re-execute preflight");
4297 using namespace jtx;
4307 {{
"minimum_txn_in_ledger_standalone",
"1"},
4308 {
"ledgers_in_queue",
"5"},
4309 {
"maximum_txn_per_account",
"10"}},
4310 {{
"account_reserve",
"1000"}, {
"owner_reserve",
"50"}});
4312 Env env(*
this, std::move(cfg));
4314 env.fund(
XRP(10000), alice);
4316 env.fund(
XRP(10000), bob);
4318 env.fund(
XRP(10000), carol);
4320 env.fund(
XRP(10000), daria);
4322 env.fund(
XRP(10000), ellie);
4324 env.fund(
XRP(10000), fiona);
4330 for (i = 0; i <= 257; ++i)
4338 __LINE__, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger, 256);
4343 using namespace std::chrono_literals;
4344 auto closeDuration = 80min;
4345 for (i = 0; i <= 255; ++i)
4346 env.close(closeDuration);
4354 5 * expectedPerLedger,
4355 expectedPerLedger + 1,
4360 auto seqAlice = env.seq(alice);
4361 auto seqBob = env.seq(bob);
4362 auto seqCarol = env.seq(carol);
4363 auto seqDaria = env.seq(daria);
4364 auto seqEllie = env.seq(ellie);
4365 auto seqFiona = env.seq(fiona);
4368 for (
int i = 0; i < 10; ++i)
4382 5 * expectedPerLedger,
4383 expectedPerLedger + 1,
4398 env.close(closeDuration);
4399 auto expectedInLedger = expectedInQueue;
4401 (expectedInQueue > expectedPerLedger + 2
4402 ? expectedInQueue - (expectedPerLedger + 2)
4404 expectedInLedger -= expectedInQueue;
4405 ++expectedPerLedger;
4410 5 * expectedPerLedger,
4415 auto const expectedPerAccount = expectedInQueue / 6;
4416 auto const expectedRemainder = expectedInQueue % 6;
4417 BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4420 seqBob - expectedPerAccount -
4421 (expectedRemainder > 4 ? 1 : 0));
4424 seqCarol - expectedPerAccount -
4425 (expectedRemainder > 3 ? 1 : 0));
4428 seqDaria - expectedPerAccount -
4429 (expectedRemainder > 2 ? 1 : 0));
4432 seqEllie - expectedPerAccount -
4433 (expectedRemainder > 1 ? 1 : 0));
4436 seqFiona - expectedPerAccount -
4437 (expectedRemainder > 0 ? 1 : 0));
4439 }
while (expectedInQueue > 0);
4452 testcase(
"Queue full drop penalty");
4453 using namespace jtx;
4469 int const medFee = 100;
4470 int const hiFee = 1000;
4473 {{
"minimum_txn_in_ledger_standalone",
"5"},
4474 {
"ledgers_in_queue",
"5"},
4475 {
"maximum_txn_per_account",
"30"},
4476 {
"minimum_queue_size",
"50"}});
4478 Env env(*
this, std::move(cfg));
4482 env.fund(
XRP(10000),
noripple(alice, bob, carol, daria, ellie, fiona));
4487 env(ticket::create(bob, 10));
4498 auto seqAlice = env.seq(alice);
4499 auto const seqSaveAlice = seqAlice;
4504 json(R
"({"LastLedgerSequence": 7})"),
4514 json(R
"({"LastLedgerSequence": 7})"),
4527 auto seqCarol = env.seq(carol);
4528 auto seqDaria = env.seq(daria);
4529 auto seqEllie = env.seq(ellie);
4530 auto seqFiona = env.seq(fiona);
4532 for (
int i = 0; i < 7; ++i)
4546 for (
int i = 0; i < 3; ++i)
4559 for (
int i = 0; i < 3; ++i)
4580 for (
int i = 0; i < 4; ++i)
4599 for (
int i = 0; i < 30; ++i)
4600 env.app().getFeeTrack().raiseLocalFee();
4610 while (env.app().getFeeTrack().lowerLocalFee())
4636 seqAlice = seqSaveAlice;
4682 testcase(
"Cancel queued offers");
4683 using namespace jtx;
4687 auto USD = gw[
"USD"];
4690 {{
"minimum_txn_in_ledger_standalone",
"5"},
4691 {
"ledgers_in_queue",
"5"},
4692 {
"maximum_txn_per_account",
"30"},
4693 {
"minimum_queue_size",
"50"}});
4695 Env env(*
this, std::move(cfg));
4707 auto const aliceSeq = env.seq(alice);
4710 env(offer(alice, USD(1000),
XRP(1001)),
4716 env(offer(alice, USD(1000),
XRP(1002)),
4718 json(jss::OfferSequence, aliceSeq),
4734 auto const aliceTkt = env.seq(alice);
4735 env(ticket::create(alice, 6));
4742 auto const aliceSeq = env.seq(alice);
4743 env(offer(alice, USD(1000),
XRP(1000)),
4747 env(offer(alice, USD(1000),
XRP(1001)),
4757 env(offer(alice, USD(1000),
XRP(1002)),
4759 json(jss::OfferSequence, aliceTkt + 4),
4769 env(offer(alice, USD(1000),
XRP(1001)),
4774 env(offer(alice, USD(1000),
XRP(1002)),
4776 json(jss::OfferSequence, aliceSeq),
4795 testcase(
"Zero reference fee");
4796 using namespace jtx;
4804 {{
"minimum_txn_in_ledger_standalone",
"3"}},
4805 {{
"reference_fee",
"0"},
4806 {
"account_reserve",
"0"},
4807 {
"owner_reserve",
"0"}}));
4811 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4814 auto const initQueueMax =
initFee(env, 3, 2, 0, 0, 0);
4819 auto const fee = env.
rpc(
"fee");
4827 auto const& levels =
result[jss::levels];
4829 levels.isMember(jss::median_level) &&
4830 levels[jss::median_level] ==
"128000");
4832 levels.isMember(jss::minimum_level) &&
4833 levels[jss::minimum_level] ==
"256");
4835 levels.isMember(jss::open_ledger_level) &&
4836 levels[jss::open_ledger_level] ==
"256");
4838 levels.isMember(jss::reference_level) &&
4839 levels[jss::reference_level] ==
"256");
4843 drops.isMember(jss::base_fee) &&
4844 drops[jss::base_fee] ==
"0");
4846 drops.isMember(jss::median_fee) &&
4847 drops[jss::base_fee] ==
"0");
4849 drops.isMember(jss::minimum_fee) &&
4850 drops[jss::base_fee] ==
"0");
4852 drops.isMember(jss::open_ledger_fee) &&
4853 drops[jss::base_fee] ==
"0");
4857 checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
4863 checkMetrics(__LINE__, env, 0, initQueueMax, 1, 3, 256);
4877 auto aliceSeq = env.
seq(alice);
4887 auto const fee = env.
rpc(
"fee");
4895 auto const& levels =
result[jss::levels];
4897 levels.isMember(jss::median_level) &&
4898 levels[jss::median_level] ==
"128000");
4900 levels.isMember(jss::minimum_level) &&
4901 levels[jss::minimum_level] ==
"256");
4903 levels.isMember(jss::open_ledger_level) &&
4904 levels[jss::open_ledger_level] ==
"355555");
4906 levels.isMember(jss::reference_level) &&
4907 levels[jss::reference_level] ==
"256");
4911 drops.isMember(jss::base_fee) &&
4912 drops[jss::base_fee] ==
"0");
4914 drops.isMember(jss::median_fee) &&
4915 drops[jss::median_fee] ==
"0");
4917 drops.isMember(jss::minimum_fee) &&
4918 drops[jss::minimum_fee] ==
"0");
4920 drops.isMember(jss::open_ledger_fee) &&
4921 drops[jss::open_ledger_fee] ==
"1389");