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