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