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