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