20 #include <ripple/app/main/Application.h>
21 #include <ripple/app/misc/LoadFeeTrack.h>
22 #include <ripple/app/misc/TxQ.h>
23 #include <ripple/app/tx/apply.h>
24 #include <ripple/basics/Log.h>
25 #include <ripple/basics/mulDiv.h>
26 #include <ripple/protocol/ErrorCodes.h>
27 #include <ripple/protocol/jss.h>
28 #include <ripple/protocol/st.h>
30 #include <test/jtx/TestSuite.h>
31 #include <test/jtx/WSClient.h>
32 #include <test/jtx/envconfig.h>
33 #include <test/jtx/ticket.h>
51 FeeLevel64 const expectedMin{expectedMinFeeLevel};
52 FeeLevel64 const expectedMed{expectedMedFeeLevel};
59 BEAST_EXPECT(metrics.minProcessingFeeLevel == expectedMin);
61 auto expectedCurFeeLevel = expectedInLedger > expectedPerLedger
62 ? expectedMed * expectedInLedger * expectedInLedger /
63 (expectedPerLedger * expectedPerLedger)
64 : metrics.referenceFeeLevel;
65 BEAST_EXPECT(metrics.openLedgerFeeLevel == expectedCurFeeLevel);
72 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
81 auto const& view = *env.
current();
85 return fee(
toDrops(metrics.openLedgerFeeLevel, view.fees().base) + 1);
94 auto& section = p->section(
"transaction_queue");
95 section.set(
"ledgers_in_queue",
"2");
96 section.set(
"minimum_queue_size",
"2");
97 section.set(
"min_ledgers_to_compute_size_limit",
"3");
98 section.set(
"max_ledger_counts_to_store",
"100");
99 section.set(
"retry_sequence_percent",
"25");
100 section.set(
"normal_consensus_increase_percent",
"0");
102 for (
auto const& [k, v] : extraTxQ)
107 if (!extraVoting.
empty())
109 auto& votingSection = p->section(
"voting");
110 for (
auto const& [k, v] : extraVoting)
112 votingSection.set(k, v);
116 p->section(
"validation_seed")
117 .legacy(
"shUwVw52ofnCUX5m7kPTKzJdr4HEH");
136 for (
auto i = env.
current()->seq(); i <= 257; ++i)
142 auto const flagPerLedger =
144 auto const flagMaxQueue = ledgersInQueue * flagPerLedger;
145 checkMetrics(env, 0, flagMaxQueue, 0, flagPerLedger, 256);
154 using namespace std::chrono_literals;
156 checkMetrics(env, 0, flagMaxQueue, 0, expectedPerLedger, 256);
157 auto const fees = env.
current()->fees();
172 testcase(
"queue sequence");
174 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
178 auto charlie =
Account(
"charlie");
360 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
373 metrics.txPerLedger + 1,
382 testcase(
"queue ticket");
384 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
406 env(ticket::create(alice, 250),
seq(tkt1 - 1),
queued);
639 testcase(
"queue tec");
641 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
645 auto USD = gw[
"USD"];
676 testcase(
"local tx retry");
678 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
682 auto charlie =
Account(
"charlie");
733 testcase(
"last ledger sequence");
735 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
739 auto charlie =
Account(
"charlie");
742 auto felicia =
Account(
"felicia");
765 json(R
"({"LastLedgerSequence":7})"),
782 aliceStat.begin()->lastValid &&
783 *aliceStat.begin()->lastValid == 8);
784 BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker());
786 auto bobStat = txQ.getAccountTxs(bob.id(), *env.
current());
789 bobStat.begin()->feeLevel ==
FeeLevel64{7000 * 256 / 10});
791 BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker());
844 testcase(
"zero transaction fee");
846 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
883 auto seqAlice = env.
seq(alice);
884 for (
int i = 0; i < 4; ++i)
887 feeAlice = (feeAlice + 1) * 125 / 100;
893 auto const seqBob = env.
seq(bob);
898 auto feeCarol = feeAlice;
899 auto seqCarol = env.
seq(carol);
900 for (
int i = 0; i < 4; ++i)
903 feeCarol = (feeCarol + 1) * 125 / 100;
942 testcase(
"fail in preclaim");
964 testcase(
"queued tx fails");
966 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
989 auto const& jt = env.
jt(
noop(alice));
1014 using namespace jtx;
1015 testcase(
"multi tx per account");
1020 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1021 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1023 auto alice =
Account(
"alice");
1025 auto charlie =
Account(
"charlie");
1026 auto daria =
Account(
"daria");
1035 auto const initQueueMax =
initFee(env, 3, 2, 10, 10, 200, 50);
1046 auto aliceSeq = env.
seq(alice);
1047 auto bobSeq = env.
seq(bob);
1048 auto charlieSeq = env.
seq(charlie);
1093 aliceSeq = env.
seq(alice);
1094 auto lastLedgerSeq = env.
current()->info().seq + 2;
1095 for (
auto i = 0; i < 7; i++)
1099 json(jss::LastLedgerSequence, lastLedgerSeq + i),
1109 auto const& baseFee = env.
current()->fees().base;
1110 auto seq = env.
seq(alice);
1112 for (
auto const& tx : aliceStat)
1118 (tx.consequences.fee() ==
drops(
fee) &&
1119 tx.consequences.potentialSpend() ==
drops(0) &&
1120 !tx.consequences.isBlocker()) ||
1121 tx.seqProxy.value() == env.
seq(alice) + 6);
1131 json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1164 aliceSeq = env.
seq(alice) + 2;
1183 aliceSeq = env.
seq(alice) + 1;
1190 env.
le(alice)->getFieldAmount(
sfBalance).xrp().drops() - (59);
1233 bobSeq = env.
seq(bob);
1235 for (
int i = 0; i < 10; ++i)
1250 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10 - 1);
1264 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10);
1283 using namespace jtx;
1284 using namespace std::chrono;
1285 testcase("tie breaking");
1287 Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "4"}}));
1289 auto alice = Account("alice");
1290 auto bob = Account("bob");
1291 auto charlie = Account("charlie");
1292 auto daria = Account("daria");
1293 auto elmo = Account("elmo");
1294 auto fred = Account("fred");
1295 auto gwen = Account("gwen");
1296 auto hank = Account("hank");
1298 auto queued = ter(terQUEUED);
1300 BEAST_EXPECT(env.current()->fees().base == 10);
1302 checkMetrics(env, 0, std::nullopt, 0, 4, 256);
1304 // Create several accounts while the fee is cheap so they all apply.
1305 env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
1306 checkMetrics(env, 0, std::nullopt, 4, 4, 256);
1309 checkMetrics(env, 0, 8, 0, 4, 256);
1311 env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
1312 checkMetrics(env, 0, 8, 4, 4, 256);
1315 checkMetrics(env, 0, 8, 0, 4, 256);
1319 // Stuff the ledger and queue so we can verify that
1320 // stuff gets kicked out.
1326 checkMetrics(env, 0, 8, 5, 4, 256);
1328 auto aliceSeq = env.seq(alice);
1329 auto bobSeq = env.seq(bob);
1330 auto charlieSeq = env.seq(charlie);
1331 auto dariaSeq = env.seq(daria);
1332 auto elmoSeq = env.seq(elmo);
1333 auto fredSeq = env.seq(fred);
1334 auto gwenSeq = env.seq(gwen);
1335 auto hankSeq = env.seq(hank);
1337 // This time, use identical fees.
1338 env(noop(alice), fee(15), queued);
1339 env(noop(bob), fee(15), queued);
1340 env(noop(charlie), fee(15), queued);
1341 env(noop(daria), fee(15), queued);
1342 env(noop(elmo), fee(15), queued);
1343 env(noop(fred), fee(15), queued);
1344 env(noop(gwen), fee(15), queued);
1345 // This one gets into the queue, but gets dropped when the
1346 // higher fee one is added later.
1347 env(noop(hank), fee(15), queued);
1349 // Queue is full now. Minimum fee now reflects the
1350 // lowest fee in the queue.
1351 checkMetrics(env, 8, 8, 5, 4, 385);
1353 // Try to add another transaction with the default (low) fee,
1354 // it should fail because it can't replace the one already
1383 aliceSeq = env.
seq(alice);
1384 bobSeq = env.
seq(bob);
1385 charlieSeq = env.
seq(charlie);
1386 dariaSeq = env.
seq(daria);
1387 elmoSeq = env.
seq(elmo);
1422 using namespace jtx;
1423 testcase(
"acct tx id");
1425 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"1"}}));
1427 auto alice =
Account(
"alice");
1443 json(R
"({"AccountTxnID": "0"})"),
1461 using namespace jtx;
1462 using namespace std::string_literals;
1463 testcase(
"maximum tx");
1469 {{
"minimum_txn_in_ledger_standalone",
"2"},
1470 {
"target_txn_in_ledger",
"4"},
1471 {
"maximum_txn_in_ledger",
"5"}}));
1473 auto alice =
Account(
"alice");
1480 for (
int i = 0; i < 10; ++i)
1495 {{
"minimum_txn_in_ledger",
"200"},
1496 {
"minimum_txn_in_ledger_standalone",
"200"},
1497 {
"target_txn_in_ledger",
"4"},
1498 {
"maximum_txn_in_ledger",
"5"}}));
1506 "The minimum number of low-fee transactions allowed "
1507 "per ledger (minimum_txn_in_ledger) exceeds "
1508 "the maximum number of low-fee transactions allowed per "
1509 "ledger (maximum_txn_in_ledger)."s);
1516 {{
"minimum_txn_in_ledger",
"200"},
1517 {
"minimum_txn_in_ledger_standalone",
"2"},
1518 {
"target_txn_in_ledger",
"4"},
1519 {
"maximum_txn_in_ledger",
"5"}}));
1527 "The minimum number of low-fee transactions allowed "
1528 "per ledger (minimum_txn_in_ledger) exceeds "
1529 "the maximum number of low-fee transactions allowed per "
1530 "ledger (maximum_txn_in_ledger)."s);
1537 {{
"minimum_txn_in_ledger",
"2"},
1538 {
"minimum_txn_in_ledger_standalone",
"200"},
1539 {
"target_txn_in_ledger",
"4"},
1540 {
"maximum_txn_in_ledger",
"5"}}));
1548 "The minimum number of low-fee transactions allowed "
1549 "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1550 "the maximum number of low-fee transactions allowed per "
1551 "ledger (maximum_txn_in_ledger)."s);
1558 using namespace jtx;
1559 testcase(
"unexpected balance change");
1564 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1565 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1567 auto alice =
Account(
"alice");
1573 auto const initQueueMax =
initFee(env, 3, 2, 10, 10, 200, 50);
1582 auto USD = bob[
"USD"];
1596 auto aliceSeq = env.
seq(alice);
1605 env(offer(bob,
drops(5000), USD(5000)),
1640 for (
int i = 0; i < 9; ++i)
1655 using namespace jtx;
1656 testcase(
"blockers sequence");
1658 auto alice =
Account(
"alice");
1660 auto charlie =
Account(
"charlie");
1661 auto daria =
Account(
"daria");
1665 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1681 env(
regkey(alice, charlie));
1685 auto const aliceSeq = env.
seq(alice);
1701 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1720 auto const aliceSeq = env.
seq(alice);
1735 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1761 auto const aliceSeq = env.
seq(alice);
1785 using namespace jtx;
1786 testcase(
"blockers ticket");
1788 auto alice =
Account(
"alice");
1790 auto charlie =
Account(
"charlie");
1791 auto daria =
Account(
"daria");
1795 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1812 env(ticket::create(alice, 250),
seq(tkt - 1));
1814 env(
regkey(alice, charlie));
1818 auto const aliceSeq = env.
seq(alice);
1834 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1838 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1862 auto const aliceSeq = env.
seq(alice);
1887 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1947 using namespace jtx;
1948 testcase(
"In-flight balance checks");
1953 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1954 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1956 auto alice =
Account(
"alice");
1957 auto charlie =
Account(
"charlie");
1968 auto const initQueueMax =
initFee(env, 3, 2, 10, 10, 200, 50);
1975 checkMetrics(env, 0, initQueueMax, limit + 1, limit, 256);
1977 auto USD = gw[
"USD"];
1978 auto BUX = gw[
"BUX"];
1982 auto aliceSeq = env.
seq(alice);
1983 auto aliceBal = env.
balance(alice);
1989 env(offer(alice, BUX(5000),
XRP(50000)),
queued);
1990 checkMetrics(env, 1, initQueueMax, limit + 1, limit, 256);
1995 checkMetrics(env, 2, initQueueMax, limit + 1, limit, 256);
2011 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2012 aliceSeq = env.
seq(alice);
2013 aliceBal = env.
balance(alice);
2019 checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
2024 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2032 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2048 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2049 aliceSeq = env.
seq(alice);
2050 aliceBal = env.
balance(alice);
2057 checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
2065 checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
2081 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2082 aliceSeq = env.
seq(alice);
2083 aliceBal = env.
balance(alice);
2087 env(offer(alice, BUX(50),
XRP(500)),
queued);
2091 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2107 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2109 aliceSeq = env.
seq(alice);
2110 aliceBal = env.
balance(alice);
2120 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2134 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2136 aliceSeq = env.
seq(alice);
2137 aliceBal = env.
balance(alice);
2145 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2157 auto const amount = USD(500000);
2158 env(
trust(alice, USD(50000000)));
2159 env(
trust(charlie, USD(50000000)));
2165 env(
pay(gw, alice, amount));
2172 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2174 aliceSeq = env.
seq(alice);
2175 aliceBal = env.
balance(alice);
2176 auto aliceUSD = env.
balance(alice, USD);
2180 env(
pay(alice, charlie, amount),
queued);
2185 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2203 env(offer(gw,
XRP(500000), USD(50000)));
2209 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2211 aliceSeq = env.
seq(alice);
2212 aliceBal = env.
balance(alice);
2213 auto charlieUSD = env.
balance(charlie, USD);
2225 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2236 balance(charlie, charlieUSD + USD(1000)),
2244 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2246 aliceSeq = env.
seq(alice);
2247 aliceBal = env.
balance(alice);
2248 charlieUSD = env.
balance(charlie, USD);
2259 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2270 balance(charlie, charlieUSD + USD(500)),
2280 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2282 aliceSeq = env.
seq(alice);
2283 aliceBal = env.
balance(alice);
2290 checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
2301 using namespace jtx;
2303 testcase(
"consequences");
2306 auto const alice =
Account(
"alice");
2325 auto USD = alice[
"USD"];
2342 auto const jtx = env.
jt(ticket::create(alice, 1),
seq(1),
fee(10));
2367 using namespace jtx;
2368 testcase(
"acct in queue but empty");
2370 auto alice =
Account(
"alice");
2372 auto charlie =
Account(
"charlie");
2376 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2464 using namespace jtx;
2469 auto fee = env.
rpc(
"fee");
2476 result.isMember(jss::ledger_current_index) &&
2477 result[jss::ledger_current_index] == 3);
2489 auto const& levels =
result[jss::levels];
2505 result.isMember(jss::ledger_current_index) &&
2506 result[jss::ledger_current_index] == 4);
2517 auto const& levels =
result[jss::levels];
2539 using namespace jtx;
2540 testcase(
"expiration replacement");
2545 {{
"minimum_txn_in_ledger_standalone",
"1"},
2546 {
"ledgers_in_queue",
"10"},
2547 {
"maximum_txn_per_account",
"20"}}));
2550 auto const alice =
Account(
"alice");
2551 auto const bob =
Account(
"bob");
2556 auto const aliceSeq = env.
seq(alice);
2560 json(R
"({"LastLedgerSequence":5})"),
2564 json(R"({"LastLedgerSequence":5})"),
2568 json(R"({"LastLedgerSequence":10})"),
2572 json(R"({"LastLedgerSequence":11})"),
2575 auto const bobSeq = env.
seq(bob);
2579 for (
int i = 0; i < 3 + 4 + 5; ++i)
2583 checkMetrics(env, 4 + 3 + 4 + 5, std::nullopt, 2, 1, 256);
2631 using namespace jtx;
2632 testcase(
"full queue gap handling");
2637 {{
"minimum_txn_in_ledger_standalone",
"1"},
2638 {
"ledgers_in_queue",
"10"},
2639 {
"maximum_txn_per_account",
"11"}}));
2644 auto const alice =
Account(
"alice");
2645 auto const bob =
Account(
"bob");
2650 auto const aliceSeq = env.
seq(alice);
2655 env(ticket::create(alice, 11),
2661 json(R
"({"LastLedgerSequence":11})"),
2665 json(R"({"LastLedgerSequence":11})"),
2669 json(R"({"LastLedgerSequence":11})"),
2673 json(R"({"LastLedgerSequence":11})"),
2677 json(R"({"LastLedgerSequence":11})"),
2681 json(R"({"LastLedgerSequence": 5})"),
2685 json(R"({"LastLedgerSequence": 5})"),
2689 json(R"({"LastLedgerSequence": 5})"),
2693 json(R"({"LastLedgerSequence":11})"),
2697 auto const bobSeq = env.
seq(bob);
2701 for (
int i = 0; i < 2 + 4 + 5; ++i)
2705 checkMetrics(env, 10 + 2 + 4 + 5, std::nullopt, 2, 1, 256);
2788 testcase(
"Autofilled sequence should account for TxQ");
2789 using namespace jtx;
2790 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"6"}}));
2794 auto const alice =
Account(
"alice");
2795 auto const bob =
Account(
"bob");
2796 env.
fund(
XRP(100000), alice, bob);
2802 auto const aliceSeq = env.
seq(alice);
2803 auto const lastLedgerSeq = env.
current()->info().seq + 2;
2806 for (
int i = 0; i < 5; ++i)
2813 json(jss::LastLedgerSequence, lastLedgerSeq),
2821 auto aliceStat = txQ.getAccountTxs(alice.id(), *env.
current());
2824 for (
auto const& tx : aliceStat)
2828 if (
seq.value() == aliceSeq + 2)
2831 tx.lastValid && *tx.lastValid == lastLedgerSeq);
2842 for (
int i = 0; i < 8; ++i)
2851 for (
int i = 0; i < 9; ++i)
2858 for (
int i = 0; i < 10; ++i)
2865 auto bobStat = txQ.getAccountTxs(bob.id(), *env.
current());
2871 auto aliceStat = txQ.getAccountTxs(alice.id(), *env.
current());
2872 auto seq = aliceSeq;
2874 for (
auto const& tx : aliceStat)
2877 if (
seq == aliceSeq + 2)
2890 auto aliceStat = txQ.getAccountTxs(alice.id(), *env.
current());
2891 auto seq = aliceSeq;
2893 for (
auto const& tx : aliceStat)
2906 auto bobStat = txQ.getAccountTxs(bob.id(), *env.
current());
2910 auto aliceStat = txQ.getAccountTxs(alice.id(), *env.
current());
2918 using namespace jtx;
2919 testcase(
"account info");
2921 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2925 env.
fund(
XRP(1000000), alice);
2928 auto const withQueue =
2929 R
"({ "account": ")" + alice.human() + R"(", "queue": true })";
2932 R"(", "queue": true, "ledger_index": 3 })";
2939 info.isMember(jss::result) &&
2940 info[jss::result].isMember(jss::account_data));
2941 BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data));
2945 auto const info = env.
rpc(
"json",
"account_info", withQueue);
2947 info.isMember(jss::result) &&
2948 info[jss::result].isMember(jss::account_data));
2967 auto const info = env.
rpc(
"json",
"account_info", withQueue);
2969 info.isMember(jss::result) &&
2970 info[jss::result].isMember(jss::account_data));
2971 auto const&
result = info[jss::result];
2992 auto const info = env.
rpc(
"json",
"account_info", withQueue);
2994 info.isMember(jss::result) &&
2995 info[jss::result].isMember(jss::account_data));
2996 auto const&
result = info[jss::result];
3009 data[jss::Sequence].asUInt() +
3020 auto const& item =
queued[i];
3030 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3045 json(jss::LastLedgerSequence, 10),
3050 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3052 info.isMember(jss::result) &&
3053 info[jss::result].isMember(jss::account_data));
3054 auto const&
result = info[jss::result];
3055 auto const&
data =
result[jss::account_data];
3067 data[jss::Sequence].asUInt() +
3078 auto const& item =
queued[i];
3087 if (i ==
queued.size() - 1)
3095 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3106 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3108 info.isMember(jss::result) &&
3109 info[jss::result].isMember(jss::account_data));
3110 auto const&
result = info[jss::result];
3111 auto const&
data =
result[jss::account_data];
3123 data[jss::Sequence].asUInt() +
3134 auto const& item =
queued[i];
3138 if (i ==
queued.size() - 1)
3166 info.isMember(jss::result) &&
3176 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3178 info.isMember(jss::result) &&
3179 info[jss::result].isMember(jss::account_data));
3180 auto const&
result = info[jss::result];
3197 using namespace jtx;
3198 testcase(
"server info");
3200 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3204 env.
fund(
XRP(1000000), alice);
3208 auto const server_info = env.
rpc(
"server_info");
3210 server_info.isMember(jss::result) &&
3211 server_info[jss::result].isMember(jss::info));
3212 auto const& info = server_info[jss::result][jss::info];
3214 info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
3218 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3221 auto const server_state = env.
rpc(
"server_state");
3222 auto const& state = server_state[jss::result][jss::state];
3224 state.isMember(jss::load_factor) &&
3225 state[jss::load_factor] == 256);
3227 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3229 state.isMember(jss::load_factor_server) &&
3230 state[jss::load_factor_server] == 256);
3232 state.isMember(jss::load_factor_fee_escalation) &&
3233 state[jss::load_factor_fee_escalation] == 256);
3235 state.isMember(jss::load_factor_fee_queue) &&
3236 state[jss::load_factor_fee_queue] == 256);
3238 state.isMember(jss::load_factor_fee_reference) &&
3239 state[jss::load_factor_fee_reference] == 256);
3247 auto aliceSeq = env.
seq(alice);
3249 for (
auto i = 0; i < 4; ++i)
3255 auto const server_info = env.
rpc(
"server_info");
3257 server_info.isMember(jss::result) &&
3258 server_info[jss::result].isMember(jss::info));
3259 auto const& info = server_info[jss::result][jss::info];
3262 info.isMember(jss::load_factor) &&
3263 info[jss::load_factor] > 888.88 &&
3264 info[jss::load_factor] < 888.89);
3266 info.isMember(jss::load_factor_server) &&
3267 info[jss::load_factor_server] == 1);
3271 info.isMember(jss::load_factor_fee_escalation) &&
3272 info[jss::load_factor_fee_escalation] > 888.88 &&
3273 info[jss::load_factor_fee_escalation] < 888.89);
3276 auto const server_state = env.
rpc(
"server_state");
3277 auto const& state = server_state[jss::result][jss::state];
3279 state.isMember(jss::load_factor) &&
3280 state[jss::load_factor] == 227555);
3282 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3284 state.isMember(jss::load_factor_server) &&
3285 state[jss::load_factor_server] == 256);
3287 state.isMember(jss::load_factor_fee_escalation) &&
3288 state[jss::load_factor_fee_escalation] == 227555);
3290 state.isMember(jss::load_factor_fee_queue) &&
3291 state[jss::load_factor_fee_queue] == 256);
3293 state.isMember(jss::load_factor_fee_reference) &&
3294 state[jss::load_factor_fee_reference] == 256);
3300 auto const server_info = env.
rpc(
"server_info");
3302 server_info.isMember(jss::result) &&
3303 server_info[jss::result].isMember(jss::info));
3304 auto const& info = server_info[jss::result][jss::info];
3307 info.isMember(jss::load_factor) &&
3308 info[jss::load_factor] == 1000);
3312 info.isMember(jss::load_factor_net) &&
3313 info[jss::load_factor_net] == 1000);
3315 info.isMember(jss::load_factor_fee_escalation) &&
3316 info[jss::load_factor_fee_escalation] > 888.88 &&
3317 info[jss::load_factor_fee_escalation] < 888.89);
3320 auto const server_state = env.
rpc(
"server_state");
3321 auto const& state = server_state[jss::result][jss::state];
3323 state.isMember(jss::load_factor) &&
3324 state[jss::load_factor] == 256000);
3326 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3328 state.isMember(jss::load_factor_server) &&
3329 state[jss::load_factor_server] == 256000);
3331 state.isMember(jss::load_factor_fee_escalation) &&
3332 state[jss::load_factor_fee_escalation] == 227555);
3334 state.isMember(jss::load_factor_fee_queue) &&
3335 state[jss::load_factor_fee_queue] == 256);
3337 state.isMember(jss::load_factor_fee_reference) &&
3338 state[jss::load_factor_fee_reference] == 256);
3344 for (
int i = 0; i < 5; ++i)
3349 auto const server_info = env.
rpc(
"server_info");
3351 server_info.isMember(jss::result) &&
3352 server_info[jss::result].isMember(jss::info));
3353 auto const& info = server_info[jss::result][jss::info];
3356 info.isMember(jss::load_factor) &&
3357 info[jss::load_factor] > 888.88 &&
3358 info[jss::load_factor] < 888.89);
3363 info.isMember(jss::load_factor_server) &&
3364 info[jss::load_factor_server] > 1.245 &&
3365 info[jss::load_factor_server] < 2.4415);
3367 info.isMember(jss::load_factor_local) &&
3368 info[jss::load_factor_local] > 1.245 &&
3369 info[jss::load_factor_local] < 2.4415);
3372 info.isMember(jss::load_factor_fee_escalation) &&
3373 info[jss::load_factor_fee_escalation] > 888.88 &&
3374 info[jss::load_factor_fee_escalation] < 888.89);
3377 auto const server_state = env.
rpc(
"server_state");
3378 auto const& state = server_state[jss::result][jss::state];
3380 state.isMember(jss::load_factor) &&
3381 state[jss::load_factor] == 227555);
3383 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3388 state.isMember(jss::load_factor_server) &&
3389 state[jss::load_factor_server] >= 320 &&
3390 state[jss::load_factor_server] <= 625);
3392 state.isMember(jss::load_factor_fee_escalation) &&
3393 state[jss::load_factor_fee_escalation] == 227555);
3395 state.isMember(jss::load_factor_fee_queue) &&
3396 state[jss::load_factor_fee_queue] == 256);
3398 state.isMember(jss::load_factor_fee_reference) &&
3399 state[jss::load_factor_fee_reference] == 256);
3405 auto const server_info = env.
rpc(
"server_info");
3407 server_info.isMember(jss::result) &&
3408 server_info[jss::result].isMember(jss::info));
3409 auto const& info = server_info[jss::result][jss::info];
3416 info.isMember(jss::load_factor) &&
3417 info[jss::load_factor] > 1.245 &&
3418 info[jss::load_factor] < 2.4415);
3421 info.isMember(jss::load_factor_local) &&
3422 info[jss::load_factor_local] > 1.245 &&
3423 info[jss::load_factor_local] < 2.4415);
3425 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3428 auto const server_state = env.
rpc(
"server_state");
3429 auto const& state = server_state[jss::result][jss::state];
3431 state.isMember(jss::load_factor) &&
3432 state[jss::load_factor] >= 320 &&
3433 state[jss::load_factor] <= 625);
3435 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3440 state.isMember(jss::load_factor_server) &&
3441 state[jss::load_factor_server] >= 320 &&
3442 state[jss::load_factor_server] <= 625);
3444 state.isMember(jss::load_factor_fee_escalation) &&
3445 state[jss::load_factor_fee_escalation] == 256);
3447 state.isMember(jss::load_factor_fee_queue) &&
3448 state[jss::load_factor_fee_queue] == 256);
3450 state.isMember(jss::load_factor_fee_reference) &&
3451 state[jss::load_factor_fee_reference] == 256);
3458 using namespace jtx;
3459 testcase(
"server subscribe");
3461 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3465 stream[jss::streams].append(
"server");
3468 auto jv = wsc->invoke(
"subscribe", stream);
3472 Account a{
"a"}, b{
"b"}, c{
"c"}, d{
"d"}, e{
"e"}, f{
"f"}, g{
"g"}, h{
"h"},
3480 using namespace std::chrono_literals;
3482 return jv[jss::type] ==
"serverStatus" &&
3483 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3484 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3485 jv.isMember(jss::load_factor_server) &&
3486 jv[jss::load_factor_server] == 256 &&
3487 jv.isMember(jss::load_factor_fee_escalation) &&
3488 jv[jss::load_factor_fee_escalation] == 256 &&
3489 jv.isMember(jss::load_factor_fee_queue) &&
3490 jv[jss::load_factor_fee_queue] == 256 &&
3491 jv.isMember(jss::load_factor_fee_reference) &&
3492 jv[jss::load_factor_fee_reference] == 256;
3496 return jv[jss::type] ==
"serverStatus" &&
3497 jv.isMember(jss::load_factor) &&
3498 jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3499 jv[jss::load_base] == 256 &&
3500 jv.isMember(jss::load_factor_server) &&
3501 jv[jss::load_factor_server] == 256 &&
3502 jv.isMember(jss::load_factor_fee_escalation) &&
3503 jv[jss::load_factor_fee_escalation] == 227555 &&
3504 jv.isMember(jss::load_factor_fee_queue) &&
3505 jv[jss::load_factor_fee_queue] == 256 &&
3506 jv.isMember(jss::load_factor_fee_reference) &&
3507 jv[jss::load_factor_fee_reference] == 256;
3514 return jv[jss::type] ==
"serverStatus" &&
3515 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3516 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3517 jv.isMember(jss::load_factor_server) &&
3518 jv[jss::load_factor_server] == 256 &&
3519 jv.isMember(jss::load_factor_fee_escalation) &&
3520 jv[jss::load_factor_fee_escalation] == 256 &&
3521 jv.isMember(jss::load_factor_fee_queue) &&
3522 jv[jss::load_factor_fee_queue] == 256 &&
3523 jv.isMember(jss::load_factor_fee_reference) &&
3524 jv[jss::load_factor_fee_reference] == 256;
3545 return jv[jss::type] ==
"serverStatus" &&
3546 jv.isMember(jss::load_factor) &&
3547 jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3548 jv[jss::load_base] == 256 &&
3549 jv.isMember(jss::load_factor_server) &&
3550 jv[jss::load_factor_server] == 256 &&
3551 jv.isMember(jss::load_factor_fee_escalation) &&
3552 jv[jss::load_factor_fee_escalation] == 200000 &&
3553 jv.isMember(jss::load_factor_fee_queue) &&
3554 jv[jss::load_factor_fee_queue] == 256 &&
3555 jv.isMember(jss::load_factor_fee_reference) &&
3556 jv[jss::load_factor_fee_reference] == 256;
3562 return jv[jss::type] ==
"serverStatus" &&
3563 jv.isMember(jss::load_factor) &&
3564 jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3565 jv[jss::load_base] == 256 &&
3566 jv.isMember(jss::load_factor_server) &&
3567 jv[jss::load_factor_server] == 256 &&
3568 jv.isMember(jss::load_factor_fee_escalation) &&
3569 jv[jss::load_factor_fee_escalation] == 184320 &&
3570 jv.isMember(jss::load_factor_fee_queue) &&
3571 jv[jss::load_factor_fee_queue] == 256 &&
3572 jv.isMember(jss::load_factor_fee_reference) &&
3573 jv[jss::load_factor_fee_reference] == 256;
3579 return jv[jss::type] ==
"serverStatus" &&
3580 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3581 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3582 jv.isMember(jss::load_factor_server) &&
3583 jv[jss::load_factor_server] == 256 &&
3584 jv.isMember(jss::load_factor_fee_escalation) &&
3585 jv[jss::load_factor_fee_escalation] == 256 &&
3586 jv.isMember(jss::load_factor_fee_queue) &&
3587 jv[jss::load_factor_fee_queue] == 256 &&
3588 jv.isMember(jss::load_factor_fee_reference) &&
3589 jv[jss::load_factor_fee_reference] == 256;
3593 return jv[jss::type] ==
"serverStatus";
3596 auto jv = wsc->invoke(
"unsubscribe", stream);
3603 using namespace jtx;
3604 testcase(
"clear queued acct txs");
3606 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3607 auto alice =
Account(
"alice");
3611 env.
fund(
XRP(50000000), alice, bob);
3618 auto totalFactor = 0;
3621 numToClear.emplace(metrics.txCount + 1);
3622 for (
int i = 0; i < *numToClear; ++i)
3625 totalFactor += inLedger * inLedger;
3628 metrics.medFeeLevel * totalFactor /
3629 (metrics.txPerLedger * metrics.txPerLedger),
3639 testcase(
"straightfoward positive case");
3642 auto aliceSeq = env.
seq(alice);
3643 for (
int i = 0; i < 2; ++i)
3674 calcTotalFee(100 * 2 + 8889 + 60911);
3677 env(
noop(alice),
fee(totalFee2),
seq(aliceSeq++));
3682 testcase(
"replace last tx with enough to clear queue");
3685 auto aliceSeq = env.
seq(alice);
3686 for (
int i = 0; i < 2; ++i)
3705 calcTotalFee(100 * 2, metrics.txCount);
3709 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3718 testcase(
"replace middle tx with enough to clear queue");
3722 auto aliceSeq = env.
seq(alice);
3723 for (
int i = 0; i < 5; ++i)
3735 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3738 auto const aliceQueue =
3742 for (
auto const& tx : aliceQueue)
3754 testcase(
"clear queue failure (load)");
3758 auto aliceSeq = env.
seq(alice);
3759 for (
int i = 0; i < 2; ++i)
3763 for (
int i = 0; i < 2; ++i)
3772 std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
3777 feeTrack.setRemoteFee(origFee * 5);
3790 feeTrack.setRemoteFee(origFee);
3809 using namespace jtx;
3810 using namespace std::chrono_literals;
3811 testcase(
"scaling");
3817 {{
"minimum_txn_in_ledger_standalone",
"3"},
3818 {
"normal_consensus_increase_percent",
"25"},
3819 {
"slow_consensus_decrease_percent",
"50"},
3820 {
"target_txn_in_ledger",
"10"},
3821 {
"maximum_txn_per_account",
"200"}}));
3822 auto alice =
Account(
"alice");
3825 env.
fund(
XRP(50000000), alice);
3829 auto seqAlice = env.
seq(alice);
3831 for (
int i = 0; i < txCount; ++i)
3875 env.
close(env.
now() + 5s, 10000ms);
3880 env.
close(env.
now() + 5s, 10000ms);
3885 env.
close(env.
now() + 5s, 10000ms);
3892 env.
close(env.
now() + 5s, 10000ms);
3903 {{
"minimum_txn_in_ledger_standalone",
"3"},
3904 {
"normal_consensus_increase_percent",
"150"},
3905 {
"slow_consensus_decrease_percent",
"150"},
3906 {
"target_txn_in_ledger",
"10"},
3907 {
"maximum_txn_per_account",
"200"}}));
3908 auto alice =
Account(
"alice");
3911 env.
fund(
XRP(50000000), alice);
3915 auto seqAlice = env.
seq(alice);
3917 for (
int i = 0; i < txCount; ++i)
3936 env.
close(env.
now() + 5s, 10000ms);
3957 testcase(
"Sequence in queue and open ledger");
3958 using namespace jtx;
3960 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3962 auto const alice =
Account(
"alice");
3978 auto const aliceSeq = env.
seq(alice);
4024 testcase(
"Ticket in queue and open ledger");
4025 using namespace jtx;
4027 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4029 auto alice =
Account(
"alice");
4043 env(ticket::create(alice, 4));
4060 auto const tx = env.
jt(
4120 testcase(
"Re-execute preflight");
4121 using namespace jtx;
4131 {{
"minimum_txn_in_ledger_standalone",
"1"},
4132 {
"ledgers_in_queue",
"5"},
4133 {
"maximum_txn_per_account",
"10"}},
4134 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}});
4136 Env env(*
this, std::move(cfg));
4138 env.fund(
XRP(10000), alice);
4140 env.fund(
XRP(10000), bob);
4142 env.fund(
XRP(10000), carol);
4144 env.fund(
XRP(10000), daria);
4146 env.fund(
XRP(10000), ellie);
4148 env.fund(
XRP(10000), fiona);
4154 for (i = 0; i <= 257; ++i)
4160 auto expectedPerLedger =
4162 checkMetrics(env, 0, 5 * expectedPerLedger, 0, expectedPerLedger, 256);
4167 using namespace std::chrono_literals;
4168 auto closeDuration = 80min;
4169 for (i = 0; i <= 255; ++i)
4170 env.close(closeDuration);
4177 5 * expectedPerLedger,
4178 expectedPerLedger + 1,
4183 auto seqAlice = env.seq(alice);
4184 auto seqBob = env.seq(bob);
4185 auto seqCarol = env.seq(carol);
4186 auto seqDaria = env.seq(daria);
4187 auto seqEllie = env.seq(ellie);
4188 auto seqFiona = env.seq(fiona);
4189 for (
int i = 0; i < 10; ++i)
4202 5 * expectedPerLedger,
4203 expectedPerLedger + 1,
4216 env.close(closeDuration);
4217 expectedInQueue -= expectedPerLedger + 2;
4218 ++expectedPerLedger;
4222 5 * expectedPerLedger,
4223 expectedPerLedger + 1,
4227 auto const expectedPerAccount = expectedInQueue / 6;
4228 auto const expectedRemainder = expectedInQueue % 6;
4229 BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4232 seqBob - expectedPerAccount - (expectedRemainder > 4 ? 1 : 0));
4235 seqCarol - expectedPerAccount -
4236 (expectedRemainder > 3 ? 1 : 0));
4239 seqDaria - expectedPerAccount -
4240 (expectedRemainder > 2 ? 1 : 0));
4243 seqEllie - expectedPerAccount -
4244 (expectedRemainder > 1 ? 1 : 0));
4247 seqFiona - expectedPerAccount -
4248 (expectedRemainder > 0 ? 1 : 0));
4251 env.close(closeDuration);
4252 auto expectedInLedger = expectedInQueue;
4254 (expectedInQueue > expectedPerLedger + 2
4255 ? expectedInQueue - (expectedPerLedger + 2)
4257 ++expectedPerLedger;
4261 5 * expectedPerLedger,
4266 auto const expectedPerAccount = expectedInQueue / 6;
4267 auto const expectedRemainder = expectedInQueue % 6;
4268 BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4271 seqBob - expectedPerAccount - (expectedRemainder > 4 ? 1 : 0));
4274 seqCarol - expectedPerAccount -
4275 (expectedRemainder > 3 ? 1 : 0));
4278 seqDaria - expectedPerAccount -
4279 (expectedRemainder > 2 ? 1 : 0));
4282 seqEllie - expectedPerAccount -
4283 (expectedRemainder > 1 ? 1 : 0));
4286 seqFiona - expectedPerAccount -
4287 (expectedRemainder > 0 ? 1 : 0));
4301 testcase(
"Queue full drop penalty");
4302 using namespace jtx;
4318 auto const medFee =
drops(15);
4319 auto const hiFee =
drops(1000);
4322 {{
"minimum_txn_in_ledger_standalone",
"5"},
4323 {
"ledgers_in_queue",
"5"},
4324 {
"maximum_txn_per_account",
"30"},
4325 {
"minimum_queue_size",
"50"}});
4327 Env env(*
this, std::move(cfg));
4331 env.fund(
XRP(10000),
noripple(alice, bob, carol, daria, ellie, fiona));
4336 env(ticket::create(bob, 10));
4347 auto seqAlice = env.seq(alice);
4348 auto const seqSaveAlice = seqAlice;
4351 json(R
"({"LastLedgerSequence": 7})"),
4361 json(R
"({"LastLedgerSequence": 7})"),
4368 auto seqCarol = env.seq(carol);
4369 auto seqDaria = env.seq(daria);
4370 auto seqEllie = env.seq(ellie);
4371 auto seqFiona = env.seq(fiona);
4372 for (
int i = 0; i < 7; ++i)
4385 for (
int i = 0; i < 3; ++i)
4397 for (
int i = 0; i < 3; ++i)
4417 for (
int i = 0; i < 4; ++i)
4436 for (
int i = 0; i < 10; ++i)
4437 env.app().getFeeTrack().raiseLocalFee();
4447 while (env.app().getFeeTrack().lowerLocalFee())
4473 seqAlice = seqSaveAlice;
4519 testcase(
"Cancel queued offers");
4520 using namespace jtx;
4524 auto USD = gw[
"USD"];
4527 {{
"minimum_txn_in_ledger_standalone",
"5"},
4528 {
"ledgers_in_queue",
"5"},
4529 {
"maximum_txn_per_account",
"30"},
4530 {
"minimum_queue_size",
"50"}});
4532 Env env(*
this, std::move(cfg));
4544 auto const aliceSeq = env.seq(alice);
4547 env(offer(alice, USD(1000),
XRP(1001)),
4553 env(offer(alice, USD(1000),
XRP(1002)),
4555 json(jss::OfferSequence, aliceSeq),
4571 auto const aliceTkt = env.seq(alice);
4572 env(ticket::create(alice, 6));
4579 auto const aliceSeq = env.seq(alice);
4580 env(offer(alice, USD(1000),
XRP(1000)),
4584 env(offer(alice, USD(1000),
XRP(1001)),
4594 env(offer(alice, USD(1000),
XRP(1002)),
4596 json(jss::OfferSequence, aliceTkt + 4),
4606 env(offer(alice, USD(1000),
XRP(1001)),
4611 env(offer(alice, USD(1000),
XRP(1002)),
4613 json(jss::OfferSequence, aliceSeq),