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