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/protocol/ErrorCodes.h>
26 #include <ripple/protocol/jss.h>
27 #include <ripple/protocol/st.h>
29 #include <test/jtx/TestSuite.h>
30 #include <test/jtx/WSClient.h>
31 #include <test/jtx/envconfig.h>
32 #include <test/jtx/ticket.h>
51 FeeLevel64 const expectedMin{expectedMinFeeLevel};
52 FeeLevel64 const expectedMed{expectedMedFeeLevel};
54 using namespace std::string_literals;
65 metrics.txCount == expectedCount
73 metrics.txQMaxSize == expectedMaxCount
82 metrics.txInLedger == expectedInLedger
90 metrics.txPerLedger == expectedPerLedger
98 metrics.minProcessingFeeLevel == expectedMin
101 "minProcessingFeeLevel: "s +
107 metrics.medFeeLevel == expectedMed
116 auto const expectedCurFeeLevel = expectedInLedger > expectedPerLedger
117 ? expectedMed * expectedInLedger * expectedInLedger /
118 (expectedPerLedger * expectedPerLedger)
119 : metrics.referenceFeeLevel;
121 metrics.openLedgerFeeLevel == expectedCurFeeLevel
124 "openLedgerFeeLevel: "s +
135 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
144 auto const& view = *env.
current();
146 auto const base = [&view]() {
147 auto base = view.fees().base;
154 return fee(
toDrops(metrics.openLedgerFeeLevel, base) + 1);
163 auto& section = p->section(
"transaction_queue");
164 section.set(
"ledgers_in_queue",
"2");
165 section.set(
"minimum_queue_size",
"2");
166 section.set(
"min_ledgers_to_compute_size_limit",
"3");
167 section.set(
"max_ledger_counts_to_store",
"100");
168 section.set(
"retry_sequence_percent",
"25");
169 section.set(
"normal_consensus_increase_percent",
"0");
171 for (
auto const& [k, v] : extraTxQ)
176 if (!extraVoting.
empty())
178 auto& votingSection = p->section(
"voting");
179 for (
auto const& [k, v] : extraVoting)
181 votingSection.set(k, v);
185 p->section(
"validation_seed")
186 .legacy(
"shUwVw52ofnCUX5m7kPTKzJdr4HEH");
204 for (
auto i = env.
current()->seq(); i <= 257; ++i)
211 auto const flagMaxQueue = ledgersInQueue * flagPerLedger;
212 checkMetrics(__LINE__, env, 0, flagMaxQueue, 0, flagPerLedger, 256);
221 using namespace std::chrono_literals;
223 checkMetrics(__LINE__, env, 0, flagMaxQueue, 0, expectedPerLedger, 256);
224 auto const fees = env.
current()->fees();
238 testcase(
"queue sequence");
240 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
244 auto charlie =
Account(
"charlie");
256 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
260 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
264 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
268 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
272 checkMetrics(__LINE__, env, 2, std::nullopt, 5, 3, 256);
390 checkMetrics(__LINE__, env, 2, 8, 5, 4, 256, 256 * 700);
405 env(pay(alice, iris,
XRP(1000)),
queued);
426 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
440 metrics.txPerLedger + 1,
449 testcase(
"queue ticket");
451 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
459 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
466 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
473 env(ticket::create(alice, 250),
seq(tkt1 - 1),
queued);
478 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
706 testcase(
"queue tec");
708 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
712 auto USD = gw[
"USD"];
714 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
718 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
743 testcase(
"local tx retry");
745 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
749 auto charlie =
Account(
"charlie");
755 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
759 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
766 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
770 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
774 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
778 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
782 checkMetrics(__LINE__, env, 2, std::nullopt, 4, 2, 256);
786 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 2, 256);
800 testcase(
"last ledger sequence");
802 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
806 auto charlie =
Account(
"charlie");
809 auto felicia =
Account(
"felicia");
813 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
823 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
827 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
832 json(R
"({"LastLedgerSequence":7})"),
842 checkMetrics(__LINE__, env, 5, std::nullopt, 3, 2, 256);
849 aliceStat.begin()->lastValid &&
850 *aliceStat.begin()->lastValid == 8);
851 BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker());
853 auto bobStat = txQ.getAccountTxs(bob.id());
856 bobStat.begin()->feeLevel ==
FeeLevel64{7000 * 256 / 10});
858 BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker());
877 checkMetrics(__LINE__, env, 1, 8, 5, 4, 256, 700 * 256);
888 checkMetrics(__LINE__, env, 8, 8, 5, 4, 257, 700 * 256);
894 checkMetrics(__LINE__, env, 1, 10, 6, 5, 256, 700 * 256);
900 checkMetrics(__LINE__, env, 0, 12, 1, 6, 256, 800 * 256);
910 testcase(
"zero transaction fee");
912 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
920 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
932 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
935 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
939 checkMetrics(__LINE__, env, 2, std::nullopt, 3, 2, 256);
949 auto seqAlice = env.
seq(alice);
950 for (
int i = 0; i < 4; ++i)
953 feeAlice = (feeAlice + 1) * 125 / 100;
959 auto const seqBob = env.
seq(bob);
964 auto feeCarol = feeAlice;
965 auto seqCarol = env.
seq(carol);
966 for (
int i = 0; i < 4; ++i)
969 feeCarol = (feeCarol + 1) * 125 / 100;
1005 using namespace jtx;
1008 testcase(
"fail in preclaim");
1010 auto alice =
Account(
"alice");
1032 using namespace jtx;
1033 testcase(
"queued tx fails");
1035 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
1037 auto alice =
Account(
"alice");
1042 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1046 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
1050 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
1054 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
1058 auto const& jt = env.
jt(
noop(alice));
1072 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
1083 using namespace jtx;
1084 testcase(
"multi tx per account");
1089 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1090 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1092 auto alice =
Account(
"alice");
1094 auto charlie =
Account(
"charlie");
1095 auto daria =
Account(
"daria");
1101 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1104 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1109 checkMetrics(__LINE__, env, 0, initQueueMax, 4, 3, 256);
1113 checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1115 auto aliceSeq = env.
seq(alice);
1116 auto bobSeq = env.
seq(bob);
1117 auto charlieSeq = env.
seq(charlie);
1121 checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1125 checkMetrics(__LINE__, env, 2, initQueueMax, 4, 3, 256);
1129 checkMetrics(__LINE__, env, 3, initQueueMax, 4, 3, 256);
1133 checkMetrics(__LINE__, env, 4, initQueueMax, 4, 3, 256);
1137 checkMetrics(__LINE__, env, 5, initQueueMax, 4, 3, 256);
1142 checkMetrics(__LINE__, env, 6, initQueueMax, 4, 3, 256);
1162 aliceSeq = env.
seq(alice);
1163 auto lastLedgerSeq = env.
current()->info().seq + 2;
1164 for (
auto i = 0; i < 7; i++)
1168 json(jss::LastLedgerSequence, lastLedgerSeq + i),
1178 auto const& baseFee = env.
current()->fees().base;
1179 auto seq = env.
seq(alice);
1181 for (
auto const& tx : aliceStat)
1188 (tx.consequences.fee() ==
drops(aliceFee) &&
1189 tx.consequences.potentialSpend() ==
drops(0) &&
1190 !tx.consequences.isBlocker()) ||
1191 tx.seqProxy.value() == env.
seq(alice) + 6);
1201 json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1234 aliceSeq = env.
seq(alice) + 2;
1253 aliceSeq = env.
seq(alice) + 1;
1260 env.
le(alice)->getFieldAmount(
sfBalance).xrp().drops() - (62);
1303 bobSeq = env.
seq(bob);
1305 for (
int i = 0; i < 10; ++i)
1320 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10 - 1);
1334 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10);
1353 using namespace jtx;
1354 using namespace std::chrono;
1355 testcase("tie breaking");
1357 Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "4"}}));
1359 auto alice = Account("alice");
1360 auto bob = Account("bob");
1361 auto charlie = Account("charlie");
1362 auto daria = Account("daria");
1363 auto elmo = Account("elmo");
1364 auto fred = Account("fred");
1365 auto gwen = Account("gwen");
1366 auto hank = Account("hank");
1368 auto queued = ter(terQUEUED);
1370 BEAST_EXPECT(env.current()->fees().base == 10);
1372 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 4, 256);
1374 // Create several accounts while the fee is cheap so they all apply.
1375 env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
1376 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 4, 256);
1379 checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
1381 env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
1382 checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
1385 checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
1389 // Stuff the ledger and queue so we can verify that
1390 // stuff gets kicked out.
1396 checkMetrics(__LINE__, env, 0, 8, 5, 4, 256);
1398 auto aliceSeq = env.seq(alice);
1399 auto bobSeq = env.seq(bob);
1400 auto charlieSeq = env.seq(charlie);
1401 auto dariaSeq = env.seq(daria);
1402 auto elmoSeq = env.seq(elmo);
1403 auto fredSeq = env.seq(fred);
1404 auto gwenSeq = env.seq(gwen);
1405 auto hankSeq = env.seq(hank);
1407 // This time, use identical fees.
1409 // All of these get into the queue, but one gets dropped when the
1410 // higher fee one is added later. Which one depends on ordering.
1411 env(noop(alice), fee(15), queued);
1412 env(noop(bob), fee(15), queued);
1413 env(noop(charlie), fee(15), queued);
1414 env(noop(daria), fee(15), queued);
1415 env(noop(elmo), fee(15), queued);
1416 env(noop(fred), fee(15), queued);
1417 env(noop(gwen), fee(15), queued);
1418 env(noop(hank), fee(15), queued);
1420 // Queue is full now. Minimum fee now reflects the
1421 // lowest fee in the queue.
1422 checkMetrics(__LINE__, env, 8, 8, 5, 4, 385);
1424 // Try to add another transaction with the default (low) fee,
1425 // it should fail because it can't replace the
one already
1446 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1447 gwenSeq + hankSeq + 6 ==
1448 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1449 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1451 using namespace std::string_literals;
1453 aliceSeq == env.
seq(alice),
1457 bobSeq + 1 == env.
seq(bob),
1461 charlieSeq + 2 == env.
seq(charlie),
1465 dariaSeq + 1 == env.
seq(daria),
1469 elmoSeq + 1 == env.
seq(elmo),
1473 fredSeq == env.
seq(fred),
1477 gwenSeq == env.
seq(gwen),
1481 hankSeq + 1 == env.
seq(hank),
1496 auto getTxsQueued = [&]() {
1499 for (
auto const& tx : txs)
1505 auto qTxCount1 = getTxsQueued();
1510 seq(aliceSeq + qTxCount1[alice.id()]++),
1513 env(noop(bob), seq(bobSeq + qTxCount1[bob.id()]++), fee(15),
queued);
1515 seq(charlieSeq + qTxCount1[charlie.id()]++),
1519 seq(dariaSeq + qTxCount1[daria.id()]++),
1522 env(noop(elmo), seq(elmoSeq + qTxCount1[elmo.id()]++), fee(15),
queued);
1523 env(noop(fred), seq(fredSeq + qTxCount1[fred.id()]++), fee(15),
queued);
1524 env(noop(gwen), seq(gwenSeq + qTxCount1[gwen.id()]++), fee(15),
queued);
1532 seq(aliceSeq + qTxCount1[alice.id()]++),
1544 auto qTxCount2 = getTxsQueued();
1550 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1551 gwenSeq + hankSeq + 7 ==
1552 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1553 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1556 aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] ==
1561 bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.
seq(bob),
1565 charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] ==
1570 dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] ==
1575 elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] ==
1580 fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] ==
1585 gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] ==
1590 hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] ==
1599 using namespace jtx;
1600 testcase(
"acct tx id");
1602 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"1"}}));
1604 auto alice =
Account(
"alice");
1608 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 1, 256);
1611 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 1, 256);
1614 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1620 json(R
"({"AccountTxnID": "0"})"),
1623 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1638 using namespace jtx;
1639 using namespace std::string_literals;
1640 testcase(
"maximum tx");
1646 {{
"minimum_txn_in_ledger_standalone",
"2"},
1647 {
"minimum_txn_in_ledger",
"5"},
1648 {
"target_txn_in_ledger",
"4"},
1649 {
"maximum_txn_in_ledger",
"5"}}));
1651 auto alice =
Account(
"alice");
1653 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1656 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 2, 256);
1658 for (
int i = 0; i < 10; ++i)
1661 checkMetrics(__LINE__, env, 0, std::nullopt, 11, 2, 256);
1673 {{
"minimum_txn_in_ledger",
"200"},
1674 {
"minimum_txn_in_ledger_standalone",
"200"},
1675 {
"target_txn_in_ledger",
"4"},
1676 {
"maximum_txn_in_ledger",
"5"}}));
1684 "The minimum number of low-fee transactions allowed "
1685 "per ledger (minimum_txn_in_ledger) exceeds "
1686 "the maximum number of low-fee transactions allowed per "
1687 "ledger (maximum_txn_in_ledger)."s);
1694 {{
"minimum_txn_in_ledger",
"200"},
1695 {
"minimum_txn_in_ledger_standalone",
"2"},
1696 {
"target_txn_in_ledger",
"4"},
1697 {
"maximum_txn_in_ledger",
"5"}}));
1705 "The minimum number of low-fee transactions allowed "
1706 "per ledger (minimum_txn_in_ledger) exceeds "
1707 "the maximum number of low-fee transactions allowed per "
1708 "ledger (maximum_txn_in_ledger)."s);
1715 {{
"minimum_txn_in_ledger",
"2"},
1716 {
"minimum_txn_in_ledger_standalone",
"200"},
1717 {
"target_txn_in_ledger",
"4"},
1718 {
"maximum_txn_in_ledger",
"5"}}));
1726 "The minimum number of low-fee transactions allowed "
1727 "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1728 "the maximum number of low-fee transactions allowed per "
1729 "ledger (maximum_txn_in_ledger)."s);
1736 using namespace jtx;
1737 testcase(
"unexpected balance change");
1742 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1743 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1745 auto alice =
Account(
"alice");
1751 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1755 checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
1759 checkMetrics(__LINE__, env, 0, initQueueMax, 2, 3, 256);
1760 auto USD = bob[
"USD"];
1763 checkMetrics(__LINE__, env, 0, initQueueMax, 3, 3, 256);
1774 auto aliceSeq = env.
seq(alice);
1783 env(offer(bob,
drops(5000), USD(5000)),
1818 for (
int i = 0; i < 9; ++i)
1833 using namespace jtx;
1834 testcase(
"blockers sequence");
1836 auto alice =
Account(
"alice");
1838 auto charlie =
Account(
"charlie");
1839 auto daria =
Account(
"daria");
1843 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1847 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1851 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1859 env(
regkey(alice, charlie));
1860 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1863 auto const aliceSeq = env.
seq(alice);
1879 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1886 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
1898 auto const aliceSeq = env.
seq(alice);
1913 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1939 auto const aliceSeq = env.
seq(alice);
1963 using namespace jtx;
1964 testcase(
"blockers ticket");
1966 auto alice =
Account(
"alice");
1968 auto charlie =
Account(
"charlie");
1969 auto daria =
Account(
"daria");
1973 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1977 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1982 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1990 env(ticket::create(alice, 250),
seq(tkt - 1));
1992 env(
regkey(alice, charlie));
1993 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1996 auto const aliceSeq = env.
seq(alice);
2012 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2016 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2023 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
2040 auto const aliceSeq = env.
seq(alice);
2065 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2125 using namespace jtx;
2126 testcase(
"In-flight balance checks");
2131 {{
"minimum_txn_in_ledger_standalone",
"3"}},
2132 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
2134 auto alice =
Account(
"alice");
2135 auto charlie =
Account(
"charlie");
2146 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
2150 checkMetrics(__LINE__, env, 0, initQueueMax, 0, limit, 256);
2153 checkMetrics(__LINE__, env, 0, initQueueMax, limit + 1, limit, 256);
2155 auto USD = gw[
"USD"];
2156 auto BUX = gw[
"BUX"];
2160 auto aliceSeq = env.
seq(alice);
2161 auto aliceBal = env.
balance(alice);
2167 env(offer(alice, BUX(5000),
XRP(50000)),
queued);
2168 checkMetrics(__LINE__, env, 1, initQueueMax, limit + 1, limit, 256);
2173 checkMetrics(__LINE__, env, 2, initQueueMax, limit + 1, limit, 256);
2177 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2189 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2190 aliceSeq = env.
seq(alice);
2191 aliceBal = env.
balance(alice);
2197 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2202 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2210 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2214 checkMetrics(__LINE__, env, 0, limit * 2, 3, limit, 256);
2226 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2227 aliceSeq = env.
seq(alice);
2228 aliceBal = env.
balance(alice);
2235 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2243 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2247 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2259 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2260 aliceSeq = env.
seq(alice);
2261 aliceBal = env.
balance(alice);
2265 env(offer(alice, BUX(50),
XRP(500)),
queued);
2269 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2273 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2285 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2287 aliceSeq = env.
seq(alice);
2288 aliceBal = env.
balance(alice);
2293 env(pay(alice, charlie,
XRP(50000)),
queued);
2298 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2302 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2312 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2314 aliceSeq = env.
seq(alice);
2315 aliceBal = env.
balance(alice);
2319 env(pay(alice, charlie,
XRP(500)),
queued);
2323 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2327 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2335 auto const amount = USD(500000);
2336 env(trust(alice, USD(50000000)));
2337 env(trust(charlie, USD(50000000)));
2338 checkMetrics(__LINE__, env, 0, limit * 2, 4, limit, 256);
2343 env(pay(gw, alice, amount));
2344 checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2350 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2352 aliceSeq = env.
seq(alice);
2353 aliceBal = env.
balance(alice);
2354 auto aliceUSD = env.
balance(alice, USD);
2358 env(pay(alice, charlie, amount),
queued);
2363 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2367 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2381 env(offer(gw,
XRP(500000), USD(50000)));
2387 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2389 aliceSeq = env.
seq(alice);
2390 aliceBal = env.
balance(alice);
2391 auto charlieUSD = env.
balance(charlie, USD);
2403 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2407 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2414 balance(charlie, charlieUSD + USD(1000)),
2422 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2424 aliceSeq = env.
seq(alice);
2425 aliceBal = env.
balance(alice);
2426 charlieUSD = env.
balance(charlie, USD);
2437 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2441 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2448 balance(charlie, charlieUSD + USD(500)),
2458 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2460 aliceSeq = env.
seq(alice);
2461 aliceBal = env.
balance(alice);
2468 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2472 checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2479 using namespace jtx;
2481 testcase(
"consequences");
2484 auto const alice =
Account(
"alice");
2503 auto USD = alice[
"USD"];
2506 env.
jt(trust(
"carol", USD(50000000)),
seq(1),
fee(10));
2520 auto const jtx = env.
jt(ticket::create(alice, 1),
seq(1),
fee(10));
2545 using namespace jtx;
2546 testcase(
"acct in queue but empty");
2548 auto alice =
Account(
"alice");
2550 auto charlie =
Account(
"charlie");
2554 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2558 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
2562 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 3, 256);
2566 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
2570 checkMetrics(__LINE__, env, 0, std::nullopt, 5, 3, 256);
2574 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
2642 using namespace jtx;
2647 auto fee = env.
rpc(
"fee");
2654 result.isMember(jss::ledger_current_index) &&
2655 result[jss::ledger_current_index] == 3);
2667 auto const& levels =
result[jss::levels];
2683 result.isMember(jss::ledger_current_index) &&
2684 result[jss::ledger_current_index] == 4);
2695 auto const& levels =
result[jss::levels];
2717 using namespace jtx;
2718 testcase(
"expiration replacement");
2723 {{
"minimum_txn_in_ledger_standalone",
"1"},
2724 {
"ledgers_in_queue",
"10"},
2725 {
"maximum_txn_per_account",
"20"}}));
2728 auto const alice =
Account(
"alice");
2729 auto const bob =
Account(
"bob");
2732 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2734 auto const aliceSeq = env.
seq(alice);
2738 json(R
"({"LastLedgerSequence":5})"),
2742 json(R"({"LastLedgerSequence":5})"),
2746 json(R"({"LastLedgerSequence":10})"),
2750 json(R"({"LastLedgerSequence":11})"),
2752 checkMetrics(__LINE__, env, 4, std::nullopt, 2, 1, 256);
2753 auto const bobSeq = env.
seq(bob);
2757 for (
int i = 0; i < 3 + 4 + 5; ++i)
2761 checkMetrics(__LINE__, env, 4 + 3 + 4 + 5, std::nullopt, 2, 1, 256);
2809 using namespace jtx;
2810 testcase(
"full queue gap handling");
2815 {{
"minimum_txn_in_ledger_standalone",
"1"},
2816 {
"ledgers_in_queue",
"10"},
2817 {
"maximum_txn_per_account",
"11"}}));
2822 auto const alice =
Account(
"alice");
2823 auto const bob =
Account(
"bob");
2826 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2828 auto const aliceSeq = env.
seq(alice);
2833 env(ticket::create(alice, 11),
2839 json(R
"({"LastLedgerSequence":11})"),
2843 json(R"({"LastLedgerSequence":11})"),
2847 json(R"({"LastLedgerSequence":11})"),
2851 json(R"({"LastLedgerSequence":11})"),
2855 json(R"({"LastLedgerSequence":11})"),
2859 json(R"({"LastLedgerSequence": 5})"),
2863 json(R"({"LastLedgerSequence": 5})"),
2867 json(R"({"LastLedgerSequence": 5})"),
2871 json(R"({"LastLedgerSequence":11})"),
2873 checkMetrics(__LINE__, env, 10, std::nullopt, 2, 1, 256);
2875 auto const bobSeq = env.
seq(bob);
2879 for (
int i = 0; i < 2 + 4 + 5; ++i)
2883 checkMetrics(__LINE__, env, 10 + 2 + 4 + 5, std::nullopt, 2, 1, 256);
2966 testcase(
"Autofilled sequence should account for TxQ");
2967 using namespace jtx;
2968 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"6"}}));
2972 auto const alice =
Account(
"alice");
2973 auto const bob =
Account(
"bob");
2974 env.
fund(
XRP(100000), alice, bob);
2977 checkMetrics(__LINE__, env, 0, std::nullopt, 7, 6, 256);
2980 auto const aliceSeq = env.
seq(alice);
2981 auto const lastLedgerSeq = env.
current()->info().seq + 2;
2984 for (
int i = 0; i < 5; ++i)
2991 json(jss::LastLedgerSequence, lastLedgerSeq),
2997 checkMetrics(__LINE__, env, 5, std::nullopt, 7, 6, 256);
2999 auto aliceStat = txQ.getAccountTxs(alice.id());
3002 for (
auto const& tx : aliceStat)
3006 if (
seq.value() == aliceSeq + 2)
3009 tx.lastValid && *tx.lastValid == lastLedgerSeq);
3020 for (
int i = 0; i < 8; ++i)
3022 checkMetrics(__LINE__, env, 13, std::nullopt, 7, 6, 256);
3029 for (
int i = 0; i < 9; ++i)
3036 for (
int i = 0; i < 10; ++i)
3043 auto bobStat = txQ.getAccountTxs(bob.id());
3049 auto aliceStat = txQ.getAccountTxs(alice.id());
3050 auto seq = aliceSeq;
3052 for (
auto const& tx : aliceStat)
3055 if (
seq == aliceSeq + 2)
3068 auto aliceStat = txQ.getAccountTxs(alice.id());
3069 auto seq = aliceSeq;
3071 for (
auto const& tx : aliceStat)
3084 auto bobStat = txQ.getAccountTxs(bob.id());
3088 auto aliceStat = txQ.getAccountTxs(alice.id());
3096 using namespace jtx;
3097 testcase(
"account info");
3099 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3103 env.
fund(
XRP(1000000), alice);
3106 auto const withQueue =
3107 R
"({ "account": ")" + alice.human() + R"(", "queue": true })";
3110 R"(", "queue": true, "ledger_index": 3 })";
3117 info.isMember(jss::result) &&
3118 info[jss::result].isMember(jss::account_data));
3119 BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data));
3123 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3125 info.isMember(jss::result) &&
3126 info[jss::result].isMember(jss::account_data));
3145 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3147 info.isMember(jss::result) &&
3148 info[jss::result].isMember(jss::account_data));
3149 auto const&
result = info[jss::result];
3170 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3172 info.isMember(jss::result) &&
3173 info[jss::result].isMember(jss::account_data));
3174 auto const&
result = info[jss::result];
3187 data[jss::Sequence].asUInt() +
3198 auto const& item =
queued[i];
3208 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3223 json(jss::LastLedgerSequence, 10),
3228 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3230 info.isMember(jss::result) &&
3231 info[jss::result].isMember(jss::account_data));
3232 auto const&
result = info[jss::result];
3233 auto const&
data =
result[jss::account_data];
3245 data[jss::Sequence].asUInt() +
3256 auto const& item =
queued[i];
3265 if (i ==
queued.size() - 1)
3273 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3284 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3286 info.isMember(jss::result) &&
3287 info[jss::result].isMember(jss::account_data));
3288 auto const&
result = info[jss::result];
3289 auto const&
data =
result[jss::account_data];
3301 data[jss::Sequence].asUInt() +
3312 auto const& item =
queued[i];
3316 if (i ==
queued.size() - 1)
3344 info.isMember(jss::result) &&
3354 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3356 info.isMember(jss::result) &&
3357 info[jss::result].isMember(jss::account_data));
3358 auto const&
result = info[jss::result];
3375 using namespace jtx;
3376 testcase(
"server info");
3378 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3382 env.
fund(
XRP(1000000), alice);
3386 auto const server_info = env.
rpc(
"server_info");
3388 server_info.isMember(jss::result) &&
3389 server_info[jss::result].isMember(jss::info));
3390 auto const& info = server_info[jss::result][jss::info];
3392 info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
3396 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3399 auto const server_state = env.
rpc(
"server_state");
3400 auto const& state = server_state[jss::result][jss::state];
3402 state.isMember(jss::load_factor) &&
3403 state[jss::load_factor] == 256);
3405 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3407 state.isMember(jss::load_factor_server) &&
3408 state[jss::load_factor_server] == 256);
3410 state.isMember(jss::load_factor_fee_escalation) &&
3411 state[jss::load_factor_fee_escalation] == 256);
3413 state.isMember(jss::load_factor_fee_queue) &&
3414 state[jss::load_factor_fee_queue] == 256);
3416 state.isMember(jss::load_factor_fee_reference) &&
3417 state[jss::load_factor_fee_reference] == 256);
3425 auto aliceSeq = env.
seq(alice);
3427 for (
auto i = 0; i < 4; ++i)
3433 auto const server_info = env.
rpc(
"server_info");
3435 server_info.isMember(jss::result) &&
3436 server_info[jss::result].isMember(jss::info));
3437 auto const& info = server_info[jss::result][jss::info];
3440 info.isMember(jss::load_factor) &&
3441 info[jss::load_factor] > 888.88 &&
3442 info[jss::load_factor] < 888.89);
3444 info.isMember(jss::load_factor_server) &&
3445 info[jss::load_factor_server] == 1);
3449 info.isMember(jss::load_factor_fee_escalation) &&
3450 info[jss::load_factor_fee_escalation] > 888.88 &&
3451 info[jss::load_factor_fee_escalation] < 888.89);
3454 auto const server_state = env.
rpc(
"server_state");
3455 auto const& state = server_state[jss::result][jss::state];
3457 state.isMember(jss::load_factor) &&
3458 state[jss::load_factor] == 227555);
3460 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3462 state.isMember(jss::load_factor_server) &&
3463 state[jss::load_factor_server] == 256);
3465 state.isMember(jss::load_factor_fee_escalation) &&
3466 state[jss::load_factor_fee_escalation] == 227555);
3468 state.isMember(jss::load_factor_fee_queue) &&
3469 state[jss::load_factor_fee_queue] == 256);
3471 state.isMember(jss::load_factor_fee_reference) &&
3472 state[jss::load_factor_fee_reference] == 256);
3478 auto const server_info = env.
rpc(
"server_info");
3480 server_info.isMember(jss::result) &&
3481 server_info[jss::result].isMember(jss::info));
3482 auto const& info = server_info[jss::result][jss::info];
3485 info.isMember(jss::load_factor) &&
3486 info[jss::load_factor] == 1000);
3490 info.isMember(jss::load_factor_net) &&
3491 info[jss::load_factor_net] == 1000);
3493 info.isMember(jss::load_factor_fee_escalation) &&
3494 info[jss::load_factor_fee_escalation] > 888.88 &&
3495 info[jss::load_factor_fee_escalation] < 888.89);
3498 auto const server_state = env.
rpc(
"server_state");
3499 auto const& state = server_state[jss::result][jss::state];
3501 state.isMember(jss::load_factor) &&
3502 state[jss::load_factor] == 256000);
3504 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3506 state.isMember(jss::load_factor_server) &&
3507 state[jss::load_factor_server] == 256000);
3509 state.isMember(jss::load_factor_fee_escalation) &&
3510 state[jss::load_factor_fee_escalation] == 227555);
3512 state.isMember(jss::load_factor_fee_queue) &&
3513 state[jss::load_factor_fee_queue] == 256);
3515 state.isMember(jss::load_factor_fee_reference) &&
3516 state[jss::load_factor_fee_reference] == 256);
3522 for (
int i = 0; i < 5; ++i)
3527 auto const server_info = env.
rpc(
"server_info");
3529 server_info.isMember(jss::result) &&
3530 server_info[jss::result].isMember(jss::info));
3531 auto const& info = server_info[jss::result][jss::info];
3534 info.isMember(jss::load_factor) &&
3535 info[jss::load_factor] > 888.88 &&
3536 info[jss::load_factor] < 888.89);
3541 info.isMember(jss::load_factor_server) &&
3542 info[jss::load_factor_server] > 1.245 &&
3543 info[jss::load_factor_server] < 2.4415);
3545 info.isMember(jss::load_factor_local) &&
3546 info[jss::load_factor_local] > 1.245 &&
3547 info[jss::load_factor_local] < 2.4415);
3550 info.isMember(jss::load_factor_fee_escalation) &&
3551 info[jss::load_factor_fee_escalation] > 888.88 &&
3552 info[jss::load_factor_fee_escalation] < 888.89);
3555 auto const server_state = env.
rpc(
"server_state");
3556 auto const& state = server_state[jss::result][jss::state];
3558 state.isMember(jss::load_factor) &&
3559 state[jss::load_factor] == 227555);
3561 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3566 state.isMember(jss::load_factor_server) &&
3567 state[jss::load_factor_server] >= 320 &&
3568 state[jss::load_factor_server] <= 625);
3570 state.isMember(jss::load_factor_fee_escalation) &&
3571 state[jss::load_factor_fee_escalation] == 227555);
3573 state.isMember(jss::load_factor_fee_queue) &&
3574 state[jss::load_factor_fee_queue] == 256);
3576 state.isMember(jss::load_factor_fee_reference) &&
3577 state[jss::load_factor_fee_reference] == 256);
3583 auto const server_info = env.
rpc(
"server_info");
3585 server_info.isMember(jss::result) &&
3586 server_info[jss::result].isMember(jss::info));
3587 auto const& info = server_info[jss::result][jss::info];
3594 info.isMember(jss::load_factor) &&
3595 info[jss::load_factor] > 1.245 &&
3596 info[jss::load_factor] < 2.4415);
3599 info.isMember(jss::load_factor_local) &&
3600 info[jss::load_factor_local] > 1.245 &&
3601 info[jss::load_factor_local] < 2.4415);
3603 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3606 auto const server_state = env.
rpc(
"server_state");
3607 auto const& state = server_state[jss::result][jss::state];
3609 state.isMember(jss::load_factor) &&
3610 state[jss::load_factor] >= 320 &&
3611 state[jss::load_factor] <= 625);
3613 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3618 state.isMember(jss::load_factor_server) &&
3619 state[jss::load_factor_server] >= 320 &&
3620 state[jss::load_factor_server] <= 625);
3622 state.isMember(jss::load_factor_fee_escalation) &&
3623 state[jss::load_factor_fee_escalation] == 256);
3625 state.isMember(jss::load_factor_fee_queue) &&
3626 state[jss::load_factor_fee_queue] == 256);
3628 state.isMember(jss::load_factor_fee_reference) &&
3629 state[jss::load_factor_fee_reference] == 256);
3636 using namespace jtx;
3637 testcase(
"server subscribe");
3639 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3643 stream[jss::streams].append(
"server");
3646 auto jv = wsc->invoke(
"subscribe", stream);
3650 Account a{
"a"}, b{
"b"}, c{
"c"}, d{
"d"}, e{
"e"}, f{
"f"}, g{
"g"}, h{
"h"},
3655 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
3658 using namespace std::chrono_literals;
3660 return jv[jss::type] ==
"serverStatus" &&
3661 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3662 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3663 jv.isMember(jss::load_factor_server) &&
3664 jv[jss::load_factor_server] == 256 &&
3665 jv.isMember(jss::load_factor_fee_escalation) &&
3666 jv[jss::load_factor_fee_escalation] == 256 &&
3667 jv.isMember(jss::load_factor_fee_queue) &&
3668 jv[jss::load_factor_fee_queue] == 256 &&
3669 jv.isMember(jss::load_factor_fee_reference) &&
3670 jv[jss::load_factor_fee_reference] == 256;
3674 return jv[jss::type] ==
"serverStatus" &&
3675 jv.isMember(jss::load_factor) &&
3676 jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3677 jv[jss::load_base] == 256 &&
3678 jv.isMember(jss::load_factor_server) &&
3679 jv[jss::load_factor_server] == 256 &&
3680 jv.isMember(jss::load_factor_fee_escalation) &&
3681 jv[jss::load_factor_fee_escalation] == 227555 &&
3682 jv.isMember(jss::load_factor_fee_queue) &&
3683 jv[jss::load_factor_fee_queue] == 256 &&
3684 jv.isMember(jss::load_factor_fee_reference) &&
3685 jv[jss::load_factor_fee_reference] == 256;
3692 return jv[jss::type] ==
"serverStatus" &&
3693 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3694 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3695 jv.isMember(jss::load_factor_server) &&
3696 jv[jss::load_factor_server] == 256 &&
3697 jv.isMember(jss::load_factor_fee_escalation) &&
3698 jv[jss::load_factor_fee_escalation] == 256 &&
3699 jv.isMember(jss::load_factor_fee_queue) &&
3700 jv[jss::load_factor_fee_queue] == 256 &&
3701 jv.isMember(jss::load_factor_fee_reference) &&
3702 jv[jss::load_factor_fee_reference] == 256;
3723 return jv[jss::type] ==
"serverStatus" &&
3724 jv.isMember(jss::load_factor) &&
3725 jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3726 jv[jss::load_base] == 256 &&
3727 jv.isMember(jss::load_factor_server) &&
3728 jv[jss::load_factor_server] == 256 &&
3729 jv.isMember(jss::load_factor_fee_escalation) &&
3730 jv[jss::load_factor_fee_escalation] == 200000 &&
3731 jv.isMember(jss::load_factor_fee_queue) &&
3732 jv[jss::load_factor_fee_queue] == 256 &&
3733 jv.isMember(jss::load_factor_fee_reference) &&
3734 jv[jss::load_factor_fee_reference] == 256;
3740 return jv[jss::type] ==
"serverStatus" &&
3741 jv.isMember(jss::load_factor) &&
3742 jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3743 jv[jss::load_base] == 256 &&
3744 jv.isMember(jss::load_factor_server) &&
3745 jv[jss::load_factor_server] == 256 &&
3746 jv.isMember(jss::load_factor_fee_escalation) &&
3747 jv[jss::load_factor_fee_escalation] == 184320 &&
3748 jv.isMember(jss::load_factor_fee_queue) &&
3749 jv[jss::load_factor_fee_queue] == 256 &&
3750 jv.isMember(jss::load_factor_fee_reference) &&
3751 jv[jss::load_factor_fee_reference] == 256;
3757 return jv[jss::type] ==
"serverStatus" &&
3758 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3759 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3760 jv.isMember(jss::load_factor_server) &&
3761 jv[jss::load_factor_server] == 256 &&
3762 jv.isMember(jss::load_factor_fee_escalation) &&
3763 jv[jss::load_factor_fee_escalation] == 256 &&
3764 jv.isMember(jss::load_factor_fee_queue) &&
3765 jv[jss::load_factor_fee_queue] == 256 &&
3766 jv.isMember(jss::load_factor_fee_reference) &&
3767 jv[jss::load_factor_fee_reference] == 256;
3771 return jv[jss::type] ==
"serverStatus";
3774 auto jv = wsc->invoke(
"unsubscribe", stream);
3781 using namespace jtx;
3782 testcase(
"clear queued acct txs");
3784 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3785 auto alice =
Account(
"alice");
3788 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
3789 env.
fund(
XRP(50000000), alice, bob);
3796 auto totalFactor = 0;
3799 numToClear.emplace(metrics.txCount + 1);
3800 for (
int i = 0; i < *numToClear; ++i)
3803 totalFactor += inLedger * inLedger;
3806 metrics.medFeeLevel * totalFactor /
3807 (metrics.txPerLedger * metrics.txPerLedger),
3817 testcase(
"straightfoward positive case");
3820 auto aliceSeq = env.
seq(alice);
3821 for (
int i = 0; i < 2; ++i)
3834 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
3847 checkMetrics(__LINE__, env, 4, std::nullopt, 4, 3, 256);
3852 calcTotalFee(100 * 2 + 8889 + 60911);
3855 env(
noop(alice),
fee(totalFee2),
seq(aliceSeq++));
3857 checkMetrics(__LINE__, env, 0, std::nullopt, 9, 3, 256);
3860 testcase(
"replace last tx with enough to clear queue");
3863 auto aliceSeq = env.
seq(alice);
3864 for (
int i = 0; i < 2; ++i)
3877 checkMetrics(__LINE__, env, 3, std::nullopt, 9, 3, 256);
3883 calcTotalFee(100 * 2, metrics.txCount);
3887 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3890 checkMetrics(__LINE__, env, 0, std::nullopt, 12, 3, 256);
3896 testcase(
"replace middle tx with enough to clear queue");
3900 auto aliceSeq = env.
seq(alice);
3901 for (
int i = 0; i < 5; ++i)
3913 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3916 auto const aliceQueue =
3920 for (
auto const& tx : aliceQueue)
3932 testcase(
"clear queue failure (load)");
3936 auto aliceSeq = env.
seq(alice);
3937 for (
int i = 0; i < 2; ++i)
3941 for (
int i = 0; i < 2; ++i)
3950 std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
3955 feeTrack.setRemoteFee(origFee * 5);
3968 feeTrack.setRemoteFee(origFee);
3987 using namespace jtx;
3988 using namespace std::chrono_literals;
3989 testcase(
"scaling");
3995 {{
"minimum_txn_in_ledger_standalone",
"3"},
3996 {
"normal_consensus_increase_percent",
"25"},
3997 {
"slow_consensus_decrease_percent",
"50"},
3998 {
"target_txn_in_ledger",
"10"},
3999 {
"maximum_txn_per_account",
"200"}}));
4000 auto alice =
Account(
"alice");
4002 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4003 env.
fund(
XRP(50000000), alice);
4006 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4007 auto seqAlice = env.
seq(alice);
4009 for (
int i = 0; i < txCount; ++i)
4011 checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4053 env.
close(env.
now() + 5s, 10000ms);
4058 env.
close(env.
now() + 5s, 10000ms);
4063 env.
close(env.
now() + 5s, 10000ms);
4070 env.
close(env.
now() + 5s, 10000ms);
4081 {{
"minimum_txn_in_ledger_standalone",
"3"},
4082 {
"normal_consensus_increase_percent",
"150"},
4083 {
"slow_consensus_decrease_percent",
"150"},
4084 {
"target_txn_in_ledger",
"10"},
4085 {
"maximum_txn_per_account",
"200"}}));
4086 auto alice =
Account(
"alice");
4088 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4089 env.
fund(
XRP(50000000), alice);
4092 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4093 auto seqAlice = env.
seq(alice);
4095 for (
int i = 0; i < txCount; ++i)
4097 checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4114 env.
close(env.
now() + 5s, 10000ms);
4135 testcase(
"Sequence in queue and open ledger");
4136 using namespace jtx;
4138 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4140 auto const alice =
Account(
"alice");
4146 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4150 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4153 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4156 auto const aliceSeq = env.
seq(alice);
4158 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4174 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4180 checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4185 checkMetrics(__LINE__, env, 3, std::nullopt, 6, 3, 256);
4202 testcase(
"Ticket in queue and open ledger");
4203 using namespace jtx;
4205 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4207 auto alice =
Account(
"alice");
4213 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4217 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4221 env(ticket::create(alice, 4));
4225 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4230 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4238 auto const tx = env.
jt(
4246 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4253 checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4259 checkMetrics(__LINE__, env, 1, std::nullopt, 7, 3, 256);
4264 checkMetrics(__LINE__, env, 2, std::nullopt, 7, 3, 256);
4280 checkMetrics(__LINE__, env, 2, std::nullopt, 8, 3, 256);
4298 testcase(
"Re-execute preflight");
4299 using namespace jtx;
4309 {{
"minimum_txn_in_ledger_standalone",
"1"},
4310 {
"ledgers_in_queue",
"5"},
4311 {
"maximum_txn_per_account",
"10"}},
4312 {{
"account_reserve",
"1000"}, {
"owner_reserve",
"50"}});
4314 Env env(*
this, std::move(cfg));
4316 env.fund(
XRP(10000), alice);
4318 env.fund(
XRP(10000), bob);
4320 env.fund(
XRP(10000), carol);
4322 env.fund(
XRP(10000), daria);
4324 env.fund(
XRP(10000), ellie);
4326 env.fund(
XRP(10000), fiona);
4332 for (i = 0; i <= 257; ++i)
4340 __LINE__, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger, 256);
4345 using namespace std::chrono_literals;
4346 auto closeDuration = 80min;
4347 for (i = 0; i <= 255; ++i)
4348 env.close(closeDuration);
4356 5 * expectedPerLedger,
4357 expectedPerLedger + 1,
4362 auto seqAlice = env.seq(alice);
4363 auto seqBob = env.seq(bob);
4364 auto seqCarol = env.seq(carol);
4365 auto seqDaria = env.seq(daria);
4366 auto seqEllie = env.seq(ellie);
4367 auto seqFiona = env.seq(fiona);
4370 for (
int i = 0; i < 10; ++i)
4384 5 * expectedPerLedger,
4385 expectedPerLedger + 1,
4400 env.close(closeDuration);
4401 auto expectedInLedger = expectedInQueue;
4403 (expectedInQueue > expectedPerLedger + 2
4404 ? expectedInQueue - (expectedPerLedger + 2)
4406 expectedInLedger -= expectedInQueue;
4407 ++expectedPerLedger;
4412 5 * expectedPerLedger,
4417 auto const expectedPerAccount = expectedInQueue / 6;
4418 auto const expectedRemainder = expectedInQueue % 6;
4419 BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4422 seqBob - expectedPerAccount -
4423 (expectedRemainder > 4 ? 1 : 0));
4426 seqCarol - expectedPerAccount -
4427 (expectedRemainder > 3 ? 1 : 0));
4430 seqDaria - expectedPerAccount -
4431 (expectedRemainder > 2 ? 1 : 0));
4434 seqEllie - expectedPerAccount -
4435 (expectedRemainder > 1 ? 1 : 0));
4438 seqFiona - expectedPerAccount -
4439 (expectedRemainder > 0 ? 1 : 0));
4441 }
while (expectedInQueue > 0);
4454 testcase(
"Queue full drop penalty");
4455 using namespace jtx;
4471 int const medFee = 100;
4472 int const hiFee = 1000;
4475 {{
"minimum_txn_in_ledger_standalone",
"5"},
4476 {
"ledgers_in_queue",
"5"},
4477 {
"maximum_txn_per_account",
"30"},
4478 {
"minimum_queue_size",
"50"}});
4480 Env env(*
this, std::move(cfg));
4484 env.fund(
XRP(10000),
noripple(alice, bob, carol, daria, ellie, fiona));
4489 env(ticket::create(bob, 10));
4500 auto seqAlice = env.seq(alice);
4501 auto const seqSaveAlice = seqAlice;
4506 json(R
"({"LastLedgerSequence": 7})"),
4516 json(R
"({"LastLedgerSequence": 7})"),
4529 auto seqCarol = env.seq(carol);
4530 auto seqDaria = env.seq(daria);
4531 auto seqEllie = env.seq(ellie);
4532 auto seqFiona = env.seq(fiona);
4534 for (
int i = 0; i < 7; ++i)
4548 for (
int i = 0; i < 3; ++i)
4561 for (
int i = 0; i < 3; ++i)
4582 for (
int i = 0; i < 4; ++i)
4601 for (
int i = 0; i < 30; ++i)
4602 env.app().getFeeTrack().raiseLocalFee();
4612 while (env.app().getFeeTrack().lowerLocalFee())
4638 seqAlice = seqSaveAlice;
4684 testcase(
"Cancel queued offers");
4685 using namespace jtx;
4689 auto USD = gw[
"USD"];
4692 {{
"minimum_txn_in_ledger_standalone",
"5"},
4693 {
"ledgers_in_queue",
"5"},
4694 {
"maximum_txn_per_account",
"30"},
4695 {
"minimum_queue_size",
"50"}});
4697 Env env(*
this, std::move(cfg));
4709 auto const aliceSeq = env.seq(alice);
4712 env(offer(alice, USD(1000),
XRP(1001)),
4718 env(offer(alice, USD(1000),
XRP(1002)),
4720 json(jss::OfferSequence, aliceSeq),
4736 auto const aliceTkt = env.seq(alice);
4737 env(ticket::create(alice, 6));
4744 auto const aliceSeq = env.seq(alice);
4745 env(offer(alice, USD(1000),
XRP(1000)),
4749 env(offer(alice, USD(1000),
XRP(1001)),
4759 env(offer(alice, USD(1000),
XRP(1002)),
4761 json(jss::OfferSequence, aliceTkt + 4),
4771 env(offer(alice, USD(1000),
XRP(1001)),
4776 env(offer(alice, USD(1000),
XRP(1002)),
4778 json(jss::OfferSequence, aliceSeq),
4797 testcase(
"Zero reference fee");
4798 using namespace jtx;
4806 {{
"minimum_txn_in_ledger_standalone",
"3"}},
4807 {{
"reference_fee",
"0"},
4808 {
"account_reserve",
"0"},
4809 {
"owner_reserve",
"0"}}));
4813 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4816 auto const initQueueMax =
initFee(env, 3, 2, 0, 0, 0);
4821 auto const fee = env.
rpc(
"fee");
4829 auto const& levels =
result[jss::levels];
4831 levels.isMember(jss::median_level) &&
4832 levels[jss::median_level] ==
"128000");
4834 levels.isMember(jss::minimum_level) &&
4835 levels[jss::minimum_level] ==
"256");
4837 levels.isMember(jss::open_ledger_level) &&
4838 levels[jss::open_ledger_level] ==
"256");
4840 levels.isMember(jss::reference_level) &&
4841 levels[jss::reference_level] ==
"256");
4845 drops.isMember(jss::base_fee) &&
4846 drops[jss::base_fee] ==
"0");
4848 drops.isMember(jss::median_fee) &&
4849 drops[jss::median_fee] ==
"0");
4851 drops.isMember(jss::minimum_fee) &&
4852 drops[jss::minimum_fee] ==
"0");
4854 drops.isMember(jss::open_ledger_fee) &&
4855 drops[jss::open_ledger_fee] ==
"0");
4859 checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
4865 checkMetrics(__LINE__, env, 0, initQueueMax, 1, 3, 256);
4879 auto aliceSeq = env.
seq(alice);
4889 auto const fee = env.
rpc(
"fee");
4897 auto const& levels =
result[jss::levels];
4899 levels.isMember(jss::median_level) &&
4900 levels[jss::median_level] ==
"128000");
4902 levels.isMember(jss::minimum_level) &&
4903 levels[jss::minimum_level] ==
"256");
4905 levels.isMember(jss::open_ledger_level) &&
4906 levels[jss::open_ledger_level] ==
"355555");
4908 levels.isMember(jss::reference_level) &&
4909 levels[jss::reference_level] ==
"256");
4913 drops.isMember(jss::base_fee) &&
4914 drops[jss::base_fee] ==
"0");
4916 drops.isMember(jss::median_fee) &&
4917 drops[jss::median_fee] ==
"0");
4919 drops.isMember(jss::minimum_fee) &&
4920 drops[jss::minimum_fee] ==
"0");
4922 drops.isMember(jss::open_ledger_fee) &&
4923 drops[jss::open_ledger_fee] ==
"1389");