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>
29 #include <boost/optional.hpp>
31 #include <test/jtx/TestSuite.h>
32 #include <test/jtx/WSClient.h>
33 #include <test/jtx/envconfig.h>
34 #include <test/jtx/ticket.h>
46 boost::optional<std::size_t> expectedMaxCount,
52 FeeLevel64 const expectedMin{expectedMinFeeLevel};
53 FeeLevel64 const expectedMed{expectedMedFeeLevel};
60 BEAST_EXPECT(metrics.minProcessingFeeLevel == expectedMin);
62 auto expectedCurFeeLevel = expectedInLedger > expectedPerLedger
63 ? expectedMed * expectedInLedger * expectedInLedger /
64 (expectedPerLedger * expectedPerLedger)
65 : metrics.referenceFeeLevel;
66 BEAST_EXPECT(metrics.openLedgerFeeLevel == expectedCurFeeLevel);
73 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
82 auto const& view = *env.
current();
86 return fee(
toDrops(metrics.openLedgerFeeLevel, view.fees().base) + 1);
95 auto& section = p->section(
"transaction_queue");
96 section.set(
"ledgers_in_queue",
"2");
97 section.set(
"minimum_queue_size",
"2");
98 section.set(
"min_ledgers_to_compute_size_limit",
"3");
99 section.set(
"max_ledger_counts_to_store",
"100");
100 section.set(
"retry_sequence_percent",
"25");
101 section.set(
"normal_consensus_increase_percent",
"0");
103 for (
auto const& [k, v] : extraTxQ)
108 if (!extraVoting.
empty())
110 auto& votingSection = p->section(
"voting");
111 for (
auto const& [k, v] : extraVoting)
113 votingSection.set(k, v);
117 p->section(
"validation_seed")
118 .legacy(
"shUwVw52ofnCUX5m7kPTKzJdr4HEH");
137 for (
auto i = env.
current()->seq(); i <= 257; ++i)
143 auto const flagPerLedger =
145 auto const flagMaxQueue = ledgersInQueue * flagPerLedger;
146 checkMetrics(env, 0, flagMaxQueue, 0, flagPerLedger, 256);
155 using namespace std::chrono_literals;
157 checkMetrics(env, 0, flagMaxQueue, 0, expectedPerLedger, 256);
158 auto const fees = env.
current()->fees();
173 testcase(
"queue sequence");
175 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
179 auto charlie =
Account(
"charlie");
361 for (
int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
374 metrics.txPerLedger + 1,
383 testcase(
"queue ticket");
385 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
407 env(ticket::create(alice, 250),
seq(tkt1 - 1),
queued);
640 testcase(
"queue tec");
642 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
646 auto USD = gw[
"USD"];
677 testcase(
"local tx retry");
679 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
683 auto charlie =
Account(
"charlie");
734 testcase(
"last ledger sequence");
736 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
740 auto charlie =
Account(
"charlie");
743 auto felicia =
Account(
"felicia");
766 json(R
"({"LastLedgerSequence":7})"),
783 aliceStat.begin()->lastValid &&
784 *aliceStat.begin()->lastValid == 8);
785 BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker());
787 auto bobStat = txQ.getAccountTxs(bob.id(), *env.
current());
790 bobStat.begin()->feeLevel ==
FeeLevel64{7000 * 256 / 10});
792 BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker());
845 testcase(
"zero transaction fee");
847 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
884 auto seqAlice = env.
seq(alice);
885 for (
int i = 0; i < 4; ++i)
888 feeAlice = (feeAlice + 1) * 125 / 100;
894 auto const seqBob = env.
seq(bob);
899 auto feeCarol = feeAlice;
900 auto seqCarol = env.
seq(carol);
901 for (
int i = 0; i < 4; ++i)
904 feeCarol = (feeCarol + 1) * 125 / 100;
943 testcase(
"fail in preclaim");
965 testcase(
"queued tx fails");
967 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"2"}}));
990 auto const& jt = env.
jt(
noop(alice));
1015 using namespace jtx;
1016 testcase(
"multi tx per account");
1021 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1022 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1024 auto alice =
Account(
"alice");
1026 auto charlie =
Account(
"charlie");
1027 auto daria =
Account(
"daria");
1036 auto const initQueueMax =
initFee(env, 3, 2, 10, 10, 200, 50);
1047 auto aliceSeq = env.
seq(alice);
1048 auto bobSeq = env.
seq(bob);
1049 auto charlieSeq = env.
seq(charlie);
1094 aliceSeq = env.
seq(alice);
1095 auto lastLedgerSeq = env.
current()->info().seq + 2;
1096 for (
auto i = 0; i < 7; i++)
1100 json(jss::LastLedgerSequence, lastLedgerSeq + i),
1110 auto const& baseFee = env.
current()->fees().base;
1111 auto seq = env.
seq(alice);
1113 for (
auto const& tx : aliceStat)
1119 (tx.consequences.fee() ==
drops(
fee) &&
1120 tx.consequences.potentialSpend() ==
drops(0) &&
1121 !tx.consequences.isBlocker()) ||
1122 tx.seqProxy.value() == env.
seq(alice) + 6);
1132 json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1165 aliceSeq = env.
seq(alice) + 2;
1184 aliceSeq = env.
seq(alice) + 1;
1191 env.
le(alice)->getFieldAmount(
sfBalance).xrp().drops() - (59);
1234 bobSeq = env.
seq(bob);
1236 for (
int i = 0; i < 10; ++i)
1251 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10 - 1);
1265 env.
le(bob)->getFieldAmount(
sfBalance).xrp().drops() - (9 * 10);
1284 using namespace jtx;
1285 using namespace std::chrono;
1286 testcase("tie breaking");
1288 Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "4"}}));
1290 auto alice = Account("alice");
1291 auto bob = Account("bob");
1292 auto charlie = Account("charlie");
1293 auto daria = Account("daria");
1294 auto elmo = Account("elmo");
1295 auto fred = Account("fred");
1296 auto gwen = Account("gwen");
1297 auto hank = Account("hank");
1299 auto queued = ter(terQUEUED);
1301 BEAST_EXPECT(env.current()->fees().base == 10);
1303 checkMetrics(env, 0, boost::none, 0, 4, 256);
1305 // Create several accounts while the fee is cheap so they all apply.
1306 env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
1307 checkMetrics(env, 0, boost::none, 4, 4, 256);
1310 checkMetrics(env, 0, 8, 0, 4, 256);
1312 env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
1313 checkMetrics(env, 0, 8, 4, 4, 256);
1316 checkMetrics(env, 0, 8, 0, 4, 256);
1320 // Stuff the ledger and queue so we can verify that
1321 // stuff gets kicked out.
1327 checkMetrics(env, 0, 8, 5, 4, 256);
1329 auto aliceSeq = env.seq(alice);
1330 auto bobSeq = env.seq(bob);
1331 auto charlieSeq = env.seq(charlie);
1332 auto dariaSeq = env.seq(daria);
1333 auto elmoSeq = env.seq(elmo);
1334 auto fredSeq = env.seq(fred);
1335 auto gwenSeq = env.seq(gwen);
1336 auto hankSeq = env.seq(hank);
1338 // This time, use identical fees.
1339 env(noop(alice), fee(15), queued);
1340 env(noop(bob), fee(15), queued);
1341 env(noop(charlie), fee(15), queued);
1342 env(noop(daria), fee(15), queued);
1343 env(noop(elmo), fee(15), queued);
1344 env(noop(fred), fee(15), queued);
1345 env(noop(gwen), fee(15), queued);
1346 // This one gets into the queue, but gets dropped when the
1347 // higher fee one is added later.
1348 env(noop(hank), fee(15), queued);
1350 // Queue is full now. Minimum fee now reflects the
1351 // lowest fee in the queue.
1352 checkMetrics(env, 8, 8, 5, 4, 385);
1354 // Try to add another transaction with the default (low) fee,
1355 // it should fail because it can't replace the one already
1384 aliceSeq = env.
seq(alice);
1385 bobSeq = env.
seq(bob);
1386 charlieSeq = env.
seq(charlie);
1387 dariaSeq = env.
seq(daria);
1388 elmoSeq = env.
seq(elmo);
1423 using namespace jtx;
1424 testcase(
"acct tx id");
1426 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"1"}}));
1428 auto alice =
Account(
"alice");
1444 json(R
"({"AccountTxnID": "0"})"),
1462 using namespace jtx;
1463 using namespace std::string_literals;
1464 testcase(
"maximum tx");
1470 {{
"minimum_txn_in_ledger_standalone",
"2"},
1471 {
"target_txn_in_ledger",
"4"},
1472 {
"maximum_txn_in_ledger",
"5"}}));
1474 auto alice =
Account(
"alice");
1481 for (
int i = 0; i < 10; ++i)
1496 {{
"minimum_txn_in_ledger",
"200"},
1497 {
"minimum_txn_in_ledger_standalone",
"200"},
1498 {
"target_txn_in_ledger",
"4"},
1499 {
"maximum_txn_in_ledger",
"5"}}));
1507 "The minimum number of low-fee transactions allowed "
1508 "per ledger (minimum_txn_in_ledger) exceeds "
1509 "the maximum number of low-fee transactions allowed per "
1510 "ledger (maximum_txn_in_ledger)."s);
1517 {{
"minimum_txn_in_ledger",
"200"},
1518 {
"minimum_txn_in_ledger_standalone",
"2"},
1519 {
"target_txn_in_ledger",
"4"},
1520 {
"maximum_txn_in_ledger",
"5"}}));
1528 "The minimum number of low-fee transactions allowed "
1529 "per ledger (minimum_txn_in_ledger) exceeds "
1530 "the maximum number of low-fee transactions allowed per "
1531 "ledger (maximum_txn_in_ledger)."s);
1538 {{
"minimum_txn_in_ledger",
"2"},
1539 {
"minimum_txn_in_ledger_standalone",
"200"},
1540 {
"target_txn_in_ledger",
"4"},
1541 {
"maximum_txn_in_ledger",
"5"}}));
1549 "The minimum number of low-fee transactions allowed "
1550 "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1551 "the maximum number of low-fee transactions allowed per "
1552 "ledger (maximum_txn_in_ledger)."s);
1559 using namespace jtx;
1560 testcase(
"unexpected balance change");
1565 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1566 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1568 auto alice =
Account(
"alice");
1574 auto const initQueueMax =
initFee(env, 3, 2, 10, 10, 200, 50);
1583 auto USD = bob[
"USD"];
1597 auto aliceSeq = env.
seq(alice);
1606 env(offer(bob,
drops(5000), USD(5000)),
1641 for (
int i = 0; i < 9; ++i)
1656 using namespace jtx;
1657 testcase(
"blockers sequence");
1659 auto alice =
Account(
"alice");
1661 auto charlie =
Account(
"charlie");
1662 auto daria =
Account(
"daria");
1666 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1682 env(
regkey(alice, charlie));
1686 auto const aliceSeq = env.
seq(alice);
1702 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1721 auto const aliceSeq = env.
seq(alice);
1736 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1762 auto const aliceSeq = env.
seq(alice);
1786 using namespace jtx;
1787 testcase(
"blockers ticket");
1789 auto alice =
Account(
"alice");
1791 auto charlie =
Account(
"charlie");
1792 auto daria =
Account(
"daria");
1796 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
1813 env(ticket::create(alice, 250),
seq(tkt - 1));
1815 env(
regkey(alice, charlie));
1819 auto const aliceSeq = env.
seq(alice);
1835 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1839 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1863 auto const aliceSeq = env.
seq(alice);
1888 env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1948 using namespace jtx;
1949 testcase(
"In-flight balance checks");
1954 {{
"minimum_txn_in_ledger_standalone",
"3"}},
1955 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}}));
1957 auto alice =
Account(
"alice");
1958 auto charlie =
Account(
"charlie");
1969 auto const initQueueMax =
initFee(env, 3, 2, 10, 10, 200, 50);
1976 checkMetrics(env, 0, initQueueMax, limit + 1, limit, 256);
1978 auto USD = gw[
"USD"];
1979 auto BUX = gw[
"BUX"];
1983 auto aliceSeq = env.
seq(alice);
1984 auto aliceBal = env.
balance(alice);
1990 env(offer(alice, BUX(5000),
XRP(50000)),
queued);
1991 checkMetrics(env, 1, initQueueMax, limit + 1, limit, 256);
1996 checkMetrics(env, 2, initQueueMax, limit + 1, limit, 256);
2012 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2013 aliceSeq = env.
seq(alice);
2014 aliceBal = env.
balance(alice);
2020 checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
2025 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2033 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2049 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2050 aliceSeq = env.
seq(alice);
2051 aliceBal = env.
balance(alice);
2058 checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
2066 checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
2082 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2083 aliceSeq = env.
seq(alice);
2084 aliceBal = env.
balance(alice);
2088 env(offer(alice, BUX(50),
XRP(500)),
queued);
2092 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2108 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2110 aliceSeq = env.
seq(alice);
2111 aliceBal = env.
balance(alice);
2121 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2135 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2137 aliceSeq = env.
seq(alice);
2138 aliceBal = env.
balance(alice);
2146 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2158 auto const amount = USD(500000);
2159 env(
trust(alice, USD(50000000)));
2160 env(
trust(charlie, USD(50000000)));
2166 env(
pay(gw, alice, amount));
2173 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2175 aliceSeq = env.
seq(alice);
2176 aliceBal = env.
balance(alice);
2177 auto aliceUSD = env.
balance(alice, USD);
2181 env(
pay(alice, charlie, amount),
queued);
2186 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2204 env(offer(gw,
XRP(500000), USD(50000)));
2210 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2212 aliceSeq = env.
seq(alice);
2213 aliceBal = env.
balance(alice);
2214 auto charlieUSD = env.
balance(charlie, USD);
2226 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2237 balance(charlie, charlieUSD + USD(1000)),
2245 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2247 aliceSeq = env.
seq(alice);
2248 aliceBal = env.
balance(alice);
2249 charlieUSD = env.
balance(charlie, USD);
2260 checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
2271 balance(charlie, charlieUSD + USD(500)),
2281 checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
2283 aliceSeq = env.
seq(alice);
2284 aliceBal = env.
balance(alice);
2291 checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
2302 using namespace jtx;
2304 testcase(
"consequences");
2307 auto const alice =
Account(
"alice");
2313 cancelOffer[jss::Account] = alice.human();
2314 cancelOffer[jss::OfferSequence] = 3;
2315 cancelOffer[jss::TransactionType] = jss::OfferCancel;
2316 auto const jtx = env.
jt(cancelOffer,
seq(5),
fee(10));
2330 auto USD = alice[
"USD"];
2347 auto const jtx = env.
jt(ticket::create(alice, 1),
seq(1),
fee(10));
2372 using namespace jtx;
2373 testcase(
"acct in queue but empty");
2375 auto alice =
Account(
"alice");
2377 auto charlie =
Account(
"charlie");
2381 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2469 using namespace jtx;
2474 auto fee = env.
rpc(
"fee");
2481 result.isMember(jss::ledger_current_index) &&
2482 result[jss::ledger_current_index] == 3);
2494 auto const& levels =
result[jss::levels];
2510 result.isMember(jss::ledger_current_index) &&
2511 result[jss::ledger_current_index] == 4);
2522 auto const& levels =
result[jss::levels];
2544 using namespace jtx;
2545 testcase(
"expiration replacement");
2550 {{
"minimum_txn_in_ledger_standalone",
"1"},
2551 {
"ledgers_in_queue",
"10"},
2552 {
"maximum_txn_per_account",
"20"}}));
2555 auto const alice =
Account(
"alice");
2556 auto const bob =
Account(
"bob");
2561 auto const aliceSeq = env.
seq(alice);
2565 json(R
"({"LastLedgerSequence":5})"),
2569 json(R"({"LastLedgerSequence":5})"),
2573 json(R"({"LastLedgerSequence":10})"),
2577 json(R"({"LastLedgerSequence":11})"),
2580 auto const bobSeq = env.
seq(bob);
2584 for (
int i = 0; i < 3 + 4 + 5; ++i)
2588 checkMetrics(env, 4 + 3 + 4 + 5, boost::none, 2, 1, 256);
2636 using namespace jtx;
2637 testcase(
"full queue gap handling");
2642 {{
"minimum_txn_in_ledger_standalone",
"1"},
2643 {
"ledgers_in_queue",
"10"},
2644 {
"maximum_txn_per_account",
"11"}}));
2649 auto const alice =
Account(
"alice");
2650 auto const bob =
Account(
"bob");
2655 auto const aliceSeq = env.
seq(alice);
2660 env(ticket::create(alice, 11),
2666 json(R
"({"LastLedgerSequence":11})"),
2670 json(R"({"LastLedgerSequence":11})"),
2674 json(R"({"LastLedgerSequence":11})"),
2678 json(R"({"LastLedgerSequence":11})"),
2682 json(R"({"LastLedgerSequence":11})"),
2686 json(R"({"LastLedgerSequence": 5})"),
2690 json(R"({"LastLedgerSequence": 5})"),
2694 json(R"({"LastLedgerSequence": 5})"),
2698 json(R"({"LastLedgerSequence":11})"),
2702 auto const bobSeq = env.
seq(bob);
2706 for (
int i = 0; i < 2 + 4 + 5; ++i)
2710 checkMetrics(env, 10 + 2 + 4 + 5, boost::none, 2, 1, 256);
2793 testcase(
"Autofilled sequence should account for TxQ");
2794 using namespace jtx;
2795 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"6"}}));
2799 auto const alice =
Account(
"alice");
2800 auto const bob =
Account(
"bob");
2801 env.
fund(
XRP(100000), alice, bob);
2807 auto const aliceSeq = env.
seq(alice);
2808 auto const lastLedgerSeq = env.
current()->info().seq + 2;
2811 for (
int i = 0; i < 5; ++i)
2818 json(jss::LastLedgerSequence, lastLedgerSeq),
2826 auto aliceStat = txQ.getAccountTxs(alice.id(), *env.
current());
2829 for (
auto const& tx : aliceStat)
2833 if (
seq.value() == aliceSeq + 2)
2836 tx.lastValid && *tx.lastValid == lastLedgerSeq);
2847 for (
int i = 0; i < 8; ++i)
2856 for (
int i = 0; i < 9; ++i)
2863 for (
int i = 0; i < 10; ++i)
2870 auto bobStat = txQ.getAccountTxs(bob.id(), *env.
current());
2876 auto aliceStat = txQ.getAccountTxs(alice.id(), *env.
current());
2877 auto seq = aliceSeq;
2879 for (
auto const& tx : aliceStat)
2882 if (
seq == aliceSeq + 2)
2895 auto aliceStat = txQ.getAccountTxs(alice.id(), *env.
current());
2896 auto seq = aliceSeq;
2898 for (
auto const& tx : aliceStat)
2911 auto bobStat = txQ.getAccountTxs(bob.id(), *env.
current());
2915 auto aliceStat = txQ.getAccountTxs(alice.id(), *env.
current());
2923 using namespace jtx;
2924 testcase(
"account info");
2926 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
2930 env.
fund(
XRP(1000000), alice);
2933 auto const withQueue =
2934 R
"({ "account": ")" + alice.human() + R"(", "queue": true })";
2937 R"(", "queue": true, "ledger_index": 3 })";
2944 info.isMember(jss::result) &&
2945 info[jss::result].isMember(jss::account_data));
2946 BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data));
2950 auto const info = env.
rpc(
"json",
"account_info", withQueue);
2952 info.isMember(jss::result) &&
2953 info[jss::result].isMember(jss::account_data));
2972 auto const info = env.
rpc(
"json",
"account_info", withQueue);
2974 info.isMember(jss::result) &&
2975 info[jss::result].isMember(jss::account_data));
2976 auto const&
result = info[jss::result];
2997 auto const info = env.
rpc(
"json",
"account_info", withQueue);
2999 info.isMember(jss::result) &&
3000 info[jss::result].isMember(jss::account_data));
3001 auto const&
result = info[jss::result];
3014 data[jss::Sequence].asUInt() +
3025 auto const& item =
queued[i];
3035 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3050 json(jss::LastLedgerSequence, 10),
3055 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3057 info.isMember(jss::result) &&
3058 info[jss::result].isMember(jss::account_data));
3059 auto const&
result = info[jss::result];
3060 auto const&
data =
result[jss::account_data];
3072 data[jss::Sequence].asUInt() +
3083 auto const& item =
queued[i];
3092 if (i ==
queued.size() - 1)
3100 BEAST_EXPECT(item[jss::auth_change].asBool() ==
false);
3111 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3113 info.isMember(jss::result) &&
3114 info[jss::result].isMember(jss::account_data));
3115 auto const&
result = info[jss::result];
3116 auto const&
data =
result[jss::account_data];
3128 data[jss::Sequence].asUInt() +
3139 auto const& item =
queued[i];
3143 if (i ==
queued.size() - 1)
3171 info.isMember(jss::result) &&
3181 auto const info = env.
rpc(
"json",
"account_info", withQueue);
3183 info.isMember(jss::result) &&
3184 info[jss::result].isMember(jss::account_data));
3185 auto const&
result = info[jss::result];
3202 using namespace jtx;
3203 testcase(
"server info");
3205 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3209 env.
fund(
XRP(1000000), alice);
3213 auto const server_info = env.
rpc(
"server_info");
3215 server_info.isMember(jss::result) &&
3216 server_info[jss::result].isMember(jss::info));
3217 auto const& info = server_info[jss::result][jss::info];
3219 info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
3223 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3226 auto const server_state = env.
rpc(
"server_state");
3227 auto const& state = server_state[jss::result][jss::state];
3229 state.isMember(jss::load_factor) &&
3230 state[jss::load_factor] == 256);
3232 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3234 state.isMember(jss::load_factor_server) &&
3235 state[jss::load_factor_server] == 256);
3237 state.isMember(jss::load_factor_fee_escalation) &&
3238 state[jss::load_factor_fee_escalation] == 256);
3240 state.isMember(jss::load_factor_fee_queue) &&
3241 state[jss::load_factor_fee_queue] == 256);
3243 state.isMember(jss::load_factor_fee_reference) &&
3244 state[jss::load_factor_fee_reference] == 256);
3252 auto aliceSeq = env.
seq(alice);
3254 for (
auto i = 0; i < 4; ++i)
3260 auto const server_info = env.
rpc(
"server_info");
3262 server_info.isMember(jss::result) &&
3263 server_info[jss::result].isMember(jss::info));
3264 auto const& info = server_info[jss::result][jss::info];
3267 info.isMember(jss::load_factor) &&
3268 info[jss::load_factor] > 888.88 &&
3269 info[jss::load_factor] < 888.89);
3271 info.isMember(jss::load_factor_server) &&
3272 info[jss::load_factor_server] == 1);
3276 info.isMember(jss::load_factor_fee_escalation) &&
3277 info[jss::load_factor_fee_escalation] > 888.88 &&
3278 info[jss::load_factor_fee_escalation] < 888.89);
3281 auto const server_state = env.
rpc(
"server_state");
3282 auto const& state = server_state[jss::result][jss::state];
3284 state.isMember(jss::load_factor) &&
3285 state[jss::load_factor] == 227555);
3287 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3289 state.isMember(jss::load_factor_server) &&
3290 state[jss::load_factor_server] == 256);
3292 state.isMember(jss::load_factor_fee_escalation) &&
3293 state[jss::load_factor_fee_escalation] == 227555);
3295 state.isMember(jss::load_factor_fee_queue) &&
3296 state[jss::load_factor_fee_queue] == 256);
3298 state.isMember(jss::load_factor_fee_reference) &&
3299 state[jss::load_factor_fee_reference] == 256);
3305 auto const server_info = env.
rpc(
"server_info");
3307 server_info.isMember(jss::result) &&
3308 server_info[jss::result].isMember(jss::info));
3309 auto const& info = server_info[jss::result][jss::info];
3312 info.isMember(jss::load_factor) &&
3313 info[jss::load_factor] == 1000);
3317 info.isMember(jss::load_factor_net) &&
3318 info[jss::load_factor_net] == 1000);
3320 info.isMember(jss::load_factor_fee_escalation) &&
3321 info[jss::load_factor_fee_escalation] > 888.88 &&
3322 info[jss::load_factor_fee_escalation] < 888.89);
3325 auto const server_state = env.
rpc(
"server_state");
3326 auto const& state = server_state[jss::result][jss::state];
3328 state.isMember(jss::load_factor) &&
3329 state[jss::load_factor] == 256000);
3331 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3333 state.isMember(jss::load_factor_server) &&
3334 state[jss::load_factor_server] == 256000);
3336 state.isMember(jss::load_factor_fee_escalation) &&
3337 state[jss::load_factor_fee_escalation] == 227555);
3339 state.isMember(jss::load_factor_fee_queue) &&
3340 state[jss::load_factor_fee_queue] == 256);
3342 state.isMember(jss::load_factor_fee_reference) &&
3343 state[jss::load_factor_fee_reference] == 256);
3349 for (
int i = 0; i < 5; ++i)
3354 auto const server_info = env.
rpc(
"server_info");
3356 server_info.isMember(jss::result) &&
3357 server_info[jss::result].isMember(jss::info));
3358 auto const& info = server_info[jss::result][jss::info];
3361 info.isMember(jss::load_factor) &&
3362 info[jss::load_factor] > 888.88 &&
3363 info[jss::load_factor] < 888.89);
3368 info.isMember(jss::load_factor_server) &&
3369 info[jss::load_factor_server] > 1.245 &&
3370 info[jss::load_factor_server] < 2.4415);
3372 info.isMember(jss::load_factor_local) &&
3373 info[jss::load_factor_local] > 1.245 &&
3374 info[jss::load_factor_local] < 2.4415);
3377 info.isMember(jss::load_factor_fee_escalation) &&
3378 info[jss::load_factor_fee_escalation] > 888.88 &&
3379 info[jss::load_factor_fee_escalation] < 888.89);
3382 auto const server_state = env.
rpc(
"server_state");
3383 auto const& state = server_state[jss::result][jss::state];
3385 state.isMember(jss::load_factor) &&
3386 state[jss::load_factor] == 227555);
3388 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3393 state.isMember(jss::load_factor_server) &&
3394 state[jss::load_factor_server] >= 320 &&
3395 state[jss::load_factor_server] <= 625);
3397 state.isMember(jss::load_factor_fee_escalation) &&
3398 state[jss::load_factor_fee_escalation] == 227555);
3400 state.isMember(jss::load_factor_fee_queue) &&
3401 state[jss::load_factor_fee_queue] == 256);
3403 state.isMember(jss::load_factor_fee_reference) &&
3404 state[jss::load_factor_fee_reference] == 256);
3410 auto const server_info = env.
rpc(
"server_info");
3412 server_info.isMember(jss::result) &&
3413 server_info[jss::result].isMember(jss::info));
3414 auto const& info = server_info[jss::result][jss::info];
3421 info.isMember(jss::load_factor) &&
3422 info[jss::load_factor] > 1.245 &&
3423 info[jss::load_factor] < 2.4415);
3426 info.isMember(jss::load_factor_local) &&
3427 info[jss::load_factor_local] > 1.245 &&
3428 info[jss::load_factor_local] < 2.4415);
3430 BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3433 auto const server_state = env.
rpc(
"server_state");
3434 auto const& state = server_state[jss::result][jss::state];
3436 state.isMember(jss::load_factor) &&
3437 state[jss::load_factor] >= 320 &&
3438 state[jss::load_factor] <= 625);
3440 state.isMember(jss::load_base) && state[jss::load_base] == 256);
3445 state.isMember(jss::load_factor_server) &&
3446 state[jss::load_factor_server] >= 320 &&
3447 state[jss::load_factor_server] <= 625);
3449 state.isMember(jss::load_factor_fee_escalation) &&
3450 state[jss::load_factor_fee_escalation] == 256);
3452 state.isMember(jss::load_factor_fee_queue) &&
3453 state[jss::load_factor_fee_queue] == 256);
3455 state.isMember(jss::load_factor_fee_reference) &&
3456 state[jss::load_factor_fee_reference] == 256);
3463 using namespace jtx;
3464 testcase(
"server subscribe");
3466 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3470 stream[jss::streams].append(
"server");
3473 auto jv = wsc->invoke(
"subscribe", stream);
3477 Account a{
"a"}, b{
"b"}, c{
"c"}, d{
"d"}, e{
"e"}, f{
"f"}, g{
"g"}, h{
"h"},
3485 using namespace std::chrono_literals;
3487 return jv[jss::type] ==
"serverStatus" &&
3488 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3489 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3490 jv.isMember(jss::load_factor_server) &&
3491 jv[jss::load_factor_server] == 256 &&
3492 jv.isMember(jss::load_factor_fee_escalation) &&
3493 jv[jss::load_factor_fee_escalation] == 256 &&
3494 jv.isMember(jss::load_factor_fee_queue) &&
3495 jv[jss::load_factor_fee_queue] == 256 &&
3496 jv.isMember(jss::load_factor_fee_reference) &&
3497 jv[jss::load_factor_fee_reference] == 256;
3501 return jv[jss::type] ==
"serverStatus" &&
3502 jv.isMember(jss::load_factor) &&
3503 jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3504 jv[jss::load_base] == 256 &&
3505 jv.isMember(jss::load_factor_server) &&
3506 jv[jss::load_factor_server] == 256 &&
3507 jv.isMember(jss::load_factor_fee_escalation) &&
3508 jv[jss::load_factor_fee_escalation] == 227555 &&
3509 jv.isMember(jss::load_factor_fee_queue) &&
3510 jv[jss::load_factor_fee_queue] == 256 &&
3511 jv.isMember(jss::load_factor_fee_reference) &&
3512 jv[jss::load_factor_fee_reference] == 256;
3519 return jv[jss::type] ==
"serverStatus" &&
3520 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3521 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3522 jv.isMember(jss::load_factor_server) &&
3523 jv[jss::load_factor_server] == 256 &&
3524 jv.isMember(jss::load_factor_fee_escalation) &&
3525 jv[jss::load_factor_fee_escalation] == 256 &&
3526 jv.isMember(jss::load_factor_fee_queue) &&
3527 jv[jss::load_factor_fee_queue] == 256 &&
3528 jv.isMember(jss::load_factor_fee_reference) &&
3529 jv[jss::load_factor_fee_reference] == 256;
3550 return jv[jss::type] ==
"serverStatus" &&
3551 jv.isMember(jss::load_factor) &&
3552 jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3553 jv[jss::load_base] == 256 &&
3554 jv.isMember(jss::load_factor_server) &&
3555 jv[jss::load_factor_server] == 256 &&
3556 jv.isMember(jss::load_factor_fee_escalation) &&
3557 jv[jss::load_factor_fee_escalation] == 200000 &&
3558 jv.isMember(jss::load_factor_fee_queue) &&
3559 jv[jss::load_factor_fee_queue] == 256 &&
3560 jv.isMember(jss::load_factor_fee_reference) &&
3561 jv[jss::load_factor_fee_reference] == 256;
3567 return jv[jss::type] ==
"serverStatus" &&
3568 jv.isMember(jss::load_factor) &&
3569 jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3570 jv[jss::load_base] == 256 &&
3571 jv.isMember(jss::load_factor_server) &&
3572 jv[jss::load_factor_server] == 256 &&
3573 jv.isMember(jss::load_factor_fee_escalation) &&
3574 jv[jss::load_factor_fee_escalation] == 184320 &&
3575 jv.isMember(jss::load_factor_fee_queue) &&
3576 jv[jss::load_factor_fee_queue] == 256 &&
3577 jv.isMember(jss::load_factor_fee_reference) &&
3578 jv[jss::load_factor_fee_reference] == 256;
3584 return jv[jss::type] ==
"serverStatus" &&
3585 jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3586 jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3587 jv.isMember(jss::load_factor_server) &&
3588 jv[jss::load_factor_server] == 256 &&
3589 jv.isMember(jss::load_factor_fee_escalation) &&
3590 jv[jss::load_factor_fee_escalation] == 256 &&
3591 jv.isMember(jss::load_factor_fee_queue) &&
3592 jv[jss::load_factor_fee_queue] == 256 &&
3593 jv.isMember(jss::load_factor_fee_reference) &&
3594 jv[jss::load_factor_fee_reference] == 256;
3598 return jv[jss::type] ==
"serverStatus";
3601 auto jv = wsc->invoke(
"unsubscribe", stream);
3608 using namespace jtx;
3609 testcase(
"clear queued acct txs");
3611 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3612 auto alice =
Account(
"alice");
3616 env.
fund(
XRP(50000000), alice, bob);
3621 boost::optional<std::size_t> numToClear =
3623 auto totalFactor = 0;
3626 numToClear.emplace(metrics.txCount + 1);
3627 for (
int i = 0; i < *numToClear; ++i)
3630 totalFactor += inLedger * inLedger;
3633 metrics.medFeeLevel * totalFactor /
3634 (metrics.txPerLedger * metrics.txPerLedger),
3644 testcase(
"straightfoward positive case");
3647 auto aliceSeq = env.
seq(alice);
3648 for (
int i = 0; i < 2; ++i)
3679 calcTotalFee(100 * 2 + 8889 + 60911);
3682 env(
noop(alice),
fee(totalFee2),
seq(aliceSeq++));
3687 testcase(
"replace last tx with enough to clear queue");
3690 auto aliceSeq = env.
seq(alice);
3691 for (
int i = 0; i < 2; ++i)
3710 calcTotalFee(100 * 2, metrics.txCount);
3714 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3723 testcase(
"replace middle tx with enough to clear queue");
3727 auto aliceSeq = env.
seq(alice);
3728 for (
int i = 0; i < 5; ++i)
3740 env(
noop(alice),
fee(totalFee),
seq(aliceSeq++));
3743 auto const aliceQueue =
3747 for (
auto const& tx : aliceQueue)
3759 testcase(
"clear queue failure (load)");
3763 auto aliceSeq = env.
seq(alice);
3764 for (
int i = 0; i < 2; ++i)
3768 for (
int i = 0; i < 2; ++i)
3777 std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
3782 feeTrack.setRemoteFee(origFee * 5);
3795 feeTrack.setRemoteFee(origFee);
3814 using namespace jtx;
3815 using namespace std::chrono_literals;
3816 testcase(
"scaling");
3822 {{
"minimum_txn_in_ledger_standalone",
"3"},
3823 {
"normal_consensus_increase_percent",
"25"},
3824 {
"slow_consensus_decrease_percent",
"50"},
3825 {
"target_txn_in_ledger",
"10"},
3826 {
"maximum_txn_per_account",
"200"}}));
3827 auto alice =
Account(
"alice");
3830 env.
fund(
XRP(50000000), alice);
3834 auto seqAlice = env.
seq(alice);
3836 for (
int i = 0; i < txCount; ++i)
3880 env.
close(env.
now() + 5s, 10000ms);
3885 env.
close(env.
now() + 5s, 10000ms);
3890 env.
close(env.
now() + 5s, 10000ms);
3897 env.
close(env.
now() + 5s, 10000ms);
3908 {{
"minimum_txn_in_ledger_standalone",
"3"},
3909 {
"normal_consensus_increase_percent",
"150"},
3910 {
"slow_consensus_decrease_percent",
"150"},
3911 {
"target_txn_in_ledger",
"10"},
3912 {
"maximum_txn_per_account",
"200"}}));
3913 auto alice =
Account(
"alice");
3916 env.
fund(
XRP(50000000), alice);
3920 auto seqAlice = env.
seq(alice);
3922 for (
int i = 0; i < txCount; ++i)
3941 env.
close(env.
now() + 5s, 10000ms);
3962 testcase(
"Sequence in queue and open ledger");
3963 using namespace jtx;
3965 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
3967 auto const alice =
Account(
"alice");
3983 auto const aliceSeq = env.
seq(alice);
4029 testcase(
"Ticket in queue and open ledger");
4030 using namespace jtx;
4032 Env env(*
this,
makeConfig({{
"minimum_txn_in_ledger_standalone",
"3"}}));
4034 auto alice =
Account(
"alice");
4048 env(ticket::create(alice, 4));
4065 auto const tx = env.
jt(
4125 testcase(
"Re-execute preflight");
4126 using namespace jtx;
4136 {{
"minimum_txn_in_ledger_standalone",
"1"},
4137 {
"ledgers_in_queue",
"5"},
4138 {
"maximum_txn_per_account",
"10"}},
4139 {{
"account_reserve",
"200"}, {
"owner_reserve",
"50"}});
4141 Env env(*
this, std::move(cfg));
4143 env.fund(
XRP(10000), alice);
4145 env.fund(
XRP(10000), bob);
4147 env.fund(
XRP(10000), carol);
4149 env.fund(
XRP(10000), daria);
4151 env.fund(
XRP(10000), ellie);
4153 env.fund(
XRP(10000), fiona);
4159 for (i = 0; i <= 257; ++i)
4165 auto expectedPerLedger =
4167 checkMetrics(env, 0, 5 * expectedPerLedger, 0, expectedPerLedger, 256);
4172 using namespace std::chrono_literals;
4173 auto closeDuration = 80min;
4174 for (i = 0; i <= 255; ++i)
4175 env.close(closeDuration);
4182 5 * expectedPerLedger,
4183 expectedPerLedger + 1,
4188 auto seqAlice = env.seq(alice);
4189 auto seqBob = env.seq(bob);
4190 auto seqCarol = env.seq(carol);
4191 auto seqDaria = env.seq(daria);
4192 auto seqEllie = env.seq(ellie);
4193 auto seqFiona = env.seq(fiona);
4194 for (
int i = 0; i < 10; ++i)
4207 5 * expectedPerLedger,
4208 expectedPerLedger + 1,
4221 env.close(closeDuration);
4222 expectedInQueue -= expectedPerLedger + 2;
4223 ++expectedPerLedger;
4227 5 * expectedPerLedger,
4228 expectedPerLedger + 1,
4232 auto const expectedPerAccount = expectedInQueue / 6;
4233 auto const expectedRemainder = expectedInQueue % 6;
4234 BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4237 seqBob - expectedPerAccount - (expectedRemainder > 4 ? 1 : 0));
4240 seqCarol - expectedPerAccount -
4241 (expectedRemainder > 3 ? 1 : 0));
4244 seqDaria - expectedPerAccount -
4245 (expectedRemainder > 2 ? 1 : 0));
4248 seqEllie - expectedPerAccount -
4249 (expectedRemainder > 1 ? 1 : 0));
4252 seqFiona - expectedPerAccount -
4253 (expectedRemainder > 0 ? 1 : 0));
4256 env.close(closeDuration);
4257 auto expectedInLedger = expectedInQueue;
4259 (expectedInQueue > expectedPerLedger + 2
4260 ? expectedInQueue - (expectedPerLedger + 2)
4262 ++expectedPerLedger;
4266 5 * expectedPerLedger,
4271 auto const expectedPerAccount = expectedInQueue / 6;
4272 auto const expectedRemainder = expectedInQueue % 6;
4273 BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4276 seqBob - expectedPerAccount - (expectedRemainder > 4 ? 1 : 0));
4279 seqCarol - expectedPerAccount -
4280 (expectedRemainder > 3 ? 1 : 0));
4283 seqDaria - expectedPerAccount -
4284 (expectedRemainder > 2 ? 1 : 0));
4287 seqEllie - expectedPerAccount -
4288 (expectedRemainder > 1 ? 1 : 0));
4291 seqFiona - expectedPerAccount -
4292 (expectedRemainder > 0 ? 1 : 0));
4306 testcase(
"Queue full drop penalty");
4307 using namespace jtx;
4323 auto const medFee =
drops(15);
4324 auto const hiFee =
drops(1000);
4327 {{
"minimum_txn_in_ledger_standalone",
"5"},
4328 {
"ledgers_in_queue",
"5"},
4329 {
"maximum_txn_per_account",
"30"},
4330 {
"minimum_queue_size",
"50"}});
4332 Env env(*
this, std::move(cfg));
4336 env.fund(
XRP(10000),
noripple(alice, bob, carol, daria, ellie, fiona));
4341 env(ticket::create(bob, 10));
4352 auto seqAlice = env.seq(alice);
4353 auto const seqSaveAlice = seqAlice;
4356 json(R
"({"LastLedgerSequence": 7})"),
4366 json(R
"({"LastLedgerSequence": 7})"),
4373 auto seqCarol = env.seq(carol);
4374 auto seqDaria = env.seq(daria);
4375 auto seqEllie = env.seq(ellie);
4376 auto seqFiona = env.seq(fiona);
4377 for (
int i = 0; i < 7; ++i)
4390 for (
int i = 0; i < 3; ++i)
4402 for (
int i = 0; i < 3; ++i)
4422 for (
int i = 0; i < 4; ++i)
4441 for (
int i = 0; i < 10; ++i)
4442 env.app().getFeeTrack().raiseLocalFee();
4452 while (env.app().getFeeTrack().lowerLocalFee())
4478 seqAlice = seqSaveAlice;
4524 testcase(
"Cancel queued offers");
4525 using namespace jtx;
4529 auto USD = gw[
"USD"];
4532 {{
"minimum_txn_in_ledger_standalone",
"5"},
4533 {
"ledgers_in_queue",
"5"},
4534 {
"maximum_txn_per_account",
"30"},
4535 {
"minimum_queue_size",
"50"}});
4537 Env env(*
this, std::move(cfg));
4549 auto const aliceSeq = env.seq(alice);
4552 env(offer(alice, USD(1000),
XRP(1001)),
4558 env(offer(alice, USD(1000),
XRP(1002)),
4560 json(jss::OfferSequence, aliceSeq),
4576 auto const aliceTkt = env.seq(alice);
4577 env(ticket::create(alice, 6));
4584 auto const aliceSeq = env.seq(alice);
4585 env(offer(alice, USD(1000),
XRP(1000)),
4589 env(offer(alice, USD(1000),
XRP(1001)),
4599 env(offer(alice, USD(1000),
XRP(1002)),
4601 json(jss::OfferSequence, aliceTkt + 4),
4611 env(offer(alice, USD(1000),
XRP(1001)),
4616 env(offer(alice, USD(1000),
XRP(1002)),
4618 json(jss::OfferSequence, aliceSeq),