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/Feature.h>
28 #include <ripple/protocol/jss.h>
29 #include <ripple/protocol/st.h>
30 #include <boost/optional.hpp>
32 #include <test/jtx/TestSuite.h>
33 #include <test/jtx/WSClient.h>
34 #include <test/jtx/envconfig.h>
35 #include <test/jtx/ticket.h>
47 boost::optional<std::size_t> expectedMaxCount,
53 FeeLevel64 const expectedMin{expectedMinFeeLevel};
54 FeeLevel64 const expectedMed{expectedMedFeeLevel};
61 BEAST_EXPECT(metrics.minProcessingFeeLevel == expectedMin);
63 auto expectedCurFeeLevel = expectedInLedger > expectedPerLedger
64 ? expectedMed * expectedInLedger * expectedInLedger /
65 (expectedPerLedger * expectedPerLedger)
66 : metrics.referenceFeeLevel;
67 BEAST_EXPECT(metrics.openLedgerFeeLevel == expectedCurFeeLevel);
74 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
83 auto const& view = *env.
current();
87 return fee(
toDrops(metrics.openLedgerFeeLevel, view.fees().base) + 1);
96 auto& section = p->section(
"transaction_queue");
97 section.set(
"ledgers_in_queue",
"2");
98 section.set(
"minimum_queue_size",
"2");
99 section.set(
"min_ledgers_to_compute_size_limit",
"3");
100 section.set(
"max_ledger_counts_to_store",
"100");
101 section.set(
"retry_sequence_percent",
"25");
102 section.set(
"normal_consensus_increase_percent",
"0");
104 for (
auto const& [k, v] : extraTxQ)
109 if (!extraVoting.
empty())
111 auto& votingSection = p->section(
"voting");
112 for (
auto const& [k, v] : extraVoting)
114 votingSection.set(k, v);
118 p->section(
"validation_seed")
119 .legacy(
"shUwVw52ofnCUX5m7kPTKzJdr4HEH");
138 for (
auto i = env.
current()->seq(); i <= 257; ++i)
144 auto const flagPerLedger =
146 auto const flagMaxQueue = ledgersInQueue * flagPerLedger;
147 checkMetrics(env, 0, flagMaxQueue, 0, flagPerLedger, 256);
156 using namespace std::chrono_literals;
158 checkMetrics(env, 0, flagMaxQueue, 0, expectedPerLedger, 256);
159 auto const fees = env.
current()->fees();
174 testcase(
"queue sequence");
176 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
180 auto charlie =
Account(
"charlie");
362 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
375 metrics.txPerLedger + 1,
384 testcase(
"queue ticket");
388 makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}),
411 env(ticket::create(alice, 250),
seq(tkt1 - 1),
queued);
644 testcase(
"queue tec");
646 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
650 auto USD = gw[
"USD"];
681 testcase(
"local tx retry");
683 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
687 auto charlie =
Account(
"charlie");
738 testcase(
"last ledger sequence");
740 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
744 auto charlie =
Account(
"charlie");
747 auto felicia =
Account(
"felicia");
770 json(R
"({"LastLedgerSequence":7})"),
787 aliceStat.begin()->lastValid &&
788 *aliceStat.begin()->lastValid == 8);
789 BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker());
791 auto bobStat = txQ.getAccountTxs(bob.id(), *env.
current());
794 bobStat.begin()->feeLevel ==
FeeLevel64{7000 * 256 / 10});
796 BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker());
849 testcase(
"zero transaction fee");
851 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
888 auto seqAlice = env.
seq(alice);
889 for (
int i = 0; i < 4; ++i)
892 feeAlice = (feeAlice + 1) * 125 / 100;
898 auto const seqBob = env.
seq(bob);
903 auto feeCarol = feeAlice;
904 auto seqCarol = env.
seq(carol);
905 for (
int i = 0; i < 4; ++i)
908 feeCarol = (feeCarol + 1) * 125 / 100;
947 testcase(
"fail in preclaim");
969 testcase(
"queued tx fails");
971 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
994 auto const& jt = env.
jt(
noop(alice));
1019 using namespace jtx;
1020 testcase(
"multi tx per account");
1025 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1026 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1028 auto alice =
Account(
"alice");
1030 auto charlie =
Account(
"charlie");
1031 auto daria =
Account(
"daria");
1040 auto const initQueueMax =
initFee(env, 3, 2, 10, 10, 200, 50);
1051 auto aliceSeq = env.
seq(alice);
1052 auto bobSeq = env.
seq(bob);
1053 auto charlieSeq = env.
seq(charlie);
1098 aliceSeq = env.
seq(alice);
1099 auto lastLedgerSeq = env.
current()->info().seq + 2;
1100 for (
auto i = 0; i < 7; i++)
1104 json(jss::LastLedgerSequence, lastLedgerSeq + i),
1114 auto const& baseFee = env.
current()->fees().base;
1115 auto seq = env.
seq(alice);
1117 for (
auto const& tx : aliceStat)
1123 (tx.consequences.fee() ==
drops(
fee) &&
1124 tx.consequences.potentialSpend() ==
drops(0) &&
1125 !tx.consequences.isBlocker()) ||
1126 tx.seqProxy.value() == env.
seq(alice) + 6);
1136 json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1169 aliceSeq = env.
seq(alice) + 2;
1188 aliceSeq = env.
seq(alice) + 1;
1195 env.
le(alice)->getFieldAmount(
sfBalance).xrp().drops() - (59);
1238 bobSeq = env.
seq(bob);
1240 for (
int i = 0; i < 10; ++i)
1255 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10 - 1);
1269 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10);
1288 using namespace jtx;
1289 using namespace std::chrono;
1290 testcase("tie breaking");
1292 Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "4"}}));
1294 auto alice = Account("alice");
1295 auto bob = Account("bob");
1296 auto charlie = Account("charlie");
1297 auto daria = Account("daria");
1298 auto elmo = Account("elmo");
1299 auto fred = Account("fred");
1300 auto gwen = Account("gwen");
1301 auto hank = Account("hank");
1303 auto queued = ter(terQUEUED);
1305 BEAST_EXPECT(env.current()->fees().base == 10);
1307 checkMetrics(env, 0, boost::none, 0, 4, 256);
1309 // Create several accounts while the fee is cheap so they all apply.
1310 env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
1311 checkMetrics(env, 0, boost::none, 4, 4, 256);
1314 checkMetrics(env, 0, 8, 0, 4, 256);
1316 env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
1317 checkMetrics(env, 0, 8, 4, 4, 256);
1320 checkMetrics(env, 0, 8, 0, 4, 256);
1324 // Stuff the ledger and queue so we can verify that
1325 // stuff gets kicked out.
1331 checkMetrics(env, 0, 8, 5, 4, 256);
1333 auto aliceSeq = env.seq(alice);
1334 auto bobSeq = env.seq(bob);
1335 auto charlieSeq = env.seq(charlie);
1336 auto dariaSeq = env.seq(daria);
1337 auto elmoSeq = env.seq(elmo);
1338 auto fredSeq = env.seq(fred);
1339 auto gwenSeq = env.seq(gwen);
1340 auto hankSeq = env.seq(hank);
1342 // This time, use identical fees.
1343 env(noop(alice), fee(15), queued);
1344 env(noop(bob), fee(15), queued);
1345 env(noop(charlie), fee(15), queued);
1346 env(noop(daria), fee(15), queued);
1347 env(noop(elmo), fee(15), queued);
1348 env(noop(fred), fee(15), queued);
1349 env(noop(gwen), fee(15), queued);
1350 // This one gets into the queue, but gets dropped when the
1351 // higher fee one is added later.
1352 env(noop(hank), fee(15), queued);
1354 // Queue is full now. Minimum fee now reflects the
1355 // lowest fee in the queue.
1356 checkMetrics(env, 8, 8, 5, 4, 385);
1358 // Try to add another transaction with the default (low) fee,
1359 // it should fail because it can't replace the one already
1388 aliceSeq = env.
seq(alice);
1389 bobSeq = env.
seq(bob);
1390 charlieSeq = env.
seq(charlie);
1391 dariaSeq = env.
seq(daria);
1392 elmoSeq = env.
seq(elmo);
1427 using namespace jtx;
1428 testcase(
"acct tx id");
1430 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"1"}}));
1432 auto alice =
Account(
"alice");
1448 json(R
"({"AccountTxnID": "0"})"),
1466 using namespace jtx;
1467 using namespace std::string_literals;
1468 testcase(
"maximum tx");
1474 {{
"minimum_txn_in_ledger_standalone",
"2"},
1475 {
"target_txn_in_ledger",
"4"},
1476 {
"maximum_txn_in_ledger",
"5"}}));
1478 auto alice =
Account(
"alice");
1485 for (
int i = 0; i < 10; ++i)
1500 {{
"minimum_txn_in_ledger",
"200"},
1501 {
"minimum_txn_in_ledger_standalone",
"200"},
1502 {
"target_txn_in_ledger",
"4"},
1503 {
"maximum_txn_in_ledger",
"5"}}));
1511 "The minimum number of low-fee transactions allowed "
1512 "per ledger (minimum_txn_in_ledger) exceeds "
1513 "the maximum number of low-fee transactions allowed per "
1514 "ledger (maximum_txn_in_ledger)."s);
1521 {{
"minimum_txn_in_ledger",
"200"},
1522 {
"minimum_txn_in_ledger_standalone",
"2"},
1523 {
"target_txn_in_ledger",
"4"},
1524 {
"maximum_txn_in_ledger",
"5"}}));
1532 "The minimum number of low-fee transactions allowed "
1533 "per ledger (minimum_txn_in_ledger) exceeds "
1534 "the maximum number of low-fee transactions allowed per "
1535 "ledger (maximum_txn_in_ledger)."s);
1542 {{
"minimum_txn_in_ledger",
"2"},
1543 {
"minimum_txn_in_ledger_standalone",
"200"},
1544 {
"target_txn_in_ledger",
"4"},
1545 {
"maximum_txn_in_ledger",
"5"}}));
1553 "The minimum number of low-fee transactions allowed "
1554 "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1555 "the maximum number of low-fee transactions allowed per "
1556 "ledger (maximum_txn_in_ledger)."s);
1563 using namespace jtx;
1564 testcase(
"unexpected balance change");
1569 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1570 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1572 auto alice =
Account(
"alice");
1578 auto const initQueueMax =
initFee(env, 3, 2, 10, 10, 200, 50);
1587 auto USD = bob[
"USD"];
1601 auto aliceSeq = env.
seq(alice);
1610 env(offer(bob,
drops(5000), USD(5000)),
1645 for (
int i = 0; i < 9; ++i)
1660 using namespace jtx;
1661 testcase(
"blockers sequence");
1663 auto alice =
Account(
"alice");
1665 auto charlie =
Account(
"charlie");
1666 auto daria =
Account(
"daria");
1670 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1686 env(
regkey(alice, charlie));
1690 auto const aliceSeq = env.
seq(alice);
1706 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1725 auto const aliceSeq = env.
seq(alice);
1740 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1766 auto const aliceSeq = env.
seq(alice);
1790 using namespace jtx;
1791 testcase(
"blockers ticket");
1793 auto alice =
Account(
"alice");
1795 auto charlie =
Account(
"charlie");
1796 auto daria =
Account(
"daria");
1802 makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}),
1820 env(ticket::create(alice, 250),
seq(tkt - 1));
1822 env(
regkey(alice, charlie));
1826 auto const aliceSeq = env.
seq(alice);
1842 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1846 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1870 auto const aliceSeq = env.
seq(alice);
1895 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1955 using namespace jtx;
1956 testcase(
"In-flight balance checks");
1961 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1962 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1964 auto alice =
Account(
"alice");
1965 auto charlie =
Account(
"charlie");
1976 auto const initQueueMax =
initFee(env, 3, 2, 10, 10, 200, 50);
1983 checkMetrics(env, 0, initQueueMax, limit + 1, limit, 256);
1985 auto USD = gw[
"USD"];
1986 auto BUX = gw[
"BUX"];
1990 auto aliceSeq = env.
seq(alice);
1991 auto aliceBal = env.
balance(alice);
1997 env(offer(alice, BUX(5000),
XRP(50000)),
queued);
1998 checkMetrics(env, 1, initQueueMax, limit + 1, limit, 256);
2003 checkMetrics(env, 2, initQueueMax, limit + 1, limit, 256);
2019 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2020 aliceSeq = env.
seq(alice);
2021 aliceBal = env.
balance(alice);
2027 checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
2032 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2040 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2056 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2057 aliceSeq = env.
seq(alice);
2058 aliceBal = env.
balance(alice);
2065 checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
2073 checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
2089 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2090 aliceSeq = env.
seq(alice);
2091 aliceBal = env.
balance(alice);
2095 env(offer(alice, BUX(50),
XRP(500)),
queued);
2099 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2115 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2117 aliceSeq = env.
seq(alice);
2118 aliceBal = env.
balance(alice);
2128 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2142 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2144 aliceSeq = env.
seq(alice);
2145 aliceBal = env.
balance(alice);
2153 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2165 auto const amount = USD(500000);
2166 env(
trust(alice, USD(50000000)));
2167 env(
trust(charlie, USD(50000000)));
2173 env(
pay(gw, alice, amount));
2180 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2182 aliceSeq = env.
seq(alice);
2183 aliceBal = env.
balance(alice);
2184 auto aliceUSD = env.
balance(alice, USD);
2188 env(
pay(alice, charlie, amount),
queued);
2193 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2211 env(offer(gw,
XRP(500000), USD(50000)));
2217 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2219 aliceSeq = env.
seq(alice);
2220 aliceBal = env.
balance(alice);
2221 auto charlieUSD = env.
balance(charlie, USD);
2233 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2244 balance(charlie, charlieUSD + USD(1000)),
2252 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2254 aliceSeq = env.
seq(alice);
2255 aliceBal = env.
balance(alice);
2256 charlieUSD = env.
balance(charlie, USD);
2267 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2278 balance(charlie, charlieUSD + USD(500)),
2288 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2290 aliceSeq = env.
seq(alice);
2291 aliceBal = env.
balance(alice);
2298 checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
2309 using namespace jtx;
2311 testcase(
"consequences");
2314 auto const alice =
Account(
"alice");
2320 cancelOffer[jss::Account] = alice.human();
2321 cancelOffer[jss::OfferSequence] = 3;
2322 cancelOffer[jss::TransactionType] = jss::OfferCancel;
2323 auto const jtx = env.
jt(cancelOffer,
seq(5),
fee(10));
2337 auto USD = alice[
"USD"];
2354 auto const jtx = env.
jt(ticket::create(alice, 1),
seq(1),
fee(10));
2379 using namespace jtx;
2380 testcase(
"acct in queue but empty");
2382 auto alice =
Account(
"alice");
2384 auto charlie =
Account(
"charlie");
2388 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2476 using namespace jtx;
2481 auto fee = env.
rpc(
"fee");
2488 result.isMember(jss::ledger_current_index) &&
2489 result[jss::ledger_current_index] == 3);
2501 auto const& levels =
result[jss::levels];
2517 result.isMember(jss::ledger_current_index) &&
2518 result[jss::ledger_current_index] == 4);
2529 auto const& levels =
result[jss::levels];
2551 using namespace jtx;
2552 testcase(
"expiration replacement");
2557 {{
"minimum_txn_in_ledger_standalone",
"1"},
2558 {
"ledgers_in_queue",
"10"},
2559 {
"maximum_txn_per_account",
"20"}}));
2562 auto const alice =
Account(
"alice");
2563 auto const bob =
Account(
"bob");
2568 auto const aliceSeq = env.
seq(alice);
2572 json(R
"({"LastLedgerSequence":5})"),
2576 json(R"({"LastLedgerSequence":5})"),
2580 json(R"({"LastLedgerSequence":10})"),
2584 json(R"({"LastLedgerSequence":11})"),
2587 auto const bobSeq = env.
seq(bob);
2591 for (
int i = 0; i < 3 + 4 + 5; ++i)
2595 checkMetrics(env, 4 + 3 + 4 + 5, boost::none, 2, 1, 256);
2643 using namespace jtx;
2644 testcase(
"full queue gap handling");
2649 {{
"minimum_txn_in_ledger_standalone",
"1"},
2650 {
"ledgers_in_queue",
"10"},
2651 {
"maximum_txn_per_account",
"11"}}),
2657 auto const alice =
Account(
"alice");
2658 auto const bob =
Account(
"bob");
2663 auto const aliceSeq = env.
seq(alice);
2668 env(ticket::create(alice, 11),
2674 json(R
"({"LastLedgerSequence":11})"),
2678 json(R"({"LastLedgerSequence":11})"),
2682 json(R"({"LastLedgerSequence":11})"),
2686 json(R"({"LastLedgerSequence":11})"),
2690 json(R"({"LastLedgerSequence":11})"),
2694 json(R"({"LastLedgerSequence": 5})"),
2698 json(R"({"LastLedgerSequence": 5})"),
2702 json(R"({"LastLedgerSequence": 5})"),
2706 json(R"({"LastLedgerSequence":11})"),
2710 auto const bobSeq = env.
seq(bob);
2714 for (
int i = 0; i < 2 + 4 + 5; ++i)
2718 checkMetrics(env, 10 + 2 + 4 + 5, boost::none, 2, 1, 256);
2801 testcase(
"Autofilled sequence should account for TxQ");
2802 using namespace jtx;
2803 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"6"}}));
2807 auto const alice =
Account(
"alice");
2808 auto const bob =
Account(
"bob");
2809 env.
fund(
XRP(100000), alice, bob);
2815 auto const aliceSeq = env.
seq(alice);
2816 auto const lastLedgerSeq = env.
current()->info().seq + 2;
2819 for (
int i = 0; i < 5; ++i)
2826 json(jss::LastLedgerSequence, lastLedgerSeq),
2834 auto aliceStat = txQ.getAccountTxs(alice.id(), *env.
current());
2837 for (
auto const& tx : aliceStat)
2841 if (
seq.value() == aliceSeq + 2)
2844 tx.lastValid && *tx.lastValid == lastLedgerSeq);
2855 for (
int i = 0; i < 8; ++i)
2864 for (
int i = 0; i < 9; ++i)
2871 for (
int i = 0; i < 10; ++i)
2878 auto bobStat = txQ.getAccountTxs(bob.id(), *env.
current());
2884 auto aliceStat = txQ.getAccountTxs(alice.id(), *env.
current());
2885 auto seq = aliceSeq;
2887 for (
auto const& tx : aliceStat)
2890 if (
seq == aliceSeq + 2)
2903 auto aliceStat = txQ.getAccountTxs(alice.id(), *env.
current());
2904 auto seq = aliceSeq;
2906 for (
auto const& tx : aliceStat)
2919 auto bobStat = txQ.getAccountTxs(bob.id(), *env.
current());
2923 auto aliceStat = txQ.getAccountTxs(alice.id(), *env.
current());
2931 using namespace jtx;
2932 testcase(
"account info");
2934 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2938 env.
fund(
XRP(1000000), alice);
2941 auto const withQueue =
2942 R
"({ "account": ")" + alice.human() + R"(", "queue": true })";
2945 R"(", "queue": true, "ledger_index": 3 })";
2952 info.isMember(jss::result) &&
2953 info[jss::result].isMember(jss::account_data));
2954 BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data));
2958 auto const info = env.
rpc(
"json",
"account_info", withQueue);
2960 info.isMember(jss::result) &&
2961 info[jss::result].isMember(jss::account_data));
2980 auto const info = env.
rpc(
"json",
"account_info", withQueue);
2982 info.isMember(jss::result) &&
2983 info[jss::result].isMember(jss::account_data));
2984 auto const&
result = info[jss::result];
3005 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3007 info.isMember(jss::result) &&
3008 info[jss::result].isMember(jss::account_data));
3009 auto const&
result = info[jss::result];
3022 data[jss::Sequence].asUInt() +
3033 auto const& item =
queued[i];
3043 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3058 json(jss::LastLedgerSequence, 10),
3063 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3065 info.isMember(jss::result) &&
3066 info[jss::result].isMember(jss::account_data));
3067 auto const&
result = info[jss::result];
3068 auto const&
data =
result[jss::account_data];
3080 data[jss::Sequence].asUInt() +
3091 auto const& item =
queued[i];
3100 if (i ==
queued.size() - 1)
3108 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3119 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3121 info.isMember(jss::result) &&
3122 info[jss::result].isMember(jss::account_data));
3123 auto const&
result = info[jss::result];
3124 auto const&
data =
result[jss::account_data];
3136 data[jss::Sequence].asUInt() +
3147 auto const& item =
queued[i];
3151 if (i ==
queued.size() - 1)
3179 info.isMember(jss::result) &&
3189 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3191 info.isMember(jss::result) &&
3192 info[jss::result].isMember(jss::account_data));
3193 auto const&
result = info[jss::result];
3210 using namespace jtx;
3211 testcase(
"server info");
3213 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3217 env.
fund(
XRP(1000000), alice);
3221 auto const server_info = env.
rpc(
"server_info");
3223 server_info.isMember(jss::result) &&
3224 server_info[jss::result].isMember(jss::info));
3225 auto const& info = server_info[jss::result][jss::info];
3227 info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
3231 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3234 auto const server_state = env.
rpc(
"server_state");
3235 auto const& state = server_state[jss::result][jss::state];
3237 state.isMember(jss::load_factor) &&
3238 state[jss::load_factor] == 256);
3240 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3242 state.isMember(jss::load_factor_server) &&
3243 state[jss::load_factor_server] == 256);
3245 state.isMember(jss::load_factor_fee_escalation) &&
3246 state[jss::load_factor_fee_escalation] == 256);
3248 state.isMember(jss::load_factor_fee_queue) &&
3249 state[jss::load_factor_fee_queue] == 256);
3251 state.isMember(jss::load_factor_fee_reference) &&
3252 state[jss::load_factor_fee_reference] == 256);
3260 auto aliceSeq = env.
seq(alice);
3262 for (
auto i = 0; i < 4; ++i)
3268 auto const server_info = env.
rpc(
"server_info");
3270 server_info.isMember(jss::result) &&
3271 server_info[jss::result].isMember(jss::info));
3272 auto const& info = server_info[jss::result][jss::info];
3275 info.isMember(jss::load_factor) &&
3276 info[jss::load_factor] > 888.88 &&
3277 info[jss::load_factor] < 888.89);
3279 info.isMember(jss::load_factor_server) &&
3280 info[jss::load_factor_server] == 1);
3284 info.isMember(jss::load_factor_fee_escalation) &&
3285 info[jss::load_factor_fee_escalation] > 888.88 &&
3286 info[jss::load_factor_fee_escalation] < 888.89);
3289 auto const server_state = env.
rpc(
"server_state");
3290 auto const& state = server_state[jss::result][jss::state];
3292 state.isMember(jss::load_factor) &&
3293 state[jss::load_factor] == 227555);
3295 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3297 state.isMember(jss::load_factor_server) &&
3298 state[jss::load_factor_server] == 256);
3300 state.isMember(jss::load_factor_fee_escalation) &&
3301 state[jss::load_factor_fee_escalation] == 227555);
3303 state.isMember(jss::load_factor_fee_queue) &&
3304 state[jss::load_factor_fee_queue] == 256);
3306 state.isMember(jss::load_factor_fee_reference) &&
3307 state[jss::load_factor_fee_reference] == 256);
3313 auto const server_info = env.
rpc(
"server_info");
3315 server_info.isMember(jss::result) &&
3316 server_info[jss::result].isMember(jss::info));
3317 auto const& info = server_info[jss::result][jss::info];
3320 info.isMember(jss::load_factor) &&
3321 info[jss::load_factor] == 1000);
3325 info.isMember(jss::load_factor_net) &&
3326 info[jss::load_factor_net] == 1000);
3328 info.isMember(jss::load_factor_fee_escalation) &&
3329 info[jss::load_factor_fee_escalation] > 888.88 &&
3330 info[jss::load_factor_fee_escalation] < 888.89);
3333 auto const server_state = env.
rpc(
"server_state");
3334 auto const& state = server_state[jss::result][jss::state];
3336 state.isMember(jss::load_factor) &&
3337 state[jss::load_factor] == 256000);
3339 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3341 state.isMember(jss::load_factor_server) &&
3342 state[jss::load_factor_server] == 256000);
3344 state.isMember(jss::load_factor_fee_escalation) &&
3345 state[jss::load_factor_fee_escalation] == 227555);
3347 state.isMember(jss::load_factor_fee_queue) &&
3348 state[jss::load_factor_fee_queue] == 256);
3350 state.isMember(jss::load_factor_fee_reference) &&
3351 state[jss::load_factor_fee_reference] == 256);
3357 for (
int i = 0; i < 5; ++i)
3362 auto const server_info = env.
rpc(
"server_info");
3364 server_info.isMember(jss::result) &&
3365 server_info[jss::result].isMember(jss::info));
3366 auto const& info = server_info[jss::result][jss::info];
3369 info.isMember(jss::load_factor) &&
3370 info[jss::load_factor] > 888.88 &&
3371 info[jss::load_factor] < 888.89);
3376 info.isMember(jss::load_factor_server) &&
3377 info[jss::load_factor_server] > 1.245 &&
3378 info[jss::load_factor_server] < 2.4415);
3380 info.isMember(jss::load_factor_local) &&
3381 info[jss::load_factor_local] > 1.245 &&
3382 info[jss::load_factor_local] < 2.4415);
3385 info.isMember(jss::load_factor_fee_escalation) &&
3386 info[jss::load_factor_fee_escalation] > 888.88 &&
3387 info[jss::load_factor_fee_escalation] < 888.89);
3390 auto const server_state = env.
rpc(
"server_state");
3391 auto const& state = server_state[jss::result][jss::state];
3393 state.isMember(jss::load_factor) &&
3394 state[jss::load_factor] == 227555);
3396 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3401 state.isMember(jss::load_factor_server) &&
3402 state[jss::load_factor_server] >= 320 &&
3403 state[jss::load_factor_server] <= 625);
3405 state.isMember(jss::load_factor_fee_escalation) &&
3406 state[jss::load_factor_fee_escalation] == 227555);
3408 state.isMember(jss::load_factor_fee_queue) &&
3409 state[jss::load_factor_fee_queue] == 256);
3411 state.isMember(jss::load_factor_fee_reference) &&
3412 state[jss::load_factor_fee_reference] == 256);
3418 auto const server_info = env.
rpc(
"server_info");
3420 server_info.isMember(jss::result) &&
3421 server_info[jss::result].isMember(jss::info));
3422 auto const& info = server_info[jss::result][jss::info];
3429 info.isMember(jss::load_factor) &&
3430 info[jss::load_factor] > 1.245 &&
3431 info[jss::load_factor] < 2.4415);
3434 info.isMember(jss::load_factor_local) &&
3435 info[jss::load_factor_local] > 1.245 &&
3436 info[jss::load_factor_local] < 2.4415);
3438 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3441 auto const server_state = env.
rpc(
"server_state");
3442 auto const& state = server_state[jss::result][jss::state];
3444 state.isMember(jss::load_factor) &&
3445 state[jss::load_factor] >= 320 &&
3446 state[jss::load_factor] <= 625);
3448 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3453 state.isMember(jss::load_factor_server) &&
3454 state[jss::load_factor_server] >= 320 &&
3455 state[jss::load_factor_server] <= 625);
3457 state.isMember(jss::load_factor_fee_escalation) &&
3458 state[jss::load_factor_fee_escalation] == 256);
3460 state.isMember(jss::load_factor_fee_queue) &&
3461 state[jss::load_factor_fee_queue] == 256);
3463 state.isMember(jss::load_factor_fee_reference) &&
3464 state[jss::load_factor_fee_reference] == 256);
3471 using namespace jtx;
3472 testcase(
"server subscribe");
3474 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3478 stream[jss::streams].append(
"server");
3481 auto jv = wsc->invoke(
"subscribe", stream);
3485 Account a{
"a"}, b{
"b"}, c{
"c"}, d{
"d"}, e{
"e"}, f{
"f"}, g{
"g"}, h{
"h"},
3493 using namespace std::chrono_literals;
3495 return jv[jss::type] ==
"serverStatus" &&
3496 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3497 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3498 jv.isMember(jss::load_factor_server) &&
3499 jv[jss::load_factor_server] == 256 &&
3500 jv.isMember(jss::load_factor_fee_escalation) &&
3501 jv[jss::load_factor_fee_escalation] == 256 &&
3502 jv.isMember(jss::load_factor_fee_queue) &&
3503 jv[jss::load_factor_fee_queue] == 256 &&
3504 jv.isMember(jss::load_factor_fee_reference) &&
3505 jv[jss::load_factor_fee_reference] == 256;
3509 return jv[jss::type] ==
"serverStatus" &&
3510 jv.isMember(jss::load_factor) &&
3511 jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3512 jv[jss::load_base] == 256 &&
3513 jv.isMember(jss::load_factor_server) &&
3514 jv[jss::load_factor_server] == 256 &&
3515 jv.isMember(jss::load_factor_fee_escalation) &&
3516 jv[jss::load_factor_fee_escalation] == 227555 &&
3517 jv.isMember(jss::load_factor_fee_queue) &&
3518 jv[jss::load_factor_fee_queue] == 256 &&
3519 jv.isMember(jss::load_factor_fee_reference) &&
3520 jv[jss::load_factor_fee_reference] == 256;
3527 return jv[jss::type] ==
"serverStatus" &&
3528 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3529 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3530 jv.isMember(jss::load_factor_server) &&
3531 jv[jss::load_factor_server] == 256 &&
3532 jv.isMember(jss::load_factor_fee_escalation) &&
3533 jv[jss::load_factor_fee_escalation] == 256 &&
3534 jv.isMember(jss::load_factor_fee_queue) &&
3535 jv[jss::load_factor_fee_queue] == 256 &&
3536 jv.isMember(jss::load_factor_fee_reference) &&
3537 jv[jss::load_factor_fee_reference] == 256;
3558 return jv[jss::type] ==
"serverStatus" &&
3559 jv.isMember(jss::load_factor) &&
3560 jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3561 jv[jss::load_base] == 256 &&
3562 jv.isMember(jss::load_factor_server) &&
3563 jv[jss::load_factor_server] == 256 &&
3564 jv.isMember(jss::load_factor_fee_escalation) &&
3565 jv[jss::load_factor_fee_escalation] == 200000 &&
3566 jv.isMember(jss::load_factor_fee_queue) &&
3567 jv[jss::load_factor_fee_queue] == 256 &&
3568 jv.isMember(jss::load_factor_fee_reference) &&
3569 jv[jss::load_factor_fee_reference] == 256;
3575 return jv[jss::type] ==
"serverStatus" &&
3576 jv.isMember(jss::load_factor) &&
3577 jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3578 jv[jss::load_base] == 256 &&
3579 jv.isMember(jss::load_factor_server) &&
3580 jv[jss::load_factor_server] == 256 &&
3581 jv.isMember(jss::load_factor_fee_escalation) &&
3582 jv[jss::load_factor_fee_escalation] == 184320 &&
3583 jv.isMember(jss::load_factor_fee_queue) &&
3584 jv[jss::load_factor_fee_queue] == 256 &&
3585 jv.isMember(jss::load_factor_fee_reference) &&
3586 jv[jss::load_factor_fee_reference] == 256;
3592 return jv[jss::type] ==
"serverStatus" &&
3593 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3594 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3595 jv.isMember(jss::load_factor_server) &&
3596 jv[jss::load_factor_server] == 256 &&
3597 jv.isMember(jss::load_factor_fee_escalation) &&
3598 jv[jss::load_factor_fee_escalation] == 256 &&
3599 jv.isMember(jss::load_factor_fee_queue) &&
3600 jv[jss::load_factor_fee_queue] == 256 &&
3601 jv.isMember(jss::load_factor_fee_reference) &&
3602 jv[jss::load_factor_fee_reference] == 256;
3606 return jv[jss::type] ==
"serverStatus";
3609 auto jv = wsc->invoke(
"unsubscribe", stream);
3616 using namespace jtx;
3617 testcase(
"clear queued acct txs");
3619 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3620 auto alice =
Account(
"alice");
3624 env.
fund(
XRP(50000000), alice, bob);
3629 boost::optional<std::size_t> numToClear =
3631 auto totalFactor = 0;
3634 numToClear.emplace(metrics.txCount + 1);
3635 for (
int i = 0; i < *numToClear; ++i)
3638 totalFactor += inLedger * inLedger;
3641 metrics.medFeeLevel * totalFactor /
3642 (metrics.txPerLedger * metrics.txPerLedger),
3652 testcase(
"straightfoward positive case");
3655 auto aliceSeq = env.
seq(alice);
3656 for (
int i = 0; i < 2; ++i)
3687 calcTotalFee(100 * 2 + 8889 + 60911);
3690 env(
noop(alice),
fee(totalFee2),
seq(aliceSeq++));
3695 testcase(
"replace last tx with enough to clear queue");
3698 auto aliceSeq = env.
seq(alice);
3699 for (
int i = 0; i < 2; ++i)
3718 calcTotalFee(100 * 2, metrics.txCount);
3722 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3731 testcase(
"replace middle tx with enough to clear queue");
3735 auto aliceSeq = env.
seq(alice);
3736 for (
int i = 0; i < 5; ++i)
3748 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3751 auto const aliceQueue =
3755 for (
auto const& tx : aliceQueue)
3767 testcase(
"clear queue failure (load)");
3771 auto aliceSeq = env.
seq(alice);
3772 for (
int i = 0; i < 2; ++i)
3776 for (
int i = 0; i < 2; ++i)
3785 std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
3790 feeTrack.setRemoteFee(origFee * 5);
3803 feeTrack.setRemoteFee(origFee);
3822 using namespace jtx;
3823 using namespace std::chrono_literals;
3824 testcase(
"scaling");
3830 {{
"minimum_txn_in_ledger_standalone",
"3"},
3831 {
"normal_consensus_increase_percent",
"25"},
3832 {
"slow_consensus_decrease_percent",
"50"},
3833 {
"target_txn_in_ledger",
"10"},
3834 {
"maximum_txn_per_account",
"200"}}));
3835 auto alice =
Account(
"alice");
3838 env.
fund(
XRP(50000000), alice);
3842 auto seqAlice = env.
seq(alice);
3844 for (
int i = 0; i < txCount; ++i)
3888 env.
close(env.
now() + 5s, 10000ms);
3893 env.
close(env.
now() + 5s, 10000ms);
3898 env.
close(env.
now() + 5s, 10000ms);
3905 env.
close(env.
now() + 5s, 10000ms);
3916 {{
"minimum_txn_in_ledger_standalone",
"3"},
3917 {
"normal_consensus_increase_percent",
"150"},
3918 {
"slow_consensus_decrease_percent",
"150"},
3919 {
"target_txn_in_ledger",
"10"},
3920 {
"maximum_txn_per_account",
"200"}}));
3921 auto alice =
Account(
"alice");
3924 env.
fund(
XRP(50000000), alice);
3928 auto seqAlice = env.
seq(alice);
3930 for (
int i = 0; i < txCount; ++i)
3949 env.
close(env.
now() + 5s, 10000ms);
3970 testcase(
"Sequence in queue and open ledger");
3971 using namespace jtx;
3973 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3975 auto const alice =
Account(
"alice");
3991 auto const aliceSeq = env.
seq(alice);
4037 testcase(
"Ticket in queue and open ledger");
4038 using namespace jtx;
4042 makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}),
4045 auto alice =
Account(
"alice");
4059 env(ticket::create(alice, 4));
4076 auto const tx = env.
jt(
4136 testcase(
"Re-execute preflight");
4137 using namespace jtx;
4147 {{
"minimum_txn_in_ledger_standalone",
"1"},
4148 {
"ledgers_in_queue",
"5"},
4149 {
"maximum_txn_per_account",
"10"}},
4150 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}});
4152 Env env(*
this, std::move(cfg));
4154 env.fund(
XRP(10000), alice);
4156 env.fund(
XRP(10000), bob);
4158 env.fund(
XRP(10000), carol);
4160 env.fund(
XRP(10000), daria);
4162 env.fund(
XRP(10000), ellie);
4164 env.fund(
XRP(10000), fiona);
4170 for (i = 0; i <= 257; ++i)
4176 auto expectedPerLedger =
4178 checkMetrics(env, 0, 5 * expectedPerLedger, 0, expectedPerLedger, 256);
4183 using namespace std::chrono_literals;
4184 auto closeDuration = 80min;
4185 for (i = 0; i <= 255; ++i)
4186 env.close(closeDuration);
4193 5 * expectedPerLedger,
4194 expectedPerLedger + 1,
4199 auto seqAlice = env.seq(alice);
4200 auto seqBob = env.seq(bob);
4201 auto seqCarol = env.seq(carol);
4202 auto seqDaria = env.seq(daria);
4203 auto seqEllie = env.seq(ellie);
4204 auto seqFiona = env.seq(fiona);
4205 for (
int i = 0; i < 10; ++i)
4218 5 * expectedPerLedger,
4219 expectedPerLedger + 1,
4232 env.close(closeDuration);
4233 expectedInQueue -= expectedPerLedger + 2;
4234 ++expectedPerLedger;
4238 5 * expectedPerLedger,
4239 expectedPerLedger + 1,
4243 auto const expectedPerAccount = expectedInQueue / 6;
4244 auto const expectedRemainder = expectedInQueue % 6;
4245 BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4248 seqBob - expectedPerAccount - (expectedRemainder > 4 ? 1 : 0));
4251 seqCarol - expectedPerAccount -
4252 (expectedRemainder > 3 ? 1 : 0));
4255 seqDaria - expectedPerAccount -
4256 (expectedRemainder > 2 ? 1 : 0));
4259 seqEllie - expectedPerAccount -
4260 (expectedRemainder > 1 ? 1 : 0));
4263 seqFiona - expectedPerAccount -
4264 (expectedRemainder > 0 ? 1 : 0));
4267 env.close(closeDuration);
4268 auto expectedInLedger = expectedInQueue;
4270 (expectedInQueue > expectedPerLedger + 2
4271 ? expectedInQueue - (expectedPerLedger + 2)
4273 ++expectedPerLedger;
4277 5 * expectedPerLedger,
4282 auto const expectedPerAccount = expectedInQueue / 6;
4283 auto const expectedRemainder = expectedInQueue % 6;
4284 BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4287 seqBob - expectedPerAccount - (expectedRemainder > 4 ? 1 : 0));
4290 seqCarol - expectedPerAccount -
4291 (expectedRemainder > 3 ? 1 : 0));
4294 seqDaria - expectedPerAccount -
4295 (expectedRemainder > 2 ? 1 : 0));
4298 seqEllie - expectedPerAccount -
4299 (expectedRemainder > 1 ? 1 : 0));
4302 seqFiona - expectedPerAccount -
4303 (expectedRemainder > 0 ? 1 : 0));
4317 testcase(
"Queue full drop penalty");
4318 using namespace jtx;
4334 auto const medFee =
drops(15);
4335 auto const hiFee =
drops(1000);
4338 {{
"minimum_txn_in_ledger_standalone",
"5"},
4339 {
"ledgers_in_queue",
"5"},
4340 {
"maximum_txn_per_account",
"30"},
4341 {
"minimum_queue_size",
"50"}});
4348 env.fund(
XRP(10000),
noripple(alice, bob, carol, daria, ellie, fiona));
4353 env(ticket::create(bob, 10));
4364 auto seqAlice = env.seq(alice);
4365 auto const seqSaveAlice = seqAlice;
4368 json(R
"({"LastLedgerSequence": 7})"),
4378 json(R
"({"LastLedgerSequence": 7})"),
4385 auto seqCarol = env.seq(carol);
4386 auto seqDaria = env.seq(daria);
4387 auto seqEllie = env.seq(ellie);
4388 auto seqFiona = env.seq(fiona);
4389 for (
int i = 0; i < 7; ++i)
4402 for (
int i = 0; i < 3; ++i)
4414 for (
int i = 0; i < 3; ++i)
4434 for (
int i = 0; i < 4; ++i)
4453 for (
int i = 0; i < 10; ++i)
4454 env.app().getFeeTrack().raiseLocalFee();
4464 while (env.app().getFeeTrack().lowerLocalFee())
4490 seqAlice = seqSaveAlice;
4536 testcase(
"Cancel queued offers");
4537 using namespace jtx;
4541 auto USD = gw[
"USD"];
4544 {{
"minimum_txn_in_ledger_standalone",
"5"},
4545 {
"ledgers_in_queue",
"5"},
4546 {
"maximum_txn_per_account",
"30"},
4547 {
"minimum_queue_size",
"50"}});
4562 auto const aliceSeq = env.seq(alice);
4565 env(offer(alice, USD(1000),
XRP(1001)),
4571 env(offer(alice, USD(1000),
XRP(1002)),
4573 json(jss::OfferSequence, aliceSeq),
4589 auto const aliceTkt = env.seq(alice);
4590 env(ticket::create(alice, 6));
4597 auto const aliceSeq = env.seq(alice);
4598 env(offer(alice, USD(1000),
XRP(1000)),
4602 env(offer(alice, USD(1000),
XRP(1001)),
4612 env(offer(alice, USD(1000),
XRP(1002)),
4614 json(jss::OfferSequence, aliceTkt + 4),
4624 env(offer(alice, USD(1000),
XRP(1001)),
4629 env(offer(alice, USD(1000),
XRP(1002)),
4631 json(jss::OfferSequence, aliceSeq),