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");
1029 using namespace jtx;
1030 testcase(
"queued tx fails");
1032 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
1034 auto alice =
Account(
"alice");
1039 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1043 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
1047 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
1051 checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
1055 auto const& jt = env.
jt(
noop(alice));
1069 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
1080 using namespace jtx;
1081 testcase(
"multi tx per account");
1086 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1087 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1089 auto alice =
Account(
"alice");
1091 auto charlie =
Account(
"charlie");
1092 auto daria =
Account(
"daria");
1098 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1101 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1106 checkMetrics(__LINE__, env, 0, initQueueMax, 4, 3, 256);
1110 checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1112 auto aliceSeq = env.
seq(alice);
1113 auto bobSeq = env.
seq(bob);
1114 auto charlieSeq = env.
seq(charlie);
1118 checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1122 checkMetrics(__LINE__, env, 2, initQueueMax, 4, 3, 256);
1126 checkMetrics(__LINE__, env, 3, initQueueMax, 4, 3, 256);
1130 checkMetrics(__LINE__, env, 4, initQueueMax, 4, 3, 256);
1134 checkMetrics(__LINE__, env, 5, initQueueMax, 4, 3, 256);
1139 checkMetrics(__LINE__, env, 6, initQueueMax, 4, 3, 256);
1159 aliceSeq = env.
seq(alice);
1160 auto lastLedgerSeq = env.
current()->info().seq + 2;
1161 for (
auto i = 0; i < 7; i++)
1165 json(jss::LastLedgerSequence, lastLedgerSeq + i),
1175 auto const& baseFee = env.
current()->fees().base;
1176 auto seq = env.
seq(alice);
1178 for (
auto const& tx : aliceStat)
1185 (tx.consequences.fee() ==
drops(aliceFee) &&
1186 tx.consequences.potentialSpend() ==
drops(0) &&
1187 !tx.consequences.isBlocker()) ||
1188 tx.seqProxy.value() == env.
seq(alice) + 6);
1198 json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1231 aliceSeq = env.
seq(alice) + 2;
1250 aliceSeq = env.
seq(alice) + 1;
1257 env.
le(alice)->getFieldAmount(
sfBalance).xrp().drops() - (62);
1300 bobSeq = env.
seq(bob);
1302 for (
int i = 0; i < 10; ++i)
1317 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10 - 1);
1331 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10);
1350 using namespace jtx;
1351 using namespace std::chrono;
1352 testcase("tie breaking");
1354 Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "4"}}));
1356 auto alice = Account("alice");
1357 auto bob = Account("bob");
1358 auto charlie = Account("charlie");
1359 auto daria = Account("daria");
1360 auto elmo = Account("elmo");
1361 auto fred = Account("fred");
1362 auto gwen = Account("gwen");
1363 auto hank = Account("hank");
1365 auto queued = ter(terQUEUED);
1367 BEAST_EXPECT(env.current()->fees().base == 10);
1369 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 4, 256);
1371 // Create several accounts while the fee is cheap so they all apply.
1372 env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
1373 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 4, 256);
1376 checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
1378 env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
1379 checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
1382 checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
1386 // Stuff the ledger and queue so we can verify that
1387 // stuff gets kicked out.
1393 checkMetrics(__LINE__, env, 0, 8, 5, 4, 256);
1395 auto aliceSeq = env.seq(alice);
1396 auto bobSeq = env.seq(bob);
1397 auto charlieSeq = env.seq(charlie);
1398 auto dariaSeq = env.seq(daria);
1399 auto elmoSeq = env.seq(elmo);
1400 auto fredSeq = env.seq(fred);
1401 auto gwenSeq = env.seq(gwen);
1402 auto hankSeq = env.seq(hank);
1404 // This time, use identical fees.
1406 // All of these get into the queue, but one gets dropped when the
1407 // higher fee one is added later. Which one depends on ordering.
1408 env(noop(alice), fee(15), queued);
1409 env(noop(bob), fee(15), queued);
1410 env(noop(charlie), fee(15), queued);
1411 env(noop(daria), fee(15), queued);
1412 env(noop(elmo), fee(15), queued);
1413 env(noop(fred), fee(15), queued);
1414 env(noop(gwen), fee(15), queued);
1415 env(noop(hank), fee(15), queued);
1417 // Queue is full now. Minimum fee now reflects the
1418 // lowest fee in the queue.
1419 checkMetrics(__LINE__, env, 8, 8, 5, 4, 385);
1421 // Try to add another transaction with the default (low) fee,
1422 // it should fail because it can't replace the
one already
1443 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1444 gwenSeq + hankSeq + 6 ==
1445 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1446 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1448 using namespace std::string_literals;
1450 aliceSeq == env.
seq(alice),
1454 bobSeq + 1 == env.
seq(bob),
1458 charlieSeq + 2 == env.
seq(charlie),
1462 dariaSeq + 1 == env.
seq(daria),
1466 elmoSeq + 1 == env.
seq(elmo),
1470 fredSeq == env.
seq(fred),
1474 gwenSeq == env.
seq(gwen),
1478 hankSeq + 1 == env.
seq(hank),
1493 auto getTxsQueued = [&]() {
1496 for (
auto const& tx : txs)
1502 auto qTxCount1 = getTxsQueued();
1507 seq(aliceSeq + qTxCount1[alice.id()]++),
1510 env(noop(bob), seq(bobSeq + qTxCount1[bob.id()]++), fee(15),
queued);
1512 seq(charlieSeq + qTxCount1[charlie.id()]++),
1516 seq(dariaSeq + qTxCount1[daria.id()]++),
1519 env(noop(elmo), seq(elmoSeq + qTxCount1[elmo.id()]++), fee(15),
queued);
1520 env(noop(fred), seq(fredSeq + qTxCount1[fred.id()]++), fee(15),
queued);
1521 env(noop(gwen), seq(gwenSeq + qTxCount1[gwen.id()]++), fee(15),
queued);
1529 seq(aliceSeq + qTxCount1[alice.id()]++),
1541 auto qTxCount2 = getTxsQueued();
1547 aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1548 gwenSeq + hankSeq + 7 ==
1549 env.
seq(alice) + env.
seq(bob) + env.
seq(charlie) + env.
seq(daria) +
1550 env.
seq(elmo) + env.
seq(fred) + env.
seq(gwen) + env.
seq(hank));
1553 aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] ==
1558 bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.
seq(bob),
1562 charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] ==
1567 dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] ==
1572 elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] ==
1577 fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] ==
1582 gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] ==
1587 hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] ==
1596 using namespace jtx;
1597 testcase(
"acct tx id");
1599 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"1"}}));
1601 auto alice =
Account(
"alice");
1605 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 1, 256);
1608 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 1, 256);
1611 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1617 json(R
"({"AccountTxnID": "0"})"),
1620 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1635 using namespace jtx;
1636 using namespace std::string_literals;
1637 testcase(
"maximum tx");
1643 {{
"minimum_txn_in_ledger_standalone",
"2"},
1644 {
"minimum_txn_in_ledger",
"5"},
1645 {
"target_txn_in_ledger",
"4"},
1646 {
"maximum_txn_in_ledger",
"5"}}));
1648 auto alice =
Account(
"alice");
1650 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1653 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 2, 256);
1655 for (
int i = 0; i < 10; ++i)
1658 checkMetrics(__LINE__, env, 0, std::nullopt, 11, 2, 256);
1670 {{
"minimum_txn_in_ledger",
"200"},
1671 {
"minimum_txn_in_ledger_standalone",
"200"},
1672 {
"target_txn_in_ledger",
"4"},
1673 {
"maximum_txn_in_ledger",
"5"}}));
1681 "The minimum number of low-fee transactions allowed "
1682 "per ledger (minimum_txn_in_ledger) exceeds "
1683 "the maximum number of low-fee transactions allowed per "
1684 "ledger (maximum_txn_in_ledger)."s);
1691 {{
"minimum_txn_in_ledger",
"200"},
1692 {
"minimum_txn_in_ledger_standalone",
"2"},
1693 {
"target_txn_in_ledger",
"4"},
1694 {
"maximum_txn_in_ledger",
"5"}}));
1702 "The minimum number of low-fee transactions allowed "
1703 "per ledger (minimum_txn_in_ledger) exceeds "
1704 "the maximum number of low-fee transactions allowed per "
1705 "ledger (maximum_txn_in_ledger)."s);
1712 {{
"minimum_txn_in_ledger",
"2"},
1713 {
"minimum_txn_in_ledger_standalone",
"200"},
1714 {
"target_txn_in_ledger",
"4"},
1715 {
"maximum_txn_in_ledger",
"5"}}));
1723 "The minimum number of low-fee transactions allowed "
1724 "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1725 "the maximum number of low-fee transactions allowed per "
1726 "ledger (maximum_txn_in_ledger)."s);
1733 using namespace jtx;
1734 testcase(
"unexpected balance change");
1739 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1740 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1742 auto alice =
Account(
"alice");
1748 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
1752 checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
1756 checkMetrics(__LINE__, env, 0, initQueueMax, 2, 3, 256);
1757 auto USD = bob[
"USD"];
1760 checkMetrics(__LINE__, env, 0, initQueueMax, 3, 3, 256);
1771 auto aliceSeq = env.
seq(alice);
1780 env(offer(bob,
drops(5000), USD(5000)),
1815 for (
int i = 0; i < 9; ++i)
1830 using namespace jtx;
1831 testcase(
"blockers sequence");
1833 auto alice =
Account(
"alice");
1835 auto charlie =
Account(
"charlie");
1836 auto daria =
Account(
"daria");
1840 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1844 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1848 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1856 env(
regkey(alice, charlie));
1857 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1860 auto const aliceSeq = env.
seq(alice);
1876 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1883 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
1895 auto const aliceSeq = env.
seq(alice);
1910 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1936 auto const aliceSeq = env.
seq(alice);
1960 using namespace jtx;
1961 testcase(
"blockers ticket");
1963 auto alice =
Account(
"alice");
1965 auto charlie =
Account(
"charlie");
1966 auto daria =
Account(
"daria");
1970 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1974 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1979 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1987 env(ticket::create(alice, 250),
seq(tkt - 1));
1989 env(
regkey(alice, charlie));
1990 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1993 auto const aliceSeq = env.
seq(alice);
2009 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2013 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2020 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
2037 auto const aliceSeq = env.
seq(alice);
2062 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2122 using namespace jtx;
2123 testcase(
"In-flight balance checks");
2128 {{
"minimum_txn_in_ledger_standalone",
"3"}},
2129 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
2131 auto alice =
Account(
"alice");
2132 auto charlie =
Account(
"charlie");
2143 auto const initQueueMax =
initFee(env, 3, 2, 10, 200, 50);
2147 checkMetrics(__LINE__, env, 0, initQueueMax, 0, limit, 256);
2150 checkMetrics(__LINE__, env, 0, initQueueMax, limit + 1, limit, 256);
2152 auto USD = gw[
"USD"];
2153 auto BUX = gw[
"BUX"];
2157 auto aliceSeq = env.
seq(alice);
2158 auto aliceBal = env.
balance(alice);
2164 env(offer(alice, BUX(5000),
XRP(50000)),
queued);
2165 checkMetrics(__LINE__, env, 1, initQueueMax, limit + 1, limit, 256);
2170 checkMetrics(__LINE__, env, 2, initQueueMax, limit + 1, limit, 256);
2174 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2186 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2187 aliceSeq = env.
seq(alice);
2188 aliceBal = env.
balance(alice);
2194 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2199 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2207 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2211 checkMetrics(__LINE__, env, 0, limit * 2, 3, limit, 256);
2223 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2224 aliceSeq = env.
seq(alice);
2225 aliceBal = env.
balance(alice);
2232 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2240 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2244 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2256 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2257 aliceSeq = env.
seq(alice);
2258 aliceBal = env.
balance(alice);
2262 env(offer(alice, BUX(50),
XRP(500)),
queued);
2266 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2270 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2282 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2284 aliceSeq = env.
seq(alice);
2285 aliceBal = env.
balance(alice);
2290 env(pay(alice, charlie,
XRP(50000)),
queued);
2295 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2299 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2309 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2311 aliceSeq = env.
seq(alice);
2312 aliceBal = env.
balance(alice);
2316 env(pay(alice, charlie,
XRP(500)),
queued);
2320 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2324 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2332 auto const amount = USD(500000);
2333 env(trust(alice, USD(50000000)));
2334 env(trust(charlie, USD(50000000)));
2335 checkMetrics(__LINE__, env, 0, limit * 2, 4, limit, 256);
2340 env(pay(gw, alice, amount));
2341 checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2347 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2349 aliceSeq = env.
seq(alice);
2350 aliceBal = env.
balance(alice);
2351 auto aliceUSD = env.
balance(alice, USD);
2355 env(pay(alice, charlie, amount),
queued);
2360 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2364 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2378 env(offer(gw,
XRP(500000), USD(50000)));
2384 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2386 aliceSeq = env.
seq(alice);
2387 aliceBal = env.
balance(alice);
2388 auto charlieUSD = env.
balance(charlie, USD);
2400 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2404 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2411 balance(charlie, charlieUSD + USD(1000)),
2419 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2421 aliceSeq = env.
seq(alice);
2422 aliceBal = env.
balance(alice);
2423 charlieUSD = env.
balance(charlie, USD);
2434 checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2438 checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2445 balance(charlie, charlieUSD + USD(500)),
2455 checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2457 aliceSeq = env.
seq(alice);
2458 aliceBal = env.
balance(alice);
2465 checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2469 checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2476 using namespace jtx;
2478 testcase(
"consequences");
2481 auto const alice =
Account(
"alice");
2500 auto USD = alice[
"USD"];
2503 env.
jt(trust(
"carol", USD(50000000)),
seq(1),
fee(10));
2517 auto const jtx = env.
jt(ticket::create(alice, 1),
seq(1),
fee(10));
2542 using namespace jtx;
2543 testcase(
"acct in queue but empty");
2545 auto alice =
Account(
"alice");
2547 auto charlie =
Account(
"charlie");
2551 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2555 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
2559 checkMetrics(__LINE__, env, 0, std::nullopt, 3, 3, 256);
2563 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
2567 checkMetrics(__LINE__, env, 0, std::nullopt, 5, 3, 256);
2571 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
2639 using namespace jtx;
2644 auto fee = env.
rpc(
"fee");
2651 result.isMember(jss::ledger_current_index) &&
2652 result[jss::ledger_current_index] == 3);
2664 auto const& levels =
result[jss::levels];
2680 result.isMember(jss::ledger_current_index) &&
2681 result[jss::ledger_current_index] == 4);
2692 auto const& levels =
result[jss::levels];
2714 using namespace jtx;
2715 testcase(
"expiration replacement");
2720 {{
"minimum_txn_in_ledger_standalone",
"1"},
2721 {
"ledgers_in_queue",
"10"},
2722 {
"maximum_txn_per_account",
"20"}}));
2725 auto const alice =
Account(
"alice");
2726 auto const bob =
Account(
"bob");
2729 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2731 auto const aliceSeq = env.
seq(alice);
2735 json(R
"({"LastLedgerSequence":5})"),
2739 json(R"({"LastLedgerSequence":5})"),
2743 json(R"({"LastLedgerSequence":10})"),
2747 json(R"({"LastLedgerSequence":11})"),
2749 checkMetrics(__LINE__, env, 4, std::nullopt, 2, 1, 256);
2750 auto const bobSeq = env.
seq(bob);
2754 for (
int i = 0; i < 3 + 4 + 5; ++i)
2758 checkMetrics(__LINE__, env, 4 + 3 + 4 + 5, std::nullopt, 2, 1, 256);
2806 using namespace jtx;
2807 testcase(
"full queue gap handling");
2812 {{
"minimum_txn_in_ledger_standalone",
"1"},
2813 {
"ledgers_in_queue",
"10"},
2814 {
"maximum_txn_per_account",
"11"}}));
2819 auto const alice =
Account(
"alice");
2820 auto const bob =
Account(
"bob");
2823 checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2825 auto const aliceSeq = env.
seq(alice);
2830 env(ticket::create(alice, 11),
2836 json(R
"({"LastLedgerSequence":11})"),
2840 json(R"({"LastLedgerSequence":11})"),
2844 json(R"({"LastLedgerSequence":11})"),
2848 json(R"({"LastLedgerSequence":11})"),
2852 json(R"({"LastLedgerSequence":11})"),
2856 json(R"({"LastLedgerSequence": 5})"),
2860 json(R"({"LastLedgerSequence": 5})"),
2864 json(R"({"LastLedgerSequence": 5})"),
2868 json(R"({"LastLedgerSequence":11})"),
2870 checkMetrics(__LINE__, env, 10, std::nullopt, 2, 1, 256);
2872 auto const bobSeq = env.
seq(bob);
2876 for (
int i = 0; i < 2 + 4 + 5; ++i)
2880 checkMetrics(__LINE__, env, 10 + 2 + 4 + 5, std::nullopt, 2, 1, 256);
2963 testcase(
"Autofilled sequence should account for TxQ");
2964 using namespace jtx;
2965 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"6"}}));
2969 auto const alice =
Account(
"alice");
2970 auto const bob =
Account(
"bob");
2971 env.
fund(
XRP(100000), alice, bob);
2974 checkMetrics(__LINE__, env, 0, std::nullopt, 7, 6, 256);
2977 auto const aliceSeq = env.
seq(alice);
2978 auto const lastLedgerSeq = env.
current()->info().seq + 2;
2981 for (
int i = 0; i < 5; ++i)
2988 json(jss::LastLedgerSequence, lastLedgerSeq),
2994 checkMetrics(__LINE__, env, 5, std::nullopt, 7, 6, 256);
2996 auto aliceStat = txQ.getAccountTxs(alice.id());
2999 for (
auto const& tx : aliceStat)
3003 if (
seq.value() == aliceSeq + 2)
3006 tx.lastValid && *tx.lastValid == lastLedgerSeq);
3017 for (
int i = 0; i < 8; ++i)
3019 checkMetrics(__LINE__, env, 13, std::nullopt, 7, 6, 256);
3026 for (
int i = 0; i < 9; ++i)
3033 for (
int i = 0; i < 10; ++i)
3040 auto bobStat = txQ.getAccountTxs(bob.id());
3046 auto aliceStat = txQ.getAccountTxs(alice.id());
3047 auto seq = aliceSeq;
3049 for (
auto const& tx : aliceStat)
3052 if (
seq == aliceSeq + 2)
3065 auto aliceStat = txQ.getAccountTxs(alice.id());
3066 auto seq = aliceSeq;
3068 for (
auto const& tx : aliceStat)
3081 auto bobStat = txQ.getAccountTxs(bob.id());
3085 auto aliceStat = txQ.getAccountTxs(alice.id());
3093 using namespace jtx;
3094 testcase(
"account info");
3096 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3100 env.
fund(
XRP(1000000), alice);
3103 auto const withQueue =
3104 R
"({ "account": ")" + alice.human() + R"(", "queue": true })";
3107 R"(", "queue": true, "ledger_index": 3 })";
3114 info.isMember(jss::result) &&
3115 info[jss::result].isMember(jss::account_data));
3116 BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data));
3120 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3122 info.isMember(jss::result) &&
3123 info[jss::result].isMember(jss::account_data));
3142 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3144 info.isMember(jss::result) &&
3145 info[jss::result].isMember(jss::account_data));
3146 auto const&
result = info[jss::result];
3167 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3169 info.isMember(jss::result) &&
3170 info[jss::result].isMember(jss::account_data));
3171 auto const&
result = info[jss::result];
3184 data[jss::Sequence].asUInt() +
3195 auto const& item =
queued[i];
3205 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3220 json(jss::LastLedgerSequence, 10),
3225 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3227 info.isMember(jss::result) &&
3228 info[jss::result].isMember(jss::account_data));
3229 auto const&
result = info[jss::result];
3230 auto const&
data =
result[jss::account_data];
3242 data[jss::Sequence].asUInt() +
3253 auto const& item =
queued[i];
3262 if (i ==
queued.size() - 1)
3270 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3281 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3283 info.isMember(jss::result) &&
3284 info[jss::result].isMember(jss::account_data));
3285 auto const&
result = info[jss::result];
3286 auto const&
data =
result[jss::account_data];
3298 data[jss::Sequence].asUInt() +
3309 auto const& item =
queued[i];
3313 if (i ==
queued.size() - 1)
3341 info.isMember(jss::result) &&
3351 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3353 info.isMember(jss::result) &&
3354 info[jss::result].isMember(jss::account_data));
3355 auto const&
result = info[jss::result];
3372 using namespace jtx;
3373 testcase(
"server info");
3375 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3379 env.
fund(
XRP(1000000), alice);
3383 auto const server_info = env.
rpc(
"server_info");
3385 server_info.isMember(jss::result) &&
3386 server_info[jss::result].isMember(jss::info));
3387 auto const& info = server_info[jss::result][jss::info];
3389 info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
3393 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3396 auto const server_state = env.
rpc(
"server_state");
3397 auto const& state = server_state[jss::result][jss::state];
3399 state.isMember(jss::load_factor) &&
3400 state[jss::load_factor] == 256);
3402 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3404 state.isMember(jss::load_factor_server) &&
3405 state[jss::load_factor_server] == 256);
3407 state.isMember(jss::load_factor_fee_escalation) &&
3408 state[jss::load_factor_fee_escalation] == 256);
3410 state.isMember(jss::load_factor_fee_queue) &&
3411 state[jss::load_factor_fee_queue] == 256);
3413 state.isMember(jss::load_factor_fee_reference) &&
3414 state[jss::load_factor_fee_reference] == 256);
3422 auto aliceSeq = env.
seq(alice);
3424 for (
auto i = 0; i < 4; ++i)
3430 auto const server_info = env.
rpc(
"server_info");
3432 server_info.isMember(jss::result) &&
3433 server_info[jss::result].isMember(jss::info));
3434 auto const& info = server_info[jss::result][jss::info];
3437 info.isMember(jss::load_factor) &&
3438 info[jss::load_factor] > 888.88 &&
3439 info[jss::load_factor] < 888.89);
3441 info.isMember(jss::load_factor_server) &&
3442 info[jss::load_factor_server] == 1);
3446 info.isMember(jss::load_factor_fee_escalation) &&
3447 info[jss::load_factor_fee_escalation] > 888.88 &&
3448 info[jss::load_factor_fee_escalation] < 888.89);
3451 auto const server_state = env.
rpc(
"server_state");
3452 auto const& state = server_state[jss::result][jss::state];
3454 state.isMember(jss::load_factor) &&
3455 state[jss::load_factor] == 227555);
3457 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3459 state.isMember(jss::load_factor_server) &&
3460 state[jss::load_factor_server] == 256);
3462 state.isMember(jss::load_factor_fee_escalation) &&
3463 state[jss::load_factor_fee_escalation] == 227555);
3465 state.isMember(jss::load_factor_fee_queue) &&
3466 state[jss::load_factor_fee_queue] == 256);
3468 state.isMember(jss::load_factor_fee_reference) &&
3469 state[jss::load_factor_fee_reference] == 256);
3475 auto const server_info = env.
rpc(
"server_info");
3477 server_info.isMember(jss::result) &&
3478 server_info[jss::result].isMember(jss::info));
3479 auto const& info = server_info[jss::result][jss::info];
3482 info.isMember(jss::load_factor) &&
3483 info[jss::load_factor] == 1000);
3487 info.isMember(jss::load_factor_net) &&
3488 info[jss::load_factor_net] == 1000);
3490 info.isMember(jss::load_factor_fee_escalation) &&
3491 info[jss::load_factor_fee_escalation] > 888.88 &&
3492 info[jss::load_factor_fee_escalation] < 888.89);
3495 auto const server_state = env.
rpc(
"server_state");
3496 auto const& state = server_state[jss::result][jss::state];
3498 state.isMember(jss::load_factor) &&
3499 state[jss::load_factor] == 256000);
3501 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3503 state.isMember(jss::load_factor_server) &&
3504 state[jss::load_factor_server] == 256000);
3506 state.isMember(jss::load_factor_fee_escalation) &&
3507 state[jss::load_factor_fee_escalation] == 227555);
3509 state.isMember(jss::load_factor_fee_queue) &&
3510 state[jss::load_factor_fee_queue] == 256);
3512 state.isMember(jss::load_factor_fee_reference) &&
3513 state[jss::load_factor_fee_reference] == 256);
3519 for (
int i = 0; i < 5; ++i)
3524 auto const server_info = env.
rpc(
"server_info");
3526 server_info.isMember(jss::result) &&
3527 server_info[jss::result].isMember(jss::info));
3528 auto const& info = server_info[jss::result][jss::info];
3531 info.isMember(jss::load_factor) &&
3532 info[jss::load_factor] > 888.88 &&
3533 info[jss::load_factor] < 888.89);
3538 info.isMember(jss::load_factor_server) &&
3539 info[jss::load_factor_server] > 1.245 &&
3540 info[jss::load_factor_server] < 2.4415);
3542 info.isMember(jss::load_factor_local) &&
3543 info[jss::load_factor_local] > 1.245 &&
3544 info[jss::load_factor_local] < 2.4415);
3547 info.isMember(jss::load_factor_fee_escalation) &&
3548 info[jss::load_factor_fee_escalation] > 888.88 &&
3549 info[jss::load_factor_fee_escalation] < 888.89);
3552 auto const server_state = env.
rpc(
"server_state");
3553 auto const& state = server_state[jss::result][jss::state];
3555 state.isMember(jss::load_factor) &&
3556 state[jss::load_factor] == 227555);
3558 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3563 state.isMember(jss::load_factor_server) &&
3564 state[jss::load_factor_server] >= 320 &&
3565 state[jss::load_factor_server] <= 625);
3567 state.isMember(jss::load_factor_fee_escalation) &&
3568 state[jss::load_factor_fee_escalation] == 227555);
3570 state.isMember(jss::load_factor_fee_queue) &&
3571 state[jss::load_factor_fee_queue] == 256);
3573 state.isMember(jss::load_factor_fee_reference) &&
3574 state[jss::load_factor_fee_reference] == 256);
3580 auto const server_info = env.
rpc(
"server_info");
3582 server_info.isMember(jss::result) &&
3583 server_info[jss::result].isMember(jss::info));
3584 auto const& info = server_info[jss::result][jss::info];
3591 info.isMember(jss::load_factor) &&
3592 info[jss::load_factor] > 1.245 &&
3593 info[jss::load_factor] < 2.4415);
3596 info.isMember(jss::load_factor_local) &&
3597 info[jss::load_factor_local] > 1.245 &&
3598 info[jss::load_factor_local] < 2.4415);
3600 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3603 auto const server_state = env.
rpc(
"server_state");
3604 auto const& state = server_state[jss::result][jss::state];
3606 state.isMember(jss::load_factor) &&
3607 state[jss::load_factor] >= 320 &&
3608 state[jss::load_factor] <= 625);
3610 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3615 state.isMember(jss::load_factor_server) &&
3616 state[jss::load_factor_server] >= 320 &&
3617 state[jss::load_factor_server] <= 625);
3619 state.isMember(jss::load_factor_fee_escalation) &&
3620 state[jss::load_factor_fee_escalation] == 256);
3622 state.isMember(jss::load_factor_fee_queue) &&
3623 state[jss::load_factor_fee_queue] == 256);
3625 state.isMember(jss::load_factor_fee_reference) &&
3626 state[jss::load_factor_fee_reference] == 256);
3633 using namespace jtx;
3634 testcase(
"server subscribe");
3636 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3640 stream[jss::streams].append(
"server");
3643 auto jv = wsc->invoke(
"subscribe", stream);
3647 Account a{
"a"}, b{
"b"}, c{
"c"}, d{
"d"}, e{
"e"}, f{
"f"}, g{
"g"}, h{
"h"},
3652 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
3655 using namespace std::chrono_literals;
3657 return jv[jss::type] ==
"serverStatus" &&
3658 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3659 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3660 jv.isMember(jss::load_factor_server) &&
3661 jv[jss::load_factor_server] == 256 &&
3662 jv.isMember(jss::load_factor_fee_escalation) &&
3663 jv[jss::load_factor_fee_escalation] == 256 &&
3664 jv.isMember(jss::load_factor_fee_queue) &&
3665 jv[jss::load_factor_fee_queue] == 256 &&
3666 jv.isMember(jss::load_factor_fee_reference) &&
3667 jv[jss::load_factor_fee_reference] == 256;
3671 return jv[jss::type] ==
"serverStatus" &&
3672 jv.isMember(jss::load_factor) &&
3673 jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3674 jv[jss::load_base] == 256 &&
3675 jv.isMember(jss::load_factor_server) &&
3676 jv[jss::load_factor_server] == 256 &&
3677 jv.isMember(jss::load_factor_fee_escalation) &&
3678 jv[jss::load_factor_fee_escalation] == 227555 &&
3679 jv.isMember(jss::load_factor_fee_queue) &&
3680 jv[jss::load_factor_fee_queue] == 256 &&
3681 jv.isMember(jss::load_factor_fee_reference) &&
3682 jv[jss::load_factor_fee_reference] == 256;
3689 return jv[jss::type] ==
"serverStatus" &&
3690 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3691 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3692 jv.isMember(jss::load_factor_server) &&
3693 jv[jss::load_factor_server] == 256 &&
3694 jv.isMember(jss::load_factor_fee_escalation) &&
3695 jv[jss::load_factor_fee_escalation] == 256 &&
3696 jv.isMember(jss::load_factor_fee_queue) &&
3697 jv[jss::load_factor_fee_queue] == 256 &&
3698 jv.isMember(jss::load_factor_fee_reference) &&
3699 jv[jss::load_factor_fee_reference] == 256;
3720 return jv[jss::type] ==
"serverStatus" &&
3721 jv.isMember(jss::load_factor) &&
3722 jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3723 jv[jss::load_base] == 256 &&
3724 jv.isMember(jss::load_factor_server) &&
3725 jv[jss::load_factor_server] == 256 &&
3726 jv.isMember(jss::load_factor_fee_escalation) &&
3727 jv[jss::load_factor_fee_escalation] == 200000 &&
3728 jv.isMember(jss::load_factor_fee_queue) &&
3729 jv[jss::load_factor_fee_queue] == 256 &&
3730 jv.isMember(jss::load_factor_fee_reference) &&
3731 jv[jss::load_factor_fee_reference] == 256;
3737 return jv[jss::type] ==
"serverStatus" &&
3738 jv.isMember(jss::load_factor) &&
3739 jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3740 jv[jss::load_base] == 256 &&
3741 jv.isMember(jss::load_factor_server) &&
3742 jv[jss::load_factor_server] == 256 &&
3743 jv.isMember(jss::load_factor_fee_escalation) &&
3744 jv[jss::load_factor_fee_escalation] == 184320 &&
3745 jv.isMember(jss::load_factor_fee_queue) &&
3746 jv[jss::load_factor_fee_queue] == 256 &&
3747 jv.isMember(jss::load_factor_fee_reference) &&
3748 jv[jss::load_factor_fee_reference] == 256;
3754 return jv[jss::type] ==
"serverStatus" &&
3755 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3756 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3757 jv.isMember(jss::load_factor_server) &&
3758 jv[jss::load_factor_server] == 256 &&
3759 jv.isMember(jss::load_factor_fee_escalation) &&
3760 jv[jss::load_factor_fee_escalation] == 256 &&
3761 jv.isMember(jss::load_factor_fee_queue) &&
3762 jv[jss::load_factor_fee_queue] == 256 &&
3763 jv.isMember(jss::load_factor_fee_reference) &&
3764 jv[jss::load_factor_fee_reference] == 256;
3768 return jv[jss::type] ==
"serverStatus";
3771 auto jv = wsc->invoke(
"unsubscribe", stream);
3778 using namespace jtx;
3779 testcase(
"clear queued acct txs");
3781 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3782 auto alice =
Account(
"alice");
3785 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
3786 env.
fund(
XRP(50000000), alice, bob);
3793 auto totalFactor = 0;
3796 numToClear.emplace(metrics.txCount + 1);
3797 for (
int i = 0; i < *numToClear; ++i)
3800 totalFactor += inLedger * inLedger;
3803 metrics.medFeeLevel * totalFactor /
3804 (metrics.txPerLedger * metrics.txPerLedger),
3814 testcase(
"straightfoward positive case");
3817 auto aliceSeq = env.
seq(alice);
3818 for (
int i = 0; i < 2; ++i)
3831 checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
3844 checkMetrics(__LINE__, env, 4, std::nullopt, 4, 3, 256);
3849 calcTotalFee(100 * 2 + 8889 + 60911);
3852 env(
noop(alice),
fee(totalFee2),
seq(aliceSeq++));
3854 checkMetrics(__LINE__, env, 0, std::nullopt, 9, 3, 256);
3857 testcase(
"replace last tx with enough to clear queue");
3860 auto aliceSeq = env.
seq(alice);
3861 for (
int i = 0; i < 2; ++i)
3874 checkMetrics(__LINE__, env, 3, std::nullopt, 9, 3, 256);
3880 calcTotalFee(100 * 2, metrics.txCount);
3884 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3887 checkMetrics(__LINE__, env, 0, std::nullopt, 12, 3, 256);
3893 testcase(
"replace middle tx with enough to clear queue");
3897 auto aliceSeq = env.
seq(alice);
3898 for (
int i = 0; i < 5; ++i)
3910 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3913 auto const aliceQueue =
3917 for (
auto const& tx : aliceQueue)
3929 testcase(
"clear queue failure (load)");
3933 auto aliceSeq = env.
seq(alice);
3934 for (
int i = 0; i < 2; ++i)
3938 for (
int i = 0; i < 2; ++i)
3947 std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
3952 feeTrack.setRemoteFee(origFee * 5);
3965 feeTrack.setRemoteFee(origFee);
3984 using namespace jtx;
3985 using namespace std::chrono_literals;
3986 testcase(
"scaling");
3992 {{
"minimum_txn_in_ledger_standalone",
"3"},
3993 {
"normal_consensus_increase_percent",
"25"},
3994 {
"slow_consensus_decrease_percent",
"50"},
3995 {
"target_txn_in_ledger",
"10"},
3996 {
"maximum_txn_per_account",
"200"}}));
3997 auto alice =
Account(
"alice");
3999 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4000 env.
fund(
XRP(50000000), alice);
4003 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4004 auto seqAlice = env.
seq(alice);
4006 for (
int i = 0; i < txCount; ++i)
4008 checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4050 env.
close(env.
now() + 5s, 10000ms);
4055 env.
close(env.
now() + 5s, 10000ms);
4060 env.
close(env.
now() + 5s, 10000ms);
4067 env.
close(env.
now() + 5s, 10000ms);
4078 {{
"minimum_txn_in_ledger_standalone",
"3"},
4079 {
"normal_consensus_increase_percent",
"150"},
4080 {
"slow_consensus_decrease_percent",
"150"},
4081 {
"target_txn_in_ledger",
"10"},
4082 {
"maximum_txn_per_account",
"200"}}));
4083 auto alice =
Account(
"alice");
4085 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4086 env.
fund(
XRP(50000000), alice);
4089 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4090 auto seqAlice = env.
seq(alice);
4092 for (
int i = 0; i < txCount; ++i)
4094 checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4111 env.
close(env.
now() + 5s, 10000ms);
4132 testcase(
"Sequence in queue and open ledger");
4133 using namespace jtx;
4135 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4137 auto const alice =
Account(
"alice");
4143 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4147 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4150 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4153 auto const aliceSeq = env.
seq(alice);
4155 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4171 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4177 checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4182 checkMetrics(__LINE__, env, 3, std::nullopt, 6, 3, 256);
4199 testcase(
"Ticket in queue and open ledger");
4200 using namespace jtx;
4202 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4204 auto alice =
Account(
"alice");
4210 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4214 checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4218 env(ticket::create(alice, 4));
4222 checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4227 checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4235 auto const tx = env.
jt(
4243 checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4250 checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4256 checkMetrics(__LINE__, env, 1, std::nullopt, 7, 3, 256);
4261 checkMetrics(__LINE__, env, 2, std::nullopt, 7, 3, 256);
4277 checkMetrics(__LINE__, env, 2, std::nullopt, 8, 3, 256);
4295 testcase(
"Re-execute preflight");
4296 using namespace jtx;
4306 {{
"minimum_txn_in_ledger_standalone",
"1"},
4307 {
"ledgers_in_queue",
"5"},
4308 {
"maximum_txn_per_account",
"10"}},
4309 {{
"account_reserve",
"1000"}, {
"owner_reserve",
"50"}});
4311 Env env(*
this, std::move(cfg));
4313 env.fund(
XRP(10000), alice);
4315 env.fund(
XRP(10000), bob);
4317 env.fund(
XRP(10000), carol);
4319 env.fund(
XRP(10000), daria);
4321 env.fund(
XRP(10000), ellie);
4323 env.fund(
XRP(10000), fiona);
4329 for (i = 0; i <= 257; ++i)
4337 __LINE__, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger, 256);
4342 using namespace std::chrono_literals;
4343 auto closeDuration = 80min;
4344 for (i = 0; i <= 255; ++i)
4345 env.close(closeDuration);
4353 5 * expectedPerLedger,
4354 expectedPerLedger + 1,
4359 auto seqAlice = env.seq(alice);
4360 auto seqBob = env.seq(bob);
4361 auto seqCarol = env.seq(carol);
4362 auto seqDaria = env.seq(daria);
4363 auto seqEllie = env.seq(ellie);
4364 auto seqFiona = env.seq(fiona);
4367 for (
int i = 0; i < 10; ++i)
4381 5 * expectedPerLedger,
4382 expectedPerLedger + 1,
4397 env.close(closeDuration);
4398 auto expectedInLedger = expectedInQueue;
4400 (expectedInQueue > expectedPerLedger + 2
4401 ? expectedInQueue - (expectedPerLedger + 2)
4403 expectedInLedger -= expectedInQueue;
4404 ++expectedPerLedger;
4409 5 * expectedPerLedger,
4414 auto const expectedPerAccount = expectedInQueue / 6;
4415 auto const expectedRemainder = expectedInQueue % 6;
4416 BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4419 seqBob - expectedPerAccount -
4420 (expectedRemainder > 4 ? 1 : 0));
4423 seqCarol - expectedPerAccount -
4424 (expectedRemainder > 3 ? 1 : 0));
4427 seqDaria - expectedPerAccount -
4428 (expectedRemainder > 2 ? 1 : 0));
4431 seqEllie - expectedPerAccount -
4432 (expectedRemainder > 1 ? 1 : 0));
4435 seqFiona - expectedPerAccount -
4436 (expectedRemainder > 0 ? 1 : 0));
4438 }
while (expectedInQueue > 0);
4451 testcase(
"Queue full drop penalty");
4452 using namespace jtx;
4468 int const medFee = 100;
4469 int const hiFee = 1000;
4472 {{
"minimum_txn_in_ledger_standalone",
"5"},
4473 {
"ledgers_in_queue",
"5"},
4474 {
"maximum_txn_per_account",
"30"},
4475 {
"minimum_queue_size",
"50"}});
4477 Env env(*
this, std::move(cfg));
4481 env.fund(
XRP(10000),
noripple(alice, bob, carol, daria, ellie, fiona));
4486 env(ticket::create(bob, 10));
4497 auto seqAlice = env.seq(alice);
4498 auto const seqSaveAlice = seqAlice;
4503 json(R
"({"LastLedgerSequence": 7})"),
4513 json(R
"({"LastLedgerSequence": 7})"),
4526 auto seqCarol = env.seq(carol);
4527 auto seqDaria = env.seq(daria);
4528 auto seqEllie = env.seq(ellie);
4529 auto seqFiona = env.seq(fiona);
4531 for (
int i = 0; i < 7; ++i)
4545 for (
int i = 0; i < 3; ++i)
4558 for (
int i = 0; i < 3; ++i)
4579 for (
int i = 0; i < 4; ++i)
4598 for (
int i = 0; i < 30; ++i)
4599 env.app().getFeeTrack().raiseLocalFee();
4609 while (env.app().getFeeTrack().lowerLocalFee())
4635 seqAlice = seqSaveAlice;
4681 testcase(
"Cancel queued offers");
4682 using namespace jtx;
4686 auto USD = gw[
"USD"];
4689 {{
"minimum_txn_in_ledger_standalone",
"5"},
4690 {
"ledgers_in_queue",
"5"},
4691 {
"maximum_txn_per_account",
"30"},
4692 {
"minimum_queue_size",
"50"}});
4694 Env env(*
this, std::move(cfg));
4706 auto const aliceSeq = env.seq(alice);
4709 env(offer(alice, USD(1000),
XRP(1001)),
4715 env(offer(alice, USD(1000),
XRP(1002)),
4717 json(jss::OfferSequence, aliceSeq),
4733 auto const aliceTkt = env.seq(alice);
4734 env(ticket::create(alice, 6));
4741 auto const aliceSeq = env.seq(alice);
4742 env(offer(alice, USD(1000),
XRP(1000)),
4746 env(offer(alice, USD(1000),
XRP(1001)),
4756 env(offer(alice, USD(1000),
XRP(1002)),
4758 json(jss::OfferSequence, aliceTkt + 4),
4768 env(offer(alice, USD(1000),
XRP(1001)),
4773 env(offer(alice, USD(1000),
XRP(1002)),
4775 json(jss::OfferSequence, aliceSeq),
4794 testcase(
"Zero reference fee");
4795 using namespace jtx;
4803 {{
"minimum_txn_in_ledger_standalone",
"3"}},
4804 {{
"reference_fee",
"0"},
4805 {
"account_reserve",
"0"},
4806 {
"owner_reserve",
"0"}}));
4810 checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4813 auto const initQueueMax =
initFee(env, 3, 2, 0, 0, 0);
4818 auto const fee = env.
rpc(
"fee");
4826 auto const& levels =
result[jss::levels];
4828 levels.isMember(jss::median_level) &&
4829 levels[jss::median_level] ==
"128000");
4831 levels.isMember(jss::minimum_level) &&
4832 levels[jss::minimum_level] ==
"256");
4834 levels.isMember(jss::open_ledger_level) &&
4835 levels[jss::open_ledger_level] ==
"256");
4837 levels.isMember(jss::reference_level) &&
4838 levels[jss::reference_level] ==
"256");
4842 drops.isMember(jss::base_fee) &&
4843 drops[jss::base_fee] ==
"0");
4845 drops.isMember(jss::median_fee) &&
4846 drops[jss::base_fee] ==
"0");
4848 drops.isMember(jss::minimum_fee) &&
4849 drops[jss::base_fee] ==
"0");
4851 drops.isMember(jss::open_ledger_fee) &&
4852 drops[jss::base_fee] ==
"0");
4856 checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
4862 checkMetrics(__LINE__, env, 0, initQueueMax, 1, 3, 256);
4876 auto aliceSeq = env.
seq(alice);
4886 auto const fee = env.
rpc(
"fee");
4894 auto const& levels =
result[jss::levels];
4896 levels.isMember(jss::median_level) &&
4897 levels[jss::median_level] ==
"128000");
4899 levels.isMember(jss::minimum_level) &&
4900 levels[jss::minimum_level] ==
"256");
4902 levels.isMember(jss::open_ledger_level) &&
4903 levels[jss::open_ledger_level] ==
"355555");
4905 levels.isMember(jss::reference_level) &&
4906 levels[jss::reference_level] ==
"256");
4910 drops.isMember(jss::base_fee) &&
4911 drops[jss::base_fee] ==
"0");
4913 drops.isMember(jss::median_fee) &&
4914 drops[jss::median_fee] ==
"0");
4916 drops.isMember(jss::minimum_fee) &&
4917 drops[jss::minimum_fee] ==
"0");
4919 drops.isMember(jss::open_ledger_fee) &&
4920 drops[jss::open_ledger_fee] ==
"1389");