From 3f4df06e3af1601ca3cb0de70a13cb8813e10f02 Mon Sep 17 00:00:00 2001 From: intelliot Date: Wed, 31 Jan 2024 06:18:02 +0000 Subject: [PATCH] deploy: 90d463b925c377878d3abdb27eb3a1530782a668 --- TxQ__test_8cpp_source.html | 7750 +++++++++-------- classripple_1_1test_1_1TxQMetaInfo__test.html | 78 +- ...ipple_1_1test_1_1TxQPosNegFlows__test.html | 76 +- 3 files changed, 3954 insertions(+), 3950 deletions(-) diff --git a/TxQ__test_8cpp_source.html b/TxQ__test_8cpp_source.html index 03738c48b8..b4626310a5 100644 --- a/TxQ__test_8cpp_source.html +++ b/TxQ__test_8cpp_source.html @@ -1080,3960 +1080,3963 @@ $(function() {
1019  // Fail in preflight
1020  env(pay(alice, bob, XRP(-1000)), ter(temBAD_AMOUNT));
1021 
-
1022  // Fail in preclaim
-
1023  env(noop(alice), fee(XRP(100000)), ter(terINSUF_FEE_B));
-
1024  }
-
1025 
-
1026  void
-
1027  testQueuedTxFails()
-
1028  {
-
1029  using namespace jtx;
-
1030  testcase("queued tx fails");
-
1031 
-
1032  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "2"}}));
-
1033 
-
1034  auto alice = Account("alice");
-
1035  auto bob = Account("bob");
+
1022  // Fail in preflight
+
1023  env(pay(alice, alice, XRP(100)), ter(temREDUNDANT));
+
1024 
+
1025  // Fail in preclaim
+
1026  env(noop(alice), fee(XRP(100000)), ter(terINSUF_FEE_B));
+
1027  }
+
1028 
+
1029  void
+
1030  testQueuedTxFails()
+
1031  {
+
1032  using namespace jtx;
+
1033  testcase("queued tx fails");
+
1034 
+
1035  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "2"}}));
1036 
-
1037  auto queued = ter(terQUEUED);
-
1038 
-
1039  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
-
1040 
-
1041  env.fund(XRP(1000), noripple(alice, bob));
-
1042 
-
1043  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
-
1044 
-
1045  // Fill the ledger
-
1046  env(noop(alice));
-
1047  checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
-
1048 
-
1049  // Put a transaction in the queue
-
1050  env(noop(alice), queued);
-
1051  checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
-
1052 
-
1053  // Now cheat, and bypass the queue.
-
1054  {
-
1055  auto const& jt = env.jt(noop(alice));
-
1056  BEAST_EXPECT(jt.stx);
-
1057 
-
1058  bool didApply;
-
1059  TER ter;
+
1037  auto alice = Account("alice");
+
1038  auto bob = Account("bob");
+
1039 
+
1040  auto queued = ter(terQUEUED);
+
1041 
+
1042  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
+
1043 
+
1044  env.fund(XRP(1000), noripple(alice, bob));
+
1045 
+
1046  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
+
1047 
+
1048  // Fill the ledger
+
1049  env(noop(alice));
+
1050  checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
+
1051 
+
1052  // Put a transaction in the queue
+
1053  env(noop(alice), queued);
+
1054  checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
+
1055 
+
1056  // Now cheat, and bypass the queue.
+
1057  {
+
1058  auto const& jt = env.jt(noop(alice));
+
1059  BEAST_EXPECT(jt.stx);
1060 
-
1061  env.app().openLedger().modify(
-
1062  [&](OpenView& view, beast::Journal j) {
-
1063  std::tie(ter, didApply) = ripple::apply(
-
1064  env.app(), view, *jt.stx, tapNONE, env.journal);
-
1065  return didApply;
-
1066  });
-
1067  env.postconditions(jt, ter, didApply);
-
1068  }
-
1069  checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
-
1070 
-
1071  env.close();
-
1072  // Alice's queued transaction failed in TxQ::accept
-
1073  // with tefPAST_SEQ
-
1074  checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
-
1075  }
-
1076 
-
1077  void
-
1078  testMultiTxnPerAccount()
-
1079  {
-
1080  using namespace jtx;
-
1081  testcase("multi tx per account");
-
1082 
-
1083  Env env(
-
1084  *this,
-
1085  makeConfig(
-
1086  {{"minimum_txn_in_ledger_standalone", "3"}},
-
1087  {{"account_reserve", "200"}, {"owner_reserve", "50"}}));
-
1088 
-
1089  auto alice = Account("alice");
-
1090  auto bob = Account("bob");
-
1091  auto charlie = Account("charlie");
-
1092  auto daria = Account("daria");
-
1093 
-
1094  auto queued = ter(terQUEUED);
-
1095 
-
1096  BEAST_EXPECT(env.current()->fees().base == 10);
-
1097 
-
1098  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
-
1099 
-
1100  // ledgers in queue is 2 because of makeConfig
-
1101  auto const initQueueMax = initFee(env, 3, 2, 10, 200, 50);
+
1061  bool didApply;
+
1062  TER ter;
+
1063 
+
1064  env.app().openLedger().modify(
+
1065  [&](OpenView& view, beast::Journal j) {
+
1066  std::tie(ter, didApply) = ripple::apply(
+
1067  env.app(), view, *jt.stx, tapNONE, env.journal);
+
1068  return didApply;
+
1069  });
+
1070  env.postconditions(jt, ter, didApply);
+
1071  }
+
1072  checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
+
1073 
+
1074  env.close();
+
1075  // Alice's queued transaction failed in TxQ::accept
+
1076  // with tefPAST_SEQ
+
1077  checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
+
1078  }
+
1079 
+
1080  void
+
1081  testMultiTxnPerAccount()
+
1082  {
+
1083  using namespace jtx;
+
1084  testcase("multi tx per account");
+
1085 
+
1086  Env env(
+
1087  *this,
+
1088  makeConfig(
+
1089  {{"minimum_txn_in_ledger_standalone", "3"}},
+
1090  {{"account_reserve", "200"}, {"owner_reserve", "50"}}));
+
1091 
+
1092  auto alice = Account("alice");
+
1093  auto bob = Account("bob");
+
1094  auto charlie = Account("charlie");
+
1095  auto daria = Account("daria");
+
1096 
+
1097  auto queued = ter(terQUEUED);
+
1098 
+
1099  BEAST_EXPECT(env.current()->fees().base == 10);
+
1100 
+
1101  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1102 
-
1103  // Create several accounts while the fee is cheap so they all apply.
-
1104  env.fund(drops(2000), noripple(alice));
-
1105  env.fund(XRP(500000), noripple(bob, charlie, daria));
-
1106  checkMetrics(__LINE__, env, 0, initQueueMax, 4, 3, 256);
-
1107 
-
1108  // Alice - price starts exploding: held
-
1109  env(noop(alice), fee(11), queued);
-
1110  checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
-
1111 
-
1112  auto aliceSeq = env.seq(alice);
-
1113  auto bobSeq = env.seq(bob);
-
1114  auto charlieSeq = env.seq(charlie);
-
1115 
-
1116  // Alice - try to queue a second transaction, but leave a gap
-
1117  env(noop(alice), seq(aliceSeq + 2), fee(100), ter(telCAN_NOT_QUEUE));
-
1118  checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
-
1119 
-
1120  // Alice - queue a second transaction. Yay!
-
1121  env(noop(alice), seq(aliceSeq + 1), fee(13), queued);
-
1122  checkMetrics(__LINE__, env, 2, initQueueMax, 4, 3, 256);
-
1123 
-
1124  // Alice - queue a third transaction. Yay.
-
1125  env(noop(alice), seq(aliceSeq + 2), fee(17), queued);
-
1126  checkMetrics(__LINE__, env, 3, initQueueMax, 4, 3, 256);
-
1127 
-
1128  // Bob - queue a transaction
-
1129  env(noop(bob), queued);
-
1130  checkMetrics(__LINE__, env, 4, initQueueMax, 4, 3, 256);
-
1131 
-
1132  // Bob - queue a second transaction
-
1133  env(noop(bob), seq(bobSeq + 1), fee(50), queued);
-
1134  checkMetrics(__LINE__, env, 5, initQueueMax, 4, 3, 256);
-
1135 
-
1136  // Charlie - queue a transaction, with a higher fee
-
1137  // than default
-
1138  env(noop(charlie), fee(15), queued);
-
1139  checkMetrics(__LINE__, env, 6, initQueueMax, 4, 3, 256);
-
1140 
-
1141  BEAST_EXPECT(env.seq(alice) == aliceSeq);
-
1142  BEAST_EXPECT(env.seq(bob) == bobSeq);
-
1143  BEAST_EXPECT(env.seq(charlie) == charlieSeq);
-
1144 
-
1145  env.close();
-
1146  // Verify that all of but one of the queued transactions
-
1147  // got applied.
-
1148  checkMetrics(__LINE__, env, 1, 8, 5, 4, 256);
-
1149 
-
1150  // Verify that the stuck transaction is Bob's second.
-
1151  // Even though it had a higher fee than Alice's and
-
1152  // Charlie's, it didn't get attempted until the fee escalated.
-
1153  BEAST_EXPECT(env.seq(alice) == aliceSeq + 3);
-
1154  BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
-
1155  BEAST_EXPECT(env.seq(charlie) == charlieSeq + 1);
-
1156 
-
1157  // Alice - fill up the queue
-
1158  std::int64_t aliceFee = 27;
-
1159  aliceSeq = env.seq(alice);
-
1160  auto lastLedgerSeq = env.current()->info().seq + 2;
-
1161  for (auto i = 0; i < 7; i++)
-
1162  {
-
1163  env(noop(alice),
-
1164  seq(aliceSeq),
-
1165  json(jss::LastLedgerSequence, lastLedgerSeq + i),
-
1166  fee(--aliceFee),
-
1167  queued);
-
1168  ++aliceSeq;
-
1169  }
-
1170  checkMetrics(__LINE__, env, 8, 8, 5, 4, 513);
-
1171  {
-
1172  auto& txQ = env.app().getTxQ();
-
1173  auto aliceStat = txQ.getAccountTxs(alice.id());
-
1174  aliceFee = 27;
-
1175  auto const& baseFee = env.current()->fees().base;
-
1176  auto seq = env.seq(alice);
-
1177  BEAST_EXPECT(aliceStat.size() == 7);
-
1178  for (auto const& tx : aliceStat)
-
1179  {
-
1180  BEAST_EXPECT(tx.seqProxy.isSeq() && tx.seqProxy.value() == seq);
-
1181  BEAST_EXPECT(
-
1182  tx.feeLevel == toFeeLevel(XRPAmount(--aliceFee), baseFee));
-
1183  BEAST_EXPECT(tx.lastValid);
+
1103  // ledgers in queue is 2 because of makeConfig
+
1104  auto const initQueueMax = initFee(env, 3, 2, 10, 200, 50);
+
1105 
+
1106  // Create several accounts while the fee is cheap so they all apply.
+
1107  env.fund(drops(2000), noripple(alice));
+
1108  env.fund(XRP(500000), noripple(bob, charlie, daria));
+
1109  checkMetrics(__LINE__, env, 0, initQueueMax, 4, 3, 256);
+
1110 
+
1111  // Alice - price starts exploding: held
+
1112  env(noop(alice), fee(11), queued);
+
1113  checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
+
1114 
+
1115  auto aliceSeq = env.seq(alice);
+
1116  auto bobSeq = env.seq(bob);
+
1117  auto charlieSeq = env.seq(charlie);
+
1118 
+
1119  // Alice - try to queue a second transaction, but leave a gap
+
1120  env(noop(alice), seq(aliceSeq + 2), fee(100), ter(telCAN_NOT_QUEUE));
+
1121  checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
+
1122 
+
1123  // Alice - queue a second transaction. Yay!
+
1124  env(noop(alice), seq(aliceSeq + 1), fee(13), queued);
+
1125  checkMetrics(__LINE__, env, 2, initQueueMax, 4, 3, 256);
+
1126 
+
1127  // Alice - queue a third transaction. Yay.
+
1128  env(noop(alice), seq(aliceSeq + 2), fee(17), queued);
+
1129  checkMetrics(__LINE__, env, 3, initQueueMax, 4, 3, 256);
+
1130 
+
1131  // Bob - queue a transaction
+
1132  env(noop(bob), queued);
+
1133  checkMetrics(__LINE__, env, 4, initQueueMax, 4, 3, 256);
+
1134 
+
1135  // Bob - queue a second transaction
+
1136  env(noop(bob), seq(bobSeq + 1), fee(50), queued);
+
1137  checkMetrics(__LINE__, env, 5, initQueueMax, 4, 3, 256);
+
1138 
+
1139  // Charlie - queue a transaction, with a higher fee
+
1140  // than default
+
1141  env(noop(charlie), fee(15), queued);
+
1142  checkMetrics(__LINE__, env, 6, initQueueMax, 4, 3, 256);
+
1143 
+
1144  BEAST_EXPECT(env.seq(alice) == aliceSeq);
+
1145  BEAST_EXPECT(env.seq(bob) == bobSeq);
+
1146  BEAST_EXPECT(env.seq(charlie) == charlieSeq);
+
1147 
+
1148  env.close();
+
1149  // Verify that all of but one of the queued transactions
+
1150  // got applied.
+
1151  checkMetrics(__LINE__, env, 1, 8, 5, 4, 256);
+
1152 
+
1153  // Verify that the stuck transaction is Bob's second.
+
1154  // Even though it had a higher fee than Alice's and
+
1155  // Charlie's, it didn't get attempted until the fee escalated.
+
1156  BEAST_EXPECT(env.seq(alice) == aliceSeq + 3);
+
1157  BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
+
1158  BEAST_EXPECT(env.seq(charlie) == charlieSeq + 1);
+
1159 
+
1160  // Alice - fill up the queue
+
1161  std::int64_t aliceFee = 27;
+
1162  aliceSeq = env.seq(alice);
+
1163  auto lastLedgerSeq = env.current()->info().seq + 2;
+
1164  for (auto i = 0; i < 7; i++)
+
1165  {
+
1166  env(noop(alice),
+
1167  seq(aliceSeq),
+
1168  json(jss::LastLedgerSequence, lastLedgerSeq + i),
+
1169  fee(--aliceFee),
+
1170  queued);
+
1171  ++aliceSeq;
+
1172  }
+
1173  checkMetrics(__LINE__, env, 8, 8, 5, 4, 513);
+
1174  {
+
1175  auto& txQ = env.app().getTxQ();
+
1176  auto aliceStat = txQ.getAccountTxs(alice.id());
+
1177  aliceFee = 27;
+
1178  auto const& baseFee = env.current()->fees().base;
+
1179  auto seq = env.seq(alice);
+
1180  BEAST_EXPECT(aliceStat.size() == 7);
+
1181  for (auto const& tx : aliceStat)
+
1182  {
+
1183  BEAST_EXPECT(tx.seqProxy.isSeq() && tx.seqProxy.value() == seq);
1184  BEAST_EXPECT(
-
1185  (tx.consequences.fee() == drops(aliceFee) &&
-
1186  tx.consequences.potentialSpend() == drops(0) &&
-
1187  !tx.consequences.isBlocker()) ||
-
1188  tx.seqProxy.value() == env.seq(alice) + 6);
-
1189  ++seq;
-
1190  }
-
1191  }
-
1192 
-
1193  // Alice attempts to add another item to the queue,
-
1194  // but you can't force your own earlier txn off the
-
1195  // queue.
-
1196  env(noop(alice),
-
1197  seq(aliceSeq),
-
1198  json(jss::LastLedgerSequence, lastLedgerSeq + 7),
-
1199  fee(aliceFee),
-
1200  ter(telCAN_NOT_QUEUE_FULL));
-
1201  checkMetrics(__LINE__, env, 8, 8, 5, 4, 513);
-
1202 
-
1203  // Charlie - try to add another item to the queue,
-
1204  // which fails because fee is lower than Alice's
-
1205  // queued average.
-
1206  env(noop(charlie), fee(19), ter(telCAN_NOT_QUEUE_FULL));
-
1207  checkMetrics(__LINE__, env, 8, 8, 5, 4, 513);
-
1208 
-
1209  // Charlie - add another item to the queue, which
-
1210  // causes Alice's last txn to drop
-
1211  env(noop(charlie), fee(30), queued);
-
1212  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
-
1213 
-
1214  // Alice - now attempt to add one more to the queue,
-
1215  // which fails because the last tx was dropped, so
-
1216  // there is no complete chain.
-
1217  env(noop(alice), seq(aliceSeq), fee(aliceFee), ter(telCAN_NOT_QUEUE));
-
1218  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
-
1219 
-
1220  // Alice wants this tx more than the dropped tx,
-
1221  // so resubmits with higher fee, but the queue
-
1222  // is full, and her account is the cheapest.
-
1223  env(noop(alice),
-
1224  seq(aliceSeq - 1),
-
1225  fee(aliceFee),
-
1226  ter(telCAN_NOT_QUEUE_FULL));
-
1227  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
-
1228 
-
1229  // Try to replace a middle item in the queue
-
1230  // without enough fee.
-
1231  aliceSeq = env.seq(alice) + 2;
-
1232  aliceFee = 29;
-
1233  env(noop(alice),
-
1234  seq(aliceSeq),
-
1235  fee(aliceFee),
-
1236  ter(telCAN_NOT_QUEUE_FEE));
-
1237  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
-
1238 
-
1239  // Replace a middle item from the queue successfully
-
1240  ++aliceFee;
-
1241  env(noop(alice), seq(aliceSeq), fee(aliceFee), queued);
-
1242  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
-
1243 
-
1244  env.close();
-
1245  // Alice's transactions processed, along with
-
1246  // Charlie's, and the lost one is replayed and
-
1247  // added back to the queue.
-
1248  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
-
1249 
-
1250  aliceSeq = env.seq(alice) + 1;
-
1251 
-
1252  // Try to replace that item with a transaction that will
-
1253  // bankrupt Alice. Fails, because an account can't have
-
1254  // more than the minimum reserve in flight before the
-
1255  // last queued transaction
-
1256  aliceFee =
-
1257  env.le(alice)->getFieldAmount(sfBalance).xrp().drops() - (62);
-
1258  env(noop(alice),
-
1259  seq(aliceSeq),
-
1260  fee(aliceFee),
-
1261  ter(telCAN_NOT_QUEUE_BALANCE));
-
1262  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
-
1263 
-
1264  // Try to spend more than Alice can afford with all the other txs.
-
1265  aliceSeq += 2;
-
1266  env(noop(alice), seq(aliceSeq), fee(aliceFee), ter(terINSUF_FEE_B));
-
1267  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
-
1268 
-
1269  // Replace the last queued item with a transaction that will
-
1270  // bankrupt Alice
-
1271  --aliceFee;
-
1272  env(noop(alice), seq(aliceSeq), fee(aliceFee), queued);
-
1273  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
-
1274 
-
1275  // Alice - Attempt to queue a last transaction, but it
-
1276  // fails because the fee in flight is too high, before
-
1277  // the fee is checked against the balance
-
1278  aliceFee /= 5;
-
1279  ++aliceSeq;
-
1280  env(noop(alice),
-
1281  seq(aliceSeq),
-
1282  fee(aliceFee),
-
1283  ter(telCAN_NOT_QUEUE_BALANCE));
-
1284  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
-
1285 
-
1286  env.close();
-
1287  // All of Alice's transactions applied.
-
1288  checkMetrics(__LINE__, env, 0, 12, 4, 6, 256);
-
1289 
-
1290  env.close();
-
1291  checkMetrics(__LINE__, env, 0, 12, 0, 6, 256);
+
1185  tx.feeLevel == toFeeLevel(XRPAmount(--aliceFee), baseFee));
+
1186  BEAST_EXPECT(tx.lastValid);
+
1187  BEAST_EXPECT(
+
1188  (tx.consequences.fee() == drops(aliceFee) &&
+
1189  tx.consequences.potentialSpend() == drops(0) &&
+
1190  !tx.consequences.isBlocker()) ||
+
1191  tx.seqProxy.value() == env.seq(alice) + 6);
+
1192  ++seq;
+
1193  }
+
1194  }
+
1195 
+
1196  // Alice attempts to add another item to the queue,
+
1197  // but you can't force your own earlier txn off the
+
1198  // queue.
+
1199  env(noop(alice),
+
1200  seq(aliceSeq),
+
1201  json(jss::LastLedgerSequence, lastLedgerSeq + 7),
+
1202  fee(aliceFee),
+
1203  ter(telCAN_NOT_QUEUE_FULL));
+
1204  checkMetrics(__LINE__, env, 8, 8, 5, 4, 513);
+
1205 
+
1206  // Charlie - try to add another item to the queue,
+
1207  // which fails because fee is lower than Alice's
+
1208  // queued average.
+
1209  env(noop(charlie), fee(19), ter(telCAN_NOT_QUEUE_FULL));
+
1210  checkMetrics(__LINE__, env, 8, 8, 5, 4, 513);
+
1211 
+
1212  // Charlie - add another item to the queue, which
+
1213  // causes Alice's last txn to drop
+
1214  env(noop(charlie), fee(30), queued);
+
1215  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
+
1216 
+
1217  // Alice - now attempt to add one more to the queue,
+
1218  // which fails because the last tx was dropped, so
+
1219  // there is no complete chain.
+
1220  env(noop(alice), seq(aliceSeq), fee(aliceFee), ter(telCAN_NOT_QUEUE));
+
1221  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
+
1222 
+
1223  // Alice wants this tx more than the dropped tx,
+
1224  // so resubmits with higher fee, but the queue
+
1225  // is full, and her account is the cheapest.
+
1226  env(noop(alice),
+
1227  seq(aliceSeq - 1),
+
1228  fee(aliceFee),
+
1229  ter(telCAN_NOT_QUEUE_FULL));
+
1230  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
+
1231 
+
1232  // Try to replace a middle item in the queue
+
1233  // without enough fee.
+
1234  aliceSeq = env.seq(alice) + 2;
+
1235  aliceFee = 29;
+
1236  env(noop(alice),
+
1237  seq(aliceSeq),
+
1238  fee(aliceFee),
+
1239  ter(telCAN_NOT_QUEUE_FEE));
+
1240  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
+
1241 
+
1242  // Replace a middle item from the queue successfully
+
1243  ++aliceFee;
+
1244  env(noop(alice), seq(aliceSeq), fee(aliceFee), queued);
+
1245  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
+
1246 
+
1247  env.close();
+
1248  // Alice's transactions processed, along with
+
1249  // Charlie's, and the lost one is replayed and
+
1250  // added back to the queue.
+
1251  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
+
1252 
+
1253  aliceSeq = env.seq(alice) + 1;
+
1254 
+
1255  // Try to replace that item with a transaction that will
+
1256  // bankrupt Alice. Fails, because an account can't have
+
1257  // more than the minimum reserve in flight before the
+
1258  // last queued transaction
+
1259  aliceFee =
+
1260  env.le(alice)->getFieldAmount(sfBalance).xrp().drops() - (62);
+
1261  env(noop(alice),
+
1262  seq(aliceSeq),
+
1263  fee(aliceFee),
+
1264  ter(telCAN_NOT_QUEUE_BALANCE));
+
1265  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
+
1266 
+
1267  // Try to spend more than Alice can afford with all the other txs.
+
1268  aliceSeq += 2;
+
1269  env(noop(alice), seq(aliceSeq), fee(aliceFee), ter(terINSUF_FEE_B));
+
1270  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
+
1271 
+
1272  // Replace the last queued item with a transaction that will
+
1273  // bankrupt Alice
+
1274  --aliceFee;
+
1275  env(noop(alice), seq(aliceSeq), fee(aliceFee), queued);
+
1276  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
+
1277 
+
1278  // Alice - Attempt to queue a last transaction, but it
+
1279  // fails because the fee in flight is too high, before
+
1280  // the fee is checked against the balance
+
1281  aliceFee /= 5;
+
1282  ++aliceSeq;
+
1283  env(noop(alice),
+
1284  seq(aliceSeq),
+
1285  fee(aliceFee),
+
1286  ter(telCAN_NOT_QUEUE_BALANCE));
+
1287  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
+
1288 
+
1289  env.close();
+
1290  // All of Alice's transactions applied.
+
1291  checkMetrics(__LINE__, env, 0, 12, 4, 6, 256);
1292 
-
1293  // Alice is broke
-
1294  env.require(balance(alice, XRP(0)));
-
1295  env(noop(alice), ter(terINSUF_FEE_B));
-
1296 
-
1297  // Bob tries to queue up more than the single
-
1298  // account limit (10) txs.
-
1299  fillQueue(env, bob);
-
1300  bobSeq = env.seq(bob);
-
1301  checkMetrics(__LINE__, env, 0, 12, 7, 6, 256);
-
1302  for (int i = 0; i < 10; ++i)
-
1303  env(noop(bob), seq(bobSeq + i), queued);
-
1304  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
-
1305  // Bob hit the single account limit
-
1306  env(noop(bob), seq(bobSeq + 10), ter(telCAN_NOT_QUEUE_FULL));
+
1293  env.close();
+
1294  checkMetrics(__LINE__, env, 0, 12, 0, 6, 256);
+
1295 
+
1296  // Alice is broke
+
1297  env.require(balance(alice, XRP(0)));
+
1298  env(noop(alice), ter(terINSUF_FEE_B));
+
1299 
+
1300  // Bob tries to queue up more than the single
+
1301  // account limit (10) txs.
+
1302  fillQueue(env, bob);
+
1303  bobSeq = env.seq(bob);
+
1304  checkMetrics(__LINE__, env, 0, 12, 7, 6, 256);
+
1305  for (int i = 0; i < 10; ++i)
+
1306  env(noop(bob), seq(bobSeq + i), queued);
1307  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
-
1308  // Bob can replace one of the earlier txs regardless
-
1309  // of the limit
-
1310  env(noop(bob), seq(bobSeq + 5), fee(20), queued);
-
1311  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
-
1312 
-
1313  // Try to replace a middle item in the queue
-
1314  // with enough fee to bankrupt bob and make the
-
1315  // later transactions unable to pay their fees
-
1316  std::int64_t bobFee =
-
1317  env.le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10 - 1);
-
1318  env(noop(bob),
-
1319  seq(bobSeq + 5),
-
1320  fee(bobFee),
-
1321  ter(telCAN_NOT_QUEUE_BALANCE));
-
1322  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
-
1323 
-
1324  // Attempt to replace a middle item in the queue with enough fee
-
1325  // to bankrupt bob, and also to use fee averaging to clear out the
-
1326  // first six transactions.
-
1327  //
-
1328  // The attempt fails because the sum of bob's fees now exceeds the
-
1329  // (artificially lowered to 200 drops) account reserve.
-
1330  bobFee =
-
1331  env.le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10);
-
1332  env(noop(bob),
-
1333  seq(bobSeq + 5),
-
1334  fee(bobFee),
-
1335  ter(telCAN_NOT_QUEUE_BALANCE));
-
1336  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
-
1337 
-
1338  // Close the ledger and verify that the queued transactions succeed
-
1339  // and bob has the right ending balance.
-
1340  env.close();
-
1341  checkMetrics(__LINE__, env, 3, 14, 8, 7, 256);
-
1342  env.close();
-
1343  checkMetrics(__LINE__, env, 0, 16, 3, 8, 256);
-
1344  env.require(balance(bob, drops(499'999'999'750)));
-
1345  }
-
1346 
-
1347  void
-
1348  testTieBreaking()
-
1349  {
-
1350  using namespace jtx;
-
1351  using namespace std::chrono;
-
1352  testcase("tie breaking");
-
1353 
-
1354  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "4"}}));
-
1355 
-
1356  auto alice = Account("alice");
-
1357  auto bob = Account("bob");
-
1358  auto charlie = Account("charlie");
-
1359  auto daria = Account("daria");
-
1360  auto elmo = Account("elmo");
-
1361  auto fred = Account("fred");
-
1362  auto gwen = Account("gwen");
-
1363  auto hank = Account("hank");
-
1364 
-
1365  auto queued = ter(terQUEUED);
-
1366 
-
1367  BEAST_EXPECT(env.current()->fees().base == 10);
-
1368 
-
1369  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 4, 256);
-
1370 
-
1371  // Create several accounts while the fee is cheap so they all apply.
-
1372  env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
-
1373  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 4, 256);
-
1374 
-
1375  env.close();
-
1376  checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
+
1308  // Bob hit the single account limit
+
1309  env(noop(bob), seq(bobSeq + 10), ter(telCAN_NOT_QUEUE_FULL));
+
1310  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
+
1311  // Bob can replace one of the earlier txs regardless
+
1312  // of the limit
+
1313  env(noop(bob), seq(bobSeq + 5), fee(20), queued);
+
1314  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
+
1315 
+
1316  // Try to replace a middle item in the queue
+
1317  // with enough fee to bankrupt bob and make the
+
1318  // later transactions unable to pay their fees
+
1319  std::int64_t bobFee =
+
1320  env.le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10 - 1);
+
1321  env(noop(bob),
+
1322  seq(bobSeq + 5),
+
1323  fee(bobFee),
+
1324  ter(telCAN_NOT_QUEUE_BALANCE));
+
1325  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
+
1326 
+
1327  // Attempt to replace a middle item in the queue with enough fee
+
1328  // to bankrupt bob, and also to use fee averaging to clear out the
+
1329  // first six transactions.
+
1330  //
+
1331  // The attempt fails because the sum of bob's fees now exceeds the
+
1332  // (artificially lowered to 200 drops) account reserve.
+
1333  bobFee =
+
1334  env.le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10);
+
1335  env(noop(bob),
+
1336  seq(bobSeq + 5),
+
1337  fee(bobFee),
+
1338  ter(telCAN_NOT_QUEUE_BALANCE));
+
1339  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
+
1340 
+
1341  // Close the ledger and verify that the queued transactions succeed
+
1342  // and bob has the right ending balance.
+
1343  env.close();
+
1344  checkMetrics(__LINE__, env, 3, 14, 8, 7, 256);
+
1345  env.close();
+
1346  checkMetrics(__LINE__, env, 0, 16, 3, 8, 256);
+
1347  env.require(balance(bob, drops(499'999'999'750)));
+
1348  }
+
1349 
+
1350  void
+
1351  testTieBreaking()
+
1352  {
+
1353  using namespace jtx;
+
1354  using namespace std::chrono;
+
1355  testcase("tie breaking");
+
1356 
+
1357  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "4"}}));
+
1358 
+
1359  auto alice = Account("alice");
+
1360  auto bob = Account("bob");
+
1361  auto charlie = Account("charlie");
+
1362  auto daria = Account("daria");
+
1363  auto elmo = Account("elmo");
+
1364  auto fred = Account("fred");
+
1365  auto gwen = Account("gwen");
+
1366  auto hank = Account("hank");
+
1367 
+
1368  auto queued = ter(terQUEUED);
+
1369 
+
1370  BEAST_EXPECT(env.current()->fees().base == 10);
+
1371 
+
1372  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 4, 256);
+
1373 
+
1374  // Create several accounts while the fee is cheap so they all apply.
+
1375  env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
+
1376  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 4, 256);
1377 
-
1378  env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
-
1379  checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
+
1378  env.close();
+
1379  checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
1380 
-
1381  env.close();
-
1382  checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
+
1381  env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
+
1382  checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
1383 
-
1385 
-
1386  // Stuff the ledger and queue so we can verify that
-
1387  // stuff gets kicked out.
-
1388  env(noop(gwen));
-
1389  env(noop(hank));
-
1390  env(noop(gwen));
-
1391  env(noop(fred));
-
1392  env(noop(elmo));
-
1393  checkMetrics(__LINE__, env, 0, 8, 5, 4, 256);
-
1394 
-
1395  auto aliceSeq = env.seq(alice);
-
1396  auto bobSeq = env.seq(bob);
-
1397  auto charlieSeq = env.seq(charlie);
-
1398  auto dariaSeq = env.seq(daria);
-
1399  auto elmoSeq = env.seq(elmo);
-
1400  auto fredSeq = env.seq(fred);
-
1401  auto gwenSeq = env.seq(gwen);
-
1402  auto hankSeq = env.seq(hank);
-
1403 
-
1404  // This time, use identical fees.
-
1405 
-
1406  // All of these get into the queue, but one gets dropped when the
-
1407  // higher fee one is added later. Which one depends on ordering.
-
1408  env(noop(alice), fee(15), queued);
-
1409  env(noop(bob), fee(15), queued);
-
1410  env(noop(charlie), fee(15), queued);
-
1411  env(noop(daria), fee(15), queued);
-
1412  env(noop(elmo), fee(15), queued);
-
1413  env(noop(fred), fee(15), queued);
-
1414  env(noop(gwen), fee(15), queued);
-
1415  env(noop(hank), fee(15), queued);
-
1416 
-
1417  // Queue is full now. Minimum fee now reflects the
-
1418  // lowest fee in the queue.
-
1419  checkMetrics(__LINE__, env, 8, 8, 5, 4, 385);
-
1420 
-
1421  // Try to add another transaction with the default (low) fee,
-
1422  // it should fail because it can't replace the one already
-
1423  // there.
-
1424  env(noop(charlie), ter(telCAN_NOT_QUEUE_FEE));
-
1425 
-
1426  // Add another transaction, with a higher fee,
-
1427  // Not high enough to get into the ledger, but high
-
1428  // enough to get into the queue (and kick somebody out)
-
1429  env(noop(charlie), fee(100), seq(charlieSeq + 1), queued);
-
1430 
-
1431  // Queue is still full.
-
1432  checkMetrics(__LINE__, env, 8, 8, 5, 4, 385);
+
1384  env.close();
+
1385  checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
+
1386 
+
1388 
+
1389  // Stuff the ledger and queue so we can verify that
+
1390  // stuff gets kicked out.
+
1391  env(noop(gwen));
+
1392  env(noop(hank));
+
1393  env(noop(gwen));
+
1394  env(noop(fred));
+
1395  env(noop(elmo));
+
1396  checkMetrics(__LINE__, env, 0, 8, 5, 4, 256);
+
1397 
+
1398  auto aliceSeq = env.seq(alice);
+
1399  auto bobSeq = env.seq(bob);
+
1400  auto charlieSeq = env.seq(charlie);
+
1401  auto dariaSeq = env.seq(daria);
+
1402  auto elmoSeq = env.seq(elmo);
+
1403  auto fredSeq = env.seq(fred);
+
1404  auto gwenSeq = env.seq(gwen);
+
1405  auto hankSeq = env.seq(hank);
+
1406 
+
1407  // This time, use identical fees.
+
1408 
+
1409  // All of these get into the queue, but one gets dropped when the
+
1410  // higher fee one is added later. Which one depends on ordering.
+
1411  env(noop(alice), fee(15), queued);
+
1412  env(noop(bob), fee(15), queued);
+
1413  env(noop(charlie), fee(15), queued);
+
1414  env(noop(daria), fee(15), queued);
+
1415  env(noop(elmo), fee(15), queued);
+
1416  env(noop(fred), fee(15), queued);
+
1417  env(noop(gwen), fee(15), queued);
+
1418  env(noop(hank), fee(15), queued);
+
1419 
+
1420  // Queue is full now. Minimum fee now reflects the
+
1421  // lowest fee in the queue.
+
1422  checkMetrics(__LINE__, env, 8, 8, 5, 4, 385);
+
1423 
+
1424  // Try to add another transaction with the default (low) fee,
+
1425  // it should fail because it can't replace the one already
+
1426  // there.
+
1427  env(noop(charlie), ter(telCAN_NOT_QUEUE_FEE));
+
1428 
+
1429  // Add another transaction, with a higher fee,
+
1430  // Not high enough to get into the ledger, but high
+
1431  // enough to get into the queue (and kick somebody out)
+
1432  env(noop(charlie), fee(100), seq(charlieSeq + 1), queued);
1433 
-
1434  // Six txs are processed out of the queue into the ledger,
-
1435  // leaving two txs. The dropped tx is retried from localTxs, and
-
1436  // put back into the queue.
-
1437  env.close();
-
1438  checkMetrics(__LINE__, env, 3, 10, 6, 5, 256);
-
1439 
-
1440  // This next test should remain unchanged regardless of
-
1441  // transaction ordering
-
1442  BEAST_EXPECT(
-
1443  aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
-
1444  gwenSeq + hankSeq + 6 ==
-
1445  env.seq(alice) + env.seq(bob) + env.seq(charlie) + env.seq(daria) +
-
1446  env.seq(elmo) + env.seq(fred) + env.seq(gwen) + env.seq(hank));
-
1447  // These tests may change if TxQ ordering is changed
-
1448  using namespace std::string_literals;
-
1449  BEAST_EXPECTS(
-
1450  aliceSeq == env.seq(alice),
-
1451  "alice: "s + std::to_string(aliceSeq) + ", " +
-
1452  std::to_string(env.seq(alice)));
-
1453  BEAST_EXPECTS(
-
1454  bobSeq + 1 == env.seq(bob),
-
1455  "bob: "s + std::to_string(bobSeq) + ", " +
-
1456  std::to_string(env.seq(bob)));
-
1457  BEAST_EXPECTS(
-
1458  charlieSeq + 2 == env.seq(charlie),
-
1459  "charlie: "s + std::to_string(charlieSeq) + ", " +
-
1460  std::to_string(env.seq(charlie)));
-
1461  BEAST_EXPECTS(
-
1462  dariaSeq + 1 == env.seq(daria),
-
1463  "daria: "s + std::to_string(dariaSeq) + ", " +
-
1464  std::to_string(env.seq(daria)));
-
1465  BEAST_EXPECTS(
-
1466  elmoSeq + 1 == env.seq(elmo),
-
1467  "elmo: "s + std::to_string(elmoSeq) + ", " +
-
1468  std::to_string(env.seq(elmo)));
-
1469  BEAST_EXPECTS(
-
1470  fredSeq == env.seq(fred),
-
1471  "fred: "s + std::to_string(fredSeq) + ", " +
-
1472  std::to_string(env.seq(fred)));
-
1473  BEAST_EXPECTS(
-
1474  gwenSeq == env.seq(gwen),
-
1475  "gwen: "s + std::to_string(gwenSeq) + ", " +
-
1476  std::to_string(env.seq(gwen)));
-
1477  BEAST_EXPECTS(
-
1478  hankSeq + 1 == env.seq(hank),
-
1479  "hank: "s + std::to_string(hankSeq) + ", " +
-
1480  std::to_string(env.seq(hank)));
-
1481 
-
1482  // Which sequences get incremented may change if TxQ ordering is
-
1483  // changed
-
1484  //++aliceSeq;
-
1485  ++bobSeq;
-
1486  ++(++charlieSeq);
-
1487  ++dariaSeq;
-
1488  ++elmoSeq;
-
1489  // ++fredSeq;
-
1490  //++gwenSeq;
-
1491  ++hankSeq;
-
1492 
-
1493  auto getTxsQueued = [&]() {
-
1494  auto const txs = env.app().getTxQ().getTxs();
-
1495  std::map<AccountID, std::size_t> result;
-
1496  for (auto const& tx : txs)
-
1497  {
-
1498  ++result[tx.txn->at(sfAccount)];
-
1499  }
-
1500  return result;
-
1501  };
-
1502  auto qTxCount1 = getTxsQueued();
-
1503  BEAST_EXPECT(qTxCount1.size() <= 3);
-
1504 
-
1505  // Fill up the queue again
-
1506  env(noop(alice),
-
1507  seq(aliceSeq + qTxCount1[alice.id()]++),
-
1508  fee(15),
-
1509  queued);
-
1510  env(noop(bob), seq(bobSeq + qTxCount1[bob.id()]++), fee(15), queued);
-
1511  env(noop(charlie),
-
1512  seq(charlieSeq + qTxCount1[charlie.id()]++),
-
1513  fee(15),
-
1514  queued);
-
1515  env(noop(daria),
-
1516  seq(dariaSeq + qTxCount1[daria.id()]++),
-
1517  fee(15),
-
1518  queued);
-
1519  env(noop(elmo), seq(elmoSeq + qTxCount1[elmo.id()]++), fee(15), queued);
-
1520  env(noop(fred), seq(fredSeq + qTxCount1[fred.id()]++), fee(15), queued);
-
1521  env(noop(gwen), seq(gwenSeq + qTxCount1[gwen.id()]++), fee(15), queued);
-
1522  checkMetrics(__LINE__, env, 10, 10, 6, 5, 385);
-
1523 
-
1524  // Add another transaction, with a higher fee,
-
1525  // Not high enough to get into the ledger, but high
-
1526  // enough to get into the queue (and kick somebody out)
-
1527  env(noop(alice),
-
1528  fee(100),
-
1529  seq(aliceSeq + qTxCount1[alice.id()]++),
-
1530  queued);
-
1531 
-
1532  checkMetrics(__LINE__, env, 10, 10, 6, 5, 385);
-
1533 
-
1534  // Seven txs are processed out of the queue, leaving 3. One
-
1535  // dropped tx is retried from localTxs, and put back into the
-
1536  // queue.
-
1537  env.close();
-
1538  checkMetrics(__LINE__, env, 4, 12, 7, 6, 256);
-
1539 
-
1540  // Refresh the queue counts
-
1541  auto qTxCount2 = getTxsQueued();
-
1542  BEAST_EXPECT(qTxCount2.size() <= 4);
-
1543 
-
1544  // This next test should remain unchanged regardless of
-
1545  // transaction ordering
-
1546  BEAST_EXPECT(
-
1547  aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
-
1548  gwenSeq + hankSeq + 7 ==
-
1549  env.seq(alice) + env.seq(bob) + env.seq(charlie) + env.seq(daria) +
-
1550  env.seq(elmo) + env.seq(fred) + env.seq(gwen) + env.seq(hank));
-
1551  // These tests may change if TxQ ordering is changed
-
1552  BEAST_EXPECTS(
-
1553  aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] ==
-
1554  env.seq(alice),
-
1555  "alice: "s + std::to_string(aliceSeq) + ", " +
-
1556  std::to_string(env.seq(alice)));
-
1557  BEAST_EXPECTS(
-
1558  bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.seq(bob),
-
1559  "bob: "s + std::to_string(bobSeq) + ", " +
-
1560  std::to_string(env.seq(bob)));
-
1561  BEAST_EXPECTS(
-
1562  charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] ==
-
1563  env.seq(charlie),
-
1564  "charlie: "s + std::to_string(charlieSeq) + ", " +
-
1565  std::to_string(env.seq(charlie)));
-
1566  BEAST_EXPECTS(
-
1567  dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] ==
-
1568  env.seq(daria),
-
1569  "daria: "s + std::to_string(dariaSeq) + ", " +
-
1570  std::to_string(env.seq(daria)));
-
1571  BEAST_EXPECTS(
-
1572  elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] ==
-
1573  env.seq(elmo),
-
1574  "elmo: "s + std::to_string(elmoSeq) + ", " +
-
1575  std::to_string(env.seq(elmo)));
-
1576  BEAST_EXPECTS(
-
1577  fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] ==
-
1578  env.seq(fred),
-
1579  "fred: "s + std::to_string(fredSeq) + ", " +
-
1580  std::to_string(env.seq(fred)));
-
1581  BEAST_EXPECTS(
-
1582  gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] ==
-
1583  env.seq(gwen),
-
1584  "gwen: "s + std::to_string(gwenSeq) + ", " +
-
1585  std::to_string(env.seq(gwen)));
-
1586  BEAST_EXPECTS(
-
1587  hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] ==
-
1588  env.seq(hank),
-
1589  "hank: "s + std::to_string(hankSeq) + ", " +
-
1590  std::to_string(env.seq(hank)));
-
1591  }
-
1592 
-
1593  void
-
1594  testAcctTxnID()
-
1595  {
-
1596  using namespace jtx;
-
1597  testcase("acct tx id");
-
1598 
-
1599  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "1"}}));
-
1600 
-
1601  auto alice = Account("alice");
-
1602 
-
1603  BEAST_EXPECT(env.current()->fees().base == 10);
-
1604 
-
1605  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 1, 256);
-
1606 
-
1607  env.fund(XRP(50000), noripple(alice));
-
1608  checkMetrics(__LINE__, env, 0, std::nullopt, 1, 1, 256);
+
1434  // Queue is still full.
+
1435  checkMetrics(__LINE__, env, 8, 8, 5, 4, 385);
+
1436 
+
1437  // Six txs are processed out of the queue into the ledger,
+
1438  // leaving two txs. The dropped tx is retried from localTxs, and
+
1439  // put back into the queue.
+
1440  env.close();
+
1441  checkMetrics(__LINE__, env, 3, 10, 6, 5, 256);
+
1442 
+
1443  // This next test should remain unchanged regardless of
+
1444  // transaction ordering
+
1445  BEAST_EXPECT(
+
1446  aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
+
1447  gwenSeq + hankSeq + 6 ==
+
1448  env.seq(alice) + env.seq(bob) + env.seq(charlie) + env.seq(daria) +
+
1449  env.seq(elmo) + env.seq(fred) + env.seq(gwen) + env.seq(hank));
+
1450  // These tests may change if TxQ ordering is changed
+
1451  using namespace std::string_literals;
+
1452  BEAST_EXPECTS(
+
1453  aliceSeq == env.seq(alice),
+
1454  "alice: "s + std::to_string(aliceSeq) + ", " +
+
1455  std::to_string(env.seq(alice)));
+
1456  BEAST_EXPECTS(
+
1457  bobSeq + 1 == env.seq(bob),
+
1458  "bob: "s + std::to_string(bobSeq) + ", " +
+
1459  std::to_string(env.seq(bob)));
+
1460  BEAST_EXPECTS(
+
1461  charlieSeq + 2 == env.seq(charlie),
+
1462  "charlie: "s + std::to_string(charlieSeq) + ", " +
+
1463  std::to_string(env.seq(charlie)));
+
1464  BEAST_EXPECTS(
+
1465  dariaSeq + 1 == env.seq(daria),
+
1466  "daria: "s + std::to_string(dariaSeq) + ", " +
+
1467  std::to_string(env.seq(daria)));
+
1468  BEAST_EXPECTS(
+
1469  elmoSeq + 1 == env.seq(elmo),
+
1470  "elmo: "s + std::to_string(elmoSeq) + ", " +
+
1471  std::to_string(env.seq(elmo)));
+
1472  BEAST_EXPECTS(
+
1473  fredSeq == env.seq(fred),
+
1474  "fred: "s + std::to_string(fredSeq) + ", " +
+
1475  std::to_string(env.seq(fred)));
+
1476  BEAST_EXPECTS(
+
1477  gwenSeq == env.seq(gwen),
+
1478  "gwen: "s + std::to_string(gwenSeq) + ", " +
+
1479  std::to_string(env.seq(gwen)));
+
1480  BEAST_EXPECTS(
+
1481  hankSeq + 1 == env.seq(hank),
+
1482  "hank: "s + std::to_string(hankSeq) + ", " +
+
1483  std::to_string(env.seq(hank)));
+
1484 
+
1485  // Which sequences get incremented may change if TxQ ordering is
+
1486  // changed
+
1487  //++aliceSeq;
+
1488  ++bobSeq;
+
1489  ++(++charlieSeq);
+
1490  ++dariaSeq;
+
1491  ++elmoSeq;
+
1492  // ++fredSeq;
+
1493  //++gwenSeq;
+
1494  ++hankSeq;
+
1495 
+
1496  auto getTxsQueued = [&]() {
+
1497  auto const txs = env.app().getTxQ().getTxs();
+
1498  std::map<AccountID, std::size_t> result;
+
1499  for (auto const& tx : txs)
+
1500  {
+
1501  ++result[tx.txn->at(sfAccount)];
+
1502  }
+
1503  return result;
+
1504  };
+
1505  auto qTxCount1 = getTxsQueued();
+
1506  BEAST_EXPECT(qTxCount1.size() <= 3);
+
1507 
+
1508  // Fill up the queue again
+
1509  env(noop(alice),
+
1510  seq(aliceSeq + qTxCount1[alice.id()]++),
+
1511  fee(15),
+
1512  queued);
+
1513  env(noop(bob), seq(bobSeq + qTxCount1[bob.id()]++), fee(15), queued);
+
1514  env(noop(charlie),
+
1515  seq(charlieSeq + qTxCount1[charlie.id()]++),
+
1516  fee(15),
+
1517  queued);
+
1518  env(noop(daria),
+
1519  seq(dariaSeq + qTxCount1[daria.id()]++),
+
1520  fee(15),
+
1521  queued);
+
1522  env(noop(elmo), seq(elmoSeq + qTxCount1[elmo.id()]++), fee(15), queued);
+
1523  env(noop(fred), seq(fredSeq + qTxCount1[fred.id()]++), fee(15), queued);
+
1524  env(noop(gwen), seq(gwenSeq + qTxCount1[gwen.id()]++), fee(15), queued);
+
1525  checkMetrics(__LINE__, env, 10, 10, 6, 5, 385);
+
1526 
+
1527  // Add another transaction, with a higher fee,
+
1528  // Not high enough to get into the ledger, but high
+
1529  // enough to get into the queue (and kick somebody out)
+
1530  env(noop(alice),
+
1531  fee(100),
+
1532  seq(aliceSeq + qTxCount1[alice.id()]++),
+
1533  queued);
+
1534 
+
1535  checkMetrics(__LINE__, env, 10, 10, 6, 5, 385);
+
1536 
+
1537  // Seven txs are processed out of the queue, leaving 3. One
+
1538  // dropped tx is retried from localTxs, and put back into the
+
1539  // queue.
+
1540  env.close();
+
1541  checkMetrics(__LINE__, env, 4, 12, 7, 6, 256);
+
1542 
+
1543  // Refresh the queue counts
+
1544  auto qTxCount2 = getTxsQueued();
+
1545  BEAST_EXPECT(qTxCount2.size() <= 4);
+
1546 
+
1547  // This next test should remain unchanged regardless of
+
1548  // transaction ordering
+
1549  BEAST_EXPECT(
+
1550  aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
+
1551  gwenSeq + hankSeq + 7 ==
+
1552  env.seq(alice) + env.seq(bob) + env.seq(charlie) + env.seq(daria) +
+
1553  env.seq(elmo) + env.seq(fred) + env.seq(gwen) + env.seq(hank));
+
1554  // These tests may change if TxQ ordering is changed
+
1555  BEAST_EXPECTS(
+
1556  aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] ==
+
1557  env.seq(alice),
+
1558  "alice: "s + std::to_string(aliceSeq) + ", " +
+
1559  std::to_string(env.seq(alice)));
+
1560  BEAST_EXPECTS(
+
1561  bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.seq(bob),
+
1562  "bob: "s + std::to_string(bobSeq) + ", " +
+
1563  std::to_string(env.seq(bob)));
+
1564  BEAST_EXPECTS(
+
1565  charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] ==
+
1566  env.seq(charlie),
+
1567  "charlie: "s + std::to_string(charlieSeq) + ", " +
+
1568  std::to_string(env.seq(charlie)));
+
1569  BEAST_EXPECTS(
+
1570  dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] ==
+
1571  env.seq(daria),
+
1572  "daria: "s + std::to_string(dariaSeq) + ", " +
+
1573  std::to_string(env.seq(daria)));
+
1574  BEAST_EXPECTS(
+
1575  elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] ==
+
1576  env.seq(elmo),
+
1577  "elmo: "s + std::to_string(elmoSeq) + ", " +
+
1578  std::to_string(env.seq(elmo)));
+
1579  BEAST_EXPECTS(
+
1580  fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] ==
+
1581  env.seq(fred),
+
1582  "fred: "s + std::to_string(fredSeq) + ", " +
+
1583  std::to_string(env.seq(fred)));
+
1584  BEAST_EXPECTS(
+
1585  gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] ==
+
1586  env.seq(gwen),
+
1587  "gwen: "s + std::to_string(gwenSeq) + ", " +
+
1588  std::to_string(env.seq(gwen)));
+
1589  BEAST_EXPECTS(
+
1590  hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] ==
+
1591  env.seq(hank),
+
1592  "hank: "s + std::to_string(hankSeq) + ", " +
+
1593  std::to_string(env.seq(hank)));
+
1594  }
+
1595 
+
1596  void
+
1597  testAcctTxnID()
+
1598  {
+
1599  using namespace jtx;
+
1600  testcase("acct tx id");
+
1601 
+
1602  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "1"}}));
+
1603 
+
1604  auto alice = Account("alice");
+
1605 
+
1606  BEAST_EXPECT(env.current()->fees().base == 10);
+
1607 
+
1608  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 1, 256);
1609 
-
1610  env(fset(alice, asfAccountTxnID));
-
1611  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
+
1610  env.fund(XRP(50000), noripple(alice));
+
1611  checkMetrics(__LINE__, env, 0, std::nullopt, 1, 1, 256);
1612 
-
1613  // Immediately after the fset, the sfAccountTxnID field
-
1614  // is still uninitialized, so preflight succeeds here,
-
1615  // and this txn fails because it can't be stored in the queue.
-
1616  env(noop(alice),
-
1617  json(R"({"AccountTxnID": "0"})"),
-
1618  ter(telCAN_NOT_QUEUE));
-
1619 
-
1620  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
-
1621  env.close();
-
1622  // The failed transaction is retried from LocalTx
-
1623  // and succeeds.
-
1624  checkMetrics(__LINE__, env, 0, 4, 1, 2, 256);
-
1625 
-
1626  env(noop(alice));
-
1627  checkMetrics(__LINE__, env, 0, 4, 2, 2, 256);
+
1613  env(fset(alice, asfAccountTxnID));
+
1614  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
+
1615 
+
1616  // Immediately after the fset, the sfAccountTxnID field
+
1617  // is still uninitialized, so preflight succeeds here,
+
1618  // and this txn fails because it can't be stored in the queue.
+
1619  env(noop(alice),
+
1620  json(R"({"AccountTxnID": "0"})"),
+
1621  ter(telCAN_NOT_QUEUE));
+
1622 
+
1623  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
+
1624  env.close();
+
1625  // The failed transaction is retried from LocalTx
+
1626  // and succeeds.
+
1627  checkMetrics(__LINE__, env, 0, 4, 1, 2, 256);
1628 
-
1629  env(noop(alice), json(R"({"AccountTxnID": "0"})"), ter(tefWRONG_PRIOR));
-
1630  }
-
1631 
-
1632  void
-
1633  testMaximum()
-
1634  {
-
1635  using namespace jtx;
-
1636  using namespace std::string_literals;
-
1637  testcase("maximum tx");
-
1638 
-
1639  {
-
1640  Env env(
-
1641  *this,
-
1642  makeConfig(
-
1643  {{"minimum_txn_in_ledger_standalone", "2"},
-
1644  {"minimum_txn_in_ledger", "5"},
-
1645  {"target_txn_in_ledger", "4"},
-
1646  {"maximum_txn_in_ledger", "5"}}));
-
1647 
-
1648  auto alice = Account("alice");
-
1649 
-
1650  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
-
1651 
-
1652  env.fund(XRP(50000), noripple(alice));
-
1653  checkMetrics(__LINE__, env, 0, std::nullopt, 1, 2, 256);
+
1629  env(noop(alice));
+
1630  checkMetrics(__LINE__, env, 0, 4, 2, 2, 256);
+
1631 
+
1632  env(noop(alice), json(R"({"AccountTxnID": "0"})"), ter(tefWRONG_PRIOR));
+
1633  }
+
1634 
+
1635  void
+
1636  testMaximum()
+
1637  {
+
1638  using namespace jtx;
+
1639  using namespace std::string_literals;
+
1640  testcase("maximum tx");
+
1641 
+
1642  {
+
1643  Env env(
+
1644  *this,
+
1645  makeConfig(
+
1646  {{"minimum_txn_in_ledger_standalone", "2"},
+
1647  {"minimum_txn_in_ledger", "5"},
+
1648  {"target_txn_in_ledger", "4"},
+
1649  {"maximum_txn_in_ledger", "5"}}));
+
1650 
+
1651  auto alice = Account("alice");
+
1652 
+
1653  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1654 
-
1655  for (int i = 0; i < 10; ++i)
-
1656  env(noop(alice), openLedgerFee(env));
+
1655  env.fund(XRP(50000), noripple(alice));
+
1656  checkMetrics(__LINE__, env, 0, std::nullopt, 1, 2, 256);
1657 
-
1658  checkMetrics(__LINE__, env, 0, std::nullopt, 11, 2, 256);
-
1659 
-
1660  env.close();
-
1661  // If not for the maximum, the per ledger would be 11.
-
1662  checkMetrics(__LINE__, env, 0, 10, 0, 5, 256, 800025);
-
1663  }
-
1664 
-
1665  try
-
1666  {
-
1667  Env env(
-
1668  *this,
-
1669  makeConfig(
-
1670  {{"minimum_txn_in_ledger", "200"},
-
1671  {"minimum_txn_in_ledger_standalone", "200"},
-
1672  {"target_txn_in_ledger", "4"},
-
1673  {"maximum_txn_in_ledger", "5"}}));
-
1674  // should throw
-
1675  fail();
-
1676  }
-
1677  catch (std::runtime_error const& e)
-
1678  {
-
1679  BEAST_EXPECT(
-
1680  e.what() ==
-
1681  "The minimum number of low-fee transactions allowed "
-
1682  "per ledger (minimum_txn_in_ledger) exceeds "
-
1683  "the maximum number of low-fee transactions allowed per "
-
1684  "ledger (maximum_txn_in_ledger)."s);
-
1685  }
-
1686  try
-
1687  {
-
1688  Env env(
-
1689  *this,
-
1690  makeConfig(
-
1691  {{"minimum_txn_in_ledger", "200"},
-
1692  {"minimum_txn_in_ledger_standalone", "2"},
-
1693  {"target_txn_in_ledger", "4"},
-
1694  {"maximum_txn_in_ledger", "5"}}));
-
1695  // should throw
-
1696  fail();
-
1697  }
-
1698  catch (std::runtime_error const& e)
-
1699  {
-
1700  BEAST_EXPECT(
-
1701  e.what() ==
-
1702  "The minimum number of low-fee transactions allowed "
-
1703  "per ledger (minimum_txn_in_ledger) exceeds "
-
1704  "the maximum number of low-fee transactions allowed per "
-
1705  "ledger (maximum_txn_in_ledger)."s);
-
1706  }
-
1707  try
-
1708  {
-
1709  Env env(
-
1710  *this,
-
1711  makeConfig(
-
1712  {{"minimum_txn_in_ledger", "2"},
-
1713  {"minimum_txn_in_ledger_standalone", "200"},
-
1714  {"target_txn_in_ledger", "4"},
-
1715  {"maximum_txn_in_ledger", "5"}}));
-
1716  // should throw
-
1717  fail();
-
1718  }
-
1719  catch (std::runtime_error const& e)
-
1720  {
-
1721  BEAST_EXPECT(
-
1722  e.what() ==
-
1723  "The minimum number of low-fee transactions allowed "
-
1724  "per ledger (minimum_txn_in_ledger_standalone) exceeds "
-
1725  "the maximum number of low-fee transactions allowed per "
-
1726  "ledger (maximum_txn_in_ledger)."s);
-
1727  }
-
1728  }
-
1729 
-
1730  void
-
1731  testUnexpectedBalanceChange()
-
1732  {
-
1733  using namespace jtx;
-
1734  testcase("unexpected balance change");
-
1735 
-
1736  Env env(
-
1737  *this,
-
1738  makeConfig(
-
1739  {{"minimum_txn_in_ledger_standalone", "3"}},
-
1740  {{"account_reserve", "200"}, {"owner_reserve", "50"}}));
-
1741 
-
1742  auto alice = Account("alice");
-
1743  auto bob = Account("bob");
+
1658  for (int i = 0; i < 10; ++i)
+
1659  env(noop(alice), openLedgerFee(env));
+
1660 
+
1661  checkMetrics(__LINE__, env, 0, std::nullopt, 11, 2, 256);
+
1662 
+
1663  env.close();
+
1664  // If not for the maximum, the per ledger would be 11.
+
1665  checkMetrics(__LINE__, env, 0, 10, 0, 5, 256, 800025);
+
1666  }
+
1667 
+
1668  try
+
1669  {
+
1670  Env env(
+
1671  *this,
+
1672  makeConfig(
+
1673  {{"minimum_txn_in_ledger", "200"},
+
1674  {"minimum_txn_in_ledger_standalone", "200"},
+
1675  {"target_txn_in_ledger", "4"},
+
1676  {"maximum_txn_in_ledger", "5"}}));
+
1677  // should throw
+
1678  fail();
+
1679  }
+
1680  catch (std::runtime_error const& e)
+
1681  {
+
1682  BEAST_EXPECT(
+
1683  e.what() ==
+
1684  "The minimum number of low-fee transactions allowed "
+
1685  "per ledger (minimum_txn_in_ledger) exceeds "
+
1686  "the maximum number of low-fee transactions allowed per "
+
1687  "ledger (maximum_txn_in_ledger)."s);
+
1688  }
+
1689  try
+
1690  {
+
1691  Env env(
+
1692  *this,
+
1693  makeConfig(
+
1694  {{"minimum_txn_in_ledger", "200"},
+
1695  {"minimum_txn_in_ledger_standalone", "2"},
+
1696  {"target_txn_in_ledger", "4"},
+
1697  {"maximum_txn_in_ledger", "5"}}));
+
1698  // should throw
+
1699  fail();
+
1700  }
+
1701  catch (std::runtime_error const& e)
+
1702  {
+
1703  BEAST_EXPECT(
+
1704  e.what() ==
+
1705  "The minimum number of low-fee transactions allowed "
+
1706  "per ledger (minimum_txn_in_ledger) exceeds "
+
1707  "the maximum number of low-fee transactions allowed per "
+
1708  "ledger (maximum_txn_in_ledger)."s);
+
1709  }
+
1710  try
+
1711  {
+
1712  Env env(
+
1713  *this,
+
1714  makeConfig(
+
1715  {{"minimum_txn_in_ledger", "2"},
+
1716  {"minimum_txn_in_ledger_standalone", "200"},
+
1717  {"target_txn_in_ledger", "4"},
+
1718  {"maximum_txn_in_ledger", "5"}}));
+
1719  // should throw
+
1720  fail();
+
1721  }
+
1722  catch (std::runtime_error const& e)
+
1723  {
+
1724  BEAST_EXPECT(
+
1725  e.what() ==
+
1726  "The minimum number of low-fee transactions allowed "
+
1727  "per ledger (minimum_txn_in_ledger_standalone) exceeds "
+
1728  "the maximum number of low-fee transactions allowed per "
+
1729  "ledger (maximum_txn_in_ledger)."s);
+
1730  }
+
1731  }
+
1732 
+
1733  void
+
1734  testUnexpectedBalanceChange()
+
1735  {
+
1736  using namespace jtx;
+
1737  testcase("unexpected balance change");
+
1738 
+
1739  Env env(
+
1740  *this,
+
1741  makeConfig(
+
1742  {{"minimum_txn_in_ledger_standalone", "3"}},
+
1743  {{"account_reserve", "200"}, {"owner_reserve", "50"}}));
1744 
-
1745  auto queued = ter(terQUEUED);
-
1746 
-
1747  // ledgers in queue is 2 because of makeConfig
-
1748  auto const initQueueMax = initFee(env, 3, 2, 10, 200, 50);
+
1745  auto alice = Account("alice");
+
1746  auto bob = Account("bob");
+
1747 
+
1748  auto queued = ter(terQUEUED);
1749 
-
1750  BEAST_EXPECT(env.current()->fees().base == 10);
-
1751 
-
1752  checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
-
1753 
-
1754  env.fund(drops(5000), noripple(alice));
-
1755  env.fund(XRP(50000), noripple(bob));
-
1756  checkMetrics(__LINE__, env, 0, initQueueMax, 2, 3, 256);
-
1757  auto USD = bob["USD"];
-
1758 
-
1759  env(offer(alice, USD(5000), drops(5000)), require(owners(alice, 1)));
-
1760  checkMetrics(__LINE__, env, 0, initQueueMax, 3, 3, 256);
+
1750  // ledgers in queue is 2 because of makeConfig
+
1751  auto const initQueueMax = initFee(env, 3, 2, 10, 200, 50);
+
1752 
+
1753  BEAST_EXPECT(env.current()->fees().base == 10);
+
1754 
+
1755  checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
+
1756 
+
1757  env.fund(drops(5000), noripple(alice));
+
1758  env.fund(XRP(50000), noripple(bob));
+
1759  checkMetrics(__LINE__, env, 0, initQueueMax, 2, 3, 256);
+
1760  auto USD = bob["USD"];
1761 
-
1762  env.close();
-
1763  checkMetrics(__LINE__, env, 0, 6, 0, 3, 256);
+
1762  env(offer(alice, USD(5000), drops(5000)), require(owners(alice, 1)));
+
1763  checkMetrics(__LINE__, env, 0, initQueueMax, 3, 3, 256);
1764 
-
1765  // Fill up the ledger
-
1766  fillQueue(env, alice);
-
1767  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
-
1768 
-
1769  // Queue up a couple of transactions, plus one
-
1770  // more expensive one.
-
1771  auto aliceSeq = env.seq(alice);
-
1772  env(noop(alice), seq(aliceSeq++), queued);
-
1773  env(noop(alice), seq(aliceSeq++), queued);
-
1774  env(noop(alice), seq(aliceSeq++), queued);
-
1775  env(noop(alice), fee(drops(1000)), seq(aliceSeq), queued);
-
1776  checkMetrics(__LINE__, env, 4, 6, 4, 3, 256);
-
1777 
-
1778  // This offer should take Alice's offer
-
1779  // up to Alice's reserve.
-
1780  env(offer(bob, drops(5000), USD(5000)),
-
1781  openLedgerFee(env),
-
1782  require(
-
1783  balance(alice, drops(250)), owners(alice, 1), lines(alice, 1)));
-
1784  checkMetrics(__LINE__, env, 4, 6, 5, 3, 256);
-
1785 
-
1786  // Try adding a new transaction.
-
1787  // Too many fees in flight.
-
1788  env(noop(alice),
-
1789  fee(drops(200)),
-
1790  seq(aliceSeq + 1),
-
1791  ter(telCAN_NOT_QUEUE_BALANCE));
-
1792  checkMetrics(__LINE__, env, 4, 6, 5, 3, 256);
-
1793 
-
1794  // Close the ledger. All of Alice's transactions
-
1795  // take a fee, except the last one.
-
1796  env.close();
-
1797  checkMetrics(__LINE__, env, 1, 10, 3, 5, 256);
-
1798  env.require(balance(alice, drops(250 - 30)));
-
1799 
-
1800  // Still can't add a new transaction for Alice,
-
1801  // no matter the fee.
-
1802  env(noop(alice),
-
1803  fee(drops(200)),
-
1804  seq(aliceSeq + 1),
-
1805  ter(telCAN_NOT_QUEUE_BALANCE));
-
1806  checkMetrics(__LINE__, env, 1, 10, 3, 5, 256);
-
1807 
-
1808  /* At this point, Alice's transaction is indefinitely
-
1809  stuck in the queue. Eventually it will either
-
1810  expire, get forced off the end by more valuable
-
1811  transactions, get replaced by Alice, or Alice
-
1812  will get more XRP, and it'll process.
-
1813  */
-
1814 
-
1815  for (int i = 0; i < 9; ++i)
-
1816  {
-
1817  env.close();
-
1818  checkMetrics(__LINE__, env, 1, 10, 0, 5, 256);
-
1819  }
-
1820 
-
1821  // And Alice's transaction expires (via the retry limit,
-
1822  // not LastLedgerSequence).
-
1823  env.close();
-
1824  checkMetrics(__LINE__, env, 0, 10, 0, 5, 256);
-
1825  }
-
1826 
-
1827  void
-
1828  testBlockersSeq()
-
1829  {
-
1830  using namespace jtx;
-
1831  testcase("blockers sequence");
-
1832 
-
1833  auto alice = Account("alice");
-
1834  auto bob = Account("bob");
-
1835  auto charlie = Account("charlie");
-
1836  auto daria = Account("daria");
-
1837 
-
1838  auto queued = ter(terQUEUED);
-
1839 
-
1840  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
-
1841 
-
1842  BEAST_EXPECT(env.current()->fees().base == 10);
-
1843 
-
1844  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
-
1845 
-
1846  env.fund(XRP(50000), noripple(alice, bob));
-
1847  env.memoize(charlie);
-
1848  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
-
1849  {
-
1850  // Cannot put a blocker in an account's queue if that queue
-
1851  // already holds two or more (non-blocker) entries.
-
1852 
-
1853  // Fill up the open ledger
-
1854  env(noop(alice));
-
1855  // Set a regular key just to clear the password spent flag
-
1856  env(regkey(alice, charlie));
-
1857  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
-
1858 
-
1859  // Put two "normal" txs in the queue
-
1860  auto const aliceSeq = env.seq(alice);
-
1861  env(noop(alice), seq(aliceSeq + 0), queued);
-
1862  env(noop(alice), seq(aliceSeq + 1), queued);
-
1863 
-
1864  // Can't replace either queued transaction with a blocker
-
1865  env(fset(alice, asfAccountTxnID),
-
1866  seq(aliceSeq + 0),
-
1867  fee(20),
-
1868  ter(telCAN_NOT_QUEUE_BLOCKS));
-
1869 
-
1870  env(regkey(alice, bob),
-
1871  seq(aliceSeq + 1),
-
1872  fee(20),
-
1873  ter(telCAN_NOT_QUEUE_BLOCKS));
-
1874 
-
1875  // Can't append a blocker to the queue.
-
1876  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
-
1877  seq(aliceSeq + 2),
-
1878  fee(20),
-
1879  ter(telCAN_NOT_QUEUE_BLOCKS));
-
1880 
-
1881  // Other accounts are not affected
-
1882  env(noop(bob), queued);
-
1883  checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
-
1884 
-
1885  // Drain the queue.
-
1886  env.close();
-
1887  checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
-
1888  }
-
1889  {
-
1890  // Replace a lone non-blocking tx with a blocker.
-
1891 
-
1892  // Fill up the open ledger and put just one entry in the TxQ.
-
1893  env(noop(alice));
+
1765  env.close();
+
1766  checkMetrics(__LINE__, env, 0, 6, 0, 3, 256);
+
1767 
+
1768  // Fill up the ledger
+
1769  fillQueue(env, alice);
+
1770  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
+
1771 
+
1772  // Queue up a couple of transactions, plus one
+
1773  // more expensive one.
+
1774  auto aliceSeq = env.seq(alice);
+
1775  env(noop(alice), seq(aliceSeq++), queued);
+
1776  env(noop(alice), seq(aliceSeq++), queued);
+
1777  env(noop(alice), seq(aliceSeq++), queued);
+
1778  env(noop(alice), fee(drops(1000)), seq(aliceSeq), queued);
+
1779  checkMetrics(__LINE__, env, 4, 6, 4, 3, 256);
+
1780 
+
1781  // This offer should take Alice's offer
+
1782  // up to Alice's reserve.
+
1783  env(offer(bob, drops(5000), USD(5000)),
+
1784  openLedgerFee(env),
+
1785  require(
+
1786  balance(alice, drops(250)), owners(alice, 1), lines(alice, 1)));
+
1787  checkMetrics(__LINE__, env, 4, 6, 5, 3, 256);
+
1788 
+
1789  // Try adding a new transaction.
+
1790  // Too many fees in flight.
+
1791  env(noop(alice),
+
1792  fee(drops(200)),
+
1793  seq(aliceSeq + 1),
+
1794  ter(telCAN_NOT_QUEUE_BALANCE));
+
1795  checkMetrics(__LINE__, env, 4, 6, 5, 3, 256);
+
1796 
+
1797  // Close the ledger. All of Alice's transactions
+
1798  // take a fee, except the last one.
+
1799  env.close();
+
1800  checkMetrics(__LINE__, env, 1, 10, 3, 5, 256);
+
1801  env.require(balance(alice, drops(250 - 30)));
+
1802 
+
1803  // Still can't add a new transaction for Alice,
+
1804  // no matter the fee.
+
1805  env(noop(alice),
+
1806  fee(drops(200)),
+
1807  seq(aliceSeq + 1),
+
1808  ter(telCAN_NOT_QUEUE_BALANCE));
+
1809  checkMetrics(__LINE__, env, 1, 10, 3, 5, 256);
+
1810 
+
1811  /* At this point, Alice's transaction is indefinitely
+
1812  stuck in the queue. Eventually it will either
+
1813  expire, get forced off the end by more valuable
+
1814  transactions, get replaced by Alice, or Alice
+
1815  will get more XRP, and it'll process.
+
1816  */
+
1817 
+
1818  for (int i = 0; i < 9; ++i)
+
1819  {
+
1820  env.close();
+
1821  checkMetrics(__LINE__, env, 1, 10, 0, 5, 256);
+
1822  }
+
1823 
+
1824  // And Alice's transaction expires (via the retry limit,
+
1825  // not LastLedgerSequence).
+
1826  env.close();
+
1827  checkMetrics(__LINE__, env, 0, 10, 0, 5, 256);
+
1828  }
+
1829 
+
1830  void
+
1831  testBlockersSeq()
+
1832  {
+
1833  using namespace jtx;
+
1834  testcase("blockers sequence");
+
1835 
+
1836  auto alice = Account("alice");
+
1837  auto bob = Account("bob");
+
1838  auto charlie = Account("charlie");
+
1839  auto daria = Account("daria");
+
1840 
+
1841  auto queued = ter(terQUEUED);
+
1842 
+
1843  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
+
1844 
+
1845  BEAST_EXPECT(env.current()->fees().base == 10);
+
1846 
+
1847  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
+
1848 
+
1849  env.fund(XRP(50000), noripple(alice, bob));
+
1850  env.memoize(charlie);
+
1851  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
+
1852  {
+
1853  // Cannot put a blocker in an account's queue if that queue
+
1854  // already holds two or more (non-blocker) entries.
+
1855 
+
1856  // Fill up the open ledger
+
1857  env(noop(alice));
+
1858  // Set a regular key just to clear the password spent flag
+
1859  env(regkey(alice, charlie));
+
1860  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
+
1861 
+
1862  // Put two "normal" txs in the queue
+
1863  auto const aliceSeq = env.seq(alice);
+
1864  env(noop(alice), seq(aliceSeq + 0), queued);
+
1865  env(noop(alice), seq(aliceSeq + 1), queued);
+
1866 
+
1867  // Can't replace either queued transaction with a blocker
+
1868  env(fset(alice, asfAccountTxnID),
+
1869  seq(aliceSeq + 0),
+
1870  fee(20),
+
1871  ter(telCAN_NOT_QUEUE_BLOCKS));
+
1872 
+
1873  env(regkey(alice, bob),
+
1874  seq(aliceSeq + 1),
+
1875  fee(20),
+
1876  ter(telCAN_NOT_QUEUE_BLOCKS));
+
1877 
+
1878  // Can't append a blocker to the queue.
+
1879  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
+
1880  seq(aliceSeq + 2),
+
1881  fee(20),
+
1882  ter(telCAN_NOT_QUEUE_BLOCKS));
+
1883 
+
1884  // Other accounts are not affected
+
1885  env(noop(bob), queued);
+
1886  checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
+
1887 
+
1888  // Drain the queue.
+
1889  env.close();
+
1890  checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
+
1891  }
+
1892  {
+
1893  // Replace a lone non-blocking tx with a blocker.
1894 
-
1895  auto const aliceSeq = env.seq(alice);
-
1896  env(noop(alice), seq(aliceSeq + 0), queued);
+
1895  // Fill up the open ledger and put just one entry in the TxQ.
+
1896  env(noop(alice));
1897 
-
1898  // Since there's only one entry in the queue we can replace
-
1899  // that entry with a blocker.
-
1900  env(regkey(alice, bob), seq(aliceSeq + 0), fee(20), queued);
-
1901 
-
1902  // Now that there's a blocker in the queue we can't append to
-
1903  // the queue.
-
1904  env(noop(alice), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BLOCKED));
-
1905 
-
1906  // Other accounts are unaffected.
-
1907  env(noop(bob), queued);
+
1898  auto const aliceSeq = env.seq(alice);
+
1899  env(noop(alice), seq(aliceSeq + 0), queued);
+
1900 
+
1901  // Since there's only one entry in the queue we can replace
+
1902  // that entry with a blocker.
+
1903  env(regkey(alice, bob), seq(aliceSeq + 0), fee(20), queued);
+
1904 
+
1905  // Now that there's a blocker in the queue we can't append to
+
1906  // the queue.
+
1907  env(noop(alice), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BLOCKED));
1908 
-
1909  // We can replace the blocker with a different blocker.
-
1910  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
-
1911  seq(aliceSeq + 0),
-
1912  fee(26),
-
1913  queued);
-
1914 
-
1915  // Prove that the queue is still blocked.
-
1916  env(noop(alice), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BLOCKED));
+
1909  // Other accounts are unaffected.
+
1910  env(noop(bob), queued);
+
1911 
+
1912  // We can replace the blocker with a different blocker.
+
1913  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
+
1914  seq(aliceSeq + 0),
+
1915  fee(26),
+
1916  queued);
1917 
-
1918  // We can replace the blocker with a non-blocker. Then we can
-
1919  // successfully append to the queue.
-
1920  env(noop(alice), seq(aliceSeq + 0), fee(33), queued);
-
1921  env(noop(alice), seq(aliceSeq + 1), queued);
-
1922 
-
1923  // Drain the queue.
-
1924  env.close();
-
1925  checkMetrics(__LINE__, env, 0, 10, 3, 5, 256);
-
1926  }
-
1927  {
-
1928  // Put a blocker in an empty queue.
-
1929 
-
1930  // Fill up the open ledger and put a blocker as Alice's first
-
1931  // entry in the (empty) TxQ.
-
1932  env(noop(alice));
-
1933  env(noop(alice));
-
1934  env(noop(alice));
-
1935 
-
1936  auto const aliceSeq = env.seq(alice);
-
1937  env(fset(alice, asfAccountTxnID), seq(aliceSeq + 0), queued);
+
1918  // Prove that the queue is still blocked.
+
1919  env(noop(alice), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BLOCKED));
+
1920 
+
1921  // We can replace the blocker with a non-blocker. Then we can
+
1922  // successfully append to the queue.
+
1923  env(noop(alice), seq(aliceSeq + 0), fee(33), queued);
+
1924  env(noop(alice), seq(aliceSeq + 1), queued);
+
1925 
+
1926  // Drain the queue.
+
1927  env.close();
+
1928  checkMetrics(__LINE__, env, 0, 10, 3, 5, 256);
+
1929  }
+
1930  {
+
1931  // Put a blocker in an empty queue.
+
1932 
+
1933  // Fill up the open ledger and put a blocker as Alice's first
+
1934  // entry in the (empty) TxQ.
+
1935  env(noop(alice));
+
1936  env(noop(alice));
+
1937  env(noop(alice));
1938 
-
1939  // Since there's a blocker in the queue we can't append to
-
1940  // the queue.
-
1941  env(noop(alice), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BLOCKED));
-
1942 
-
1943  // Other accounts are unaffected.
-
1944  env(noop(bob), queued);
+
1939  auto const aliceSeq = env.seq(alice);
+
1940  env(fset(alice, asfAccountTxnID), seq(aliceSeq + 0), queued);
+
1941 
+
1942  // Since there's a blocker in the queue we can't append to
+
1943  // the queue.
+
1944  env(noop(alice), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BLOCKED));
1945 
-
1946  // We can replace the blocker with a non-blocker. Then we can
-
1947  // successfully append to the queue.
-
1948  env(noop(alice), seq(aliceSeq + 0), fee(20), queued);
-
1949  env(noop(alice), seq(aliceSeq + 1), queued);
-
1950 
-
1951  // Drain the queue.
-
1952  env.close();
-
1953  checkMetrics(__LINE__, env, 0, 12, 3, 6, 256);
-
1954  }
-
1955  }
-
1956 
-
1957  void
-
1958  testBlockersTicket()
-
1959  {
-
1960  using namespace jtx;
-
1961  testcase("blockers ticket");
-
1962 
-
1963  auto alice = Account("alice");
-
1964  auto bob = Account("bob");
-
1965  auto charlie = Account("charlie");
-
1966  auto daria = Account("daria");
-
1967 
-
1968  auto queued = ter(terQUEUED);
-
1969 
-
1970  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
-
1971 
-
1972  BEAST_EXPECT(env.current()->fees().base == 10);
-
1973 
-
1974  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
-
1975 
-
1976  env.fund(XRP(50000), noripple(alice, bob));
-
1977  env.memoize(charlie);
+
1946  // Other accounts are unaffected.
+
1947  env(noop(bob), queued);
+
1948 
+
1949  // We can replace the blocker with a non-blocker. Then we can
+
1950  // successfully append to the queue.
+
1951  env(noop(alice), seq(aliceSeq + 0), fee(20), queued);
+
1952  env(noop(alice), seq(aliceSeq + 1), queued);
+
1953 
+
1954  // Drain the queue.
+
1955  env.close();
+
1956  checkMetrics(__LINE__, env, 0, 12, 3, 6, 256);
+
1957  }
+
1958  }
+
1959 
+
1960  void
+
1961  testBlockersTicket()
+
1962  {
+
1963  using namespace jtx;
+
1964  testcase("blockers ticket");
+
1965 
+
1966  auto alice = Account("alice");
+
1967  auto bob = Account("bob");
+
1968  auto charlie = Account("charlie");
+
1969  auto daria = Account("daria");
+
1970 
+
1971  auto queued = ter(terQUEUED);
+
1972 
+
1973  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
+
1974 
+
1975  BEAST_EXPECT(env.current()->fees().base == 10);
+
1976 
+
1977  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1978 
-
1979  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
-
1980 
-
1981  std::uint32_t tkt{env.seq(alice) + 1};
-
1982  {
-
1983  // Cannot put a blocker in an account's queue if that queue
-
1984  // already holds two or more (non-blocker) entries.
-
1985 
-
1986  // Fill up the open ledger
-
1987  env(ticket::create(alice, 250), seq(tkt - 1));
-
1988  // Set a regular key just to clear the password spent flag
-
1989  env(regkey(alice, charlie));
-
1990  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
-
1991 
-
1992  // Put two "normal" txs in the queue
-
1993  auto const aliceSeq = env.seq(alice);
-
1994  env(noop(alice), ticket::use(tkt + 2), queued);
-
1995  env(noop(alice), ticket::use(tkt + 1), queued);
-
1996 
-
1997  // Can't replace either queued transaction with a blocker
-
1998  env(fset(alice, asfAccountTxnID),
-
1999  ticket::use(tkt + 1),
-
2000  fee(20),
-
2001  ter(telCAN_NOT_QUEUE_BLOCKS));
-
2002 
-
2003  env(regkey(alice, bob),
-
2004  ticket::use(tkt + 2),
-
2005  fee(20),
-
2006  ter(telCAN_NOT_QUEUE_BLOCKS));
-
2007 
-
2008  // Can't append a blocker to the queue.
-
2009  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
-
2010  fee(20),
-
2011  ter(telCAN_NOT_QUEUE_BLOCKS));
-
2012 
-
2013  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
-
2014  ticket::use(tkt + 0),
-
2015  fee(20),
-
2016  ter(telCAN_NOT_QUEUE_BLOCKS));
-
2017 
-
2018  // Other accounts are not affected
-
2019  env(noop(bob), queued);
-
2020  checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
-
2021 
-
2022  // Drain the queue and local transactions.
-
2023  env.close();
-
2024  checkMetrics(__LINE__, env, 0, 8, 5, 4, 256);
-
2025 
-
2026  // Show that the local transactions have flushed through as well.
-
2027  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
-
2028  env(noop(alice), ticket::use(tkt + 0), ter(tefNO_TICKET));
-
2029  env(noop(alice), ticket::use(tkt + 1), ter(tefNO_TICKET));
-
2030  env(noop(alice), ticket::use(tkt + 2), ter(tefNO_TICKET));
-
2031  tkt += 3;
-
2032  }
-
2033  {
-
2034  // Replace a lone non-blocking tx with a blocker.
-
2035 
-
2036  // Put just one entry in the TxQ.
-
2037  auto const aliceSeq = env.seq(alice);
-
2038  env(noop(alice), ticket::use(tkt + 0), queued);
-
2039 
-
2040  // Since there's an entry in the queue we cannot append a
-
2041  // blocker to the account's queue.
-
2042  env(regkey(alice, bob), fee(20), ter(telCAN_NOT_QUEUE_BLOCKS));
-
2043  env(regkey(alice, bob),
-
2044  ticket::use(tkt + 1),
-
2045  fee(20),
-
2046  ter(telCAN_NOT_QUEUE_BLOCKS));
-
2047 
-
2048  // However we can _replace_ that lone entry with a blocker.
-
2049  env(regkey(alice, bob), ticket::use(tkt + 0), fee(20), queued);
+
1979  env.fund(XRP(50000), noripple(alice, bob));
+
1980  env.memoize(charlie);
+
1981 
+
1982  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
+
1983 
+
1984  std::uint32_t tkt{env.seq(alice) + 1};
+
1985  {
+
1986  // Cannot put a blocker in an account's queue if that queue
+
1987  // already holds two or more (non-blocker) entries.
+
1988 
+
1989  // Fill up the open ledger
+
1990  env(ticket::create(alice, 250), seq(tkt - 1));
+
1991  // Set a regular key just to clear the password spent flag
+
1992  env(regkey(alice, charlie));
+
1993  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
+
1994 
+
1995  // Put two "normal" txs in the queue
+
1996  auto const aliceSeq = env.seq(alice);
+
1997  env(noop(alice), ticket::use(tkt + 2), queued);
+
1998  env(noop(alice), ticket::use(tkt + 1), queued);
+
1999 
+
2000  // Can't replace either queued transaction with a blocker
+
2001  env(fset(alice, asfAccountTxnID),
+
2002  ticket::use(tkt + 1),
+
2003  fee(20),
+
2004  ter(telCAN_NOT_QUEUE_BLOCKS));
+
2005 
+
2006  env(regkey(alice, bob),
+
2007  ticket::use(tkt + 2),
+
2008  fee(20),
+
2009  ter(telCAN_NOT_QUEUE_BLOCKS));
+
2010 
+
2011  // Can't append a blocker to the queue.
+
2012  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
+
2013  fee(20),
+
2014  ter(telCAN_NOT_QUEUE_BLOCKS));
+
2015 
+
2016  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
+
2017  ticket::use(tkt + 0),
+
2018  fee(20),
+
2019  ter(telCAN_NOT_QUEUE_BLOCKS));
+
2020 
+
2021  // Other accounts are not affected
+
2022  env(noop(bob), queued);
+
2023  checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
+
2024 
+
2025  // Drain the queue and local transactions.
+
2026  env.close();
+
2027  checkMetrics(__LINE__, env, 0, 8, 5, 4, 256);
+
2028 
+
2029  // Show that the local transactions have flushed through as well.
+
2030  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
+
2031  env(noop(alice), ticket::use(tkt + 0), ter(tefNO_TICKET));
+
2032  env(noop(alice), ticket::use(tkt + 1), ter(tefNO_TICKET));
+
2033  env(noop(alice), ticket::use(tkt + 2), ter(tefNO_TICKET));
+
2034  tkt += 3;
+
2035  }
+
2036  {
+
2037  // Replace a lone non-blocking tx with a blocker.
+
2038 
+
2039  // Put just one entry in the TxQ.
+
2040  auto const aliceSeq = env.seq(alice);
+
2041  env(noop(alice), ticket::use(tkt + 0), queued);
+
2042 
+
2043  // Since there's an entry in the queue we cannot append a
+
2044  // blocker to the account's queue.
+
2045  env(regkey(alice, bob), fee(20), ter(telCAN_NOT_QUEUE_BLOCKS));
+
2046  env(regkey(alice, bob),
+
2047  ticket::use(tkt + 1),
+
2048  fee(20),
+
2049  ter(telCAN_NOT_QUEUE_BLOCKS));
2050 
-
2051  // Now that there's a blocker in the queue we can't append to
-
2052  // the queue.
-
2053  env(noop(alice), ter(telCAN_NOT_QUEUE_BLOCKED));
-
2054  env(noop(alice),
-
2055  ticket::use(tkt + 1),
-
2056  ter(telCAN_NOT_QUEUE_BLOCKED));
-
2057 
-
2058  // Other accounts are unaffected.
-
2059  env(noop(bob), queued);
+
2051  // However we can _replace_ that lone entry with a blocker.
+
2052  env(regkey(alice, bob), ticket::use(tkt + 0), fee(20), queued);
+
2053 
+
2054  // Now that there's a blocker in the queue we can't append to
+
2055  // the queue.
+
2056  env(noop(alice), ter(telCAN_NOT_QUEUE_BLOCKED));
+
2057  env(noop(alice),
+
2058  ticket::use(tkt + 1),
+
2059  ter(telCAN_NOT_QUEUE_BLOCKED));
2060 
-
2061  // We can replace the blocker with a different blocker.
-
2062  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
-
2063  ticket::use(tkt + 0),
-
2064  fee(26),
-
2065  queued);
-
2066 
-
2067  // Prove that the queue is still blocked.
-
2068  env(noop(alice), ter(telCAN_NOT_QUEUE_BLOCKED));
-
2069  env(noop(alice),
-
2070  ticket::use(tkt + 1),
-
2071  ter(telCAN_NOT_QUEUE_BLOCKED));
-
2072 
-
2073  // We can replace the blocker with a non-blocker. Then we can
-
2074  // successfully append to the queue.
-
2075  env(noop(alice), ticket::use(tkt + 0), fee(33), queued);
-
2076  env(noop(alice), ticket::use(tkt + 1), queued);
-
2077  env(noop(alice), seq(aliceSeq), queued);
-
2078 
-
2079  // Drain the queue.
-
2080  env.close();
-
2081  checkMetrics(__LINE__, env, 0, 10, 4, 5, 256);
-
2082 
-
2083  // Show that the local transactions have flushed through as well.
-
2084  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
-
2085  env(noop(alice), ticket::use(tkt + 0), ter(tefNO_TICKET));
-
2086  env(noop(alice), ticket::use(tkt + 1), ter(tefNO_TICKET));
-
2087  tkt += 2;
-
2088  }
-
2089  {
-
2090  // Put a blocker in an empty queue.
-
2091 
-
2092  // Fill up the open ledger and put a blocker as Alice's first
-
2093  // entry in the (empty) TxQ.
-
2094  env(noop(alice));
-
2095  env(noop(alice));
-
2096 
-
2097  env(fset(alice, asfAccountTxnID), ticket::use(tkt + 2), queued);
-
2098 
-
2099  // Since there's a blocker in the queue we can't append to
-
2100  // the queue.
-
2101  env(noop(alice),
-
2102  ticket::use(tkt + 1),
-
2103  ter(telCAN_NOT_QUEUE_BLOCKED));
-
2104 
-
2105  // Other accounts are unaffected.
-
2106  env(noop(bob), queued);
+
2061  // Other accounts are unaffected.
+
2062  env(noop(bob), queued);
+
2063 
+
2064  // We can replace the blocker with a different blocker.
+
2065  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
+
2066  ticket::use(tkt + 0),
+
2067  fee(26),
+
2068  queued);
+
2069 
+
2070  // Prove that the queue is still blocked.
+
2071  env(noop(alice), ter(telCAN_NOT_QUEUE_BLOCKED));
+
2072  env(noop(alice),
+
2073  ticket::use(tkt + 1),
+
2074  ter(telCAN_NOT_QUEUE_BLOCKED));
+
2075 
+
2076  // We can replace the blocker with a non-blocker. Then we can
+
2077  // successfully append to the queue.
+
2078  env(noop(alice), ticket::use(tkt + 0), fee(33), queued);
+
2079  env(noop(alice), ticket::use(tkt + 1), queued);
+
2080  env(noop(alice), seq(aliceSeq), queued);
+
2081 
+
2082  // Drain the queue.
+
2083  env.close();
+
2084  checkMetrics(__LINE__, env, 0, 10, 4, 5, 256);
+
2085 
+
2086  // Show that the local transactions have flushed through as well.
+
2087  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
+
2088  env(noop(alice), ticket::use(tkt + 0), ter(tefNO_TICKET));
+
2089  env(noop(alice), ticket::use(tkt + 1), ter(tefNO_TICKET));
+
2090  tkt += 2;
+
2091  }
+
2092  {
+
2093  // Put a blocker in an empty queue.
+
2094 
+
2095  // Fill up the open ledger and put a blocker as Alice's first
+
2096  // entry in the (empty) TxQ.
+
2097  env(noop(alice));
+
2098  env(noop(alice));
+
2099 
+
2100  env(fset(alice, asfAccountTxnID), ticket::use(tkt + 2), queued);
+
2101 
+
2102  // Since there's a blocker in the queue we can't append to
+
2103  // the queue.
+
2104  env(noop(alice),
+
2105  ticket::use(tkt + 1),
+
2106  ter(telCAN_NOT_QUEUE_BLOCKED));
2107 
-
2108  // We can replace the blocker with a non-blocker. Then we can
-
2109  // successfully append to the queue.
-
2110  env(noop(alice), ticket::use(tkt + 2), fee(20), queued);
-
2111  env(noop(alice), ticket::use(tkt + 1), queued);
-
2112 
-
2113  // Drain the queue.
-
2114  env.close();
-
2115  checkMetrics(__LINE__, env, 0, 12, 3, 6, 256);
-
2116  }
-
2117  }
-
2118 
-
2119  void
-
2120  testInFlightBalance()
-
2121  {
-
2122  using namespace jtx;
-
2123  testcase("In-flight balance checks");
-
2124 
-
2125  Env env(
-
2126  *this,
-
2127  makeConfig(
-
2128  {{"minimum_txn_in_ledger_standalone", "3"}},
-
2129  {{"account_reserve", "200"}, {"owner_reserve", "50"}}));
-
2130 
-
2131  auto alice = Account("alice");
-
2132  auto charlie = Account("charlie");
-
2133  auto gw = Account("gw");
-
2134 
-
2135  auto queued = ter(terQUEUED);
-
2136 
-
2137  // Set the fee reserves _really_ low so transactions with fees
-
2138  // in the ballpark of the reserves can be queued. With default
-
2139  // reserves, a couple hundred transactions would have to be
-
2140  // queued before the open ledger fee approached the reserve,
-
2141  // which would unnecessarily slow down this test.
-
2142  // ledgers in queue is 2 because of makeConfig
-
2143  auto const initQueueMax = initFee(env, 3, 2, 10, 200, 50);
-
2144 
-
2145  auto limit = 3;
-
2146 
-
2147  checkMetrics(__LINE__, env, 0, initQueueMax, 0, limit, 256);
-
2148 
-
2149  env.fund(XRP(50000), noripple(alice, charlie), gw);
-
2150  checkMetrics(__LINE__, env, 0, initQueueMax, limit + 1, limit, 256);
+
2108  // Other accounts are unaffected.
+
2109  env(noop(bob), queued);
+
2110 
+
2111  // We can replace the blocker with a non-blocker. Then we can
+
2112  // successfully append to the queue.
+
2113  env(noop(alice), ticket::use(tkt + 2), fee(20), queued);
+
2114  env(noop(alice), ticket::use(tkt + 1), queued);
+
2115 
+
2116  // Drain the queue.
+
2117  env.close();
+
2118  checkMetrics(__LINE__, env, 0, 12, 3, 6, 256);
+
2119  }
+
2120  }
+
2121 
+
2122  void
+
2123  testInFlightBalance()
+
2124  {
+
2125  using namespace jtx;
+
2126  testcase("In-flight balance checks");
+
2127 
+
2128  Env env(
+
2129  *this,
+
2130  makeConfig(
+
2131  {{"minimum_txn_in_ledger_standalone", "3"}},
+
2132  {{"account_reserve", "200"}, {"owner_reserve", "50"}}));
+
2133 
+
2134  auto alice = Account("alice");
+
2135  auto charlie = Account("charlie");
+
2136  auto gw = Account("gw");
+
2137 
+
2138  auto queued = ter(terQUEUED);
+
2139 
+
2140  // Set the fee reserves _really_ low so transactions with fees
+
2141  // in the ballpark of the reserves can be queued. With default
+
2142  // reserves, a couple hundred transactions would have to be
+
2143  // queued before the open ledger fee approached the reserve,
+
2144  // which would unnecessarily slow down this test.
+
2145  // ledgers in queue is 2 because of makeConfig
+
2146  auto const initQueueMax = initFee(env, 3, 2, 10, 200, 50);
+
2147 
+
2148  auto limit = 3;
+
2149 
+
2150  checkMetrics(__LINE__, env, 0, initQueueMax, 0, limit, 256);
2151 
-
2152  auto USD = gw["USD"];
-
2153  auto BUX = gw["BUX"];
+
2152  env.fund(XRP(50000), noripple(alice, charlie), gw);
+
2153  checkMetrics(__LINE__, env, 0, initQueueMax, limit + 1, limit, 256);
2154 
-
2156  // Offer with high XRP out and low fee doesn't block
-
2157  auto aliceSeq = env.seq(alice);
-
2158  auto aliceBal = env.balance(alice);
-
2159 
-
2160  env.require(balance(alice, XRP(50000)), owners(alice, 0));
-
2161 
-
2162  // If this offer crosses, all of alice's
-
2163  // XRP will be taken (except the reserve).
-
2164  env(offer(alice, BUX(5000), XRP(50000)), queued);
-
2165  checkMetrics(__LINE__, env, 1, initQueueMax, limit + 1, limit, 256);
-
2166 
-
2167  // But because the reserve is protected, another
-
2168  // transaction will be allowed to queue
-
2169  env(noop(alice), seq(aliceSeq + 1), queued);
-
2170  checkMetrics(__LINE__, env, 2, initQueueMax, limit + 1, limit, 256);
-
2171 
-
2172  env.close();
-
2173  ++limit;
-
2174  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
-
2175 
-
2176  // But once we close the ledger, we find alice
-
2177  // has plenty of XRP, because the offer didn't
-
2178  // cross (of course).
-
2179  env.require(balance(alice, aliceBal - drops(20)), owners(alice, 1));
-
2180  // cancel the offer
-
2181  env(offer_cancel(alice, aliceSeq));
-
2182 
-
2184  // Offer with high XRP out and high total fee blocks later txs
-
2185  fillQueue(env, alice);
-
2186  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
-
2187  aliceSeq = env.seq(alice);
-
2188  aliceBal = env.balance(alice);
-
2189 
-
2190  env.require(owners(alice, 0));
-
2191 
-
2192  // Alice creates an offer with a fee of half the reserve
-
2193  env(offer(alice, BUX(5000), XRP(50000)), fee(drops(100)), queued);
-
2194  checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
-
2195 
-
2196  // Alice creates another offer with a fee
-
2197  // that brings the total to just shy of the reserve
-
2198  env(noop(alice), fee(drops(99)), seq(aliceSeq + 1), queued);
-
2199  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
-
2200 
-
2201  // So even a noop will look like alice
-
2202  // doesn't have the balance to pay the fee
-
2203  env(noop(alice),
-
2204  fee(drops(51)),
-
2205  seq(aliceSeq + 2),
-
2206  ter(terINSUF_FEE_B));
-
2207  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
-
2208 
-
2209  env.close();
-
2210  ++limit;
-
2211  checkMetrics(__LINE__, env, 0, limit * 2, 3, limit, 256);
-
2212 
-
2213  // But once we close the ledger, we find alice
-
2214  // has plenty of XRP, because the offer didn't
-
2215  // cross (of course).
-
2216  env.require(balance(alice, aliceBal - drops(250)), owners(alice, 1));
-
2217  // cancel the offer
-
2218  env(offer_cancel(alice, aliceSeq));
-
2219 
-
2221  // Offer with high XRP out and super high fee blocks later txs
-
2222  fillQueue(env, alice);
-
2223  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
-
2224  aliceSeq = env.seq(alice);
-
2225  aliceBal = env.balance(alice);
-
2226 
-
2227  env.require(owners(alice, 0));
-
2228 
-
2229  // Alice creates an offer with a fee larger than the reserve
-
2230  // This one can queue because it's the first in the queue for alice
-
2231  env(offer(alice, BUX(5000), XRP(50000)), fee(drops(300)), queued);
-
2232  checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
-
2233 
-
2234  // So even a noop will look like alice
-
2235  // doesn't have the balance to pay the fee
-
2236  env(noop(alice),
-
2237  fee(drops(51)),
-
2238  seq(aliceSeq + 1),
-
2239  ter(telCAN_NOT_QUEUE_BALANCE));
-
2240  checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
-
2241 
-
2242  env.close();
-
2243  ++limit;
-
2244  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
-
2245 
-
2246  // But once we close the ledger, we find alice
-
2247  // has plenty of XRP, because the offer didn't
-
2248  // cross (of course).
-
2249  env.require(balance(alice, aliceBal - drops(351)), owners(alice, 1));
-
2250  // cancel the offer
-
2251  env(offer_cancel(alice, aliceSeq));
-
2252 
-
2254  // Offer with low XRP out allows later txs
-
2255  fillQueue(env, alice);
-
2256  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
-
2257  aliceSeq = env.seq(alice);
-
2258  aliceBal = env.balance(alice);
-
2259 
-
2260  // If this offer crosses, just a bit
-
2261  // of alice's XRP will be taken.
-
2262  env(offer(alice, BUX(50), XRP(500)), queued);
-
2263 
-
2264  // And later transactions are just fine
-
2265  env(noop(alice), seq(aliceSeq + 1), queued);
-
2266  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
-
2267 
-
2268  env.close();
-
2269  ++limit;
-
2270  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
-
2271 
-
2272  // But once we close the ledger, we find alice
-
2273  // has plenty of XRP, because the offer didn't
-
2274  // cross (of course).
-
2275  env.require(balance(alice, aliceBal - drops(20)), owners(alice, 1));
-
2276  // cancel the offer
-
2277  env(offer_cancel(alice, aliceSeq));
-
2278 
-
2280  // Large XRP payment doesn't block later txs
-
2281  fillQueue(env, alice);
-
2282  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
-
2283 
-
2284  aliceSeq = env.seq(alice);
-
2285  aliceBal = env.balance(alice);
+
2155  auto USD = gw["USD"];
+
2156  auto BUX = gw["BUX"];
+
2157 
+
2159  // Offer with high XRP out and low fee doesn't block
+
2160  auto aliceSeq = env.seq(alice);
+
2161  auto aliceBal = env.balance(alice);
+
2162 
+
2163  env.require(balance(alice, XRP(50000)), owners(alice, 0));
+
2164 
+
2165  // If this offer crosses, all of alice's
+
2166  // XRP will be taken (except the reserve).
+
2167  env(offer(alice, BUX(5000), XRP(50000)), queued);
+
2168  checkMetrics(__LINE__, env, 1, initQueueMax, limit + 1, limit, 256);
+
2169 
+
2170  // But because the reserve is protected, another
+
2171  // transaction will be allowed to queue
+
2172  env(noop(alice), seq(aliceSeq + 1), queued);
+
2173  checkMetrics(__LINE__, env, 2, initQueueMax, limit + 1, limit, 256);
+
2174 
+
2175  env.close();
+
2176  ++limit;
+
2177  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
+
2178 
+
2179  // But once we close the ledger, we find alice
+
2180  // has plenty of XRP, because the offer didn't
+
2181  // cross (of course).
+
2182  env.require(balance(alice, aliceBal - drops(20)), owners(alice, 1));
+
2183  // cancel the offer
+
2184  env(offer_cancel(alice, aliceSeq));
+
2185 
+
2187  // Offer with high XRP out and high total fee blocks later txs
+
2188  fillQueue(env, alice);
+
2189  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
+
2190  aliceSeq = env.seq(alice);
+
2191  aliceBal = env.balance(alice);
+
2192 
+
2193  env.require(owners(alice, 0));
+
2194 
+
2195  // Alice creates an offer with a fee of half the reserve
+
2196  env(offer(alice, BUX(5000), XRP(50000)), fee(drops(100)), queued);
+
2197  checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
+
2198 
+
2199  // Alice creates another offer with a fee
+
2200  // that brings the total to just shy of the reserve
+
2201  env(noop(alice), fee(drops(99)), seq(aliceSeq + 1), queued);
+
2202  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
+
2203 
+
2204  // So even a noop will look like alice
+
2205  // doesn't have the balance to pay the fee
+
2206  env(noop(alice),
+
2207  fee(drops(51)),
+
2208  seq(aliceSeq + 2),
+
2209  ter(terINSUF_FEE_B));
+
2210  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
+
2211 
+
2212  env.close();
+
2213  ++limit;
+
2214  checkMetrics(__LINE__, env, 0, limit * 2, 3, limit, 256);
+
2215 
+
2216  // But once we close the ledger, we find alice
+
2217  // has plenty of XRP, because the offer didn't
+
2218  // cross (of course).
+
2219  env.require(balance(alice, aliceBal - drops(250)), owners(alice, 1));
+
2220  // cancel the offer
+
2221  env(offer_cancel(alice, aliceSeq));
+
2222 
+
2224  // Offer with high XRP out and super high fee blocks later txs
+
2225  fillQueue(env, alice);
+
2226  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
+
2227  aliceSeq = env.seq(alice);
+
2228  aliceBal = env.balance(alice);
+
2229 
+
2230  env.require(owners(alice, 0));
+
2231 
+
2232  // Alice creates an offer with a fee larger than the reserve
+
2233  // This one can queue because it's the first in the queue for alice
+
2234  env(offer(alice, BUX(5000), XRP(50000)), fee(drops(300)), queued);
+
2235  checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
+
2236 
+
2237  // So even a noop will look like alice
+
2238  // doesn't have the balance to pay the fee
+
2239  env(noop(alice),
+
2240  fee(drops(51)),
+
2241  seq(aliceSeq + 1),
+
2242  ter(telCAN_NOT_QUEUE_BALANCE));
+
2243  checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
+
2244 
+
2245  env.close();
+
2246  ++limit;
+
2247  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
+
2248 
+
2249  // But once we close the ledger, we find alice
+
2250  // has plenty of XRP, because the offer didn't
+
2251  // cross (of course).
+
2252  env.require(balance(alice, aliceBal - drops(351)), owners(alice, 1));
+
2253  // cancel the offer
+
2254  env(offer_cancel(alice, aliceSeq));
+
2255 
+
2257  // Offer with low XRP out allows later txs
+
2258  fillQueue(env, alice);
+
2259  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
+
2260  aliceSeq = env.seq(alice);
+
2261  aliceBal = env.balance(alice);
+
2262 
+
2263  // If this offer crosses, just a bit
+
2264  // of alice's XRP will be taken.
+
2265  env(offer(alice, BUX(50), XRP(500)), queued);
+
2266 
+
2267  // And later transactions are just fine
+
2268  env(noop(alice), seq(aliceSeq + 1), queued);
+
2269  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
+
2270 
+
2271  env.close();
+
2272  ++limit;
+
2273  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
+
2274 
+
2275  // But once we close the ledger, we find alice
+
2276  // has plenty of XRP, because the offer didn't
+
2277  // cross (of course).
+
2278  env.require(balance(alice, aliceBal - drops(20)), owners(alice, 1));
+
2279  // cancel the offer
+
2280  env(offer_cancel(alice, aliceSeq));
+
2281 
+
2283  // Large XRP payment doesn't block later txs
+
2284  fillQueue(env, alice);
+
2285  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2286 
-
2287  // If this payment succeeds, alice will
-
2288  // send her entire balance to charlie
-
2289  // (minus the reserve).
-
2290  env(pay(alice, charlie, XRP(50000)), queued);
-
2291 
-
2292  // But because the reserve is protected, another
-
2293  // transaction will be allowed to queue
-
2294  env(noop(alice), seq(aliceSeq + 1), queued);
-
2295  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
-
2296 
-
2297  env.close();
-
2298  ++limit;
-
2299  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
-
2300 
-
2301  // But once we close the ledger, we find alice
-
2302  // still has most of her balance, because the
-
2303  // payment was unfunded!
-
2304  env.require(balance(alice, aliceBal - drops(20)), owners(alice, 0));
-
2305 
-
2307  // Small XRP payment allows later txs
-
2308  fillQueue(env, alice);
-
2309  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
-
2310 
-
2311  aliceSeq = env.seq(alice);
-
2312  aliceBal = env.balance(alice);
+
2287  aliceSeq = env.seq(alice);
+
2288  aliceBal = env.balance(alice);
+
2289 
+
2290  // If this payment succeeds, alice will
+
2291  // send her entire balance to charlie
+
2292  // (minus the reserve).
+
2293  env(pay(alice, charlie, XRP(50000)), queued);
+
2294 
+
2295  // But because the reserve is protected, another
+
2296  // transaction will be allowed to queue
+
2297  env(noop(alice), seq(aliceSeq + 1), queued);
+
2298  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
+
2299 
+
2300  env.close();
+
2301  ++limit;
+
2302  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
+
2303 
+
2304  // But once we close the ledger, we find alice
+
2305  // still has most of her balance, because the
+
2306  // payment was unfunded!
+
2307  env.require(balance(alice, aliceBal - drops(20)), owners(alice, 0));
+
2308 
+
2310  // Small XRP payment allows later txs
+
2311  fillQueue(env, alice);
+
2312  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2313 
-
2314  // If this payment succeeds, alice will
-
2315  // send just a bit of balance to charlie
-
2316  env(pay(alice, charlie, XRP(500)), queued);
-
2317 
-
2318  // And later transactions are just fine
-
2319  env(noop(alice), seq(aliceSeq + 1), queued);
-
2320  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
-
2321 
-
2322  env.close();
-
2323  ++limit;
-
2324  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
-
2325 
-
2326  // The payment succeeds
-
2327  env.require(
-
2328  balance(alice, aliceBal - XRP(500) - drops(20)), owners(alice, 0));
-
2329 
-
2331  // Large IOU payment allows later txs
-
2332  auto const amount = USD(500000);
-
2333  env(trust(alice, USD(50000000)));
-
2334  env(trust(charlie, USD(50000000)));
-
2335  checkMetrics(__LINE__, env, 0, limit * 2, 4, limit, 256);
-
2336  // Close so we don't have to deal
-
2337  // with tx ordering in consensus.
-
2338  env.close();
-
2339 
-
2340  env(pay(gw, alice, amount));
-
2341  checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
-
2342  // Close so we don't have to deal
-
2343  // with tx ordering in consensus.
-
2344  env.close();
-
2345 
-
2346  fillQueue(env, alice);
-
2347  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
+
2314  aliceSeq = env.seq(alice);
+
2315  aliceBal = env.balance(alice);
+
2316 
+
2317  // If this payment succeeds, alice will
+
2318  // send just a bit of balance to charlie
+
2319  env(pay(alice, charlie, XRP(500)), queued);
+
2320 
+
2321  // And later transactions are just fine
+
2322  env(noop(alice), seq(aliceSeq + 1), queued);
+
2323  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
+
2324 
+
2325  env.close();
+
2326  ++limit;
+
2327  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
+
2328 
+
2329  // The payment succeeds
+
2330  env.require(
+
2331  balance(alice, aliceBal - XRP(500) - drops(20)), owners(alice, 0));
+
2332 
+
2334  // Large IOU payment allows later txs
+
2335  auto const amount = USD(500000);
+
2336  env(trust(alice, USD(50000000)));
+
2337  env(trust(charlie, USD(50000000)));
+
2338  checkMetrics(__LINE__, env, 0, limit * 2, 4, limit, 256);
+
2339  // Close so we don't have to deal
+
2340  // with tx ordering in consensus.
+
2341  env.close();
+
2342 
+
2343  env(pay(gw, alice, amount));
+
2344  checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
+
2345  // Close so we don't have to deal
+
2346  // with tx ordering in consensus.
+
2347  env.close();
2348 
-
2349  aliceSeq = env.seq(alice);
-
2350  aliceBal = env.balance(alice);
-
2351  auto aliceUSD = env.balance(alice, USD);
-
2352 
-
2353  // If this payment succeeds, alice will
-
2354  // send her entire USD balance to charlie.
-
2355  env(pay(alice, charlie, amount), queued);
-
2356 
-
2357  // But that's fine, because it doesn't affect
-
2358  // alice's XRP balance (other than the fee, of course).
-
2359  env(noop(alice), seq(aliceSeq + 1), queued);
-
2360  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
-
2361 
-
2362  env.close();
-
2363  ++limit;
-
2364  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
-
2365 
-
2366  // So once we close the ledger, alice has her
-
2367  // XRP balance, but her USD balance went to charlie.
-
2368  env.require(
-
2369  balance(alice, aliceBal - drops(20)),
-
2370  balance(alice, USD(0)),
-
2371  balance(charlie, aliceUSD),
-
2372  owners(alice, 1),
-
2373  owners(charlie, 1));
-
2374 
-
2376  // Large XRP to IOU payment doesn't block later txs.
+
2349  fillQueue(env, alice);
+
2350  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
+
2351 
+
2352  aliceSeq = env.seq(alice);
+
2353  aliceBal = env.balance(alice);
+
2354  auto aliceUSD = env.balance(alice, USD);
+
2355 
+
2356  // If this payment succeeds, alice will
+
2357  // send her entire USD balance to charlie.
+
2358  env(pay(alice, charlie, amount), queued);
+
2359 
+
2360  // But that's fine, because it doesn't affect
+
2361  // alice's XRP balance (other than the fee, of course).
+
2362  env(noop(alice), seq(aliceSeq + 1), queued);
+
2363  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
+
2364 
+
2365  env.close();
+
2366  ++limit;
+
2367  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
+
2368 
+
2369  // So once we close the ledger, alice has her
+
2370  // XRP balance, but her USD balance went to charlie.
+
2371  env.require(
+
2372  balance(alice, aliceBal - drops(20)),
+
2373  balance(alice, USD(0)),
+
2374  balance(charlie, aliceUSD),
+
2375  owners(alice, 1),
+
2376  owners(charlie, 1));
2377 
-
2378  env(offer(gw, XRP(500000), USD(50000)));
-
2379  // Close so we don't have to deal
-
2380  // with tx ordering in consensus.
-
2381  env.close();
-
2382 
-
2383  fillQueue(env, charlie);
-
2384  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
+
2379  // Large XRP to IOU payment doesn't block later txs.
+
2380 
+
2381  env(offer(gw, XRP(500000), USD(50000)));
+
2382  // Close so we don't have to deal
+
2383  // with tx ordering in consensus.
+
2384  env.close();
2385 
-
2386  aliceSeq = env.seq(alice);
-
2387  aliceBal = env.balance(alice);
-
2388  auto charlieUSD = env.balance(charlie, USD);
-
2389 
-
2390  // If this payment succeeds, and uses the
-
2391  // entire sendMax, alice will send her
-
2392  // entire XRP balance to charlie in the
-
2393  // form of USD.
-
2394  BEAST_EXPECT(XRP(60000) > aliceBal);
-
2395  env(pay(alice, charlie, USD(1000)), sendmax(XRP(60000)), queued);
-
2396 
-
2397  // But because the reserve is protected, another
-
2398  // transaction will be allowed to queue
-
2399  env(noop(alice), seq(aliceSeq + 1), queued);
-
2400  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
-
2401 
-
2402  env.close();
-
2403  ++limit;
-
2404  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
-
2405 
-
2406  // So once we close the ledger, alice sent a payment
-
2407  // to charlie using only a portion of her XRP balance
-
2408  env.require(
-
2409  balance(alice, aliceBal - XRP(10000) - drops(20)),
-
2410  balance(alice, USD(0)),
-
2411  balance(charlie, charlieUSD + USD(1000)),
-
2412  owners(alice, 1),
-
2413  owners(charlie, 1));
-
2414 
-
2416  // Small XRP to IOU payment allows later txs.
+
2386  fillQueue(env, charlie);
+
2387  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
+
2388 
+
2389  aliceSeq = env.seq(alice);
+
2390  aliceBal = env.balance(alice);
+
2391  auto charlieUSD = env.balance(charlie, USD);
+
2392 
+
2393  // If this payment succeeds, and uses the
+
2394  // entire sendMax, alice will send her
+
2395  // entire XRP balance to charlie in the
+
2396  // form of USD.
+
2397  BEAST_EXPECT(XRP(60000) > aliceBal);
+
2398  env(pay(alice, charlie, USD(1000)), sendmax(XRP(60000)), queued);
+
2399 
+
2400  // But because the reserve is protected, another
+
2401  // transaction will be allowed to queue
+
2402  env(noop(alice), seq(aliceSeq + 1), queued);
+
2403  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
+
2404 
+
2405  env.close();
+
2406  ++limit;
+
2407  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
+
2408 
+
2409  // So once we close the ledger, alice sent a payment
+
2410  // to charlie using only a portion of her XRP balance
+
2411  env.require(
+
2412  balance(alice, aliceBal - XRP(10000) - drops(20)),
+
2413  balance(alice, USD(0)),
+
2414  balance(charlie, charlieUSD + USD(1000)),
+
2415  owners(alice, 1),
+
2416  owners(charlie, 1));
2417 
-
2418  fillQueue(env, charlie);
-
2419  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
+
2419  // Small XRP to IOU payment allows later txs.
2420 
-
2421  aliceSeq = env.seq(alice);
-
2422  aliceBal = env.balance(alice);
-
2423  charlieUSD = env.balance(charlie, USD);
-
2424 
-
2425  // If this payment succeeds, and uses the
-
2426  // entire sendMax, alice will only send
-
2427  // a portion of her XRP balance to charlie
-
2428  // in the form of USD.
-
2429  BEAST_EXPECT(aliceBal > XRP(6001));
-
2430  env(pay(alice, charlie, USD(500)), sendmax(XRP(6000)), queued);
-
2431 
-
2432  // And later transactions are just fine
-
2433  env(noop(alice), seq(aliceSeq + 1), queued);
-
2434  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
-
2435 
-
2436  env.close();
-
2437  ++limit;
-
2438  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
-
2439 
-
2440  // So once we close the ledger, alice sent a payment
-
2441  // to charlie using only a portion of her XRP balance
-
2442  env.require(
-
2443  balance(alice, aliceBal - XRP(5000) - drops(20)),
-
2444  balance(alice, USD(0)),
-
2445  balance(charlie, charlieUSD + USD(500)),
-
2446  owners(alice, 1),
-
2447  owners(charlie, 1));
-
2448 
-
2450  // Edge case: what happens if the balance is below the reserve?
-
2451  env(noop(alice), fee(env.balance(alice) - drops(30)));
-
2452  env.close();
-
2453 
-
2454  fillQueue(env, charlie);
-
2455  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
+
2421  fillQueue(env, charlie);
+
2422  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
+
2423 
+
2424  aliceSeq = env.seq(alice);
+
2425  aliceBal = env.balance(alice);
+
2426  charlieUSD = env.balance(charlie, USD);
+
2427 
+
2428  // If this payment succeeds, and uses the
+
2429  // entire sendMax, alice will only send
+
2430  // a portion of her XRP balance to charlie
+
2431  // in the form of USD.
+
2432  BEAST_EXPECT(aliceBal > XRP(6001));
+
2433  env(pay(alice, charlie, USD(500)), sendmax(XRP(6000)), queued);
+
2434 
+
2435  // And later transactions are just fine
+
2436  env(noop(alice), seq(aliceSeq + 1), queued);
+
2437  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
+
2438 
+
2439  env.close();
+
2440  ++limit;
+
2441  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
+
2442 
+
2443  // So once we close the ledger, alice sent a payment
+
2444  // to charlie using only a portion of her XRP balance
+
2445  env.require(
+
2446  balance(alice, aliceBal - XRP(5000) - drops(20)),
+
2447  balance(alice, USD(0)),
+
2448  balance(charlie, charlieUSD + USD(500)),
+
2449  owners(alice, 1),
+
2450  owners(charlie, 1));
+
2451 
+
2453  // Edge case: what happens if the balance is below the reserve?
+
2454  env(noop(alice), fee(env.balance(alice) - drops(30)));
+
2455  env.close();
2456 
-
2457  aliceSeq = env.seq(alice);
-
2458  aliceBal = env.balance(alice);
-
2459  BEAST_EXPECT(aliceBal == drops(30));
-
2460 
-
2461  env(noop(alice), fee(drops(25)), queued);
-
2462  env(noop(alice), seq(aliceSeq + 1), ter(terINSUF_FEE_B));
-
2463  BEAST_EXPECT(env.balance(alice) == drops(30));
-
2464 
-
2465  checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
-
2466 
-
2467  env.close();
-
2468  ++limit;
-
2469  checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
-
2470  BEAST_EXPECT(env.balance(alice) == drops(5));
-
2471  }
-
2472 
-
2473  void
-
2474  testConsequences()
-
2475  {
-
2476  using namespace jtx;
-
2477  using namespace std::chrono;
-
2478  testcase("consequences");
-
2479 
-
2480  Env env(*this);
-
2481  auto const alice = Account("alice");
-
2482  env.memoize(alice);
-
2483  env.memoize("bob");
-
2484  env.memoize("carol");
-
2485  {
-
2486  auto const jtx = env.jt(offer_cancel(alice, 3), seq(5), fee(10));
-
2487  auto const pf = preflight(
-
2488  env.app(),
-
2489  env.current()->rules(),
-
2490  *jtx.stx,
-
2491  tapNONE,
-
2492  env.journal);
-
2493  BEAST_EXPECT(pf.ter == tesSUCCESS);
-
2494  BEAST_EXPECT(!pf.consequences.isBlocker());
-
2495  BEAST_EXPECT(pf.consequences.fee() == drops(10));
-
2496  BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
-
2497  }
-
2498 
-
2499  {
-
2500  auto USD = alice["USD"];
+
2457  fillQueue(env, charlie);
+
2458  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
+
2459 
+
2460  aliceSeq = env.seq(alice);
+
2461  aliceBal = env.balance(alice);
+
2462  BEAST_EXPECT(aliceBal == drops(30));
+
2463 
+
2464  env(noop(alice), fee(drops(25)), queued);
+
2465  env(noop(alice), seq(aliceSeq + 1), ter(terINSUF_FEE_B));
+
2466  BEAST_EXPECT(env.balance(alice) == drops(30));
+
2467 
+
2468  checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
+
2469 
+
2470  env.close();
+
2471  ++limit;
+
2472  checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
+
2473  BEAST_EXPECT(env.balance(alice) == drops(5));
+
2474  }
+
2475 
+
2476  void
+
2477  testConsequences()
+
2478  {
+
2479  using namespace jtx;
+
2480  using namespace std::chrono;
+
2481  testcase("consequences");
+
2482 
+
2483  Env env(*this);
+
2484  auto const alice = Account("alice");
+
2485  env.memoize(alice);
+
2486  env.memoize("bob");
+
2487  env.memoize("carol");
+
2488  {
+
2489  auto const jtx = env.jt(offer_cancel(alice, 3), seq(5), fee(10));
+
2490  auto const pf = preflight(
+
2491  env.app(),
+
2492  env.current()->rules(),
+
2493  *jtx.stx,
+
2494  tapNONE,
+
2495  env.journal);
+
2496  BEAST_EXPECT(pf.ter == tesSUCCESS);
+
2497  BEAST_EXPECT(!pf.consequences.isBlocker());
+
2498  BEAST_EXPECT(pf.consequences.fee() == drops(10));
+
2499  BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
+
2500  }
2501 
-
2502  auto const jtx =
-
2503  env.jt(trust("carol", USD(50000000)), seq(1), fee(10));
-
2504  auto const pf = preflight(
-
2505  env.app(),
-
2506  env.current()->rules(),
-
2507  *jtx.stx,
-
2508  tapNONE,
-
2509  env.journal);
-
2510  BEAST_EXPECT(pf.ter == tesSUCCESS);
-
2511  BEAST_EXPECT(!pf.consequences.isBlocker());
-
2512  BEAST_EXPECT(pf.consequences.fee() == drops(10));
-
2513  BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
-
2514  }
-
2515 
-
2516  {
-
2517  auto const jtx = env.jt(ticket::create(alice, 1), seq(1), fee(10));
-
2518  auto const pf = preflight(
-
2519  env.app(),
-
2520  env.current()->rules(),
-
2521  *jtx.stx,
-
2522  tapNONE,
-
2523  env.journal);
-
2524  BEAST_EXPECT(pf.ter == tesSUCCESS);
-
2525  BEAST_EXPECT(!pf.consequences.isBlocker());
-
2526  BEAST_EXPECT(pf.consequences.fee() == drops(10));
-
2527  BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
-
2528  }
-
2529  }
-
2530 
-
2531  void
-
2532  testAcctInQueueButEmpty()
-
2533  {
-
2534  // It is possible for an account to be present in the queue but have
-
2535  // no queued transactions. This has been the source of at least one
-
2536  // bug where an insufficiently informed developer assumed that if an
-
2537  // account was present in the queue then it also had at least one
-
2538  // queued transaction.
-
2539  //
-
2540  // This test does touch testing to verify that, at least, that bug
-
2541  // is addressed.
-
2542  using namespace jtx;
-
2543  testcase("acct in queue but empty");
-
2544 
-
2545  auto alice = Account("alice");
-
2546  auto bob = Account("bob");
-
2547  auto charlie = Account("charlie");
-
2548 
-
2549  auto queued = ter(terQUEUED);
-
2550 
-
2551  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
-
2552 
-
2553  BEAST_EXPECT(env.current()->fees().base == 10);
-
2554 
-
2555  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
-
2556 
-
2557  // Fund accounts while the fee is cheap so they all apply.
-
2558  env.fund(XRP(50000), noripple(alice, bob, charlie));
-
2559  checkMetrics(__LINE__, env, 0, std::nullopt, 3, 3, 256);
-
2560 
-
2561  // Alice - no fee change yet
-
2562  env(noop(alice));
-
2563  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
-
2564 
-
2565  // Bob with really high fee - applies
-
2566  env(noop(bob), openLedgerFee(env));
-
2567  checkMetrics(__LINE__, env, 0, std::nullopt, 5, 3, 256);
-
2568 
-
2569  // Charlie with low fee: queued
-
2570  env(noop(charlie), fee(1000), queued);
-
2571  checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
-
2572 
-
2573  env.close();
-
2574  // Verify that the queued transaction was applied
-
2575  checkMetrics(__LINE__, env, 0, 10, 1, 5, 256);
-
2576 
-
2578 
-
2579  // Stuff the ledger and queue so we can verify that
-
2580  // stuff gets kicked out.
-
2581  env(noop(bob), fee(1000));
-
2582  env(noop(bob), fee(1000));
-
2583  env(noop(bob), fee(1000));
+
2502  {
+
2503  auto USD = alice["USD"];
+
2504 
+
2505  auto const jtx =
+
2506  env.jt(trust("carol", USD(50000000)), seq(1), fee(10));
+
2507  auto const pf = preflight(
+
2508  env.app(),
+
2509  env.current()->rules(),
+
2510  *jtx.stx,
+
2511  tapNONE,
+
2512  env.journal);
+
2513  BEAST_EXPECT(pf.ter == tesSUCCESS);
+
2514  BEAST_EXPECT(!pf.consequences.isBlocker());
+
2515  BEAST_EXPECT(pf.consequences.fee() == drops(10));
+
2516  BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
+
2517  }
+
2518 
+
2519  {
+
2520  auto const jtx = env.jt(ticket::create(alice, 1), seq(1), fee(10));
+
2521  auto const pf = preflight(
+
2522  env.app(),
+
2523  env.current()->rules(),
+
2524  *jtx.stx,
+
2525  tapNONE,
+
2526  env.journal);
+
2527  BEAST_EXPECT(pf.ter == tesSUCCESS);
+
2528  BEAST_EXPECT(!pf.consequences.isBlocker());
+
2529  BEAST_EXPECT(pf.consequences.fee() == drops(10));
+
2530  BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
+
2531  }
+
2532  }
+
2533 
+
2534  void
+
2535  testAcctInQueueButEmpty()
+
2536  {
+
2537  // It is possible for an account to be present in the queue but have
+
2538  // no queued transactions. This has been the source of at least one
+
2539  // bug where an insufficiently informed developer assumed that if an
+
2540  // account was present in the queue then it also had at least one
+
2541  // queued transaction.
+
2542  //
+
2543  // This test does touch testing to verify that, at least, that bug
+
2544  // is addressed.
+
2545  using namespace jtx;
+
2546  testcase("acct in queue but empty");
+
2547 
+
2548  auto alice = Account("alice");
+
2549  auto bob = Account("bob");
+
2550  auto charlie = Account("charlie");
+
2551 
+
2552  auto queued = ter(terQUEUED);
+
2553 
+
2554  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
+
2555 
+
2556  BEAST_EXPECT(env.current()->fees().base == 10);
+
2557 
+
2558  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
+
2559 
+
2560  // Fund accounts while the fee is cheap so they all apply.
+
2561  env.fund(XRP(50000), noripple(alice, bob, charlie));
+
2562  checkMetrics(__LINE__, env, 0, std::nullopt, 3, 3, 256);
+
2563 
+
2564  // Alice - no fee change yet
+
2565  env(noop(alice));
+
2566  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
+
2567 
+
2568  // Bob with really high fee - applies
+
2569  env(noop(bob), openLedgerFee(env));
+
2570  checkMetrics(__LINE__, env, 0, std::nullopt, 5, 3, 256);
+
2571 
+
2572  // Charlie with low fee: queued
+
2573  env(noop(charlie), fee(1000), queued);
+
2574  checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
+
2575 
+
2576  env.close();
+
2577  // Verify that the queued transaction was applied
+
2578  checkMetrics(__LINE__, env, 0, 10, 1, 5, 256);
+
2579 
+
2581 
+
2582  // Stuff the ledger and queue so we can verify that
+
2583  // stuff gets kicked out.
2584  env(noop(bob), fee(1000));
2585  env(noop(bob), fee(1000));
-
2586  checkMetrics(__LINE__, env, 0, 10, 6, 5, 256);
-
2587 
-
2588  // Use explicit fees so we can control which txn
-
2589  // will get dropped
-
2590  // This one gets into the queue, but gets dropped when the
-
2591  // higher fee one is added later.
-
2592  std::uint32_t const charlieSeq{env.seq(charlie)};
-
2593  env(noop(charlie), fee(15), seq(charlieSeq), queued);
-
2594 
-
2595  // These stay in the queue.
-
2596  std::uint32_t aliceSeq{env.seq(alice)};
-
2597  std::uint32_t bobSeq{env.seq(bob)};
-
2598 
-
2599  env(noop(alice), fee(16), seq(aliceSeq++), queued);
-
2600  env(noop(bob), fee(16), seq(bobSeq++), queued);
-
2601  env(noop(alice), fee(17), seq(aliceSeq++), queued);
-
2602  env(noop(bob), fee(17), seq(bobSeq++), queued);
-
2603  env(noop(alice), fee(18), seq(aliceSeq++), queued);
-
2604  env(noop(bob), fee(19), seq(bobSeq++), queued);
-
2605  env(noop(alice), fee(20), seq(aliceSeq++), queued);
-
2606  env(noop(bob), fee(20), seq(bobSeq++), queued);
-
2607  env(noop(alice), fee(21), seq(aliceSeq++), queued);
-
2608 
-
2609  // Queue is full now.
-
2610  checkMetrics(__LINE__, env, 10, 10, 6, 5, 385);
+
2586  env(noop(bob), fee(1000));
+
2587  env(noop(bob), fee(1000));
+
2588  env(noop(bob), fee(1000));
+
2589  checkMetrics(__LINE__, env, 0, 10, 6, 5, 256);
+
2590 
+
2591  // Use explicit fees so we can control which txn
+
2592  // will get dropped
+
2593  // This one gets into the queue, but gets dropped when the
+
2594  // higher fee one is added later.
+
2595  std::uint32_t const charlieSeq{env.seq(charlie)};
+
2596  env(noop(charlie), fee(15), seq(charlieSeq), queued);
+
2597 
+
2598  // These stay in the queue.
+
2599  std::uint32_t aliceSeq{env.seq(alice)};
+
2600  std::uint32_t bobSeq{env.seq(bob)};
+
2601 
+
2602  env(noop(alice), fee(16), seq(aliceSeq++), queued);
+
2603  env(noop(bob), fee(16), seq(bobSeq++), queued);
+
2604  env(noop(alice), fee(17), seq(aliceSeq++), queued);
+
2605  env(noop(bob), fee(17), seq(bobSeq++), queued);
+
2606  env(noop(alice), fee(18), seq(aliceSeq++), queued);
+
2607  env(noop(bob), fee(19), seq(bobSeq++), queued);
+
2608  env(noop(alice), fee(20), seq(aliceSeq++), queued);
+
2609  env(noop(bob), fee(20), seq(bobSeq++), queued);
+
2610  env(noop(alice), fee(21), seq(aliceSeq++), queued);
2611 
-
2612  // Try to add another transaction with the default (low) fee,
-
2613  // it should fail because the queue is full.
-
2614  env(noop(alice), seq(aliceSeq++), ter(telCAN_NOT_QUEUE_FULL));
-
2615 
-
2616  // Add another transaction, with a higher fee,
-
2617  // not high enough to get into the ledger, but high
-
2618  // enough to get into the queue (and kick Charlie's out)
-
2619  env(noop(bob), fee(22), seq(bobSeq++), queued);
-
2620 
-
2622 
-
2623  // That was the setup for the actual test :-). Now make
-
2624  // sure we get the right results if we try to add a
-
2625  // transaction for Charlie (who's in the queue, but has no queued
-
2626  // transactions) with the wrong sequence numbers.
-
2627  //
-
2628  // Charlie is paying a high enough fee to go straight into the
-
2629  // ledger in order to get into the vicinity of an assert which
-
2630  // should no longer fire :-).
-
2631  env(noop(charlie), fee(8000), seq(charlieSeq - 1), ter(tefPAST_SEQ));
-
2632  env(noop(charlie), fee(8000), seq(charlieSeq + 1), ter(terPRE_SEQ));
-
2633  env(noop(charlie), fee(8000), seq(charlieSeq), ter(tesSUCCESS));
-
2634  }
-
2635 
-
2636  void
-
2637  testRPC()
-
2638  {
-
2639  using namespace jtx;
-
2640  testcase("rpc");
-
2641 
-
2642  Env env(*this);
-
2643 
-
2644  auto fee = env.rpc("fee");
-
2645 
-
2646  if (BEAST_EXPECT(fee.isMember(jss::result)) &&
-
2647  BEAST_EXPECT(!RPC::contains_error(fee[jss::result])))
-
2648  {
-
2649  auto const& result = fee[jss::result];
-
2650  BEAST_EXPECT(
-
2651  result.isMember(jss::ledger_current_index) &&
-
2652  result[jss::ledger_current_index] == 3);
-
2653  BEAST_EXPECT(result.isMember(jss::current_ledger_size));
-
2654  BEAST_EXPECT(result.isMember(jss::current_queue_size));
-
2655  BEAST_EXPECT(result.isMember(jss::expected_ledger_size));
-
2656  BEAST_EXPECT(!result.isMember(jss::max_queue_size));
-
2657  BEAST_EXPECT(result.isMember(jss::drops));
-
2658  auto const& drops = result[jss::drops];
-
2659  BEAST_EXPECT(drops.isMember(jss::base_fee));
-
2660  BEAST_EXPECT(drops.isMember(jss::median_fee));
-
2661  BEAST_EXPECT(drops.isMember(jss::minimum_fee));
-
2662  BEAST_EXPECT(drops.isMember(jss::open_ledger_fee));
-
2663  BEAST_EXPECT(result.isMember(jss::levels));
-
2664  auto const& levels = result[jss::levels];
-
2665  BEAST_EXPECT(levels.isMember(jss::median_level));
-
2666  BEAST_EXPECT(levels.isMember(jss::minimum_level));
-
2667  BEAST_EXPECT(levels.isMember(jss::open_ledger_level));
-
2668  BEAST_EXPECT(levels.isMember(jss::reference_level));
-
2669  }
-
2670 
-
2671  env.close();
-
2672 
-
2673  fee = env.rpc("fee");
-
2674 
-
2675  if (BEAST_EXPECT(fee.isMember(jss::result)) &&
-
2676  BEAST_EXPECT(!RPC::contains_error(fee[jss::result])))
-
2677  {
-
2678  auto const& result = fee[jss::result];
-
2679  BEAST_EXPECT(
-
2680  result.isMember(jss::ledger_current_index) &&
-
2681  result[jss::ledger_current_index] == 4);
-
2682  BEAST_EXPECT(result.isMember(jss::current_ledger_size));
-
2683  BEAST_EXPECT(result.isMember(jss::current_queue_size));
-
2684  BEAST_EXPECT(result.isMember(jss::expected_ledger_size));
-
2685  BEAST_EXPECT(result.isMember(jss::max_queue_size));
-
2686  auto const& drops = result[jss::drops];
-
2687  BEAST_EXPECT(drops.isMember(jss::base_fee));
-
2688  BEAST_EXPECT(drops.isMember(jss::median_fee));
-
2689  BEAST_EXPECT(drops.isMember(jss::minimum_fee));
-
2690  BEAST_EXPECT(drops.isMember(jss::open_ledger_fee));
-
2691  BEAST_EXPECT(result.isMember(jss::levels));
-
2692  auto const& levels = result[jss::levels];
-
2693  BEAST_EXPECT(levels.isMember(jss::median_level));
-
2694  BEAST_EXPECT(levels.isMember(jss::minimum_level));
-
2695  BEAST_EXPECT(levels.isMember(jss::open_ledger_level));
-
2696  BEAST_EXPECT(levels.isMember(jss::reference_level));
-
2697  }
-
2698  }
-
2699 
-
2700  void
-
2701  testExpirationReplacement()
-
2702  {
-
2703  /* This test is based on a reported regression where a
-
2704  replacement candidate transaction found the tx it was trying
-
2705  to replace did not have `consequences` set
-
2706 
-
2707  Hypothesis: The queue had '22 through '25. At some point(s),
-
2708  both the original '22 and '23 expired and were removed from
-
2709  the queue. A second '22 was submitted, and the multi-tx logic
-
2710  did not kick in, because it matched the account's sequence
-
2711  number (a_seq == t_seq). The third '22 was submitted and found
-
2712  the '22 in the queue did not have consequences.
-
2713  */
-
2714  using namespace jtx;
-
2715  testcase("expiration replacement");
-
2716 
-
2717  Env env(
-
2718  *this,
-
2719  makeConfig(
-
2720  {{"minimum_txn_in_ledger_standalone", "1"},
-
2721  {"ledgers_in_queue", "10"},
-
2722  {"maximum_txn_per_account", "20"}}));
-
2723 
-
2724  // Alice will recreate the scenario. Bob will block.
-
2725  auto const alice = Account("alice");
-
2726  auto const bob = Account("bob");
-
2727 
-
2728  env.fund(XRP(500000), noripple(alice, bob));
-
2729  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
+
2612  // Queue is full now.
+
2613  checkMetrics(__LINE__, env, 10, 10, 6, 5, 385);
+
2614 
+
2615  // Try to add another transaction with the default (low) fee,
+
2616  // it should fail because the queue is full.
+
2617  env(noop(alice), seq(aliceSeq++), ter(telCAN_NOT_QUEUE_FULL));
+
2618 
+
2619  // Add another transaction, with a higher fee,
+
2620  // not high enough to get into the ledger, but high
+
2621  // enough to get into the queue (and kick Charlie's out)
+
2622  env(noop(bob), fee(22), seq(bobSeq++), queued);
+
2623 
+
2625 
+
2626  // That was the setup for the actual test :-). Now make
+
2627  // sure we get the right results if we try to add a
+
2628  // transaction for Charlie (who's in the queue, but has no queued
+
2629  // transactions) with the wrong sequence numbers.
+
2630  //
+
2631  // Charlie is paying a high enough fee to go straight into the
+
2632  // ledger in order to get into the vicinity of an assert which
+
2633  // should no longer fire :-).
+
2634  env(noop(charlie), fee(8000), seq(charlieSeq - 1), ter(tefPAST_SEQ));
+
2635  env(noop(charlie), fee(8000), seq(charlieSeq + 1), ter(terPRE_SEQ));
+
2636  env(noop(charlie), fee(8000), seq(charlieSeq), ter(tesSUCCESS));
+
2637  }
+
2638 
+
2639  void
+
2640  testRPC()
+
2641  {
+
2642  using namespace jtx;
+
2643  testcase("rpc");
+
2644 
+
2645  Env env(*this);
+
2646 
+
2647  auto fee = env.rpc("fee");
+
2648 
+
2649  if (BEAST_EXPECT(fee.isMember(jss::result)) &&
+
2650  BEAST_EXPECT(!RPC::contains_error(fee[jss::result])))
+
2651  {
+
2652  auto const& result = fee[jss::result];
+
2653  BEAST_EXPECT(
+
2654  result.isMember(jss::ledger_current_index) &&
+
2655  result[jss::ledger_current_index] == 3);
+
2656  BEAST_EXPECT(result.isMember(jss::current_ledger_size));
+
2657  BEAST_EXPECT(result.isMember(jss::current_queue_size));
+
2658  BEAST_EXPECT(result.isMember(jss::expected_ledger_size));
+
2659  BEAST_EXPECT(!result.isMember(jss::max_queue_size));
+
2660  BEAST_EXPECT(result.isMember(jss::drops));
+
2661  auto const& drops = result[jss::drops];
+
2662  BEAST_EXPECT(drops.isMember(jss::base_fee));
+
2663  BEAST_EXPECT(drops.isMember(jss::median_fee));
+
2664  BEAST_EXPECT(drops.isMember(jss::minimum_fee));
+
2665  BEAST_EXPECT(drops.isMember(jss::open_ledger_fee));
+
2666  BEAST_EXPECT(result.isMember(jss::levels));
+
2667  auto const& levels = result[jss::levels];
+
2668  BEAST_EXPECT(levels.isMember(jss::median_level));
+
2669  BEAST_EXPECT(levels.isMember(jss::minimum_level));
+
2670  BEAST_EXPECT(levels.isMember(jss::open_ledger_level));
+
2671  BEAST_EXPECT(levels.isMember(jss::reference_level));
+
2672  }
+
2673 
+
2674  env.close();
+
2675 
+
2676  fee = env.rpc("fee");
+
2677 
+
2678  if (BEAST_EXPECT(fee.isMember(jss::result)) &&
+
2679  BEAST_EXPECT(!RPC::contains_error(fee[jss::result])))
+
2680  {
+
2681  auto const& result = fee[jss::result];
+
2682  BEAST_EXPECT(
+
2683  result.isMember(jss::ledger_current_index) &&
+
2684  result[jss::ledger_current_index] == 4);
+
2685  BEAST_EXPECT(result.isMember(jss::current_ledger_size));
+
2686  BEAST_EXPECT(result.isMember(jss::current_queue_size));
+
2687  BEAST_EXPECT(result.isMember(jss::expected_ledger_size));
+
2688  BEAST_EXPECT(result.isMember(jss::max_queue_size));
+
2689  auto const& drops = result[jss::drops];
+
2690  BEAST_EXPECT(drops.isMember(jss::base_fee));
+
2691  BEAST_EXPECT(drops.isMember(jss::median_fee));
+
2692  BEAST_EXPECT(drops.isMember(jss::minimum_fee));
+
2693  BEAST_EXPECT(drops.isMember(jss::open_ledger_fee));
+
2694  BEAST_EXPECT(result.isMember(jss::levels));
+
2695  auto const& levels = result[jss::levels];
+
2696  BEAST_EXPECT(levels.isMember(jss::median_level));
+
2697  BEAST_EXPECT(levels.isMember(jss::minimum_level));
+
2698  BEAST_EXPECT(levels.isMember(jss::open_ledger_level));
+
2699  BEAST_EXPECT(levels.isMember(jss::reference_level));
+
2700  }
+
2701  }
+
2702 
+
2703  void
+
2704  testExpirationReplacement()
+
2705  {
+
2706  /* This test is based on a reported regression where a
+
2707  replacement candidate transaction found the tx it was trying
+
2708  to replace did not have `consequences` set
+
2709 
+
2710  Hypothesis: The queue had '22 through '25. At some point(s),
+
2711  both the original '22 and '23 expired and were removed from
+
2712  the queue. A second '22 was submitted, and the multi-tx logic
+
2713  did not kick in, because it matched the account's sequence
+
2714  number (a_seq == t_seq). The third '22 was submitted and found
+
2715  the '22 in the queue did not have consequences.
+
2716  */
+
2717  using namespace jtx;
+
2718  testcase("expiration replacement");
+
2719 
+
2720  Env env(
+
2721  *this,
+
2722  makeConfig(
+
2723  {{"minimum_txn_in_ledger_standalone", "1"},
+
2724  {"ledgers_in_queue", "10"},
+
2725  {"maximum_txn_per_account", "20"}}));
+
2726 
+
2727  // Alice will recreate the scenario. Bob will block.
+
2728  auto const alice = Account("alice");
+
2729  auto const bob = Account("bob");
2730 
-
2731  auto const aliceSeq = env.seq(alice);
-
2732  BEAST_EXPECT(env.current()->info().seq == 3);
-
2733  env(noop(alice),
-
2734  seq(aliceSeq),
-
2735  json(R"({"LastLedgerSequence":5})"),
-
2736  ter(terQUEUED));
-
2737  env(noop(alice),
-
2738  seq(aliceSeq + 1),
-
2739  json(R"({"LastLedgerSequence":5})"),
-
2740  ter(terQUEUED));
-
2741  env(noop(alice),
-
2742  seq(aliceSeq + 2),
-
2743  json(R"({"LastLedgerSequence":10})"),
-
2744  ter(terQUEUED));
-
2745  env(noop(alice),
-
2746  seq(aliceSeq + 3),
-
2747  json(R"({"LastLedgerSequence":11})"),
-
2748  ter(terQUEUED));
-
2749  checkMetrics(__LINE__, env, 4, std::nullopt, 2, 1, 256);
-
2750  auto const bobSeq = env.seq(bob);
-
2751  // Ledger 4 gets 3,
-
2752  // Ledger 5 gets 4,
-
2753  // Ledger 6 gets 5.
-
2754  for (int i = 0; i < 3 + 4 + 5; ++i)
-
2755  {
-
2756  env(noop(bob), seq(bobSeq + i), fee(200), ter(terQUEUED));
-
2757  }
-
2758  checkMetrics(__LINE__, env, 4 + 3 + 4 + 5, std::nullopt, 2, 1, 256);
-
2759  // Close ledger 3
-
2760  env.close();
-
2761  checkMetrics(__LINE__, env, 4 + 4 + 5, 20, 3, 2, 256);
-
2762  // Close ledger 4
+
2731  env.fund(XRP(500000), noripple(alice, bob));
+
2732  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
+
2733 
+
2734  auto const aliceSeq = env.seq(alice);
+
2735  BEAST_EXPECT(env.current()->info().seq == 3);
+
2736  env(noop(alice),
+
2737  seq(aliceSeq),
+
2738  json(R"({"LastLedgerSequence":5})"),
+
2739  ter(terQUEUED));
+
2740  env(noop(alice),
+
2741  seq(aliceSeq + 1),
+
2742  json(R"({"LastLedgerSequence":5})"),
+
2743  ter(terQUEUED));
+
2744  env(noop(alice),
+
2745  seq(aliceSeq + 2),
+
2746  json(R"({"LastLedgerSequence":10})"),
+
2747  ter(terQUEUED));
+
2748  env(noop(alice),
+
2749  seq(aliceSeq + 3),
+
2750  json(R"({"LastLedgerSequence":11})"),
+
2751  ter(terQUEUED));
+
2752  checkMetrics(__LINE__, env, 4, std::nullopt, 2, 1, 256);
+
2753  auto const bobSeq = env.seq(bob);
+
2754  // Ledger 4 gets 3,
+
2755  // Ledger 5 gets 4,
+
2756  // Ledger 6 gets 5.
+
2757  for (int i = 0; i < 3 + 4 + 5; ++i)
+
2758  {
+
2759  env(noop(bob), seq(bobSeq + i), fee(200), ter(terQUEUED));
+
2760  }
+
2761  checkMetrics(__LINE__, env, 4 + 3 + 4 + 5, std::nullopt, 2, 1, 256);
+
2762  // Close ledger 3
2763  env.close();
-
2764  checkMetrics(__LINE__, env, 4 + 5, 30, 4, 3, 256);
-
2765  // Close ledger 5
+
2764  checkMetrics(__LINE__, env, 4 + 4 + 5, 20, 3, 2, 256);
+
2765  // Close ledger 4
2766  env.close();
-
2767  // Alice's first two txs expired.
-
2768  checkMetrics(__LINE__, env, 2, 40, 5, 4, 256);
-
2769 
-
2770  // Because aliceSeq is missing, aliceSeq + 1 fails
-
2771  env(noop(alice), seq(aliceSeq + 1), ter(terPRE_SEQ));
+
2767  checkMetrics(__LINE__, env, 4 + 5, 30, 4, 3, 256);
+
2768  // Close ledger 5
+
2769  env.close();
+
2770  // Alice's first two txs expired.
+
2771  checkMetrics(__LINE__, env, 2, 40, 5, 4, 256);
2772 
-
2773  // Cannot fill the gap with a blocker since Alice's queue is not empty.
-
2774  env(fset(alice, asfAccountTxnID),
-
2775  seq(aliceSeq),
-
2776  ter(telCAN_NOT_QUEUE_BLOCKS));
-
2777  checkMetrics(__LINE__, env, 2, 40, 5, 4, 256);
-
2778 
-
2779  // However we can fill the gap with a non-blocker.
-
2780  env(noop(alice), seq(aliceSeq), fee(20), ter(terQUEUED));
-
2781  checkMetrics(__LINE__, env, 3, 40, 5, 4, 256);
-
2782 
-
2783  // Attempt to queue up a new aliceSeq + 1 tx that's a blocker.
-
2784  env(fset(alice, asfAccountTxnID),
-
2785  seq(aliceSeq + 1),
-
2786  ter(telCAN_NOT_QUEUE_BLOCKS));
-
2787  checkMetrics(__LINE__, env, 3, 40, 5, 4, 256);
-
2788 
-
2789  // Queue up a non-blocker replacement for aliceSeq + 1.
-
2790  env(noop(alice), seq(aliceSeq + 1), fee(20), ter(terQUEUED));
-
2791  checkMetrics(__LINE__, env, 4, 40, 5, 4, 256);
-
2792 
-
2793  // Close ledger 6
-
2794  env.close();
-
2795  // We expect that all of alice's queued tx's got into
-
2796  // the open ledger.
-
2797  checkMetrics(__LINE__, env, 0, 50, 4, 5, 256);
-
2798  BEAST_EXPECT(env.seq(alice) == aliceSeq + 4);
-
2799  }
-
2800 
-
2801  void
-
2802  testFullQueueGapFill()
-
2803  {
-
2804  // This test focuses on which gaps in queued transactions are
-
2805  // allowed to be filled even when the account's queue is full.
-
2806  using namespace jtx;
-
2807  testcase("full queue gap handling");
-
2808 
-
2809  Env env(
-
2810  *this,
-
2811  makeConfig(
-
2812  {{"minimum_txn_in_ledger_standalone", "1"},
-
2813  {"ledgers_in_queue", "10"},
-
2814  {"maximum_txn_per_account", "11"}}));
-
2815 
-
2816  // Alice will have the gaps. Bob will keep the queue busy with
-
2817  // high fee transactions so alice's transactions can expire to leave
-
2818  // gaps.
-
2819  auto const alice = Account("alice");
-
2820  auto const bob = Account("bob");
-
2821 
-
2822  env.fund(XRP(500000), noripple(alice, bob));
-
2823  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
+
2773  // Because aliceSeq is missing, aliceSeq + 1 fails
+
2774  env(noop(alice), seq(aliceSeq + 1), ter(terPRE_SEQ));
+
2775 
+
2776  // Cannot fill the gap with a blocker since Alice's queue is not empty.
+
2777  env(fset(alice, asfAccountTxnID),
+
2778  seq(aliceSeq),
+
2779  ter(telCAN_NOT_QUEUE_BLOCKS));
+
2780  checkMetrics(__LINE__, env, 2, 40, 5, 4, 256);
+
2781 
+
2782  // However we can fill the gap with a non-blocker.
+
2783  env(noop(alice), seq(aliceSeq), fee(20), ter(terQUEUED));
+
2784  checkMetrics(__LINE__, env, 3, 40, 5, 4, 256);
+
2785 
+
2786  // Attempt to queue up a new aliceSeq + 1 tx that's a blocker.
+
2787  env(fset(alice, asfAccountTxnID),
+
2788  seq(aliceSeq + 1),
+
2789  ter(telCAN_NOT_QUEUE_BLOCKS));
+
2790  checkMetrics(__LINE__, env, 3, 40, 5, 4, 256);
+
2791 
+
2792  // Queue up a non-blocker replacement for aliceSeq + 1.
+
2793  env(noop(alice), seq(aliceSeq + 1), fee(20), ter(terQUEUED));
+
2794  checkMetrics(__LINE__, env, 4, 40, 5, 4, 256);
+
2795 
+
2796  // Close ledger 6
+
2797  env.close();
+
2798  // We expect that all of alice's queued tx's got into
+
2799  // the open ledger.
+
2800  checkMetrics(__LINE__, env, 0, 50, 4, 5, 256);
+
2801  BEAST_EXPECT(env.seq(alice) == aliceSeq + 4);
+
2802  }
+
2803 
+
2804  void
+
2805  testFullQueueGapFill()
+
2806  {
+
2807  // This test focuses on which gaps in queued transactions are
+
2808  // allowed to be filled even when the account's queue is full.
+
2809  using namespace jtx;
+
2810  testcase("full queue gap handling");
+
2811 
+
2812  Env env(
+
2813  *this,
+
2814  makeConfig(
+
2815  {{"minimum_txn_in_ledger_standalone", "1"},
+
2816  {"ledgers_in_queue", "10"},
+
2817  {"maximum_txn_per_account", "11"}}));
+
2818 
+
2819  // Alice will have the gaps. Bob will keep the queue busy with
+
2820  // high fee transactions so alice's transactions can expire to leave
+
2821  // gaps.
+
2822  auto const alice = Account("alice");
+
2823  auto const bob = Account("bob");
2824 
-
2825  auto const aliceSeq = env.seq(alice);
-
2826  BEAST_EXPECT(env.current()->info().seq == 3);
+
2825  env.fund(XRP(500000), noripple(alice, bob));
+
2826  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2827 
-
2828  // Start by procuring tickets for alice to use to keep her queue full
-
2829  // without affecting the sequence gap that will appear later.
-
2830  env(ticket::create(alice, 11),
-
2831  seq(aliceSeq + 0),
-
2832  fee(201),
-
2833  ter(terQUEUED));
-
2834  env(noop(alice),
-
2835  seq(aliceSeq + 11),
-
2836  json(R"({"LastLedgerSequence":11})"),
-
2837  ter(terQUEUED));
-
2838  env(noop(alice),
-
2839  seq(aliceSeq + 12),
-
2840  json(R"({"LastLedgerSequence":11})"),
-
2841  ter(terQUEUED));
-
2842  env(noop(alice),
-
2843  seq(aliceSeq + 13),
-
2844  json(R"({"LastLedgerSequence":11})"),
-
2845  ter(terQUEUED));
-
2846  env(noop(alice),
-
2847  seq(aliceSeq + 14),
-
2848  json(R"({"LastLedgerSequence":11})"),
-
2849  ter(terQUEUED));
-
2850  env(noop(alice),
-
2851  seq(aliceSeq + 15),
-
2852  json(R"({"LastLedgerSequence":11})"),
-
2853  ter(terQUEUED));
-
2854  env(noop(alice),
-
2855  seq(aliceSeq + 16),
-
2856  json(R"({"LastLedgerSequence": 5})"),
-
2857  ter(terQUEUED));
-
2858  env(noop(alice),
-
2859  seq(aliceSeq + 17),
-
2860  json(R"({"LastLedgerSequence": 5})"),
-
2861  ter(terQUEUED));
-
2862  env(noop(alice),
-
2863  seq(aliceSeq + 18),
-
2864  json(R"({"LastLedgerSequence": 5})"),
-
2865  ter(terQUEUED));
-
2866  env(noop(alice),
-
2867  seq(aliceSeq + 19),
-
2868  json(R"({"LastLedgerSequence":11})"),
-
2869  ter(terQUEUED));
-
2870  checkMetrics(__LINE__, env, 10, std::nullopt, 2, 1, 256);
-
2871 
-
2872  auto const bobSeq = env.seq(bob);
-
2873  // Ledger 4 gets 2 from bob and 1 from alice,
-
2874  // Ledger 5 gets 4 from bob,
-
2875  // Ledger 6 gets 5 from bob.
-
2876  for (int i = 0; i < 2 + 4 + 5; ++i)
-
2877  {
-
2878  env(noop(bob), seq(bobSeq + i), fee(200), ter(terQUEUED));
-
2879  }
-
2880  checkMetrics(__LINE__, env, 10 + 2 + 4 + 5, std::nullopt, 2, 1, 256);
-
2881  // Close ledger 3
-
2882  env.close();
-
2883  checkMetrics(__LINE__, env, 9 + 4 + 5, 20, 3, 2, 256);
-
2884  BEAST_EXPECT(env.seq(alice) == aliceSeq + 12);
-
2885 
-
2886  // Close ledger 4
-
2887  env.close();
-
2888  checkMetrics(__LINE__, env, 9 + 5, 30, 4, 3, 256);
-
2889  BEAST_EXPECT(env.seq(alice) == aliceSeq + 12);
-
2890 
-
2891  // Close ledger 5
-
2892  env.close();
-
2893  // Three of Alice's txs expired.
-
2894  checkMetrics(__LINE__, env, 6, 40, 5, 4, 256);
-
2895  BEAST_EXPECT(env.seq(alice) == aliceSeq + 12);
-
2896 
-
2897  // Top off Alice's queue again using Tickets so the sequence gap is
-
2898  // unaffected.
-
2899  env(noop(alice), ticket::use(aliceSeq + 1), ter(terQUEUED));
-
2900  env(noop(alice), ticket::use(aliceSeq + 2), ter(terQUEUED));
-
2901  env(noop(alice), ticket::use(aliceSeq + 3), ter(terQUEUED));
-
2902  env(noop(alice), ticket::use(aliceSeq + 4), ter(terQUEUED));
-
2903  env(noop(alice), ticket::use(aliceSeq + 5), ter(terQUEUED));
-
2904  env(noop(alice), ticket::use(aliceSeq + 6), ter(telCAN_NOT_QUEUE_FULL));
-
2905  checkMetrics(__LINE__, env, 11, 40, 5, 4, 256);
-
2906 
-
2907  // Even though alice's queue is full we can still slide in a couple
-
2908  // more transactions because she has a sequence gap. But we
-
2909  // can only install a transaction that fills the bottom of the gap.
-
2910  // Explore that...
-
2911 
-
2912  // Verify that we can't queue a sequence-based transaction that
-
2913  // follows a gap.
-
2914  env(noop(alice), seq(aliceSeq + 20), ter(telCAN_NOT_QUEUE_FULL));
-
2915 
-
2916  // Verify that the transaction in front of the gap is still present
-
2917  // by attempting to replace it without a sufficient fee.
-
2918  env(noop(alice), seq(aliceSeq + 15), ter(telCAN_NOT_QUEUE_FEE));
-
2919 
-
2920  // We can't queue a transaction into the middle of the gap. It must
-
2921  // go at the front.
-
2922  env(noop(alice), seq(aliceSeq + 18), ter(telCAN_NOT_QUEUE_FULL));
-
2923  env(noop(alice), seq(aliceSeq + 17), ter(telCAN_NOT_QUEUE_FULL));
-
2924 
-
2925  // Successfully put this transaction into the front of the gap.
-
2926  env(noop(alice), seq(aliceSeq + 16), ter(terQUEUED));
+
2828  auto const aliceSeq = env.seq(alice);
+
2829  BEAST_EXPECT(env.current()->info().seq == 3);
+
2830 
+
2831  // Start by procuring tickets for alice to use to keep her queue full
+
2832  // without affecting the sequence gap that will appear later.
+
2833  env(ticket::create(alice, 11),
+
2834  seq(aliceSeq + 0),
+
2835  fee(201),
+
2836  ter(terQUEUED));
+
2837  env(noop(alice),
+
2838  seq(aliceSeq + 11),
+
2839  json(R"({"LastLedgerSequence":11})"),
+
2840  ter(terQUEUED));
+
2841  env(noop(alice),
+
2842  seq(aliceSeq + 12),
+
2843  json(R"({"LastLedgerSequence":11})"),
+
2844  ter(terQUEUED));
+
2845  env(noop(alice),
+
2846  seq(aliceSeq + 13),
+
2847  json(R"({"LastLedgerSequence":11})"),
+
2848  ter(terQUEUED));
+
2849  env(noop(alice),
+
2850  seq(aliceSeq + 14),
+
2851  json(R"({"LastLedgerSequence":11})"),
+
2852  ter(terQUEUED));
+
2853  env(noop(alice),
+
2854  seq(aliceSeq + 15),
+
2855  json(R"({"LastLedgerSequence":11})"),
+
2856  ter(terQUEUED));
+
2857  env(noop(alice),
+
2858  seq(aliceSeq + 16),
+
2859  json(R"({"LastLedgerSequence": 5})"),
+
2860  ter(terQUEUED));
+
2861  env(noop(alice),
+
2862  seq(aliceSeq + 17),
+
2863  json(R"({"LastLedgerSequence": 5})"),
+
2864  ter(terQUEUED));
+
2865  env(noop(alice),
+
2866  seq(aliceSeq + 18),
+
2867  json(R"({"LastLedgerSequence": 5})"),
+
2868  ter(terQUEUED));
+
2869  env(noop(alice),
+
2870  seq(aliceSeq + 19),
+
2871  json(R"({"LastLedgerSequence":11})"),
+
2872  ter(terQUEUED));
+
2873  checkMetrics(__LINE__, env, 10, std::nullopt, 2, 1, 256);
+
2874 
+
2875  auto const bobSeq = env.seq(bob);
+
2876  // Ledger 4 gets 2 from bob and 1 from alice,
+
2877  // Ledger 5 gets 4 from bob,
+
2878  // Ledger 6 gets 5 from bob.
+
2879  for (int i = 0; i < 2 + 4 + 5; ++i)
+
2880  {
+
2881  env(noop(bob), seq(bobSeq + i), fee(200), ter(terQUEUED));
+
2882  }
+
2883  checkMetrics(__LINE__, env, 10 + 2 + 4 + 5, std::nullopt, 2, 1, 256);
+
2884  // Close ledger 3
+
2885  env.close();
+
2886  checkMetrics(__LINE__, env, 9 + 4 + 5, 20, 3, 2, 256);
+
2887  BEAST_EXPECT(env.seq(alice) == aliceSeq + 12);
+
2888 
+
2889  // Close ledger 4
+
2890  env.close();
+
2891  checkMetrics(__LINE__, env, 9 + 5, 30, 4, 3, 256);
+
2892  BEAST_EXPECT(env.seq(alice) == aliceSeq + 12);
+
2893 
+
2894  // Close ledger 5
+
2895  env.close();
+
2896  // Three of Alice's txs expired.
+
2897  checkMetrics(__LINE__, env, 6, 40, 5, 4, 256);
+
2898  BEAST_EXPECT(env.seq(alice) == aliceSeq + 12);
+
2899 
+
2900  // Top off Alice's queue again using Tickets so the sequence gap is
+
2901  // unaffected.
+
2902  env(noop(alice), ticket::use(aliceSeq + 1), ter(terQUEUED));
+
2903  env(noop(alice), ticket::use(aliceSeq + 2), ter(terQUEUED));
+
2904  env(noop(alice), ticket::use(aliceSeq + 3), ter(terQUEUED));
+
2905  env(noop(alice), ticket::use(aliceSeq + 4), ter(terQUEUED));
+
2906  env(noop(alice), ticket::use(aliceSeq + 5), ter(terQUEUED));
+
2907  env(noop(alice), ticket::use(aliceSeq + 6), ter(telCAN_NOT_QUEUE_FULL));
+
2908  checkMetrics(__LINE__, env, 11, 40, 5, 4, 256);
+
2909 
+
2910  // Even though alice's queue is full we can still slide in a couple
+
2911  // more transactions because she has a sequence gap. But we
+
2912  // can only install a transaction that fills the bottom of the gap.
+
2913  // Explore that...
+
2914 
+
2915  // Verify that we can't queue a sequence-based transaction that
+
2916  // follows a gap.
+
2917  env(noop(alice), seq(aliceSeq + 20), ter(telCAN_NOT_QUEUE_FULL));
+
2918 
+
2919  // Verify that the transaction in front of the gap is still present
+
2920  // by attempting to replace it without a sufficient fee.
+
2921  env(noop(alice), seq(aliceSeq + 15), ter(telCAN_NOT_QUEUE_FEE));
+
2922 
+
2923  // We can't queue a transaction into the middle of the gap. It must
+
2924  // go at the front.
+
2925  env(noop(alice), seq(aliceSeq + 18), ter(telCAN_NOT_QUEUE_FULL));
+
2926  env(noop(alice), seq(aliceSeq + 17), ter(telCAN_NOT_QUEUE_FULL));
2927 
-
2928  // Still can't put a sequence-based transaction at the end of the gap.
-
2929  env(noop(alice), seq(aliceSeq + 18), ter(telCAN_NOT_QUEUE_FULL));
+
2928  // Successfully put this transaction into the front of the gap.
+
2929  env(noop(alice), seq(aliceSeq + 16), ter(terQUEUED));
2930 
-
2931  // But we can still fill the gap from the front.
-
2932  env(noop(alice), seq(aliceSeq + 17), ter(terQUEUED));
+
2931  // Still can't put a sequence-based transaction at the end of the gap.
+
2932  env(noop(alice), seq(aliceSeq + 18), ter(telCAN_NOT_QUEUE_FULL));
2933 
-
2934  // Finally we can fill in the entire gap.
-
2935  env(noop(alice), seq(aliceSeq + 18), ter(terQUEUED));
-
2936  checkMetrics(__LINE__, env, 14, 40, 5, 4, 256);
-
2937 
-
2938  // Verify that nothing can be added now that the gap is filled.
-
2939  env(noop(alice), seq(aliceSeq + 20), ter(telCAN_NOT_QUEUE_FULL));
+
2934  // But we can still fill the gap from the front.
+
2935  env(noop(alice), seq(aliceSeq + 17), ter(terQUEUED));
+
2936 
+
2937  // Finally we can fill in the entire gap.
+
2938  env(noop(alice), seq(aliceSeq + 18), ter(terQUEUED));
+
2939  checkMetrics(__LINE__, env, 14, 40, 5, 4, 256);
2940 
-
2941  // Close ledger 6. That removes some of alice's transactions,
-
2942  // but alice adds some more transaction(s) so expectedCount
-
2943  // may not reduce to 8.
-
2944  env.close();
-
2945  checkMetrics(__LINE__, env, 9, 50, 6, 5, 256);
-
2946  BEAST_EXPECT(env.seq(alice) == aliceSeq + 13);
-
2947 
-
2948  // Close ledger 7. That should remove 7 more of alice's transactions.
-
2949  env.close();
-
2950  checkMetrics(__LINE__, env, 2, 60, 7, 6, 256);
-
2951  BEAST_EXPECT(env.seq(alice) == aliceSeq + 19);
-
2952 
-
2953  // Close one last ledger to see all of alice's transactions moved
-
2954  // into the ledger, including the tickets
-
2955  env.close();
-
2956  checkMetrics(__LINE__, env, 0, 70, 2, 7, 256);
-
2957  BEAST_EXPECT(env.seq(alice) == aliceSeq + 21);
-
2958  }
-
2959 
-
2960  void
-
2961  testSignAndSubmitSequence()
-
2962  {
-
2963  testcase("Autofilled sequence should account for TxQ");
-
2964  using namespace jtx;
-
2965  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "6"}}));
-
2966  Env_ss envs(env);
-
2967  auto const& txQ = env.app().getTxQ();
-
2968 
-
2969  auto const alice = Account("alice");
-
2970  auto const bob = Account("bob");
-
2971  env.fund(XRP(100000), alice, bob);
-
2972 
-
2973  fillQueue(env, alice);
-
2974  checkMetrics(__LINE__, env, 0, std::nullopt, 7, 6, 256);
+
2941  // Verify that nothing can be added now that the gap is filled.
+
2942  env(noop(alice), seq(aliceSeq + 20), ter(telCAN_NOT_QUEUE_FULL));
+
2943 
+
2944  // Close ledger 6. That removes some of alice's transactions,
+
2945  // but alice adds some more transaction(s) so expectedCount
+
2946  // may not reduce to 8.
+
2947  env.close();
+
2948  checkMetrics(__LINE__, env, 9, 50, 6, 5, 256);
+
2949  BEAST_EXPECT(env.seq(alice) == aliceSeq + 13);
+
2950 
+
2951  // Close ledger 7. That should remove 7 more of alice's transactions.
+
2952  env.close();
+
2953  checkMetrics(__LINE__, env, 2, 60, 7, 6, 256);
+
2954  BEAST_EXPECT(env.seq(alice) == aliceSeq + 19);
+
2955 
+
2956  // Close one last ledger to see all of alice's transactions moved
+
2957  // into the ledger, including the tickets
+
2958  env.close();
+
2959  checkMetrics(__LINE__, env, 0, 70, 2, 7, 256);
+
2960  BEAST_EXPECT(env.seq(alice) == aliceSeq + 21);
+
2961  }
+
2962 
+
2963  void
+
2964  testSignAndSubmitSequence()
+
2965  {
+
2966  testcase("Autofilled sequence should account for TxQ");
+
2967  using namespace jtx;
+
2968  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "6"}}));
+
2969  Env_ss envs(env);
+
2970  auto const& txQ = env.app().getTxQ();
+
2971 
+
2972  auto const alice = Account("alice");
+
2973  auto const bob = Account("bob");
+
2974  env.fund(XRP(100000), alice, bob);
2975 
-
2976  // Queue up several transactions for alice sign-and-submit
-
2977  auto const aliceSeq = env.seq(alice);
-
2978  auto const lastLedgerSeq = env.current()->info().seq + 2;
-
2979 
-
2980  auto submitParams = Json::Value(Json::objectValue);
-
2981  for (int i = 0; i < 5; ++i)
-
2982  {
-
2983  if (i == 2)
-
2984  envs(
-
2985  noop(alice),
-
2986  fee(1000),
-
2987  seq(none),
-
2988  json(jss::LastLedgerSequence, lastLedgerSeq),
-
2989  ter(terQUEUED))(submitParams);
-
2990  else
-
2991  envs(noop(alice), fee(1000), seq(none), ter(terQUEUED))(
-
2992  submitParams);
-
2993  }
-
2994  checkMetrics(__LINE__, env, 5, std::nullopt, 7, 6, 256);
-
2995  {
-
2996  auto aliceStat = txQ.getAccountTxs(alice.id());
-
2997  SeqProxy seq = SeqProxy::sequence(aliceSeq);
-
2998  BEAST_EXPECT(aliceStat.size() == 5);
-
2999  for (auto const& tx : aliceStat)
-
3000  {
-
3001  BEAST_EXPECT(tx.seqProxy == seq);
-
3002  BEAST_EXPECT(tx.feeLevel == FeeLevel64{25600});
-
3003  if (seq.value() == aliceSeq + 2)
-
3004  {
-
3005  BEAST_EXPECT(
-
3006  tx.lastValid && *tx.lastValid == lastLedgerSeq);
-
3007  }
-
3008  else
-
3009  {
-
3010  BEAST_EXPECT(!tx.lastValid);
-
3011  }
-
3012  seq.advanceBy(1);
-
3013  }
-
3014  }
-
3015  // Put some txs in the queue for bob.
-
3016  // Give them a higher fee so they'll beat alice's.
-
3017  for (int i = 0; i < 8; ++i)
-
3018  envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
-
3019  checkMetrics(__LINE__, env, 13, std::nullopt, 7, 6, 256);
-
3020 
-
3021  env.close();
-
3022  checkMetrics(__LINE__, env, 5, 14, 8, 7, 256);
-
3023  // Put some more txs in the queue for bob.
-
3024  // Give them a higher fee so they'll beat alice's.
-
3025  fillQueue(env, bob);
-
3026  for (int i = 0; i < 9; ++i)
-
3027  envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
-
3028  checkMetrics(__LINE__, env, 14, 14, 8, 7, 25601);
-
3029  env.close();
-
3030  // Put some more txs in the queue for bob.
-
3031  // Give them a higher fee so they'll beat alice's.
-
3032  fillQueue(env, bob);
-
3033  for (int i = 0; i < 10; ++i)
-
3034  envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
-
3035  checkMetrics(__LINE__, env, 15, 16, 9, 8, 256);
-
3036  env.close();
-
3037  checkMetrics(__LINE__, env, 4, 18, 10, 9, 256);
-
3038  {
-
3039  // Bob has nothing left in the queue.
-
3040  auto bobStat = txQ.getAccountTxs(bob.id());
-
3041  BEAST_EXPECT(bobStat.empty());
-
3042  }
-
3043  // Verify alice's tx got dropped as we BEAST_EXPECT, and that there's
-
3044  // a gap in her queued txs.
-
3045  {
-
3046  auto aliceStat = txQ.getAccountTxs(alice.id());
-
3047  auto seq = aliceSeq;
-
3048  BEAST_EXPECT(aliceStat.size() == 4);
-
3049  for (auto const& tx : aliceStat)
-
3050  {
-
3051  // Skip over the missing one.
-
3052  if (seq == aliceSeq + 2)
-
3053  ++seq;
-
3054 
-
3055  BEAST_EXPECT(tx.seqProxy.isSeq() && tx.seqProxy.value() == seq);
-
3056  BEAST_EXPECT(tx.feeLevel == FeeLevel64{25600});
-
3057  BEAST_EXPECT(!tx.lastValid);
-
3058  ++seq;
-
3059  }
-
3060  }
-
3061  // Now, fill the gap.
-
3062  envs(noop(alice), fee(1000), seq(none), ter(terQUEUED))(submitParams);
-
3063  checkMetrics(__LINE__, env, 5, 18, 10, 9, 256);
-
3064  {
-
3065  auto aliceStat = txQ.getAccountTxs(alice.id());
-
3066  auto seq = aliceSeq;
-
3067  BEAST_EXPECT(aliceStat.size() == 5);
-
3068  for (auto const& tx : aliceStat)
-
3069  {
-
3070  BEAST_EXPECT(tx.seqProxy.isSeq() && tx.seqProxy.value() == seq);
-
3071  BEAST_EXPECT(tx.feeLevel == FeeLevel64{25600});
-
3072  BEAST_EXPECT(!tx.lastValid);
-
3073  ++seq;
-
3074  }
-
3075  }
-
3076 
-
3077  env.close();
-
3078  checkMetrics(__LINE__, env, 0, 20, 5, 10, 256);
-
3079  {
-
3080  // Bob's data has been cleaned up.
-
3081  auto bobStat = txQ.getAccountTxs(bob.id());
-
3082  BEAST_EXPECT(bobStat.empty());
-
3083  }
-
3084  {
-
3085  auto aliceStat = txQ.getAccountTxs(alice.id());
-
3086  BEAST_EXPECT(aliceStat.empty());
-
3087  }
-
3088  }
-
3089 
-
3090  void
-
3091  testAccountInfo()
-
3092  {
-
3093  using namespace jtx;
-
3094  testcase("account info");
-
3095 
-
3096  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
-
3097  Env_ss envs(env);
+
2976  fillQueue(env, alice);
+
2977  checkMetrics(__LINE__, env, 0, std::nullopt, 7, 6, 256);
+
2978 
+
2979  // Queue up several transactions for alice sign-and-submit
+
2980  auto const aliceSeq = env.seq(alice);
+
2981  auto const lastLedgerSeq = env.current()->info().seq + 2;
+
2982 
+
2983  auto submitParams = Json::Value(Json::objectValue);
+
2984  for (int i = 0; i < 5; ++i)
+
2985  {
+
2986  if (i == 2)
+
2987  envs(
+
2988  noop(alice),
+
2989  fee(1000),
+
2990  seq(none),
+
2991  json(jss::LastLedgerSequence, lastLedgerSeq),
+
2992  ter(terQUEUED))(submitParams);
+
2993  else
+
2994  envs(noop(alice), fee(1000), seq(none), ter(terQUEUED))(
+
2995  submitParams);
+
2996  }
+
2997  checkMetrics(__LINE__, env, 5, std::nullopt, 7, 6, 256);
+
2998  {
+
2999  auto aliceStat = txQ.getAccountTxs(alice.id());
+
3000  SeqProxy seq = SeqProxy::sequence(aliceSeq);
+
3001  BEAST_EXPECT(aliceStat.size() == 5);
+
3002  for (auto const& tx : aliceStat)
+
3003  {
+
3004  BEAST_EXPECT(tx.seqProxy == seq);
+
3005  BEAST_EXPECT(tx.feeLevel == FeeLevel64{25600});
+
3006  if (seq.value() == aliceSeq + 2)
+
3007  {
+
3008  BEAST_EXPECT(
+
3009  tx.lastValid && *tx.lastValid == lastLedgerSeq);
+
3010  }
+
3011  else
+
3012  {
+
3013  BEAST_EXPECT(!tx.lastValid);
+
3014  }
+
3015  seq.advanceBy(1);
+
3016  }
+
3017  }
+
3018  // Put some txs in the queue for bob.
+
3019  // Give them a higher fee so they'll beat alice's.
+
3020  for (int i = 0; i < 8; ++i)
+
3021  envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
+
3022  checkMetrics(__LINE__, env, 13, std::nullopt, 7, 6, 256);
+
3023 
+
3024  env.close();
+
3025  checkMetrics(__LINE__, env, 5, 14, 8, 7, 256);
+
3026  // Put some more txs in the queue for bob.
+
3027  // Give them a higher fee so they'll beat alice's.
+
3028  fillQueue(env, bob);
+
3029  for (int i = 0; i < 9; ++i)
+
3030  envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
+
3031  checkMetrics(__LINE__, env, 14, 14, 8, 7, 25601);
+
3032  env.close();
+
3033  // Put some more txs in the queue for bob.
+
3034  // Give them a higher fee so they'll beat alice's.
+
3035  fillQueue(env, bob);
+
3036  for (int i = 0; i < 10; ++i)
+
3037  envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
+
3038  checkMetrics(__LINE__, env, 15, 16, 9, 8, 256);
+
3039  env.close();
+
3040  checkMetrics(__LINE__, env, 4, 18, 10, 9, 256);
+
3041  {
+
3042  // Bob has nothing left in the queue.
+
3043  auto bobStat = txQ.getAccountTxs(bob.id());
+
3044  BEAST_EXPECT(bobStat.empty());
+
3045  }
+
3046  // Verify alice's tx got dropped as we BEAST_EXPECT, and that there's
+
3047  // a gap in her queued txs.
+
3048  {
+
3049  auto aliceStat = txQ.getAccountTxs(alice.id());
+
3050  auto seq = aliceSeq;
+
3051  BEAST_EXPECT(aliceStat.size() == 4);
+
3052  for (auto const& tx : aliceStat)
+
3053  {
+
3054  // Skip over the missing one.
+
3055  if (seq == aliceSeq + 2)
+
3056  ++seq;
+
3057 
+
3058  BEAST_EXPECT(tx.seqProxy.isSeq() && tx.seqProxy.value() == seq);
+
3059  BEAST_EXPECT(tx.feeLevel == FeeLevel64{25600});
+
3060  BEAST_EXPECT(!tx.lastValid);
+
3061  ++seq;
+
3062  }
+
3063  }
+
3064  // Now, fill the gap.
+
3065  envs(noop(alice), fee(1000), seq(none), ter(terQUEUED))(submitParams);
+
3066  checkMetrics(__LINE__, env, 5, 18, 10, 9, 256);
+
3067  {
+
3068  auto aliceStat = txQ.getAccountTxs(alice.id());
+
3069  auto seq = aliceSeq;
+
3070  BEAST_EXPECT(aliceStat.size() == 5);
+
3071  for (auto const& tx : aliceStat)
+
3072  {
+
3073  BEAST_EXPECT(tx.seqProxy.isSeq() && tx.seqProxy.value() == seq);
+
3074  BEAST_EXPECT(tx.feeLevel == FeeLevel64{25600});
+
3075  BEAST_EXPECT(!tx.lastValid);
+
3076  ++seq;
+
3077  }
+
3078  }
+
3079 
+
3080  env.close();
+
3081  checkMetrics(__LINE__, env, 0, 20, 5, 10, 256);
+
3082  {
+
3083  // Bob's data has been cleaned up.
+
3084  auto bobStat = txQ.getAccountTxs(bob.id());
+
3085  BEAST_EXPECT(bobStat.empty());
+
3086  }
+
3087  {
+
3088  auto aliceStat = txQ.getAccountTxs(alice.id());
+
3089  BEAST_EXPECT(aliceStat.empty());
+
3090  }
+
3091  }
+
3092 
+
3093  void
+
3094  testAccountInfo()
+
3095  {
+
3096  using namespace jtx;
+
3097  testcase("account info");
3098 
-
3099  Account const alice{"alice"};
-
3100  env.fund(XRP(1000000), alice);
-
3101  env.close();
-
3102 
-
3103  auto const withQueue =
-
3104  R"({ "account": ")" + alice.human() + R"(", "queue": true })";
-
3105  auto const withoutQueue = R"({ "account": ")" + alice.human() + R"("})";
-
3106  auto const prevLedgerWithQueue = R"({ "account": ")" + alice.human() +
-
3107  R"(", "queue": true, "ledger_index": 3 })";
-
3108  BEAST_EXPECT(env.current()->info().seq > 3);
-
3109 
-
3110  {
-
3111  // account_info without the "queue" argument.
-
3112  auto const info = env.rpc("json", "account_info", withoutQueue);
-
3113  BEAST_EXPECT(
-
3114  info.isMember(jss::result) &&
-
3115  info[jss::result].isMember(jss::account_data));
-
3116  BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data));
-
3117  }
-
3118  {
-
3119  // account_info with the "queue" argument.
-
3120  auto const info = env.rpc("json", "account_info", withQueue);
-
3121  BEAST_EXPECT(
-
3122  info.isMember(jss::result) &&
-
3123  info[jss::result].isMember(jss::account_data));
-
3124  auto const& result = info[jss::result];
-
3125  BEAST_EXPECT(result.isMember(jss::queue_data));
-
3126  auto const& queue_data = result[jss::queue_data];
-
3127  BEAST_EXPECT(queue_data.isObject());
-
3128  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
-
3129  BEAST_EXPECT(queue_data[jss::txn_count] == 0);
-
3130  BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
-
3131  BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
-
3132  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
-
3133  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
-
3134  BEAST_EXPECT(!queue_data.isMember(jss::transactions));
-
3135  }
-
3136  checkMetrics(__LINE__, env, 0, 6, 0, 3, 256);
-
3137 
-
3138  fillQueue(env, alice);
-
3139  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
+
3099  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
+
3100  Env_ss envs(env);
+
3101 
+
3102  Account const alice{"alice"};
+
3103  env.fund(XRP(1000000), alice);
+
3104  env.close();
+
3105 
+
3106  auto const withQueue =
+
3107  R"({ "account": ")" + alice.human() + R"(", "queue": true })";
+
3108  auto const withoutQueue = R"({ "account": ")" + alice.human() + R"("})";
+
3109  auto const prevLedgerWithQueue = R"({ "account": ")" + alice.human() +
+
3110  R"(", "queue": true, "ledger_index": 3 })";
+
3111  BEAST_EXPECT(env.current()->info().seq > 3);
+
3112 
+
3113  {
+
3114  // account_info without the "queue" argument.
+
3115  auto const info = env.rpc("json", "account_info", withoutQueue);
+
3116  BEAST_EXPECT(
+
3117  info.isMember(jss::result) &&
+
3118  info[jss::result].isMember(jss::account_data));
+
3119  BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data));
+
3120  }
+
3121  {
+
3122  // account_info with the "queue" argument.
+
3123  auto const info = env.rpc("json", "account_info", withQueue);
+
3124  BEAST_EXPECT(
+
3125  info.isMember(jss::result) &&
+
3126  info[jss::result].isMember(jss::account_data));
+
3127  auto const& result = info[jss::result];
+
3128  BEAST_EXPECT(result.isMember(jss::queue_data));
+
3129  auto const& queue_data = result[jss::queue_data];
+
3130  BEAST_EXPECT(queue_data.isObject());
+
3131  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
+
3132  BEAST_EXPECT(queue_data[jss::txn_count] == 0);
+
3133  BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
+
3134  BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
+
3135  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
+
3136  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
+
3137  BEAST_EXPECT(!queue_data.isMember(jss::transactions));
+
3138  }
+
3139  checkMetrics(__LINE__, env, 0, 6, 0, 3, 256);
3140 
-
3141  {
-
3142  auto const info = env.rpc("json", "account_info", withQueue);
-
3143  BEAST_EXPECT(
-
3144  info.isMember(jss::result) &&
-
3145  info[jss::result].isMember(jss::account_data));
-
3146  auto const& result = info[jss::result];
-
3147  BEAST_EXPECT(result.isMember(jss::queue_data));
-
3148  auto const& queue_data = result[jss::queue_data];
-
3149  BEAST_EXPECT(queue_data.isObject());
-
3150  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
-
3151  BEAST_EXPECT(queue_data[jss::txn_count] == 0);
-
3152  BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
-
3153  BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
-
3154  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
-
3155  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
-
3156  BEAST_EXPECT(!queue_data.isMember(jss::transactions));
-
3157  }
-
3158 
-
3159  auto submitParams = Json::Value(Json::objectValue);
-
3160  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
-
3161  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
-
3162  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
+
3141  fillQueue(env, alice);
+
3142  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
+
3143 
+
3144  {
+
3145  auto const info = env.rpc("json", "account_info", withQueue);
+
3146  BEAST_EXPECT(
+
3147  info.isMember(jss::result) &&
+
3148  info[jss::result].isMember(jss::account_data));
+
3149  auto const& result = info[jss::result];
+
3150  BEAST_EXPECT(result.isMember(jss::queue_data));
+
3151  auto const& queue_data = result[jss::queue_data];
+
3152  BEAST_EXPECT(queue_data.isObject());
+
3153  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
+
3154  BEAST_EXPECT(queue_data[jss::txn_count] == 0);
+
3155  BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
+
3156  BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
+
3157  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
+
3158  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
+
3159  BEAST_EXPECT(!queue_data.isMember(jss::transactions));
+
3160  }
+
3161 
+
3162  auto submitParams = Json::Value(Json::objectValue);
3163  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
-
3164  checkMetrics(__LINE__, env, 4, 6, 4, 3, 256);
-
3165 
-
3166  {
-
3167  auto const info = env.rpc("json", "account_info", withQueue);
-
3168  BEAST_EXPECT(
-
3169  info.isMember(jss::result) &&
-
3170  info[jss::result].isMember(jss::account_data));
-
3171  auto const& result = info[jss::result];
-
3172  auto const& data = result[jss::account_data];
-
3173  BEAST_EXPECT(result.isMember(jss::queue_data));
-
3174  auto const& queue_data = result[jss::queue_data];
-
3175  BEAST_EXPECT(queue_data.isObject());
-
3176  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
-
3177  BEAST_EXPECT(queue_data[jss::txn_count] == 4);
-
3178  BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
-
3179  BEAST_EXPECT(
-
3180  queue_data[jss::lowest_sequence] == data[jss::Sequence]);
-
3181  BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
+
3164  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
+
3165  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
+
3166  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
+
3167  checkMetrics(__LINE__, env, 4, 6, 4, 3, 256);
+
3168 
+
3169  {
+
3170  auto const info = env.rpc("json", "account_info", withQueue);
+
3171  BEAST_EXPECT(
+
3172  info.isMember(jss::result) &&
+
3173  info[jss::result].isMember(jss::account_data));
+
3174  auto const& result = info[jss::result];
+
3175  auto const& data = result[jss::account_data];
+
3176  BEAST_EXPECT(result.isMember(jss::queue_data));
+
3177  auto const& queue_data = result[jss::queue_data];
+
3178  BEAST_EXPECT(queue_data.isObject());
+
3179  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
+
3180  BEAST_EXPECT(queue_data[jss::txn_count] == 4);
+
3181  BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
3182  BEAST_EXPECT(
-
3183  queue_data[jss::highest_sequence] ==
-
3184  data[jss::Sequence].asUInt() +
-
3185  queue_data[jss::txn_count].asUInt() - 1);
-
3186  BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued));
-
3187  BEAST_EXPECT(queue_data[jss::auth_change_queued] == false);
-
3188  BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total));
-
3189  BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == "400");
-
3190  BEAST_EXPECT(queue_data.isMember(jss::transactions));
-
3191  auto const& queued = queue_data[jss::transactions];
-
3192  BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
-
3193  for (unsigned i = 0; i < queued.size(); ++i)
-
3194  {
-
3195  auto const& item = queued[i];
-
3196  BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
-
3197  BEAST_EXPECT(item[jss::fee_level] == "2560");
-
3198  BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
-
3199 
-
3200  BEAST_EXPECT(item.isMember(jss::fee));
-
3201  BEAST_EXPECT(item[jss::fee] == "100");
-
3202  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
-
3203  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
-
3204  BEAST_EXPECT(item.isMember(jss::auth_change));
-
3205  BEAST_EXPECT(item[jss::auth_change].asBool() == false);
-
3206  }
-
3207  }
-
3208 
-
3209  // Drain the queue so we can queue up a blocker.
-
3210  env.close();
-
3211  checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
-
3212 
-
3213  // Fill the ledger and then queue up a blocker.
-
3214  envs(noop(alice), seq(none))(submitParams);
+
3183  queue_data[jss::lowest_sequence] == data[jss::Sequence]);
+
3184  BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
+
3185  BEAST_EXPECT(
+
3186  queue_data[jss::highest_sequence] ==
+
3187  data[jss::Sequence].asUInt() +
+
3188  queue_data[jss::txn_count].asUInt() - 1);
+
3189  BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued));
+
3190  BEAST_EXPECT(queue_data[jss::auth_change_queued] == false);
+
3191  BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total));
+
3192  BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == "400");
+
3193  BEAST_EXPECT(queue_data.isMember(jss::transactions));
+
3194  auto const& queued = queue_data[jss::transactions];
+
3195  BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
+
3196  for (unsigned i = 0; i < queued.size(); ++i)
+
3197  {
+
3198  auto const& item = queued[i];
+
3199  BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
+
3200  BEAST_EXPECT(item[jss::fee_level] == "2560");
+
3201  BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
+
3202 
+
3203  BEAST_EXPECT(item.isMember(jss::fee));
+
3204  BEAST_EXPECT(item[jss::fee] == "100");
+
3205  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
+
3206  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
+
3207  BEAST_EXPECT(item.isMember(jss::auth_change));
+
3208  BEAST_EXPECT(item[jss::auth_change].asBool() == false);
+
3209  }
+
3210  }
+
3211 
+
3212  // Drain the queue so we can queue up a blocker.
+
3213  env.close();
+
3214  checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
3215 
-
3216  envs(
-
3217  fset(alice, asfAccountTxnID),
-
3218  fee(100),
-
3219  seq(none),
-
3220  json(jss::LastLedgerSequence, 10),
-
3221  ter(terQUEUED))(submitParams);
-
3222  checkMetrics(__LINE__, env, 1, 8, 5, 4, 256);
-
3223 
-
3224  {
-
3225  auto const info = env.rpc("json", "account_info", withQueue);
-
3226  BEAST_EXPECT(
-
3227  info.isMember(jss::result) &&
-
3228  info[jss::result].isMember(jss::account_data));
-
3229  auto const& result = info[jss::result];
-
3230  auto const& data = result[jss::account_data];
-
3231  BEAST_EXPECT(result.isMember(jss::queue_data));
-
3232  auto const& queue_data = result[jss::queue_data];
-
3233  BEAST_EXPECT(queue_data.isObject());
-
3234  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
-
3235  BEAST_EXPECT(queue_data[jss::txn_count] == 1);
-
3236  BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
-
3237  BEAST_EXPECT(
-
3238  queue_data[jss::lowest_sequence] == data[jss::Sequence]);
-
3239  BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
+
3216  // Fill the ledger and then queue up a blocker.
+
3217  envs(noop(alice), seq(none))(submitParams);
+
3218 
+
3219  envs(
+
3220  fset(alice, asfAccountTxnID),
+
3221  fee(100),
+
3222  seq(none),
+
3223  json(jss::LastLedgerSequence, 10),
+
3224  ter(terQUEUED))(submitParams);
+
3225  checkMetrics(__LINE__, env, 1, 8, 5, 4, 256);
+
3226 
+
3227  {
+
3228  auto const info = env.rpc("json", "account_info", withQueue);
+
3229  BEAST_EXPECT(
+
3230  info.isMember(jss::result) &&
+
3231  info[jss::result].isMember(jss::account_data));
+
3232  auto const& result = info[jss::result];
+
3233  auto const& data = result[jss::account_data];
+
3234  BEAST_EXPECT(result.isMember(jss::queue_data));
+
3235  auto const& queue_data = result[jss::queue_data];
+
3236  BEAST_EXPECT(queue_data.isObject());
+
3237  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
+
3238  BEAST_EXPECT(queue_data[jss::txn_count] == 1);
+
3239  BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
3240  BEAST_EXPECT(
-
3241  queue_data[jss::highest_sequence] ==
-
3242  data[jss::Sequence].asUInt() +
-
3243  queue_data[jss::txn_count].asUInt() - 1);
-
3244  BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued));
-
3245  BEAST_EXPECT(queue_data[jss::auth_change_queued] == true);
-
3246  BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total));
-
3247  BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == "100");
-
3248  BEAST_EXPECT(queue_data.isMember(jss::transactions));
-
3249  auto const& queued = queue_data[jss::transactions];
-
3250  BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
-
3251  for (unsigned i = 0; i < queued.size(); ++i)
-
3252  {
-
3253  auto const& item = queued[i];
-
3254  BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
-
3255  BEAST_EXPECT(item[jss::fee_level] == "2560");
-
3256  BEAST_EXPECT(item.isMember(jss::fee));
-
3257  BEAST_EXPECT(item[jss::fee] == "100");
-
3258  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
-
3259  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
-
3260  BEAST_EXPECT(item.isMember(jss::auth_change));
-
3261 
-
3262  if (i == queued.size() - 1)
-
3263  {
-
3264  BEAST_EXPECT(item[jss::auth_change].asBool() == true);
-
3265  BEAST_EXPECT(item.isMember(jss::LastLedgerSequence));
-
3266  BEAST_EXPECT(item[jss::LastLedgerSequence] == 10);
-
3267  }
-
3268  else
-
3269  {
-
3270  BEAST_EXPECT(item[jss::auth_change].asBool() == false);
-
3271  BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
-
3272  }
-
3273  }
-
3274  }
-
3275 
-
3276  envs(noop(alice), fee(100), seq(none), ter(telCAN_NOT_QUEUE_BLOCKED))(
-
3277  submitParams);
-
3278  checkMetrics(__LINE__, env, 1, 8, 5, 4, 256);
-
3279 
-
3280  {
-
3281  auto const info = env.rpc("json", "account_info", withQueue);
-
3282  BEAST_EXPECT(
-
3283  info.isMember(jss::result) &&
-
3284  info[jss::result].isMember(jss::account_data));
-
3285  auto const& result = info[jss::result];
-
3286  auto const& data = result[jss::account_data];
-
3287  BEAST_EXPECT(result.isMember(jss::queue_data));
-
3288  auto const& queue_data = result[jss::queue_data];
-
3289  BEAST_EXPECT(queue_data.isObject());
-
3290  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
-
3291  BEAST_EXPECT(queue_data[jss::txn_count] == 1);
-
3292  BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
-
3293  BEAST_EXPECT(
-
3294  queue_data[jss::lowest_sequence] == data[jss::Sequence]);
-
3295  BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
+
3241  queue_data[jss::lowest_sequence] == data[jss::Sequence]);
+
3242  BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
+
3243  BEAST_EXPECT(
+
3244  queue_data[jss::highest_sequence] ==
+
3245  data[jss::Sequence].asUInt() +
+
3246  queue_data[jss::txn_count].asUInt() - 1);
+
3247  BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued));
+
3248  BEAST_EXPECT(queue_data[jss::auth_change_queued] == true);
+
3249  BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total));
+
3250  BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == "100");
+
3251  BEAST_EXPECT(queue_data.isMember(jss::transactions));
+
3252  auto const& queued = queue_data[jss::transactions];
+
3253  BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
+
3254  for (unsigned i = 0; i < queued.size(); ++i)
+
3255  {
+
3256  auto const& item = queued[i];
+
3257  BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
+
3258  BEAST_EXPECT(item[jss::fee_level] == "2560");
+
3259  BEAST_EXPECT(item.isMember(jss::fee));
+
3260  BEAST_EXPECT(item[jss::fee] == "100");
+
3261  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
+
3262  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
+
3263  BEAST_EXPECT(item.isMember(jss::auth_change));
+
3264 
+
3265  if (i == queued.size() - 1)
+
3266  {
+
3267  BEAST_EXPECT(item[jss::auth_change].asBool() == true);
+
3268  BEAST_EXPECT(item.isMember(jss::LastLedgerSequence));
+
3269  BEAST_EXPECT(item[jss::LastLedgerSequence] == 10);
+
3270  }
+
3271  else
+
3272  {
+
3273  BEAST_EXPECT(item[jss::auth_change].asBool() == false);
+
3274  BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
+
3275  }
+
3276  }
+
3277  }
+
3278 
+
3279  envs(noop(alice), fee(100), seq(none), ter(telCAN_NOT_QUEUE_BLOCKED))(
+
3280  submitParams);
+
3281  checkMetrics(__LINE__, env, 1, 8, 5, 4, 256);
+
3282 
+
3283  {
+
3284  auto const info = env.rpc("json", "account_info", withQueue);
+
3285  BEAST_EXPECT(
+
3286  info.isMember(jss::result) &&
+
3287  info[jss::result].isMember(jss::account_data));
+
3288  auto const& result = info[jss::result];
+
3289  auto const& data = result[jss::account_data];
+
3290  BEAST_EXPECT(result.isMember(jss::queue_data));
+
3291  auto const& queue_data = result[jss::queue_data];
+
3292  BEAST_EXPECT(queue_data.isObject());
+
3293  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
+
3294  BEAST_EXPECT(queue_data[jss::txn_count] == 1);
+
3295  BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
3296  BEAST_EXPECT(
-
3297  queue_data[jss::highest_sequence] ==
-
3298  data[jss::Sequence].asUInt() +
-
3299  queue_data[jss::txn_count].asUInt() - 1);
-
3300  BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued));
-
3301  BEAST_EXPECT(queue_data[jss::auth_change_queued].asBool());
-
3302  BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total));
-
3303  BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == "100");
-
3304  BEAST_EXPECT(queue_data.isMember(jss::transactions));
-
3305  auto const& queued = queue_data[jss::transactions];
-
3306  BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
-
3307  for (unsigned i = 0; i < queued.size(); ++i)
-
3308  {
-
3309  auto const& item = queued[i];
-
3310  BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
-
3311  BEAST_EXPECT(item[jss::fee_level] == "2560");
-
3312 
-
3313  if (i == queued.size() - 1)
-
3314  {
-
3315  BEAST_EXPECT(item.isMember(jss::fee));
-
3316  BEAST_EXPECT(item[jss::fee] == "100");
-
3317  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
-
3318  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
-
3319  BEAST_EXPECT(item.isMember(jss::auth_change));
-
3320  BEAST_EXPECT(item[jss::auth_change].asBool());
-
3321  BEAST_EXPECT(item.isMember(jss::LastLedgerSequence));
-
3322  BEAST_EXPECT(item[jss::LastLedgerSequence] == 10);
-
3323  }
-
3324  else
-
3325  {
-
3326  BEAST_EXPECT(item.isMember(jss::fee));
-
3327  BEAST_EXPECT(item[jss::fee] == "100");
-
3328  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
-
3329  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
-
3330  BEAST_EXPECT(item.isMember(jss::auth_change));
-
3331  BEAST_EXPECT(!item[jss::auth_change].asBool());
-
3332  BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
-
3333  }
-
3334  }
-
3335  }
-
3336 
-
3337  {
-
3338  auto const info =
-
3339  env.rpc("json", "account_info", prevLedgerWithQueue);
-
3340  BEAST_EXPECT(
-
3341  info.isMember(jss::result) &&
-
3342  RPC::contains_error(info[jss::result]));
-
3343  }
-
3344 
-
3345  env.close();
-
3346  checkMetrics(__LINE__, env, 0, 10, 2, 5, 256);
-
3347  env.close();
-
3348  checkMetrics(__LINE__, env, 0, 10, 0, 5, 256);
-
3349 
-
3350  {
-
3351  auto const info = env.rpc("json", "account_info", withQueue);
-
3352  BEAST_EXPECT(
-
3353  info.isMember(jss::result) &&
-
3354  info[jss::result].isMember(jss::account_data));
-
3355  auto const& result = info[jss::result];
-
3356  BEAST_EXPECT(result.isMember(jss::queue_data));
-
3357  auto const& queue_data = result[jss::queue_data];
-
3358  BEAST_EXPECT(queue_data.isObject());
-
3359  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
-
3360  BEAST_EXPECT(queue_data[jss::txn_count] == 0);
-
3361  BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
-
3362  BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
-
3363  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
-
3364  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
-
3365  BEAST_EXPECT(!queue_data.isMember(jss::transactions));
-
3366  }
-
3367  }
-
3368 
-
3369  void
-
3370  testServerInfo()
-
3371  {
-
3372  using namespace jtx;
-
3373  testcase("server info");
-
3374 
-
3375  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
-
3376  Env_ss envs(env);
+
3297  queue_data[jss::lowest_sequence] == data[jss::Sequence]);
+
3298  BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
+
3299  BEAST_EXPECT(
+
3300  queue_data[jss::highest_sequence] ==
+
3301  data[jss::Sequence].asUInt() +
+
3302  queue_data[jss::txn_count].asUInt() - 1);
+
3303  BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued));
+
3304  BEAST_EXPECT(queue_data[jss::auth_change_queued].asBool());
+
3305  BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total));
+
3306  BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == "100");
+
3307  BEAST_EXPECT(queue_data.isMember(jss::transactions));
+
3308  auto const& queued = queue_data[jss::transactions];
+
3309  BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
+
3310  for (unsigned i = 0; i < queued.size(); ++i)
+
3311  {
+
3312  auto const& item = queued[i];
+
3313  BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
+
3314  BEAST_EXPECT(item[jss::fee_level] == "2560");
+
3315 
+
3316  if (i == queued.size() - 1)
+
3317  {
+
3318  BEAST_EXPECT(item.isMember(jss::fee));
+
3319  BEAST_EXPECT(item[jss::fee] == "100");
+
3320  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
+
3321  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
+
3322  BEAST_EXPECT(item.isMember(jss::auth_change));
+
3323  BEAST_EXPECT(item[jss::auth_change].asBool());
+
3324  BEAST_EXPECT(item.isMember(jss::LastLedgerSequence));
+
3325  BEAST_EXPECT(item[jss::LastLedgerSequence] == 10);
+
3326  }
+
3327  else
+
3328  {
+
3329  BEAST_EXPECT(item.isMember(jss::fee));
+
3330  BEAST_EXPECT(item[jss::fee] == "100");
+
3331  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
+
3332  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
+
3333  BEAST_EXPECT(item.isMember(jss::auth_change));
+
3334  BEAST_EXPECT(!item[jss::auth_change].asBool());
+
3335  BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
+
3336  }
+
3337  }
+
3338  }
+
3339 
+
3340  {
+
3341  auto const info =
+
3342  env.rpc("json", "account_info", prevLedgerWithQueue);
+
3343  BEAST_EXPECT(
+
3344  info.isMember(jss::result) &&
+
3345  RPC::contains_error(info[jss::result]));
+
3346  }
+
3347 
+
3348  env.close();
+
3349  checkMetrics(__LINE__, env, 0, 10, 2, 5, 256);
+
3350  env.close();
+
3351  checkMetrics(__LINE__, env, 0, 10, 0, 5, 256);
+
3352 
+
3353  {
+
3354  auto const info = env.rpc("json", "account_info", withQueue);
+
3355  BEAST_EXPECT(
+
3356  info.isMember(jss::result) &&
+
3357  info[jss::result].isMember(jss::account_data));
+
3358  auto const& result = info[jss::result];
+
3359  BEAST_EXPECT(result.isMember(jss::queue_data));
+
3360  auto const& queue_data = result[jss::queue_data];
+
3361  BEAST_EXPECT(queue_data.isObject());
+
3362  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
+
3363  BEAST_EXPECT(queue_data[jss::txn_count] == 0);
+
3364  BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
+
3365  BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
+
3366  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
+
3367  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
+
3368  BEAST_EXPECT(!queue_data.isMember(jss::transactions));
+
3369  }
+
3370  }
+
3371 
+
3372  void
+
3373  testServerInfo()
+
3374  {
+
3375  using namespace jtx;
+
3376  testcase("server info");
3377 
-
3378  Account const alice{"alice"};
-
3379  env.fund(XRP(1000000), alice);
-
3380  env.close();
-
3381 
-
3382  {
-
3383  auto const server_info = env.rpc("server_info");
-
3384  BEAST_EXPECT(
-
3385  server_info.isMember(jss::result) &&
-
3386  server_info[jss::result].isMember(jss::info));
-
3387  auto const& info = server_info[jss::result][jss::info];
-
3388  BEAST_EXPECT(
-
3389  info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
-
3390  BEAST_EXPECT(!info.isMember(jss::load_factor_server));
-
3391  BEAST_EXPECT(!info.isMember(jss::load_factor_local));
-
3392  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
-
3393  BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
-
3394  }
-
3395  {
-
3396  auto const server_state = env.rpc("server_state");
-
3397  auto const& state = server_state[jss::result][jss::state];
-
3398  BEAST_EXPECT(
-
3399  state.isMember(jss::load_factor) &&
-
3400  state[jss::load_factor] == 256);
+
3378  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
+
3379  Env_ss envs(env);
+
3380 
+
3381  Account const alice{"alice"};
+
3382  env.fund(XRP(1000000), alice);
+
3383  env.close();
+
3384 
+
3385  {
+
3386  auto const server_info = env.rpc("server_info");
+
3387  BEAST_EXPECT(
+
3388  server_info.isMember(jss::result) &&
+
3389  server_info[jss::result].isMember(jss::info));
+
3390  auto const& info = server_info[jss::result][jss::info];
+
3391  BEAST_EXPECT(
+
3392  info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
+
3393  BEAST_EXPECT(!info.isMember(jss::load_factor_server));
+
3394  BEAST_EXPECT(!info.isMember(jss::load_factor_local));
+
3395  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
+
3396  BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
+
3397  }
+
3398  {
+
3399  auto const server_state = env.rpc("server_state");
+
3400  auto const& state = server_state[jss::result][jss::state];
3401  BEAST_EXPECT(
-
3402  state.isMember(jss::load_base) && state[jss::load_base] == 256);
-
3403  BEAST_EXPECT(
-
3404  state.isMember(jss::load_factor_server) &&
-
3405  state[jss::load_factor_server] == 256);
+
3402  state.isMember(jss::load_factor) &&
+
3403  state[jss::load_factor] == 256);
+
3404  BEAST_EXPECT(
+
3405  state.isMember(jss::load_base) && state[jss::load_base] == 256);
3406  BEAST_EXPECT(
-
3407  state.isMember(jss::load_factor_fee_escalation) &&
-
3408  state[jss::load_factor_fee_escalation] == 256);
+
3407  state.isMember(jss::load_factor_server) &&
+
3408  state[jss::load_factor_server] == 256);
3409  BEAST_EXPECT(
-
3410  state.isMember(jss::load_factor_fee_queue) &&
-
3411  state[jss::load_factor_fee_queue] == 256);
+
3410  state.isMember(jss::load_factor_fee_escalation) &&
+
3411  state[jss::load_factor_fee_escalation] == 256);
3412  BEAST_EXPECT(
-
3413  state.isMember(jss::load_factor_fee_reference) &&
-
3414  state[jss::load_factor_fee_reference] == 256);
-
3415  }
-
3416 
-
3417  checkMetrics(__LINE__, env, 0, 6, 0, 3, 256);
-
3418 
-
3419  fillQueue(env, alice);
-
3420  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
+
3413  state.isMember(jss::load_factor_fee_queue) &&
+
3414  state[jss::load_factor_fee_queue] == 256);
+
3415  BEAST_EXPECT(
+
3416  state.isMember(jss::load_factor_fee_reference) &&
+
3417  state[jss::load_factor_fee_reference] == 256);
+
3418  }
+
3419 
+
3420  checkMetrics(__LINE__, env, 0, 6, 0, 3, 256);
3421 
-
3422  auto aliceSeq = env.seq(alice);
-
3423  auto submitParams = Json::Value(Json::objectValue);
-
3424  for (auto i = 0; i < 4; ++i)
-
3425  envs(noop(alice), fee(100), seq(aliceSeq + i), ter(terQUEUED))(
-
3426  submitParams);
-
3427  checkMetrics(__LINE__, env, 4, 6, 4, 3, 256);
-
3428 
-
3429  {
-
3430  auto const server_info = env.rpc("server_info");
-
3431  BEAST_EXPECT(
-
3432  server_info.isMember(jss::result) &&
-
3433  server_info[jss::result].isMember(jss::info));
-
3434  auto const& info = server_info[jss::result][jss::info];
-
3435  // Avoid double rounding issues by comparing to a range.
-
3436  BEAST_EXPECT(
-
3437  info.isMember(jss::load_factor) &&
-
3438  info[jss::load_factor] > 888.88 &&
-
3439  info[jss::load_factor] < 888.89);
-
3440  BEAST_EXPECT(
-
3441  info.isMember(jss::load_factor_server) &&
-
3442  info[jss::load_factor_server] == 1);
-
3443  BEAST_EXPECT(!info.isMember(jss::load_factor_local));
-
3444  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
-
3445  BEAST_EXPECT(
-
3446  info.isMember(jss::load_factor_fee_escalation) &&
-
3447  info[jss::load_factor_fee_escalation] > 888.88 &&
-
3448  info[jss::load_factor_fee_escalation] < 888.89);
-
3449  }
-
3450  {
-
3451  auto const server_state = env.rpc("server_state");
-
3452  auto const& state = server_state[jss::result][jss::state];
-
3453  BEAST_EXPECT(
-
3454  state.isMember(jss::load_factor) &&
-
3455  state[jss::load_factor] == 227555);
+
3422  fillQueue(env, alice);
+
3423  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
+
3424 
+
3425  auto aliceSeq = env.seq(alice);
+
3426  auto submitParams = Json::Value(Json::objectValue);
+
3427  for (auto i = 0; i < 4; ++i)
+
3428  envs(noop(alice), fee(100), seq(aliceSeq + i), ter(terQUEUED))(
+
3429  submitParams);
+
3430  checkMetrics(__LINE__, env, 4, 6, 4, 3, 256);
+
3431 
+
3432  {
+
3433  auto const server_info = env.rpc("server_info");
+
3434  BEAST_EXPECT(
+
3435  server_info.isMember(jss::result) &&
+
3436  server_info[jss::result].isMember(jss::info));
+
3437  auto const& info = server_info[jss::result][jss::info];
+
3438  // Avoid double rounding issues by comparing to a range.
+
3439  BEAST_EXPECT(
+
3440  info.isMember(jss::load_factor) &&
+
3441  info[jss::load_factor] > 888.88 &&
+
3442  info[jss::load_factor] < 888.89);
+
3443  BEAST_EXPECT(
+
3444  info.isMember(jss::load_factor_server) &&
+
3445  info[jss::load_factor_server] == 1);
+
3446  BEAST_EXPECT(!info.isMember(jss::load_factor_local));
+
3447  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
+
3448  BEAST_EXPECT(
+
3449  info.isMember(jss::load_factor_fee_escalation) &&
+
3450  info[jss::load_factor_fee_escalation] > 888.88 &&
+
3451  info[jss::load_factor_fee_escalation] < 888.89);
+
3452  }
+
3453  {
+
3454  auto const server_state = env.rpc("server_state");
+
3455  auto const& state = server_state[jss::result][jss::state];
3456  BEAST_EXPECT(
-
3457  state.isMember(jss::load_base) && state[jss::load_base] == 256);
-
3458  BEAST_EXPECT(
-
3459  state.isMember(jss::load_factor_server) &&
-
3460  state[jss::load_factor_server] == 256);
+
3457  state.isMember(jss::load_factor) &&
+
3458  state[jss::load_factor] == 227555);
+
3459  BEAST_EXPECT(
+
3460  state.isMember(jss::load_base) && state[jss::load_base] == 256);
3461  BEAST_EXPECT(
-
3462  state.isMember(jss::load_factor_fee_escalation) &&
-
3463  state[jss::load_factor_fee_escalation] == 227555);
+
3462  state.isMember(jss::load_factor_server) &&
+
3463  state[jss::load_factor_server] == 256);
3464  BEAST_EXPECT(
-
3465  state.isMember(jss::load_factor_fee_queue) &&
-
3466  state[jss::load_factor_fee_queue] == 256);
+
3465  state.isMember(jss::load_factor_fee_escalation) &&
+
3466  state[jss::load_factor_fee_escalation] == 227555);
3467  BEAST_EXPECT(
-
3468  state.isMember(jss::load_factor_fee_reference) &&
-
3469  state[jss::load_factor_fee_reference] == 256);
-
3470  }
-
3471 
-
3472  env.app().getFeeTrack().setRemoteFee(256000);
-
3473 
-
3474  {
-
3475  auto const server_info = env.rpc("server_info");
-
3476  BEAST_EXPECT(
-
3477  server_info.isMember(jss::result) &&
-
3478  server_info[jss::result].isMember(jss::info));
-
3479  auto const& info = server_info[jss::result][jss::info];
-
3480  // Avoid double rounding issues by comparing to a range.
-
3481  BEAST_EXPECT(
-
3482  info.isMember(jss::load_factor) &&
-
3483  info[jss::load_factor] == 1000);
-
3484  BEAST_EXPECT(!info.isMember(jss::load_factor_server));
-
3485  BEAST_EXPECT(!info.isMember(jss::load_factor_local));
-
3486  BEAST_EXPECT(
-
3487  info.isMember(jss::load_factor_net) &&
-
3488  info[jss::load_factor_net] == 1000);
+
3468  state.isMember(jss::load_factor_fee_queue) &&
+
3469  state[jss::load_factor_fee_queue] == 256);
+
3470  BEAST_EXPECT(
+
3471  state.isMember(jss::load_factor_fee_reference) &&
+
3472  state[jss::load_factor_fee_reference] == 256);
+
3473  }
+
3474 
+
3475  env.app().getFeeTrack().setRemoteFee(256000);
+
3476 
+
3477  {
+
3478  auto const server_info = env.rpc("server_info");
+
3479  BEAST_EXPECT(
+
3480  server_info.isMember(jss::result) &&
+
3481  server_info[jss::result].isMember(jss::info));
+
3482  auto const& info = server_info[jss::result][jss::info];
+
3483  // Avoid double rounding issues by comparing to a range.
+
3484  BEAST_EXPECT(
+
3485  info.isMember(jss::load_factor) &&
+
3486  info[jss::load_factor] == 1000);
+
3487  BEAST_EXPECT(!info.isMember(jss::load_factor_server));
+
3488  BEAST_EXPECT(!info.isMember(jss::load_factor_local));
3489  BEAST_EXPECT(
-
3490  info.isMember(jss::load_factor_fee_escalation) &&
-
3491  info[jss::load_factor_fee_escalation] > 888.88 &&
-
3492  info[jss::load_factor_fee_escalation] < 888.89);
-
3493  }
-
3494  {
-
3495  auto const server_state = env.rpc("server_state");
-
3496  auto const& state = server_state[jss::result][jss::state];
-
3497  BEAST_EXPECT(
-
3498  state.isMember(jss::load_factor) &&
-
3499  state[jss::load_factor] == 256000);
+
3490  info.isMember(jss::load_factor_net) &&
+
3491  info[jss::load_factor_net] == 1000);
+
3492  BEAST_EXPECT(
+
3493  info.isMember(jss::load_factor_fee_escalation) &&
+
3494  info[jss::load_factor_fee_escalation] > 888.88 &&
+
3495  info[jss::load_factor_fee_escalation] < 888.89);
+
3496  }
+
3497  {
+
3498  auto const server_state = env.rpc("server_state");
+
3499  auto const& state = server_state[jss::result][jss::state];
3500  BEAST_EXPECT(
-
3501  state.isMember(jss::load_base) && state[jss::load_base] == 256);
-
3502  BEAST_EXPECT(
-
3503  state.isMember(jss::load_factor_server) &&
-
3504  state[jss::load_factor_server] == 256000);
+
3501  state.isMember(jss::load_factor) &&
+
3502  state[jss::load_factor] == 256000);
+
3503  BEAST_EXPECT(
+
3504  state.isMember(jss::load_base) && state[jss::load_base] == 256);
3505  BEAST_EXPECT(
-
3506  state.isMember(jss::load_factor_fee_escalation) &&
-
3507  state[jss::load_factor_fee_escalation] == 227555);
+
3506  state.isMember(jss::load_factor_server) &&
+
3507  state[jss::load_factor_server] == 256000);
3508  BEAST_EXPECT(
-
3509  state.isMember(jss::load_factor_fee_queue) &&
-
3510  state[jss::load_factor_fee_queue] == 256);
+
3509  state.isMember(jss::load_factor_fee_escalation) &&
+
3510  state[jss::load_factor_fee_escalation] == 227555);
3511  BEAST_EXPECT(
-
3512  state.isMember(jss::load_factor_fee_reference) &&
-
3513  state[jss::load_factor_fee_reference] == 256);
-
3514  }
-
3515 
-
3516  env.app().getFeeTrack().setRemoteFee(256);
-
3517 
-
3518  // Increase the server load
-
3519  for (int i = 0; i < 5; ++i)
-
3520  env.app().getFeeTrack().raiseLocalFee();
-
3521  BEAST_EXPECT(env.app().getFeeTrack().getLoadFactor() == 625);
-
3522 
-
3523  {
-
3524  auto const server_info = env.rpc("server_info");
-
3525  BEAST_EXPECT(
-
3526  server_info.isMember(jss::result) &&
-
3527  server_info[jss::result].isMember(jss::info));
-
3528  auto const& info = server_info[jss::result][jss::info];
-
3529  // Avoid double rounding issues by comparing to a range.
-
3530  BEAST_EXPECT(
-
3531  info.isMember(jss::load_factor) &&
-
3532  info[jss::load_factor] > 888.88 &&
-
3533  info[jss::load_factor] < 888.89);
-
3534  // There can be a race between LoadManager lowering the fee,
-
3535  // and the call to server_info, so check a wide range.
-
3536  // The important thing is that it's not 1.
-
3537  BEAST_EXPECT(
-
3538  info.isMember(jss::load_factor_server) &&
-
3539  info[jss::load_factor_server] > 1.245 &&
-
3540  info[jss::load_factor_server] < 2.4415);
-
3541  BEAST_EXPECT(
-
3542  info.isMember(jss::load_factor_local) &&
-
3543  info[jss::load_factor_local] > 1.245 &&
-
3544  info[jss::load_factor_local] < 2.4415);
-
3545  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
-
3546  BEAST_EXPECT(
-
3547  info.isMember(jss::load_factor_fee_escalation) &&
-
3548  info[jss::load_factor_fee_escalation] > 888.88 &&
-
3549  info[jss::load_factor_fee_escalation] < 888.89);
-
3550  }
-
3551  {
-
3552  auto const server_state = env.rpc("server_state");
-
3553  auto const& state = server_state[jss::result][jss::state];
-
3554  BEAST_EXPECT(
-
3555  state.isMember(jss::load_factor) &&
-
3556  state[jss::load_factor] == 227555);
+
3512  state.isMember(jss::load_factor_fee_queue) &&
+
3513  state[jss::load_factor_fee_queue] == 256);
+
3514  BEAST_EXPECT(
+
3515  state.isMember(jss::load_factor_fee_reference) &&
+
3516  state[jss::load_factor_fee_reference] == 256);
+
3517  }
+
3518 
+
3519  env.app().getFeeTrack().setRemoteFee(256);
+
3520 
+
3521  // Increase the server load
+
3522  for (int i = 0; i < 5; ++i)
+
3523  env.app().getFeeTrack().raiseLocalFee();
+
3524  BEAST_EXPECT(env.app().getFeeTrack().getLoadFactor() == 625);
+
3525 
+
3526  {
+
3527  auto const server_info = env.rpc("server_info");
+
3528  BEAST_EXPECT(
+
3529  server_info.isMember(jss::result) &&
+
3530  server_info[jss::result].isMember(jss::info));
+
3531  auto const& info = server_info[jss::result][jss::info];
+
3532  // Avoid double rounding issues by comparing to a range.
+
3533  BEAST_EXPECT(
+
3534  info.isMember(jss::load_factor) &&
+
3535  info[jss::load_factor] > 888.88 &&
+
3536  info[jss::load_factor] < 888.89);
+
3537  // There can be a race between LoadManager lowering the fee,
+
3538  // and the call to server_info, so check a wide range.
+
3539  // The important thing is that it's not 1.
+
3540  BEAST_EXPECT(
+
3541  info.isMember(jss::load_factor_server) &&
+
3542  info[jss::load_factor_server] > 1.245 &&
+
3543  info[jss::load_factor_server] < 2.4415);
+
3544  BEAST_EXPECT(
+
3545  info.isMember(jss::load_factor_local) &&
+
3546  info[jss::load_factor_local] > 1.245 &&
+
3547  info[jss::load_factor_local] < 2.4415);
+
3548  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
+
3549  BEAST_EXPECT(
+
3550  info.isMember(jss::load_factor_fee_escalation) &&
+
3551  info[jss::load_factor_fee_escalation] > 888.88 &&
+
3552  info[jss::load_factor_fee_escalation] < 888.89);
+
3553  }
+
3554  {
+
3555  auto const server_state = env.rpc("server_state");
+
3556  auto const& state = server_state[jss::result][jss::state];
3557  BEAST_EXPECT(
-
3558  state.isMember(jss::load_base) && state[jss::load_base] == 256);
-
3559  // There can be a race between LoadManager lowering the fee,
-
3560  // and the call to server_info, so check a wide range.
-
3561  // The important thing is that it's not 256.
-
3562  BEAST_EXPECT(
-
3563  state.isMember(jss::load_factor_server) &&
-
3564  state[jss::load_factor_server] >= 320 &&
-
3565  state[jss::load_factor_server] <= 625);
-
3566  BEAST_EXPECT(
-
3567  state.isMember(jss::load_factor_fee_escalation) &&
-
3568  state[jss::load_factor_fee_escalation] == 227555);
+
3558  state.isMember(jss::load_factor) &&
+
3559  state[jss::load_factor] == 227555);
+
3560  BEAST_EXPECT(
+
3561  state.isMember(jss::load_base) && state[jss::load_base] == 256);
+
3562  // There can be a race between LoadManager lowering the fee,
+
3563  // and the call to server_info, so check a wide range.
+
3564  // The important thing is that it's not 256.
+
3565  BEAST_EXPECT(
+
3566  state.isMember(jss::load_factor_server) &&
+
3567  state[jss::load_factor_server] >= 320 &&
+
3568  state[jss::load_factor_server] <= 625);
3569  BEAST_EXPECT(
-
3570  state.isMember(jss::load_factor_fee_queue) &&
-
3571  state[jss::load_factor_fee_queue] == 256);
+
3570  state.isMember(jss::load_factor_fee_escalation) &&
+
3571  state[jss::load_factor_fee_escalation] == 227555);
3572  BEAST_EXPECT(
-
3573  state.isMember(jss::load_factor_fee_reference) &&
-
3574  state[jss::load_factor_fee_reference] == 256);
-
3575  }
-
3576 
-
3577  env.close();
-
3578 
-
3579  {
-
3580  auto const server_info = env.rpc("server_info");
-
3581  BEAST_EXPECT(
-
3582  server_info.isMember(jss::result) &&
-
3583  server_info[jss::result].isMember(jss::info));
-
3584  auto const& info = server_info[jss::result][jss::info];
-
3585  // Avoid double rounding issues by comparing to a range.
-
3586 
-
3587  // There can be a race between LoadManager lowering the fee,
-
3588  // and the call to server_info, so check a wide range.
-
3589  // The important thing is that it's not 1.
-
3590  BEAST_EXPECT(
-
3591  info.isMember(jss::load_factor) &&
-
3592  info[jss::load_factor] > 1.245 &&
-
3593  info[jss::load_factor] < 2.4415);
-
3594  BEAST_EXPECT(!info.isMember(jss::load_factor_server));
-
3595  BEAST_EXPECT(
-
3596  info.isMember(jss::load_factor_local) &&
-
3597  info[jss::load_factor_local] > 1.245 &&
-
3598  info[jss::load_factor_local] < 2.4415);
-
3599  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
-
3600  BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
-
3601  }
-
3602  {
-
3603  auto const server_state = env.rpc("server_state");
-
3604  auto const& state = server_state[jss::result][jss::state];
-
3605  BEAST_EXPECT(
-
3606  state.isMember(jss::load_factor) &&
-
3607  state[jss::load_factor] >= 320 &&
-
3608  state[jss::load_factor] <= 625);
-
3609  BEAST_EXPECT(
-
3610  state.isMember(jss::load_base) && state[jss::load_base] == 256);
-
3611  // There can be a race between LoadManager lowering the fee,
-
3612  // and the call to server_info, so check a wide range.
-
3613  // The important thing is that it's not 256.
-
3614  BEAST_EXPECT(
-
3615  state.isMember(jss::load_factor_server) &&
-
3616  state[jss::load_factor_server] >= 320 &&
-
3617  state[jss::load_factor_server] <= 625);
-
3618  BEAST_EXPECT(
-
3619  state.isMember(jss::load_factor_fee_escalation) &&
-
3620  state[jss::load_factor_fee_escalation] == 256);
+
3573  state.isMember(jss::load_factor_fee_queue) &&
+
3574  state[jss::load_factor_fee_queue] == 256);
+
3575  BEAST_EXPECT(
+
3576  state.isMember(jss::load_factor_fee_reference) &&
+
3577  state[jss::load_factor_fee_reference] == 256);
+
3578  }
+
3579 
+
3580  env.close();
+
3581 
+
3582  {
+
3583  auto const server_info = env.rpc("server_info");
+
3584  BEAST_EXPECT(
+
3585  server_info.isMember(jss::result) &&
+
3586  server_info[jss::result].isMember(jss::info));
+
3587  auto const& info = server_info[jss::result][jss::info];
+
3588  // Avoid double rounding issues by comparing to a range.
+
3589 
+
3590  // There can be a race between LoadManager lowering the fee,
+
3591  // and the call to server_info, so check a wide range.
+
3592  // The important thing is that it's not 1.
+
3593  BEAST_EXPECT(
+
3594  info.isMember(jss::load_factor) &&
+
3595  info[jss::load_factor] > 1.245 &&
+
3596  info[jss::load_factor] < 2.4415);
+
3597  BEAST_EXPECT(!info.isMember(jss::load_factor_server));
+
3598  BEAST_EXPECT(
+
3599  info.isMember(jss::load_factor_local) &&
+
3600  info[jss::load_factor_local] > 1.245 &&
+
3601  info[jss::load_factor_local] < 2.4415);
+
3602  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
+
3603  BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
+
3604  }
+
3605  {
+
3606  auto const server_state = env.rpc("server_state");
+
3607  auto const& state = server_state[jss::result][jss::state];
+
3608  BEAST_EXPECT(
+
3609  state.isMember(jss::load_factor) &&
+
3610  state[jss::load_factor] >= 320 &&
+
3611  state[jss::load_factor] <= 625);
+
3612  BEAST_EXPECT(
+
3613  state.isMember(jss::load_base) && state[jss::load_base] == 256);
+
3614  // There can be a race between LoadManager lowering the fee,
+
3615  // and the call to server_info, so check a wide range.
+
3616  // The important thing is that it's not 256.
+
3617  BEAST_EXPECT(
+
3618  state.isMember(jss::load_factor_server) &&
+
3619  state[jss::load_factor_server] >= 320 &&
+
3620  state[jss::load_factor_server] <= 625);
3621  BEAST_EXPECT(
-
3622  state.isMember(jss::load_factor_fee_queue) &&
-
3623  state[jss::load_factor_fee_queue] == 256);
+
3622  state.isMember(jss::load_factor_fee_escalation) &&
+
3623  state[jss::load_factor_fee_escalation] == 256);
3624  BEAST_EXPECT(
-
3625  state.isMember(jss::load_factor_fee_reference) &&
-
3626  state[jss::load_factor_fee_reference] == 256);
-
3627  }
-
3628  }
-
3629 
-
3630  void
-
3631  testServerSubscribe()
-
3632  {
-
3633  using namespace jtx;
-
3634  testcase("server subscribe");
-
3635 
-
3636  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
-
3637 
-
3638  Json::Value stream;
-
3639  stream[jss::streams] = Json::arrayValue;
-
3640  stream[jss::streams].append("server");
-
3641  auto wsc = makeWSClient(env.app().config());
-
3642  {
-
3643  auto jv = wsc->invoke("subscribe", stream);
-
3644  BEAST_EXPECT(jv[jss::status] == "success");
-
3645  }
-
3646 
-
3647  Account a{"a"}, b{"b"}, c{"c"}, d{"d"}, e{"e"}, f{"f"}, g{"g"}, h{"h"},
-
3648  i{"i"};
+
3625  state.isMember(jss::load_factor_fee_queue) &&
+
3626  state[jss::load_factor_fee_queue] == 256);
+
3627  BEAST_EXPECT(
+
3628  state.isMember(jss::load_factor_fee_reference) &&
+
3629  state[jss::load_factor_fee_reference] == 256);
+
3630  }
+
3631  }
+
3632 
+
3633  void
+
3634  testServerSubscribe()
+
3635  {
+
3636  using namespace jtx;
+
3637  testcase("server subscribe");
+
3638 
+
3639  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
+
3640 
+
3641  Json::Value stream;
+
3642  stream[jss::streams] = Json::arrayValue;
+
3643  stream[jss::streams].append("server");
+
3644  auto wsc = makeWSClient(env.app().config());
+
3645  {
+
3646  auto jv = wsc->invoke("subscribe", stream);
+
3647  BEAST_EXPECT(jv[jss::status] == "success");
+
3648  }
3649 
-
3650  // Fund the first few accounts at non escalated fee
-
3651  env.fund(XRP(50000), noripple(a, b, c, d));
-
3652  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
-
3653 
-
3654  // First transaction establishes the messaging
-
3655  using namespace std::chrono_literals;
-
3656  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
-
3657  return jv[jss::type] == "serverStatus" &&
-
3658  jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
-
3659  jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
-
3660  jv.isMember(jss::load_factor_server) &&
-
3661  jv[jss::load_factor_server] == 256 &&
-
3662  jv.isMember(jss::load_factor_fee_escalation) &&
-
3663  jv[jss::load_factor_fee_escalation] == 256 &&
-
3664  jv.isMember(jss::load_factor_fee_queue) &&
-
3665  jv[jss::load_factor_fee_queue] == 256 &&
-
3666  jv.isMember(jss::load_factor_fee_reference) &&
-
3667  jv[jss::load_factor_fee_reference] == 256;
-
3668  }));
-
3669  // Last transaction escalates the fee
-
3670  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
-
3671  return jv[jss::type] == "serverStatus" &&
-
3672  jv.isMember(jss::load_factor) &&
-
3673  jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
-
3674  jv[jss::load_base] == 256 &&
-
3675  jv.isMember(jss::load_factor_server) &&
-
3676  jv[jss::load_factor_server] == 256 &&
-
3677  jv.isMember(jss::load_factor_fee_escalation) &&
-
3678  jv[jss::load_factor_fee_escalation] == 227555 &&
-
3679  jv.isMember(jss::load_factor_fee_queue) &&
-
3680  jv[jss::load_factor_fee_queue] == 256 &&
-
3681  jv.isMember(jss::load_factor_fee_reference) &&
-
3682  jv[jss::load_factor_fee_reference] == 256;
-
3683  }));
-
3684 
-
3685  env.close();
-
3686 
-
3687  // Closing ledger should publish a status update
-
3688  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
-
3689  return jv[jss::type] == "serverStatus" &&
-
3690  jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
-
3691  jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
-
3692  jv.isMember(jss::load_factor_server) &&
-
3693  jv[jss::load_factor_server] == 256 &&
-
3694  jv.isMember(jss::load_factor_fee_escalation) &&
-
3695  jv[jss::load_factor_fee_escalation] == 256 &&
-
3696  jv.isMember(jss::load_factor_fee_queue) &&
-
3697  jv[jss::load_factor_fee_queue] == 256 &&
-
3698  jv.isMember(jss::load_factor_fee_reference) &&
-
3699  jv[jss::load_factor_fee_reference] == 256;
-
3700  }));
-
3701 
-
3702  checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
-
3703 
-
3704  // Fund then next few accounts at non escalated fee
-
3705  env.fund(XRP(50000), noripple(e, f, g, h, i));
+
3650  Account a{"a"}, b{"b"}, c{"c"}, d{"d"}, e{"e"}, f{"f"}, g{"g"}, h{"h"},
+
3651  i{"i"};
+
3652 
+
3653  // Fund the first few accounts at non escalated fee
+
3654  env.fund(XRP(50000), noripple(a, b, c, d));
+
3655  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
+
3656 
+
3657  // First transaction establishes the messaging
+
3658  using namespace std::chrono_literals;
+
3659  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
+
3660  return jv[jss::type] == "serverStatus" &&
+
3661  jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
+
3662  jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
+
3663  jv.isMember(jss::load_factor_server) &&
+
3664  jv[jss::load_factor_server] == 256 &&
+
3665  jv.isMember(jss::load_factor_fee_escalation) &&
+
3666  jv[jss::load_factor_fee_escalation] == 256 &&
+
3667  jv.isMember(jss::load_factor_fee_queue) &&
+
3668  jv[jss::load_factor_fee_queue] == 256 &&
+
3669  jv.isMember(jss::load_factor_fee_reference) &&
+
3670  jv[jss::load_factor_fee_reference] == 256;
+
3671  }));
+
3672  // Last transaction escalates the fee
+
3673  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
+
3674  return jv[jss::type] == "serverStatus" &&
+
3675  jv.isMember(jss::load_factor) &&
+
3676  jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
+
3677  jv[jss::load_base] == 256 &&
+
3678  jv.isMember(jss::load_factor_server) &&
+
3679  jv[jss::load_factor_server] == 256 &&
+
3680  jv.isMember(jss::load_factor_fee_escalation) &&
+
3681  jv[jss::load_factor_fee_escalation] == 227555 &&
+
3682  jv.isMember(jss::load_factor_fee_queue) &&
+
3683  jv[jss::load_factor_fee_queue] == 256 &&
+
3684  jv.isMember(jss::load_factor_fee_reference) &&
+
3685  jv[jss::load_factor_fee_reference] == 256;
+
3686  }));
+
3687 
+
3688  env.close();
+
3689 
+
3690  // Closing ledger should publish a status update
+
3691  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
+
3692  return jv[jss::type] == "serverStatus" &&
+
3693  jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
+
3694  jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
+
3695  jv.isMember(jss::load_factor_server) &&
+
3696  jv[jss::load_factor_server] == 256 &&
+
3697  jv.isMember(jss::load_factor_fee_escalation) &&
+
3698  jv[jss::load_factor_fee_escalation] == 256 &&
+
3699  jv.isMember(jss::load_factor_fee_queue) &&
+
3700  jv[jss::load_factor_fee_queue] == 256 &&
+
3701  jv.isMember(jss::load_factor_fee_reference) &&
+
3702  jv[jss::load_factor_fee_reference] == 256;
+
3703  }));
+
3704 
+
3705  checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
3706 
-
3707  // Extra transactions with low fee are queued
-
3708  auto queued = ter(terQUEUED);
-
3709  env(noop(a), fee(10), queued);
-
3710  env(noop(b), fee(10), queued);
-
3711  env(noop(c), fee(10), queued);
-
3712  env(noop(d), fee(10), queued);
-
3713  env(noop(e), fee(10), queued);
-
3714  env(noop(f), fee(10), queued);
-
3715  env(noop(g), fee(10), queued);
-
3716  checkMetrics(__LINE__, env, 7, 8, 5, 4, 256);
-
3717 
-
3718  // Last transaction escalates the fee
-
3719  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
-
3720  return jv[jss::type] == "serverStatus" &&
-
3721  jv.isMember(jss::load_factor) &&
-
3722  jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
-
3723  jv[jss::load_base] == 256 &&
-
3724  jv.isMember(jss::load_factor_server) &&
-
3725  jv[jss::load_factor_server] == 256 &&
-
3726  jv.isMember(jss::load_factor_fee_escalation) &&
-
3727  jv[jss::load_factor_fee_escalation] == 200000 &&
-
3728  jv.isMember(jss::load_factor_fee_queue) &&
-
3729  jv[jss::load_factor_fee_queue] == 256 &&
-
3730  jv.isMember(jss::load_factor_fee_reference) &&
-
3731  jv[jss::load_factor_fee_reference] == 256;
-
3732  }));
-
3733 
-
3734  env.close();
-
3735  // Ledger close publishes with escalated fees for queued transactions
-
3736  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
-
3737  return jv[jss::type] == "serverStatus" &&
-
3738  jv.isMember(jss::load_factor) &&
-
3739  jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
-
3740  jv[jss::load_base] == 256 &&
-
3741  jv.isMember(jss::load_factor_server) &&
-
3742  jv[jss::load_factor_server] == 256 &&
-
3743  jv.isMember(jss::load_factor_fee_escalation) &&
-
3744  jv[jss::load_factor_fee_escalation] == 184320 &&
-
3745  jv.isMember(jss::load_factor_fee_queue) &&
-
3746  jv[jss::load_factor_fee_queue] == 256 &&
-
3747  jv.isMember(jss::load_factor_fee_reference) &&
-
3748  jv[jss::load_factor_fee_reference] == 256;
-
3749  }));
-
3750 
-
3751  env.close();
-
3752  // ledger close clears queue so fee is back to normal
-
3753  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
-
3754  return jv[jss::type] == "serverStatus" &&
-
3755  jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
-
3756  jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
-
3757  jv.isMember(jss::load_factor_server) &&
-
3758  jv[jss::load_factor_server] == 256 &&
-
3759  jv.isMember(jss::load_factor_fee_escalation) &&
-
3760  jv[jss::load_factor_fee_escalation] == 256 &&
-
3761  jv.isMember(jss::load_factor_fee_queue) &&
-
3762  jv[jss::load_factor_fee_queue] == 256 &&
-
3763  jv.isMember(jss::load_factor_fee_reference) &&
-
3764  jv[jss::load_factor_fee_reference] == 256;
-
3765  }));
-
3766 
-
3767  BEAST_EXPECT(!wsc->findMsg(1s, [&](auto const& jv) {
-
3768  return jv[jss::type] == "serverStatus";
-
3769  }));
-
3770 
-
3771  auto jv = wsc->invoke("unsubscribe", stream);
-
3772  BEAST_EXPECT(jv[jss::status] == "success");
-
3773  }
-
3774 
-
3775  void
-
3776  testClearQueuedAccountTxs()
-
3777  {
-
3778  using namespace jtx;
-
3779  testcase("clear queued acct txs");
-
3780 
-
3781  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
-
3782  auto alice = Account("alice");
-
3783  auto bob = Account("bob");
-
3784 
-
3785  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
-
3786  env.fund(XRP(50000000), alice, bob);
+
3707  // Fund then next few accounts at non escalated fee
+
3708  env.fund(XRP(50000), noripple(e, f, g, h, i));
+
3709 
+
3710  // Extra transactions with low fee are queued
+
3711  auto queued = ter(terQUEUED);
+
3712  env(noop(a), fee(10), queued);
+
3713  env(noop(b), fee(10), queued);
+
3714  env(noop(c), fee(10), queued);
+
3715  env(noop(d), fee(10), queued);
+
3716  env(noop(e), fee(10), queued);
+
3717  env(noop(f), fee(10), queued);
+
3718  env(noop(g), fee(10), queued);
+
3719  checkMetrics(__LINE__, env, 7, 8, 5, 4, 256);
+
3720 
+
3721  // Last transaction escalates the fee
+
3722  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
+
3723  return jv[jss::type] == "serverStatus" &&
+
3724  jv.isMember(jss::load_factor) &&
+
3725  jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
+
3726  jv[jss::load_base] == 256 &&
+
3727  jv.isMember(jss::load_factor_server) &&
+
3728  jv[jss::load_factor_server] == 256 &&
+
3729  jv.isMember(jss::load_factor_fee_escalation) &&
+
3730  jv[jss::load_factor_fee_escalation] == 200000 &&
+
3731  jv.isMember(jss::load_factor_fee_queue) &&
+
3732  jv[jss::load_factor_fee_queue] == 256 &&
+
3733  jv.isMember(jss::load_factor_fee_reference) &&
+
3734  jv[jss::load_factor_fee_reference] == 256;
+
3735  }));
+
3736 
+
3737  env.close();
+
3738  // Ledger close publishes with escalated fees for queued transactions
+
3739  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
+
3740  return jv[jss::type] == "serverStatus" &&
+
3741  jv.isMember(jss::load_factor) &&
+
3742  jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
+
3743  jv[jss::load_base] == 256 &&
+
3744  jv.isMember(jss::load_factor_server) &&
+
3745  jv[jss::load_factor_server] == 256 &&
+
3746  jv.isMember(jss::load_factor_fee_escalation) &&
+
3747  jv[jss::load_factor_fee_escalation] == 184320 &&
+
3748  jv.isMember(jss::load_factor_fee_queue) &&
+
3749  jv[jss::load_factor_fee_queue] == 256 &&
+
3750  jv.isMember(jss::load_factor_fee_reference) &&
+
3751  jv[jss::load_factor_fee_reference] == 256;
+
3752  }));
+
3753 
+
3754  env.close();
+
3755  // ledger close clears queue so fee is back to normal
+
3756  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
+
3757  return jv[jss::type] == "serverStatus" &&
+
3758  jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
+
3759  jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
+
3760  jv.isMember(jss::load_factor_server) &&
+
3761  jv[jss::load_factor_server] == 256 &&
+
3762  jv.isMember(jss::load_factor_fee_escalation) &&
+
3763  jv[jss::load_factor_fee_escalation] == 256 &&
+
3764  jv.isMember(jss::load_factor_fee_queue) &&
+
3765  jv[jss::load_factor_fee_queue] == 256 &&
+
3766  jv.isMember(jss::load_factor_fee_reference) &&
+
3767  jv[jss::load_factor_fee_reference] == 256;
+
3768  }));
+
3769 
+
3770  BEAST_EXPECT(!wsc->findMsg(1s, [&](auto const& jv) {
+
3771  return jv[jss::type] == "serverStatus";
+
3772  }));
+
3773 
+
3774  auto jv = wsc->invoke("unsubscribe", stream);
+
3775  BEAST_EXPECT(jv[jss::status] == "success");
+
3776  }
+
3777 
+
3778  void
+
3779  testClearQueuedAccountTxs()
+
3780  {
+
3781  using namespace jtx;
+
3782  testcase("clear queued acct txs");
+
3783 
+
3784  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
+
3785  auto alice = Account("alice");
+
3786  auto bob = Account("bob");
3787 
-
3788  fillQueue(env, alice);
-
3789 
-
3790  auto calcTotalFee = [&](std::int64_t alreadyPaid,
-
3791  std::optional<std::size_t> numToClear =
-
3792  std::nullopt) -> std::uint64_t {
-
3793  auto totalFactor = 0;
-
3794  auto const metrics = env.app().getTxQ().getMetrics(*env.current());
-
3795  if (!numToClear)
-
3796  numToClear.emplace(metrics.txCount + 1);
-
3797  for (int i = 0; i < *numToClear; ++i)
-
3798  {
-
3799  auto inLedger = metrics.txInLedger + i;
-
3800  totalFactor += inLedger * inLedger;
-
3801  }
-
3802  auto result = toDrops(
-
3803  metrics.medFeeLevel * totalFactor /
-
3804  (metrics.txPerLedger * metrics.txPerLedger),
-
3805  env.current()->fees().base)
-
3806  .drops();
-
3807  // Subtract the fees already paid
-
3808  result -= alreadyPaid;
-
3809  // round up
-
3810  ++result;
-
3811  return result;
-
3812  };
-
3813 
-
3814  testcase("straightfoward positive case");
-
3815  {
-
3816  // Queue up some transactions at a too-low fee.
-
3817  auto aliceSeq = env.seq(alice);
-
3818  for (int i = 0; i < 2; ++i)
-
3819  {
-
3820  env(noop(alice), fee(100), seq(aliceSeq++), ter(terQUEUED));
-
3821  }
-
3822 
-
3823  // Queue up a transaction paying the open ledger fee
-
3824  // This will be the first tx to call the operative function,
-
3825  // but it won't succeed.
-
3826  env(noop(alice),
-
3827  openLedgerFee(env),
-
3828  seq(aliceSeq++),
-
3829  ter(terQUEUED));
-
3830 
-
3831  checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
-
3832 
-
3833  // Figure out how much it would cost to cover all the
-
3834  // queued txs + itself
-
3835  std::uint64_t totalFee1 = calcTotalFee(100 * 2 + 8889);
-
3836  --totalFee1;
-
3837 
-
3838  BEAST_EXPECT(totalFee1 == 60911);
-
3839  // Submit a transaction with that fee. It will get queued
-
3840  // because the fee level calculation rounds down. This is
-
3841  // the edge case test.
-
3842  env(noop(alice), fee(totalFee1), seq(aliceSeq++), ter(terQUEUED));
-
3843 
-
3844  checkMetrics(__LINE__, env, 4, std::nullopt, 4, 3, 256);
-
3845 
-
3846  // Now repeat the process including the new tx
-
3847  // and avoiding the rounding error
-
3848  std::uint64_t const totalFee2 =
-
3849  calcTotalFee(100 * 2 + 8889 + 60911);
-
3850  BEAST_EXPECT(totalFee2 == 35556);
-
3851  // Submit a transaction with that fee. It will succeed.
-
3852  env(noop(alice), fee(totalFee2), seq(aliceSeq++));
-
3853 
-
3854  checkMetrics(__LINE__, env, 0, std::nullopt, 9, 3, 256);
-
3855  }
+
3788  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
+
3789  env.fund(XRP(50000000), alice, bob);
+
3790 
+
3791  fillQueue(env, alice);
+
3792 
+
3793  auto calcTotalFee = [&](std::int64_t alreadyPaid,
+
3794  std::optional<std::size_t> numToClear =
+
3795  std::nullopt) -> std::uint64_t {
+
3796  auto totalFactor = 0;
+
3797  auto const metrics = env.app().getTxQ().getMetrics(*env.current());
+
3798  if (!numToClear)
+
3799  numToClear.emplace(metrics.txCount + 1);
+
3800  for (int i = 0; i < *numToClear; ++i)
+
3801  {
+
3802  auto inLedger = metrics.txInLedger + i;
+
3803  totalFactor += inLedger * inLedger;
+
3804  }
+
3805  auto result = toDrops(
+
3806  metrics.medFeeLevel * totalFactor /
+
3807  (metrics.txPerLedger * metrics.txPerLedger),
+
3808  env.current()->fees().base)
+
3809  .drops();
+
3810  // Subtract the fees already paid
+
3811  result -= alreadyPaid;
+
3812  // round up
+
3813  ++result;
+
3814  return result;
+
3815  };
+
3816 
+
3817  testcase("straightfoward positive case");
+
3818  {
+
3819  // Queue up some transactions at a too-low fee.
+
3820  auto aliceSeq = env.seq(alice);
+
3821  for (int i = 0; i < 2; ++i)
+
3822  {
+
3823  env(noop(alice), fee(100), seq(aliceSeq++), ter(terQUEUED));
+
3824  }
+
3825 
+
3826  // Queue up a transaction paying the open ledger fee
+
3827  // This will be the first tx to call the operative function,
+
3828  // but it won't succeed.
+
3829  env(noop(alice),
+
3830  openLedgerFee(env),
+
3831  seq(aliceSeq++),
+
3832  ter(terQUEUED));
+
3833 
+
3834  checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
+
3835 
+
3836  // Figure out how much it would cost to cover all the
+
3837  // queued txs + itself
+
3838  std::uint64_t totalFee1 = calcTotalFee(100 * 2 + 8889);
+
3839  --totalFee1;
+
3840 
+
3841  BEAST_EXPECT(totalFee1 == 60911);
+
3842  // Submit a transaction with that fee. It will get queued
+
3843  // because the fee level calculation rounds down. This is
+
3844  // the edge case test.
+
3845  env(noop(alice), fee(totalFee1), seq(aliceSeq++), ter(terQUEUED));
+
3846 
+
3847  checkMetrics(__LINE__, env, 4, std::nullopt, 4, 3, 256);
+
3848 
+
3849  // Now repeat the process including the new tx
+
3850  // and avoiding the rounding error
+
3851  std::uint64_t const totalFee2 =
+
3852  calcTotalFee(100 * 2 + 8889 + 60911);
+
3853  BEAST_EXPECT(totalFee2 == 35556);
+
3854  // Submit a transaction with that fee. It will succeed.
+
3855  env(noop(alice), fee(totalFee2), seq(aliceSeq++));
3856 
-
3857  testcase("replace last tx with enough to clear queue");
-
3858  {
-
3859  // Queue up some transactions at a too-low fee.
-
3860  auto aliceSeq = env.seq(alice);
-
3861  for (int i = 0; i < 2; ++i)
-
3862  {
-
3863  env(noop(alice), fee(100), seq(aliceSeq++), ter(terQUEUED));
-
3864  }
-
3865 
-
3866  // Queue up a transaction paying the open ledger fee
-
3867  // This will be the first tx to call the operative function,
-
3868  // but it won't succeed.
-
3869  env(noop(alice),
-
3870  openLedgerFee(env),
-
3871  seq(aliceSeq++),
-
3872  ter(terQUEUED));
-
3873 
-
3874  checkMetrics(__LINE__, env, 3, std::nullopt, 9, 3, 256);
-
3875 
-
3876  // Figure out how much it would cost to cover all the
-
3877  // queued txs + itself
-
3878  auto const metrics = env.app().getTxQ().getMetrics(*env.current());
-
3879  std::uint64_t const totalFee =
-
3880  calcTotalFee(100 * 2, metrics.txCount);
-
3881  BEAST_EXPECT(totalFee == 167578);
-
3882  // Replacing the last tx with the large fee succeeds.
-
3883  --aliceSeq;
-
3884  env(noop(alice), fee(totalFee), seq(aliceSeq++));
-
3885 
-
3886  // The queue is clear
-
3887  checkMetrics(__LINE__, env, 0, std::nullopt, 12, 3, 256);
+
3857  checkMetrics(__LINE__, env, 0, std::nullopt, 9, 3, 256);
+
3858  }
+
3859 
+
3860  testcase("replace last tx with enough to clear queue");
+
3861  {
+
3862  // Queue up some transactions at a too-low fee.
+
3863  auto aliceSeq = env.seq(alice);
+
3864  for (int i = 0; i < 2; ++i)
+
3865  {
+
3866  env(noop(alice), fee(100), seq(aliceSeq++), ter(terQUEUED));
+
3867  }
+
3868 
+
3869  // Queue up a transaction paying the open ledger fee
+
3870  // This will be the first tx to call the operative function,
+
3871  // but it won't succeed.
+
3872  env(noop(alice),
+
3873  openLedgerFee(env),
+
3874  seq(aliceSeq++),
+
3875  ter(terQUEUED));
+
3876 
+
3877  checkMetrics(__LINE__, env, 3, std::nullopt, 9, 3, 256);
+
3878 
+
3879  // Figure out how much it would cost to cover all the
+
3880  // queued txs + itself
+
3881  auto const metrics = env.app().getTxQ().getMetrics(*env.current());
+
3882  std::uint64_t const totalFee =
+
3883  calcTotalFee(100 * 2, metrics.txCount);
+
3884  BEAST_EXPECT(totalFee == 167578);
+
3885  // Replacing the last tx with the large fee succeeds.
+
3886  --aliceSeq;
+
3887  env(noop(alice), fee(totalFee), seq(aliceSeq++));
3888 
-
3889  env.close();
-
3890  checkMetrics(__LINE__, env, 0, 24, 0, 12, 256);
-
3891  }
-
3892 
-
3893  testcase("replace middle tx with enough to clear queue");
-
3894  {
-
3895  fillQueue(env, alice);
-
3896  // Queue up some transactions at a too-low fee.
-
3897  auto aliceSeq = env.seq(alice);
-
3898  for (int i = 0; i < 5; ++i)
-
3899  {
-
3900  env(noop(alice), fee(100), seq(aliceSeq++), ter(terQUEUED));
-
3901  }
-
3902 
-
3903  checkMetrics(__LINE__, env, 5, 24, 13, 12, 256);
-
3904 
-
3905  // Figure out how much it would cost to cover 3 txns
-
3906  std::uint64_t const totalFee = calcTotalFee(100 * 2, 3);
-
3907  BEAST_EXPECT(totalFee == 20287);
-
3908  // Replacing the last tx with the large fee succeeds.
-
3909  aliceSeq -= 3;
-
3910  env(noop(alice), fee(totalFee), seq(aliceSeq++));
-
3911 
-
3912  checkMetrics(__LINE__, env, 2, 24, 16, 12, 256);
-
3913  auto const aliceQueue =
-
3914  env.app().getTxQ().getAccountTxs(alice.id());
-
3915  BEAST_EXPECT(aliceQueue.size() == 2);
-
3916  SeqProxy seq = SeqProxy::sequence(aliceSeq);
-
3917  for (auto const& tx : aliceQueue)
-
3918  {
-
3919  BEAST_EXPECT(tx.seqProxy == seq);
-
3920  BEAST_EXPECT(tx.feeLevel == FeeLevel64{2560});
-
3921  seq.advanceBy(1);
-
3922  }
-
3923 
-
3924  // Close the ledger to clear the queue
-
3925  env.close();
-
3926  checkMetrics(__LINE__, env, 0, 32, 2, 16, 256);
-
3927  }
-
3928 
-
3929  testcase("clear queue failure (load)");
-
3930  {
-
3931  fillQueue(env, alice);
-
3932  // Queue up some transactions at a too-low fee.
-
3933  auto aliceSeq = env.seq(alice);
-
3934  for (int i = 0; i < 2; ++i)
-
3935  {
-
3936  env(noop(alice), fee(200), seq(aliceSeq++), ter(terQUEUED));
-
3937  }
-
3938  for (int i = 0; i < 2; ++i)
-
3939  {
-
3940  env(noop(alice), fee(22), seq(aliceSeq++), ter(terQUEUED));
-
3941  }
-
3942 
-
3943  checkMetrics(__LINE__, env, 4, 32, 17, 16, 256);
-
3944 
-
3945  // Figure out how much it would cost to cover all the txns
-
3946  // + 1
-
3947  std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
-
3948  BEAST_EXPECT(totalFee == 35006);
-
3949  // This fee should be enough, but oh no! Server load went up!
-
3950  auto& feeTrack = env.app().getFeeTrack();
-
3951  auto const origFee = feeTrack.getRemoteFee();
-
3952  feeTrack.setRemoteFee(origFee * 5);
-
3953  // Instead the tx gets queued, and all of the queued
-
3954  // txs stay in the queue.
-
3955  env(noop(alice), fee(totalFee), seq(aliceSeq++), ter(terQUEUED));
-
3956 
-
3957  // The original last transaction is still in the queue
-
3958  checkMetrics(__LINE__, env, 5, 32, 17, 16, 256);
+
3889  // The queue is clear
+
3890  checkMetrics(__LINE__, env, 0, std::nullopt, 12, 3, 256);
+
3891 
+
3892  env.close();
+
3893  checkMetrics(__LINE__, env, 0, 24, 0, 12, 256);
+
3894  }
+
3895 
+
3896  testcase("replace middle tx with enough to clear queue");
+
3897  {
+
3898  fillQueue(env, alice);
+
3899  // Queue up some transactions at a too-low fee.
+
3900  auto aliceSeq = env.seq(alice);
+
3901  for (int i = 0; i < 5; ++i)
+
3902  {
+
3903  env(noop(alice), fee(100), seq(aliceSeq++), ter(terQUEUED));
+
3904  }
+
3905 
+
3906  checkMetrics(__LINE__, env, 5, 24, 13, 12, 256);
+
3907 
+
3908  // Figure out how much it would cost to cover 3 txns
+
3909  std::uint64_t const totalFee = calcTotalFee(100 * 2, 3);
+
3910  BEAST_EXPECT(totalFee == 20287);
+
3911  // Replacing the last tx with the large fee succeeds.
+
3912  aliceSeq -= 3;
+
3913  env(noop(alice), fee(totalFee), seq(aliceSeq++));
+
3914 
+
3915  checkMetrics(__LINE__, env, 2, 24, 16, 12, 256);
+
3916  auto const aliceQueue =
+
3917  env.app().getTxQ().getAccountTxs(alice.id());
+
3918  BEAST_EXPECT(aliceQueue.size() == 2);
+
3919  SeqProxy seq = SeqProxy::sequence(aliceSeq);
+
3920  for (auto const& tx : aliceQueue)
+
3921  {
+
3922  BEAST_EXPECT(tx.seqProxy == seq);
+
3923  BEAST_EXPECT(tx.feeLevel == FeeLevel64{2560});
+
3924  seq.advanceBy(1);
+
3925  }
+
3926 
+
3927  // Close the ledger to clear the queue
+
3928  env.close();
+
3929  checkMetrics(__LINE__, env, 0, 32, 2, 16, 256);
+
3930  }
+
3931 
+
3932  testcase("clear queue failure (load)");
+
3933  {
+
3934  fillQueue(env, alice);
+
3935  // Queue up some transactions at a too-low fee.
+
3936  auto aliceSeq = env.seq(alice);
+
3937  for (int i = 0; i < 2; ++i)
+
3938  {
+
3939  env(noop(alice), fee(200), seq(aliceSeq++), ter(terQUEUED));
+
3940  }
+
3941  for (int i = 0; i < 2; ++i)
+
3942  {
+
3943  env(noop(alice), fee(22), seq(aliceSeq++), ter(terQUEUED));
+
3944  }
+
3945 
+
3946  checkMetrics(__LINE__, env, 4, 32, 17, 16, 256);
+
3947 
+
3948  // Figure out how much it would cost to cover all the txns
+
3949  // + 1
+
3950  std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
+
3951  BEAST_EXPECT(totalFee == 35006);
+
3952  // This fee should be enough, but oh no! Server load went up!
+
3953  auto& feeTrack = env.app().getFeeTrack();
+
3954  auto const origFee = feeTrack.getRemoteFee();
+
3955  feeTrack.setRemoteFee(origFee * 5);
+
3956  // Instead the tx gets queued, and all of the queued
+
3957  // txs stay in the queue.
+
3958  env(noop(alice), fee(totalFee), seq(aliceSeq++), ter(terQUEUED));
3959 
-
3960  // With high load, some of the txs stay in the queue
-
3961  env.close();
-
3962  checkMetrics(__LINE__, env, 3, 34, 2, 17, 256);
-
3963 
-
3964  // Load drops back down
-
3965  feeTrack.setRemoteFee(origFee);
+
3960  // The original last transaction is still in the queue
+
3961  checkMetrics(__LINE__, env, 5, 32, 17, 16, 256);
+
3962 
+
3963  // With high load, some of the txs stay in the queue
+
3964  env.close();
+
3965  checkMetrics(__LINE__, env, 3, 34, 2, 17, 256);
3966 
-
3967  // Because of the earlier failure, alice can not clear the queue,
-
3968  // no matter how high the fee
-
3969  fillQueue(env, bob);
-
3970  checkMetrics(__LINE__, env, 3, 34, 18, 17, 256);
-
3971 
-
3972  env(noop(alice), fee(XRP(1)), seq(aliceSeq++), ter(terQUEUED));
-
3973  checkMetrics(__LINE__, env, 4, 34, 18, 17, 256);
+
3967  // Load drops back down
+
3968  feeTrack.setRemoteFee(origFee);
+
3969 
+
3970  // Because of the earlier failure, alice can not clear the queue,
+
3971  // no matter how high the fee
+
3972  fillQueue(env, bob);
+
3973  checkMetrics(__LINE__, env, 3, 34, 18, 17, 256);
3974 
-
3975  // With normal load, those txs get into the ledger
-
3976  env.close();
-
3977  checkMetrics(__LINE__, env, 0, 36, 4, 18, 256);
-
3978  }
-
3979  }
-
3980 
-
3981  void
-
3982  testScaling()
-
3983  {
-
3984  using namespace jtx;
-
3985  using namespace std::chrono_literals;
-
3986  testcase("scaling");
-
3987 
-
3988  {
-
3989  Env env(
-
3990  *this,
-
3991  makeConfig(
-
3992  {{"minimum_txn_in_ledger_standalone", "3"},
-
3993  {"normal_consensus_increase_percent", "25"},
-
3994  {"slow_consensus_decrease_percent", "50"},
-
3995  {"target_txn_in_ledger", "10"},
-
3996  {"maximum_txn_per_account", "200"}}));
-
3997  auto alice = Account("alice");
-
3998 
-
3999  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
-
4000  env.fund(XRP(50000000), alice);
+
3975  env(noop(alice), fee(XRP(1)), seq(aliceSeq++), ter(terQUEUED));
+
3976  checkMetrics(__LINE__, env, 4, 34, 18, 17, 256);
+
3977 
+
3978  // With normal load, those txs get into the ledger
+
3979  env.close();
+
3980  checkMetrics(__LINE__, env, 0, 36, 4, 18, 256);
+
3981  }
+
3982  }
+
3983 
+
3984  void
+
3985  testScaling()
+
3986  {
+
3987  using namespace jtx;
+
3988  using namespace std::chrono_literals;
+
3989  testcase("scaling");
+
3990 
+
3991  {
+
3992  Env env(
+
3993  *this,
+
3994  makeConfig(
+
3995  {{"minimum_txn_in_ledger_standalone", "3"},
+
3996  {"normal_consensus_increase_percent", "25"},
+
3997  {"slow_consensus_decrease_percent", "50"},
+
3998  {"target_txn_in_ledger", "10"},
+
3999  {"maximum_txn_per_account", "200"}}));
+
4000  auto alice = Account("alice");
4001 
-
4002  fillQueue(env, alice);
-
4003  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
-
4004  auto seqAlice = env.seq(alice);
-
4005  auto txCount = 140;
-
4006  for (int i = 0; i < txCount; ++i)
-
4007  env(noop(alice), seq(seqAlice++), ter(terQUEUED));
-
4008  checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
-
4009 
-
4010  // Close a few ledgers successfully, so the limit grows
-
4011 
-
4012  env.close();
-
4013  // 4 + 25% = 5
-
4014  txCount -= 6;
-
4015  checkMetrics(__LINE__, env, txCount, 10, 6, 5, 257);
-
4016 
-
4017  env.close();
-
4018  // 6 + 25% = 7
-
4019  txCount -= 8;
-
4020  checkMetrics(__LINE__, env, txCount, 14, 8, 7, 257);
-
4021 
-
4022  env.close();
-
4023  // 8 + 25% = 10
-
4024  txCount -= 11;
-
4025  checkMetrics(__LINE__, env, txCount, 20, 11, 10, 257);
-
4026 
-
4027  env.close();
-
4028  // 11 + 25% = 13
-
4029  txCount -= 14;
-
4030  checkMetrics(__LINE__, env, txCount, 26, 14, 13, 257);
-
4031 
-
4032  env.close();
-
4033  // 14 + 25% = 17
-
4034  txCount -= 18;
-
4035  checkMetrics(__LINE__, env, txCount, 34, 18, 17, 257);
-
4036 
-
4037  env.close();
-
4038  // 18 + 25% = 22
-
4039  txCount -= 23;
-
4040  checkMetrics(__LINE__, env, txCount, 44, 23, 22, 257);
-
4041 
-
4042  env.close();
-
4043  // 23 + 25% = 28
-
4044  txCount -= 29;
-
4045  checkMetrics(__LINE__, env, txCount, 56, 29, 28, 256);
-
4046 
-
4047  // From 3 expected to 28 in 7 "fast" ledgers.
-
4048 
-
4049  // Close the ledger with a delay.
-
4050  env.close(env.now() + 5s, 10000ms);
-
4051  txCount -= 15;
-
4052  checkMetrics(__LINE__, env, txCount, 56, 15, 14, 256);
-
4053 
-
4054  // Close the ledger with a delay.
-
4055  env.close(env.now() + 5s, 10000ms);
-
4056  txCount -= 8;
-
4057  checkMetrics(__LINE__, env, txCount, 56, 8, 7, 256);
-
4058 
-
4059  // Close the ledger with a delay.
-
4060  env.close(env.now() + 5s, 10000ms);
-
4061  txCount -= 4;
-
4062  checkMetrics(__LINE__, env, txCount, 56, 4, 3, 256);
-
4063 
-
4064  // From 28 expected back down to 3 in 3 "slow" ledgers.
-
4065 
-
4066  // Confirm the minimum sticks
-
4067  env.close(env.now() + 5s, 10000ms);
-
4068  txCount -= 4;
-
4069  checkMetrics(__LINE__, env, txCount, 56, 4, 3, 256);
-
4070 
-
4071  BEAST_EXPECT(!txCount);
-
4072  }
+
4002  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
+
4003  env.fund(XRP(50000000), alice);
+
4004 
+
4005  fillQueue(env, alice);
+
4006  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
+
4007  auto seqAlice = env.seq(alice);
+
4008  auto txCount = 140;
+
4009  for (int i = 0; i < txCount; ++i)
+
4010  env(noop(alice), seq(seqAlice++), ter(terQUEUED));
+
4011  checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
+
4012 
+
4013  // Close a few ledgers successfully, so the limit grows
+
4014 
+
4015  env.close();
+
4016  // 4 + 25% = 5
+
4017  txCount -= 6;
+
4018  checkMetrics(__LINE__, env, txCount, 10, 6, 5, 257);
+
4019 
+
4020  env.close();
+
4021  // 6 + 25% = 7
+
4022  txCount -= 8;
+
4023  checkMetrics(__LINE__, env, txCount, 14, 8, 7, 257);
+
4024 
+
4025  env.close();
+
4026  // 8 + 25% = 10
+
4027  txCount -= 11;
+
4028  checkMetrics(__LINE__, env, txCount, 20, 11, 10, 257);
+
4029 
+
4030  env.close();
+
4031  // 11 + 25% = 13
+
4032  txCount -= 14;
+
4033  checkMetrics(__LINE__, env, txCount, 26, 14, 13, 257);
+
4034 
+
4035  env.close();
+
4036  // 14 + 25% = 17
+
4037  txCount -= 18;
+
4038  checkMetrics(__LINE__, env, txCount, 34, 18, 17, 257);
+
4039 
+
4040  env.close();
+
4041  // 18 + 25% = 22
+
4042  txCount -= 23;
+
4043  checkMetrics(__LINE__, env, txCount, 44, 23, 22, 257);
+
4044 
+
4045  env.close();
+
4046  // 23 + 25% = 28
+
4047  txCount -= 29;
+
4048  checkMetrics(__LINE__, env, txCount, 56, 29, 28, 256);
+
4049 
+
4050  // From 3 expected to 28 in 7 "fast" ledgers.
+
4051 
+
4052  // Close the ledger with a delay.
+
4053  env.close(env.now() + 5s, 10000ms);
+
4054  txCount -= 15;
+
4055  checkMetrics(__LINE__, env, txCount, 56, 15, 14, 256);
+
4056 
+
4057  // Close the ledger with a delay.
+
4058  env.close(env.now() + 5s, 10000ms);
+
4059  txCount -= 8;
+
4060  checkMetrics(__LINE__, env, txCount, 56, 8, 7, 256);
+
4061 
+
4062  // Close the ledger with a delay.
+
4063  env.close(env.now() + 5s, 10000ms);
+
4064  txCount -= 4;
+
4065  checkMetrics(__LINE__, env, txCount, 56, 4, 3, 256);
+
4066 
+
4067  // From 28 expected back down to 3 in 3 "slow" ledgers.
+
4068 
+
4069  // Confirm the minimum sticks
+
4070  env.close(env.now() + 5s, 10000ms);
+
4071  txCount -= 4;
+
4072  checkMetrics(__LINE__, env, txCount, 56, 4, 3, 256);
4073 
-
4074  {
-
4075  Env env(
-
4076  *this,
-
4077  makeConfig(
-
4078  {{"minimum_txn_in_ledger_standalone", "3"},
-
4079  {"normal_consensus_increase_percent", "150"},
-
4080  {"slow_consensus_decrease_percent", "150"},
-
4081  {"target_txn_in_ledger", "10"},
-
4082  {"maximum_txn_per_account", "200"}}));
-
4083  auto alice = Account("alice");
-
4084 
-
4085  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
-
4086  env.fund(XRP(50000000), alice);
+
4074  BEAST_EXPECT(!txCount);
+
4075  }
+
4076 
+
4077  {
+
4078  Env env(
+
4079  *this,
+
4080  makeConfig(
+
4081  {{"minimum_txn_in_ledger_standalone", "3"},
+
4082  {"normal_consensus_increase_percent", "150"},
+
4083  {"slow_consensus_decrease_percent", "150"},
+
4084  {"target_txn_in_ledger", "10"},
+
4085  {"maximum_txn_per_account", "200"}}));
+
4086  auto alice = Account("alice");
4087 
-
4088  fillQueue(env, alice);
-
4089  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
-
4090  auto seqAlice = env.seq(alice);
-
4091  auto txCount = 43;
-
4092  for (int i = 0; i < txCount; ++i)
-
4093  env(noop(alice), seq(seqAlice++), ter(terQUEUED));
-
4094  checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
-
4095 
-
4096  // Close a few ledgers successfully, so the limit grows
-
4097 
-
4098  env.close();
-
4099  // 4 + 150% = 10
-
4100  txCount -= 11;
-
4101  checkMetrics(__LINE__, env, txCount, 20, 11, 10, 257);
-
4102 
-
4103  env.close();
-
4104  // 11 + 150% = 27
-
4105  txCount -= 28;
-
4106  checkMetrics(__LINE__, env, txCount, 54, 28, 27, 256);
-
4107 
-
4108  // From 3 expected to 28 in 7 "fast" ledgers.
-
4109 
-
4110  // Close the ledger with a delay.
-
4111  env.close(env.now() + 5s, 10000ms);
-
4112  txCount -= 4;
-
4113  checkMetrics(__LINE__, env, txCount, 54, 4, 3, 256);
-
4114 
-
4115  // From 28 expected back down to 3 in 3 "slow" ledgers.
-
4116 
-
4117  BEAST_EXPECT(!txCount);
-
4118  }
-
4119  }
-
4120 
-
4121  void
-
4122  testInLedgerSeq()
-
4123  {
-
4124  // Test the situation where a transaction with an account and
-
4125  // sequence that's in the queue also appears in the ledger.
-
4126  //
-
4127  // Normally this situation can only happen on a network
-
4128  // when a transaction gets validated by most of the network,
-
4129  // but one or more nodes have that transaction (or a different
-
4130  // transaction with the same sequence) queued. And, yes, this
-
4131  // situation has been observed (rarely) in the wild.
-
4132  testcase("Sequence in queue and open ledger");
-
4133  using namespace jtx;
-
4134 
-
4135  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
-
4136 
-
4137  auto const alice = Account("alice");
-
4138 
-
4139  auto const queued = ter(terQUEUED);
-
4140 
-
4141  BEAST_EXPECT(env.current()->fees().base == 10);
-
4142 
-
4143  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
-
4144 
-
4145  // Create account
-
4146  env.fund(XRP(50000), noripple(alice));
-
4147  checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
-
4148 
-
4149  fillQueue(env, alice);
-
4150  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
+
4088  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
+
4089  env.fund(XRP(50000000), alice);
+
4090 
+
4091  fillQueue(env, alice);
+
4092  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
+
4093  auto seqAlice = env.seq(alice);
+
4094  auto txCount = 43;
+
4095  for (int i = 0; i < txCount; ++i)
+
4096  env(noop(alice), seq(seqAlice++), ter(terQUEUED));
+
4097  checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
+
4098 
+
4099  // Close a few ledgers successfully, so the limit grows
+
4100 
+
4101  env.close();
+
4102  // 4 + 150% = 10
+
4103  txCount -= 11;
+
4104  checkMetrics(__LINE__, env, txCount, 20, 11, 10, 257);
+
4105 
+
4106  env.close();
+
4107  // 11 + 150% = 27
+
4108  txCount -= 28;
+
4109  checkMetrics(__LINE__, env, txCount, 54, 28, 27, 256);
+
4110 
+
4111  // From 3 expected to 28 in 7 "fast" ledgers.
+
4112 
+
4113  // Close the ledger with a delay.
+
4114  env.close(env.now() + 5s, 10000ms);
+
4115  txCount -= 4;
+
4116  checkMetrics(__LINE__, env, txCount, 54, 4, 3, 256);
+
4117 
+
4118  // From 28 expected back down to 3 in 3 "slow" ledgers.
+
4119 
+
4120  BEAST_EXPECT(!txCount);
+
4121  }
+
4122  }
+
4123 
+
4124  void
+
4125  testInLedgerSeq()
+
4126  {
+
4127  // Test the situation where a transaction with an account and
+
4128  // sequence that's in the queue also appears in the ledger.
+
4129  //
+
4130  // Normally this situation can only happen on a network
+
4131  // when a transaction gets validated by most of the network,
+
4132  // but one or more nodes have that transaction (or a different
+
4133  // transaction with the same sequence) queued. And, yes, this
+
4134  // situation has been observed (rarely) in the wild.
+
4135  testcase("Sequence in queue and open ledger");
+
4136  using namespace jtx;
+
4137 
+
4138  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
+
4139 
+
4140  auto const alice = Account("alice");
+
4141 
+
4142  auto const queued = ter(terQUEUED);
+
4143 
+
4144  BEAST_EXPECT(env.current()->fees().base == 10);
+
4145 
+
4146  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
+
4147 
+
4148  // Create account
+
4149  env.fund(XRP(50000), noripple(alice));
+
4150  checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4151 
-
4152  // Queue a transaction
-
4153  auto const aliceSeq = env.seq(alice);
-
4154  env(noop(alice), queued);
-
4155  checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
-
4156 
-
4157  // Now, apply a (different) transaction directly
-
4158  // to the open ledger, bypassing the queue
-
4159  // (This requires calling directly into the open ledger,
-
4160  // which won't work if unit tests are separated to only
-
4161  // be callable via RPC.)
-
4162  env.app().openLedger().modify([&](OpenView& view, beast::Journal j) {
-
4163  auto const tx =
-
4164  env.jt(noop(alice), seq(aliceSeq), openLedgerFee(env));
-
4165  auto const result =
-
4166  ripple::apply(env.app(), view, *tx.stx, tapUNLIMITED, j);
-
4167  BEAST_EXPECT(result.first == tesSUCCESS && result.second);
-
4168  return result.second;
-
4169  });
-
4170  // the queued transaction is still there
-
4171  checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
-
4172 
-
4173  // The next transaction should be able to go into the open
-
4174  // ledger, even though aliceSeq is queued. In earlier incarnations
-
4175  // of the TxQ this would cause an assert.
-
4176  env(noop(alice), seq(aliceSeq + 1), openLedgerFee(env));
-
4177  checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
-
4178  // Now queue a couple more transactions to make sure
-
4179  // they succeed despite aliceSeq being queued
-
4180  env(noop(alice), seq(aliceSeq + 2), queued);
-
4181  env(noop(alice), seq(aliceSeq + 3), queued);
-
4182  checkMetrics(__LINE__, env, 3, std::nullopt, 6, 3, 256);
-
4183 
-
4184  // Now close the ledger. One of the queued transactions
-
4185  // (aliceSeq) should be dropped.
-
4186  env.close();
-
4187  checkMetrics(__LINE__, env, 0, 12, 2, 6, 256);
-
4188  }
-
4189 
-
4190  void
-
4191  testInLedgerTicket()
-
4192  {
-
4193  // Test the situation where a transaction with an account and
-
4194  // ticket that's in the queue also appears in the ledger.
-
4195  //
-
4196  // Although this situation has not (yet) been observed in the wild,
-
4197  // it is a direct analogy to the previous sequence based test. So
-
4198  // there is no reason to not expect to see it in the wild.
-
4199  testcase("Ticket in queue and open ledger");
-
4200  using namespace jtx;
-
4201 
-
4202  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
-
4203 
-
4204  auto alice = Account("alice");
-
4205 
-
4206  auto queued = ter(terQUEUED);
-
4207 
-
4208  BEAST_EXPECT(env.current()->fees().base == 10);
-
4209 
-
4210  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
-
4211 
-
4212  // Create account
-
4213  env.fund(XRP(50000), noripple(alice));
-
4214  checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
-
4215 
-
4216  // Create tickets
-
4217  std::uint32_t const tktSeq0{env.seq(alice) + 1};
-
4218  env(ticket::create(alice, 4));
-
4219 
-
4220  // Fill the queue so the next transaction will be queued.
-
4221  fillQueue(env, alice);
-
4222  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
-
4223 
-
4224  // Queue a transaction with a ticket. Leave an unused ticket
-
4225  // on either side.
-
4226  env(noop(alice), ticket::use(tktSeq0 + 1), queued);
-
4227  checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
-
4228 
-
4229  // Now, apply a (different) transaction directly
-
4230  // to the open ledger, bypassing the queue
-
4231  // (This requires calling directly into the open ledger,
-
4232  // which won't work if unit tests are separated to only
-
4233  // be callable via RPC.)
-
4234  env.app().openLedger().modify([&](OpenView& view, beast::Journal j) {
-
4235  auto const tx = env.jt(
-
4236  noop(alice), ticket::use(tktSeq0 + 1), openLedgerFee(env));
-
4237  auto const result =
-
4238  ripple::apply(env.app(), view, *tx.stx, tapUNLIMITED, j);
-
4239  BEAST_EXPECT(result.first == tesSUCCESS && result.second);
-
4240  return result.second;
-
4241  });
-
4242  // the queued transaction is still there
-
4243  checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
-
4244 
-
4245  // The next (sequence-based) transaction should be able to go into
-
4246  // the open ledger, even though tktSeq0 is queued. Note that this
-
4247  // sequence-based transaction goes in front of the queued
-
4248  // transaction, so the queued transaction is left in the queue.
-
4249  env(noop(alice), openLedgerFee(env));
-
4250  checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
-
4251 
-
4252  // We should be able to do the same thing with a ticket that goes
-
4253  // if front of the queued transaction. This one too will leave
-
4254  // the queued transaction in place.
-
4255  env(noop(alice), ticket::use(tktSeq0 + 0), openLedgerFee(env));
-
4256  checkMetrics(__LINE__, env, 1, std::nullopt, 7, 3, 256);
-
4257 
-
4258  // We have one ticketed transaction in the queue. We should able
-
4259  // to add another to the queue.
-
4260  env(noop(alice), ticket::use(tktSeq0 + 2), queued);
-
4261  checkMetrics(__LINE__, env, 2, std::nullopt, 7, 3, 256);
-
4262 
-
4263  // Here we try to force the queued transactions into the ledger by
-
4264  // adding one more queued (ticketed) transaction that pays enough
-
4265  // so fee averaging kicks in. It doesn't work. It only succeeds in
-
4266  // forcing just the one ticketed transaction into the ledger.
-
4267  //
-
4268  // The fee averaging functionality makes sense for sequence-based
-
4269  // transactions because if there are several sequence-based
-
4270  // transactions queued, the transactions in front must go into the
-
4271  // ledger before the later ones can go in.
-
4272  //
-
4273  // Fee averaging does not make sense with tickets. Every ticketed
-
4274  // transaction is equally capable of going into the ledger independent
-
4275  // of all other ticket- or sequence-based transactions.
-
4276  env(noop(alice), ticket::use(tktSeq0 + 3), fee(XRP(1)));
-
4277  checkMetrics(__LINE__, env, 2, std::nullopt, 8, 3, 256);
-
4278 
-
4279  // Now close the ledger. One of the queued transactions
-
4280  // (the one with tktSeq0 + 1) should be dropped.
-
4281  env.close();
-
4282  checkMetrics(__LINE__, env, 0, 16, 1, 8, 256);
-
4283  }
-
4284 
-
4285  void
-
4286  testReexecutePreflight()
-
4287  {
-
4288  // The TxQ caches preflight results. But there are situations where
-
4289  // that cache must become invalidated, like if amendments change.
-
4290  //
-
4291  // This test puts transactions into the TxQ and then enables an
-
4292  // amendment. We won't really see much interesting here in the unit
-
4293  // test, but the code that checks for cache invalidation should be
-
4294  // exercised. You can see that in improved code coverage,
-
4295  testcase("Re-execute preflight");
-
4296  using namespace jtx;
-
4297 
-
4298  Account const alice("alice");
-
4299  Account const bob("bob");
-
4300  Account const carol("carol");
-
4301  Account const daria("daria");
-
4302  Account const ellie("ellie");
-
4303  Account const fiona("fiona");
-
4304 
-
4305  auto cfg = makeConfig(
-
4306  {{"minimum_txn_in_ledger_standalone", "1"},
-
4307  {"ledgers_in_queue", "5"},
-
4308  {"maximum_txn_per_account", "10"}},
-
4309  {{"account_reserve", "1000"}, {"owner_reserve", "50"}});
-
4310 
-
4311  Env env(*this, std::move(cfg));
-
4312 
-
4313  env.fund(XRP(10000), alice);
-
4314  env.close();
-
4315  env.fund(XRP(10000), bob);
-
4316  env.close();
-
4317  env.fund(XRP(10000), carol);
-
4318  env.close();
-
4319  env.fund(XRP(10000), daria);
-
4320  env.close();
-
4321  env.fund(XRP(10000), ellie);
-
4322  env.close();
-
4323  env.fund(XRP(10000), fiona);
-
4324  env.close();
-
4325  checkMetrics(__LINE__, env, 0, 10, 0, 2, 256);
-
4326 
-
4327  // Close ledgers until the amendments show up.
-
4328  int i = 0;
-
4329  for (i = 0; i <= 257; ++i)
-
4330  {
-
4331  env.close();
-
4332  if (!getMajorityAmendments(*env.closed()).empty())
-
4333  break;
-
4334  }
-
4335  auto expectedPerLedger = ripple::detail::numUpVotedAmendments() + 1;
-
4336  checkMetrics(
-
4337  __LINE__, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger, 256);
-
4338 
-
4339  // Now wait 2 weeks modulo 256 ledgers for the amendments to be
-
4340  // enabled. Speed the process by closing ledgers every 80 minutes,
-
4341  // which should get us to just past 2 weeks after 256 ledgers.
-
4342  using namespace std::chrono_literals;
-
4343  auto closeDuration = 80min;
-
4344  for (i = 0; i <= 255; ++i)
-
4345  env.close(closeDuration);
-
4346 
-
4347  // We're very close to the flag ledger. Fill the ledger.
-
4348  fillQueue(env, alice);
-
4349  checkMetrics(
-
4350  __LINE__,
-
4351  env,
-
4352  0,
-
4353  5 * expectedPerLedger,
-
4354  expectedPerLedger + 1,
-
4355  expectedPerLedger,
-
4356  256);
-
4357 
-
4358  // Fill everyone's queues.
-
4359  auto seqAlice = env.seq(alice);
-
4360  auto seqBob = env.seq(bob);
-
4361  auto seqCarol = env.seq(carol);
-
4362  auto seqDaria = env.seq(daria);
-
4363  auto seqEllie = env.seq(ellie);
-
4364  auto seqFiona = env.seq(fiona);
-
4365  // Use fees to guarantee order
-
4366  int txFee{90};
-
4367  for (int i = 0; i < 10; ++i)
-
4368  {
-
4369  env(noop(alice), seq(seqAlice++), fee(--txFee), ter(terQUEUED));
-
4370  env(noop(bob), seq(seqBob++), fee(--txFee), ter(terQUEUED));
-
4371  env(noop(carol), seq(seqCarol++), fee(--txFee), ter(terQUEUED));
-
4372  env(noop(daria), seq(seqDaria++), fee(--txFee), ter(terQUEUED));
-
4373  env(noop(ellie), seq(seqEllie++), fee(--txFee), ter(terQUEUED));
-
4374  env(noop(fiona), seq(seqFiona++), fee(--txFee), ter(terQUEUED));
-
4375  }
-
4376  std::size_t expectedInQueue = 60;
-
4377  checkMetrics(
-
4378  __LINE__,
-
4379  env,
-
4380  expectedInQueue,
-
4381  5 * expectedPerLedger,
-
4382  expectedPerLedger + 1,
-
4383  expectedPerLedger,
-
4384  256);
-
4385 
-
4386  // The next close should cause the in-ledger amendments to change.
-
4387  // Alice's queued transactions have a cached PreflightResult
-
4388  // that resulted from running against the Rules in the previous
-
4389  // ledger. Since the amendments change in this newest ledger
-
4390  // The TxQ must re-run preflight using the new rules.
-
4391  //
-
4392  // These particular amendments don't impact any of the queued
-
4393  // transactions, so we won't see any change in the transaction
-
4394  // outcomes. But code coverage is affected.
-
4395  do
-
4396  {
-
4397  env.close(closeDuration);
-
4398  auto expectedInLedger = expectedInQueue;
-
4399  expectedInQueue =
-
4400  (expectedInQueue > expectedPerLedger + 2
-
4401  ? expectedInQueue - (expectedPerLedger + 2)
-
4402  : 0);
-
4403  expectedInLedger -= expectedInQueue;
-
4404  ++expectedPerLedger;
-
4405  checkMetrics(
-
4406  __LINE__,
-
4407  env,
-
4408  expectedInQueue,
-
4409  5 * expectedPerLedger,
-
4410  expectedInLedger,
-
4411  expectedPerLedger,
-
4412  256);
-
4413  {
-
4414  auto const expectedPerAccount = expectedInQueue / 6;
-
4415  auto const expectedRemainder = expectedInQueue % 6;
-
4416  BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
-
4417  BEAST_EXPECT(
-
4418  env.seq(bob) ==
-
4419  seqBob - expectedPerAccount -
-
4420  (expectedRemainder > 4 ? 1 : 0));
-
4421  BEAST_EXPECT(
-
4422  env.seq(carol) ==
-
4423  seqCarol - expectedPerAccount -
-
4424  (expectedRemainder > 3 ? 1 : 0));
-
4425  BEAST_EXPECT(
-
4426  env.seq(daria) ==
-
4427  seqDaria - expectedPerAccount -
-
4428  (expectedRemainder > 2 ? 1 : 0));
-
4429  BEAST_EXPECT(
-
4430  env.seq(ellie) ==
-
4431  seqEllie - expectedPerAccount -
-
4432  (expectedRemainder > 1 ? 1 : 0));
-
4433  BEAST_EXPECT(
-
4434  env.seq(fiona) ==
-
4435  seqFiona - expectedPerAccount -
-
4436  (expectedRemainder > 0 ? 1 : 0));
-
4437  }
-
4438  } while (expectedInQueue > 0);
-
4439  }
-
4440 
-
4441  void
-
4442  testQueueFullDropPenalty()
-
4443  {
-
4444  // If...
-
4445  // o The queue is close to full,
-
4446  // o An account has multiple txs queued, and
-
4447  // o That same account has a transaction fail
-
4448  // Then drop the last transaction for the account if possible.
-
4449  //
-
4450  // Verify that happens.
-
4451  testcase("Queue full drop penalty");
-
4452  using namespace jtx;
-
4453 
-
4454  // Because we're looking at a phenomenon that occurs when the TxQ
-
4455  // is at 95% capacity or greater, we need to have lots of entries
-
4456  // in the queue. You can't even see 95% capacity unless there are
-
4457  // 20 entries in the queue.
-
4458  Account const alice("alice");
-
4459  Account const bob("bob");
-
4460  Account const carol("carol");
-
4461  Account const daria("daria");
-
4462  Account const ellie("ellie");
-
4463  Account const fiona("fiona");
-
4464 
-
4465  // We'll be using fees to control which entries leave the queue in
-
4466  // which order. There's no "lowFee" -- that's the default fee from
-
4467  // the unit test.
-
4468  int const medFee = 100;
-
4469  int const hiFee = 1000;
-
4470 
-
4471  auto cfg = makeConfig(
-
4472  {{"minimum_txn_in_ledger_standalone", "5"},
-
4473  {"ledgers_in_queue", "5"},
-
4474  {"maximum_txn_per_account", "30"},
-
4475  {"minimum_queue_size", "50"}});
-
4476 
-
4477  Env env(*this, std::move(cfg));
-
4478 
-
4479  // The noripple is to reduce the number of transactions required to
-
4480  // fund the accounts. There is no rippling in this test.
-
4481  env.fund(XRP(10000), noripple(alice, bob, carol, daria, ellie, fiona));
-
4482  env.close();
-
4483 
-
4484  // Get bob some tickets.
-
4485  std::uint32_t const bobTicketSeq = env.seq(bob) + 1;
-
4486  env(ticket::create(bob, 10));
-
4487  env.close();
-
4488 
-
4489  // Get the dropPenalty flag set on alice and bob by having one
-
4490  // of their transactions expire out of the queue. To start out
-
4491  // alice fills the ledger.
-
4492  fillQueue(env, alice);
-
4493  checkMetrics(__LINE__, env, 0, 50, 7, 6, 256);
-
4494 
-
4495  // Now put a few transactions into alice's queue, including one that
-
4496  // will expire out soon.
-
4497  auto seqAlice = env.seq(alice);
-
4498  auto const seqSaveAlice = seqAlice;
-
4499  int feeDrops = 40;
-
4500  env(noop(alice),
-
4501  seq(seqAlice++),
-
4502  fee(--feeDrops),
-
4503  json(R"({"LastLedgerSequence": 7})"),
-
4504  ter(terQUEUED));
-
4505  env(noop(alice), seq(seqAlice++), fee(--feeDrops), ter(terQUEUED));
-
4506  env(noop(alice), seq(seqAlice++), fee(--feeDrops), ter(terQUEUED));
-
4507  BEAST_EXPECT(env.seq(alice) == seqSaveAlice);
-
4508 
-
4509  // Similarly for bob, but bob uses tickets in his transactions.
-
4510  // The drop penalty works a little differently with tickets.
-
4511  env(noop(bob),
-
4512  ticket::use(bobTicketSeq + 0),
-
4513  json(R"({"LastLedgerSequence": 7})"),
-
4514  ter(terQUEUED));
-
4515  env(noop(bob),
-
4516  ticket::use(bobTicketSeq + 1),
-
4517  fee(--feeDrops),
-
4518  ter(terQUEUED));
-
4519  env(noop(bob),
-
4520  ticket::use(bobTicketSeq + 2),
-
4521  fee(--feeDrops),
-
4522  ter(terQUEUED));
-
4523 
-
4524  // Fill the queue with higher fee transactions so alice's and
-
4525  // bob's transactions are stuck in the queue.
-
4526  auto seqCarol = env.seq(carol);
-
4527  auto seqDaria = env.seq(daria);
-
4528  auto seqEllie = env.seq(ellie);
-
4529  auto seqFiona = env.seq(fiona);
-
4530  feeDrops = medFee;
-
4531  for (int i = 0; i < 7; ++i)
-
4532  {
-
4533  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
-
4534  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
-
4535  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
-
4536  env(noop(fiona), seq(seqFiona++), fee(--feeDrops), ter(terQUEUED));
-
4537  }
-
4538 
-
4539  checkMetrics(__LINE__, env, 34, 50, 7, 6, 256);
-
4540  env.close();
-
4541  checkMetrics(__LINE__, env, 26, 50, 8, 7, 256);
-
4542 
-
4543  // Re-fill the queue so alice and bob stay stuck.
-
4544  feeDrops = medFee;
-
4545  for (int i = 0; i < 3; ++i)
-
4546  {
-
4547  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
-
4548  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
-
4549  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
-
4550  env(noop(fiona), seq(seqFiona++), fee(--feeDrops), ter(terQUEUED));
-
4551  }
-
4552  checkMetrics(__LINE__, env, 38, 50, 8, 7, 256);
-
4553  env.close();
-
4554  checkMetrics(__LINE__, env, 29, 50, 9, 8, 256);
-
4555 
-
4556  // One more time...
-
4557  feeDrops = medFee;
-
4558  for (int i = 0; i < 3; ++i)
-
4559  {
-
4560  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
-
4561  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
-
4562  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
-
4563  env(noop(fiona), seq(seqFiona++), fee(--feeDrops), ter(terQUEUED));
-
4564  }
-
4565  checkMetrics(__LINE__, env, 41, 50, 9, 8, 256);
-
4566  env.close();
-
4567  checkMetrics(__LINE__, env, 29, 50, 10, 9, 256);
-
4568 
-
4569  // Finally the stage is set. alice's and bob's transactions expired
-
4570  // out of the queue which caused the dropPenalty flag to be set on
-
4571  // their accounts.
-
4572  //
-
4573  // This also means that alice has a sequence gap in her transactions,
-
4574  // and thus can't queue any more.
-
4575  env(noop(alice), seq(seqAlice), fee(hiFee), ter(telCAN_NOT_QUEUE));
-
4576 
-
4577  // Once again, fill the queue almost to the brim.
-
4578  feeDrops = medFee;
-
4579  for (int i = 0; i < 4; ++i)
-
4580  {
-
4581  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
-
4582  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
-
4583  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
-
4584  env(noop(fiona), seq(seqFiona++), fee(--feeDrops), ter(terQUEUED));
-
4585  }
-
4586  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
-
4587  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
-
4588  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
-
4589  checkMetrics(__LINE__, env, 48, 50, 10, 9, 256);
-
4590 
-
4591  // Now induce a fee jump which should cause all the transactions
-
4592  // in the queue to fail with telINSUF_FEE_P.
-
4593  //
-
4594  // *NOTE* raiseLocalFee() is tricky to use since the local fee is
-
4595  // asynchronously lowered by LoadManager. Here we're just
-
4596  // pushing the local fee up really high and then hoping that we
-
4597  // outrace LoadManager undoing our work.
-
4598  for (int i = 0; i < 30; ++i)
-
4599  env.app().getFeeTrack().raiseLocalFee();
-
4600 
-
4601  // Now close the ledger, which will attempt to process alice's
-
4602  // and bob's queued transactions.
-
4603  // o The _last_ transaction should be dropped from alice's queue.
-
4604  // o The first failing transaction should be dropped from bob's queue.
-
4605  env.close();
-
4606  checkMetrics(__LINE__, env, 46, 50, 0, 10, 256);
-
4607 
-
4608  // Run the local fee back down.
-
4609  while (env.app().getFeeTrack().lowerLocalFee())
-
4610  ;
-
4611 
-
4612  // bob fills the ledger so it's easier to probe the TxQ.
-
4613  fillQueue(env, bob);
-
4614  checkMetrics(__LINE__, env, 46, 50, 11, 10, 256);
-
4615 
-
4616  // Before the close() alice had two transactions in her queue.
-
4617  // We now expect her to have one. Here's the state of alice's queue.
-
4618  //
-
4619  // 0. The transaction that used to be first in her queue expired
-
4620  // out two env.close() calls back. That left a gap in alice's
-
4621  // queue which has not been filled yet.
-
4622  //
-
4623  // 1. The first transaction in the queue failed to apply because
-
4624  // of the sequence gap. But it is retained in the queue.
+
4152  fillQueue(env, alice);
+
4153  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
+
4154 
+
4155  // Queue a transaction
+
4156  auto const aliceSeq = env.seq(alice);
+
4157  env(noop(alice), queued);
+
4158  checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
+
4159 
+
4160  // Now, apply a (different) transaction directly
+
4161  // to the open ledger, bypassing the queue
+
4162  // (This requires calling directly into the open ledger,
+
4163  // which won't work if unit tests are separated to only
+
4164  // be callable via RPC.)
+
4165  env.app().openLedger().modify([&](OpenView& view, beast::Journal j) {
+
4166  auto const tx =
+
4167  env.jt(noop(alice), seq(aliceSeq), openLedgerFee(env));
+
4168  auto const result =
+
4169  ripple::apply(env.app(), view, *tx.stx, tapUNLIMITED, j);
+
4170  BEAST_EXPECT(result.first == tesSUCCESS && result.second);
+
4171  return result.second;
+
4172  });
+
4173  // the queued transaction is still there
+
4174  checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
+
4175 
+
4176  // The next transaction should be able to go into the open
+
4177  // ledger, even though aliceSeq is queued. In earlier incarnations
+
4178  // of the TxQ this would cause an assert.
+
4179  env(noop(alice), seq(aliceSeq + 1), openLedgerFee(env));
+
4180  checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
+
4181  // Now queue a couple more transactions to make sure
+
4182  // they succeed despite aliceSeq being queued
+
4183  env(noop(alice), seq(aliceSeq + 2), queued);
+
4184  env(noop(alice), seq(aliceSeq + 3), queued);
+
4185  checkMetrics(__LINE__, env, 3, std::nullopt, 6, 3, 256);
+
4186 
+
4187  // Now close the ledger. One of the queued transactions
+
4188  // (aliceSeq) should be dropped.
+
4189  env.close();
+
4190  checkMetrics(__LINE__, env, 0, 12, 2, 6, 256);
+
4191  }
+
4192 
+
4193  void
+
4194  testInLedgerTicket()
+
4195  {
+
4196  // Test the situation where a transaction with an account and
+
4197  // ticket that's in the queue also appears in the ledger.
+
4198  //
+
4199  // Although this situation has not (yet) been observed in the wild,
+
4200  // it is a direct analogy to the previous sequence based test. So
+
4201  // there is no reason to not expect to see it in the wild.
+
4202  testcase("Ticket in queue and open ledger");
+
4203  using namespace jtx;
+
4204 
+
4205  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
+
4206 
+
4207  auto alice = Account("alice");
+
4208 
+
4209  auto queued = ter(terQUEUED);
+
4210 
+
4211  BEAST_EXPECT(env.current()->fees().base == 10);
+
4212 
+
4213  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
+
4214 
+
4215  // Create account
+
4216  env.fund(XRP(50000), noripple(alice));
+
4217  checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
+
4218 
+
4219  // Create tickets
+
4220  std::uint32_t const tktSeq0{env.seq(alice) + 1};
+
4221  env(ticket::create(alice, 4));
+
4222 
+
4223  // Fill the queue so the next transaction will be queued.
+
4224  fillQueue(env, alice);
+
4225  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
+
4226 
+
4227  // Queue a transaction with a ticket. Leave an unused ticket
+
4228  // on either side.
+
4229  env(noop(alice), ticket::use(tktSeq0 + 1), queued);
+
4230  checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
+
4231 
+
4232  // Now, apply a (different) transaction directly
+
4233  // to the open ledger, bypassing the queue
+
4234  // (This requires calling directly into the open ledger,
+
4235  // which won't work if unit tests are separated to only
+
4236  // be callable via RPC.)
+
4237  env.app().openLedger().modify([&](OpenView& view, beast::Journal j) {
+
4238  auto const tx = env.jt(
+
4239  noop(alice), ticket::use(tktSeq0 + 1), openLedgerFee(env));
+
4240  auto const result =
+
4241  ripple::apply(env.app(), view, *tx.stx, tapUNLIMITED, j);
+
4242  BEAST_EXPECT(result.first == tesSUCCESS && result.second);
+
4243  return result.second;
+
4244  });
+
4245  // the queued transaction is still there
+
4246  checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
+
4247 
+
4248  // The next (sequence-based) transaction should be able to go into
+
4249  // the open ledger, even though tktSeq0 is queued. Note that this
+
4250  // sequence-based transaction goes in front of the queued
+
4251  // transaction, so the queued transaction is left in the queue.
+
4252  env(noop(alice), openLedgerFee(env));
+
4253  checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
+
4254 
+
4255  // We should be able to do the same thing with a ticket that goes
+
4256  // if front of the queued transaction. This one too will leave
+
4257  // the queued transaction in place.
+
4258  env(noop(alice), ticket::use(tktSeq0 + 0), openLedgerFee(env));
+
4259  checkMetrics(__LINE__, env, 1, std::nullopt, 7, 3, 256);
+
4260 
+
4261  // We have one ticketed transaction in the queue. We should able
+
4262  // to add another to the queue.
+
4263  env(noop(alice), ticket::use(tktSeq0 + 2), queued);
+
4264  checkMetrics(__LINE__, env, 2, std::nullopt, 7, 3, 256);
+
4265 
+
4266  // Here we try to force the queued transactions into the ledger by
+
4267  // adding one more queued (ticketed) transaction that pays enough
+
4268  // so fee averaging kicks in. It doesn't work. It only succeeds in
+
4269  // forcing just the one ticketed transaction into the ledger.
+
4270  //
+
4271  // The fee averaging functionality makes sense for sequence-based
+
4272  // transactions because if there are several sequence-based
+
4273  // transactions queued, the transactions in front must go into the
+
4274  // ledger before the later ones can go in.
+
4275  //
+
4276  // Fee averaging does not make sense with tickets. Every ticketed
+
4277  // transaction is equally capable of going into the ledger independent
+
4278  // of all other ticket- or sequence-based transactions.
+
4279  env(noop(alice), ticket::use(tktSeq0 + 3), fee(XRP(1)));
+
4280  checkMetrics(__LINE__, env, 2, std::nullopt, 8, 3, 256);
+
4281 
+
4282  // Now close the ledger. One of the queued transactions
+
4283  // (the one with tktSeq0 + 1) should be dropped.
+
4284  env.close();
+
4285  checkMetrics(__LINE__, env, 0, 16, 1, 8, 256);
+
4286  }
+
4287 
+
4288  void
+
4289  testReexecutePreflight()
+
4290  {
+
4291  // The TxQ caches preflight results. But there are situations where
+
4292  // that cache must become invalidated, like if amendments change.
+
4293  //
+
4294  // This test puts transactions into the TxQ and then enables an
+
4295  // amendment. We won't really see much interesting here in the unit
+
4296  // test, but the code that checks for cache invalidation should be
+
4297  // exercised. You can see that in improved code coverage,
+
4298  testcase("Re-execute preflight");
+
4299  using namespace jtx;
+
4300 
+
4301  Account const alice("alice");
+
4302  Account const bob("bob");
+
4303  Account const carol("carol");
+
4304  Account const daria("daria");
+
4305  Account const ellie("ellie");
+
4306  Account const fiona("fiona");
+
4307 
+
4308  auto cfg = makeConfig(
+
4309  {{"minimum_txn_in_ledger_standalone", "1"},
+
4310  {"ledgers_in_queue", "5"},
+
4311  {"maximum_txn_per_account", "10"}},
+
4312  {{"account_reserve", "1000"}, {"owner_reserve", "50"}});
+
4313 
+
4314  Env env(*this, std::move(cfg));
+
4315 
+
4316  env.fund(XRP(10000), alice);
+
4317  env.close();
+
4318  env.fund(XRP(10000), bob);
+
4319  env.close();
+
4320  env.fund(XRP(10000), carol);
+
4321  env.close();
+
4322  env.fund(XRP(10000), daria);
+
4323  env.close();
+
4324  env.fund(XRP(10000), ellie);
+
4325  env.close();
+
4326  env.fund(XRP(10000), fiona);
+
4327  env.close();
+
4328  checkMetrics(__LINE__, env, 0, 10, 0, 2, 256);
+
4329 
+
4330  // Close ledgers until the amendments show up.
+
4331  int i = 0;
+
4332  for (i = 0; i <= 257; ++i)
+
4333  {
+
4334  env.close();
+
4335  if (!getMajorityAmendments(*env.closed()).empty())
+
4336  break;
+
4337  }
+
4338  auto expectedPerLedger = ripple::detail::numUpVotedAmendments() + 1;
+
4339  checkMetrics(
+
4340  __LINE__, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger, 256);
+
4341 
+
4342  // Now wait 2 weeks modulo 256 ledgers for the amendments to be
+
4343  // enabled. Speed the process by closing ledgers every 80 minutes,
+
4344  // which should get us to just past 2 weeks after 256 ledgers.
+
4345  using namespace std::chrono_literals;
+
4346  auto closeDuration = 80min;
+
4347  for (i = 0; i <= 255; ++i)
+
4348  env.close(closeDuration);
+
4349 
+
4350  // We're very close to the flag ledger. Fill the ledger.
+
4351  fillQueue(env, alice);
+
4352  checkMetrics(
+
4353  __LINE__,
+
4354  env,
+
4355  0,
+
4356  5 * expectedPerLedger,
+
4357  expectedPerLedger + 1,
+
4358  expectedPerLedger,
+
4359  256);
+
4360 
+
4361  // Fill everyone's queues.
+
4362  auto seqAlice = env.seq(alice);
+
4363  auto seqBob = env.seq(bob);
+
4364  auto seqCarol = env.seq(carol);
+
4365  auto seqDaria = env.seq(daria);
+
4366  auto seqEllie = env.seq(ellie);
+
4367  auto seqFiona = env.seq(fiona);
+
4368  // Use fees to guarantee order
+
4369  int txFee{90};
+
4370  for (int i = 0; i < 10; ++i)
+
4371  {
+
4372  env(noop(alice), seq(seqAlice++), fee(--txFee), ter(terQUEUED));
+
4373  env(noop(bob), seq(seqBob++), fee(--txFee), ter(terQUEUED));
+
4374  env(noop(carol), seq(seqCarol++), fee(--txFee), ter(terQUEUED));
+
4375  env(noop(daria), seq(seqDaria++), fee(--txFee), ter(terQUEUED));
+
4376  env(noop(ellie), seq(seqEllie++), fee(--txFee), ter(terQUEUED));
+
4377  env(noop(fiona), seq(seqFiona++), fee(--txFee), ter(terQUEUED));
+
4378  }
+
4379  std::size_t expectedInQueue = 60;
+
4380  checkMetrics(
+
4381  __LINE__,
+
4382  env,
+
4383  expectedInQueue,
+
4384  5 * expectedPerLedger,
+
4385  expectedPerLedger + 1,
+
4386  expectedPerLedger,
+
4387  256);
+
4388 
+
4389  // The next close should cause the in-ledger amendments to change.
+
4390  // Alice's queued transactions have a cached PreflightResult
+
4391  // that resulted from running against the Rules in the previous
+
4392  // ledger. Since the amendments change in this newest ledger
+
4393  // The TxQ must re-run preflight using the new rules.
+
4394  //
+
4395  // These particular amendments don't impact any of the queued
+
4396  // transactions, so we won't see any change in the transaction
+
4397  // outcomes. But code coverage is affected.
+
4398  do
+
4399  {
+
4400  env.close(closeDuration);
+
4401  auto expectedInLedger = expectedInQueue;
+
4402  expectedInQueue =
+
4403  (expectedInQueue > expectedPerLedger + 2
+
4404  ? expectedInQueue - (expectedPerLedger + 2)
+
4405  : 0);
+
4406  expectedInLedger -= expectedInQueue;
+
4407  ++expectedPerLedger;
+
4408  checkMetrics(
+
4409  __LINE__,
+
4410  env,
+
4411  expectedInQueue,
+
4412  5 * expectedPerLedger,
+
4413  expectedInLedger,
+
4414  expectedPerLedger,
+
4415  256);
+
4416  {
+
4417  auto const expectedPerAccount = expectedInQueue / 6;
+
4418  auto const expectedRemainder = expectedInQueue % 6;
+
4419  BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
+
4420  BEAST_EXPECT(
+
4421  env.seq(bob) ==
+
4422  seqBob - expectedPerAccount -
+
4423  (expectedRemainder > 4 ? 1 : 0));
+
4424  BEAST_EXPECT(
+
4425  env.seq(carol) ==
+
4426  seqCarol - expectedPerAccount -
+
4427  (expectedRemainder > 3 ? 1 : 0));
+
4428  BEAST_EXPECT(
+
4429  env.seq(daria) ==
+
4430  seqDaria - expectedPerAccount -
+
4431  (expectedRemainder > 2 ? 1 : 0));
+
4432  BEAST_EXPECT(
+
4433  env.seq(ellie) ==
+
4434  seqEllie - expectedPerAccount -
+
4435  (expectedRemainder > 1 ? 1 : 0));
+
4436  BEAST_EXPECT(
+
4437  env.seq(fiona) ==
+
4438  seqFiona - expectedPerAccount -
+
4439  (expectedRemainder > 0 ? 1 : 0));
+
4440  }
+
4441  } while (expectedInQueue > 0);
+
4442  }
+
4443 
+
4444  void
+
4445  testQueueFullDropPenalty()
+
4446  {
+
4447  // If...
+
4448  // o The queue is close to full,
+
4449  // o An account has multiple txs queued, and
+
4450  // o That same account has a transaction fail
+
4451  // Then drop the last transaction for the account if possible.
+
4452  //
+
4453  // Verify that happens.
+
4454  testcase("Queue full drop penalty");
+
4455  using namespace jtx;
+
4456 
+
4457  // Because we're looking at a phenomenon that occurs when the TxQ
+
4458  // is at 95% capacity or greater, we need to have lots of entries
+
4459  // in the queue. You can't even see 95% capacity unless there are
+
4460  // 20 entries in the queue.
+
4461  Account const alice("alice");
+
4462  Account const bob("bob");
+
4463  Account const carol("carol");
+
4464  Account const daria("daria");
+
4465  Account const ellie("ellie");
+
4466  Account const fiona("fiona");
+
4467 
+
4468  // We'll be using fees to control which entries leave the queue in
+
4469  // which order. There's no "lowFee" -- that's the default fee from
+
4470  // the unit test.
+
4471  int const medFee = 100;
+
4472  int const hiFee = 1000;
+
4473 
+
4474  auto cfg = makeConfig(
+
4475  {{"minimum_txn_in_ledger_standalone", "5"},
+
4476  {"ledgers_in_queue", "5"},
+
4477  {"maximum_txn_per_account", "30"},
+
4478  {"minimum_queue_size", "50"}});
+
4479 
+
4480  Env env(*this, std::move(cfg));
+
4481 
+
4482  // The noripple is to reduce the number of transactions required to
+
4483  // fund the accounts. There is no rippling in this test.
+
4484  env.fund(XRP(10000), noripple(alice, bob, carol, daria, ellie, fiona));
+
4485  env.close();
+
4486 
+
4487  // Get bob some tickets.
+
4488  std::uint32_t const bobTicketSeq = env.seq(bob) + 1;
+
4489  env(ticket::create(bob, 10));
+
4490  env.close();
+
4491 
+
4492  // Get the dropPenalty flag set on alice and bob by having one
+
4493  // of their transactions expire out of the queue. To start out
+
4494  // alice fills the ledger.
+
4495  fillQueue(env, alice);
+
4496  checkMetrics(__LINE__, env, 0, 50, 7, 6, 256);
+
4497 
+
4498  // Now put a few transactions into alice's queue, including one that
+
4499  // will expire out soon.
+
4500  auto seqAlice = env.seq(alice);
+
4501  auto const seqSaveAlice = seqAlice;
+
4502  int feeDrops = 40;
+
4503  env(noop(alice),
+
4504  seq(seqAlice++),
+
4505  fee(--feeDrops),
+
4506  json(R"({"LastLedgerSequence": 7})"),
+
4507  ter(terQUEUED));
+
4508  env(noop(alice), seq(seqAlice++), fee(--feeDrops), ter(terQUEUED));
+
4509  env(noop(alice), seq(seqAlice++), fee(--feeDrops), ter(terQUEUED));
+
4510  BEAST_EXPECT(env.seq(alice) == seqSaveAlice);
+
4511 
+
4512  // Similarly for bob, but bob uses tickets in his transactions.
+
4513  // The drop penalty works a little differently with tickets.
+
4514  env(noop(bob),
+
4515  ticket::use(bobTicketSeq + 0),
+
4516  json(R"({"LastLedgerSequence": 7})"),
+
4517  ter(terQUEUED));
+
4518  env(noop(bob),
+
4519  ticket::use(bobTicketSeq + 1),
+
4520  fee(--feeDrops),
+
4521  ter(terQUEUED));
+
4522  env(noop(bob),
+
4523  ticket::use(bobTicketSeq + 2),
+
4524  fee(--feeDrops),
+
4525  ter(terQUEUED));
+
4526 
+
4527  // Fill the queue with higher fee transactions so alice's and
+
4528  // bob's transactions are stuck in the queue.
+
4529  auto seqCarol = env.seq(carol);
+
4530  auto seqDaria = env.seq(daria);
+
4531  auto seqEllie = env.seq(ellie);
+
4532  auto seqFiona = env.seq(fiona);
+
4533  feeDrops = medFee;
+
4534  for (int i = 0; i < 7; ++i)
+
4535  {
+
4536  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
+
4537  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
+
4538  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
+
4539  env(noop(fiona), seq(seqFiona++), fee(--feeDrops), ter(terQUEUED));
+
4540  }
+
4541 
+
4542  checkMetrics(__LINE__, env, 34, 50, 7, 6, 256);
+
4543  env.close();
+
4544  checkMetrics(__LINE__, env, 26, 50, 8, 7, 256);
+
4545 
+
4546  // Re-fill the queue so alice and bob stay stuck.
+
4547  feeDrops = medFee;
+
4548  for (int i = 0; i < 3; ++i)
+
4549  {
+
4550  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
+
4551  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
+
4552  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
+
4553  env(noop(fiona), seq(seqFiona++), fee(--feeDrops), ter(terQUEUED));
+
4554  }
+
4555  checkMetrics(__LINE__, env, 38, 50, 8, 7, 256);
+
4556  env.close();
+
4557  checkMetrics(__LINE__, env, 29, 50, 9, 8, 256);
+
4558 
+
4559  // One more time...
+
4560  feeDrops = medFee;
+
4561  for (int i = 0; i < 3; ++i)
+
4562  {
+
4563  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
+
4564  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
+
4565  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
+
4566  env(noop(fiona), seq(seqFiona++), fee(--feeDrops), ter(terQUEUED));
+
4567  }
+
4568  checkMetrics(__LINE__, env, 41, 50, 9, 8, 256);
+
4569  env.close();
+
4570  checkMetrics(__LINE__, env, 29, 50, 10, 9, 256);
+
4571 
+
4572  // Finally the stage is set. alice's and bob's transactions expired
+
4573  // out of the queue which caused the dropPenalty flag to be set on
+
4574  // their accounts.
+
4575  //
+
4576  // This also means that alice has a sequence gap in her transactions,
+
4577  // and thus can't queue any more.
+
4578  env(noop(alice), seq(seqAlice), fee(hiFee), ter(telCAN_NOT_QUEUE));
+
4579 
+
4580  // Once again, fill the queue almost to the brim.
+
4581  feeDrops = medFee;
+
4582  for (int i = 0; i < 4; ++i)
+
4583  {
+
4584  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
+
4585  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
+
4586  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
+
4587  env(noop(fiona), seq(seqFiona++), fee(--feeDrops), ter(terQUEUED));
+
4588  }
+
4589  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
+
4590  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
+
4591  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
+
4592  checkMetrics(__LINE__, env, 48, 50, 10, 9, 256);
+
4593 
+
4594  // Now induce a fee jump which should cause all the transactions
+
4595  // in the queue to fail with telINSUF_FEE_P.
+
4596  //
+
4597  // *NOTE* raiseLocalFee() is tricky to use since the local fee is
+
4598  // asynchronously lowered by LoadManager. Here we're just
+
4599  // pushing the local fee up really high and then hoping that we
+
4600  // outrace LoadManager undoing our work.
+
4601  for (int i = 0; i < 30; ++i)
+
4602  env.app().getFeeTrack().raiseLocalFee();
+
4603 
+
4604  // Now close the ledger, which will attempt to process alice's
+
4605  // and bob's queued transactions.
+
4606  // o The _last_ transaction should be dropped from alice's queue.
+
4607  // o The first failing transaction should be dropped from bob's queue.
+
4608  env.close();
+
4609  checkMetrics(__LINE__, env, 46, 50, 0, 10, 256);
+
4610 
+
4611  // Run the local fee back down.
+
4612  while (env.app().getFeeTrack().lowerLocalFee())
+
4613  ;
+
4614 
+
4615  // bob fills the ledger so it's easier to probe the TxQ.
+
4616  fillQueue(env, bob);
+
4617  checkMetrics(__LINE__, env, 46, 50, 11, 10, 256);
+
4618 
+
4619  // Before the close() alice had two transactions in her queue.
+
4620  // We now expect her to have one. Here's the state of alice's queue.
+
4621  //
+
4622  // 0. The transaction that used to be first in her queue expired
+
4623  // out two env.close() calls back. That left a gap in alice's
+
4624  // queue which has not been filled yet.
4625  //
-
4626  // 2. The last (second) transaction in alice's queue was removed
-
4627  // as "punishment"...
-
4628  // a) For already having a transaction expire out of her queue, and
-
4629  // b) For just now having a queued transaction fail on apply()
-
4630  // because of the sequence gap.
-
4631  //
-
4632  // Verify that none of alice's queued transactions actually applied to
-
4633  // her account.
-
4634  BEAST_EXPECT(env.seq(alice) == seqSaveAlice);
-
4635  seqAlice = seqSaveAlice;
-
4636 
-
4637  // Verify that there's a gap at the front of alice's queue by
-
4638  // queuing another low fee transaction into that spot.
-
4639  env(noop(alice), seq(seqAlice++), fee(11), ter(terQUEUED));
-
4640 
-
4641  // Verify that the first entry in alice's queue is still there
-
4642  // by trying to replace it and having that fail.
-
4643  env(noop(alice), seq(seqAlice++), ter(telCAN_NOT_QUEUE_FEE));
-
4644 
-
4645  // Verify that the last transaction in alice's queue was removed by
-
4646  // appending to her queue with a very low fee.
-
4647  env(noop(alice), seq(seqAlice++), ter(terQUEUED));
-
4648 
-
4649  // Before the close() bob had two transactions in his queue.
-
4650  // We now expect him to have one. Here's the state of bob's queue.
-
4651  //
-
4652  // 0. The transaction that used to be first in his queue expired out
-
4653  // two env.close() calls back. That is how the dropPenalty flag
-
4654  // got set on bob's queue.
-
4655  //
-
4656  // 1. Since bob's remaining transactions all have the same fee, the
-
4657  // TxQ attempted to apply bob's second transaction to the ledger,
-
4658  // but the fee was too low. So the TxQ threw that transaction
-
4659  // (not bob's last transaction) out of the queue.
-
4660  //
-
4661  // 2. The last of bob's transactions remains in the TxQ.
-
4662 
-
4663  // Verify that bob's first transaction was removed from the queue
-
4664  // by queueing another low fee transaction into that spot.
-
4665  env(noop(bob), ticket::use(bobTicketSeq + 0), fee(12), ter(terQUEUED));
-
4666 
-
4667  // Verify that bob's second transaction was removed from the queue
-
4668  // by queueing another low fee transaction into that spot.
-
4669  env(noop(bob), ticket::use(bobTicketSeq + 1), fee(11), ter(terQUEUED));
-
4670 
-
4671  // Verify that the last entry in bob's queue is still there
-
4672  // by trying to replace it and having that fail.
-
4673  env(noop(bob),
-
4674  ticket::use(bobTicketSeq + 2),
-
4675  ter(telCAN_NOT_QUEUE_FEE));
-
4676  }
-
4677 
-
4678  void
-
4679  testCancelQueuedOffers()
-
4680  {
-
4681  testcase("Cancel queued offers");
-
4682  using namespace jtx;
-
4683 
-
4684  Account const alice("alice");
-
4685  auto gw = Account("gw");
-
4686  auto USD = gw["USD"];
-
4687 
-
4688  auto cfg = makeConfig(
-
4689  {{"minimum_txn_in_ledger_standalone", "5"},
-
4690  {"ledgers_in_queue", "5"},
-
4691  {"maximum_txn_per_account", "30"},
-
4692  {"minimum_queue_size", "50"}});
-
4693 
-
4694  Env env(*this, std::move(cfg));
-
4695 
-
4696  // The noripple is to reduce the number of transactions required to
-
4697  // fund the accounts. There is no rippling in this test.
-
4698  env.fund(XRP(100000), noripple(alice));
-
4699  env.close();
-
4700 
-
4701  {
-
4702  // ------- Sequence-based transactions -------
-
4703  fillQueue(env, alice);
-
4704 
-
4705  // Alice creates a couple offers
-
4706  auto const aliceSeq = env.seq(alice);
-
4707  env(offer(alice, USD(1000), XRP(1000)), ter(terQUEUED));
-
4708 
-
4709  env(offer(alice, USD(1000), XRP(1001)),
-
4710  seq(aliceSeq + 1),
-
4711  ter(terQUEUED));
-
4712 
-
4713  // Alice creates transactions that cancel the first set of
-
4714  // offers, one through another offer, and one cancel
-
4715  env(offer(alice, USD(1000), XRP(1002)),
-
4716  seq(aliceSeq + 2),
-
4717  json(jss::OfferSequence, aliceSeq),
-
4718  ter(terQUEUED));
-
4719 
-
4720  env(offer_cancel(alice, aliceSeq + 1),
-
4721  seq(aliceSeq + 3),
-
4722  ter(terQUEUED));
-
4723 
-
4724  env.close();
-
4725 
-
4726  checkMetrics(__LINE__, env, 0, 50, 4, 6, 256);
-
4727  }
+
4626  // 1. The first transaction in the queue failed to apply because
+
4627  // of the sequence gap. But it is retained in the queue.
+
4628  //
+
4629  // 2. The last (second) transaction in alice's queue was removed
+
4630  // as "punishment"...
+
4631  // a) For already having a transaction expire out of her queue, and
+
4632  // b) For just now having a queued transaction fail on apply()
+
4633  // because of the sequence gap.
+
4634  //
+
4635  // Verify that none of alice's queued transactions actually applied to
+
4636  // her account.
+
4637  BEAST_EXPECT(env.seq(alice) == seqSaveAlice);
+
4638  seqAlice = seqSaveAlice;
+
4639 
+
4640  // Verify that there's a gap at the front of alice's queue by
+
4641  // queuing another low fee transaction into that spot.
+
4642  env(noop(alice), seq(seqAlice++), fee(11), ter(terQUEUED));
+
4643 
+
4644  // Verify that the first entry in alice's queue is still there
+
4645  // by trying to replace it and having that fail.
+
4646  env(noop(alice), seq(seqAlice++), ter(telCAN_NOT_QUEUE_FEE));
+
4647 
+
4648  // Verify that the last transaction in alice's queue was removed by
+
4649  // appending to her queue with a very low fee.
+
4650  env(noop(alice), seq(seqAlice++), ter(terQUEUED));
+
4651 
+
4652  // Before the close() bob had two transactions in his queue.
+
4653  // We now expect him to have one. Here's the state of bob's queue.
+
4654  //
+
4655  // 0. The transaction that used to be first in his queue expired out
+
4656  // two env.close() calls back. That is how the dropPenalty flag
+
4657  // got set on bob's queue.
+
4658  //
+
4659  // 1. Since bob's remaining transactions all have the same fee, the
+
4660  // TxQ attempted to apply bob's second transaction to the ledger,
+
4661  // but the fee was too low. So the TxQ threw that transaction
+
4662  // (not bob's last transaction) out of the queue.
+
4663  //
+
4664  // 2. The last of bob's transactions remains in the TxQ.
+
4665 
+
4666  // Verify that bob's first transaction was removed from the queue
+
4667  // by queueing another low fee transaction into that spot.
+
4668  env(noop(bob), ticket::use(bobTicketSeq + 0), fee(12), ter(terQUEUED));
+
4669 
+
4670  // Verify that bob's second transaction was removed from the queue
+
4671  // by queueing another low fee transaction into that spot.
+
4672  env(noop(bob), ticket::use(bobTicketSeq + 1), fee(11), ter(terQUEUED));
+
4673 
+
4674  // Verify that the last entry in bob's queue is still there
+
4675  // by trying to replace it and having that fail.
+
4676  env(noop(bob),
+
4677  ticket::use(bobTicketSeq + 2),
+
4678  ter(telCAN_NOT_QUEUE_FEE));
+
4679  }
+
4680 
+
4681  void
+
4682  testCancelQueuedOffers()
+
4683  {
+
4684  testcase("Cancel queued offers");
+
4685  using namespace jtx;
+
4686 
+
4687  Account const alice("alice");
+
4688  auto gw = Account("gw");
+
4689  auto USD = gw["USD"];
+
4690 
+
4691  auto cfg = makeConfig(
+
4692  {{"minimum_txn_in_ledger_standalone", "5"},
+
4693  {"ledgers_in_queue", "5"},
+
4694  {"maximum_txn_per_account", "30"},
+
4695  {"minimum_queue_size", "50"}});
+
4696 
+
4697  Env env(*this, std::move(cfg));
+
4698 
+
4699  // The noripple is to reduce the number of transactions required to
+
4700  // fund the accounts. There is no rippling in this test.
+
4701  env.fund(XRP(100000), noripple(alice));
+
4702  env.close();
+
4703 
+
4704  {
+
4705  // ------- Sequence-based transactions -------
+
4706  fillQueue(env, alice);
+
4707 
+
4708  // Alice creates a couple offers
+
4709  auto const aliceSeq = env.seq(alice);
+
4710  env(offer(alice, USD(1000), XRP(1000)), ter(terQUEUED));
+
4711 
+
4712  env(offer(alice, USD(1000), XRP(1001)),
+
4713  seq(aliceSeq + 1),
+
4714  ter(terQUEUED));
+
4715 
+
4716  // Alice creates transactions that cancel the first set of
+
4717  // offers, one through another offer, and one cancel
+
4718  env(offer(alice, USD(1000), XRP(1002)),
+
4719  seq(aliceSeq + 2),
+
4720  json(jss::OfferSequence, aliceSeq),
+
4721  ter(terQUEUED));
+
4722 
+
4723  env(offer_cancel(alice, aliceSeq + 1),
+
4724  seq(aliceSeq + 3),
+
4725  ter(terQUEUED));
+
4726 
+
4727  env.close();
4728 
-
4729  {
-
4730  // ------- Ticket-based transactions -------
+
4729  checkMetrics(__LINE__, env, 0, 50, 4, 6, 256);
+
4730  }
4731 
-
4732  // Alice creates some tickets
-
4733  auto const aliceTkt = env.seq(alice);
-
4734  env(ticket::create(alice, 6));
-
4735  env.close();
-
4736 
-
4737  fillQueue(env, alice);
-
4738 
-
4739  // Alice creates a couple offers using tickets, consuming the
-
4740  // tickets in reverse order
-
4741  auto const aliceSeq = env.seq(alice);
-
4742  env(offer(alice, USD(1000), XRP(1000)),
-
4743  ticket::use(aliceTkt + 4),
-
4744  ter(terQUEUED));
-
4745 
-
4746  env(offer(alice, USD(1000), XRP(1001)),
-
4747  ticket::use(aliceTkt + 3),
-
4748  ter(terQUEUED));
-
4749 
-
4750  // Alice creates a couple more transactions that cancel the first
-
4751  // set of offers, also in reverse order. This allows Alice to submit
-
4752  // a tx with a lower ticket value than the offer it's cancelling.
-
4753  // These transactions succeed because Ticket ordering is arbitrary
-
4754  // and it's up to the user to ensure they don't step on their own
-
4755  // feet.
-
4756  env(offer(alice, USD(1000), XRP(1002)),
-
4757  ticket::use(aliceTkt + 2),
-
4758  json(jss::OfferSequence, aliceTkt + 4),
-
4759  ter(terQUEUED));
-
4760 
-
4761  env(offer_cancel(alice, aliceTkt + 3),
-
4762  ticket::use(aliceTkt + 1),
-
4763  ter(terQUEUED));
-
4764 
-
4765  // Create a couple more offers using sequences
-
4766  env(offer(alice, USD(1000), XRP(1000)), ter(terQUEUED));
+
4732  {
+
4733  // ------- Ticket-based transactions -------
+
4734 
+
4735  // Alice creates some tickets
+
4736  auto const aliceTkt = env.seq(alice);
+
4737  env(ticket::create(alice, 6));
+
4738  env.close();
+
4739 
+
4740  fillQueue(env, alice);
+
4741 
+
4742  // Alice creates a couple offers using tickets, consuming the
+
4743  // tickets in reverse order
+
4744  auto const aliceSeq = env.seq(alice);
+
4745  env(offer(alice, USD(1000), XRP(1000)),
+
4746  ticket::use(aliceTkt + 4),
+
4747  ter(terQUEUED));
+
4748 
+
4749  env(offer(alice, USD(1000), XRP(1001)),
+
4750  ticket::use(aliceTkt + 3),
+
4751  ter(terQUEUED));
+
4752 
+
4753  // Alice creates a couple more transactions that cancel the first
+
4754  // set of offers, also in reverse order. This allows Alice to submit
+
4755  // a tx with a lower ticket value than the offer it's cancelling.
+
4756  // These transactions succeed because Ticket ordering is arbitrary
+
4757  // and it's up to the user to ensure they don't step on their own
+
4758  // feet.
+
4759  env(offer(alice, USD(1000), XRP(1002)),
+
4760  ticket::use(aliceTkt + 2),
+
4761  json(jss::OfferSequence, aliceTkt + 4),
+
4762  ter(terQUEUED));
+
4763 
+
4764  env(offer_cancel(alice, aliceTkt + 3),
+
4765  ticket::use(aliceTkt + 1),
+
4766  ter(terQUEUED));
4767 
-
4768  env(offer(alice, USD(1000), XRP(1001)),
-
4769  seq(aliceSeq + 1),
-
4770  ter(terQUEUED));
-
4771 
-
4772  // And try to cancel those using tickets
-
4773  env(offer(alice, USD(1000), XRP(1002)),
-
4774  ticket::use(aliceTkt + 5),
-
4775  json(jss::OfferSequence, aliceSeq),
-
4776  ter(terQUEUED));
-
4777 
-
4778  env(offer_cancel(alice, aliceSeq + 1),
-
4779  ticket::use(aliceTkt + 6),
-
4780  ter(terQUEUED));
-
4781 
-
4782  env.close();
-
4783 
-
4784  // The ticket transactions that didn't succeed or get queued succeed
-
4785  // this time because the tickets got consumed when the offers came
-
4786  // out of the queue
-
4787  checkMetrics(__LINE__, env, 0, 50, 8, 7, 256);
-
4788  }
-
4789  }
-
4790 
-
4791  void
-
4792  testZeroReferenceFee()
-
4793  {
-
4794  testcase("Zero reference fee");
-
4795  using namespace jtx;
-
4796 
-
4797  Account const alice("alice");
-
4798  auto const queued = ter(terQUEUED);
+
4768  // Create a couple more offers using sequences
+
4769  env(offer(alice, USD(1000), XRP(1000)), ter(terQUEUED));
+
4770 
+
4771  env(offer(alice, USD(1000), XRP(1001)),
+
4772  seq(aliceSeq + 1),
+
4773  ter(terQUEUED));
+
4774 
+
4775  // And try to cancel those using tickets
+
4776  env(offer(alice, USD(1000), XRP(1002)),
+
4777  ticket::use(aliceTkt + 5),
+
4778  json(jss::OfferSequence, aliceSeq),
+
4779  ter(terQUEUED));
+
4780 
+
4781  env(offer_cancel(alice, aliceSeq + 1),
+
4782  ticket::use(aliceTkt + 6),
+
4783  ter(terQUEUED));
+
4784 
+
4785  env.close();
+
4786 
+
4787  // The ticket transactions that didn't succeed or get queued succeed
+
4788  // this time because the tickets got consumed when the offers came
+
4789  // out of the queue
+
4790  checkMetrics(__LINE__, env, 0, 50, 8, 7, 256);
+
4791  }
+
4792  }
+
4793 
+
4794  void
+
4795  testZeroReferenceFee()
+
4796  {
+
4797  testcase("Zero reference fee");
+
4798  using namespace jtx;
4799 
-
4800  Env env(
-
4801  *this,
-
4802  makeConfig(
-
4803  {{"minimum_txn_in_ledger_standalone", "3"}},
-
4804  {{"reference_fee", "0"},
-
4805  {"account_reserve", "0"},
-
4806  {"owner_reserve", "0"}}));
-
4807 
-
4808  BEAST_EXPECT(env.current()->fees().base == 10);
-
4809 
-
4810  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
-
4811 
-
4812  // ledgers in queue is 2 because of makeConfig
-
4813  auto const initQueueMax = initFee(env, 3, 2, 0, 0, 0);
+
4800  Account const alice("alice");
+
4801  auto const queued = ter(terQUEUED);
+
4802 
+
4803  Env env(
+
4804  *this,
+
4805  makeConfig(
+
4806  {{"minimum_txn_in_ledger_standalone", "3"}},
+
4807  {{"reference_fee", "0"},
+
4808  {"account_reserve", "0"},
+
4809  {"owner_reserve", "0"}}));
+
4810 
+
4811  BEAST_EXPECT(env.current()->fees().base == 10);
+
4812 
+
4813  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4814 
-
4815  BEAST_EXPECT(env.current()->fees().base == 0);
-
4816 
-
4817  {
-
4818  auto const fee = env.rpc("fee");
+
4815  // ledgers in queue is 2 because of makeConfig
+
4816  auto const initQueueMax = initFee(env, 3, 2, 0, 0, 0);
+
4817 
+
4818  BEAST_EXPECT(env.current()->fees().base == 0);
4819 
-
4820  if (BEAST_EXPECT(fee.isMember(jss::result)) &&
-
4821  BEAST_EXPECT(!RPC::contains_error(fee[jss::result])))
-
4822  {
-
4823  auto const& result = fee[jss::result];
-
4824 
-
4825  BEAST_EXPECT(result.isMember(jss::levels));
-
4826  auto const& levels = result[jss::levels];
-
4827  BEAST_EXPECT(
-
4828  levels.isMember(jss::median_level) &&
-
4829  levels[jss::median_level] == "128000");
+
4820  {
+
4821  auto const fee = env.rpc("fee");
+
4822 
+
4823  if (BEAST_EXPECT(fee.isMember(jss::result)) &&
+
4824  BEAST_EXPECT(!RPC::contains_error(fee[jss::result])))
+
4825  {
+
4826  auto const& result = fee[jss::result];
+
4827 
+
4828  BEAST_EXPECT(result.isMember(jss::levels));
+
4829  auto const& levels = result[jss::levels];
4830  BEAST_EXPECT(
-
4831  levels.isMember(jss::minimum_level) &&
-
4832  levels[jss::minimum_level] == "256");
+
4831  levels.isMember(jss::median_level) &&
+
4832  levels[jss::median_level] == "128000");
4833  BEAST_EXPECT(
-
4834  levels.isMember(jss::open_ledger_level) &&
-
4835  levels[jss::open_ledger_level] == "256");
+
4834  levels.isMember(jss::minimum_level) &&
+
4835  levels[jss::minimum_level] == "256");
4836  BEAST_EXPECT(
-
4837  levels.isMember(jss::reference_level) &&
-
4838  levels[jss::reference_level] == "256");
-
4839 
-
4840  auto const& drops = result[jss::drops];
-
4841  BEAST_EXPECT(
-
4842  drops.isMember(jss::base_fee) &&
-
4843  drops[jss::base_fee] == "0");
+
4837  levels.isMember(jss::open_ledger_level) &&
+
4838  levels[jss::open_ledger_level] == "256");
+
4839  BEAST_EXPECT(
+
4840  levels.isMember(jss::reference_level) &&
+
4841  levels[jss::reference_level] == "256");
+
4842 
+
4843  auto const& drops = result[jss::drops];
4844  BEAST_EXPECT(
-
4845  drops.isMember(jss::median_fee) &&
-
4846  drops[jss::median_fee] == "0");
+
4845  drops.isMember(jss::base_fee) &&
+
4846  drops[jss::base_fee] == "0");
4847  BEAST_EXPECT(
-
4848  drops.isMember(jss::minimum_fee) &&
-
4849  drops[jss::minimum_fee] == "0");
+
4848  drops.isMember(jss::median_fee) &&
+
4849  drops[jss::median_fee] == "0");
4850  BEAST_EXPECT(
-
4851  drops.isMember(jss::open_ledger_fee) &&
-
4852  drops[jss::open_ledger_fee] == "0");
-
4853  }
-
4854  }
-
4855 
-
4856  checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
-
4857 
-
4858  // The noripple is to reduce the number of transactions required to
-
4859  // fund the accounts. There is no rippling in this test.
-
4860  env.fund(XRP(100000), noripple(alice));
-
4861 
-
4862  checkMetrics(__LINE__, env, 0, initQueueMax, 1, 3, 256);
-
4863 
-
4864  env.close();
-
4865 
-
4866  checkMetrics(__LINE__, env, 0, 6, 0, 3, 256);
-
4867 
-
4868  fillQueue(env, alice);
-
4869 
-
4870  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
-
4871 
-
4872  env(noop(alice), openLedgerFee(env));
-
4873 
-
4874  checkMetrics(__LINE__, env, 0, 6, 5, 3, 256);
-
4875 
-
4876  auto aliceSeq = env.seq(alice);
-
4877  env(noop(alice), queued);
+
4851  drops.isMember(jss::minimum_fee) &&
+
4852  drops[jss::minimum_fee] == "0");
+
4853  BEAST_EXPECT(
+
4854  drops.isMember(jss::open_ledger_fee) &&
+
4855  drops[jss::open_ledger_fee] == "0");
+
4856  }
+
4857  }
+
4858 
+
4859  checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
+
4860 
+
4861  // The noripple is to reduce the number of transactions required to
+
4862  // fund the accounts. There is no rippling in this test.
+
4863  env.fund(XRP(100000), noripple(alice));
+
4864 
+
4865  checkMetrics(__LINE__, env, 0, initQueueMax, 1, 3, 256);
+
4866 
+
4867  env.close();
+
4868 
+
4869  checkMetrics(__LINE__, env, 0, 6, 0, 3, 256);
+
4870 
+
4871  fillQueue(env, alice);
+
4872 
+
4873  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
+
4874 
+
4875  env(noop(alice), openLedgerFee(env));
+
4876 
+
4877  checkMetrics(__LINE__, env, 0, 6, 5, 3, 256);
4878 
-
4879  checkMetrics(__LINE__, env, 1, 6, 5, 3, 256);
-
4880 
-
4881  env(noop(alice), seq(aliceSeq + 1), fee(10), queued);
-
4882 
-
4883  checkMetrics(__LINE__, env, 2, 6, 5, 3, 256);
-
4884 
-
4885  {
-
4886  auto const fee = env.rpc("fee");
+
4879  auto aliceSeq = env.seq(alice);
+
4880  env(noop(alice), queued);
+
4881 
+
4882  checkMetrics(__LINE__, env, 1, 6, 5, 3, 256);
+
4883 
+
4884  env(noop(alice), seq(aliceSeq + 1), fee(10), queued);
+
4885 
+
4886  checkMetrics(__LINE__, env, 2, 6, 5, 3, 256);
4887 
-
4888  if (BEAST_EXPECT(fee.isMember(jss::result)) &&
-
4889  BEAST_EXPECT(!RPC::contains_error(fee[jss::result])))
-
4890  {
-
4891  auto const& result = fee[jss::result];
-
4892 
-
4893  BEAST_EXPECT(result.isMember(jss::levels));
-
4894  auto const& levels = result[jss::levels];
-
4895  BEAST_EXPECT(
-
4896  levels.isMember(jss::median_level) &&
-
4897  levels[jss::median_level] == "128000");
+
4888  {
+
4889  auto const fee = env.rpc("fee");
+
4890 
+
4891  if (BEAST_EXPECT(fee.isMember(jss::result)) &&
+
4892  BEAST_EXPECT(!RPC::contains_error(fee[jss::result])))
+
4893  {
+
4894  auto const& result = fee[jss::result];
+
4895 
+
4896  BEAST_EXPECT(result.isMember(jss::levels));
+
4897  auto const& levels = result[jss::levels];
4898  BEAST_EXPECT(
-
4899  levels.isMember(jss::minimum_level) &&
-
4900  levels[jss::minimum_level] == "256");
+
4899  levels.isMember(jss::median_level) &&
+
4900  levels[jss::median_level] == "128000");
4901  BEAST_EXPECT(
-
4902  levels.isMember(jss::open_ledger_level) &&
-
4903  levels[jss::open_ledger_level] == "355555");
+
4902  levels.isMember(jss::minimum_level) &&
+
4903  levels[jss::minimum_level] == "256");
4904  BEAST_EXPECT(
-
4905  levels.isMember(jss::reference_level) &&
-
4906  levels[jss::reference_level] == "256");
-
4907 
-
4908  auto const& drops = result[jss::drops];
-
4909  BEAST_EXPECT(
-
4910  drops.isMember(jss::base_fee) &&
-
4911  drops[jss::base_fee] == "0");
+
4905  levels.isMember(jss::open_ledger_level) &&
+
4906  levels[jss::open_ledger_level] == "355555");
+
4907  BEAST_EXPECT(
+
4908  levels.isMember(jss::reference_level) &&
+
4909  levels[jss::reference_level] == "256");
+
4910 
+
4911  auto const& drops = result[jss::drops];
4912  BEAST_EXPECT(
-
4913  drops.isMember(jss::median_fee) &&
-
4914  drops[jss::median_fee] == "0");
+
4913  drops.isMember(jss::base_fee) &&
+
4914  drops[jss::base_fee] == "0");
4915  BEAST_EXPECT(
-
4916  drops.isMember(jss::minimum_fee) &&
-
4917  drops[jss::minimum_fee] == "0");
+
4916  drops.isMember(jss::median_fee) &&
+
4917  drops[jss::median_fee] == "0");
4918  BEAST_EXPECT(
-
4919  drops.isMember(jss::open_ledger_fee) &&
-
4920  drops[jss::open_ledger_fee] == "1389");
-
4921  }
-
4922  }
-
4923 
-
4924  env.close();
-
4925 
-
4926  checkMetrics(__LINE__, env, 0, 10, 2, 5, 256);
-
4927  }
+
4919  drops.isMember(jss::minimum_fee) &&
+
4920  drops[jss::minimum_fee] == "0");
+
4921  BEAST_EXPECT(
+
4922  drops.isMember(jss::open_ledger_fee) &&
+
4923  drops[jss::open_ledger_fee] == "1389");
+
4924  }
+
4925  }
+
4926 
+
4927  env.close();
4928 
-
4929  void
-
4930  run() override
-
4931  {
-
4932  testQueueSeq();
-
4933  testQueueTicket();
-
4934  testTecResult();
-
4935  testLocalTxRetry();
-
4936  testLastLedgerSeq();
-
4937  testZeroFeeTxn();
-
4938  testFailInPreclaim();
-
4939  testQueuedTxFails();
-
4940  testMultiTxnPerAccount();
-
4941  testTieBreaking();
-
4942  testAcctTxnID();
-
4943  testMaximum();
-
4944  testUnexpectedBalanceChange();
-
4945  testBlockersSeq();
-
4946  testBlockersTicket();
-
4947  testInFlightBalance();
-
4948  testConsequences();
-
4949  }
-
4950 
-
4951  void
-
4952  runMetaInfo()
-
4953  {
-
4954  testAcctInQueueButEmpty();
-
4955  testRPC();
-
4956  testExpirationReplacement();
-
4957  testFullQueueGapFill();
-
4958  testSignAndSubmitSequence();
-
4959  testAccountInfo();
-
4960  testServerInfo();
-
4961  testServerSubscribe();
-
4962  testClearQueuedAccountTxs();
-
4963  testScaling();
-
4964  testInLedgerSeq();
-
4965  testInLedgerTicket();
-
4966  testReexecutePreflight();
-
4967  testQueueFullDropPenalty();
-
4968  testCancelQueuedOffers();
-
4969  testZeroReferenceFee();
-
4970  }
-
4971 };
-
4972 
-
4973 class TxQMetaInfo_test : public TxQPosNegFlows_test
-
4974 {
-
4975  void
-
4976  run() override
-
4977  {
-
4978  runMetaInfo();
-
4979  }
-
4980 };
-
4981 
-
4982 BEAST_DEFINE_TESTSUITE_PRIO(TxQPosNegFlows, app, ripple, 1);
-
4983 BEAST_DEFINE_TESTSUITE_PRIO(TxQMetaInfo, app, ripple, 1);
+
4929  checkMetrics(__LINE__, env, 0, 10, 2, 5, 256);
+
4930  }
+
4931 
+
4932  void
+
4933  run() override
+
4934  {
+
4935  testQueueSeq();
+
4936  testQueueTicket();
+
4937  testTecResult();
+
4938  testLocalTxRetry();
+
4939  testLastLedgerSeq();
+
4940  testZeroFeeTxn();
+
4941  testFailInPreclaim();
+
4942  testQueuedTxFails();
+
4943  testMultiTxnPerAccount();
+
4944  testTieBreaking();
+
4945  testAcctTxnID();
+
4946  testMaximum();
+
4947  testUnexpectedBalanceChange();
+
4948  testBlockersSeq();
+
4949  testBlockersTicket();
+
4950  testInFlightBalance();
+
4951  testConsequences();
+
4952  }
+
4953 
+
4954  void
+
4955  runMetaInfo()
+
4956  {
+
4957  testAcctInQueueButEmpty();
+
4958  testRPC();
+
4959  testExpirationReplacement();
+
4960  testFullQueueGapFill();
+
4961  testSignAndSubmitSequence();
+
4962  testAccountInfo();
+
4963  testServerInfo();
+
4964  testServerSubscribe();
+
4965  testClearQueuedAccountTxs();
+
4966  testScaling();
+
4967  testInLedgerSeq();
+
4968  testInLedgerTicket();
+
4969  testReexecutePreflight();
+
4970  testQueueFullDropPenalty();
+
4971  testCancelQueuedOffers();
+
4972  testZeroReferenceFee();
+
4973  }
+
4974 };
+
4975 
+
4976 class TxQMetaInfo_test : public TxQPosNegFlows_test
+
4977 {
+
4978  void
+
4979  run() override
+
4980  {
+
4981  runMetaInfo();
+
4982  }
+
4983 };
4984 
-
4985 } // namespace test
-
4986 } // namespace ripple
+
4985 BEAST_DEFINE_TESTSUITE_PRIO(TxQPosNegFlows, app, ripple, 1);
+
4986 BEAST_DEFINE_TESTSUITE_PRIO(TxQMetaInfo, app, ripple, 1);
+
4987 
+
4988 } // namespace test
+
4989 } // namespace ripple
-
void testScaling()
Definition: TxQ_test.cpp:3982
+
void testScaling()
Definition: TxQ_test.cpp:3985
void testQueueTicket()
Definition: TxQ_test.cpp:446
@ tecUNFUNDED_OFFER
Definition: TER.h:264
Inject raw JSON.
Definition: jtx_json.h:31
@@ -5041,41 +5044,41 @@ $(function() {
Json::Value noop(Account const &account)
The null transaction.
Definition: noop.h:31
@ terPRE_TICKET
Definition: TER.h:219
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition: View.cpp:638
-
void testMaximum()
Definition: TxQ_test.cpp:1633
+
void testMaximum()
Definition: TxQ_test.cpp:1636
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
-
void testQueuedTxFails()
Definition: TxQ_test.cpp:1027
-
void testTieBreaking()
Definition: TxQ_test.cpp:1348
+
void testQueuedTxFails()
Definition: TxQ_test.cpp:1030
+
void testTieBreaking()
Definition: TxQ_test.cpp:1351
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
@ terINSUF_FEE_B
Definition: TER.h:209
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:711
-
void testMultiTxnPerAccount()
Definition: TxQ_test.cpp:1078
+
void testMultiTxnPerAccount()
Definition: TxQ_test.cpp:1081
std::pair< TER, bool > apply(Application &app, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
Definition: apply.cpp:109
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
Match the number of items in the account's owner directory.
Definition: owners.h:69
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:489
-
auto const & data
Definition: TxQ_test.cpp:3172
+
auto const & data
Definition: TxQ_test.cpp:3175
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
-
void testAccountInfo()
Definition: TxQ_test.cpp:3091
+
void testAccountInfo()
Definition: TxQ_test.cpp:3094
constexpr value_type drops() const
Returns the number of drops.
Definition: XRPAmount.h:172
Definition: TxQ_test.cpp:38
A balance matches.
Definition: balance.h:38
@ telCAN_NOT_QUEUE_FEE
Definition: TER.h:63
-
void testServerSubscribe()
Definition: TxQ_test.cpp:3631
+
void testServerSubscribe()
Definition: TxQ_test.cpp:3634
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:55
std::vector< TxDetails > getTxs() const
Returns information about all transactions currently in the queue.
Definition: TxQ.cpp:1815
-
void testServerInfo()
Definition: TxQ_test.cpp:3370
+
void testServerInfo()
Definition: TxQ_test.cpp:3373
void fillQueue(jtx::Env &env, jtx::Account const &account)
Definition: TxQ_test.cpp:132
T value_or(T... args)
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition: Env.h:450
Json::Value offer_cancel(Account const &account, std::uint32_t offerSeq)
Cancel an offer.
Definition: offer.cpp:45
-
void runMetaInfo()
Definition: TxQ_test.cpp:4952
+
void runMetaInfo()
Definition: TxQ_test.cpp:4955
Check a set of conditions.
Definition: require.h:63
-
void testBlockersTicket()
Definition: TxQ_test.cpp:1958
+
void testBlockersTicket()
Definition: TxQ_test.cpp:1961
static constexpr SeqProxy sequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition: SeqProxy.h:76
const beast::Journal journal
Definition: Env.h:144
@ telCAN_NOT_QUEUE_FULL
Definition: TER.h:64
@ telCAN_NOT_QUEUE
Definition: TER.h:59
-
void testReexecutePreflight()
Definition: TxQ_test.cpp:4286
+
void testReexecutePreflight()
Definition: TxQ_test.cpp:4289
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition: Env.cpp:183
Application & app()
Definition: Env.h:241
PreflightResult preflight(Application &app, Rules const &rules, STTx const &tx, ApplyFlags flags, beast::Journal j)
Gate a transaction based on static information.
Definition: applySteps.cpp:355
@@ -5085,9 +5088,9 @@ $(function() {
void testLocalTxRetry()
Definition: TxQ_test.cpp:739
@ tapNONE
Definition: ApplyView.h:30
std::size_t initFee(jtx::Env &env, std::size_t expectedPerLedger, std::size_t ledgersInQueue, std::uint32_t base, std::uint32_t reserve, std::uint32_t increment)
Definition: TxQ_test.cpp:192
-
void run() override
Definition: TxQ_test.cpp:4976
+
void run() override
Definition: TxQ_test.cpp:4979
BEAST_DEFINE_TESTSUITE_PRIO(AccountDelete, app, ripple, 2)
-
void testUnexpectedBalanceChange()
Definition: TxQ_test.cpp:1731
+
void testUnexpectedBalanceChange()
Definition: TxQ_test.cpp:1734
virtual LoadFeeTrack & getFeeTrack()=0
@ terQUEUED
Definition: TER.h:218
T tie(T... args)
@@ -5096,17 +5099,17 @@ $(function() {
auto openLedgerFee(jtx::Env &env)
Definition: TxQ_test.cpp:140
Set a ticket sequence on a JTx.
Definition: ticket.h:47
envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams)
-
void testZeroReferenceFee()
Definition: TxQ_test.cpp:4792
-
const auto withoutQueue
Definition: TxQ_test.cpp:3105
-
void testAcctInQueueButEmpty()
Definition: TxQ_test.cpp:2532
+
void testZeroReferenceFee()
Definition: TxQ_test.cpp:4795
+
const auto withoutQueue
Definition: TxQ_test.cpp:3108
+
void testAcctInQueueButEmpty()
Definition: TxQ_test.cpp:2535
std::vector< TxDetails > getAccountTxs(AccountID const &account) const
Returns information about the transactions currently in the queue for the account.
Definition: TxQ.cpp:1794
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:196
-
void testExpirationReplacement()
Definition: TxQ_test.cpp:2701
+
void testExpirationReplacement()
Definition: TxQ_test.cpp:2704
void checkMetrics(int line, jtx::Env &env, std::size_t expectedCount, std::optional< std::size_t > expectedMaxCount, std::size_t expectedInLedger, std::size_t expectedPerLedger, std::uint64_t expectedMinFeeLevel, std::uint64_t expectedMedFeeLevel=256 *500)
Definition: TxQ_test.cpp:41
void postconditions(JTx const &jt, TER ter, bool didApply)
Check expected postconditions of JTx submission.
Definition: Env.cpp:349
virtual Config & config()=0
-
auto submitParams
Definition: TxQ_test.cpp:3159
+
auto submitParams
Definition: TxQ_test.cpp:3162
Sets the SendMax on a JTx.
Definition: sendmax.h:31
virtual TxQ & getTxQ()=0
@@ -5115,8 +5118,8 @@ $(function() {
static XRPAmount reserve(jtx::Env &env, std::uint32_t count)
static std::unique_ptr< Config > makeConfig(std::map< std::string, std::string > extraTxQ={}, std::map< std::string, std::string > extraVoting={})
Definition: TxQ_test.cpp:158
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
-
void run() override
Definition: TxQ_test.cpp:4930
-
void testBlockersSeq()
Definition: TxQ_test.cpp:1828
+
void run() override
Definition: TxQ_test.cpp:4933
+
void testBlockersSeq()
Definition: TxQ_test.cpp:1831
STL class.
@ temBAD_AMOUNT
Definition: TER.h:88
A generic endpoint for log messages.
Definition: Journal.h:58
@@ -5125,48 +5128,49 @@ $(function() {
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:207
Definition: FeeUnits.h:70
+
@ temREDUNDANT
Definition: TER.h:111
A transaction testing environment wrapper.
Definition: Env_ss.h:33
@ telCAN_NOT_QUEUE_BLOCKS
Definition: TER.h:61
BEAST_EXPECT(env.current() ->info().seq > 3)
-
auto const & queue_data
Definition: TxQ_test.cpp:3126
-
void testQueueFullDropPenalty()
Definition: TxQ_test.cpp:4442
+
auto const & queue_data
Definition: TxQ_test.cpp:3129
+
void testQueueFullDropPenalty()
Definition: TxQ_test.cpp:4445
Set the fee on a JTx.
Definition: fee.h:35
FeeLevel64 referenceFeeLevel
Reference transaction fee level.
Definition: TxQ.h:175
-
auto const & result
Definition: TxQ_test.cpp:3124
+
auto const & result
Definition: TxQ_test.cpp:3127
void testQueueSeq()
Definition: TxQ_test.cpp:234
@ terNO_ACCOUNT
Definition: TER.h:210
-
void testFullQueueGapFill()
Definition: TxQ_test.cpp:2802
-
void testSignAndSubmitSequence()
Definition: TxQ_test.cpp:2961
-
void testInLedgerTicket()
Definition: TxQ_test.cpp:4191
+
void testFullQueueGapFill()
Definition: TxQ_test.cpp:2805
+
void testSignAndSubmitSequence()
Definition: TxQ_test.cpp:2964
+
void testInLedgerTicket()
Definition: TxQ_test.cpp:4194
Set the sequence number on a JTx.
Definition: seq.h:33
-
void testInFlightBalance()
Definition: TxQ_test.cpp:2120
+
void testInFlightBalance()
Definition: TxQ_test.cpp:2123
constexpr Number one
Definition: Number.cpp:169
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::array< Account, 1+sizeof...(Args)> noripple(Account const &account, Args const &... args)
Designate accounts as no-ripple in Env::fund.
Definition: Env.h:64
std::uint32_t getLoadFactor() const
Definition: LoadFeeTrack.h:95
@ tapUNLIMITED
Definition: ApplyView.h:41
-
auto const & queued
Definition: TxQ_test.cpp:3191
+
auto const & queued
Definition: TxQ_test.cpp:3194
bool raiseLocalFee()
@ tefPAST_SEQ
Definition: TER.h:169
NetClock::time_point now()
Returns the current network time.
Definition: Env.h:264
void testFailInPreclaim()
Definition: TxQ_test.cpp:1003
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Definition: regkey.cpp:28
-
Definition: TxQ_test.cpp:4973
+
Definition: TxQ_test.cpp:4976
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:216
std::size_t txInLedger
Number of transactions currently in the open ledger.
Definition: TxQ.h:171
-
void testConsequences()
Definition: TxQ_test.cpp:2474
-
void testRPC()
Definition: TxQ_test.cpp:2637
+
void testConsequences()
Definition: TxQ_test.cpp:2477
+
void testRPC()
Definition: TxQ_test.cpp:2640
Account const & master
Definition: Env.h:121
void testTecResult()
Definition: TxQ_test.cpp:703
-
void testAcctTxnID()
Definition: TxQ_test.cpp:1594
+
void testAcctTxnID()
Definition: TxQ_test.cpp:1597
const SF_AMOUNT sfBalance
A type that represents either a sequence value or a ticket value.
Definition: SeqProxy.h:55
@ tefWRONG_PRIOR
Definition: TER.h:170
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpc_version, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Definition: WSClient.cpp:300
T empty(T... args)
-
void testCancelQueuedOffers()
Definition: TxQ_test.cpp:4679
-
void testInLedgerSeq()
Definition: TxQ_test.cpp:4122
+
void testCancelQueuedOffers()
Definition: TxQ_test.cpp:4682
+
void testInLedgerSeq()
Definition: TxQ_test.cpp:4125
@ terPRE_SEQ
Definition: TER.h:214
@@ -5183,13 +5187,13 @@ $(function() {
void testLastLedgerSeq()
Definition: TxQ_test.cpp:796
XRPAmount toDrops(FeeLevel< T > const &level, XRPAmount baseFee)
Definition: TxQ.h:863
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:311
-
void testClearQueuedAccountTxs()
Definition: TxQ_test.cpp:3776
+
void testClearQueuedAccountTxs()
Definition: TxQ_test.cpp:3779
A transaction testing environment.
Definition: Env.h:116
void testZeroFeeTxn()
Definition: TxQ_test.cpp:906
T what(T... args)
@ telCAN_NOT_QUEUE_BLOCKED
Definition: TER.h:62
Represents a JSON value.
Definition: json_value.h:145
-
const auto prevLedgerWithQueue
Definition: TxQ_test.cpp:3106
+
const auto prevLedgerWithQueue
Definition: TxQ_test.cpp:3109
Definition: XRPAmount.h:46
Definition: owners.h:49
diff --git a/classripple_1_1test_1_1TxQMetaInfo__test.html b/classripple_1_1test_1_1TxQMetaInfo__test.html index 46af25c5d1..1613739631 100644 --- a/classripple_1_1test_1_1TxQMetaInfo__test.html +++ b/classripple_1_1test_1_1TxQMetaInfo__test.html @@ -406,7 +406,7 @@ Static Private Member Functions

Detailed Description

-

Definition at line 4973 of file TxQ_test.cpp.

+

Definition at line 4976 of file TxQ_test.cpp.

Member Function Documentation

◆ run()

@@ -431,7 +431,7 @@ Static Private Member Functions
-

Definition at line 4976 of file TxQ_test.cpp.

+

Definition at line 4979 of file TxQ_test.cpp.

@@ -1451,7 +1451,7 @@ Static Private Member Functions
-

Definition at line 1027 of file TxQ_test.cpp.

+

Definition at line 1030 of file TxQ_test.cpp.

@@ -1478,7 +1478,7 @@ Static Private Member Functions
-

Definition at line 1078 of file TxQ_test.cpp.

+

Definition at line 1081 of file TxQ_test.cpp.

@@ -1505,7 +1505,7 @@ Static Private Member Functions
-

Definition at line 1348 of file TxQ_test.cpp.

+

Definition at line 1351 of file TxQ_test.cpp.

@@ -1532,7 +1532,7 @@ Static Private Member Functions
-

Definition at line 1594 of file TxQ_test.cpp.

+

Definition at line 1597 of file TxQ_test.cpp.

@@ -1559,7 +1559,7 @@ Static Private Member Functions
-

Definition at line 1633 of file TxQ_test.cpp.

+

Definition at line 1636 of file TxQ_test.cpp.

@@ -1586,7 +1586,7 @@ Static Private Member Functions
-

Definition at line 1731 of file TxQ_test.cpp.

+

Definition at line 1734 of file TxQ_test.cpp.

@@ -1613,7 +1613,7 @@ Static Private Member Functions
-

Definition at line 1828 of file TxQ_test.cpp.

+

Definition at line 1831 of file TxQ_test.cpp.

@@ -1640,7 +1640,7 @@ Static Private Member Functions
-

Definition at line 1958 of file TxQ_test.cpp.

+

Definition at line 1961 of file TxQ_test.cpp.

@@ -1667,7 +1667,7 @@ Static Private Member Functions
-

Definition at line 2120 of file TxQ_test.cpp.

+

Definition at line 2123 of file TxQ_test.cpp.

@@ -1694,7 +1694,7 @@ Static Private Member Functions
-

Definition at line 2474 of file TxQ_test.cpp.

+

Definition at line 2477 of file TxQ_test.cpp.

@@ -1721,7 +1721,7 @@ Static Private Member Functions
-

Definition at line 2532 of file TxQ_test.cpp.

+

Definition at line 2535 of file TxQ_test.cpp.

@@ -1748,7 +1748,7 @@ Static Private Member Functions
-

Definition at line 2637 of file TxQ_test.cpp.

+

Definition at line 2640 of file TxQ_test.cpp.

@@ -1775,7 +1775,7 @@ Static Private Member Functions
-

Definition at line 2701 of file TxQ_test.cpp.

+

Definition at line 2704 of file TxQ_test.cpp.

@@ -1802,7 +1802,7 @@ Static Private Member Functions
-

Definition at line 2802 of file TxQ_test.cpp.

+

Definition at line 2805 of file TxQ_test.cpp.

@@ -1829,7 +1829,7 @@ Static Private Member Functions
-

Definition at line 2961 of file TxQ_test.cpp.

+

Definition at line 2964 of file TxQ_test.cpp.

@@ -1856,7 +1856,7 @@ Static Private Member Functions
-

Definition at line 3091 of file TxQ_test.cpp.

+

Definition at line 3094 of file TxQ_test.cpp.

@@ -4277,7 +4277,7 @@ Static Private Member Functions
-

Definition at line 3193 of file TxQ_test.cpp.

+

Definition at line 3196 of file TxQ_test.cpp.

@@ -4304,7 +4304,7 @@ Static Private Member Functions
-

Definition at line 3251 of file TxQ_test.cpp.

+

Definition at line 3254 of file TxQ_test.cpp.

@@ -4331,7 +4331,7 @@ Static Private Member Functions
-

Definition at line 3307 of file TxQ_test.cpp.

+

Definition at line 3310 of file TxQ_test.cpp.

@@ -4433,7 +4433,7 @@ Static Private Member Functions
-

Definition at line 3370 of file TxQ_test.cpp.

+

Definition at line 3373 of file TxQ_test.cpp.

@@ -4460,7 +4460,7 @@ Static Private Member Functions
-

Definition at line 3631 of file TxQ_test.cpp.

+

Definition at line 3634 of file TxQ_test.cpp.

@@ -4487,7 +4487,7 @@ Static Private Member Functions
-

Definition at line 3776 of file TxQ_test.cpp.

+

Definition at line 3779 of file TxQ_test.cpp.

@@ -4514,7 +4514,7 @@ Static Private Member Functions
-

Definition at line 3982 of file TxQ_test.cpp.

+

Definition at line 3985 of file TxQ_test.cpp.

@@ -4541,7 +4541,7 @@ Static Private Member Functions
-

Definition at line 4122 of file TxQ_test.cpp.

+

Definition at line 4125 of file TxQ_test.cpp.

@@ -4568,7 +4568,7 @@ Static Private Member Functions
-

Definition at line 4191 of file TxQ_test.cpp.

+

Definition at line 4194 of file TxQ_test.cpp.

@@ -4595,7 +4595,7 @@ Static Private Member Functions
-

Definition at line 4286 of file TxQ_test.cpp.

+

Definition at line 4289 of file TxQ_test.cpp.

@@ -4622,7 +4622,7 @@ Static Private Member Functions
-

Definition at line 4442 of file TxQ_test.cpp.

+

Definition at line 4445 of file TxQ_test.cpp.

@@ -4649,7 +4649,7 @@ Static Private Member Functions
-

Definition at line 4679 of file TxQ_test.cpp.

+

Definition at line 4682 of file TxQ_test.cpp.

@@ -4676,7 +4676,7 @@ Static Private Member Functions
-

Definition at line 4792 of file TxQ_test.cpp.

+

Definition at line 4795 of file TxQ_test.cpp.

@@ -4703,7 +4703,7 @@ Static Private Member Functions
-

Definition at line 4952 of file TxQ_test.cpp.

+

Definition at line 4955 of file TxQ_test.cpp.

@@ -4728,7 +4728,7 @@ Static Private Member Functions
-

Definition at line 3105 of file TxQ_test.cpp.

+

Definition at line 3108 of file TxQ_test.cpp.

@@ -4754,7 +4754,7 @@ Static Private Member Functions Initial value:
= R"({ "account": ")" + alice.human() +
R"(", "queue": true, "ledger_index": 3 })"
-

Definition at line 3106 of file TxQ_test.cpp.

+

Definition at line 3109 of file TxQ_test.cpp.

@@ -4778,7 +4778,7 @@ Static Private Member Functions
-

Definition at line 3124 of file TxQ_test.cpp.

+

Definition at line 3127 of file TxQ_test.cpp.

@@ -4802,7 +4802,7 @@ Static Private Member Functions
-

Definition at line 3126 of file TxQ_test.cpp.

+

Definition at line 3129 of file TxQ_test.cpp.

@@ -4826,7 +4826,7 @@ Static Private Member Functions
-

Definition at line 3159 of file TxQ_test.cpp.

+

Definition at line 3162 of file TxQ_test.cpp.

@@ -4850,7 +4850,7 @@ Static Private Member Functions
-

Definition at line 3172 of file TxQ_test.cpp.

+

Definition at line 3175 of file TxQ_test.cpp.

@@ -4874,7 +4874,7 @@ Static Private Member Functions
-

Definition at line 3191 of file TxQ_test.cpp.

+

Definition at line 3194 of file TxQ_test.cpp.

diff --git a/classripple_1_1test_1_1TxQPosNegFlows__test.html b/classripple_1_1test_1_1TxQPosNegFlows__test.html index 1438c637d4..e99aa311a2 100644 --- a/classripple_1_1test_1_1TxQPosNegFlows__test.html +++ b/classripple_1_1test_1_1TxQPosNegFlows__test.html @@ -795,7 +795,7 @@ Static Private Member Functions
-

Definition at line 1027 of file TxQ_test.cpp.

+

Definition at line 1030 of file TxQ_test.cpp.

@@ -814,7 +814,7 @@ Static Private Member Functions
-

Definition at line 1078 of file TxQ_test.cpp.

+

Definition at line 1081 of file TxQ_test.cpp.

@@ -833,7 +833,7 @@ Static Private Member Functions
-

Definition at line 1348 of file TxQ_test.cpp.

+

Definition at line 1351 of file TxQ_test.cpp.

@@ -852,7 +852,7 @@ Static Private Member Functions
-

Definition at line 1594 of file TxQ_test.cpp.

+

Definition at line 1597 of file TxQ_test.cpp.

@@ -871,7 +871,7 @@ Static Private Member Functions
-

Definition at line 1633 of file TxQ_test.cpp.

+

Definition at line 1636 of file TxQ_test.cpp.

@@ -890,7 +890,7 @@ Static Private Member Functions
-

Definition at line 1731 of file TxQ_test.cpp.

+

Definition at line 1734 of file TxQ_test.cpp.

@@ -909,7 +909,7 @@ Static Private Member Functions
-

Definition at line 1828 of file TxQ_test.cpp.

+

Definition at line 1831 of file TxQ_test.cpp.

@@ -928,7 +928,7 @@ Static Private Member Functions
-

Definition at line 1958 of file TxQ_test.cpp.

+

Definition at line 1961 of file TxQ_test.cpp.

@@ -947,7 +947,7 @@ Static Private Member Functions
-

Definition at line 2120 of file TxQ_test.cpp.

+

Definition at line 2123 of file TxQ_test.cpp.

@@ -966,7 +966,7 @@ Static Private Member Functions
-

Definition at line 2474 of file TxQ_test.cpp.

+

Definition at line 2477 of file TxQ_test.cpp.

@@ -985,7 +985,7 @@ Static Private Member Functions
-

Definition at line 2532 of file TxQ_test.cpp.

+

Definition at line 2535 of file TxQ_test.cpp.

@@ -1004,7 +1004,7 @@ Static Private Member Functions
-

Definition at line 2637 of file TxQ_test.cpp.

+

Definition at line 2640 of file TxQ_test.cpp.

@@ -1023,7 +1023,7 @@ Static Private Member Functions
-

Definition at line 2701 of file TxQ_test.cpp.

+

Definition at line 2704 of file TxQ_test.cpp.

@@ -1042,7 +1042,7 @@ Static Private Member Functions
-

Definition at line 2802 of file TxQ_test.cpp.

+

Definition at line 2805 of file TxQ_test.cpp.

@@ -1061,7 +1061,7 @@ Static Private Member Functions
-

Definition at line 2961 of file TxQ_test.cpp.

+

Definition at line 2964 of file TxQ_test.cpp.

@@ -1080,7 +1080,7 @@ Static Private Member Functions
-

Definition at line 3091 of file TxQ_test.cpp.

+

Definition at line 3094 of file TxQ_test.cpp.

@@ -2155,7 +2155,7 @@ Static Private Member Functions
-

Definition at line 3193 of file TxQ_test.cpp.

+

Definition at line 3196 of file TxQ_test.cpp.

@@ -2651,7 +2651,7 @@ Static Private Member Functions
-

Definition at line 3251 of file TxQ_test.cpp.

+

Definition at line 3254 of file TxQ_test.cpp.

@@ -3038,7 +3038,7 @@ Static Private Member Functions
-

Definition at line 3307 of file TxQ_test.cpp.

+

Definition at line 3310 of file TxQ_test.cpp.

@@ -3405,7 +3405,7 @@ Static Private Member Functions
-

Definition at line 3370 of file TxQ_test.cpp.

+

Definition at line 3373 of file TxQ_test.cpp.

@@ -3424,7 +3424,7 @@ Static Private Member Functions
-

Definition at line 3631 of file TxQ_test.cpp.

+

Definition at line 3634 of file TxQ_test.cpp.

@@ -3443,7 +3443,7 @@ Static Private Member Functions
-

Definition at line 3776 of file TxQ_test.cpp.

+

Definition at line 3779 of file TxQ_test.cpp.

@@ -3462,7 +3462,7 @@ Static Private Member Functions
-

Definition at line 3982 of file TxQ_test.cpp.

+

Definition at line 3985 of file TxQ_test.cpp.

@@ -3481,7 +3481,7 @@ Static Private Member Functions
-

Definition at line 4122 of file TxQ_test.cpp.

+

Definition at line 4125 of file TxQ_test.cpp.

@@ -3500,7 +3500,7 @@ Static Private Member Functions
-

Definition at line 4191 of file TxQ_test.cpp.

+

Definition at line 4194 of file TxQ_test.cpp.

@@ -3519,7 +3519,7 @@ Static Private Member Functions
-

Definition at line 4286 of file TxQ_test.cpp.

+

Definition at line 4289 of file TxQ_test.cpp.

@@ -3538,7 +3538,7 @@ Static Private Member Functions
-

Definition at line 4442 of file TxQ_test.cpp.

+

Definition at line 4445 of file TxQ_test.cpp.

@@ -3557,7 +3557,7 @@ Static Private Member Functions
-

Definition at line 4679 of file TxQ_test.cpp.

+

Definition at line 4682 of file TxQ_test.cpp.

@@ -3576,7 +3576,7 @@ Static Private Member Functions
-

Definition at line 4792 of file TxQ_test.cpp.

+

Definition at line 4795 of file TxQ_test.cpp.

@@ -3603,7 +3603,7 @@ Static Private Member Functions
-

Definition at line 4930 of file TxQ_test.cpp.

+

Definition at line 4933 of file TxQ_test.cpp.

@@ -3622,7 +3622,7 @@ Static Private Member Functions
-

Definition at line 4952 of file TxQ_test.cpp.

+

Definition at line 4955 of file TxQ_test.cpp.

@@ -3639,7 +3639,7 @@ Static Private Member Functions
-

Definition at line 3105 of file TxQ_test.cpp.

+

Definition at line 3108 of file TxQ_test.cpp.

@@ -3657,7 +3657,7 @@ Static Private Member Functions Initial value:
= R"({ "account": ")" + alice.human() +
R"(", "queue": true, "ledger_index": 3 })"
-

Definition at line 3106 of file TxQ_test.cpp.

+

Definition at line 3109 of file TxQ_test.cpp.

@@ -3673,7 +3673,7 @@ Static Private Member Functions
-

Definition at line 3124 of file TxQ_test.cpp.

+

Definition at line 3127 of file TxQ_test.cpp.

@@ -3689,7 +3689,7 @@ Static Private Member Functions
-

Definition at line 3126 of file TxQ_test.cpp.

+

Definition at line 3129 of file TxQ_test.cpp.

@@ -3705,7 +3705,7 @@ Static Private Member Functions
-

Definition at line 3159 of file TxQ_test.cpp.

+

Definition at line 3162 of file TxQ_test.cpp.

@@ -3721,7 +3721,7 @@ Static Private Member Functions
-

Definition at line 3172 of file TxQ_test.cpp.

+

Definition at line 3175 of file TxQ_test.cpp.

@@ -3737,7 +3737,7 @@ Static Private Member Functions
-

Definition at line 3191 of file TxQ_test.cpp.

+

Definition at line 3194 of file TxQ_test.cpp.