rippled
TxQ_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/main/Application.h>
21 #include <ripple/app/misc/LoadFeeTrack.h>
22 #include <ripple/app/misc/TxQ.h>
23 #include <ripple/app/tx/apply.h>
24 #include <ripple/basics/Log.h>
25 #include <ripple/basics/mulDiv.h>
26 #include <ripple/protocol/ErrorCodes.h>
27 #include <ripple/protocol/jss.h>
28 #include <ripple/protocol/st.h>
29 #include <test/jtx.h>
30 #include <test/jtx/TestSuite.h>
31 #include <test/jtx/WSClient.h>
32 #include <test/jtx/envconfig.h>
33 #include <test/jtx/ticket.h>
34 
35 namespace ripple {
36 
37 namespace test {
38 
39 class TxQ1_test : public beast::unit_test::suite
40 {
41  void
43  int line,
44  jtx::Env& env,
45  std::size_t expectedCount,
46  std::optional<std::size_t> expectedMaxCount,
47  std::size_t expectedInLedger,
48  std::size_t expectedPerLedger,
49  std::uint64_t expectedMinFeeLevel,
50  std::uint64_t expectedMedFeeLevel = 256 * 500)
51  {
52  FeeLevel64 const expectedMin{expectedMinFeeLevel};
53  FeeLevel64 const expectedMed{expectedMedFeeLevel};
54  auto const metrics = env.app().getTxQ().getMetrics(*env.current());
55  using namespace std::string_literals;
56 
57  metrics.referenceFeeLevel == FeeLevel64{256}
58  ? pass()
59  : fail(
60  "reference: "s +
61  std::to_string(metrics.referenceFeeLevel.value()) +
62  "/256",
63  __FILE__,
64  line);
65 
66  metrics.txCount == expectedCount
67  ? pass()
68  : fail(
69  "txCount: "s + std::to_string(metrics.txCount) + "/" +
70  std::to_string(expectedCount),
71  __FILE__,
72  line);
73 
74  metrics.txQMaxSize == expectedMaxCount
75  ? pass()
76  : fail(
77  "txQMaxSize: "s +
78  std::to_string(metrics.txQMaxSize.value_or(0)) + "/" +
79  std::to_string(expectedMaxCount.value_or(0)),
80  __FILE__,
81  line);
82 
83  metrics.txInLedger == expectedInLedger
84  ? pass()
85  : fail(
86  "txInLedger: "s + std::to_string(metrics.txInLedger) + "/" +
87  std::to_string(expectedInLedger),
88  __FILE__,
89  line);
90 
91  metrics.txPerLedger == expectedPerLedger
92  ? pass()
93  : fail(
94  "txPerLedger: "s + std::to_string(metrics.txPerLedger) + "/" +
95  std::to_string(expectedPerLedger),
96  __FILE__,
97  line);
98 
99  metrics.minProcessingFeeLevel == expectedMin
100  ? pass()
101  : fail(
102  "minProcessingFeeLevel: "s +
103  std::to_string(metrics.minProcessingFeeLevel.value()) +
104  "/" + std::to_string(expectedMin.value()),
105  __FILE__,
106  line);
107 
108  metrics.medFeeLevel == expectedMed
109  ? pass()
110  : fail(
111  "medFeeLevel: "s +
112  std::to_string(metrics.medFeeLevel.value()) + "/" +
113  std::to_string(expectedMed.value()),
114  __FILE__,
115  line);
116 
117  auto const expectedCurFeeLevel = expectedInLedger > expectedPerLedger
118  ? expectedMed * expectedInLedger * expectedInLedger /
119  (expectedPerLedger * expectedPerLedger)
120  : metrics.referenceFeeLevel;
121 
122  metrics.openLedgerFeeLevel == expectedCurFeeLevel
123  ? pass()
124  : fail(
125  "openLedgerFeeLevel: "s +
126  std::to_string(metrics.openLedgerFeeLevel.value()) + "/" +
127  std::to_string(expectedCurFeeLevel.value()),
128  __FILE__,
129  line);
130  }
131 
132  void
133  fillQueue(jtx::Env& env, jtx::Account const& account)
134  {
135  auto metrics = env.app().getTxQ().getMetrics(*env.current());
136  for (int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
137  env(noop(account));
138  }
139 
140  auto
142  {
143  using namespace jtx;
144 
145  auto const& view = *env.current();
146  auto metrics = env.app().getTxQ().getMetrics(view);
147 
148  // Don't care about the overflow flag
149  return fee(toDrops(metrics.openLedgerFeeLevel, view.fees().base) + 1);
150  }
151 
155  std::map<std::string, std::string> extraVoting = {})
156  {
157  auto p = test::jtx::envconfig();
158  auto& section = p->section("transaction_queue");
159  section.set("ledgers_in_queue", "2");
160  section.set("minimum_queue_size", "2");
161  section.set("min_ledgers_to_compute_size_limit", "3");
162  section.set("max_ledger_counts_to_store", "100");
163  section.set("retry_sequence_percent", "25");
164  section.set("normal_consensus_increase_percent", "0");
165 
166  for (auto const& [k, v] : extraTxQ)
167  section.set(k, v);
168 
169  // Some tests specify different fee settings that are enabled by
170  // a FeeVote
171  if (!extraVoting.empty())
172  {
173  auto& votingSection = p->section("voting");
174  for (auto const& [k, v] : extraVoting)
175  {
176  votingSection.set(k, v);
177  }
178 
179  // In order for the vote to occur, we must run as a validator
180  p->section("validation_seed")
181  .legacy("shUwVw52ofnCUX5m7kPTKzJdr4HEH");
182  }
183  return p;
184  }
185 
188  jtx::Env& env,
189  std::size_t expectedPerLedger,
190  std::size_t ledgersInQueue,
191  std::uint32_t base,
192  std::uint32_t units,
194  std::uint32_t increment)
195  {
196  // Run past the flag ledger so that a Fee change vote occurs and
197  // lowers the reserve fee. (It also activates all supported
198  // amendments.) This will allow creating accounts with lower
199  // reserves and balances.
200  for (auto i = env.current()->seq(); i <= 257; ++i)
201  env.close();
202  // The ledger after the flag ledger creates all the
203  // fee (1) and amendment (numUpVotedAmendments())
204  // pseudotransactions. The queue treats the fees on these
205  // transactions as though they are ordinary transactions.
206  auto const flagPerLedger = 1 + ripple::detail::numUpVotedAmendments();
207  auto const flagMaxQueue = ledgersInQueue * flagPerLedger;
208  checkMetrics(__LINE__, env, 0, flagMaxQueue, 0, flagPerLedger, 256);
209 
210  // Pad a couple of txs with normal fees so the median comes
211  // back down to normal
212  env(noop(env.master));
213  env(noop(env.master));
214 
215  // Close the ledger with a delay, which causes all the TxQ
216  // metrics to reset to defaults, EXCEPT the maxQueue size.
217  using namespace std::chrono_literals;
218  env.close(env.now() + 5s, 10000ms);
219  checkMetrics(__LINE__, env, 0, flagMaxQueue, 0, expectedPerLedger, 256);
220  auto const fees = env.current()->fees();
221  BEAST_EXPECT(fees.base == XRPAmount{base});
222  BEAST_EXPECT(fees.units == FeeUnit64{units});
223  BEAST_EXPECT(fees.reserve == XRPAmount{reserve});
224  BEAST_EXPECT(fees.increment == XRPAmount{increment});
225 
226  return flagMaxQueue;
227  }
228 
229 public:
230  void
232  {
233  using namespace jtx;
234  using namespace std::chrono;
235  testcase("queue sequence");
236 
237  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
238 
239  auto alice = Account("alice");
240  auto bob = Account("bob");
241  auto charlie = Account("charlie");
242  auto daria = Account("daria");
243  auto elmo = Account("elmo");
244  auto fred = Account("fred");
245  auto gwen = Account("gwen");
246  auto hank = Account("hank");
247  auto iris = Account("iris");
248 
249  auto queued = ter(terQUEUED);
250 
251  BEAST_EXPECT(env.current()->fees().base == 10);
252 
253  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
254 
255  // Create several accounts while the fee is cheap so they all apply.
256  env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
257  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
258 
259  // Alice - price starts exploding: held
260  env(noop(alice), queued);
261  checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
262 
263  // Bob with really high fee - applies
264  env(noop(bob), openLedgerFee(env));
265  checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
266 
267  // Daria with low fee: hold
268  env(noop(daria), fee(1000), queued);
269  checkMetrics(__LINE__, env, 2, std::nullopt, 5, 3, 256);
270 
271  env.close();
272  // Verify that the held transactions got applied
273  checkMetrics(__LINE__, env, 0, 10, 2, 5, 256);
274 
276 
277  // Make some more accounts. We'll need them later to abuse the queue.
278  env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
279  checkMetrics(__LINE__, env, 0, 10, 6, 5, 256);
280 
281  // Now get a bunch of transactions held.
282  env(noop(alice), fee(12), queued);
283  checkMetrics(__LINE__, env, 1, 10, 6, 5, 256);
284 
285  env(noop(bob), fee(10), queued); // won't clear the queue
286  env(noop(charlie), fee(20), queued);
287  env(noop(daria), fee(15), queued);
288  env(noop(elmo), fee(11), queued);
289  env(noop(fred), fee(19), queued);
290  env(noop(gwen), fee(16), queued);
291  env(noop(hank), fee(18), queued);
292  checkMetrics(__LINE__, env, 8, 10, 6, 5, 256);
293 
294  env.close();
295  // Verify that the held transactions got applied
296  checkMetrics(__LINE__, env, 1, 12, 7, 6, 256);
297 
298  // Bob's transaction is still stuck in the queue.
299 
301 
302  // Hank sends another txn
303  env(noop(hank), fee(10), queued);
304  // But he's not going to leave it in the queue
305  checkMetrics(__LINE__, env, 2, 12, 7, 6, 256);
306 
307  // Hank sees his txn got held and bumps the fee,
308  // but doesn't even bump it enough to requeue
309  env(noop(hank), fee(11), ter(telCAN_NOT_QUEUE_FEE));
310  checkMetrics(__LINE__, env, 2, 12, 7, 6, 256);
311 
312  // Hank sees his txn got held and bumps the fee,
313  // enough to requeue, but doesn't bump it enough to
314  // apply to the ledger
315  env(noop(hank), fee(6000), queued);
316  // But he's not going to leave it in the queue
317  checkMetrics(__LINE__, env, 2, 12, 7, 6, 256);
318 
319  // Hank sees his txn got held and bumps the fee,
320  // high enough to get into the open ledger, because
321  // he doesn't want to wait.
322  env(noop(hank), openLedgerFee(env));
323  checkMetrics(__LINE__, env, 1, 12, 8, 6, 256);
324 
325  // Hank then sends another, less important txn
326  // (In addition to the metrics, this will verify that
327  // the original txn got removed.)
328  env(noop(hank), fee(6000), queued);
329  checkMetrics(__LINE__, env, 2, 12, 8, 6, 256);
330 
331  env.close();
332 
333  // Verify that bob and hank's txns were applied
334  checkMetrics(__LINE__, env, 0, 16, 2, 8, 256);
335 
336  // Close again with a simulated time leap to
337  // reset the escalation limit down to minimum
338  env.close(env.now() + 5s, 10000ms);
339  checkMetrics(__LINE__, env, 0, 16, 0, 3, 256);
340  // Then close once more without the time leap
341  // to reset the queue maxsize down to minimum
342  env.close();
343  checkMetrics(__LINE__, env, 0, 6, 0, 3, 256);
344 
346 
347  // Stuff the ledger and queue so we can verify that
348  // stuff gets kicked out.
349  env(noop(hank), fee(7000));
350  env(noop(gwen), fee(7000));
351  env(noop(fred), fee(7000));
352  env(noop(elmo), fee(7000));
353  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
354 
355  // Use explicit fees so we can control which txn
356  // will get dropped
357  // This one gets into the queue, but gets dropped when the
358  // higher fee one is added later.
359  env(noop(daria), fee(15), queued);
360  // These stay in the queue.
361  env(noop(elmo), fee(16), queued);
362  env(noop(fred), fee(17), queued);
363  env(noop(gwen), fee(18), queued);
364  env(noop(hank), fee(19), queued);
365  env(noop(alice), fee(20), queued);
366 
367  // Queue is full now.
368  checkMetrics(__LINE__, env, 6, 6, 4, 3, 385);
369 
370  // Try to add another transaction with the default (low) fee,
371  // it should fail because the queue is full.
372  env(noop(charlie), ter(telCAN_NOT_QUEUE_FULL));
373 
374  // Add another transaction, with a higher fee,
375  // Not high enough to get into the ledger, but high
376  // enough to get into the queue (and kick somebody out)
377  env(noop(charlie), fee(100), queued);
378 
379  // Queue is still full, of course, but the min fee has gone up
380  checkMetrics(__LINE__, env, 6, 6, 4, 3, 410);
381 
382  // Close out the ledger, the transactions are accepted, the
383  // queue is cleared, then the localTxs are retried. At this
384  // point, daria's transaction that was dropped from the queue
385  // is put back in. Neat.
386  env.close();
387  checkMetrics(__LINE__, env, 2, 8, 5, 4, 256, 256 * 700);
388 
389  env.close();
390  checkMetrics(__LINE__, env, 0, 10, 2, 5, 256);
391 
393 
394  // Attempt to put a transaction in the queue for an account
395  // that is not yet funded.
396  env.memoize(iris);
397 
398  env(noop(alice));
399  env(noop(bob));
400  env(noop(charlie));
401  env(noop(daria));
402  env(pay(alice, iris, XRP(1000)), queued);
403  env(noop(iris), seq(1), fee(20), ter(terNO_ACCOUNT));
404  checkMetrics(__LINE__, env, 1, 10, 6, 5, 256);
405 
406  env.close();
407  checkMetrics(__LINE__, env, 0, 12, 1, 6, 256);
408 
409  env.require(balance(iris, XRP(1000)));
410  BEAST_EXPECT(env.seq(iris) == 11);
411 
413  // Cleanup:
414 
415  // Create a few more transactions, so that
416  // we can be sure that there's one in the queue when the
417  // test ends and the TxQ is destructed.
418 
419  auto metrics = env.app().getTxQ().getMetrics(*env.current());
420  BEAST_EXPECT(metrics.txCount == 0);
421 
422  // Stuff the ledger.
423  for (int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
424  {
425  env(noop(env.master));
426  }
427 
428  // Queue one straightforward transaction
429  env(noop(env.master), fee(20), queued);
430  ++metrics.txCount;
431 
432  checkMetrics(
433  __LINE__,
434  env,
435  metrics.txCount,
436  metrics.txQMaxSize,
437  metrics.txPerLedger + 1,
438  metrics.txPerLedger,
439  256);
440  }
441 
442  void
444  {
445  using namespace jtx;
446  testcase("queue ticket");
447 
448  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
449 
450  auto alice = Account("alice");
451 
452  auto queued = ter(terQUEUED);
453 
454  BEAST_EXPECT(env.current()->fees().base == 10);
455 
456  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
457 
458  // Fund alice and then fill the ledger.
459  env.fund(XRP(50000), noripple(alice));
460  env(noop(alice));
461  env(noop(alice));
462  env(noop(alice));
463  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
464 
466 
467  // Alice requests tickets, but that transaction is queued. So
468  // Alice can't queue ticketed transactions yet.
469  std::uint32_t const tkt1{env.seq(alice) + 1};
470  env(ticket::create(alice, 250), seq(tkt1 - 1), queued);
471 
472  env(noop(alice), ticket::use(tkt1 - 2), ter(tefNO_TICKET));
473  env(noop(alice), ticket::use(tkt1 - 1), ter(terPRE_TICKET));
474  env.require(owners(alice, 0), tickets(alice, 0));
475  checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
476 
477  env.close();
478  env.require(owners(alice, 250), tickets(alice, 250));
479  checkMetrics(__LINE__, env, 0, 8, 1, 4, 256);
480  BEAST_EXPECT(env.seq(alice) == tkt1 + 250);
481 
483 
484  // Unlike queued sequence-based transactions, ticket-based
485  // transactions _do_ move out of the queue largest fee first,
486  // even within one account, since they can be applied in any order.
487  // Demonstrate that.
488 
489  // Fill the ledger so we can start queuing things.
490  env(noop(alice), ticket::use(tkt1 + 1), fee(11));
491  env(noop(alice), ticket::use(tkt1 + 2), fee(12));
492  env(noop(alice), ticket::use(tkt1 + 3), fee(13));
493  env(noop(alice), ticket::use(tkt1 + 4), fee(14));
494  env(noop(alice), ticket::use(tkt1 + 5), fee(15), queued);
495  env(noop(alice), ticket::use(tkt1 + 6), fee(16), queued);
496  env(noop(alice), ticket::use(tkt1 + 7), fee(17), queued);
497  env(noop(alice), ticket::use(tkt1 + 8), fee(18), queued);
498  env(noop(alice), ticket::use(tkt1 + 9), fee(19), queued);
499  env(noop(alice), ticket::use(tkt1 + 10), fee(20), queued);
500  env(noop(alice), ticket::use(tkt1 + 11), fee(21), queued);
501  env(noop(alice), ticket::use(tkt1 + 12), fee(22), queued);
502  env(noop(alice),
503  ticket::use(tkt1 + 13),
504  fee(23),
506  checkMetrics(__LINE__, env, 8, 8, 5, 4, 385);
507 
508  // Check which of the queued transactions got into the ledger by
509  // attempting to replace them.
510  // o Get tefNO_TICKET if the ticket has already been used.
511  // o Get telCAN_NOT_QUEUE_FEE if the transaction is still in the queue.
512  env.close();
513  env.require(owners(alice, 240), tickets(alice, 240));
514 
515  // These 4 went straight to the ledger:
516  env(noop(alice), ticket::use(tkt1 + 1), ter(tefNO_TICKET));
517  env(noop(alice), ticket::use(tkt1 + 2), ter(tefNO_TICKET));
518  env(noop(alice), ticket::use(tkt1 + 3), ter(tefNO_TICKET));
519  env(noop(alice), ticket::use(tkt1 + 4), ter(tefNO_TICKET));
520 
521  // These two are still in the TxQ:
522  env(noop(alice), ticket::use(tkt1 + 5), ter(telCAN_NOT_QUEUE_FEE));
523  env(noop(alice), ticket::use(tkt1 + 6), ter(telCAN_NOT_QUEUE_FEE));
524 
525  // These six were moved from the queue into the open ledger
526  // since those with the highest fees go first.
527  env(noop(alice), ticket::use(tkt1 + 7), ter(tefNO_TICKET));
528  env(noop(alice), ticket::use(tkt1 + 8), ter(tefNO_TICKET));
529  env(noop(alice), ticket::use(tkt1 + 9), ter(tefNO_TICKET));
530  env(noop(alice), ticket::use(tkt1 + 10), ter(tefNO_TICKET));
531  env(noop(alice), ticket::use(tkt1 + 11), ter(tefNO_TICKET));
532  env(noop(alice), ticket::use(tkt1 + 12), ter(tefNO_TICKET));
533 
534  // This last one was moved from the local transactions into
535  // the queue.
536  env(noop(alice), ticket::use(tkt1 + 13), ter(telCAN_NOT_QUEUE_FEE));
537 
538  checkMetrics(__LINE__, env, 3, 10, 6, 5, 256);
539 
541 
542  // Do some experiments with putting sequence-based transactions
543  // into the queue while there are ticket-based transactions
544  // already in the queue.
545 
546  // Alice still has three ticket-based transactions in the queue.
547  // The fee is escalated so unless we pay a sufficient fee
548  // transactions will go straight to the queue.
549  std::uint32_t const nextSeq{env.seq(alice)};
550  env(noop(alice), seq(nextSeq + 1), ter(terPRE_SEQ));
551  env(noop(alice), seq(nextSeq - 1), ter(tefPAST_SEQ));
552  env(noop(alice), seq(nextSeq + 0), queued);
553 
554  // Now that nextSeq is in the queue, we should be able to queue
555  // nextSeq + 1.
556  env(noop(alice), seq(nextSeq + 1), queued);
557 
558  // Fill the queue with sequence-based transactions. When the
559  // ledger closes we should find the three ticket-based
560  // transactions gone from the queue (because they had the
561  // highest fee). Then the earliest of the sequence-based
562  // transactions should also be gone from the queue.
563  env(noop(alice), seq(nextSeq + 2), queued);
564  env(noop(alice), seq(nextSeq + 3), queued);
565  env(noop(alice), seq(nextSeq + 4), queued);
566  env(noop(alice), seq(nextSeq + 5), queued);
567  env(noop(alice), seq(nextSeq + 6), queued);
568  env(noop(alice), seq(nextSeq + 7), ter(telCAN_NOT_QUEUE_FULL));
569  checkMetrics(__LINE__, env, 10, 10, 6, 5, 257);
570 
571  // Check which of the queued transactions got into the ledger by
572  // attempting to replace them.
573  // o Get tefNo_TICKET if the ticket has already been used.
574  // o Get tefPAST_SEQ if the sequence moved out of the queue.
575  // o Get telCAN_NOT_QUEUE_FEE if the transaction is still in
576  // the queue.
577  env.close();
578  env.require(owners(alice, 237), tickets(alice, 237));
579 
580  // The four ticket-based transactions went out first, since
581  // they paid the highest fee.
582  env(noop(alice), ticket::use(tkt1 + 4), ter(tefNO_TICKET));
583  env(noop(alice), ticket::use(tkt1 + 5), ter(tefNO_TICKET));
584  env(noop(alice), ticket::use(tkt1 + 12), ter(tefNO_TICKET));
585  env(noop(alice), ticket::use(tkt1 + 13), ter(tefNO_TICKET));
586 
587  // Three of the sequence-based transactions also moved out of
588  // the queue.
589  env(noop(alice), seq(nextSeq + 1), ter(tefPAST_SEQ));
590  env(noop(alice), seq(nextSeq + 2), ter(tefPAST_SEQ));
591  env(noop(alice), seq(nextSeq + 3), ter(tefPAST_SEQ));
592  env(noop(alice), seq(nextSeq + 4), ter(telCAN_NOT_QUEUE_FEE));
593  env(noop(alice), seq(nextSeq + 5), ter(telCAN_NOT_QUEUE_FEE));
594  env(noop(alice), seq(nextSeq + 6), ter(telCAN_NOT_QUEUE_FEE));
595  env(noop(alice), seq(nextSeq + 7), ter(telCAN_NOT_QUEUE_FEE));
596 
597  checkMetrics(__LINE__, env, 4, 12, 7, 6, 256);
598  BEAST_EXPECT(env.seq(alice) == nextSeq + 4);
599 
601 
602  // We haven't yet shown that ticket-based transactions can be added
603  // to the queue in any order. We should do that...
604  std::uint32_t tkt250 = tkt1 + 249;
605  env(noop(alice), ticket::use(tkt250 - 0), fee(30), queued);
606  env(noop(alice), ticket::use(tkt1 + 14), fee(29), queued);
607  env(noop(alice), ticket::use(tkt250 - 1), fee(28), queued);
608  env(noop(alice), ticket::use(tkt1 + 15), fee(27), queued);
609  env(noop(alice), ticket::use(tkt250 - 2), fee(26), queued);
610  env(noop(alice), ticket::use(tkt1 + 16), fee(25), queued);
611  env(noop(alice),
612  ticket::use(tkt250 - 3),
613  fee(24),
615  env(noop(alice),
616  ticket::use(tkt1 + 17),
617  fee(23),
619  env(noop(alice),
620  ticket::use(tkt250 - 4),
621  fee(22),
623  env(noop(alice),
624  ticket::use(tkt1 + 18),
625  fee(21),
627 
628  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
629 
630  env.close();
631  env.require(owners(alice, 231), tickets(alice, 231));
632 
633  // These three ticket-based transactions escaped the queue.
634  env(noop(alice), ticket::use(tkt1 + 14), ter(tefNO_TICKET));
635  env(noop(alice), ticket::use(tkt1 + 15), ter(tefNO_TICKET));
636  env(noop(alice), ticket::use(tkt1 + 16), ter(tefNO_TICKET));
637 
638  // But these four ticket-based transactions are in the queue
639  // now; they moved into the TxQ from local transactions.
640  env(noop(alice), ticket::use(tkt250 - 3), ter(telCAN_NOT_QUEUE_FEE));
641  env(noop(alice), ticket::use(tkt1 + 17), ter(telCAN_NOT_QUEUE_FEE));
642  env(noop(alice), ticket::use(tkt250 - 4), ter(telCAN_NOT_QUEUE_FEE));
643  env(noop(alice), ticket::use(tkt1 + 18), ter(telCAN_NOT_QUEUE_FEE));
644 
645  // These three ticket-based transactions also escaped the queue.
646  env(noop(alice), ticket::use(tkt250 - 2), ter(tefNO_TICKET));
647  env(noop(alice), ticket::use(tkt250 - 1), ter(tefNO_TICKET));
648  env(noop(alice), ticket::use(tkt250 - 0), ter(tefNO_TICKET));
649 
650  // These sequence-based transactions escaped the queue.
651  env(noop(alice), seq(nextSeq + 4), ter(tefPAST_SEQ));
652  env(noop(alice), seq(nextSeq + 5), ter(tefPAST_SEQ));
653 
654  // But these sequence-based transactions are still stuck in the queue.
655  env(noop(alice), seq(nextSeq + 6), ter(telCAN_NOT_QUEUE_FEE));
656  env(noop(alice), seq(nextSeq + 7), ter(telCAN_NOT_QUEUE_FEE));
657 
658  BEAST_EXPECT(env.seq(alice) == nextSeq + 6);
659  checkMetrics(__LINE__, env, 6, 14, 8, 7, 256);
660 
662 
663  // Since we still have two ticket-based transactions in the queue
664  // let's try replacing them.
665 
666  // 26 drops is less than 21 * 1.25
667  env(noop(alice),
668  ticket::use(tkt1 + 18),
669  fee(26),
671 
672  // 27 drops is more than 21 * 1.25
673  env(noop(alice), ticket::use(tkt1 + 18), fee(27), queued);
674 
675  // 27 drops is less than 22 * 1.25
676  env(noop(alice),
677  ticket::use(tkt250 - 4),
678  fee(27),
680 
681  // 28 drops is more than 22 * 1.25
682  env(noop(alice), ticket::use(tkt250 - 4), fee(28), queued);
683 
684  env.close();
685  env.require(owners(alice, 227), tickets(alice, 227));
686 
687  // Verify that all remaining transactions made it out of the TxQ.
688  env(noop(alice), ticket::use(tkt1 + 18), ter(tefNO_TICKET));
689  env(noop(alice), ticket::use(tkt250 - 4), ter(tefNO_TICKET));
690  env(noop(alice), seq(nextSeq + 4), ter(tefPAST_SEQ));
691  env(noop(alice), seq(nextSeq + 5), ter(tefPAST_SEQ));
692  env(noop(alice), seq(nextSeq + 6), ter(tefPAST_SEQ));
693  env(noop(alice), seq(nextSeq + 7), ter(tefPAST_SEQ));
694 
695  BEAST_EXPECT(env.seq(alice) == nextSeq + 8);
696  checkMetrics(__LINE__, env, 0, 16, 6, 8, 256);
697  }
698 
699  void
701  {
702  using namespace jtx;
703  testcase("queue tec");
704 
705  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "2"}}));
706 
707  auto alice = Account("alice");
708  auto gw = Account("gw");
709  auto USD = gw["USD"];
710 
711  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
712 
713  // Create accounts
714  env.fund(XRP(50000), noripple(alice, gw));
715  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
716  env.close();
717  checkMetrics(__LINE__, env, 0, 4, 0, 2, 256);
718 
719  // Alice creates an unfunded offer while the ledger is not full
720  env(offer(alice, XRP(1000), USD(1000)), ter(tecUNFUNDED_OFFER));
721  checkMetrics(__LINE__, env, 0, 4, 1, 2, 256);
722 
723  fillQueue(env, alice);
724  checkMetrics(__LINE__, env, 0, 4, 3, 2, 256);
725 
726  // Alice creates an unfunded offer that goes in the queue
727  env(offer(alice, XRP(1000), USD(1000)), ter(terQUEUED));
728  checkMetrics(__LINE__, env, 1, 4, 3, 2, 256);
729 
730  // The offer comes out of the queue
731  env.close();
732  checkMetrics(__LINE__, env, 0, 6, 1, 3, 256);
733  }
734 
735  void
737  {
738  using namespace jtx;
739  using namespace std::chrono;
740  testcase("local tx retry");
741 
742  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "2"}}));
743 
744  auto alice = Account("alice");
745  auto bob = Account("bob");
746  auto charlie = Account("charlie");
747 
748  auto queued = ter(terQUEUED);
749 
750  BEAST_EXPECT(env.current()->fees().base == 10);
751 
752  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
753 
754  // Create several accounts while the fee is cheap so they all apply.
755  env.fund(XRP(50000), noripple(alice, bob, charlie));
756  checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
757 
758  // Future transaction for Alice - fails
759  env(noop(alice),
760  openLedgerFee(env),
761  seq(env.seq(alice) + 1),
762  ter(terPRE_SEQ));
763  checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
764 
765  // Current transaction for Alice: held
766  env(noop(alice), queued);
767  checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
768 
769  // Alice - sequence is too far ahead, so won't queue.
770  env(noop(alice), seq(env.seq(alice) + 2), ter(telCAN_NOT_QUEUE));
771  checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
772 
773  // Bob with really high fee - applies
774  env(noop(bob), openLedgerFee(env));
775  checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
776 
777  // Daria with low fee: hold
778  env(noop(charlie), fee(1000), queued);
779  checkMetrics(__LINE__, env, 2, std::nullopt, 4, 2, 256);
780 
781  // Alice with normal fee: hold
782  env(noop(alice), seq(env.seq(alice) + 1), queued);
783  checkMetrics(__LINE__, env, 3, std::nullopt, 4, 2, 256);
784 
785  env.close();
786  // Verify that the held transactions got applied
787  // Alice's bad transaction applied from the
788  // Local Txs.
789  checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
790  }
791 
792  void
794  {
795  using namespace jtx;
796  using namespace std::chrono;
797  testcase("last ledger sequence");
798 
799  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "2"}}));
800 
801  auto alice = Account("alice");
802  auto bob = Account("bob");
803  auto charlie = Account("charlie");
804  auto daria = Account("daria");
805  auto edgar = Account("edgar");
806  auto felicia = Account("felicia");
807 
808  auto queued = ter(terQUEUED);
809 
810  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
811 
812  // Fund across several ledgers so the TxQ metrics stay restricted.
813  env.fund(XRP(1000), noripple(alice, bob));
814  env.close(env.now() + 5s, 10000ms);
815  env.fund(XRP(1000), noripple(charlie, daria));
816  env.close(env.now() + 5s, 10000ms);
817  env.fund(XRP(1000), noripple(edgar, felicia));
818  env.close(env.now() + 5s, 10000ms);
819 
820  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
821  env(noop(bob));
822  env(noop(charlie));
823  env(noop(daria));
824  checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
825 
826  BEAST_EXPECT(env.current()->info().seq == 6);
827  // Fail to queue an item with a low LastLedgerSeq
828  env(noop(alice),
829  json(R"({"LastLedgerSequence":7})"),
831  // Queue an item with a sufficient LastLedgerSeq.
832  env(noop(alice), json(R"({"LastLedgerSequence":8})"), queued);
833  // Queue items with higher fees to force the previous
834  // txn to wait.
835  env(noop(bob), fee(7000), queued);
836  env(noop(charlie), fee(7000), queued);
837  env(noop(daria), fee(7000), queued);
838  env(noop(edgar), fee(7000), queued);
839  checkMetrics(__LINE__, env, 5, std::nullopt, 3, 2, 256);
840  {
841  auto& txQ = env.app().getTxQ();
842  auto aliceStat = txQ.getAccountTxs(alice.id());
843  BEAST_EXPECT(aliceStat.size() == 1);
844  BEAST_EXPECT(aliceStat.begin()->feeLevel == FeeLevel64{256});
845  BEAST_EXPECT(
846  aliceStat.begin()->lastValid &&
847  *aliceStat.begin()->lastValid == 8);
848  BEAST_EXPECT(!aliceStat.begin()->consequences.isBlocker());
849 
850  auto bobStat = txQ.getAccountTxs(bob.id());
851  BEAST_EXPECT(bobStat.size() == 1);
852  BEAST_EXPECT(
853  bobStat.begin()->feeLevel == FeeLevel64{7000 * 256 / 10});
854  BEAST_EXPECT(!bobStat.begin()->lastValid);
855  BEAST_EXPECT(!bobStat.begin()->consequences.isBlocker());
856 
857  auto noStat = txQ.getAccountTxs(Account::master.id());
858  BEAST_EXPECT(noStat.empty());
859  }
860 
861  env.close();
862  checkMetrics(__LINE__, env, 1, 6, 4, 3, 256);
863 
864  // Keep alice's transaction waiting.
865  env(noop(bob), fee(7000), queued);
866  env(noop(charlie), fee(7000), queued);
867  env(noop(daria), fee(7000), queued);
868  env(noop(edgar), fee(7000), queued);
869  env(noop(felicia), fee(6999), queued);
870  checkMetrics(__LINE__, env, 6, 6, 4, 3, 257);
871 
872  env.close();
873  // alice's transaction is still hanging around
874  checkMetrics(__LINE__, env, 1, 8, 5, 4, 256, 700 * 256);
875  BEAST_EXPECT(env.seq(alice) == 3);
876 
877  // Keep alice's transaction waiting.
878  env(noop(bob), fee(8000), queued);
879  env(noop(charlie), fee(8000), queued);
880  env(noop(daria), fee(8000), queued);
881  env(noop(daria), fee(8000), seq(env.seq(daria) + 1), queued);
882  env(noop(edgar), fee(8000), queued);
883  env(noop(felicia), fee(7999), queued);
884  env(noop(felicia), fee(7999), seq(env.seq(felicia) + 1), queued);
885  checkMetrics(__LINE__, env, 8, 8, 5, 4, 257, 700 * 256);
886 
887  env.close();
888  // alice's transaction expired without getting
889  // into the ledger, so her transaction is gone,
890  // though one of felicia's is still in the queue.
891  checkMetrics(__LINE__, env, 1, 10, 6, 5, 256, 700 * 256);
892  BEAST_EXPECT(env.seq(alice) == 3);
893  BEAST_EXPECT(env.seq(felicia) == 7);
894 
895  env.close();
896  // And now the queue is empty
897  checkMetrics(__LINE__, env, 0, 12, 1, 6, 256, 800 * 256);
898  BEAST_EXPECT(env.seq(alice) == 3);
899  BEAST_EXPECT(env.seq(felicia) == 8);
900  }
901 
902  void
904  {
905  using namespace jtx;
906  using namespace std::chrono;
907  testcase("zero transaction fee");
908 
909  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "2"}}));
910 
911  auto alice = Account("alice");
912  auto bob = Account("bob");
913  auto carol = Account("carol");
914 
915  auto queued = ter(terQUEUED);
916 
917  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
918 
919  // Fund across several ledgers so the TxQ metrics stay restricted.
920  env.fund(XRP(1000), noripple(alice, bob));
921  env.close(env.now() + 5s, 10000ms);
922  env.fund(XRP(1000), noripple(carol));
923  env.close(env.now() + 5s, 10000ms);
924 
925  // Fill the ledger
926  env(noop(alice));
927  env(noop(alice));
928  env(noop(alice));
929  checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
930 
931  env(noop(bob), queued);
932  checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
933 
934  // Since Alice's queue is empty this blocker can go into her queue.
935  env(regkey(alice, bob), fee(0), queued);
936  checkMetrics(__LINE__, env, 2, std::nullopt, 3, 2, 256);
937 
938  // Close out this ledger so we can get a maxsize
939  env.close();
940  checkMetrics(__LINE__, env, 0, 6, 2, 3, 256);
941 
942  fillQueue(env, alice);
943  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
944 
945  auto feeAlice = 30;
946  auto seqAlice = env.seq(alice);
947  for (int i = 0; i < 4; ++i)
948  {
949  env(noop(alice), fee(feeAlice), seq(seqAlice), queued);
950  feeAlice = (feeAlice + 1) * 125 / 100;
951  ++seqAlice;
952  }
953  checkMetrics(__LINE__, env, 4, 6, 4, 3, 256);
954 
955  // Bob adds a zero fee blocker to his queue.
956  auto const seqBob = env.seq(bob);
957  env(regkey(bob, alice), fee(0), queued);
958  checkMetrics(__LINE__, env, 5, 6, 4, 3, 256);
959 
960  // Carol fills the queue.
961  auto feeCarol = feeAlice;
962  auto seqCarol = env.seq(carol);
963  for (int i = 0; i < 4; ++i)
964  {
965  env(noop(carol), fee(feeCarol), seq(seqCarol), queued);
966  feeCarol = (feeCarol + 1) * 125 / 100;
967  ++seqCarol;
968  }
969  checkMetrics(__LINE__, env, 6, 6, 4, 3, 3 * 256 + 1);
970 
971  // Carol submits high enough to beat Bob's average fee which kicks
972  // out Bob's queued transaction. However Bob's transaction stays
973  // in the localTx queue, so it will return to the TxQ next time
974  // around.
975  env(noop(carol), fee(feeCarol), seq(seqCarol), ter(terQUEUED));
976 
977  env.close();
978  // Some of Alice's transactions stay in the queue. Bob's
979  // transaction returns to the TxQ.
980  checkMetrics(__LINE__, env, 5, 8, 5, 4, 256);
981  BEAST_EXPECT(env.seq(alice) == seqAlice - 4);
982  BEAST_EXPECT(env.seq(bob) == seqBob);
983  BEAST_EXPECT(env.seq(carol) == seqCarol + 1);
984 
985  env.close();
986  // The remaining queued transactions flush through to the ledger.
987  checkMetrics(__LINE__, env, 0, 10, 5, 5, 256);
988  BEAST_EXPECT(env.seq(alice) == seqAlice);
989  BEAST_EXPECT(env.seq(bob) == seqBob + 1);
990  BEAST_EXPECT(env.seq(carol) == seqCarol + 1);
991 
992  env.close();
993  checkMetrics(__LINE__, env, 0, 10, 0, 5, 256);
994  BEAST_EXPECT(env.seq(alice) == seqAlice);
995  BEAST_EXPECT(env.seq(bob) == seqBob + 1);
996  BEAST_EXPECT(env.seq(carol) == seqCarol + 1);
997  }
998 
999  void
1001  {
1002  using namespace jtx;
1003 
1004  Env env(*this, makeConfig());
1005  testcase("fail in preclaim");
1006 
1007  auto alice = Account("alice");
1008  auto bob = Account("bob");
1009 
1010  env.fund(XRP(1000), noripple(alice));
1011 
1012  // These types of checks are tested elsewhere, but
1013  // this verifies that TxQ handles the failures as
1014  // expected.
1015 
1016  // Fail in preflight
1017  env(pay(alice, bob, XRP(-1000)), ter(temBAD_AMOUNT));
1018 
1019  // Fail in preclaim
1020  env(noop(alice), fee(XRP(100000)), ter(terINSUF_FEE_B));
1021  }
1022 
1023  void
1025  {
1026  using namespace jtx;
1027  testcase("queued tx fails");
1028 
1029  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "2"}}));
1030 
1031  auto alice = Account("alice");
1032  auto bob = Account("bob");
1033 
1034  auto queued = ter(terQUEUED);
1035 
1036  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1037 
1038  env.fund(XRP(1000), noripple(alice, bob));
1039 
1040  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 2, 256);
1041 
1042  // Fill the ledger
1043  env(noop(alice));
1044  checkMetrics(__LINE__, env, 0, std::nullopt, 3, 2, 256);
1045 
1046  // Put a transaction in the queue
1047  env(noop(alice), queued);
1048  checkMetrics(__LINE__, env, 1, std::nullopt, 3, 2, 256);
1049 
1050  // Now cheat, and bypass the queue.
1051  {
1052  auto const& jt = env.jt(noop(alice));
1053  BEAST_EXPECT(jt.stx);
1054 
1055  bool didApply;
1056  TER ter;
1057 
1058  env.app().openLedger().modify(
1059  [&](OpenView& view, beast::Journal j) {
1060  std::tie(ter, didApply) = ripple::apply(
1061  env.app(), view, *jt.stx, tapNONE, env.journal);
1062  return didApply;
1063  });
1064  env.postconditions(jt, ter, didApply);
1065  }
1066  checkMetrics(__LINE__, env, 1, std::nullopt, 4, 2, 256);
1067 
1068  env.close();
1069  // Alice's queued transaction failed in TxQ::accept
1070  // with tefPAST_SEQ
1071  checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
1072  }
1073 
1074  void
1076  {
1077  using namespace jtx;
1078  testcase("multi tx per account");
1079 
1080  Env env(
1081  *this,
1082  makeConfig(
1083  {{"minimum_txn_in_ledger_standalone", "3"}},
1084  {{"account_reserve", "200"}, {"owner_reserve", "50"}}));
1085 
1086  auto alice = Account("alice");
1087  auto bob = Account("bob");
1088  auto charlie = Account("charlie");
1089  auto daria = Account("daria");
1090 
1091  auto queued = ter(terQUEUED);
1092 
1093  BEAST_EXPECT(env.current()->fees().base == 10);
1094 
1095  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1096 
1097  // ledgers in queue is 2 because of makeConfig
1098  auto const initQueueMax = initFee(env, 3, 2, 10, 10, 200, 50);
1099 
1100  // Create several accounts while the fee is cheap so they all apply.
1101  env.fund(drops(2000), noripple(alice));
1102  env.fund(XRP(500000), noripple(bob, charlie, daria));
1103  checkMetrics(__LINE__, env, 0, initQueueMax, 4, 3, 256);
1104 
1105  // Alice - price starts exploding: held
1106  env(noop(alice), fee(11), queued);
1107  checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1108 
1109  auto aliceSeq = env.seq(alice);
1110  auto bobSeq = env.seq(bob);
1111  auto charlieSeq = env.seq(charlie);
1112 
1113  // Alice - try to queue a second transaction, but leave a gap
1114  env(noop(alice), seq(aliceSeq + 2), fee(100), ter(telCAN_NOT_QUEUE));
1115  checkMetrics(__LINE__, env, 1, initQueueMax, 4, 3, 256);
1116 
1117  // Alice - queue a second transaction. Yay!
1118  env(noop(alice), seq(aliceSeq + 1), fee(13), queued);
1119  checkMetrics(__LINE__, env, 2, initQueueMax, 4, 3, 256);
1120 
1121  // Alice - queue a third transaction. Yay.
1122  env(noop(alice), seq(aliceSeq + 2), fee(17), queued);
1123  checkMetrics(__LINE__, env, 3, initQueueMax, 4, 3, 256);
1124 
1125  // Bob - queue a transaction
1126  env(noop(bob), queued);
1127  checkMetrics(__LINE__, env, 4, initQueueMax, 4, 3, 256);
1128 
1129  // Bob - queue a second transaction
1130  env(noop(bob), seq(bobSeq + 1), fee(50), queued);
1131  checkMetrics(__LINE__, env, 5, initQueueMax, 4, 3, 256);
1132 
1133  // Charlie - queue a transaction, with a higher fee
1134  // than default
1135  env(noop(charlie), fee(15), queued);
1136  checkMetrics(__LINE__, env, 6, initQueueMax, 4, 3, 256);
1137 
1138  BEAST_EXPECT(env.seq(alice) == aliceSeq);
1139  BEAST_EXPECT(env.seq(bob) == bobSeq);
1140  BEAST_EXPECT(env.seq(charlie) == charlieSeq);
1141 
1142  env.close();
1143  // Verify that all of but one of the queued transactions
1144  // got applied.
1145  checkMetrics(__LINE__, env, 1, 8, 5, 4, 256);
1146 
1147  // Verify that the stuck transaction is Bob's second.
1148  // Even though it had a higher fee than Alice's and
1149  // Charlie's, it didn't get attempted until the fee escalated.
1150  BEAST_EXPECT(env.seq(alice) == aliceSeq + 3);
1151  BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
1152  BEAST_EXPECT(env.seq(charlie) == charlieSeq + 1);
1153 
1154  // Alice - fill up the queue
1155  std::int64_t aliceFee = 27;
1156  aliceSeq = env.seq(alice);
1157  auto lastLedgerSeq = env.current()->info().seq + 2;
1158  for (auto i = 0; i < 7; i++)
1159  {
1160  env(noop(alice),
1161  seq(aliceSeq),
1162  json(jss::LastLedgerSequence, lastLedgerSeq + i),
1163  fee(--aliceFee),
1164  queued);
1165  ++aliceSeq;
1166  }
1167  checkMetrics(__LINE__, env, 8, 8, 5, 4, 513);
1168  {
1169  auto& txQ = env.app().getTxQ();
1170  auto aliceStat = txQ.getAccountTxs(alice.id());
1171  aliceFee = 27;
1172  auto const& baseFee = env.current()->fees().base;
1173  auto seq = env.seq(alice);
1174  BEAST_EXPECT(aliceStat.size() == 7);
1175  for (auto const& tx : aliceStat)
1176  {
1177  BEAST_EXPECT(tx.seqProxy.isSeq() && tx.seqProxy.value() == seq);
1178  BEAST_EXPECT(
1179  tx.feeLevel == toFeeLevel(XRPAmount(--aliceFee), baseFee));
1180  BEAST_EXPECT(tx.lastValid);
1181  BEAST_EXPECT(
1182  (tx.consequences.fee() == drops(aliceFee) &&
1183  tx.consequences.potentialSpend() == drops(0) &&
1184  !tx.consequences.isBlocker()) ||
1185  tx.seqProxy.value() == env.seq(alice) + 6);
1186  ++seq;
1187  }
1188  }
1189 
1190  // Alice attempts to add another item to the queue,
1191  // but you can't force your own earlier txn off the
1192  // queue.
1193  env(noop(alice),
1194  seq(aliceSeq),
1195  json(jss::LastLedgerSequence, lastLedgerSeq + 7),
1196  fee(aliceFee),
1198  checkMetrics(__LINE__, env, 8, 8, 5, 4, 513);
1199 
1200  // Charlie - try to add another item to the queue,
1201  // which fails because fee is lower than Alice's
1202  // queued average.
1203  env(noop(charlie), fee(19), ter(telCAN_NOT_QUEUE_FULL));
1204  checkMetrics(__LINE__, env, 8, 8, 5, 4, 513);
1205 
1206  // Charlie - add another item to the queue, which
1207  // causes Alice's last txn to drop
1208  env(noop(charlie), fee(30), queued);
1209  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
1210 
1211  // Alice - now attempt to add one more to the queue,
1212  // which fails because the last tx was dropped, so
1213  // there is no complete chain.
1214  env(noop(alice), seq(aliceSeq), fee(aliceFee), ter(telCAN_NOT_QUEUE));
1215  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
1216 
1217  // Alice wants this tx more than the dropped tx,
1218  // so resubmits with higher fee, but the queue
1219  // is full, and her account is the cheapest.
1220  env(noop(alice),
1221  seq(aliceSeq - 1),
1222  fee(aliceFee),
1224  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
1225 
1226  // Try to replace a middle item in the queue
1227  // without enough fee.
1228  aliceSeq = env.seq(alice) + 2;
1229  aliceFee = 29;
1230  env(noop(alice),
1231  seq(aliceSeq),
1232  fee(aliceFee),
1234  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
1235 
1236  // Replace a middle item from the queue successfully
1237  ++aliceFee;
1238  env(noop(alice), seq(aliceSeq), fee(aliceFee), queued);
1239  checkMetrics(__LINE__, env, 8, 8, 5, 4, 538);
1240 
1241  env.close();
1242  // Alice's transactions processed, along with
1243  // Charlie's, and the lost one is replayed and
1244  // added back to the queue.
1245  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
1246 
1247  aliceSeq = env.seq(alice) + 1;
1248 
1249  // Try to replace that item with a transaction that will
1250  // bankrupt Alice. Fails, because an account can't have
1251  // more than the minimum reserve in flight before the
1252  // last queued transaction
1253  aliceFee =
1254  env.le(alice)->getFieldAmount(sfBalance).xrp().drops() - (62);
1255  env(noop(alice),
1256  seq(aliceSeq),
1257  fee(aliceFee),
1259  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
1260 
1261  // Try to spend more than Alice can afford with all the other txs.
1262  aliceSeq += 2;
1263  env(noop(alice), seq(aliceSeq), fee(aliceFee), ter(terINSUF_FEE_B));
1264  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
1265 
1266  // Replace the last queued item with a transaction that will
1267  // bankrupt Alice
1268  --aliceFee;
1269  env(noop(alice), seq(aliceSeq), fee(aliceFee), queued);
1270  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
1271 
1272  // Alice - Attempt to queue a last transaction, but it
1273  // fails because the fee in flight is too high, before
1274  // the fee is checked against the balance
1275  aliceFee /= 5;
1276  ++aliceSeq;
1277  env(noop(alice),
1278  seq(aliceSeq),
1279  fee(aliceFee),
1281  checkMetrics(__LINE__, env, 4, 10, 6, 5, 256);
1282 
1283  env.close();
1284  // All of Alice's transactions applied.
1285  checkMetrics(__LINE__, env, 0, 12, 4, 6, 256);
1286 
1287  env.close();
1288  checkMetrics(__LINE__, env, 0, 12, 0, 6, 256);
1289 
1290  // Alice is broke
1291  env.require(balance(alice, XRP(0)));
1292  env(noop(alice), ter(terINSUF_FEE_B));
1293 
1294  // Bob tries to queue up more than the single
1295  // account limit (10) txs.
1296  fillQueue(env, bob);
1297  bobSeq = env.seq(bob);
1298  checkMetrics(__LINE__, env, 0, 12, 7, 6, 256);
1299  for (int i = 0; i < 10; ++i)
1300  env(noop(bob), seq(bobSeq + i), queued);
1301  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
1302  // Bob hit the single account limit
1303  env(noop(bob), seq(bobSeq + 10), ter(telCAN_NOT_QUEUE_FULL));
1304  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
1305  // Bob can replace one of the earlier txs regardless
1306  // of the limit
1307  env(noop(bob), seq(bobSeq + 5), fee(20), queued);
1308  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
1309 
1310  // Try to replace a middle item in the queue
1311  // with enough fee to bankrupt bob and make the
1312  // later transactions unable to pay their fees
1313  std::int64_t bobFee =
1314  env.le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10 - 1);
1315  env(noop(bob),
1316  seq(bobSeq + 5),
1317  fee(bobFee),
1319  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
1320 
1321  // Attempt to replace a middle item in the queue with enough fee
1322  // to bankrupt bob, and also to use fee averaging to clear out the
1323  // first six transactions.
1324  //
1325  // The attempt fails because the sum of bob's fees now exceeds the
1326  // (artificially lowered to 200 drops) account reserve.
1327  bobFee =
1328  env.le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10);
1329  env(noop(bob),
1330  seq(bobSeq + 5),
1331  fee(bobFee),
1333  checkMetrics(__LINE__, env, 10, 12, 7, 6, 256);
1334 
1335  // Close the ledger and verify that the queued transactions succeed
1336  // and bob has the right ending balance.
1337  env.close();
1338  checkMetrics(__LINE__, env, 3, 14, 8, 7, 256);
1339  env.close();
1340  checkMetrics(__LINE__, env, 0, 16, 3, 8, 256);
1341  env.require(balance(bob, drops(499'999'999'750)));
1342  }
1343 
1344  void
1345  testTieBreaking()
1346  {
1347  using namespace jtx;
1348  using namespace std::chrono;
1349  testcase("tie breaking");
1350 
1351  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "4"}}));
1352 
1353  auto alice = Account("alice");
1354  auto bob = Account("bob");
1355  auto charlie = Account("charlie");
1356  auto daria = Account("daria");
1357  auto elmo = Account("elmo");
1358  auto fred = Account("fred");
1359  auto gwen = Account("gwen");
1360  auto hank = Account("hank");
1361 
1362  auto queued = ter(terQUEUED);
1363 
1364  BEAST_EXPECT(env.current()->fees().base == 10);
1365 
1366  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 4, 256);
1367 
1368  // Create several accounts while the fee is cheap so they all apply.
1369  env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
1370  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 4, 256);
1371 
1372  env.close();
1373  checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
1374 
1375  env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
1376  checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
1377 
1378  env.close();
1379  checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
1380 
1382 
1383  // Stuff the ledger and queue so we can verify that
1384  // stuff gets kicked out.
1385  env(noop(gwen));
1386  env(noop(hank));
1387  env(noop(gwen));
1388  env(noop(fred));
1389  env(noop(elmo));
1390  checkMetrics(__LINE__, env, 0, 8, 5, 4, 256);
1391 
1392  auto aliceSeq = env.seq(alice);
1393  auto bobSeq = env.seq(bob);
1394  auto charlieSeq = env.seq(charlie);
1395  auto dariaSeq = env.seq(daria);
1396  auto elmoSeq = env.seq(elmo);
1397  auto fredSeq = env.seq(fred);
1398  auto gwenSeq = env.seq(gwen);
1399  auto hankSeq = env.seq(hank);
1400 
1401  // This time, use identical fees.
1402 
1403  // All of these get into the queue, but one gets dropped when the
1404  // higher fee one is added later. Which one depends on ordering.
1405  env(noop(alice), fee(15), queued);
1406  env(noop(bob), fee(15), queued);
1407  env(noop(charlie), fee(15), queued);
1408  env(noop(daria), fee(15), queued);
1409  env(noop(elmo), fee(15), queued);
1410  env(noop(fred), fee(15), queued);
1411  env(noop(gwen), fee(15), queued);
1412  env(noop(hank), fee(15), queued);
1413 
1414  // Queue is full now. Minimum fee now reflects the
1415  // lowest fee in the queue.
1416  checkMetrics(__LINE__, env, 8, 8, 5, 4, 385);
1417 
1418  // Try to add another transaction with the default (low) fee,
1419  // it should fail because it can't replace the one already
1420  // there.
1421  env(noop(charlie), ter(telCAN_NOT_QUEUE_FEE));
1422 
1423  // Add another transaction, with a higher fee,
1424  // Not high enough to get into the ledger, but high
1425  // enough to get into the queue (and kick somebody out)
1426  env(noop(charlie), fee(100), seq(charlieSeq + 1), queued);
1427 
1428  // Queue is still full.
1429  checkMetrics(__LINE__, env, 8, 8, 5, 4, 385);
1430 
1431  // Six txs are processed out of the queue into the ledger,
1432  // leaving two txs. The dropped tx is retried from localTxs, and
1433  // put back into the queue.
1434  env.close();
1435  checkMetrics(__LINE__, env, 3, 10, 6, 5, 256);
1436 
1437  // This next test should remain unchanged regardless of
1438  // transaction ordering
1439  BEAST_EXPECT(
1440  aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1441  gwenSeq + hankSeq + 6 ==
1442  env.seq(alice) + env.seq(bob) + env.seq(charlie) + env.seq(daria) +
1443  env.seq(elmo) + env.seq(fred) + env.seq(gwen) + env.seq(hank));
1444  // These tests may change if TxQ ordering is changed
1445  using namespace std::string_literals;
1446  BEAST_EXPECTS(
1447  aliceSeq + 1 == env.seq(alice),
1448  "alice: "s + std::to_string(aliceSeq) + ", " +
1449  std::to_string(env.seq(alice)));
1450  BEAST_EXPECTS(
1451  bobSeq + 1 == env.seq(bob),
1452  "bob: "s + std::to_string(bobSeq) + ", " +
1453  std::to_string(env.seq(bob)));
1454  BEAST_EXPECTS(
1455  charlieSeq + 2 == env.seq(charlie),
1456  "charlie: "s + std::to_string(charlieSeq) + ", " +
1457  std::to_string(env.seq(charlie)));
1458  BEAST_EXPECTS(
1459  dariaSeq == env.seq(daria),
1460  "daria: "s + std::to_string(dariaSeq) + ", " +
1461  std::to_string(env.seq(daria)));
1462  BEAST_EXPECTS(
1463  elmoSeq + 1 == env.seq(elmo),
1464  "elmo: "s + std::to_string(elmoSeq) + ", " +
1465  std::to_string(env.seq(elmo)));
1466  BEAST_EXPECTS(
1467  fredSeq == env.seq(fred),
1468  "fred: "s + std::to_string(fredSeq) + ", " +
1469  std::to_string(env.seq(fred)));
1470  BEAST_EXPECTS(
1471  gwenSeq + 1 == env.seq(gwen),
1472  "gwen: "s + std::to_string(gwenSeq) + ", " +
1473  std::to_string(env.seq(gwen)));
1474  BEAST_EXPECTS(
1475  hankSeq == env.seq(hank),
1476  "hank: "s + std::to_string(hankSeq) + ", " +
1477  std::to_string(env.seq(hank)));
1478 
1479  // Which sequences get incremented may change if TxQ ordering is
1480  // changed
1481  ++aliceSeq;
1482  ++bobSeq;
1483  ++(++charlieSeq);
1484  // ++dariaSeq;
1485  ++elmoSeq;
1486  // ++fredSeq;
1487  ++gwenSeq;
1488  // ++hankSeq;
1489 
1490  auto getTxsQueued = [&]() {
1491  auto const txs = env.app().getTxQ().getTxs();
1493  for (auto const& tx : txs)
1494  {
1495  ++result[tx.txn->at(sfAccount)];
1496  }
1497  return result;
1498  };
1499  auto qTxCount1 = getTxsQueued();
1500  BEAST_EXPECT(qTxCount1.size() <= 3);
1501 
1502  // Fill up the queue again
1503  env(noop(alice),
1504  seq(aliceSeq + qTxCount1[alice.id()]++),
1505  fee(15),
1506  queued);
1507  env(noop(bob), seq(bobSeq + qTxCount1[bob.id()]++), fee(15), queued);
1508  env(noop(charlie),
1509  seq(charlieSeq + qTxCount1[charlie.id()]++),
1510  fee(15),
1511  queued);
1512  env(noop(daria),
1513  seq(dariaSeq + qTxCount1[daria.id()]++),
1514  fee(15),
1515  queued);
1516  env(noop(elmo), seq(elmoSeq + qTxCount1[elmo.id()]++), fee(15), queued);
1517  env(noop(fred), seq(fredSeq + qTxCount1[fred.id()]++), fee(15), queued);
1518  env(noop(gwen), seq(gwenSeq + qTxCount1[gwen.id()]++), fee(15), queued);
1519  checkMetrics(__LINE__, env, 10, 10, 6, 5, 385);
1520 
1521  // Add another transaction, with a higher fee,
1522  // Not high enough to get into the ledger, but high
1523  // enough to get into the queue (and kick somebody out)
1524  env(noop(alice),
1525  fee(100),
1526  seq(aliceSeq + qTxCount1[alice.id()]++),
1527  queued);
1528 
1529  checkMetrics(__LINE__, env, 10, 10, 6, 5, 385);
1530 
1531  // Seven txs are processed out of the queue, leaving 3. One
1532  // dropped tx is retried from localTxs, and put back into the
1533  // queue.
1534  env.close();
1535  checkMetrics(__LINE__, env, 4, 12, 7, 6, 256);
1536 
1537  // Refresh the queue counts
1538  auto qTxCount2 = getTxsQueued();
1539  BEAST_EXPECT(qTxCount2.size() <= 4);
1540 
1541  // This next test should remain unchanged regardless of
1542  // transaction ordering
1543  BEAST_EXPECT(
1544  aliceSeq + bobSeq + charlieSeq + dariaSeq + elmoSeq + fredSeq +
1545  gwenSeq + hankSeq + 7 ==
1546  env.seq(alice) + env.seq(bob) + env.seq(charlie) + env.seq(daria) +
1547  env.seq(elmo) + env.seq(fred) + env.seq(gwen) + env.seq(hank));
1548  // These tests may change if TxQ ordering is changed
1549  BEAST_EXPECTS(
1550  aliceSeq + qTxCount1[alice.id()] - qTxCount2[alice.id()] ==
1551  env.seq(alice),
1552  "alice: "s + std::to_string(aliceSeq) + ", " +
1553  std::to_string(env.seq(alice)));
1554  BEAST_EXPECTS(
1555  bobSeq + qTxCount1[bob.id()] - qTxCount2[bob.id()] == env.seq(bob),
1556  "bob: "s + std::to_string(bobSeq) + ", " +
1557  std::to_string(env.seq(bob)));
1558  BEAST_EXPECTS(
1559  charlieSeq + qTxCount1[charlie.id()] - qTxCount2[charlie.id()] ==
1560  env.seq(charlie),
1561  "charlie: "s + std::to_string(charlieSeq) + ", " +
1562  std::to_string(env.seq(charlie)));
1563  BEAST_EXPECTS(
1564  dariaSeq + qTxCount1[daria.id()] - qTxCount2[daria.id()] ==
1565  env.seq(daria),
1566  "daria: "s + std::to_string(dariaSeq) + ", " +
1567  std::to_string(env.seq(daria)));
1568  BEAST_EXPECTS(
1569  elmoSeq + qTxCount1[elmo.id()] - qTxCount2[elmo.id()] ==
1570  env.seq(elmo),
1571  "elmo: "s + std::to_string(elmoSeq) + ", " +
1572  std::to_string(env.seq(elmo)));
1573  BEAST_EXPECTS(
1574  fredSeq + qTxCount1[fred.id()] - qTxCount2[fred.id()] ==
1575  env.seq(fred),
1576  "fred: "s + std::to_string(fredSeq) + ", " +
1577  std::to_string(env.seq(fred)));
1578  BEAST_EXPECTS(
1579  gwenSeq + qTxCount1[gwen.id()] - qTxCount2[gwen.id()] ==
1580  env.seq(gwen),
1581  "gwen: "s + std::to_string(gwenSeq) + ", " +
1582  std::to_string(env.seq(gwen)));
1583  BEAST_EXPECTS(
1584  hankSeq + qTxCount1[hank.id()] - qTxCount2[hank.id()] ==
1585  env.seq(hank),
1586  "hank: "s + std::to_string(hankSeq) + ", " +
1587  std::to_string(env.seq(hank)));
1588  }
1589 
1590  void
1592  {
1593  using namespace jtx;
1594  testcase("acct tx id");
1595 
1596  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "1"}}));
1597 
1598  auto alice = Account("alice");
1599 
1600  BEAST_EXPECT(env.current()->fees().base == 10);
1601 
1602  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 1, 256);
1603 
1604  env.fund(XRP(50000), noripple(alice));
1605  checkMetrics(__LINE__, env, 0, std::nullopt, 1, 1, 256);
1606 
1607  env(fset(alice, asfAccountTxnID));
1608  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1609 
1610  // Immediately after the fset, the sfAccountTxnID field
1611  // is still uninitialized, so preflight succeeds here,
1612  // and this txn fails because it can't be stored in the queue.
1613  env(noop(alice),
1614  json(R"({"AccountTxnID": "0"})"),
1616 
1617  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
1618  env.close();
1619  // The failed transaction is retried from LocalTx
1620  // and succeeds.
1621  checkMetrics(__LINE__, env, 0, 4, 1, 2, 256);
1622 
1623  env(noop(alice));
1624  checkMetrics(__LINE__, env, 0, 4, 2, 2, 256);
1625 
1626  env(noop(alice), json(R"({"AccountTxnID": "0"})"), ter(tefWRONG_PRIOR));
1627  }
1628 
1629  void
1631  {
1632  using namespace jtx;
1633  using namespace std::string_literals;
1634  testcase("maximum tx");
1635 
1636  {
1637  Env env(
1638  *this,
1639  makeConfig(
1640  {{"minimum_txn_in_ledger_standalone", "2"},
1641  {"minimum_txn_in_ledger", "5"},
1642  {"target_txn_in_ledger", "4"},
1643  {"maximum_txn_in_ledger", "5"}}));
1644 
1645  auto alice = Account("alice");
1646 
1647  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 2, 256);
1648 
1649  env.fund(XRP(50000), noripple(alice));
1650  checkMetrics(__LINE__, env, 0, std::nullopt, 1, 2, 256);
1651 
1652  for (int i = 0; i < 10; ++i)
1653  env(noop(alice), openLedgerFee(env));
1654 
1655  checkMetrics(__LINE__, env, 0, std::nullopt, 11, 2, 256);
1656 
1657  env.close();
1658  // If not for the maximum, the per ledger would be 11.
1659  checkMetrics(__LINE__, env, 0, 10, 0, 5, 256, 800025);
1660  }
1661 
1662  try
1663  {
1664  Env env(
1665  *this,
1666  makeConfig(
1667  {{"minimum_txn_in_ledger", "200"},
1668  {"minimum_txn_in_ledger_standalone", "200"},
1669  {"target_txn_in_ledger", "4"},
1670  {"maximum_txn_in_ledger", "5"}}));
1671  // should throw
1672  fail();
1673  }
1674  catch (std::runtime_error const& e)
1675  {
1676  BEAST_EXPECT(
1677  e.what() ==
1678  "The minimum number of low-fee transactions allowed "
1679  "per ledger (minimum_txn_in_ledger) exceeds "
1680  "the maximum number of low-fee transactions allowed per "
1681  "ledger (maximum_txn_in_ledger)."s);
1682  }
1683  try
1684  {
1685  Env env(
1686  *this,
1687  makeConfig(
1688  {{"minimum_txn_in_ledger", "200"},
1689  {"minimum_txn_in_ledger_standalone", "2"},
1690  {"target_txn_in_ledger", "4"},
1691  {"maximum_txn_in_ledger", "5"}}));
1692  // should throw
1693  fail();
1694  }
1695  catch (std::runtime_error const& e)
1696  {
1697  BEAST_EXPECT(
1698  e.what() ==
1699  "The minimum number of low-fee transactions allowed "
1700  "per ledger (minimum_txn_in_ledger) exceeds "
1701  "the maximum number of low-fee transactions allowed per "
1702  "ledger (maximum_txn_in_ledger)."s);
1703  }
1704  try
1705  {
1706  Env env(
1707  *this,
1708  makeConfig(
1709  {{"minimum_txn_in_ledger", "2"},
1710  {"minimum_txn_in_ledger_standalone", "200"},
1711  {"target_txn_in_ledger", "4"},
1712  {"maximum_txn_in_ledger", "5"}}));
1713  // should throw
1714  fail();
1715  }
1716  catch (std::runtime_error const& e)
1717  {
1718  BEAST_EXPECT(
1719  e.what() ==
1720  "The minimum number of low-fee transactions allowed "
1721  "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1722  "the maximum number of low-fee transactions allowed per "
1723  "ledger (maximum_txn_in_ledger)."s);
1724  }
1725  }
1726 
1727  void
1729  {
1730  using namespace jtx;
1731  testcase("unexpected balance change");
1732 
1733  Env env(
1734  *this,
1735  makeConfig(
1736  {{"minimum_txn_in_ledger_standalone", "3"}},
1737  {{"account_reserve", "200"}, {"owner_reserve", "50"}}));
1738 
1739  auto alice = Account("alice");
1740  auto bob = Account("bob");
1741 
1742  auto queued = ter(terQUEUED);
1743 
1744  // ledgers in queue is 2 because of makeConfig
1745  auto const initQueueMax = initFee(env, 3, 2, 10, 10, 200, 50);
1746 
1747  BEAST_EXPECT(env.current()->fees().base == 10);
1748 
1749  checkMetrics(__LINE__, env, 0, initQueueMax, 0, 3, 256);
1750 
1751  env.fund(drops(5000), noripple(alice));
1752  env.fund(XRP(50000), noripple(bob));
1753  checkMetrics(__LINE__, env, 0, initQueueMax, 2, 3, 256);
1754  auto USD = bob["USD"];
1755 
1756  env(offer(alice, USD(5000), drops(5000)), require(owners(alice, 1)));
1757  checkMetrics(__LINE__, env, 0, initQueueMax, 3, 3, 256);
1758 
1759  env.close();
1760  checkMetrics(__LINE__, env, 0, 6, 0, 3, 256);
1761 
1762  // Fill up the ledger
1763  fillQueue(env, alice);
1764  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
1765 
1766  // Queue up a couple of transactions, plus one
1767  // more expensive one.
1768  auto aliceSeq = env.seq(alice);
1769  env(noop(alice), seq(aliceSeq++), queued);
1770  env(noop(alice), seq(aliceSeq++), queued);
1771  env(noop(alice), seq(aliceSeq++), queued);
1772  env(noop(alice), fee(drops(1000)), seq(aliceSeq), queued);
1773  checkMetrics(__LINE__, env, 4, 6, 4, 3, 256);
1774 
1775  // This offer should take Alice's offer
1776  // up to Alice's reserve.
1777  env(offer(bob, drops(5000), USD(5000)),
1778  openLedgerFee(env),
1779  require(
1780  balance(alice, drops(250)), owners(alice, 1), lines(alice, 1)));
1781  checkMetrics(__LINE__, env, 4, 6, 5, 3, 256);
1782 
1783  // Try adding a new transaction.
1784  // Too many fees in flight.
1785  env(noop(alice),
1786  fee(drops(200)),
1787  seq(aliceSeq + 1),
1789  checkMetrics(__LINE__, env, 4, 6, 5, 3, 256);
1790 
1791  // Close the ledger. All of Alice's transactions
1792  // take a fee, except the last one.
1793  env.close();
1794  checkMetrics(__LINE__, env, 1, 10, 3, 5, 256);
1795  env.require(balance(alice, drops(250 - 30)));
1796 
1797  // Still can't add a new transaction for Alice,
1798  // no matter the fee.
1799  env(noop(alice),
1800  fee(drops(200)),
1801  seq(aliceSeq + 1),
1803  checkMetrics(__LINE__, env, 1, 10, 3, 5, 256);
1804 
1805  /* At this point, Alice's transaction is indefinitely
1806  stuck in the queue. Eventually it will either
1807  expire, get forced off the end by more valuable
1808  transactions, get replaced by Alice, or Alice
1809  will get more XRP, and it'll process.
1810  */
1811 
1812  for (int i = 0; i < 9; ++i)
1813  {
1814  env.close();
1815  checkMetrics(__LINE__, env, 1, 10, 0, 5, 256);
1816  }
1817 
1818  // And Alice's transaction expires (via the retry limit,
1819  // not LastLedgerSequence).
1820  env.close();
1821  checkMetrics(__LINE__, env, 0, 10, 0, 5, 256);
1822  }
1823 
1824  void
1826  {
1827  using namespace jtx;
1828  testcase("blockers sequence");
1829 
1830  auto alice = Account("alice");
1831  auto bob = Account("bob");
1832  auto charlie = Account("charlie");
1833  auto daria = Account("daria");
1834 
1835  auto queued = ter(terQUEUED);
1836 
1837  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
1838 
1839  BEAST_EXPECT(env.current()->fees().base == 10);
1840 
1841  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1842 
1843  env.fund(XRP(50000), noripple(alice, bob));
1844  env.memoize(charlie);
1845  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1846  {
1847  // Cannot put a blocker in an account's queue if that queue
1848  // already holds two or more (non-blocker) entries.
1849 
1850  // Fill up the open ledger
1851  env(noop(alice));
1852  // Set a regular key just to clear the password spent flag
1853  env(regkey(alice, charlie));
1854  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1855 
1856  // Put two "normal" txs in the queue
1857  auto const aliceSeq = env.seq(alice);
1858  env(noop(alice), seq(aliceSeq + 0), queued);
1859  env(noop(alice), seq(aliceSeq + 1), queued);
1860 
1861  // Can't replace either queued transaction with a blocker
1862  env(fset(alice, asfAccountTxnID),
1863  seq(aliceSeq + 0),
1864  fee(20),
1866 
1867  env(regkey(alice, bob),
1868  seq(aliceSeq + 1),
1869  fee(20),
1871 
1872  // Can't append a blocker to the queue.
1873  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1874  seq(aliceSeq + 2),
1875  fee(20),
1877 
1878  // Other accounts are not affected
1879  env(noop(bob), queued);
1880  checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
1881 
1882  // Drain the queue.
1883  env.close();
1884  checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
1885  }
1886  {
1887  // Replace a lone non-blocking tx with a blocker.
1888 
1889  // Fill up the open ledger and put just one entry in the TxQ.
1890  env(noop(alice));
1891 
1892  auto const aliceSeq = env.seq(alice);
1893  env(noop(alice), seq(aliceSeq + 0), queued);
1894 
1895  // Since there's only one entry in the queue we can replace
1896  // that entry with a blocker.
1897  env(regkey(alice, bob), seq(aliceSeq + 0), fee(20), queued);
1898 
1899  // Now that there's a blocker in the queue we can't append to
1900  // the queue.
1901  env(noop(alice), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BLOCKED));
1902 
1903  // Other accounts are unaffected.
1904  env(noop(bob), queued);
1905 
1906  // We can replace the blocker with a different blocker.
1907  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1908  seq(aliceSeq + 0),
1909  fee(26),
1910  queued);
1911 
1912  // Prove that the queue is still blocked.
1913  env(noop(alice), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BLOCKED));
1914 
1915  // We can replace the blocker with a non-blocker. Then we can
1916  // successfully append to the queue.
1917  env(noop(alice), seq(aliceSeq + 0), fee(33), queued);
1918  env(noop(alice), seq(aliceSeq + 1), queued);
1919 
1920  // Drain the queue.
1921  env.close();
1922  checkMetrics(__LINE__, env, 0, 10, 3, 5, 256);
1923  }
1924  {
1925  // Put a blocker in an empty queue.
1926 
1927  // Fill up the open ledger and put a blocker as Alice's first
1928  // entry in the (empty) TxQ.
1929  env(noop(alice));
1930  env(noop(alice));
1931  env(noop(alice));
1932 
1933  auto const aliceSeq = env.seq(alice);
1934  env(fset(alice, asfAccountTxnID), seq(aliceSeq + 0), queued);
1935 
1936  // Since there's a blocker in the queue we can't append to
1937  // the queue.
1938  env(noop(alice), seq(aliceSeq + 1), ter(telCAN_NOT_QUEUE_BLOCKED));
1939 
1940  // Other accounts are unaffected.
1941  env(noop(bob), queued);
1942 
1943  // We can replace the blocker with a non-blocker. Then we can
1944  // successfully append to the queue.
1945  env(noop(alice), seq(aliceSeq + 0), fee(20), queued);
1946  env(noop(alice), seq(aliceSeq + 1), queued);
1947 
1948  // Drain the queue.
1949  env.close();
1950  checkMetrics(__LINE__, env, 0, 12, 3, 6, 256);
1951  }
1952  }
1953 
1954  void
1956  {
1957  using namespace jtx;
1958  testcase("blockers ticket");
1959 
1960  auto alice = Account("alice");
1961  auto bob = Account("bob");
1962  auto charlie = Account("charlie");
1963  auto daria = Account("daria");
1964 
1965  auto queued = ter(terQUEUED);
1966 
1967  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
1968 
1969  BEAST_EXPECT(env.current()->fees().base == 10);
1970 
1971  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
1972 
1973  env.fund(XRP(50000), noripple(alice, bob));
1974  env.memoize(charlie);
1975 
1976  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 3, 256);
1977 
1978  std::uint32_t tkt{env.seq(alice) + 1};
1979  {
1980  // Cannot put a blocker in an account's queue if that queue
1981  // already holds two or more (non-blocker) entries.
1982 
1983  // Fill up the open ledger
1984  env(ticket::create(alice, 250), seq(tkt - 1));
1985  // Set a regular key just to clear the password spent flag
1986  env(regkey(alice, charlie));
1987  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
1988 
1989  // Put two "normal" txs in the queue
1990  auto const aliceSeq = env.seq(alice);
1991  env(noop(alice), ticket::use(tkt + 2), queued);
1992  env(noop(alice), ticket::use(tkt + 1), queued);
1993 
1994  // Can't replace either queued transaction with a blocker
1995  env(fset(alice, asfAccountTxnID),
1996  ticket::use(tkt + 1),
1997  fee(20),
1999 
2000  env(regkey(alice, bob),
2001  ticket::use(tkt + 2),
2002  fee(20),
2004 
2005  // Can't append a blocker to the queue.
2006  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2007  fee(20),
2009 
2010  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2011  ticket::use(tkt + 0),
2012  fee(20),
2014 
2015  // Other accounts are not affected
2016  env(noop(bob), queued);
2017  checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
2018 
2019  // Drain the queue and local transactions.
2020  env.close();
2021  checkMetrics(__LINE__, env, 0, 8, 5, 4, 256);
2022 
2023  // Show that the local transactions have flushed through as well.
2024  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
2025  env(noop(alice), ticket::use(tkt + 0), ter(tefNO_TICKET));
2026  env(noop(alice), ticket::use(tkt + 1), ter(tefNO_TICKET));
2027  env(noop(alice), ticket::use(tkt + 2), ter(tefNO_TICKET));
2028  tkt += 3;
2029  }
2030  {
2031  // Replace a lone non-blocking tx with a blocker.
2032 
2033  // Put just one entry in the TxQ.
2034  auto const aliceSeq = env.seq(alice);
2035  env(noop(alice), ticket::use(tkt + 0), queued);
2036 
2037  // Since there's an entry in the queue we cannot append a
2038  // blocker to the account's queue.
2039  env(regkey(alice, bob), fee(20), ter(telCAN_NOT_QUEUE_BLOCKS));
2040  env(regkey(alice, bob),
2041  ticket::use(tkt + 1),
2042  fee(20),
2044 
2045  // However we can _replace_ that lone entry with a blocker.
2046  env(regkey(alice, bob), ticket::use(tkt + 0), fee(20), queued);
2047 
2048  // Now that there's a blocker in the queue we can't append to
2049  // the queue.
2050  env(noop(alice), ter(telCAN_NOT_QUEUE_BLOCKED));
2051  env(noop(alice),
2052  ticket::use(tkt + 1),
2054 
2055  // Other accounts are unaffected.
2056  env(noop(bob), queued);
2057 
2058  // We can replace the blocker with a different blocker.
2059  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
2060  ticket::use(tkt + 0),
2061  fee(26),
2062  queued);
2063 
2064  // Prove that the queue is still blocked.
2065  env(noop(alice), ter(telCAN_NOT_QUEUE_BLOCKED));
2066  env(noop(alice),
2067  ticket::use(tkt + 1),
2069 
2070  // We can replace the blocker with a non-blocker. Then we can
2071  // successfully append to the queue.
2072  env(noop(alice), ticket::use(tkt + 0), fee(33), queued);
2073  env(noop(alice), ticket::use(tkt + 1), queued);
2074  env(noop(alice), seq(aliceSeq), queued);
2075 
2076  // Drain the queue.
2077  env.close();
2078  checkMetrics(__LINE__, env, 0, 10, 4, 5, 256);
2079 
2080  // Show that the local transactions have flushed through as well.
2081  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
2082  env(noop(alice), ticket::use(tkt + 0), ter(tefNO_TICKET));
2083  env(noop(alice), ticket::use(tkt + 1), ter(tefNO_TICKET));
2084  tkt += 2;
2085  }
2086  {
2087  // Put a blocker in an empty queue.
2088 
2089  // Fill up the open ledger and put a blocker as Alice's first
2090  // entry in the (empty) TxQ.
2091  env(noop(alice));
2092  env(noop(alice));
2093 
2094  env(fset(alice, asfAccountTxnID), ticket::use(tkt + 2), queued);
2095 
2096  // Since there's a blocker in the queue we can't append to
2097  // the queue.
2098  env(noop(alice),
2099  ticket::use(tkt + 1),
2101 
2102  // Other accounts are unaffected.
2103  env(noop(bob), queued);
2104 
2105  // We can replace the blocker with a non-blocker. Then we can
2106  // successfully append to the queue.
2107  env(noop(alice), ticket::use(tkt + 2), fee(20), queued);
2108  env(noop(alice), ticket::use(tkt + 1), queued);
2109 
2110  // Drain the queue.
2111  env.close();
2112  checkMetrics(__LINE__, env, 0, 12, 3, 6, 256);
2113  }
2114  }
2115 
2116  void
2118  {
2119  using namespace jtx;
2120  testcase("In-flight balance checks");
2121 
2122  Env env(
2123  *this,
2124  makeConfig(
2125  {{"minimum_txn_in_ledger_standalone", "3"}},
2126  {{"account_reserve", "200"}, {"owner_reserve", "50"}}));
2127 
2128  auto alice = Account("alice");
2129  auto charlie = Account("charlie");
2130  auto gw = Account("gw");
2131 
2132  auto queued = ter(terQUEUED);
2133 
2134  // Set the fee reserves _really_ low so transactions with fees
2135  // in the ballpark of the reserves can be queued. With default
2136  // reserves, a couple hundred transactions would have to be
2137  // queued before the open ledger fee approached the reserve,
2138  // which would unnecessarily slow down this test.
2139  // ledgers in queue is 2 because of makeConfig
2140  auto const initQueueMax = initFee(env, 3, 2, 10, 10, 200, 50);
2141 
2142  auto limit = 3;
2143 
2144  checkMetrics(__LINE__, env, 0, initQueueMax, 0, limit, 256);
2145 
2146  env.fund(XRP(50000), noripple(alice, charlie), gw);
2147  checkMetrics(__LINE__, env, 0, initQueueMax, limit + 1, limit, 256);
2148 
2149  auto USD = gw["USD"];
2150  auto BUX = gw["BUX"];
2151 
2153  // Offer with high XRP out and low fee doesn't block
2154  auto aliceSeq = env.seq(alice);
2155  auto aliceBal = env.balance(alice);
2156 
2157  env.require(balance(alice, XRP(50000)), owners(alice, 0));
2158 
2159  // If this offer crosses, all of alice's
2160  // XRP will be taken (except the reserve).
2161  env(offer(alice, BUX(5000), XRP(50000)), queued);
2162  checkMetrics(__LINE__, env, 1, initQueueMax, limit + 1, limit, 256);
2163 
2164  // But because the reserve is protected, another
2165  // transaction will be allowed to queue
2166  env(noop(alice), seq(aliceSeq + 1), queued);
2167  checkMetrics(__LINE__, env, 2, initQueueMax, limit + 1, limit, 256);
2168 
2169  env.close();
2170  ++limit;
2171  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2172 
2173  // But once we close the ledger, we find alice
2174  // has plenty of XRP, because the offer didn't
2175  // cross (of course).
2176  env.require(balance(alice, aliceBal - drops(20)), owners(alice, 1));
2177  // cancel the offer
2178  env(offer_cancel(alice, aliceSeq));
2179 
2181  // Offer with high XRP out and high total fee blocks later txs
2182  fillQueue(env, alice);
2183  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2184  aliceSeq = env.seq(alice);
2185  aliceBal = env.balance(alice);
2186 
2187  env.require(owners(alice, 0));
2188 
2189  // Alice creates an offer with a fee of half the reserve
2190  env(offer(alice, BUX(5000), XRP(50000)), fee(drops(100)), queued);
2191  checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2192 
2193  // Alice creates another offer with a fee
2194  // that brings the total to just shy of the reserve
2195  env(noop(alice), fee(drops(99)), seq(aliceSeq + 1), queued);
2196  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2197 
2198  // So even a noop will look like alice
2199  // doesn't have the balance to pay the fee
2200  env(noop(alice),
2201  fee(drops(51)),
2202  seq(aliceSeq + 2),
2203  ter(terINSUF_FEE_B));
2204  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2205 
2206  env.close();
2207  ++limit;
2208  checkMetrics(__LINE__, env, 0, limit * 2, 3, limit, 256);
2209 
2210  // But once we close the ledger, we find alice
2211  // has plenty of XRP, because the offer didn't
2212  // cross (of course).
2213  env.require(balance(alice, aliceBal - drops(250)), owners(alice, 1));
2214  // cancel the offer
2215  env(offer_cancel(alice, aliceSeq));
2216 
2218  // Offer with high XRP out and super high fee blocks later txs
2219  fillQueue(env, alice);
2220  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2221  aliceSeq = env.seq(alice);
2222  aliceBal = env.balance(alice);
2223 
2224  env.require(owners(alice, 0));
2225 
2226  // Alice creates an offer with a fee larger than the reserve
2227  // This one can queue because it's the first in the queue for alice
2228  env(offer(alice, BUX(5000), XRP(50000)), fee(drops(300)), queued);
2229  checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2230 
2231  // So even a noop will look like alice
2232  // doesn't have the balance to pay the fee
2233  env(noop(alice),
2234  fee(drops(51)),
2235  seq(aliceSeq + 1),
2237  checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2238 
2239  env.close();
2240  ++limit;
2241  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2242 
2243  // But once we close the ledger, we find alice
2244  // has plenty of XRP, because the offer didn't
2245  // cross (of course).
2246  env.require(balance(alice, aliceBal - drops(351)), owners(alice, 1));
2247  // cancel the offer
2248  env(offer_cancel(alice, aliceSeq));
2249 
2251  // Offer with low XRP out allows later txs
2252  fillQueue(env, alice);
2253  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2254  aliceSeq = env.seq(alice);
2255  aliceBal = env.balance(alice);
2256 
2257  // If this offer crosses, just a bit
2258  // of alice's XRP will be taken.
2259  env(offer(alice, BUX(50), XRP(500)), queued);
2260 
2261  // And later transactions are just fine
2262  env(noop(alice), seq(aliceSeq + 1), queued);
2263  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2264 
2265  env.close();
2266  ++limit;
2267  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2268 
2269  // But once we close the ledger, we find alice
2270  // has plenty of XRP, because the offer didn't
2271  // cross (of course).
2272  env.require(balance(alice, aliceBal - drops(20)), owners(alice, 1));
2273  // cancel the offer
2274  env(offer_cancel(alice, aliceSeq));
2275 
2277  // Large XRP payment doesn't block later txs
2278  fillQueue(env, alice);
2279  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2280 
2281  aliceSeq = env.seq(alice);
2282  aliceBal = env.balance(alice);
2283 
2284  // If this payment succeeds, alice will
2285  // send her entire balance to charlie
2286  // (minus the reserve).
2287  env(pay(alice, charlie, XRP(50000)), queued);
2288 
2289  // But because the reserve is protected, another
2290  // transaction will be allowed to queue
2291  env(noop(alice), seq(aliceSeq + 1), queued);
2292  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2293 
2294  env.close();
2295  ++limit;
2296  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2297 
2298  // But once we close the ledger, we find alice
2299  // still has most of her balance, because the
2300  // payment was unfunded!
2301  env.require(balance(alice, aliceBal - drops(20)), owners(alice, 0));
2302 
2304  // Small XRP payment allows later txs
2305  fillQueue(env, alice);
2306  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2307 
2308  aliceSeq = env.seq(alice);
2309  aliceBal = env.balance(alice);
2310 
2311  // If this payment succeeds, alice will
2312  // send just a bit of balance to charlie
2313  env(pay(alice, charlie, XRP(500)), queued);
2314 
2315  // And later transactions are just fine
2316  env(noop(alice), seq(aliceSeq + 1), queued);
2317  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2318 
2319  env.close();
2320  ++limit;
2321  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2322 
2323  // The payment succeeds
2324  env.require(
2325  balance(alice, aliceBal - XRP(500) - drops(20)), owners(alice, 0));
2326 
2328  // Large IOU payment allows later txs
2329  auto const amount = USD(500000);
2330  env(trust(alice, USD(50000000)));
2331  env(trust(charlie, USD(50000000)));
2332  checkMetrics(__LINE__, env, 0, limit * 2, 4, limit, 256);
2333  // Close so we don't have to deal
2334  // with tx ordering in consensus.
2335  env.close();
2336 
2337  env(pay(gw, alice, amount));
2338  checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2339  // Close so we don't have to deal
2340  // with tx ordering in consensus.
2341  env.close();
2342 
2343  fillQueue(env, alice);
2344  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2345 
2346  aliceSeq = env.seq(alice);
2347  aliceBal = env.balance(alice);
2348  auto aliceUSD = env.balance(alice, USD);
2349 
2350  // If this payment succeeds, alice will
2351  // send her entire USD balance to charlie.
2352  env(pay(alice, charlie, amount), queued);
2353 
2354  // But that's fine, because it doesn't affect
2355  // alice's XRP balance (other than the fee, of course).
2356  env(noop(alice), seq(aliceSeq + 1), queued);
2357  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2358 
2359  env.close();
2360  ++limit;
2361  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2362 
2363  // So once we close the ledger, alice has her
2364  // XRP balance, but her USD balance went to charlie.
2365  env.require(
2366  balance(alice, aliceBal - drops(20)),
2367  balance(alice, USD(0)),
2368  balance(charlie, aliceUSD),
2369  owners(alice, 1),
2370  owners(charlie, 1));
2371 
2373  // Large XRP to IOU payment doesn't block later txs.
2374 
2375  env(offer(gw, XRP(500000), USD(50000)));
2376  // Close so we don't have to deal
2377  // with tx ordering in consensus.
2378  env.close();
2379 
2380  fillQueue(env, charlie);
2381  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2382 
2383  aliceSeq = env.seq(alice);
2384  aliceBal = env.balance(alice);
2385  auto charlieUSD = env.balance(charlie, USD);
2386 
2387  // If this payment succeeds, and uses the
2388  // entire sendMax, alice will send her
2389  // entire XRP balance to charlie in the
2390  // form of USD.
2391  BEAST_EXPECT(XRP(60000) > aliceBal);
2392  env(pay(alice, charlie, USD(1000)), sendmax(XRP(60000)), queued);
2393 
2394  // But because the reserve is protected, another
2395  // transaction will be allowed to queue
2396  env(noop(alice), seq(aliceSeq + 1), queued);
2397  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2398 
2399  env.close();
2400  ++limit;
2401  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2402 
2403  // So once we close the ledger, alice sent a payment
2404  // to charlie using only a portion of her XRP balance
2405  env.require(
2406  balance(alice, aliceBal - XRP(10000) - drops(20)),
2407  balance(alice, USD(0)),
2408  balance(charlie, charlieUSD + USD(1000)),
2409  owners(alice, 1),
2410  owners(charlie, 1));
2411 
2413  // Small XRP to IOU payment allows later txs.
2414 
2415  fillQueue(env, charlie);
2416  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2417 
2418  aliceSeq = env.seq(alice);
2419  aliceBal = env.balance(alice);
2420  charlieUSD = env.balance(charlie, USD);
2421 
2422  // If this payment succeeds, and uses the
2423  // entire sendMax, alice will only send
2424  // a portion of her XRP balance to charlie
2425  // in the form of USD.
2426  BEAST_EXPECT(aliceBal > XRP(6001));
2427  env(pay(alice, charlie, USD(500)), sendmax(XRP(6000)), queued);
2428 
2429  // And later transactions are just fine
2430  env(noop(alice), seq(aliceSeq + 1), queued);
2431  checkMetrics(__LINE__, env, 2, limit * 2, limit + 1, limit, 256);
2432 
2433  env.close();
2434  ++limit;
2435  checkMetrics(__LINE__, env, 0, limit * 2, 2, limit, 256);
2436 
2437  // So once we close the ledger, alice sent a payment
2438  // to charlie using only a portion of her XRP balance
2439  env.require(
2440  balance(alice, aliceBal - XRP(5000) - drops(20)),
2441  balance(alice, USD(0)),
2442  balance(charlie, charlieUSD + USD(500)),
2443  owners(alice, 1),
2444  owners(charlie, 1));
2445 
2447  // Edge case: what happens if the balance is below the reserve?
2448  env(noop(alice), fee(env.balance(alice) - drops(30)));
2449  env.close();
2450 
2451  fillQueue(env, charlie);
2452  checkMetrics(__LINE__, env, 0, limit * 2, limit + 1, limit, 256);
2453 
2454  aliceSeq = env.seq(alice);
2455  aliceBal = env.balance(alice);
2456  BEAST_EXPECT(aliceBal == drops(30));
2457 
2458  env(noop(alice), fee(drops(25)), queued);
2459  env(noop(alice), seq(aliceSeq + 1), ter(terINSUF_FEE_B));
2460  BEAST_EXPECT(env.balance(alice) == drops(30));
2461 
2462  checkMetrics(__LINE__, env, 1, limit * 2, limit + 1, limit, 256);
2463 
2464  env.close();
2465  ++limit;
2466  checkMetrics(__LINE__, env, 0, limit * 2, 1, limit, 256);
2467  BEAST_EXPECT(env.balance(alice) == drops(5));
2468  }
2469 
2470  void
2472  {
2473  using namespace jtx;
2474  using namespace std::chrono;
2475  testcase("consequences");
2476 
2477  Env env(*this);
2478  auto const alice = Account("alice");
2479  env.memoize(alice);
2480  env.memoize("bob");
2481  env.memoize("carol");
2482  {
2483  auto const jtx = env.jt(offer_cancel(alice, 3), seq(5), fee(10));
2484  auto const pf = preflight(
2485  env.app(),
2486  env.current()->rules(),
2487  *jtx.stx,
2488  tapNONE,
2489  env.journal);
2490  BEAST_EXPECT(pf.ter == tesSUCCESS);
2491  BEAST_EXPECT(!pf.consequences.isBlocker());
2492  BEAST_EXPECT(pf.consequences.fee() == drops(10));
2493  BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
2494  }
2495 
2496  {
2497  auto USD = alice["USD"];
2498 
2499  auto const jtx =
2500  env.jt(trust("carol", USD(50000000)), seq(1), fee(10));
2501  auto const pf = preflight(
2502  env.app(),
2503  env.current()->rules(),
2504  *jtx.stx,
2505  tapNONE,
2506  env.journal);
2507  BEAST_EXPECT(pf.ter == tesSUCCESS);
2508  BEAST_EXPECT(!pf.consequences.isBlocker());
2509  BEAST_EXPECT(pf.consequences.fee() == drops(10));
2510  BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
2511  }
2512 
2513  {
2514  auto const jtx = env.jt(ticket::create(alice, 1), seq(1), fee(10));
2515  auto const pf = preflight(
2516  env.app(),
2517  env.current()->rules(),
2518  *jtx.stx,
2519  tapNONE,
2520  env.journal);
2521  BEAST_EXPECT(pf.ter == tesSUCCESS);
2522  BEAST_EXPECT(!pf.consequences.isBlocker());
2523  BEAST_EXPECT(pf.consequences.fee() == drops(10));
2524  BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
2525  }
2526  }
2527 
2528  void
2530  {
2531  // It is possible for an account to be present in the queue but have
2532  // no queued transactions. This has been the source of at least one
2533  // bug where an insufficiently informed developer assumed that if an
2534  // account was present in the queue then it also had at least one
2535  // queued transaction.
2536  //
2537  // This test does touch testing to verify that, at least, that bug
2538  // is addressed.
2539  using namespace jtx;
2540  testcase("acct in queue but empty");
2541 
2542  auto alice = Account("alice");
2543  auto bob = Account("bob");
2544  auto charlie = Account("charlie");
2545 
2546  auto queued = ter(terQUEUED);
2547 
2548  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
2549 
2550  BEAST_EXPECT(env.current()->fees().base == 10);
2551 
2552  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
2553 
2554  // Fund accounts while the fee is cheap so they all apply.
2555  env.fund(XRP(50000), noripple(alice, bob, charlie));
2556  checkMetrics(__LINE__, env, 0, std::nullopt, 3, 3, 256);
2557 
2558  // Alice - no fee change yet
2559  env(noop(alice));
2560  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
2561 
2562  // Bob with really high fee - applies
2563  env(noop(bob), openLedgerFee(env));
2564  checkMetrics(__LINE__, env, 0, std::nullopt, 5, 3, 256);
2565 
2566  // Charlie with low fee: queued
2567  env(noop(charlie), fee(1000), queued);
2568  checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
2569 
2570  env.close();
2571  // Verify that the queued transaction was applied
2572  checkMetrics(__LINE__, env, 0, 10, 1, 5, 256);
2573 
2575 
2576  // Stuff the ledger and queue so we can verify that
2577  // stuff gets kicked out.
2578  env(noop(bob), fee(1000));
2579  env(noop(bob), fee(1000));
2580  env(noop(bob), fee(1000));
2581  env(noop(bob), fee(1000));
2582  env(noop(bob), fee(1000));
2583  checkMetrics(__LINE__, env, 0, 10, 6, 5, 256);
2584 
2585  // Use explicit fees so we can control which txn
2586  // will get dropped
2587  // This one gets into the queue, but gets dropped when the
2588  // higher fee one is added later.
2589  std::uint32_t const charlieSeq{env.seq(charlie)};
2590  env(noop(charlie), fee(15), seq(charlieSeq), queued);
2591 
2592  // These stay in the queue.
2593  std::uint32_t aliceSeq{env.seq(alice)};
2594  std::uint32_t bobSeq{env.seq(bob)};
2595 
2596  env(noop(alice), fee(16), seq(aliceSeq++), queued);
2597  env(noop(bob), fee(16), seq(bobSeq++), queued);
2598  env(noop(alice), fee(17), seq(aliceSeq++), queued);
2599  env(noop(bob), fee(17), seq(bobSeq++), queued);
2600  env(noop(alice), fee(18), seq(aliceSeq++), queued);
2601  env(noop(bob), fee(19), seq(bobSeq++), queued);
2602  env(noop(alice), fee(20), seq(aliceSeq++), queued);
2603  env(noop(bob), fee(20), seq(bobSeq++), queued);
2604  env(noop(alice), fee(21), seq(aliceSeq++), queued);
2605 
2606  // Queue is full now.
2607  checkMetrics(__LINE__, env, 10, 10, 6, 5, 385);
2608 
2609  // Try to add another transaction with the default (low) fee,
2610  // it should fail because the queue is full.
2611  env(noop(alice), seq(aliceSeq++), ter(telCAN_NOT_QUEUE_FULL));
2612 
2613  // Add another transaction, with a higher fee,
2614  // not high enough to get into the ledger, but high
2615  // enough to get into the queue (and kick Charlie's out)
2616  env(noop(bob), fee(22), seq(bobSeq++), queued);
2617 
2619 
2620  // That was the setup for the actual test :-). Now make
2621  // sure we get the right results if we try to add a
2622  // transaction for Charlie (who's in the queue, but has no queued
2623  // transactions) with the wrong sequence numbers.
2624  //
2625  // Charlie is paying a high enough fee to go straight into the
2626  // ledger in order to get into the vicinity of an assert which
2627  // should no longer fire :-).
2628  env(noop(charlie), fee(8000), seq(charlieSeq - 1), ter(tefPAST_SEQ));
2629  env(noop(charlie), fee(8000), seq(charlieSeq + 1), ter(terPRE_SEQ));
2630  env(noop(charlie), fee(8000), seq(charlieSeq), ter(tesSUCCESS));
2631  }
2632 
2633  void
2635  {
2636  using namespace jtx;
2637  testcase("rpc");
2638 
2639  Env env(*this);
2640 
2641  auto fee = env.rpc("fee");
2642 
2643  if (BEAST_EXPECT(fee.isMember(jss::result)) &&
2644  BEAST_EXPECT(!RPC::contains_error(fee[jss::result])))
2645  {
2646  auto const& result = fee[jss::result];
2647  BEAST_EXPECT(
2648  result.isMember(jss::ledger_current_index) &&
2649  result[jss::ledger_current_index] == 3);
2650  BEAST_EXPECT(result.isMember(jss::current_ledger_size));
2651  BEAST_EXPECT(result.isMember(jss::current_queue_size));
2652  BEAST_EXPECT(result.isMember(jss::expected_ledger_size));
2653  BEAST_EXPECT(!result.isMember(jss::max_queue_size));
2654  BEAST_EXPECT(result.isMember(jss::drops));
2655  auto const& drops = result[jss::drops];
2656  BEAST_EXPECT(drops.isMember(jss::base_fee));
2657  BEAST_EXPECT(drops.isMember(jss::median_fee));
2658  BEAST_EXPECT(drops.isMember(jss::minimum_fee));
2659  BEAST_EXPECT(drops.isMember(jss::open_ledger_fee));
2660  BEAST_EXPECT(result.isMember(jss::levels));
2661  auto const& levels = result[jss::levels];
2662  BEAST_EXPECT(levels.isMember(jss::median_level));
2663  BEAST_EXPECT(levels.isMember(jss::minimum_level));
2664  BEAST_EXPECT(levels.isMember(jss::open_ledger_level));
2665  BEAST_EXPECT(levels.isMember(jss::reference_level));
2666  }
2667 
2668  env.close();
2669 
2670  fee = env.rpc("fee");
2671 
2672  if (BEAST_EXPECT(fee.isMember(jss::result)) &&
2673  BEAST_EXPECT(!RPC::contains_error(fee[jss::result])))
2674  {
2675  auto const& result = fee[jss::result];
2676  BEAST_EXPECT(
2677  result.isMember(jss::ledger_current_index) &&
2678  result[jss::ledger_current_index] == 4);
2679  BEAST_EXPECT(result.isMember(jss::current_ledger_size));
2680  BEAST_EXPECT(result.isMember(jss::current_queue_size));
2681  BEAST_EXPECT(result.isMember(jss::expected_ledger_size));
2682  BEAST_EXPECT(result.isMember(jss::max_queue_size));
2683  auto const& drops = result[jss::drops];
2684  BEAST_EXPECT(drops.isMember(jss::base_fee));
2685  BEAST_EXPECT(drops.isMember(jss::median_fee));
2686  BEAST_EXPECT(drops.isMember(jss::minimum_fee));
2687  BEAST_EXPECT(drops.isMember(jss::open_ledger_fee));
2688  BEAST_EXPECT(result.isMember(jss::levels));
2689  auto const& levels = result[jss::levels];
2690  BEAST_EXPECT(levels.isMember(jss::median_level));
2691  BEAST_EXPECT(levels.isMember(jss::minimum_level));
2692  BEAST_EXPECT(levels.isMember(jss::open_ledger_level));
2693  BEAST_EXPECT(levels.isMember(jss::reference_level));
2694  }
2695  }
2696 
2697  void
2699  {
2700  /* This test is based on a reported regression where a
2701  replacement candidate transaction found the tx it was trying
2702  to replace did not have `consequences` set
2703 
2704  Hypothesis: The queue had '22 through '25. At some point(s),
2705  both the original '22 and '23 expired and were removed from
2706  the queue. A second '22 was submitted, and the multi-tx logic
2707  did not kick in, because it matched the account's sequence
2708  number (a_seq == t_seq). The third '22 was submitted and found
2709  the '22 in the queue did not have consequences.
2710  */
2711  using namespace jtx;
2712  testcase("expiration replacement");
2713 
2714  Env env(
2715  *this,
2716  makeConfig(
2717  {{"minimum_txn_in_ledger_standalone", "1"},
2718  {"ledgers_in_queue", "10"},
2719  {"maximum_txn_per_account", "20"}}));
2720 
2721  // Alice will recreate the scenario. Bob will block.
2722  auto const alice = Account("alice");
2723  auto const bob = Account("bob");
2724 
2725  env.fund(XRP(500000), noripple(alice, bob));
2726  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2727 
2728  auto const aliceSeq = env.seq(alice);
2729  BEAST_EXPECT(env.current()->info().seq == 3);
2730  env(noop(alice),
2731  seq(aliceSeq),
2732  json(R"({"LastLedgerSequence":5})"),
2733  ter(terQUEUED));
2734  env(noop(alice),
2735  seq(aliceSeq + 1),
2736  json(R"({"LastLedgerSequence":5})"),
2737  ter(terQUEUED));
2738  env(noop(alice),
2739  seq(aliceSeq + 2),
2740  json(R"({"LastLedgerSequence":10})"),
2741  ter(terQUEUED));
2742  env(noop(alice),
2743  seq(aliceSeq + 3),
2744  json(R"({"LastLedgerSequence":11})"),
2745  ter(terQUEUED));
2746  checkMetrics(__LINE__, env, 4, std::nullopt, 2, 1, 256);
2747  auto const bobSeq = env.seq(bob);
2748  // Ledger 4 gets 3,
2749  // Ledger 5 gets 4,
2750  // Ledger 6 gets 5.
2751  for (int i = 0; i < 3 + 4 + 5; ++i)
2752  {
2753  env(noop(bob), seq(bobSeq + i), fee(200), ter(terQUEUED));
2754  }
2755  checkMetrics(__LINE__, env, 4 + 3 + 4 + 5, std::nullopt, 2, 1, 256);
2756  // Close ledger 3
2757  env.close();
2758  checkMetrics(__LINE__, env, 4 + 4 + 5, 20, 3, 2, 256);
2759  // Close ledger 4
2760  env.close();
2761  checkMetrics(__LINE__, env, 4 + 5, 30, 4, 3, 256);
2762  // Close ledger 5
2763  env.close();
2764  // Alice's first two txs expired.
2765  checkMetrics(__LINE__, env, 2, 40, 5, 4, 256);
2766 
2767  // Because aliceSeq is missing, aliceSeq + 1 fails
2768  env(noop(alice), seq(aliceSeq + 1), ter(terPRE_SEQ));
2769 
2770  // Cannot fill the gap with a blocker since Alice's queue is not empty.
2771  env(fset(alice, asfAccountTxnID),
2772  seq(aliceSeq),
2774  checkMetrics(__LINE__, env, 2, 40, 5, 4, 256);
2775 
2776  // However we can fill the gap with a non-blocker.
2777  env(noop(alice), seq(aliceSeq), fee(20), ter(terQUEUED));
2778  checkMetrics(__LINE__, env, 3, 40, 5, 4, 256);
2779 
2780  // Attempt to queue up a new aliceSeq + 1 tx that's a blocker.
2781  env(fset(alice, asfAccountTxnID),
2782  seq(aliceSeq + 1),
2784  checkMetrics(__LINE__, env, 3, 40, 5, 4, 256);
2785 
2786  // Queue up a non-blocker replacement for aliceSeq + 1.
2787  env(noop(alice), seq(aliceSeq + 1), fee(20), ter(terQUEUED));
2788  checkMetrics(__LINE__, env, 4, 40, 5, 4, 256);
2789 
2790  // Close ledger 6
2791  env.close();
2792  // We expect that all of alice's queued tx's got into
2793  // the open ledger.
2794  checkMetrics(__LINE__, env, 0, 50, 4, 5, 256);
2795  BEAST_EXPECT(env.seq(alice) == aliceSeq + 4);
2796  }
2797 
2798  void
2800  {
2801  // This test focuses on which gaps in queued transactions are
2802  // allowed to be filled even when the account's queue is full.
2803  using namespace jtx;
2804  testcase("full queue gap handling");
2805 
2806  Env env(
2807  *this,
2808  makeConfig(
2809  {{"minimum_txn_in_ledger_standalone", "1"},
2810  {"ledgers_in_queue", "10"},
2811  {"maximum_txn_per_account", "11"}}));
2812 
2813  // Alice will have the gaps. Bob will keep the queue busy with
2814  // high fee transactions so alice's transactions can expire to leave
2815  // gaps.
2816  auto const alice = Account("alice");
2817  auto const bob = Account("bob");
2818 
2819  env.fund(XRP(500000), noripple(alice, bob));
2820  checkMetrics(__LINE__, env, 0, std::nullopt, 2, 1, 256);
2821 
2822  auto const aliceSeq = env.seq(alice);
2823  BEAST_EXPECT(env.current()->info().seq == 3);
2824 
2825  // Start by procuring tickets for alice to use to keep her queue full
2826  // without affecting the sequence gap that will appear later.
2827  env(ticket::create(alice, 11),
2828  seq(aliceSeq + 0),
2829  fee(201),
2830  ter(terQUEUED));
2831  env(noop(alice),
2832  seq(aliceSeq + 11),
2833  json(R"({"LastLedgerSequence":11})"),
2834  ter(terQUEUED));
2835  env(noop(alice),
2836  seq(aliceSeq + 12),
2837  json(R"({"LastLedgerSequence":11})"),
2838  ter(terQUEUED));
2839  env(noop(alice),
2840  seq(aliceSeq + 13),
2841  json(R"({"LastLedgerSequence":11})"),
2842  ter(terQUEUED));
2843  env(noop(alice),
2844  seq(aliceSeq + 14),
2845  json(R"({"LastLedgerSequence":11})"),
2846  ter(terQUEUED));
2847  env(noop(alice),
2848  seq(aliceSeq + 15),
2849  json(R"({"LastLedgerSequence":11})"),
2850  ter(terQUEUED));
2851  env(noop(alice),
2852  seq(aliceSeq + 16),
2853  json(R"({"LastLedgerSequence": 5})"),
2854  ter(terQUEUED));
2855  env(noop(alice),
2856  seq(aliceSeq + 17),
2857  json(R"({"LastLedgerSequence": 5})"),
2858  ter(terQUEUED));
2859  env(noop(alice),
2860  seq(aliceSeq + 18),
2861  json(R"({"LastLedgerSequence": 5})"),
2862  ter(terQUEUED));
2863  env(noop(alice),
2864  seq(aliceSeq + 19),
2865  json(R"({"LastLedgerSequence":11})"),
2866  ter(terQUEUED));
2867  checkMetrics(__LINE__, env, 10, std::nullopt, 2, 1, 256);
2868 
2869  auto const bobSeq = env.seq(bob);
2870  // Ledger 4 gets 2 from bob and 1 from alice,
2871  // Ledger 5 gets 4 from bob,
2872  // Ledger 6 gets 5 from bob.
2873  for (int i = 0; i < 2 + 4 + 5; ++i)
2874  {
2875  env(noop(bob), seq(bobSeq + i), fee(200), ter(terQUEUED));
2876  }
2877  checkMetrics(__LINE__, env, 10 + 2 + 4 + 5, std::nullopt, 2, 1, 256);
2878  // Close ledger 3
2879  env.close();
2880  checkMetrics(__LINE__, env, 9 + 4 + 5, 20, 3, 2, 256);
2881  BEAST_EXPECT(env.seq(alice) == aliceSeq + 12);
2882 
2883  // Close ledger 4
2884  env.close();
2885  checkMetrics(__LINE__, env, 9 + 5, 30, 4, 3, 256);
2886  BEAST_EXPECT(env.seq(alice) == aliceSeq + 12);
2887 
2888  // Close ledger 5
2889  env.close();
2890  // Three of Alice's txs expired.
2891  checkMetrics(__LINE__, env, 6, 40, 5, 4, 256);
2892  BEAST_EXPECT(env.seq(alice) == aliceSeq + 12);
2893 
2894  // Top off Alice's queue again using Tickets so the sequence gap is
2895  // unaffected.
2896  env(noop(alice), ticket::use(aliceSeq + 1), ter(terQUEUED));
2897  env(noop(alice), ticket::use(aliceSeq + 2), ter(terQUEUED));
2898  env(noop(alice), ticket::use(aliceSeq + 3), ter(terQUEUED));
2899  env(noop(alice), ticket::use(aliceSeq + 4), ter(terQUEUED));
2900  env(noop(alice), ticket::use(aliceSeq + 5), ter(terQUEUED));
2901  env(noop(alice), ticket::use(aliceSeq + 6), ter(telCAN_NOT_QUEUE_FULL));
2902  checkMetrics(__LINE__, env, 11, 40, 5, 4, 256);
2903 
2904  // Even though alice's queue is full we can still slide in a couple
2905  // more transactions because she has a sequence gap. But we
2906  // can only install a transaction that fills the bottom of the gap.
2907  // Explore that...
2908 
2909  // Verify that we can't queue a sequence-based transaction that
2910  // follows a gap.
2911  env(noop(alice), seq(aliceSeq + 20), ter(telCAN_NOT_QUEUE_FULL));
2912 
2913  // Verify that the transaction in front of the gap is still present
2914  // by attempting to replace it without a sufficient fee.
2915  env(noop(alice), seq(aliceSeq + 15), ter(telCAN_NOT_QUEUE_FEE));
2916 
2917  // We can't queue a transaction into the middle of the gap. It must
2918  // go at the front.
2919  env(noop(alice), seq(aliceSeq + 18), ter(telCAN_NOT_QUEUE_FULL));
2920  env(noop(alice), seq(aliceSeq + 17), ter(telCAN_NOT_QUEUE_FULL));
2921 
2922  // Successfully put this transaction into the front of the gap.
2923  env(noop(alice), seq(aliceSeq + 16), ter(terQUEUED));
2924 
2925  // Still can't put a sequence-based transaction at the end of the gap.
2926  env(noop(alice), seq(aliceSeq + 18), ter(telCAN_NOT_QUEUE_FULL));
2927 
2928  // But we can still fill the gap from the front.
2929  env(noop(alice), seq(aliceSeq + 17), ter(terQUEUED));
2930 
2931  // Finally we can fill in the entire gap.
2932  env(noop(alice), seq(aliceSeq + 18), ter(terQUEUED));
2933  checkMetrics(__LINE__, env, 14, 40, 5, 4, 256);
2934 
2935  // Verify that nothing can be added now that the gap is filled.
2936  env(noop(alice), seq(aliceSeq + 20), ter(telCAN_NOT_QUEUE_FULL));
2937 
2938  // Close ledger 6. That removes 6 of alice's transactions,
2939  // but alice adds one more transaction at seq(aliceSeq + 20) so
2940  // we only see a reduction by 5.
2941  env.close();
2942  checkMetrics(__LINE__, env, 9, 50, 6, 5, 256);
2943  BEAST_EXPECT(env.seq(alice) == aliceSeq + 15);
2944 
2945  // Close ledger 7. That should remove 7 more of alice's transactions.
2946  env.close();
2947  checkMetrics(__LINE__, env, 2, 60, 7, 6, 256);
2948  BEAST_EXPECT(env.seq(alice) == aliceSeq + 19);
2949 
2950  // Close one last ledger to see all of alice's transactions moved
2951  // into the ledger, including the tickets
2952  env.close();
2953  checkMetrics(__LINE__, env, 0, 70, 2, 7, 256);
2954  BEAST_EXPECT(env.seq(alice) == aliceSeq + 21);
2955  }
2956 
2957  void
2959  {
2960  testcase("Autofilled sequence should account for TxQ");
2961  using namespace jtx;
2962  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "6"}}));
2963  Env_ss envs(env);
2964  auto const& txQ = env.app().getTxQ();
2965 
2966  auto const alice = Account("alice");
2967  auto const bob = Account("bob");
2968  env.fund(XRP(100000), alice, bob);
2969 
2970  fillQueue(env, alice);
2971  checkMetrics(__LINE__, env, 0, std::nullopt, 7, 6, 256);
2972 
2973  // Queue up several transactions for alice sign-and-submit
2974  auto const aliceSeq = env.seq(alice);
2975  auto const lastLedgerSeq = env.current()->info().seq + 2;
2976 
2978  for (int i = 0; i < 5; ++i)
2979  {
2980  if (i == 2)
2981  envs(
2982  noop(alice),
2983  fee(1000),
2984  seq(none),
2985  json(jss::LastLedgerSequence, lastLedgerSeq),
2987  else
2988  envs(noop(alice), fee(1000), seq(none), ter(terQUEUED))(
2989  submitParams);
2990  }
2991  checkMetrics(__LINE__, env, 5, std::nullopt, 7, 6, 256);
2992  {
2993  auto aliceStat = txQ.getAccountTxs(alice.id());
2994  SeqProxy seq = SeqProxy::sequence(aliceSeq);
2995  BEAST_EXPECT(aliceStat.size() == 5);
2996  for (auto const& tx : aliceStat)
2997  {
2998  BEAST_EXPECT(tx.seqProxy == seq);
2999  BEAST_EXPECT(tx.feeLevel == FeeLevel64{25600});
3000  if (seq.value() == aliceSeq + 2)
3001  {
3002  BEAST_EXPECT(
3003  tx.lastValid && *tx.lastValid == lastLedgerSeq);
3004  }
3005  else
3006  {
3007  BEAST_EXPECT(!tx.lastValid);
3008  }
3009  seq.advanceBy(1);
3010  }
3011  }
3012  // Put some txs in the queue for bob.
3013  // Give them a higher fee so they'll beat alice's.
3014  for (int i = 0; i < 8; ++i)
3015  envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
3016  checkMetrics(__LINE__, env, 13, std::nullopt, 7, 6, 256);
3017 
3018  env.close();
3019  checkMetrics(__LINE__, env, 5, 14, 8, 7, 256);
3020  // Put some more txs in the queue for bob.
3021  // Give them a higher fee so they'll beat alice's.
3022  fillQueue(env, bob);
3023  for (int i = 0; i < 9; ++i)
3024  envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
3025  checkMetrics(__LINE__, env, 14, 14, 8, 7, 25601);
3026  env.close();
3027  // Put some more txs in the queue for bob.
3028  // Give them a higher fee so they'll beat alice's.
3029  fillQueue(env, bob);
3030  for (int i = 0; i < 10; ++i)
3031  envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
3032  checkMetrics(__LINE__, env, 15, 16, 9, 8, 256);
3033  env.close();
3034  checkMetrics(__LINE__, env, 4, 18, 10, 9, 256);
3035  {
3036  // Bob has nothing left in the queue.
3037  auto bobStat = txQ.getAccountTxs(bob.id());
3038  BEAST_EXPECT(bobStat.empty());
3039  }
3040  // Verify alice's tx got dropped as we BEAST_EXPECT, and that there's
3041  // a gap in her queued txs.
3042  {
3043  auto aliceStat = txQ.getAccountTxs(alice.id());
3044  auto seq = aliceSeq;
3045  BEAST_EXPECT(aliceStat.size() == 4);
3046  for (auto const& tx : aliceStat)
3047  {
3048  // Skip over the missing one.
3049  if (seq == aliceSeq + 2)
3050  ++seq;
3051 
3052  BEAST_EXPECT(tx.seqProxy.isSeq() && tx.seqProxy.value() == seq);
3053  BEAST_EXPECT(tx.feeLevel == FeeLevel64{25600});
3054  BEAST_EXPECT(!tx.lastValid);
3055  ++seq;
3056  }
3057  }
3058  // Now, fill the gap.
3059  envs(noop(alice), fee(1000), seq(none), ter(terQUEUED))(submitParams);
3060  checkMetrics(__LINE__, env, 5, 18, 10, 9, 256);
3061  {
3062  auto aliceStat = txQ.getAccountTxs(alice.id());
3063  auto seq = aliceSeq;
3064  BEAST_EXPECT(aliceStat.size() == 5);
3065  for (auto const& tx : aliceStat)
3066  {
3067  BEAST_EXPECT(tx.seqProxy.isSeq() && tx.seqProxy.value() == seq);
3068  BEAST_EXPECT(tx.feeLevel == FeeLevel64{25600});
3069  BEAST_EXPECT(!tx.lastValid);
3070  ++seq;
3071  }
3072  }
3073 
3074  env.close();
3075  checkMetrics(__LINE__, env, 0, 20, 5, 10, 256);
3076  {
3077  // Bob's data has been cleaned up.
3078  auto bobStat = txQ.getAccountTxs(bob.id());
3079  BEAST_EXPECT(bobStat.empty());
3080  }
3081  {
3082  auto aliceStat = txQ.getAccountTxs(alice.id());
3083  BEAST_EXPECT(aliceStat.empty());
3084  }
3085  }
3086 
3087  void
3089  {
3090  using namespace jtx;
3091  testcase("account info");
3092 
3093  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
3094  Env_ss envs(env);
3095 
3096  Account const alice{"alice"};
3097  env.fund(XRP(1000000), alice);
3098  env.close();
3099 
3100  auto const withQueue =
3101  R"({ "account": ")" + alice.human() + R"(", "queue": true })";
3102  auto const withoutQueue = R"({ "account": ")" + alice.human() + R"("})";
3103  auto const prevLedgerWithQueue = R"({ "account": ")" + alice.human() +
3104  R"(", "queue": true, "ledger_index": 3 })";
3105  BEAST_EXPECT(env.current()->info().seq > 3);
3106 
3107  {
3108  // account_info without the "queue" argument.
3109  auto const info = env.rpc("json", "account_info", withoutQueue);
3110  BEAST_EXPECT(
3111  info.isMember(jss::result) &&
3112  info[jss::result].isMember(jss::account_data));
3113  BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data));
3114  }
3115  {
3116  // account_info with the "queue" argument.
3117  auto const info = env.rpc("json", "account_info", withQueue);
3118  BEAST_EXPECT(
3119  info.isMember(jss::result) &&
3120  info[jss::result].isMember(jss::account_data));
3121  auto const& result = info[jss::result];
3122  BEAST_EXPECT(result.isMember(jss::queue_data));
3123  auto const& queue_data = result[jss::queue_data];
3124  BEAST_EXPECT(queue_data.isObject());
3125  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
3126  BEAST_EXPECT(queue_data[jss::txn_count] == 0);
3127  BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
3128  BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
3129  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
3130  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
3131  BEAST_EXPECT(!queue_data.isMember(jss::transactions));
3132  }
3133  checkMetrics(__LINE__, env, 0, 6, 0, 3, 256);
3134 
3135  fillQueue(env, alice);
3136  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
3137 
3138  {
3139  auto const info = env.rpc("json", "account_info", withQueue);
3140  BEAST_EXPECT(
3141  info.isMember(jss::result) &&
3142  info[jss::result].isMember(jss::account_data));
3143  auto const& result = info[jss::result];
3144  BEAST_EXPECT(result.isMember(jss::queue_data));
3145  auto const& queue_data = result[jss::queue_data];
3146  BEAST_EXPECT(queue_data.isObject());
3147  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
3148  BEAST_EXPECT(queue_data[jss::txn_count] == 0);
3149  BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
3150  BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
3151  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
3152  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
3153  BEAST_EXPECT(!queue_data.isMember(jss::transactions));
3154  }
3155 
3157  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
3158  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
3159  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
3160  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
3161  checkMetrics(__LINE__, env, 4, 6, 4, 3, 256);
3162 
3163  {
3164  auto const info = env.rpc("json", "account_info", withQueue);
3165  BEAST_EXPECT(
3166  info.isMember(jss::result) &&
3167  info[jss::result].isMember(jss::account_data));
3168  auto const& result = info[jss::result];
3169  auto const& data = result[jss::account_data];
3170  BEAST_EXPECT(result.isMember(jss::queue_data));
3171  auto const& queue_data = result[jss::queue_data];
3172  BEAST_EXPECT(queue_data.isObject());
3173  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
3174  BEAST_EXPECT(queue_data[jss::txn_count] == 4);
3175  BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
3176  BEAST_EXPECT(
3177  queue_data[jss::lowest_sequence] == data[jss::Sequence]);
3178  BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
3179  BEAST_EXPECT(
3180  queue_data[jss::highest_sequence] ==
3181  data[jss::Sequence].asUInt() +
3182  queue_data[jss::txn_count].asUInt() - 1);
3183  BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued));
3184  BEAST_EXPECT(queue_data[jss::auth_change_queued] == false);
3185  BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total));
3186  BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == "400");
3187  BEAST_EXPECT(queue_data.isMember(jss::transactions));
3188  auto const& queued = queue_data[jss::transactions];
3189  BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
3190  for (unsigned i = 0; i < queued.size(); ++i)
3191  {
3192  auto const& item = queued[i];
3193  BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
3194  BEAST_EXPECT(item[jss::fee_level] == "2560");
3195  BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
3196 
3197  BEAST_EXPECT(item.isMember(jss::fee));
3198  BEAST_EXPECT(item[jss::fee] == "100");
3199  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
3200  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
3201  BEAST_EXPECT(item.isMember(jss::auth_change));
3202  BEAST_EXPECT(item[jss::auth_change].asBool() == false);
3203  }
3204  }
3205 
3206  // Drain the queue so we can queue up a blocker.
3207  env.close();
3208  checkMetrics(__LINE__, env, 0, 8, 4, 4, 256);
3209 
3210  // Fill the ledger and then queue up a blocker.
3211  envs(noop(alice), seq(none))(submitParams);
3212 
3213  envs(
3214  fset(alice, asfAccountTxnID),
3215  fee(100),
3216  seq(none),
3217  json(jss::LastLedgerSequence, 10),
3218  ter(terQUEUED))(submitParams);
3219  checkMetrics(__LINE__, env, 1, 8, 5, 4, 256);
3220 
3221  {
3222  auto const info = env.rpc("json", "account_info", withQueue);
3223  BEAST_EXPECT(
3224  info.isMember(jss::result) &&
3225  info[jss::result].isMember(jss::account_data));
3226  auto const& result = info[jss::result];
3227  auto const& data = result[jss::account_data];
3228  BEAST_EXPECT(result.isMember(jss::queue_data));
3229  auto const& queue_data = result[jss::queue_data];
3230  BEAST_EXPECT(queue_data.isObject());
3231  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
3232  BEAST_EXPECT(queue_data[jss::txn_count] == 1);
3233  BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
3234  BEAST_EXPECT(
3235  queue_data[jss::lowest_sequence] == data[jss::Sequence]);
3236  BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
3237  BEAST_EXPECT(
3238  queue_data[jss::highest_sequence] ==
3239  data[jss::Sequence].asUInt() +
3240  queue_data[jss::txn_count].asUInt() - 1);
3241  BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued));
3242  BEAST_EXPECT(queue_data[jss::auth_change_queued] == true);
3243  BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total));
3244  BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == "100");
3245  BEAST_EXPECT(queue_data.isMember(jss::transactions));
3246  auto const& queued = queue_data[jss::transactions];
3247  BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
3248  for (unsigned i = 0; i < queued.size(); ++i)
3249  {
3250  auto const& item = queued[i];
3251  BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
3252  BEAST_EXPECT(item[jss::fee_level] == "2560");
3253  BEAST_EXPECT(item.isMember(jss::fee));
3254  BEAST_EXPECT(item[jss::fee] == "100");
3255  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
3256  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
3257  BEAST_EXPECT(item.isMember(jss::auth_change));
3258 
3259  if (i == queued.size() - 1)
3260  {
3261  BEAST_EXPECT(item[jss::auth_change].asBool() == true);
3262  BEAST_EXPECT(item.isMember(jss::LastLedgerSequence));
3263  BEAST_EXPECT(item[jss::LastLedgerSequence] == 10);
3264  }
3265  else
3266  {
3267  BEAST_EXPECT(item[jss::auth_change].asBool() == false);
3268  BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
3269  }
3270  }
3271  }
3272 
3273  envs(noop(alice), fee(100), seq(none), ter(telCAN_NOT_QUEUE_BLOCKED))(
3274  submitParams);
3275  checkMetrics(__LINE__, env, 1, 8, 5, 4, 256);
3276 
3277  {
3278  auto const info = env.rpc("json", "account_info", withQueue);
3279  BEAST_EXPECT(
3280  info.isMember(jss::result) &&
3281  info[jss::result].isMember(jss::account_data));
3282  auto const& result = info[jss::result];
3283  auto const& data = result[jss::account_data];
3284  BEAST_EXPECT(result.isMember(jss::queue_data));
3285  auto const& queue_data = result[jss::queue_data];
3286  BEAST_EXPECT(queue_data.isObject());
3287  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
3288  BEAST_EXPECT(queue_data[jss::txn_count] == 1);
3289  BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
3290  BEAST_EXPECT(
3291  queue_data[jss::lowest_sequence] == data[jss::Sequence]);
3292  BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
3293  BEAST_EXPECT(
3294  queue_data[jss::highest_sequence] ==
3295  data[jss::Sequence].asUInt() +
3296  queue_data[jss::txn_count].asUInt() - 1);
3297  BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued));
3298  BEAST_EXPECT(queue_data[jss::auth_change_queued].asBool());
3299  BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total));
3300  BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == "100");
3301  BEAST_EXPECT(queue_data.isMember(jss::transactions));
3302  auto const& queued = queue_data[jss::transactions];
3303  BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
3304  for (unsigned i = 0; i < queued.size(); ++i)
3305  {
3306  auto const& item = queued[i];
3307  BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
3308  BEAST_EXPECT(item[jss::fee_level] == "2560");
3309 
3310  if (i == queued.size() - 1)
3311  {
3312  BEAST_EXPECT(item.isMember(jss::fee));
3313  BEAST_EXPECT(item[jss::fee] == "100");
3314  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
3315  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
3316  BEAST_EXPECT(item.isMember(jss::auth_change));
3317  BEAST_EXPECT(item[jss::auth_change].asBool());
3318  BEAST_EXPECT(item.isMember(jss::LastLedgerSequence));
3319  BEAST_EXPECT(item[jss::LastLedgerSequence] == 10);
3320  }
3321  else
3322  {
3323  BEAST_EXPECT(item.isMember(jss::fee));
3324  BEAST_EXPECT(item[jss::fee] == "100");
3325  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
3326  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
3327  BEAST_EXPECT(item.isMember(jss::auth_change));
3328  BEAST_EXPECT(!item[jss::auth_change].asBool());
3329  BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
3330  }
3331  }
3332  }
3333 
3334  {
3335  auto const info =
3336  env.rpc("json", "account_info", prevLedgerWithQueue);
3337  BEAST_EXPECT(
3338  info.isMember(jss::result) &&
3339  RPC::contains_error(info[jss::result]));
3340  }
3341 
3342  env.close();
3343  checkMetrics(__LINE__, env, 0, 10, 2, 5, 256);
3344  env.close();
3345  checkMetrics(__LINE__, env, 0, 10, 0, 5, 256);
3346 
3347  {
3348  auto const info = env.rpc("json", "account_info", withQueue);
3349  BEAST_EXPECT(
3350  info.isMember(jss::result) &&
3351  info[jss::result].isMember(jss::account_data));
3352  auto const& result = info[jss::result];
3353  BEAST_EXPECT(result.isMember(jss::queue_data));
3354  auto const& queue_data = result[jss::queue_data];
3355  BEAST_EXPECT(queue_data.isObject());
3356  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
3357  BEAST_EXPECT(queue_data[jss::txn_count] == 0);
3358  BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
3359  BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
3360  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
3361  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
3362  BEAST_EXPECT(!queue_data.isMember(jss::transactions));
3363  }
3364  }
3365 
3366  void
3368  {
3369  using namespace jtx;
3370  testcase("server info");
3371 
3372  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
3373  Env_ss envs(env);
3374 
3375  Account const alice{"alice"};
3376  env.fund(XRP(1000000), alice);
3377  env.close();
3378 
3379  {
3380  auto const server_info = env.rpc("server_info");
3381  BEAST_EXPECT(
3382  server_info.isMember(jss::result) &&
3383  server_info[jss::result].isMember(jss::info));
3384  auto const& info = server_info[jss::result][jss::info];
3385  BEAST_EXPECT(
3386  info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
3387  BEAST_EXPECT(!info.isMember(jss::load_factor_server));
3388  BEAST_EXPECT(!info.isMember(jss::load_factor_local));
3389  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
3390  BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3391  }
3392  {
3393  auto const server_state = env.rpc("server_state");
3394  auto const& state = server_state[jss::result][jss::state];
3395  BEAST_EXPECT(
3396  state.isMember(jss::load_factor) &&
3397  state[jss::load_factor] == 256);
3398  BEAST_EXPECT(
3399  state.isMember(jss::load_base) && state[jss::load_base] == 256);
3400  BEAST_EXPECT(
3401  state.isMember(jss::load_factor_server) &&
3402  state[jss::load_factor_server] == 256);
3403  BEAST_EXPECT(
3404  state.isMember(jss::load_factor_fee_escalation) &&
3405  state[jss::load_factor_fee_escalation] == 256);
3406  BEAST_EXPECT(
3407  state.isMember(jss::load_factor_fee_queue) &&
3408  state[jss::load_factor_fee_queue] == 256);
3409  BEAST_EXPECT(
3410  state.isMember(jss::load_factor_fee_reference) &&
3411  state[jss::load_factor_fee_reference] == 256);
3412  }
3413 
3414  checkMetrics(__LINE__, env, 0, 6, 0, 3, 256);
3415 
3416  fillQueue(env, alice);
3417  checkMetrics(__LINE__, env, 0, 6, 4, 3, 256);
3418 
3419  auto aliceSeq = env.seq(alice);
3421  for (auto i = 0; i < 4; ++i)
3422  envs(noop(alice), fee(100), seq(aliceSeq + i), ter(terQUEUED))(
3423  submitParams);
3424  checkMetrics(__LINE__, env, 4, 6, 4, 3, 256);
3425 
3426  {
3427  auto const server_info = env.rpc("server_info");
3428  BEAST_EXPECT(
3429  server_info.isMember(jss::result) &&
3430  server_info[jss::result].isMember(jss::info));
3431  auto const& info = server_info[jss::result][jss::info];
3432  // Avoid double rounding issues by comparing to a range.
3433  BEAST_EXPECT(
3434  info.isMember(jss::load_factor) &&
3435  info[jss::load_factor] > 888.88 &&
3436  info[jss::load_factor] < 888.89);
3437  BEAST_EXPECT(
3438  info.isMember(jss::load_factor_server) &&
3439  info[jss::load_factor_server] == 1);
3440  BEAST_EXPECT(!info.isMember(jss::load_factor_local));
3441  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
3442  BEAST_EXPECT(
3443  info.isMember(jss::load_factor_fee_escalation) &&
3444  info[jss::load_factor_fee_escalation] > 888.88 &&
3445  info[jss::load_factor_fee_escalation] < 888.89);
3446  }
3447  {
3448  auto const server_state = env.rpc("server_state");
3449  auto const& state = server_state[jss::result][jss::state];
3450  BEAST_EXPECT(
3451  state.isMember(jss::load_factor) &&
3452  state[jss::load_factor] == 227555);
3453  BEAST_EXPECT(
3454  state.isMember(jss::load_base) && state[jss::load_base] == 256);
3455  BEAST_EXPECT(
3456  state.isMember(jss::load_factor_server) &&
3457  state[jss::load_factor_server] == 256);
3458  BEAST_EXPECT(
3459  state.isMember(jss::load_factor_fee_escalation) &&
3460  state[jss::load_factor_fee_escalation] == 227555);
3461  BEAST_EXPECT(
3462  state.isMember(jss::load_factor_fee_queue) &&
3463  state[jss::load_factor_fee_queue] == 256);
3464  BEAST_EXPECT(
3465  state.isMember(jss::load_factor_fee_reference) &&
3466  state[jss::load_factor_fee_reference] == 256);
3467  }
3468 
3469  env.app().getFeeTrack().setRemoteFee(256000);
3470 
3471  {
3472  auto const server_info = env.rpc("server_info");
3473  BEAST_EXPECT(
3474  server_info.isMember(jss::result) &&
3475  server_info[jss::result].isMember(jss::info));
3476  auto const& info = server_info[jss::result][jss::info];
3477  // Avoid double rounding issues by comparing to a range.
3478  BEAST_EXPECT(
3479  info.isMember(jss::load_factor) &&
3480  info[jss::load_factor] == 1000);
3481  BEAST_EXPECT(!info.isMember(jss::load_factor_server));
3482  BEAST_EXPECT(!info.isMember(jss::load_factor_local));
3483  BEAST_EXPECT(
3484  info.isMember(jss::load_factor_net) &&
3485  info[jss::load_factor_net] == 1000);
3486  BEAST_EXPECT(
3487  info.isMember(jss::load_factor_fee_escalation) &&
3488  info[jss::load_factor_fee_escalation] > 888.88 &&
3489  info[jss::load_factor_fee_escalation] < 888.89);
3490  }
3491  {
3492  auto const server_state = env.rpc("server_state");
3493  auto const& state = server_state[jss::result][jss::state];
3494  BEAST_EXPECT(
3495  state.isMember(jss::load_factor) &&
3496  state[jss::load_factor] == 256000);
3497  BEAST_EXPECT(
3498  state.isMember(jss::load_base) && state[jss::load_base] == 256);
3499  BEAST_EXPECT(
3500  state.isMember(jss::load_factor_server) &&
3501  state[jss::load_factor_server] == 256000);
3502  BEAST_EXPECT(
3503  state.isMember(jss::load_factor_fee_escalation) &&
3504  state[jss::load_factor_fee_escalation] == 227555);
3505  BEAST_EXPECT(
3506  state.isMember(jss::load_factor_fee_queue) &&
3507  state[jss::load_factor_fee_queue] == 256);
3508  BEAST_EXPECT(
3509  state.isMember(jss::load_factor_fee_reference) &&
3510  state[jss::load_factor_fee_reference] == 256);
3511  }
3512 
3513  env.app().getFeeTrack().setRemoteFee(256);
3514 
3515  // Increase the server load
3516  for (int i = 0; i < 5; ++i)
3517  env.app().getFeeTrack().raiseLocalFee();
3518  BEAST_EXPECT(env.app().getFeeTrack().getLoadFactor() == 625);
3519 
3520  {
3521  auto const server_info = env.rpc("server_info");
3522  BEAST_EXPECT(
3523  server_info.isMember(jss::result) &&
3524  server_info[jss::result].isMember(jss::info));
3525  auto const& info = server_info[jss::result][jss::info];
3526  // Avoid double rounding issues by comparing to a range.
3527  BEAST_EXPECT(
3528  info.isMember(jss::load_factor) &&
3529  info[jss::load_factor] > 888.88 &&
3530  info[jss::load_factor] < 888.89);
3531  // There can be a race between LoadManager lowering the fee,
3532  // and the call to server_info, so check a wide range.
3533  // The important thing is that it's not 1.
3534  BEAST_EXPECT(
3535  info.isMember(jss::load_factor_server) &&
3536  info[jss::load_factor_server] > 1.245 &&
3537  info[jss::load_factor_server] < 2.4415);
3538  BEAST_EXPECT(
3539  info.isMember(jss::load_factor_local) &&
3540  info[jss::load_factor_local] > 1.245 &&
3541  info[jss::load_factor_local] < 2.4415);
3542  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
3543  BEAST_EXPECT(
3544  info.isMember(jss::load_factor_fee_escalation) &&
3545  info[jss::load_factor_fee_escalation] > 888.88 &&
3546  info[jss::load_factor_fee_escalation] < 888.89);
3547  }
3548  {
3549  auto const server_state = env.rpc("server_state");
3550  auto const& state = server_state[jss::result][jss::state];
3551  BEAST_EXPECT(
3552  state.isMember(jss::load_factor) &&
3553  state[jss::load_factor] == 227555);
3554  BEAST_EXPECT(
3555  state.isMember(jss::load_base) && state[jss::load_base] == 256);
3556  // There can be a race between LoadManager lowering the fee,
3557  // and the call to server_info, so check a wide range.
3558  // The important thing is that it's not 256.
3559  BEAST_EXPECT(
3560  state.isMember(jss::load_factor_server) &&
3561  state[jss::load_factor_server] >= 320 &&
3562  state[jss::load_factor_server] <= 625);
3563  BEAST_EXPECT(
3564  state.isMember(jss::load_factor_fee_escalation) &&
3565  state[jss::load_factor_fee_escalation] == 227555);
3566  BEAST_EXPECT(
3567  state.isMember(jss::load_factor_fee_queue) &&
3568  state[jss::load_factor_fee_queue] == 256);
3569  BEAST_EXPECT(
3570  state.isMember(jss::load_factor_fee_reference) &&
3571  state[jss::load_factor_fee_reference] == 256);
3572  }
3573 
3574  env.close();
3575 
3576  {
3577  auto const server_info = env.rpc("server_info");
3578  BEAST_EXPECT(
3579  server_info.isMember(jss::result) &&
3580  server_info[jss::result].isMember(jss::info));
3581  auto const& info = server_info[jss::result][jss::info];
3582  // Avoid double rounding issues by comparing to a range.
3583 
3584  // There can be a race between LoadManager lowering the fee,
3585  // and the call to server_info, so check a wide range.
3586  // The important thing is that it's not 1.
3587  BEAST_EXPECT(
3588  info.isMember(jss::load_factor) &&
3589  info[jss::load_factor] > 1.245 &&
3590  info[jss::load_factor] < 2.4415);
3591  BEAST_EXPECT(!info.isMember(jss::load_factor_server));
3592  BEAST_EXPECT(
3593  info.isMember(jss::load_factor_local) &&
3594  info[jss::load_factor_local] > 1.245 &&
3595  info[jss::load_factor_local] < 2.4415);
3596  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
3597  BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
3598  }
3599  {
3600  auto const server_state = env.rpc("server_state");
3601  auto const& state = server_state[jss::result][jss::state];
3602  BEAST_EXPECT(
3603  state.isMember(jss::load_factor) &&
3604  state[jss::load_factor] >= 320 &&
3605  state[jss::load_factor] <= 625);
3606  BEAST_EXPECT(
3607  state.isMember(jss::load_base) && state[jss::load_base] == 256);
3608  // There can be a race between LoadManager lowering the fee,
3609  // and the call to server_info, so check a wide range.
3610  // The important thing is that it's not 256.
3611  BEAST_EXPECT(
3612  state.isMember(jss::load_factor_server) &&
3613  state[jss::load_factor_server] >= 320 &&
3614  state[jss::load_factor_server] <= 625);
3615  BEAST_EXPECT(
3616  state.isMember(jss::load_factor_fee_escalation) &&
3617  state[jss::load_factor_fee_escalation] == 256);
3618  BEAST_EXPECT(
3619  state.isMember(jss::load_factor_fee_queue) &&
3620  state[jss::load_factor_fee_queue] == 256);
3621  BEAST_EXPECT(
3622  state.isMember(jss::load_factor_fee_reference) &&
3623  state[jss::load_factor_fee_reference] == 256);
3624  }
3625  }
3626 
3627  void
3629  {
3630  using namespace jtx;
3631  testcase("server subscribe");
3632 
3633  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
3634 
3635  Json::Value stream;
3636  stream[jss::streams] = Json::arrayValue;
3637  stream[jss::streams].append("server");
3638  auto wsc = makeWSClient(env.app().config());
3639  {
3640  auto jv = wsc->invoke("subscribe", stream);
3641  BEAST_EXPECT(jv[jss::status] == "success");
3642  }
3643 
3644  Account a{"a"}, b{"b"}, c{"c"}, d{"d"}, e{"e"}, f{"f"}, g{"g"}, h{"h"},
3645  i{"i"};
3646 
3647  // Fund the first few accounts at non escalated fee
3648  env.fund(XRP(50000), noripple(a, b, c, d));
3649  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
3650 
3651  // First transaction establishes the messaging
3652  using namespace std::chrono_literals;
3653  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
3654  return jv[jss::type] == "serverStatus" &&
3655  jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3656  jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3657  jv.isMember(jss::load_factor_server) &&
3658  jv[jss::load_factor_server] == 256 &&
3659  jv.isMember(jss::load_factor_fee_escalation) &&
3660  jv[jss::load_factor_fee_escalation] == 256 &&
3661  jv.isMember(jss::load_factor_fee_queue) &&
3662  jv[jss::load_factor_fee_queue] == 256 &&
3663  jv.isMember(jss::load_factor_fee_reference) &&
3664  jv[jss::load_factor_fee_reference] == 256;
3665  }));
3666  // Last transaction escalates the fee
3667  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
3668  return jv[jss::type] == "serverStatus" &&
3669  jv.isMember(jss::load_factor) &&
3670  jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
3671  jv[jss::load_base] == 256 &&
3672  jv.isMember(jss::load_factor_server) &&
3673  jv[jss::load_factor_server] == 256 &&
3674  jv.isMember(jss::load_factor_fee_escalation) &&
3675  jv[jss::load_factor_fee_escalation] == 227555 &&
3676  jv.isMember(jss::load_factor_fee_queue) &&
3677  jv[jss::load_factor_fee_queue] == 256 &&
3678  jv.isMember(jss::load_factor_fee_reference) &&
3679  jv[jss::load_factor_fee_reference] == 256;
3680  }));
3681 
3682  env.close();
3683 
3684  // Closing ledger should publish a status update
3685  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
3686  return jv[jss::type] == "serverStatus" &&
3687  jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3688  jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3689  jv.isMember(jss::load_factor_server) &&
3690  jv[jss::load_factor_server] == 256 &&
3691  jv.isMember(jss::load_factor_fee_escalation) &&
3692  jv[jss::load_factor_fee_escalation] == 256 &&
3693  jv.isMember(jss::load_factor_fee_queue) &&
3694  jv[jss::load_factor_fee_queue] == 256 &&
3695  jv.isMember(jss::load_factor_fee_reference) &&
3696  jv[jss::load_factor_fee_reference] == 256;
3697  }));
3698 
3699  checkMetrics(__LINE__, env, 0, 8, 0, 4, 256);
3700 
3701  // Fund then next few accounts at non escalated fee
3702  env.fund(XRP(50000), noripple(e, f, g, h, i));
3703 
3704  // Extra transactions with low fee are queued
3705  auto queued = ter(terQUEUED);
3706  env(noop(a), fee(10), queued);
3707  env(noop(b), fee(10), queued);
3708  env(noop(c), fee(10), queued);
3709  env(noop(d), fee(10), queued);
3710  env(noop(e), fee(10), queued);
3711  env(noop(f), fee(10), queued);
3712  env(noop(g), fee(10), queued);
3713  checkMetrics(__LINE__, env, 7, 8, 5, 4, 256);
3714 
3715  // Last transaction escalates the fee
3716  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
3717  return jv[jss::type] == "serverStatus" &&
3718  jv.isMember(jss::load_factor) &&
3719  jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
3720  jv[jss::load_base] == 256 &&
3721  jv.isMember(jss::load_factor_server) &&
3722  jv[jss::load_factor_server] == 256 &&
3723  jv.isMember(jss::load_factor_fee_escalation) &&
3724  jv[jss::load_factor_fee_escalation] == 200000 &&
3725  jv.isMember(jss::load_factor_fee_queue) &&
3726  jv[jss::load_factor_fee_queue] == 256 &&
3727  jv.isMember(jss::load_factor_fee_reference) &&
3728  jv[jss::load_factor_fee_reference] == 256;
3729  }));
3730 
3731  env.close();
3732  // Ledger close publishes with escalated fees for queued transactions
3733  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
3734  return jv[jss::type] == "serverStatus" &&
3735  jv.isMember(jss::load_factor) &&
3736  jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
3737  jv[jss::load_base] == 256 &&
3738  jv.isMember(jss::load_factor_server) &&
3739  jv[jss::load_factor_server] == 256 &&
3740  jv.isMember(jss::load_factor_fee_escalation) &&
3741  jv[jss::load_factor_fee_escalation] == 184320 &&
3742  jv.isMember(jss::load_factor_fee_queue) &&
3743  jv[jss::load_factor_fee_queue] == 256 &&
3744  jv.isMember(jss::load_factor_fee_reference) &&
3745  jv[jss::load_factor_fee_reference] == 256;
3746  }));
3747 
3748  env.close();
3749  // ledger close clears queue so fee is back to normal
3750  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
3751  return jv[jss::type] == "serverStatus" &&
3752  jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
3753  jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
3754  jv.isMember(jss::load_factor_server) &&
3755  jv[jss::load_factor_server] == 256 &&
3756  jv.isMember(jss::load_factor_fee_escalation) &&
3757  jv[jss::load_factor_fee_escalation] == 256 &&
3758  jv.isMember(jss::load_factor_fee_queue) &&
3759  jv[jss::load_factor_fee_queue] == 256 &&
3760  jv.isMember(jss::load_factor_fee_reference) &&
3761  jv[jss::load_factor_fee_reference] == 256;
3762  }));
3763 
3764  BEAST_EXPECT(!wsc->findMsg(1s, [&](auto const& jv) {
3765  return jv[jss::type] == "serverStatus";
3766  }));
3767 
3768  auto jv = wsc->invoke("unsubscribe", stream);
3769  BEAST_EXPECT(jv[jss::status] == "success");
3770  }
3771 
3772  void
3774  {
3775  using namespace jtx;
3776  testcase("clear queued acct txs");
3777 
3778  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
3779  auto alice = Account("alice");
3780  auto bob = Account("bob");
3781 
3782  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
3783  env.fund(XRP(50000000), alice, bob);
3784 
3785  fillQueue(env, alice);
3786 
3787  auto calcTotalFee = [&](std::int64_t alreadyPaid,
3788  std::optional<std::size_t> numToClear =
3789  std::nullopt) -> std::uint64_t {
3790  auto totalFactor = 0;
3791  auto const metrics = env.app().getTxQ().getMetrics(*env.current());
3792  if (!numToClear)
3793  numToClear.emplace(metrics.txCount + 1);
3794  for (int i = 0; i < *numToClear; ++i)
3795  {
3796  auto inLedger = metrics.txInLedger + i;
3797  totalFactor += inLedger * inLedger;
3798  }
3799  auto result = toDrops(
3800  metrics.medFeeLevel * totalFactor /
3801  (metrics.txPerLedger * metrics.txPerLedger),
3802  env.current()->fees().base)
3803  .drops();
3804  // Subtract the fees already paid
3805  result -= alreadyPaid;
3806  // round up
3807  ++result;
3808  return result;
3809  };
3810 
3811  testcase("straightfoward positive case");
3812  {
3813  // Queue up some transactions at a too-low fee.
3814  auto aliceSeq = env.seq(alice);
3815  for (int i = 0; i < 2; ++i)
3816  {
3817  env(noop(alice), fee(100), seq(aliceSeq++), ter(terQUEUED));
3818  }
3819 
3820  // Queue up a transaction paying the open ledger fee
3821  // This will be the first tx to call the operative function,
3822  // but it won't succeed.
3823  env(noop(alice),
3824  openLedgerFee(env),
3825  seq(aliceSeq++),
3826  ter(terQUEUED));
3827 
3828  checkMetrics(__LINE__, env, 3, std::nullopt, 4, 3, 256);
3829 
3830  // Figure out how much it would cost to cover all the
3831  // queued txs + itself
3832  std::uint64_t totalFee1 = calcTotalFee(100 * 2 + 8889);
3833  --totalFee1;
3834 
3835  BEAST_EXPECT(totalFee1 == 60911);
3836  // Submit a transaction with that fee. It will get queued
3837  // because the fee level calculation rounds down. This is
3838  // the edge case test.
3839  env(noop(alice), fee(totalFee1), seq(aliceSeq++), ter(terQUEUED));
3840 
3841  checkMetrics(__LINE__, env, 4, std::nullopt, 4, 3, 256);
3842 
3843  // Now repeat the process including the new tx
3844  // and avoiding the rounding error
3845  std::uint64_t const totalFee2 =
3846  calcTotalFee(100 * 2 + 8889 + 60911);
3847  BEAST_EXPECT(totalFee2 == 35556);
3848  // Submit a transaction with that fee. It will succeed.
3849  env(noop(alice), fee(totalFee2), seq(aliceSeq++));
3850 
3851  checkMetrics(__LINE__, env, 0, std::nullopt, 9, 3, 256);
3852  }
3853 
3854  testcase("replace last tx with enough to clear queue");
3855  {
3856  // Queue up some transactions at a too-low fee.
3857  auto aliceSeq = env.seq(alice);
3858  for (int i = 0; i < 2; ++i)
3859  {
3860  env(noop(alice), fee(100), seq(aliceSeq++), ter(terQUEUED));
3861  }
3862 
3863  // Queue up a transaction paying the open ledger fee
3864  // This will be the first tx to call the operative function,
3865  // but it won't succeed.
3866  env(noop(alice),
3867  openLedgerFee(env),
3868  seq(aliceSeq++),
3869  ter(terQUEUED));
3870 
3871  checkMetrics(__LINE__, env, 3, std::nullopt, 9, 3, 256);
3872 
3873  // Figure out how much it would cost to cover all the
3874  // queued txs + itself
3875  auto const metrics = env.app().getTxQ().getMetrics(*env.current());
3876  std::uint64_t const totalFee =
3877  calcTotalFee(100 * 2, metrics.txCount);
3878  BEAST_EXPECT(totalFee == 167578);
3879  // Replacing the last tx with the large fee succeeds.
3880  --aliceSeq;
3881  env(noop(alice), fee(totalFee), seq(aliceSeq++));
3882 
3883  // The queue is clear
3884  checkMetrics(__LINE__, env, 0, std::nullopt, 12, 3, 256);
3885 
3886  env.close();
3887  checkMetrics(__LINE__, env, 0, 24, 0, 12, 256);
3888  }
3889 
3890  testcase("replace middle tx with enough to clear queue");
3891  {
3892  fillQueue(env, alice);
3893  // Queue up some transactions at a too-low fee.
3894  auto aliceSeq = env.seq(alice);
3895  for (int i = 0; i < 5; ++i)
3896  {
3897  env(noop(alice), fee(100), seq(aliceSeq++), ter(terQUEUED));
3898  }
3899 
3900  checkMetrics(__LINE__, env, 5, 24, 13, 12, 256);
3901 
3902  // Figure out how much it would cost to cover 3 txns
3903  std::uint64_t const totalFee = calcTotalFee(100 * 2, 3);
3904  BEAST_EXPECT(totalFee == 20287);
3905  // Replacing the last tx with the large fee succeeds.
3906  aliceSeq -= 3;
3907  env(noop(alice), fee(totalFee), seq(aliceSeq++));
3908 
3909  checkMetrics(__LINE__, env, 2, 24, 16, 12, 256);
3910  auto const aliceQueue =
3911  env.app().getTxQ().getAccountTxs(alice.id());
3912  BEAST_EXPECT(aliceQueue.size() == 2);
3913  SeqProxy seq = SeqProxy::sequence(aliceSeq);
3914  for (auto const& tx : aliceQueue)
3915  {
3916  BEAST_EXPECT(tx.seqProxy == seq);
3917  BEAST_EXPECT(tx.feeLevel == FeeLevel64{2560});
3918  seq.advanceBy(1);
3919  }
3920 
3921  // Close the ledger to clear the queue
3922  env.close();
3923  checkMetrics(__LINE__, env, 0, 32, 2, 16, 256);
3924  }
3925 
3926  testcase("clear queue failure (load)");
3927  {
3928  fillQueue(env, alice);
3929  // Queue up some transactions at a too-low fee.
3930  auto aliceSeq = env.seq(alice);
3931  for (int i = 0; i < 2; ++i)
3932  {
3933  env(noop(alice), fee(200), seq(aliceSeq++), ter(terQUEUED));
3934  }
3935  for (int i = 0; i < 2; ++i)
3936  {
3937  env(noop(alice), fee(22), seq(aliceSeq++), ter(terQUEUED));
3938  }
3939 
3940  checkMetrics(__LINE__, env, 4, 32, 17, 16, 256);
3941 
3942  // Figure out how much it would cost to cover all the txns
3943  // + 1
3944  std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
3945  BEAST_EXPECT(totalFee == 35006);
3946  // This fee should be enough, but oh no! Server load went up!
3947  auto& feeTrack = env.app().getFeeTrack();
3948  auto const origFee = feeTrack.getRemoteFee();
3949  feeTrack.setRemoteFee(origFee * 5);
3950  // Instead the tx gets queued, and all of the queued
3951  // txs stay in the queue.
3952  env(noop(alice), fee(totalFee), seq(aliceSeq++), ter(terQUEUED));
3953 
3954  // The original last transaction is still in the queue
3955  checkMetrics(__LINE__, env, 5, 32, 17, 16, 256);
3956 
3957  // With high load, some of the txs stay in the queue
3958  env.close();
3959  checkMetrics(__LINE__, env, 3, 34, 2, 17, 256);
3960 
3961  // Load drops back down
3962  feeTrack.setRemoteFee(origFee);
3963 
3964  // Because of the earlier failure, alice can not clear the queue,
3965  // no matter how high the fee
3966  fillQueue(env, bob);
3967  checkMetrics(__LINE__, env, 3, 34, 18, 17, 256);
3968 
3969  env(noop(alice), fee(XRP(1)), seq(aliceSeq++), ter(terQUEUED));
3970  checkMetrics(__LINE__, env, 4, 34, 18, 17, 256);
3971 
3972  // With normal load, those txs get into the ledger
3973  env.close();
3974  checkMetrics(__LINE__, env, 0, 36, 4, 18, 256);
3975  }
3976  }
3977 
3978  void
3980  {
3981  using namespace jtx;
3982  using namespace std::chrono_literals;
3983  testcase("scaling");
3984 
3985  {
3986  Env env(
3987  *this,
3988  makeConfig(
3989  {{"minimum_txn_in_ledger_standalone", "3"},
3990  {"normal_consensus_increase_percent", "25"},
3991  {"slow_consensus_decrease_percent", "50"},
3992  {"target_txn_in_ledger", "10"},
3993  {"maximum_txn_per_account", "200"}}));
3994  auto alice = Account("alice");
3995 
3996  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
3997  env.fund(XRP(50000000), alice);
3998 
3999  fillQueue(env, alice);
4000  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4001  auto seqAlice = env.seq(alice);
4002  auto txCount = 140;
4003  for (int i = 0; i < txCount; ++i)
4004  env(noop(alice), seq(seqAlice++), ter(terQUEUED));
4005  checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4006 
4007  // Close a few ledgers successfully, so the limit grows
4008 
4009  env.close();
4010  // 4 + 25% = 5
4011  txCount -= 6;
4012  checkMetrics(__LINE__, env, txCount, 10, 6, 5, 257);
4013 
4014  env.close();
4015  // 6 + 25% = 7
4016  txCount -= 8;
4017  checkMetrics(__LINE__, env, txCount, 14, 8, 7, 257);
4018 
4019  env.close();
4020  // 8 + 25% = 10
4021  txCount -= 11;
4022  checkMetrics(__LINE__, env, txCount, 20, 11, 10, 257);
4023 
4024  env.close();
4025  // 11 + 25% = 13
4026  txCount -= 14;
4027  checkMetrics(__LINE__, env, txCount, 26, 14, 13, 257);
4028 
4029  env.close();
4030  // 14 + 25% = 17
4031  txCount -= 18;
4032  checkMetrics(__LINE__, env, txCount, 34, 18, 17, 257);
4033 
4034  env.close();
4035  // 18 + 25% = 22
4036  txCount -= 23;
4037  checkMetrics(__LINE__, env, txCount, 44, 23, 22, 257);
4038 
4039  env.close();
4040  // 23 + 25% = 28
4041  txCount -= 29;
4042  checkMetrics(__LINE__, env, txCount, 56, 29, 28, 256);
4043 
4044  // From 3 expected to 28 in 7 "fast" ledgers.
4045 
4046  // Close the ledger with a delay.
4047  env.close(env.now() + 5s, 10000ms);
4048  txCount -= 15;
4049  checkMetrics(__LINE__, env, txCount, 56, 15, 14, 256);
4050 
4051  // Close the ledger with a delay.
4052  env.close(env.now() + 5s, 10000ms);
4053  txCount -= 8;
4054  checkMetrics(__LINE__, env, txCount, 56, 8, 7, 256);
4055 
4056  // Close the ledger with a delay.
4057  env.close(env.now() + 5s, 10000ms);
4058  txCount -= 4;
4059  checkMetrics(__LINE__, env, txCount, 56, 4, 3, 256);
4060 
4061  // From 28 expected back down to 3 in 3 "slow" ledgers.
4062 
4063  // Confirm the minimum sticks
4064  env.close(env.now() + 5s, 10000ms);
4065  txCount -= 4;
4066  checkMetrics(__LINE__, env, txCount, 56, 4, 3, 256);
4067 
4068  BEAST_EXPECT(!txCount);
4069  }
4070 
4071  {
4072  Env env(
4073  *this,
4074  makeConfig(
4075  {{"minimum_txn_in_ledger_standalone", "3"},
4076  {"normal_consensus_increase_percent", "150"},
4077  {"slow_consensus_decrease_percent", "150"},
4078  {"target_txn_in_ledger", "10"},
4079  {"maximum_txn_per_account", "200"}}));
4080  auto alice = Account("alice");
4081 
4082  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4083  env.fund(XRP(50000000), alice);
4084 
4085  fillQueue(env, alice);
4086  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4087  auto seqAlice = env.seq(alice);
4088  auto txCount = 43;
4089  for (int i = 0; i < txCount; ++i)
4090  env(noop(alice), seq(seqAlice++), ter(terQUEUED));
4091  checkMetrics(__LINE__, env, txCount, std::nullopt, 4, 3, 256);
4092 
4093  // Close a few ledgers successfully, so the limit grows
4094 
4095  env.close();
4096  // 4 + 150% = 10
4097  txCount -= 11;
4098  checkMetrics(__LINE__, env, txCount, 20, 11, 10, 257);
4099 
4100  env.close();
4101  // 11 + 150% = 27
4102  txCount -= 28;
4103  checkMetrics(__LINE__, env, txCount, 54, 28, 27, 256);
4104 
4105  // From 3 expected to 28 in 7 "fast" ledgers.
4106 
4107  // Close the ledger with a delay.
4108  env.close(env.now() + 5s, 10000ms);
4109  txCount -= 4;
4110  checkMetrics(__LINE__, env, txCount, 54, 4, 3, 256);
4111 
4112  // From 28 expected back down to 3 in 3 "slow" ledgers.
4113 
4114  BEAST_EXPECT(!txCount);
4115  }
4116  }
4117 
4118  void
4120  {
4121  // Test the situation where a transaction with an account and
4122  // sequence that's in the queue also appears in the ledger.
4123  //
4124  // Normally this situation can only happen on a network
4125  // when a transaction gets validated by most of the network,
4126  // but one or more nodes have that transaction (or a different
4127  // transaction with the same sequence) queued. And, yes, this
4128  // situation has been observed (rarely) in the wild.
4129  testcase("Sequence in queue and open ledger");
4130  using namespace jtx;
4131 
4132  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
4133 
4134  auto const alice = Account("alice");
4135 
4136  auto const queued = ter(terQUEUED);
4137 
4138  BEAST_EXPECT(env.current()->fees().base == 10);
4139 
4140  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4141 
4142  // Create account
4143  env.fund(XRP(50000), noripple(alice));
4144  checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4145 
4146  fillQueue(env, alice);
4147  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4148 
4149  // Queue a transaction
4150  auto const aliceSeq = env.seq(alice);
4151  env(noop(alice), queued);
4152  checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4153 
4154  // Now, apply a (different) transaction directly
4155  // to the open ledger, bypassing the queue
4156  // (This requires calling directly into the open ledger,
4157  // which won't work if unit tests are separated to only
4158  // be callable via RPC.)
4159  env.app().openLedger().modify([&](OpenView& view, beast::Journal j) {
4160  auto const tx =
4161  env.jt(noop(alice), seq(aliceSeq), openLedgerFee(env));
4162  auto const result =
4163  ripple::apply(env.app(), view, *tx.stx, tapUNLIMITED, j);
4164  BEAST_EXPECT(result.first == tesSUCCESS && result.second);
4165  return result.second;
4166  });
4167  // the queued transaction is still there
4168  checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4169 
4170  // The next transaction should be able to go into the open
4171  // ledger, even though aliceSeq is queued. In earlier incarnations
4172  // of the TxQ this would cause an assert.
4173  env(noop(alice), seq(aliceSeq + 1), openLedgerFee(env));
4174  checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4175  // Now queue a couple more transactions to make sure
4176  // they succeed despite aliceSeq being queued
4177  env(noop(alice), seq(aliceSeq + 2), queued);
4178  env(noop(alice), seq(aliceSeq + 3), queued);
4179  checkMetrics(__LINE__, env, 3, std::nullopt, 6, 3, 256);
4180 
4181  // Now close the ledger. One of the queued transactions
4182  // (aliceSeq) should be dropped.
4183  env.close();
4184  checkMetrics(__LINE__, env, 0, 12, 2, 6, 256);
4185  }
4186 
4187  void
4189  {
4190  // Test the situation where a transaction with an account and
4191  // ticket that's in the queue also appears in the ledger.
4192  //
4193  // Although this situation has not (yet) been observed in the wild,
4194  // it is a direct analogy to the previous sequence based test. So
4195  // there is no reason to not expect to see it in the wild.
4196  testcase("Ticket in queue and open ledger");
4197  using namespace jtx;
4198 
4199  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
4200 
4201  auto alice = Account("alice");
4202 
4203  auto queued = ter(terQUEUED);
4204 
4205  BEAST_EXPECT(env.current()->fees().base == 10);
4206 
4207  checkMetrics(__LINE__, env, 0, std::nullopt, 0, 3, 256);
4208 
4209  // Create account
4210  env.fund(XRP(50000), noripple(alice));
4211  checkMetrics(__LINE__, env, 0, std::nullopt, 1, 3, 256);
4212 
4213  // Create tickets
4214  std::uint32_t const tktSeq0{env.seq(alice) + 1};
4215  env(ticket::create(alice, 4));
4216 
4217  // Fill the queue so the next transaction will be queued.
4218  fillQueue(env, alice);
4219  checkMetrics(__LINE__, env, 0, std::nullopt, 4, 3, 256);
4220 
4221  // Queue a transaction with a ticket. Leave an unused ticket
4222  // on either side.
4223  env(noop(alice), ticket::use(tktSeq0 + 1), queued);
4224  checkMetrics(__LINE__, env, 1, std::nullopt, 4, 3, 256);
4225 
4226  // Now, apply a (different) transaction directly
4227  // to the open ledger, bypassing the queue
4228  // (This requires calling directly into the open ledger,
4229  // which won't work if unit tests are separated to only
4230  // be callable via RPC.)
4231  env.app().openLedger().modify([&](OpenView& view, beast::Journal j) {
4232  auto const tx = env.jt(
4233  noop(alice), ticket::use(tktSeq0 + 1), openLedgerFee(env));
4234  auto const result =
4235  ripple::apply(env.app(), view, *tx.stx, tapUNLIMITED, j);
4236  BEAST_EXPECT(result.first == tesSUCCESS && result.second);
4237  return result.second;
4238  });
4239  // the queued transaction is still there
4240  checkMetrics(__LINE__, env, 1, std::nullopt, 5, 3, 256);
4241 
4242  // The next (sequence-based) transaction should be able to go into
4243  // the open ledger, even though tktSeq0 is queued. Note that this
4244  // sequence-based transaction goes in front of the queued
4245  // transaction, so the queued transaction is left in the queue.
4246  env(noop(alice), openLedgerFee(env));
4247  checkMetrics(__LINE__, env, 1, std::nullopt, 6, 3, 256);
4248 
4249  // We should be able to do the same thing with a ticket that goes
4250  // if front of the queued transaction. This one too will leave
4251  // the queued transaction in place.
4252  env(noop(alice), ticket::use(tktSeq0 + 0), openLedgerFee(env));
4253  checkMetrics(__LINE__, env, 1, std::nullopt, 7, 3, 256);
4254 
4255  // We have one ticketed transaction in the queue. We should able
4256  // to add another to the queue.
4257  env(noop(alice), ticket::use(tktSeq0 + 2), queued);
4258  checkMetrics(__LINE__, env, 2, std::nullopt, 7, 3, 256);
4259 
4260  // Here we try to force the queued transactions into the ledger by
4261  // adding one more queued (ticketed) transaction that pays enough
4262  // so fee averaging kicks in. It doesn't work. It only succeeds in
4263  // forcing just the one ticketed transaction into the ledger.
4264  //
4265  // The fee averaging functionality makes sense for sequence-based
4266  // transactions because if there are several sequence-based
4267  // transactions queued, the transactions in front must go into the
4268  // ledger before the later ones can go in.
4269  //
4270  // Fee averaging does not make sense with tickets. Every ticketed
4271  // transaction is equally capable of going into the ledger independent
4272  // of all other ticket- or sequence-based transactions.
4273  env(noop(alice), ticket::use(tktSeq0 + 3), fee(XRP(1)));
4274  checkMetrics(__LINE__, env, 2, std::nullopt, 8, 3, 256);
4275 
4276  // Now close the ledger. One of the queued transactions
4277  // (the one with tktSeq0 + 1) should be dropped.
4278  env.close();
4279  checkMetrics(__LINE__, env, 0, 16, 1, 8, 256);
4280  }
4281 
4282  void
4284  {
4285  // The TxQ caches preflight results. But there are situations where
4286  // that cache must become invalidated, like if amendments change.
4287  //
4288  // This test puts transactions into the TxQ and then enables an
4289  // amendment. We won't really see much interesting here in the unit
4290  // test, but the code that checks for cache invalidation should be
4291  // exercised. You can see that in improved code coverage,
4292  testcase("Re-execute preflight");
4293  using namespace jtx;
4294 
4295  Account const alice("alice");
4296  Account const bob("bob");
4297  Account const carol("carol");
4298  Account const daria("daria");
4299  Account const ellie("ellie");
4300  Account const fiona("fiona");
4301 
4302  auto cfg = makeConfig(
4303  {{"minimum_txn_in_ledger_standalone", "1"},
4304  {"ledgers_in_queue", "5"},
4305  {"maximum_txn_per_account", "10"}},
4306  {{"account_reserve", "1000"}, {"owner_reserve", "50"}});
4307 
4308  Env env(*this, std::move(cfg));
4309 
4310  env.fund(XRP(10000), alice);
4311  env.close();
4312  env.fund(XRP(10000), bob);
4313  env.close();
4314  env.fund(XRP(10000), carol);
4315  env.close();
4316  env.fund(XRP(10000), daria);
4317  env.close();
4318  env.fund(XRP(10000), ellie);
4319  env.close();
4320  env.fund(XRP(10000), fiona);
4321  env.close();
4322  checkMetrics(__LINE__, env, 0, 10, 0, 2, 256);
4323 
4324  // Close ledgers until the amendments show up.
4325  int i = 0;
4326  for (i = 0; i <= 257; ++i)
4327  {
4328  env.close();
4329  if (!getMajorityAmendments(*env.closed()).empty())
4330  break;
4331  }
4332  auto expectedPerLedger = ripple::detail::numUpVotedAmendments() + 1;
4333  checkMetrics(
4334  __LINE__, env, 0, 5 * expectedPerLedger, 0, expectedPerLedger, 256);
4335 
4336  // Now wait 2 weeks modulo 256 ledgers for the amendments to be
4337  // enabled. Speed the process by closing ledgers every 80 minutes,
4338  // which should get us to just past 2 weeks after 256 ledgers.
4339  using namespace std::chrono_literals;
4340  auto closeDuration = 80min;
4341  for (i = 0; i <= 255; ++i)
4342  env.close(closeDuration);
4343 
4344  // We're very close to the flag ledger. Fill the ledger.
4345  fillQueue(env, alice);
4346  checkMetrics(
4347  __LINE__,
4348  env,
4349  0,
4350  5 * expectedPerLedger,
4351  expectedPerLedger + 1,
4352  expectedPerLedger,
4353  256);
4354 
4355  // Fill everyone's queues.
4356  auto seqAlice = env.seq(alice);
4357  auto seqBob = env.seq(bob);
4358  auto seqCarol = env.seq(carol);
4359  auto seqDaria = env.seq(daria);
4360  auto seqEllie = env.seq(ellie);
4361  auto seqFiona = env.seq(fiona);
4362  // Use fees to guarantee order
4363  int txFee{90};
4364  for (int i = 0; i < 10; ++i)
4365  {
4366  env(noop(alice), seq(seqAlice++), fee(--txFee), ter(terQUEUED));
4367  env(noop(bob), seq(seqBob++), fee(--txFee), ter(terQUEUED));
4368  env(noop(carol), seq(seqCarol++), fee(--txFee), ter(terQUEUED));
4369  env(noop(daria), seq(seqDaria++), fee(--txFee), ter(terQUEUED));
4370  env(noop(ellie), seq(seqEllie++), fee(--txFee), ter(terQUEUED));
4371  env(noop(fiona), seq(seqFiona++), fee(--txFee), ter(terQUEUED));
4372  }
4373  std::size_t expectedInQueue = 60;
4374  checkMetrics(
4375  __LINE__,
4376  env,
4377  expectedInQueue,
4378  5 * expectedPerLedger,
4379  expectedPerLedger + 1,
4380  expectedPerLedger,
4381  256);
4382 
4383  // The next close should cause the in-ledger amendments to change.
4384  // Alice's queued transactions have a cached PreflightResult
4385  // that resulted from running against the Rules in the previous
4386  // ledger. Since the amendments change in this newest ledger
4387  // The TxQ must re-run preflight using the new rules.
4388  //
4389  // These particular amendments don't impact any of the queued
4390  // transactions, so we won't see any change in the transaction
4391  // outcomes. But code coverage is affected.
4392  do
4393  {
4394  env.close(closeDuration);
4395  auto expectedInLedger = expectedInQueue;
4396  expectedInQueue =
4397  (expectedInQueue > expectedPerLedger + 2
4398  ? expectedInQueue - (expectedPerLedger + 2)
4399  : 0);
4400  expectedInLedger -= expectedInQueue;
4401  ++expectedPerLedger;
4402  checkMetrics(
4403  __LINE__,
4404  env,
4405  expectedInQueue,
4406  5 * expectedPerLedger,
4407  expectedInLedger,
4408  expectedPerLedger,
4409  256);
4410  {
4411  auto const expectedPerAccount = expectedInQueue / 6;
4412  auto const expectedRemainder = expectedInQueue % 6;
4413  BEAST_EXPECT(env.seq(alice) == seqAlice - expectedPerAccount);
4414  BEAST_EXPECT(
4415  env.seq(bob) ==
4416  seqBob - expectedPerAccount -
4417  (expectedRemainder > 4 ? 1 : 0));
4418  BEAST_EXPECT(
4419  env.seq(carol) ==
4420  seqCarol - expectedPerAccount -
4421  (expectedRemainder > 3 ? 1 : 0));
4422  BEAST_EXPECT(
4423  env.seq(daria) ==
4424  seqDaria - expectedPerAccount -
4425  (expectedRemainder > 2 ? 1 : 0));
4426  BEAST_EXPECT(
4427  env.seq(ellie) ==
4428  seqEllie - expectedPerAccount -
4429  (expectedRemainder > 1 ? 1 : 0));
4430  BEAST_EXPECT(
4431  env.seq(fiona) ==
4432  seqFiona - expectedPerAccount -
4433  (expectedRemainder > 0 ? 1 : 0));
4434  }
4435  } while (expectedInQueue > 0);
4436  }
4437 
4438  void
4440  {
4441  // If...
4442  // o The queue is close to full,
4443  // o An account has multiple txs queued, and
4444  // o That same account has a transaction fail
4445  // Then drop the last transaction for the account if possible.
4446  //
4447  // Verify that happens.
4448  testcase("Queue full drop penalty");
4449  using namespace jtx;
4450 
4451  // Because we're looking at a phenomenon that occurs when the TxQ
4452  // is at 95% capacity or greater, we need to have lots of entries
4453  // in the queue. You can't even see 95% capacity unless there are
4454  // 20 entries in the queue.
4455  Account const alice("alice");
4456  Account const bob("bob");
4457  Account const carol("carol");
4458  Account const daria("daria");
4459  Account const ellie("ellie");
4460  Account const fiona("fiona");
4461 
4462  // We'll be using fees to control which entries leave the queue in
4463  // which order. There's no "lowFee" -- that's the default fee from
4464  // the unit test.
4465  int const medFee = 100;
4466  int const hiFee = 1000;
4467 
4468  auto cfg = makeConfig(
4469  {{"minimum_txn_in_ledger_standalone", "5"},
4470  {"ledgers_in_queue", "5"},
4471  {"maximum_txn_per_account", "30"},
4472  {"minimum_queue_size", "50"}});
4473 
4474  Env env(*this, std::move(cfg));
4475 
4476  // The noripple is to reduce the number of transactions required to
4477  // fund the accounts. There is no rippling in this test.
4478  env.fund(XRP(10000), noripple(alice, bob, carol, daria, ellie, fiona));
4479  env.close();
4480 
4481  // Get bob some tickets.
4482  std::uint32_t const bobTicketSeq = env.seq(bob) + 1;
4483  env(ticket::create(bob, 10));
4484  env.close();
4485 
4486  // Get the dropPenalty flag set on alice and bob by having one
4487  // of their transactions expire out of the queue. To start out
4488  // alice fills the ledger.
4489  fillQueue(env, alice);
4490  checkMetrics(__LINE__, env, 0, 50, 7, 6, 256);
4491 
4492  // Now put a few transactions into alice's queue, including one that
4493  // will expire out soon.
4494  auto seqAlice = env.seq(alice);
4495  auto const seqSaveAlice = seqAlice;
4496  int feeDrops = 40;
4497  env(noop(alice),
4498  seq(seqAlice++),
4499  fee(--feeDrops),
4500  json(R"({"LastLedgerSequence": 7})"),
4501  ter(terQUEUED));
4502  env(noop(alice), seq(seqAlice++), fee(--feeDrops), ter(terQUEUED));
4503  env(noop(alice), seq(seqAlice++), fee(--feeDrops), ter(terQUEUED));
4504  BEAST_EXPECT(env.seq(alice) == seqSaveAlice);
4505 
4506  // Similarly for bob, but bob uses tickets in his transactions.
4507  // The drop penalty works a little differently with tickets.
4508  env(noop(bob),
4509  ticket::use(bobTicketSeq + 0),
4510  json(R"({"LastLedgerSequence": 7})"),
4511  ter(terQUEUED));
4512  env(noop(bob),
4513  ticket::use(bobTicketSeq + 1),
4514  fee(--feeDrops),
4515  ter(terQUEUED));
4516  env(noop(bob),
4517  ticket::use(bobTicketSeq + 2),
4518  fee(--feeDrops),
4519  ter(terQUEUED));
4520 
4521  // Fill the queue with higher fee transactions so alice's and
4522  // bob's transactions are stuck in the queue.
4523  auto seqCarol = env.seq(carol);
4524  auto seqDaria = env.seq(daria);
4525  auto seqEllie = env.seq(ellie);
4526  auto seqFiona = env.seq(fiona);
4527  feeDrops = medFee;
4528  for (int i = 0; i < 7; ++i)
4529  {
4530  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
4531  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
4532  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
4533  env(noop(fiona), seq(seqFiona++), fee(--feeDrops), ter(terQUEUED));
4534  }
4535 
4536  checkMetrics(__LINE__, env, 34, 50, 7, 6, 256);
4537  env.close();
4538  checkMetrics(__LINE__, env, 26, 50, 8, 7, 256);
4539 
4540  // Re-fill the queue so alice and bob stay stuck.
4541  feeDrops = medFee;
4542  for (int i = 0; i < 3; ++i)
4543  {
4544  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
4545  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
4546  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
4547  env(noop(fiona), seq(seqFiona++), fee(--feeDrops), ter(terQUEUED));
4548  }
4549  checkMetrics(__LINE__, env, 38, 50, 8, 7, 256);
4550  env.close();
4551  checkMetrics(__LINE__, env, 29, 50, 9, 8, 256);
4552 
4553  // One more time...
4554  feeDrops = medFee;
4555  for (int i = 0; i < 3; ++i)
4556  {
4557  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
4558  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
4559  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
4560  env(noop(fiona), seq(seqFiona++), fee(--feeDrops), ter(terQUEUED));
4561  }
4562  checkMetrics(__LINE__, env, 41, 50, 9, 8, 256);
4563  env.close();
4564  checkMetrics(__LINE__, env, 29, 50, 10, 9, 256);
4565 
4566  // Finally the stage is set. alice's and bob's transactions expired
4567  // out of the queue which caused the dropPenalty flag to be set on
4568  // their accounts.
4569  //
4570  // This also means that alice has a sequence gap in her transactions,
4571  // and thus can't queue any more.
4572  env(noop(alice), seq(seqAlice), fee(hiFee), ter(telCAN_NOT_QUEUE));
4573 
4574  // Once again, fill the queue almost to the brim.
4575  feeDrops = medFee;
4576  for (int i = 0; i < 4; ++i)
4577  {
4578  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
4579  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
4580  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
4581  env(noop(fiona), seq(seqFiona++), fee(--feeDrops), ter(terQUEUED));
4582  }
4583  env(noop(carol), seq(seqCarol++), fee(--feeDrops), ter(terQUEUED));
4584  env(noop(daria), seq(seqDaria++), fee(--feeDrops), ter(terQUEUED));
4585  env(noop(ellie), seq(seqEllie++), fee(--feeDrops), ter(terQUEUED));
4586  checkMetrics(__LINE__, env, 48, 50, 10, 9, 256);
4587 
4588  // Now induce a fee jump which should cause all the transactions
4589  // in the queue to fail with telINSUF_FEE_P.
4590  //
4591  // *NOTE* raiseLocalFee() is tricky to use since the local fee is
4592  // asynchronously lowered by LoadManager. Here we're just
4593  // pushing the local fee up really high and then hoping that we
4594  // outrace LoadManager undoing our work.
4595  for (int i = 0; i < 30; ++i)
4596  env.app().getFeeTrack().raiseLocalFee();
4597 
4598  // Now close the ledger, which will attempt to process alice's
4599  // and bob's queued transactions.
4600  // o The _last_ transaction should be dropped from alice's queue.
4601  // o The first failing transaction should be dropped from bob's queue.
4602  env.close();
4603  checkMetrics(__LINE__, env, 46, 50, 0, 10, 256);
4604 
4605  // Run the local fee back down.
4606  while (env.app().getFeeTrack().lowerLocalFee())
4607  ;
4608 
4609  // bob fills the ledger so it's easier to probe the TxQ.
4610  fillQueue(env, bob);
4611  checkMetrics(__LINE__, env, 46, 50, 11, 10, 256);
4612 
4613  // Before the close() alice had two transactions in her queue.
4614  // We now expect her to have one. Here's the state of alice's queue.
4615  //
4616  // 0. The transaction that used to be first in her queue expired
4617  // out two env.close() calls back. That left a gap in alice's
4618  // queue which has not been filled yet.
4619  //
4620  // 1. The first transaction in the queue failed to apply because
4621  // of the sequence gap. But it is retained in the queue.
4622  //
4623  // 2. The last (second) transaction in alice's queue was removed
4624  // as "punishment"...
4625  // a) For already having a transaction expire out of her queue, and
4626  // b) For just now having a queued transaction fail on apply()
4627  // because of the sequence gap.
4628  //
4629  // Verify that none of alice's queued transactions actually applied to
4630  // her account.
4631  BEAST_EXPECT(env.seq(alice) == seqSaveAlice);
4632  seqAlice = seqSaveAlice;
4633 
4634  // Verify that there's a gap at the front of alice's queue by
4635  // queuing another low fee transaction into that spot.
4636  env(noop(alice), seq(seqAlice++), fee(11), ter(terQUEUED));
4637 
4638  // Verify that the first entry in alice's queue is still there
4639  // by trying to replace it and having that fail.
4640  env(noop(alice), seq(seqAlice++), ter(telCAN_NOT_QUEUE_FEE));
4641 
4642  // Verify that the last transaction in alice's queue was removed by
4643  // appending to her queue with a very low fee.
4644  env(noop(alice), seq(seqAlice++), ter(terQUEUED));
4645 
4646  // Before the close() bob had two transactions in his queue.
4647  // We now expect him to have one. Here's the state of bob's queue.
4648  //
4649  // 0. The transaction that used to be first in his queue expired out
4650  // two env.close() calls back. That is how the dropPenalty flag
4651  // got set on bob's queue.
4652  //
4653  // 1. Since bob's remaining transactions all have the same fee, the
4654  // TxQ attempted to apply bob's second transaction to the ledger,
4655  // but the fee was too low. So the TxQ threw that transaction
4656  // (not bob's last transaction) out of the queue.
4657  //
4658  // 2. The last of bob's transactions remains in the TxQ.
4659 
4660  // Verify that bob's first transaction was removed from the queue
4661  // by queueing another low fee transaction into that spot.
4662  env(noop(bob), ticket::use(bobTicketSeq + 0), fee(12), ter(terQUEUED));
4663 
4664  // Verify that bob's second transaction was removed from the queue
4665  // by queueing another low fee transaction into that spot.
4666  env(noop(bob), ticket::use(bobTicketSeq + 1), fee(11), ter(terQUEUED));
4667 
4668  // Verify that the last entry in bob's queue is still there
4669  // by trying to replace it and having that fail.
4670  env(noop(bob),
4671  ticket::use(bobTicketSeq + 2),
4673  }
4674 
4675  void
4677  {
4678  testcase("Cancel queued offers");
4679  using namespace jtx;
4680 
4681  Account const alice("alice");
4682  auto gw = Account("gw");
4683  auto USD = gw["USD"];
4684 
4685  auto cfg = makeConfig(
4686  {{"minimum_txn_in_ledger_standalone", "5"},
4687  {"ledgers_in_queue", "5"},
4688  {"maximum_txn_per_account", "30"},
4689  {"minimum_queue_size", "50"}});
4690 
4691  Env env(*this, std::move(cfg));
4692 
4693  // The noripple is to reduce the number of transactions required to
4694  // fund the accounts. There is no rippling in this test.
4695  env.fund(XRP(100000), noripple(alice));
4696  env.close();
4697 
4698  {
4699  // ------- Sequence-based transactions -------
4700  fillQueue(env, alice);
4701 
4702  // Alice creates a couple offers
4703  auto const aliceSeq = env.seq(alice);
4704  env(offer(alice, USD(1000), XRP(1000)), ter(terQUEUED));
4705 
4706  env(offer(alice, USD(1000), XRP(1001)),
4707  seq(aliceSeq + 1),
4708  ter(terQUEUED));
4709 
4710  // Alice creates transactions that cancel the first set of
4711  // offers, one through another offer, and one cancel
4712  env(offer(alice, USD(1000), XRP(1002)),
4713  seq(aliceSeq + 2),
4714  json(jss::OfferSequence, aliceSeq),
4715  ter(terQUEUED));
4716 
4717  env(offer_cancel(alice, aliceSeq + 1),
4718  seq(aliceSeq + 3),
4719  ter(terQUEUED));
4720 
4721  env.close();
4722 
4723  checkMetrics(__LINE__, env, 0, 50, 4, 6, 256);
4724  }
4725 
4726  {
4727  // ------- Ticket-based transactions -------
4728 
4729  // Alice creates some tickets
4730  auto const aliceTkt = env.seq(alice);
4731  env(ticket::create(alice, 6));
4732  env.close();
4733 
4734  fillQueue(env, alice);
4735 
4736  // Alice creates a couple offers using tickets, consuming the
4737  // tickets in reverse order
4738  auto const aliceSeq = env.seq(alice);
4739  env(offer(alice, USD(1000), XRP(1000)),
4740  ticket::use(aliceTkt + 4),
4741  ter(terQUEUED));
4742 
4743  env(offer(alice, USD(1000), XRP(1001)),
4744  ticket::use(aliceTkt + 3),
4745  ter(terQUEUED));
4746 
4747  // Alice creates a couple more transactions that cancel the first
4748  // set of offers, also in reverse order. This allows Alice to submit
4749  // a tx with a lower ticket value than the offer it's cancelling.
4750  // These transactions succeed because Ticket ordering is arbitrary
4751  // and it's up to the user to ensure they don't step on their own
4752  // feet.
4753  env(offer(alice, USD(1000), XRP(1002)),
4754  ticket::use(aliceTkt + 2),
4755  json(jss::OfferSequence, aliceTkt + 4),
4756  ter(terQUEUED));
4757 
4758  env(offer_cancel(alice, aliceTkt + 3),
4759  ticket::use(aliceTkt + 1),
4760  ter(terQUEUED));
4761 
4762  // Create a couple more offers using sequences
4763  env(offer(alice, USD(1000), XRP(1000)), ter(terQUEUED));
4764 
4765  env(offer(alice, USD(1000), XRP(1001)),
4766  seq(aliceSeq + 1),
4767  ter(terQUEUED));
4768 
4769  // And try to cancel those using tickets
4770  env(offer(alice, USD(1000), XRP(1002)),
4771  ticket::use(aliceTkt + 5),
4772  json(jss::OfferSequence, aliceSeq),
4773  ter(terQUEUED));
4774 
4775  env(offer_cancel(alice, aliceSeq + 1),
4776  ticket::use(aliceTkt + 6),
4777  ter(terQUEUED));
4778 
4779  env.close();
4780 
4781  // The ticket transactions that didn't succeed or get queued succeed
4782  // this time because the tickets got consumed when the offers came
4783  // out of the queue
4784  checkMetrics(__LINE__, env, 0, 50, 8, 7, 256);
4785  }
4786  }
4787 
4788  void
4789  run() override
4790  {
4791  testQueueSeq();
4792  testQueueTicket();
4793  testTecResult();
4794  testLocalTxRetry();
4796  testZeroFeeTxn();
4800  testTieBreaking();
4801  testAcctTxnID();
4802  testMaximum();
4804  testBlockersSeq();
4807  testConsequences();
4808  }
4809 
4810  void
4812  {
4814  testRPC();
4818  testAccountInfo();
4819  testServerInfo();
4822  testScaling();
4823  testInLedgerSeq();
4828  }
4829 };
4830 
4831 class TxQ2_test : public TxQ1_test
4832 {
4833  void
4834  run() override
4835  {
4836  run2();
4837  }
4838 };
4839 
4840 BEAST_DEFINE_TESTSUITE_PRIO(TxQ1, app, ripple, 1);
4841 BEAST_DEFINE_TESTSUITE_PRIO(TxQ2, app, ripple, 1);
4842 
4843 } // namespace test
4844 } // namespace ripple
ripple::test::TxQ1_test::testInLedgerSeq
void testInLedgerSeq()
Definition: TxQ_test.cpp:4119
ripple::tecUNFUNDED_OFFER
@ tecUNFUNDED_OFFER
Definition: TER.h:248
ripple::test::jtx::json
Inject raw JSON.
Definition: jtx_json.h:31
ripple::tefNO_TICKET
@ tefNO_TICKET
Definition: TER.h:164
ripple::test::jtx::noop
Json::Value noop(Account const &account)
The null transaction.
Definition: noop.h:31
ripple::test::TxQ1_test::testInLedgerTicket
void testInLedgerTicket()
Definition: TxQ_test.cpp:4188
ripple::terPRE_TICKET
@ terPRE_TICKET
Definition: TER.h:204
ripple::getMajorityAmendments
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition: View.cpp:621
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::test::TxQ1_test::testQueueTicket
void testQueueTicket()
Definition: TxQ_test.cpp:443
ripple::test::TxQ1_test::testServerInfo
void testServerInfo()
Definition: TxQ_test.cpp:3367
ripple::test::TxQ1_test::testQueueFullDropPenalty
void testQueueFullDropPenalty()
Definition: TxQ_test.cpp:4439
ripple::test::TxQ1_test::testLocalTxRetry
void testLocalTxRetry()
Definition: TxQ_test.cpp:736
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
ripple::terINSUF_FEE_B
@ terINSUF_FEE_B
Definition: TER.h:194
ripple::test::TxQ1_test::testUnexpectedBalanceChange
void testUnexpectedBalanceChange()
Definition: TxQ_test.cpp:1728
ripple::apply
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
ripple::test::jtx::ter
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
ripple::test::jtx::owners
Match the number of items in the account's owner directory.
Definition: owners.h:69
ripple::test::TxQ1_test::submitParams
auto submitParams
Definition: TxQ_test.cpp:3156
ripple::test::jtx::Env::require
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:466
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::test::TxQ1_test::openLedgerFee
auto openLedgerFee(jtx::Env &env)
Definition: TxQ_test.cpp:141
ripple::XRPAmount::drops
constexpr value_type drops() const
Returns the number of drops.
Definition: XRPAmount.h:172
ripple::test::jtx::balance
A balance matches.
Definition: balance.h:38
ripple::test::TxQ1_test::testMaximum
void testMaximum()
Definition: TxQ_test.cpp:1630
ripple::telCAN_NOT_QUEUE_FEE
@ telCAN_NOT_QUEUE_FEE
Definition: TER.h:62
ripple::OpenView
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:55
ripple::TxQ::getTxs
std::vector< TxDetails > getTxs() const
Returns information about all transactions currently in the queue.
Definition: TxQ.cpp:1794
ripple::test::jtx::trust
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition: trust.cpp:30
std::optional::value_or
T value_or(T... args)
ripple::test::jtx::Env::jt
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition: Env.h:439
ripple::test::TxQ2_test
Definition: TxQ_test.cpp:4831
ripple::test::jtx::offer_cancel
Json::Value offer_cancel(Account const &account, std::uint32_t offerSeq)
Cancel an offer.
Definition: offer.cpp:45
ripple::test::jtx::require
Check a set of conditions.
Definition: require.h:63
ripple::SeqProxy::sequence
static constexpr SeqProxy sequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition: SeqProxy.h:76
ripple::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:144
ripple::telCAN_NOT_QUEUE_FULL
@ telCAN_NOT_QUEUE_FULL
Definition: TER.h:63
ripple::test::TxQ1_test::withoutQueue
const auto withoutQueue
Definition: TxQ_test.cpp:3102
ripple::telCAN_NOT_QUEUE
@ telCAN_NOT_QUEUE
Definition: TER.h:58
ripple::test::jtx::Env::balance
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition: Env.cpp:180
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:241
ripple::preflight
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:473
ripple::test::TxQ1_test::testMultiTxnPerAccount
void testMultiTxnPerAccount()
Definition: TxQ_test.cpp:1075
ripple::test::TxQ1_test::testLastLedgerSeq
void testLastLedgerSeq()
Definition: TxQ_test.cpp:793
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:49
ripple::Application::openLedger
virtual OpenLedger & openLedger()=0
ripple::toFeeLevel
FeeLevel64 toFeeLevel(XRPAmount const &drops, XRPAmount const &baseFee)
Definition: TxQ.h:872
ripple::tapNONE
@ tapNONE
Definition: ApplyView.h:30
ripple::test::TxQ1_test::testTecResult
void testTecResult()
Definition: TxQ_test.cpp:700
ripple::test::TxQ1_test::testQueuedTxFails
void testQueuedTxFails()
Definition: TxQ_test.cpp:1024
ripple::test::BEAST_DEFINE_TESTSUITE_PRIO
BEAST_DEFINE_TESTSUITE_PRIO(AccountDelete, app, ripple, 2)
ripple::test::TxQ1_test::queued
auto const & queued
Definition: TxQ_test.cpp:3188
ripple::test::TxQ1_test::result
auto const & result
Definition: TxQ_test.cpp:3121
ripple::Application::getFeeTrack
virtual LoadFeeTrack & getFeeTrack()=0
ripple::test::TxQ1_test::testBlockersTicket
void testBlockersTicket()
Definition: TxQ_test.cpp:1955
ripple::terQUEUED
@ terQUEUED
Definition: TER.h:203
std::tie
T tie(T... args)
ripple::LoadFeeTrack::getRemoteFee
std::uint32_t getRemoteFee() const
Definition: LoadFeeTrack.h:68
ripple::detail::numUpVotedAmendments
std::size_t numUpVotedAmendments()
Amendments that this server will vote for by default.
Definition: Feature.cpp:333
ripple::test::jtx::ticket::use
Set a ticket sequence on a JTx.
Definition: ticket.h:47
ripple::test::TxQ2_test::run
void run() override
Definition: TxQ_test.cpp:4834
ripple::toDrops
XRPAmount toDrops(FeeLevel< T > const &level, XRPAmount const &baseFee)
Definition: TxQ.h:863
ripple::test::TxQ1_test::checkMetrics
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:42
ripple::test::TxQ1_test::data
auto const & data
Definition: TxQ_test.cpp:3169
ripple::TxQ::getAccountTxs
std::vector< TxDetails > getAccountTxs(AccountID const &account) const
Returns information about the transactions currently in the queue for the account.
Definition: TxQ.cpp:1773
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::RPC::contains_error
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:194
ripple::test::TxQ1_test::testBlockersSeq
void testBlockersSeq()
Definition: TxQ_test.cpp:1825
ripple::test::jtx::Env::postconditions
void postconditions(JTx const &jt, TER ter, bool didApply)
Check expected postconditions of JTx submission.
Definition: Env.cpp:346
ripple::JsonOptions::none
@ none
ripple::Application::config
virtual Config & config()=0
ripple::TERSubset< CanCvtToTER >
ripple::test::jtx::sendmax
Sets the SendMax on a JTx.
Definition: sendmax.h:31
ripple::test::TxQ1_test::prevLedgerWithQueue
const auto prevLedgerWithQueue
Definition: TxQ_test.cpp:3103
ripple::Application::getTxQ
virtual TxQ & getTxQ()=0
ripple::test::TxQ1_test::testRPC
void testRPC()
Definition: TxQ_test.cpp:2634
ripple::test::jtx::fset
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:28
std::to_string
T to_string(T... args)
ripple::test::reserve
static XRPAmount reserve(jtx::Env &env, std::uint32_t count)
Definition: DepositAuth_test.cpp:29
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
ripple::test::TxQ1_test::envs
envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams)
std::runtime_error
STL class.
ripple::temBAD_AMOUNT
@ temBAD_AMOUNT
Definition: TER.h:84
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::test::TxQ1_test::testExpirationReplacement
void testExpirationReplacement()
Definition: TxQ_test.cpp:2698
std::uint64_t
ripple::test::jtx::Account::master
static const Account master
The master account.
Definition: Account.h:47
ripple::test::jtx::Env::seq
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:204
ripple::feeunit::TaggedFee
Definition: FeeUnits.h:70
std::map< std::string, std::string >
ripple::test::TxQ1_test::run2
void run2()
Definition: TxQ_test.cpp:4811
ripple::test::jtx::Env_ss
A transaction testing environment wrapper.
Definition: Env_ss.h:33
ripple::telCAN_NOT_QUEUE_BLOCKS
@ telCAN_NOT_QUEUE_BLOCKS
Definition: TER.h:60
ripple::test::TxQ1_test::testConsequences
void testConsequences()
Definition: TxQ_test.cpp:2471
ripple::test::TxQ1_test::testServerSubscribe
void testServerSubscribe()
Definition: TxQ_test.cpp:3628
ripple::test::jtx::fee
Set the fee on a JTx.
Definition: fee.h:35
ripple::TxQ::Metrics::referenceFeeLevel
FeeLevel64 referenceFeeLevel
Reference transaction fee level.
Definition: TxQ.h:175
ripple::terNO_ACCOUNT
@ terNO_ACCOUNT
Definition: TER.h:195
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:33
ripple::test::TxQ1_test::testZeroFeeTxn
void testZeroFeeTxn()
Definition: TxQ_test.cpp:903
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::jtx::noripple
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
ripple::LoadFeeTrack::getLoadFactor
std::uint32_t getLoadFactor() const
Definition: LoadFeeTrack.h:95
ripple::tapUNLIMITED
@ tapUNLIMITED
Definition: ApplyView.h:41
ripple::test::TxQ1_test::testAcctTxnID
void testAcctTxnID()
Definition: TxQ_test.cpp:1591
ripple::LoadFeeTrack::raiseLocalFee
bool raiseLocalFee()
Definition: LoadFeeTrack.cpp:37
ripple::tefPAST_SEQ
@ tefPAST_SEQ
Definition: TER.h:154
ripple::test::jtx::pay
Json::Value pay(Account const &account, Account const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
ripple::test::jtx::Env::now
NetClock::time_point now()
Returns the current network time.
Definition: Env.h:264
ripple::test::TxQ1_test::queue_data
auto const & queue_data
Definition: TxQ_test.cpp:3123
ripple::test::jtx::regkey
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Definition: regkey.cpp:28
ripple::test::TxQ1_test::fillQueue
void fillQueue(jtx::Env &env, jtx::Account const &account)
Definition: TxQ_test.cpp:133
ripple::test::TxQ1_test::testCancelQueuedOffers
void testCancelQueuedOffers()
Definition: TxQ_test.cpp:4676
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:225
ripple::test::jtx::Env::le
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:213
ripple::test::TxQ1_test::testInFlightBalance
void testInFlightBalance()
Definition: TxQ_test.cpp:2117
ripple::TxQ::Metrics::txInLedger
std::size_t txInLedger
Number of transactions currently in the open ledger.
Definition: TxQ.h:171
ripple::test::jtx::Env::master
Account const & master
Definition: Env.h:121
ripple::test::TxQ1_test::BEAST_EXPECT
BEAST_EXPECT(env.current() ->info().seq > 3)
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::SeqProxy
A type that represents either a sequence value or a ticket value.
Definition: SeqProxy.h:55
ripple::tefWRONG_PRIOR
@ tefWRONG_PRIOR
Definition: TER.h:155
ripple::test::TxQ1_test::testClearQueuedAccountTxs
void testClearQueuedAccountTxs()
Definition: TxQ_test.cpp:3773
ripple::test::makeWSClient
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
std::map::empty
T empty(T... args)
ripple::test::TxQ1_test::testQueueSeq
void testQueueSeq()
Definition: TxQ_test.cpp:231
ripple::terPRE_SEQ
@ terPRE_SEQ
Definition: TER.h:199
std::optional< std::size_t >
std::size_t
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::test::TxQ1_test
Definition: TxQ_test.cpp:39
ripple::test::TxQ1_test::testTieBreaking
void testTieBreaking()
Definition: TxQ_test.cpp:1345
ripple::test::TxQ1_test::run
void run() override
Definition: TxQ_test.cpp:4789
ripple::TxQ::getMetrics
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
Definition: TxQ.cpp:1730
ripple::LoadFeeTrack::setRemoteFee
void setRemoteFee(std::uint32_t f)
Definition: LoadFeeTrack.h:60
ripple::test::jtx::Env::memoize
void memoize(Account const &account)
Associate AccountID with account.
Definition: Env.cpp:156
std::unique_ptr
STL class.
ripple::telCAN_NOT_QUEUE_BALANCE
@ telCAN_NOT_QUEUE_BALANCE
Definition: TER.h:59
ripple::test::TxQ1_test::testReexecutePreflight
void testReexecutePreflight()
Definition: TxQ_test.cpp:4283
ripple::test::TxQ1_test::initFee
std::size_t initFee(jtx::Env &env, std::size_t expectedPerLedger, std::size_t ledgersInQueue, std::uint32_t base, std::uint32_t units, std::uint32_t reserve, std::uint32_t increment)
Definition: TxQ_test.cpp:187
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:219
ripple::test::TxQ1_test::testFailInPreclaim
void testFailInPreclaim()
Definition: TxQ_test.cpp:1000
ripple::asfAccountTxnID
constexpr std::uint32_t asfAccountTxnID
Definition: TxFlags.h:76
ripple::test::TxQ1_test::testAcctInQueueButEmpty
void testAcctInQueueButEmpty()
Definition: TxQ_test.cpp:2529
ripple::OpenLedger::modify
bool modify(modify_type const &f)
Modify the open ledger.
Definition: OpenLedger.cpp:57
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:300
ripple::test::TxQ1_test::testAccountInfo
void testAccountInfo()
Definition: TxQ_test.cpp:3088
ripple::test::TxQ1_test::testFullQueueGapFill
void testFullQueueGapFill()
Definition: TxQ_test.cpp:2799
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::test::TxQ1_test::makeConfig
static std::unique_ptr< Config > makeConfig(std::map< std::string, std::string > extraTxQ={}, std::map< std::string, std::string > extraVoting={})
Definition: TxQ_test.cpp:153
ripple::test::TxQ1_test::testScaling
void testScaling()
Definition: TxQ_test.cpp:3979
std::runtime_error::what
T what(T... args)
ripple::test::jtx::Env::rpc
Json::Value rpc(std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:684
ripple::telCAN_NOT_QUEUE_BLOCKED
@ telCAN_NOT_QUEUE_BLOCKED
Definition: TER.h:61
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::TxQ1_test::testSignAndSubmitSequence
void testSignAndSubmitSequence()
Definition: TxQ_test.cpp:2958
ripple::XRPAmount
Definition: XRPAmount.h:46
ripple::test::jtx::owner_count
Definition: owners.h:49
std::chrono