rippled
TxQ_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/main/Application.h>
21 #include <ripple/app/misc/LoadFeeTrack.h>
22 #include <ripple/app/misc/TxQ.h>
23 #include <ripple/app/tx/apply.h>
24 #include <ripple/basics/Log.h>
25 #include <ripple/basics/mulDiv.h>
26 #include <ripple/protocol/ErrorCodes.h>
27 #include <ripple/protocol/Feature.h>
28 #include <ripple/protocol/jss.h>
29 #include <ripple/protocol/st.h>
30 #include <boost/optional.hpp>
31 #include <test/jtx.h>
32 #include <test/jtx/TestSuite.h>
33 #include <test/jtx/WSClient.h>
34 #include <test/jtx/envconfig.h>
35 #include <test/jtx/ticket.h>
36 
37 namespace ripple {
38 
39 namespace test {
40 
41 class TxQ_test : public beast::unit_test::suite
42 {
43  void
45  jtx::Env& env,
46  std::size_t expectedCount,
47  boost::optional<std::size_t> expectedMaxCount,
48  std::size_t expectedInLedger,
49  std::size_t expectedPerLedger,
50  std::uint64_t expectedMinFeeLevel,
51  std::uint64_t expectedMedFeeLevel = 256 * 500)
52  {
53  FeeLevel64 const expectedMin{expectedMinFeeLevel};
54  FeeLevel64 const expectedMed{expectedMedFeeLevel};
55  auto const metrics = env.app().getTxQ().getMetrics(*env.current());
56  BEAST_EXPECT(metrics.referenceFeeLevel == FeeLevel64{256});
57  BEAST_EXPECT(metrics.txCount == expectedCount);
58  BEAST_EXPECT(metrics.txQMaxSize == expectedMaxCount);
59  BEAST_EXPECT(metrics.txInLedger == expectedInLedger);
60  BEAST_EXPECT(metrics.txPerLedger == expectedPerLedger);
61  BEAST_EXPECT(metrics.minProcessingFeeLevel == expectedMin);
62  BEAST_EXPECT(metrics.medFeeLevel == expectedMed);
63  auto expectedCurFeeLevel = expectedInLedger > expectedPerLedger
64  ? expectedMed * expectedInLedger * expectedInLedger /
65  (expectedPerLedger * expectedPerLedger)
66  : metrics.referenceFeeLevel;
67  BEAST_EXPECT(metrics.openLedgerFeeLevel == expectedCurFeeLevel);
68  }
69 
70  void
71  fillQueue(jtx::Env& env, jtx::Account const& account)
72  {
73  auto metrics = env.app().getTxQ().getMetrics(*env.current());
74  for (int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
75  env(noop(account));
76  }
77 
78  auto
80  {
81  using namespace jtx;
82 
83  auto const& view = *env.current();
84  auto metrics = env.app().getTxQ().getMetrics(view);
85 
86  // Don't care about the overflow flag
87  return fee(
88  toDrops(metrics.openLedgerFeeLevel, view.fees().base).second + 1);
89  }
90 
94  std::map<std::string, std::string> extraVoting = {})
95  {
96  auto p = test::jtx::envconfig();
97  auto& section = p->section("transaction_queue");
98  section.set("ledgers_in_queue", "2");
99  section.set("minimum_queue_size", "2");
100  section.set("min_ledgers_to_compute_size_limit", "3");
101  section.set("max_ledger_counts_to_store", "100");
102  section.set("retry_sequence_percent", "25");
103  section.set("zero_basefee_transaction_feelevel", "100000000000");
104  section.set("normal_consensus_increase_percent", "0");
105 
106  for (auto const& [k, v] : extraTxQ)
107  section.set(k, v);
108 
109  // Some tests specify different fee settings that are enabled by
110  // a FeeVote
111  if (!extraVoting.empty())
112  {
113  auto& votingSection = p->section("voting");
114  for (auto const& [k, v] : extraVoting)
115  {
116  votingSection.set(k, v);
117  }
118 
119  // In order for the vote to occur, we must run as a validator
120  p->section("validation_seed")
121  .legacy("shUwVw52ofnCUX5m7kPTKzJdr4HEH");
122  }
123  return p;
124  }
125 
128  jtx::Env& env,
129  std::size_t expectedPerLedger,
130  std::size_t ledgersInQueue,
131  std::uint32_t base,
132  std::uint32_t units,
134  std::uint32_t increment)
135  {
136  // Run past the flag ledger so that a Fee change vote occurs and
137  // lowers the reserve fee. (It also activates all supported
138  // amendments.) This will allow creating accounts with lower
139  // reserves and balances.
140  for (auto i = env.current()->seq(); i <= 257; ++i)
141  env.close();
142  // The ledger after the flag ledger creates all the
143  // fee (1) and amendment (supportedAmendments().size())
144  // pseudotransactions. They all have 0 fee, which is
145  // treated as a high fee level by the queue, so the
146  // medianFeeLevel is 100000000000.
147  auto const flagPerLedger =
149  auto const flagMaxQueue = ledgersInQueue * flagPerLedger;
150  checkMetrics(env, 0, flagMaxQueue, 0, flagPerLedger, 256, 100000000000);
151 
152  // Pad a couple of txs with normal fees so the median comes
153  // back down to normal
154  env(noop(env.master));
155  env(noop(env.master));
156 
157  // Close the ledger with a delay, which causes all the TxQ
158  // metrics to reset to defaults, EXCEPT the maxQueue size.
159  using namespace std::chrono_literals;
160  env.close(env.now() + 5s, 10000ms);
161  checkMetrics(env, 0, flagMaxQueue, 0, expectedPerLedger, 256);
162  auto const fees = env.current()->fees();
163  BEAST_EXPECT(fees.base == XRPAmount{base});
164  BEAST_EXPECT(fees.units == FeeUnit64{units});
165  BEAST_EXPECT(fees.reserve == XRPAmount{reserve});
166  BEAST_EXPECT(fees.increment == XRPAmount{increment});
167 
168  return flagMaxQueue;
169  }
170 
171 public:
172  void
174  {
175  using namespace jtx;
176  using namespace std::chrono;
177 
178  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
179  auto& txq = env.app().getTxQ();
180 
181  auto alice = Account("alice");
182  auto bob = Account("bob");
183  auto charlie = Account("charlie");
184  auto daria = Account("daria");
185  auto elmo = Account("elmo");
186  auto fred = Account("fred");
187  auto gwen = Account("gwen");
188  auto hank = Account("hank");
189 
190  auto queued = ter(terQUEUED);
191 
192  BEAST_EXPECT(env.current()->fees().base == 10);
193 
194  checkMetrics(env, 0, boost::none, 0, 3, 256);
195 
196  // Create several accounts while the fee is cheap so they all apply.
197  env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
198  checkMetrics(env, 0, boost::none, 4, 3, 256);
199 
200  // Alice - price starts exploding: held
201  env(noop(alice), queued);
202  checkMetrics(env, 1, boost::none, 4, 3, 256);
203 
204  // Bob with really high fee - applies
205  env(noop(bob), openLedgerFee(env));
206  checkMetrics(env, 1, boost::none, 5, 3, 256);
207 
208  // Daria with low fee: hold
209  env(noop(daria), fee(1000), queued);
210  checkMetrics(env, 2, boost::none, 5, 3, 256);
211 
212  env.close();
213  // Verify that the held transactions got applied
214  checkMetrics(env, 0, 10, 2, 5, 256);
215 
217 
218  // Make some more accounts. We'll need them later to abuse the queue.
219  env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
220  checkMetrics(env, 0, 10, 6, 5, 256);
221 
222  // Now get a bunch of transactions held.
223  env(noop(alice), fee(12), queued);
224  checkMetrics(env, 1, 10, 6, 5, 256);
225 
226  env(noop(bob), fee(10), queued); // won't clear the queue
227  env(noop(charlie), fee(20), queued);
228  env(noop(daria), fee(15), queued);
229  env(noop(elmo), fee(11), queued);
230  env(noop(fred), fee(19), queued);
231  env(noop(gwen), fee(16), queued);
232  env(noop(hank), fee(18), queued);
233  checkMetrics(env, 8, 10, 6, 5, 256);
234 
235  env.close();
236  // Verify that the held transactions got applied
237  checkMetrics(env, 1, 12, 7, 6, 256);
238 
239  // Bob's transaction is still stuck in the queue.
240 
242 
243  // Hank sends another txn
244  env(noop(hank), fee(10), queued);
245  // But he's not going to leave it in the queue
246  checkMetrics(env, 2, 12, 7, 6, 256);
247 
248  // Hank sees his txn got held and bumps the fee,
249  // but doesn't even bump it enough to requeue
250  env(noop(hank), fee(11), ter(telCAN_NOT_QUEUE_FEE));
251  checkMetrics(env, 2, 12, 7, 6, 256);
252 
253  // Hank sees his txn got held and bumps the fee,
254  // enough to requeue, but doesn't bump it enough to
255  // apply to the ledger
256  env(noop(hank), fee(6000), queued);
257  // But he's not going to leave it in the queue
258  checkMetrics(env, 2, 12, 7, 6, 256);
259 
260  // Hank sees his txn got held and bumps the fee,
261  // high enough to get into the open ledger, because
262  // he doesn't want to wait.
263  env(noop(hank), openLedgerFee(env));
264  checkMetrics(env, 1, 12, 8, 6, 256);
265 
266  // Hank then sends another, less important txn
267  // (In addition to the metrics, this will verify that
268  // the original txn got removed.)
269  env(noop(hank), fee(6000), queued);
270  checkMetrics(env, 2, 12, 8, 6, 256);
271 
272  env.close();
273 
274  // Verify that bob and hank's txns were applied
275  checkMetrics(env, 0, 16, 2, 8, 256);
276 
277  // Close again with a simulated time leap to
278  // reset the escalation limit down to minimum
279  env.close(env.now() + 5s, 10000ms);
280  checkMetrics(env, 0, 16, 0, 3, 256);
281  // Then close once more without the time leap
282  // to reset the queue maxsize down to minimum
283  env.close();
284  checkMetrics(env, 0, 6, 0, 3, 256);
285 
287 
288  // Stuff the ledger and queue so we can verify that
289  // stuff gets kicked out.
290  env(noop(hank), fee(7000));
291  env(noop(gwen), fee(7000));
292  env(noop(fred), fee(7000));
293  env(noop(elmo), fee(7000));
294  checkMetrics(env, 0, 6, 4, 3, 256);
295 
296  // Use explicit fees so we can control which txn
297  // will get dropped
298  // This one gets into the queue, but gets dropped when the
299  // higher fee one is added later.
300  env(noop(daria), fee(15), queued);
301  // These stay in the queue.
302  env(noop(elmo), fee(16), queued);
303  env(noop(fred), fee(17), queued);
304  env(noop(gwen), fee(18), queued);
305  env(noop(hank), fee(19), queued);
306  env(noop(alice), fee(20), queued);
307 
308  // Queue is full now.
309  checkMetrics(env, 6, 6, 4, 3, 385);
310 
311  // Try to add another transaction with the default (low) fee,
312  // it should fail because the queue is full.
313  env(noop(charlie), ter(telCAN_NOT_QUEUE_FULL));
314 
315  // Add another transaction, with a higher fee,
316  // Not high enough to get into the ledger, but high
317  // enough to get into the queue (and kick somebody out)
318  env(noop(charlie), fee(100), queued);
319 
320  // Queue is still full, of course, but the min fee has gone up
321  checkMetrics(env, 6, 6, 4, 3, 410);
322 
323  // Close out the ledger, the transactions are accepted, the
324  // queue is cleared, then the localTxs are retried. At this
325  // point, daria's transaction that was dropped from the queue
326  // is put back in. Neat.
327  env.close();
328  checkMetrics(env, 2, 8, 5, 4, 256, 256 * 700);
329 
330  env.close();
331  checkMetrics(env, 0, 10, 2, 5, 256);
332 
334  // Cleanup:
335 
336  // Create a few more transactions, so that
337  // we can be sure that there's one in the queue when the
338  // test ends and the TxQ is destructed.
339 
340  auto metrics = txq.getMetrics(*env.current());
341  BEAST_EXPECT(metrics.txCount == 0);
342 
343  // Stuff the ledger.
344  for (int i = metrics.txInLedger; i <= metrics.txPerLedger; ++i)
345  {
346  env(noop(env.master));
347  }
348 
349  // Queue one straightforward transaction
350  env(noop(env.master), fee(20), queued);
351  ++metrics.txCount;
352 
353  checkMetrics(
354  env,
355  metrics.txCount,
356  metrics.txQMaxSize,
357  metrics.txPerLedger + 1,
358  metrics.txPerLedger,
359  256);
360  }
361 
362  void
364  {
365  using namespace jtx;
366 
367  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "2"}}));
368 
369  auto alice = Account("alice");
370  auto gw = Account("gw");
371  auto USD = gw["USD"];
372 
373  checkMetrics(env, 0, boost::none, 0, 2, 256);
374 
375  // Create accounts
376  env.fund(XRP(50000), noripple(alice, gw));
377  checkMetrics(env, 0, boost::none, 2, 2, 256);
378  env.close();
379  checkMetrics(env, 0, 4, 0, 2, 256);
380 
381  // Alice creates an unfunded offer while the ledger is not full
382  env(offer(alice, XRP(1000), USD(1000)), ter(tecUNFUNDED_OFFER));
383  checkMetrics(env, 0, 4, 1, 2, 256);
384 
385  fillQueue(env, alice);
386  checkMetrics(env, 0, 4, 3, 2, 256);
387 
388  // Alice creates an unfunded offer that goes in the queue
389  env(offer(alice, XRP(1000), USD(1000)), ter(terQUEUED));
390  checkMetrics(env, 1, 4, 3, 2, 256);
391 
392  // The offer comes out of the queue
393  env.close();
394  checkMetrics(env, 0, 6, 1, 3, 256);
395  }
396 
397  void
399  {
400  using namespace jtx;
401  using namespace std::chrono;
402 
403  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "2"}}));
404 
405  auto alice = Account("alice");
406  auto bob = Account("bob");
407  auto charlie = Account("charlie");
408 
409  auto queued = ter(terQUEUED);
410 
411  BEAST_EXPECT(env.current()->fees().base == 10);
412 
413  checkMetrics(env, 0, boost::none, 0, 2, 256);
414 
415  // Create several accounts while the fee is cheap so they all apply.
416  env.fund(XRP(50000), noripple(alice, bob, charlie));
417  checkMetrics(env, 0, boost::none, 3, 2, 256);
418 
419  // Future transaction for Alice - fails
420  env(noop(alice),
421  openLedgerFee(env),
422  seq(env.seq(alice) + 1),
423  ter(terPRE_SEQ));
424  checkMetrics(env, 0, boost::none, 3, 2, 256);
425 
426  // Current transaction for Alice: held
427  env(noop(alice), queued);
428  checkMetrics(env, 1, boost::none, 3, 2, 256);
429 
430  // Alice - sequence is too far ahead, so won't queue.
431  env(noop(alice), seq(env.seq(alice) + 2), ter(terPRE_SEQ));
432  checkMetrics(env, 1, boost::none, 3, 2, 256);
433 
434  // Bob with really high fee - applies
435  env(noop(bob), openLedgerFee(env));
436  checkMetrics(env, 1, boost::none, 4, 2, 256);
437 
438  // Daria with low fee: hold
439  env(noop(charlie), fee(1000), queued);
440  checkMetrics(env, 2, boost::none, 4, 2, 256);
441 
442  // Alice with normal fee: hold
443  env(noop(alice), seq(env.seq(alice) + 1), queued);
444  checkMetrics(env, 3, boost::none, 4, 2, 256);
445 
446  env.close();
447  // Verify that the held transactions got applied
448  // Alice's bad transaction applied from the
449  // Local Txs.
450  checkMetrics(env, 0, 8, 4, 4, 256);
451  }
452 
453  void
455  {
456  using namespace jtx;
457  using namespace std::chrono;
458 
459  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "2"}}));
460 
461  auto alice = Account("alice");
462  auto bob = Account("bob");
463  auto charlie = Account("charlie");
464  auto daria = Account("daria");
465  auto edgar = Account("edgar");
466  auto felicia = Account("felicia");
467 
468  auto queued = ter(terQUEUED);
469 
470  checkMetrics(env, 0, boost::none, 0, 2, 256);
471 
472  // Fund across several ledgers so the TxQ metrics stay restricted.
473  env.fund(XRP(1000), noripple(alice, bob));
474  env.close(env.now() + 5s, 10000ms);
475  env.fund(XRP(1000), noripple(charlie, daria));
476  env.close(env.now() + 5s, 10000ms);
477  env.fund(XRP(1000), noripple(edgar, felicia));
478  env.close(env.now() + 5s, 10000ms);
479 
480  checkMetrics(env, 0, boost::none, 0, 2, 256);
481  env(noop(bob));
482  env(noop(charlie));
483  env(noop(daria));
484  checkMetrics(env, 0, boost::none, 3, 2, 256);
485 
486  BEAST_EXPECT(env.current()->info().seq == 6);
487  // Fail to queue an item with a low LastLedgerSeq
488  env(noop(alice),
489  json(R"({"LastLedgerSequence":7})"),
491  // Queue an item with a sufficient LastLedgerSeq.
492  env(noop(alice), json(R"({"LastLedgerSequence":8})"), queued);
493  // Queue items with higher fees to force the previous
494  // txn to wait.
495  env(noop(bob), fee(7000), queued);
496  env(noop(charlie), fee(7000), queued);
497  env(noop(daria), fee(7000), queued);
498  env(noop(edgar), fee(7000), queued);
499  checkMetrics(env, 5, boost::none, 3, 2, 256);
500  {
501  auto& txQ = env.app().getTxQ();
502  auto aliceStat = txQ.getAccountTxs(alice.id(), *env.current());
503  BEAST_EXPECT(aliceStat.size() == 1);
504  BEAST_EXPECT(aliceStat.begin()->second.feeLevel == FeeLevel64{256});
505  BEAST_EXPECT(
506  aliceStat.begin()->second.lastValid &&
507  *aliceStat.begin()->second.lastValid == 8);
508  BEAST_EXPECT(!aliceStat.begin()->second.consequences);
509 
510  auto bobStat = txQ.getAccountTxs(bob.id(), *env.current());
511  BEAST_EXPECT(bobStat.size() == 1);
512  BEAST_EXPECT(
513  bobStat.begin()->second.feeLevel ==
514  FeeLevel64{7000 * 256 / 10});
515  BEAST_EXPECT(!bobStat.begin()->second.lastValid);
516  BEAST_EXPECT(!bobStat.begin()->second.consequences);
517 
518  auto noStat =
519  txQ.getAccountTxs(Account::master.id(), *env.current());
520  BEAST_EXPECT(noStat.empty());
521  }
522 
523  env.close();
524  checkMetrics(env, 1, 6, 4, 3, 256);
525 
526  // Keep alice's transaction waiting.
527  env(noop(bob), fee(7000), queued);
528  env(noop(charlie), fee(7000), queued);
529  env(noop(daria), fee(7000), queued);
530  env(noop(edgar), fee(7000), queued);
531  env(noop(felicia), fee(7000), queued);
532  checkMetrics(env, 6, 6, 4, 3, 257);
533 
534  env.close();
535  // alice's transaction is still hanging around
536  checkMetrics(env, 1, 8, 5, 4, 256, 700 * 256);
537  BEAST_EXPECT(env.seq(alice) == 3);
538 
539  // Keep alice's transaction waiting.
540  env(noop(bob), fee(8000), queued);
541  env(noop(charlie), fee(8000), queued);
542  env(noop(daria), fee(8000), queued);
543  env(noop(daria), fee(8000), seq(env.seq(daria) + 1), queued);
544  env(noop(edgar), fee(8000), queued);
545  env(noop(felicia), fee(8000), queued);
546  env(noop(felicia), fee(8000), seq(env.seq(felicia) + 1), queued);
547  checkMetrics(env, 8, 8, 5, 4, 257, 700 * 256);
548 
549  env.close();
550  // alice's transaction expired without getting
551  // into the ledger, so her transaction is gone,
552  // though one of felicia's is still in the queue.
553  checkMetrics(env, 1, 10, 6, 5, 256, 700 * 256);
554  BEAST_EXPECT(env.seq(alice) == 3);
555 
556  env.close();
557  // And now the queue is empty
558  checkMetrics(env, 0, 12, 1, 6, 256, 800 * 256);
559  BEAST_EXPECT(env.seq(alice) == 3);
560  }
561 
562  void
564  {
565  using namespace jtx;
566  using namespace std::chrono;
567 
568  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "2"}}));
569 
570  auto alice = Account("alice");
571  auto bob = Account("bob");
572  auto carol = Account("carol");
573 
574  auto queued = ter(terQUEUED);
575 
576  checkMetrics(env, 0, boost::none, 0, 2, 256);
577 
578  // Fund across several ledgers so the TxQ metrics stay restricted.
579  env.fund(XRP(1000), noripple(alice, bob));
580  env.close(env.now() + 5s, 10000ms);
581  env.fund(XRP(1000), noripple(carol));
582  env.close(env.now() + 5s, 10000ms);
583 
584  // Fill the ledger
585  env(noop(alice));
586  env(noop(alice));
587  env(noop(alice));
588  checkMetrics(env, 0, boost::none, 3, 2, 256);
589 
590  env(noop(bob), queued);
591  checkMetrics(env, 1, boost::none, 3, 2, 256);
592 
593  // Even though this transaction has a 0 fee,
594  // SetRegularKey::calculateBaseFee indicates this is
595  // a "free" transaction, so it has an "infinite" fee
596  // level and goes into the open ledger.
597  env(regkey(alice, bob), fee(0));
598  checkMetrics(env, 1, boost::none, 4, 2, 256);
599 
600  // Close out this ledger so we can get a maxsize
601  env.close();
602  checkMetrics(env, 0, 8, 1, 4, 256);
603 
604  fillQueue(env, bob);
605  checkMetrics(env, 0, 8, 5, 4, 256);
606 
607  auto feeBob = 30;
608  auto seqBob = env.seq(bob);
609  for (int i = 0; i < 4; ++i)
610  {
611  env(noop(bob), fee(feeBob), seq(seqBob), queued);
612  feeBob = (feeBob + 1) * 125 / 100;
613  ++seqBob;
614  }
615  checkMetrics(env, 4, 8, 5, 4, 256);
616 
617  // This transaction also has an "infinite" fee level,
618  // but since bob has txns in the queue, it gets queued.
619  env(regkey(bob, alice), fee(0), seq(seqBob), queued);
620  ++seqBob;
621  checkMetrics(env, 5, 8, 5, 4, 256);
622 
623  // Unfortunately bob can't get any more txns into
624  // the queue, because of the multiTxnPercent.
625  // TANSTAAFL
626  env(noop(bob), fee(XRP(100)), seq(seqBob), ter(telINSUF_FEE_P));
627 
628  // Carol fills the queue, but can't kick out any
629  // transactions.
630  auto feeCarol = feeBob;
631  auto seqCarol = env.seq(carol);
632  for (int i = 0; i < 3; ++i)
633  {
634  env(noop(carol), fee(feeCarol), seq(seqCarol), queued);
635  feeCarol = (feeCarol + 1) * 125 / 100;
636  ++seqCarol;
637  }
638  checkMetrics(env, 8, 8, 5, 4, 3 * 256 + 1);
639 
640  // Carol doesn't submit high enough to beat Bob's
641  // average fee. (Which is ~144,115,188,075,855,907
642  // because of the zero fee txn.)
643  env(noop(carol),
644  fee(feeCarol),
645  seq(seqCarol),
647 
648  env.close();
649  // Some of Bob's transactions stay in the queue,
650  // and Carol's low fee tx is reapplied from the
651  // Local Txs.
652  checkMetrics(env, 3, 10, 6, 5, 256);
653  BEAST_EXPECT(env.seq(bob) == seqBob - 2);
654  BEAST_EXPECT(env.seq(carol) == seqCarol);
655 
656  env.close();
657  checkMetrics(env, 0, 12, 4, 6, 256);
658  BEAST_EXPECT(env.seq(bob) == seqBob + 1);
659  BEAST_EXPECT(env.seq(carol) == seqCarol + 1);
660 
661  env.close();
662  checkMetrics(env, 0, 12, 0, 6, 256);
663  BEAST_EXPECT(env.seq(bob) == seqBob + 1);
664  BEAST_EXPECT(env.seq(carol) == seqCarol + 1);
665  }
666 
667  void
669  {
670  using namespace jtx;
671 
672  Env env(*this, makeConfig());
673 
674  auto alice = Account("alice");
675  auto bob = Account("bob");
676 
677  env.fund(XRP(1000), noripple(alice));
678 
679  // These types of checks are tested elsewhere, but
680  // this verifies that TxQ handles the failures as
681  // expected.
682 
683  // Fail in preflight
684  env(pay(alice, bob, XRP(-1000)), ter(temBAD_AMOUNT));
685 
686  // Fail in preclaim
687  env(noop(alice), fee(XRP(100000)), ter(terINSUF_FEE_B));
688  }
689 
690  void
692  {
693  using namespace jtx;
694 
695  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "2"}}));
696 
697  auto alice = Account("alice");
698  auto bob = Account("bob");
699 
700  auto queued = ter(terQUEUED);
701 
702  checkMetrics(env, 0, boost::none, 0, 2, 256);
703 
704  env.fund(XRP(1000), noripple(alice, bob));
705 
706  checkMetrics(env, 0, boost::none, 2, 2, 256);
707 
708  // Fill the ledger
709  env(noop(alice));
710  checkMetrics(env, 0, boost::none, 3, 2, 256);
711 
712  // Put a transaction in the queue
713  env(noop(alice), queued);
714  checkMetrics(env, 1, boost::none, 3, 2, 256);
715 
716  // Now cheat, and bypass the queue.
717  {
718  auto const& jt = env.jt(noop(alice));
719  BEAST_EXPECT(jt.stx);
720 
721  bool didApply;
722  TER ter;
723 
724  env.app().openLedger().modify(
725  [&](OpenView& view, beast::Journal j) {
726  std::tie(ter, didApply) = ripple::apply(
727  env.app(), view, *jt.stx, tapNONE, env.journal);
728  return didApply;
729  });
730  env.postconditions(jt, ter, didApply);
731  }
732  checkMetrics(env, 1, boost::none, 4, 2, 256);
733 
734  env.close();
735  // Alice's queued transaction failed in TxQ::accept
736  // with tefPAST_SEQ
737  checkMetrics(env, 0, 8, 0, 4, 256);
738  }
739 
740  void
742  {
743  using namespace jtx;
744 
745  Env env(
746  *this,
747  makeConfig(
748  {{"minimum_txn_in_ledger_standalone", "3"}},
749  {{"account_reserve", "200"}, {"owner_reserve", "50"}}));
750 
751  auto alice = Account("alice");
752  auto bob = Account("bob");
753  auto charlie = Account("charlie");
754  auto daria = Account("daria");
755 
756  auto queued = ter(terQUEUED);
757 
758  BEAST_EXPECT(env.current()->fees().base == 10);
759 
760  checkMetrics(env, 0, boost::none, 0, 3, 256);
761 
762  // ledgers in queue is 2 because of makeConfig
763  auto const initQueueMax = initFee(env, 3, 2, 10, 10, 200, 50);
764 
765  // Create several accounts while the fee is cheap so they all apply.
766  env.fund(drops(2000), noripple(alice));
767  env.fund(XRP(500000), noripple(bob, charlie, daria));
768  checkMetrics(env, 0, initQueueMax, 4, 3, 256);
769 
770  // Alice - price starts exploding: held
771  env(noop(alice), queued);
772  checkMetrics(env, 1, initQueueMax, 4, 3, 256);
773 
774  auto aliceSeq = env.seq(alice);
775  auto bobSeq = env.seq(bob);
776  auto charlieSeq = env.seq(charlie);
777 
778  // Alice - try to queue a second transaction, but leave a gap
779  env(noop(alice), seq(aliceSeq + 2), fee(100), ter(terPRE_SEQ));
780  checkMetrics(env, 1, initQueueMax, 4, 3, 256);
781 
782  // Alice - queue a second transaction. Yay.
783  env(noop(alice), seq(aliceSeq + 1), fee(13), queued);
784  checkMetrics(env, 2, initQueueMax, 4, 3, 256);
785 
786  // Alice - queue a third transaction. Yay.
787  env(noop(alice), seq(aliceSeq + 2), fee(17), queued);
788  checkMetrics(env, 3, initQueueMax, 4, 3, 256);
789 
790  // Bob - queue a transaction
791  env(noop(bob), queued);
792  checkMetrics(env, 4, initQueueMax, 4, 3, 256);
793 
794  // Bob - queue a second transaction
795  env(noop(bob), seq(bobSeq + 1), fee(50), queued);
796  checkMetrics(env, 5, initQueueMax, 4, 3, 256);
797 
798  // Charlie - queue a transaction, with a higher fee
799  // than default
800  env(noop(charlie), fee(15), queued);
801  checkMetrics(env, 6, initQueueMax, 4, 3, 256);
802 
803  BEAST_EXPECT(env.seq(alice) == aliceSeq);
804  BEAST_EXPECT(env.seq(bob) == bobSeq);
805  BEAST_EXPECT(env.seq(charlie) == charlieSeq);
806 
807  env.close();
808  // Verify that all of but one of the queued transactions
809  // got applied.
810  checkMetrics(env, 1, 8, 5, 4, 256);
811 
812  // Verify that the stuck transaction is Bob's second.
813  // Even though it had a higher fee than Alice's and
814  // Charlie's, it didn't get attempted until the fee escalated.
815  BEAST_EXPECT(env.seq(alice) == aliceSeq + 3);
816  BEAST_EXPECT(env.seq(bob) == bobSeq + 1);
817  BEAST_EXPECT(env.seq(charlie) == charlieSeq + 1);
818 
819  // Alice - fill up the queue
820  std::int64_t aliceFee = 20;
821  aliceSeq = env.seq(alice);
822  auto lastLedgerSeq = env.current()->info().seq + 2;
823  for (auto i = 0; i < 7; i++)
824  {
825  env(noop(alice),
826  seq(aliceSeq),
827  json(jss::LastLedgerSequence, lastLedgerSeq + i),
828  fee(aliceFee),
829  queued);
830  ++aliceSeq;
831  }
832  checkMetrics(env, 8, 8, 5, 4, 513);
833  {
834  auto& txQ = env.app().getTxQ();
835  auto aliceStat = txQ.getAccountTxs(alice.id(), *env.current());
836  constexpr XRPAmount fee{20};
837  auto const& baseFee = env.current()->fees().base;
838  auto seq = env.seq(alice);
839  BEAST_EXPECT(aliceStat.size() == 7);
840  for (auto const& [txSeq, details] : aliceStat)
841  {
842  BEAST_EXPECT(txSeq == seq);
843  BEAST_EXPECT(
844  details.feeLevel == toFeeLevel(fee, baseFee).second);
845  BEAST_EXPECT(details.lastValid);
846  BEAST_EXPECT(
847  (details.consequences &&
848  details.consequences->fee == drops(fee) &&
849  details.consequences->potentialSpend == drops(0) &&
850  details.consequences->category ==
852  txSeq == env.seq(alice) + 6);
853  ++seq;
854  }
855  }
856 
857  // Alice attempts to add another item to the queue,
858  // but you can't force your own earlier txn off the
859  // queue.
860  env(noop(alice),
861  seq(aliceSeq),
862  json(jss::LastLedgerSequence, lastLedgerSeq + 7),
863  fee(aliceFee),
865  checkMetrics(env, 8, 8, 5, 4, 513);
866 
867  // Charlie - try to add another item to the queue,
868  // which fails because fee is lower than Alice's
869  // queued average.
870  env(noop(charlie), fee(19), ter(telCAN_NOT_QUEUE_FULL));
871  checkMetrics(env, 8, 8, 5, 4, 513);
872 
873  // Charlie - add another item to the queue, which
874  // causes Alice's last txn to drop
875  env(noop(charlie), fee(30), queued);
876  checkMetrics(env, 8, 8, 5, 4, 513);
877 
878  // Alice - now attempt to add one more to the queue,
879  // which fails because the last tx was dropped, so
880  // there is no complete chain.
881  env(noop(alice), seq(aliceSeq), fee(aliceFee), ter(terPRE_SEQ));
882  checkMetrics(env, 8, 8, 5, 4, 513);
883 
884  // Alice wants this tx more than the dropped tx,
885  // so resubmits with higher fee, but the queue
886  // is full, and her account is the cheapest.
887  env(noop(alice),
888  seq(aliceSeq - 1),
889  fee(aliceFee),
891  checkMetrics(env, 8, 8, 5, 4, 513);
892 
893  // Try to replace a middle item in the queue
894  // without enough fee.
895  aliceSeq = env.seq(alice) + 2;
896  aliceFee = 25;
897  env(noop(alice),
898  seq(aliceSeq),
899  fee(aliceFee),
901  checkMetrics(env, 8, 8, 5, 4, 513);
902 
903  // Replace a middle item from the queue successfully
904  ++aliceFee;
905  env(noop(alice), seq(aliceSeq), fee(aliceFee), queued);
906  checkMetrics(env, 8, 8, 5, 4, 513);
907 
908  env.close();
909  // Alice's transactions processed, along with
910  // Charlie's, and the lost one is replayed and
911  // added back to the queue.
912  checkMetrics(env, 4, 10, 6, 5, 256);
913 
914  aliceSeq = env.seq(alice) + 1;
915 
916  // Try to replace that item with a transaction that will
917  // bankrupt Alice. Fails, because an account can't have
918  // more than the minimum reserve in flight before the
919  // last queued transaction
920  aliceFee =
921  env.le(alice)->getFieldAmount(sfBalance).xrp().drops() - (59);
922  env(noop(alice),
923  seq(aliceSeq),
924  fee(aliceFee),
926  checkMetrics(env, 4, 10, 6, 5, 256);
927 
928  // Try to spend more than Alice can afford with all the other txs.
929  aliceSeq += 2;
930  env(noop(alice), seq(aliceSeq), fee(aliceFee), ter(terINSUF_FEE_B));
931  checkMetrics(env, 4, 10, 6, 5, 256);
932 
933  // Replace the last queued item with a transaction that will
934  // bankrupt Alice
935  --aliceFee;
936  env(noop(alice), seq(aliceSeq), fee(aliceFee), queued);
937  checkMetrics(env, 4, 10, 6, 5, 256);
938 
939  // Alice - Attempt to queue a last transaction, but it
940  // fails because the fee in flight is too high, before
941  // the fee is checked against the balance
942  aliceFee /= 5;
943  ++aliceSeq;
944  env(noop(alice),
945  seq(aliceSeq),
946  fee(aliceFee),
948  checkMetrics(env, 4, 10, 6, 5, 256);
949 
950  env.close();
951  // All of Alice's transactions applied.
952  checkMetrics(env, 0, 12, 4, 6, 256);
953 
954  env.close();
955  checkMetrics(env, 0, 12, 0, 6, 256);
956 
957  // Alice is broke
958  env.require(balance(alice, XRP(0)));
959  env(noop(alice), ter(terINSUF_FEE_B));
960 
961  // Bob tries to queue up more than the single
962  // account limit (10) txs.
963  fillQueue(env, bob);
964  bobSeq = env.seq(bob);
965  checkMetrics(env, 0, 12, 7, 6, 256);
966  for (int i = 0; i < 10; ++i)
967  env(noop(bob), seq(bobSeq + i), queued);
968  checkMetrics(env, 10, 12, 7, 6, 256);
969  // Bob hit the single account limit
970  env(noop(bob), seq(bobSeq + 10), ter(terPRE_SEQ));
971  checkMetrics(env, 10, 12, 7, 6, 256);
972  // Bob can replace one of the earlier txs regardless
973  // of the limit
974  env(noop(bob), seq(bobSeq + 5), fee(20), queued);
975  checkMetrics(env, 10, 12, 7, 6, 256);
976  }
977 
978  void
980  {
981  using namespace jtx;
982  using namespace std::chrono;
983 
984  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "4"}}));
985 
986  auto alice = Account("alice");
987  auto bob = Account("bob");
988  auto charlie = Account("charlie");
989  auto daria = Account("daria");
990  auto elmo = Account("elmo");
991  auto fred = Account("fred");
992  auto gwen = Account("gwen");
993  auto hank = Account("hank");
994 
995  auto queued = ter(terQUEUED);
996 
997  BEAST_EXPECT(env.current()->fees().base == 10);
998 
999  checkMetrics(env, 0, boost::none, 0, 4, 256);
1000 
1001  // Create several accounts while the fee is cheap so they all apply.
1002  env.fund(XRP(50000), noripple(alice, bob, charlie, daria));
1003  checkMetrics(env, 0, boost::none, 4, 4, 256);
1004 
1005  env.close();
1006  checkMetrics(env, 0, 8, 0, 4, 256);
1007 
1008  env.fund(XRP(50000), noripple(elmo, fred, gwen, hank));
1009  checkMetrics(env, 0, 8, 4, 4, 256);
1010 
1011  env.close();
1012  checkMetrics(env, 0, 8, 0, 4, 256);
1013 
1015 
1016  // Stuff the ledger and queue so we can verify that
1017  // stuff gets kicked out.
1018  env(noop(gwen));
1019  env(noop(hank));
1020  env(noop(gwen));
1021  env(noop(fred));
1022  env(noop(elmo));
1023  checkMetrics(env, 0, 8, 5, 4, 256);
1024 
1025  auto aliceSeq = env.seq(alice);
1026  auto bobSeq = env.seq(bob);
1027  auto charlieSeq = env.seq(charlie);
1028  auto dariaSeq = env.seq(daria);
1029  auto elmoSeq = env.seq(elmo);
1030  auto fredSeq = env.seq(fred);
1031  auto gwenSeq = env.seq(gwen);
1032  auto hankSeq = env.seq(hank);
1033 
1034  // This time, use identical fees.
1035  env(noop(alice), fee(15), queued);
1036  env(noop(bob), fee(15), queued);
1037  env(noop(charlie), fee(15), queued);
1038  env(noop(daria), fee(15), queued);
1039  env(noop(elmo), fee(15), queued);
1040  env(noop(fred), fee(15), queued);
1041  env(noop(gwen), fee(15), queued);
1042  // This one gets into the queue, but gets dropped when the
1043  // higher fee one is added later.
1044  env(noop(hank), fee(15), queued);
1045 
1046  // Queue is full now. Minimum fee now reflects the
1047  // lowest fee in the queue.
1048  checkMetrics(env, 8, 8, 5, 4, 385);
1049 
1050  // Try to add another transaction with the default (low) fee,
1051  // it should fail because it can't replace the one already
1052  // there.
1053  env(noop(charlie), ter(telCAN_NOT_QUEUE_FEE));
1054 
1055  // Add another transaction, with a higher fee,
1056  // Not high enough to get into the ledger, but high
1057  // enough to get into the queue (and kick somebody out)
1058  env(noop(charlie), fee(100), seq(charlieSeq + 1), queued);
1059 
1060  // Queue is still full.
1061  checkMetrics(env, 8, 8, 5, 4, 385);
1062 
1063  // alice, bob, charlie, daria, and elmo's txs
1064  // are processed out of the queue into the ledger,
1065  // leaving fred and gwen's txs. hank's tx is
1066  // retried from localTxs, and put back into the
1067  // queue.
1068  env.close();
1069  checkMetrics(env, 3, 10, 6, 5, 256);
1070 
1071  BEAST_EXPECT(aliceSeq + 1 == env.seq(alice));
1072  BEAST_EXPECT(bobSeq + 1 == env.seq(bob));
1073  BEAST_EXPECT(charlieSeq + 2 == env.seq(charlie));
1074  BEAST_EXPECT(dariaSeq + 1 == env.seq(daria));
1075  BEAST_EXPECT(elmoSeq + 1 == env.seq(elmo));
1076  BEAST_EXPECT(fredSeq == env.seq(fred));
1077  BEAST_EXPECT(gwenSeq == env.seq(gwen));
1078  BEAST_EXPECT(hankSeq == env.seq(hank));
1079 
1080  aliceSeq = env.seq(alice);
1081  bobSeq = env.seq(bob);
1082  charlieSeq = env.seq(charlie);
1083  dariaSeq = env.seq(daria);
1084  elmoSeq = env.seq(elmo);
1085 
1086  // Fill up the queue again
1087  env(noop(alice), fee(15), queued);
1088  env(noop(alice), seq(aliceSeq + 1), fee(15), queued);
1089  env(noop(alice), seq(aliceSeq + 2), fee(15), queued);
1090  env(noop(bob), fee(15), queued);
1091  env(noop(charlie), fee(15), queued);
1092  env(noop(daria), fee(15), queued);
1093  // This one gets into the queue, but gets dropped when the
1094  // higher fee one is added later.
1095  env(noop(elmo), fee(15), queued);
1096  checkMetrics(env, 10, 10, 6, 5, 385);
1097 
1098  // Add another transaction, with a higher fee,
1099  // Not high enough to get into the ledger, but high
1100  // enough to get into the queue (and kick somebody out)
1101  env(noop(alice), fee(100), seq(aliceSeq + 3), queued);
1102 
1103  env.close();
1104  checkMetrics(env, 4, 12, 7, 6, 256);
1105 
1106  BEAST_EXPECT(fredSeq + 1 == env.seq(fred));
1107  BEAST_EXPECT(gwenSeq + 1 == env.seq(gwen));
1108  BEAST_EXPECT(hankSeq + 1 == env.seq(hank));
1109  BEAST_EXPECT(aliceSeq + 4 == env.seq(alice));
1110  BEAST_EXPECT(bobSeq == env.seq(bob));
1111  BEAST_EXPECT(charlieSeq == env.seq(charlie));
1112  BEAST_EXPECT(dariaSeq == env.seq(daria));
1113  BEAST_EXPECT(elmoSeq == env.seq(elmo));
1114  }
1115 
1116  void
1118  {
1119  using namespace jtx;
1120 
1121  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "1"}}));
1122 
1123  auto alice = Account("alice");
1124 
1125  BEAST_EXPECT(env.current()->fees().base == 10);
1126 
1127  checkMetrics(env, 0, boost::none, 0, 1, 256);
1128 
1129  env.fund(XRP(50000), noripple(alice));
1130  checkMetrics(env, 0, boost::none, 1, 1, 256);
1131 
1132  env(fset(alice, asfAccountTxnID));
1133  checkMetrics(env, 0, boost::none, 2, 1, 256);
1134 
1135  // Immediately after the fset, the sfAccountTxnID field
1136  // is still uninitialized, so preflight succeeds here,
1137  // and this txn fails because it can't be stored in the queue.
1138  env(noop(alice),
1139  json(R"({"AccountTxnID": "0"})"),
1141 
1142  checkMetrics(env, 0, boost::none, 2, 1, 256);
1143  env.close();
1144  // The failed transaction is retried from LocalTx
1145  // and succeeds.
1146  checkMetrics(env, 0, 4, 1, 2, 256);
1147 
1148  env(noop(alice));
1149  checkMetrics(env, 0, 4, 2, 2, 256);
1150 
1151  env(noop(alice), json(R"({"AccountTxnID": "0"})"), ter(tefWRONG_PRIOR));
1152  }
1153 
1154  void
1156  {
1157  using namespace jtx;
1158  using namespace std::string_literals;
1159 
1160  {
1161  Env env(
1162  *this,
1163  makeConfig(
1164  {{"minimum_txn_in_ledger_standalone", "2"},
1165  {"target_txn_in_ledger", "4"},
1166  {"maximum_txn_in_ledger", "5"}}));
1167 
1168  auto alice = Account("alice");
1169 
1170  checkMetrics(env, 0, boost::none, 0, 2, 256);
1171 
1172  env.fund(XRP(50000), noripple(alice));
1173  checkMetrics(env, 0, boost::none, 1, 2, 256);
1174 
1175  for (int i = 0; i < 10; ++i)
1176  env(noop(alice), openLedgerFee(env));
1177 
1178  checkMetrics(env, 0, boost::none, 11, 2, 256);
1179 
1180  env.close();
1181  // If not for the maximum, the per ledger would be 11.
1182  checkMetrics(env, 0, 10, 0, 5, 256, 800025);
1183  }
1184 
1185  try
1186  {
1187  Env env(
1188  *this,
1189  makeConfig(
1190  {{"minimum_txn_in_ledger", "200"},
1191  {"minimum_txn_in_ledger_standalone", "200"},
1192  {"target_txn_in_ledger", "4"},
1193  {"maximum_txn_in_ledger", "5"}}));
1194  // should throw
1195  fail();
1196  }
1197  catch (std::runtime_error const& e)
1198  {
1199  BEAST_EXPECT(
1200  e.what() ==
1201  "The minimum number of low-fee transactions allowed "
1202  "per ledger (minimum_txn_in_ledger) exceeds "
1203  "the maximum number of low-fee transactions allowed per "
1204  "ledger (maximum_txn_in_ledger)."s);
1205  }
1206  try
1207  {
1208  Env env(
1209  *this,
1210  makeConfig(
1211  {{"minimum_txn_in_ledger", "200"},
1212  {"minimum_txn_in_ledger_standalone", "2"},
1213  {"target_txn_in_ledger", "4"},
1214  {"maximum_txn_in_ledger", "5"}}));
1215  // should throw
1216  fail();
1217  }
1218  catch (std::runtime_error const& e)
1219  {
1220  BEAST_EXPECT(
1221  e.what() ==
1222  "The minimum number of low-fee transactions allowed "
1223  "per ledger (minimum_txn_in_ledger) exceeds "
1224  "the maximum number of low-fee transactions allowed per "
1225  "ledger (maximum_txn_in_ledger)."s);
1226  }
1227  try
1228  {
1229  Env env(
1230  *this,
1231  makeConfig(
1232  {{"minimum_txn_in_ledger", "2"},
1233  {"minimum_txn_in_ledger_standalone", "200"},
1234  {"target_txn_in_ledger", "4"},
1235  {"maximum_txn_in_ledger", "5"}}));
1236  // should throw
1237  fail();
1238  }
1239  catch (std::runtime_error const& e)
1240  {
1241  BEAST_EXPECT(
1242  e.what() ==
1243  "The minimum number of low-fee transactions allowed "
1244  "per ledger (minimum_txn_in_ledger_standalone) exceeds "
1245  "the maximum number of low-fee transactions allowed per "
1246  "ledger (maximum_txn_in_ledger)."s);
1247  }
1248  }
1249 
1250  void
1252  {
1253  using namespace jtx;
1254 
1255  Env env(
1256  *this,
1257  makeConfig(
1258  {{"minimum_txn_in_ledger_standalone", "3"}},
1259  {{"account_reserve", "200"}, {"owner_reserve", "50"}}));
1260 
1261  auto alice = Account("alice");
1262  auto bob = Account("bob");
1263 
1264  auto queued = ter(terQUEUED);
1265 
1266  // ledgers in queue is 2 because of makeConfig
1267  auto const initQueueMax = initFee(env, 3, 2, 10, 10, 200, 50);
1268 
1269  BEAST_EXPECT(env.current()->fees().base == 10);
1270 
1271  checkMetrics(env, 0, initQueueMax, 0, 3, 256);
1272 
1273  env.fund(drops(5000), noripple(alice));
1274  env.fund(XRP(50000), noripple(bob));
1275  checkMetrics(env, 0, initQueueMax, 2, 3, 256);
1276  auto USD = bob["USD"];
1277 
1278  env(offer(alice, USD(5000), drops(5000)), require(owners(alice, 1)));
1279  checkMetrics(env, 0, initQueueMax, 3, 3, 256);
1280 
1281  env.close();
1282  checkMetrics(env, 0, 6, 0, 3, 256);
1283 
1284  // Fill up the ledger
1285  fillQueue(env, alice);
1286  checkMetrics(env, 0, 6, 4, 3, 256);
1287 
1288  // Queue up a couple of transactions, plus one
1289  // more expensive one.
1290  auto aliceSeq = env.seq(alice);
1291  env(noop(alice), seq(aliceSeq++), queued);
1292  env(noop(alice), seq(aliceSeq++), queued);
1293  env(noop(alice), seq(aliceSeq++), queued);
1294  env(noop(alice), fee(drops(1000)), seq(aliceSeq), queued);
1295  checkMetrics(env, 4, 6, 4, 3, 256);
1296 
1297  // This offer should take Alice's offer
1298  // up to Alice's reserve.
1299  env(offer(bob, drops(5000), USD(5000)),
1300  openLedgerFee(env),
1301  require(
1302  balance(alice, drops(250)), owners(alice, 1), lines(alice, 1)));
1303  checkMetrics(env, 4, 6, 5, 3, 256);
1304 
1305  // Try adding a new transaction.
1306  // Too many fees in flight.
1307  env(noop(alice),
1308  fee(drops(200)),
1309  seq(aliceSeq + 1),
1311  checkMetrics(env, 4, 6, 5, 3, 256);
1312 
1313  // Close the ledger. All of Alice's transactions
1314  // take a fee, except the last one.
1315  env.close();
1316  checkMetrics(env, 1, 10, 3, 5, 256);
1317  env.require(balance(alice, drops(250 - 30)));
1318 
1319  // Still can't add a new transaction for Alice,
1320  // no matter the fee.
1321  env(noop(alice),
1322  fee(drops(200)),
1323  seq(aliceSeq + 1),
1325  checkMetrics(env, 1, 10, 3, 5, 256);
1326 
1327  /* At this point, Alice's transaction is indefinitely
1328  stuck in the queue. Eventually it will either
1329  expire, get forced off the end by more valuable
1330  transactions, get replaced by Alice, or Alice
1331  will get more XRP, and it'll process.
1332  */
1333 
1334  for (int i = 0; i < 9; ++i)
1335  {
1336  env.close();
1337  checkMetrics(env, 1, 10, 0, 5, 256);
1338  }
1339 
1340  // And Alice's transaction expires (via the retry limit,
1341  // not LastLedgerSequence).
1342  env.close();
1343  checkMetrics(env, 0, 10, 0, 5, 256);
1344  }
1345 
1346  void
1348  {
1349  using namespace jtx;
1350 
1351  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
1352 
1353  auto alice = Account("alice");
1354  auto bob = Account("bob");
1355  auto charlie = Account("charlie");
1356  auto daria = Account("daria");
1357 
1358  auto queued = ter(terQUEUED);
1359 
1360  BEAST_EXPECT(env.current()->fees().base == 10);
1361 
1362  checkMetrics(env, 0, boost::none, 0, 3, 256);
1363 
1364  env.fund(XRP(50000), noripple(alice, bob));
1365  env.memoize(charlie);
1366  env.memoize(daria);
1367  checkMetrics(env, 0, boost::none, 2, 3, 256);
1368 
1369  // Fill up the open ledger
1370  env(noop(alice));
1371  // Set a regular key just to clear the password spent flag
1372  env(regkey(alice, charlie));
1373  checkMetrics(env, 0, boost::none, 4, 3, 256);
1374 
1375  // Put some "normal" txs in the queue
1376  auto aliceSeq = env.seq(alice);
1377  env(noop(alice), queued);
1378  env(noop(alice), seq(aliceSeq + 1), queued);
1379  env(noop(alice), seq(aliceSeq + 2), queued);
1380 
1381  // Can't replace the first tx with a blocker
1382  env(fset(alice, asfAccountTxnID),
1383  fee(20),
1385  // Can't replace the second / middle tx with a blocker
1386  env(regkey(alice, bob),
1387  seq(aliceSeq + 1),
1388  fee(20),
1390  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1391  fee(20),
1392  seq(aliceSeq + 1),
1394  // CAN replace the last tx with a blocker
1395  env(signers(alice, 2, {{bob}, {charlie}, {daria}}),
1396  fee(20),
1397  seq(aliceSeq + 2),
1398  queued);
1399  env(regkey(alice, bob), seq(aliceSeq + 2), fee(30), queued);
1400 
1401  // Can't queue up any more transactions after the blocker
1402  env(noop(alice), seq(aliceSeq + 3), ter(telCAN_NOT_QUEUE_BLOCKED));
1403 
1404  // Other accounts are not affected
1405  env(noop(bob), queued);
1406 
1407  // Can replace the txs before the blocker
1408  env(noop(alice), fee(14), queued);
1409 
1410  // Can replace the blocker itself
1411  env(noop(alice), seq(aliceSeq + 2), fee(40), queued);
1412 
1413  // And now there's no block.
1414  env(noop(alice), seq(aliceSeq + 3), queued);
1415  }
1416 
1417  void
1419  {
1420  using namespace jtx;
1421  testcase("In-flight balance checks");
1422 
1423  Env env(
1424  *this,
1425  makeConfig(
1426  {{"minimum_txn_in_ledger_standalone", "3"}},
1427  {{"account_reserve", "200"}, {"owner_reserve", "50"}}));
1428 
1429  auto alice = Account("alice");
1430  auto charlie = Account("charlie");
1431  auto gw = Account("gw");
1432 
1433  auto queued = ter(terQUEUED);
1434 
1435  // Set the fee reserves _really_ low so transactions with fees
1436  // in the ballpark of the reserves can be queued. With default
1437  // reserves, a couple hundred transactions would have to be
1438  // queued before the open ledger fee approached the reserve,
1439  // which would unnecessarily slow down this test.
1440  // ledgers in queue is 2 because of makeConfig
1441  auto const initQueueMax = initFee(env, 3, 2, 10, 10, 200, 50);
1442 
1443  auto limit = 3;
1444 
1445  checkMetrics(env, 0, initQueueMax, 0, limit, 256);
1446 
1447  env.fund(XRP(50000), noripple(alice, charlie), gw);
1448  checkMetrics(env, 0, initQueueMax, limit + 1, limit, 256);
1449 
1450  auto USD = gw["USD"];
1451  auto BUX = gw["BUX"];
1452 
1454  // Offer with high XRP out and low fee doesn't block
1455  auto aliceSeq = env.seq(alice);
1456  auto aliceBal = env.balance(alice);
1457 
1458  env.require(balance(alice, XRP(50000)), owners(alice, 0));
1459 
1460  // If this offer crosses, all of alice's
1461  // XRP will be taken (except the reserve).
1462  env(offer(alice, BUX(5000), XRP(50000)), queued);
1463  checkMetrics(env, 1, initQueueMax, limit + 1, limit, 256);
1464 
1465  // But because the reserve is protected, another
1466  // transaction will be allowed to queue
1467  env(noop(alice), seq(aliceSeq + 1), queued);
1468  checkMetrics(env, 2, initQueueMax, limit + 1, limit, 256);
1469 
1470  env.close();
1471  ++limit;
1472  checkMetrics(env, 0, limit * 2, 2, limit, 256);
1473 
1474  // But once we close the ledger, we find alice
1475  // has plenty of XRP, because the offer didn't
1476  // cross (of course).
1477  env.require(balance(alice, aliceBal - drops(20)), owners(alice, 1));
1478  // cancel the offer
1479  env(offer_cancel(alice, aliceSeq));
1480 
1482  // Offer with high XRP out and high total fee blocks later txs
1483  fillQueue(env, alice);
1484  checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
1485  aliceSeq = env.seq(alice);
1486  aliceBal = env.balance(alice);
1487 
1488  env.require(owners(alice, 0));
1489 
1490  // Alice creates an offer with a fee of half the reserve
1491  env(offer(alice, BUX(5000), XRP(50000)), fee(drops(100)), queued);
1492  checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
1493 
1494  // Alice creates another offer with a fee
1495  // that brings the total to just shy of the reserve
1496  env(noop(alice), fee(drops(99)), seq(aliceSeq + 1), queued);
1497  checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
1498 
1499  // So even a noop will look like alice
1500  // doesn't have the balance to pay the fee
1501  env(noop(alice),
1502  fee(drops(51)),
1503  seq(aliceSeq + 2),
1504  ter(terINSUF_FEE_B));
1505  checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
1506 
1507  env.close();
1508  ++limit;
1509  checkMetrics(env, 0, limit * 2, 3, limit, 256);
1510 
1511  // But once we close the ledger, we find alice
1512  // has plenty of XRP, because the offer didn't
1513  // cross (of course).
1514  env.require(balance(alice, aliceBal - drops(250)), owners(alice, 1));
1515  // cancel the offer
1516  env(offer_cancel(alice, aliceSeq));
1517 
1519  // Offer with high XRP out and super high fee blocks later txs
1520  fillQueue(env, alice);
1521  checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
1522  aliceSeq = env.seq(alice);
1523  aliceBal = env.balance(alice);
1524 
1525  env.require(owners(alice, 0));
1526 
1527  // Alice creates an offer with a fee larger than the reserve
1528  // This one can queue because it's the first in the queue for alice
1529  env(offer(alice, BUX(5000), XRP(50000)), fee(drops(300)), queued);
1530  checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
1531 
1532  // So even a noop will look like alice
1533  // doesn't have the balance to pay the fee
1534  env(noop(alice),
1535  fee(drops(51)),
1536  seq(aliceSeq + 1),
1538  checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
1539 
1540  env.close();
1541  ++limit;
1542  checkMetrics(env, 0, limit * 2, 2, limit, 256);
1543 
1544  // But once we close the ledger, we find alice
1545  // has plenty of XRP, because the offer didn't
1546  // cross (of course).
1547  env.require(balance(alice, aliceBal - drops(351)), owners(alice, 1));
1548  // cancel the offer
1549  env(offer_cancel(alice, aliceSeq));
1550 
1552  // Offer with low XRP out allows later txs
1553  fillQueue(env, alice);
1554  checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
1555  aliceSeq = env.seq(alice);
1556  aliceBal = env.balance(alice);
1557 
1558  // If this offer crosses, just a bit
1559  // of alice's XRP will be taken.
1560  env(offer(alice, BUX(50), XRP(500)), queued);
1561 
1562  // And later transactions are just fine
1563  env(noop(alice), seq(aliceSeq + 1), queued);
1564  checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
1565 
1566  env.close();
1567  ++limit;
1568  checkMetrics(env, 0, limit * 2, 2, limit, 256);
1569 
1570  // But once we close the ledger, we find alice
1571  // has plenty of XRP, because the offer didn't
1572  // cross (of course).
1573  env.require(balance(alice, aliceBal - drops(20)), owners(alice, 1));
1574  // cancel the offer
1575  env(offer_cancel(alice, aliceSeq));
1576 
1578  // Large XRP payment doesn't block later txs
1579  fillQueue(env, alice);
1580  checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
1581 
1582  aliceSeq = env.seq(alice);
1583  aliceBal = env.balance(alice);
1584 
1585  // If this payment succeeds, alice will
1586  // send her entire balance to charlie
1587  // (minus the reserve).
1588  env(pay(alice, charlie, XRP(50000)), queued);
1589 
1590  // But because the reserve is protected, another
1591  // transaction will be allowed to queue
1592  env(noop(alice), seq(aliceSeq + 1), queued);
1593  checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
1594 
1595  env.close();
1596  ++limit;
1597  checkMetrics(env, 0, limit * 2, 2, limit, 256);
1598 
1599  // But once we close the ledger, we find alice
1600  // still has most of her balance, because the
1601  // payment was unfunded!
1602  env.require(balance(alice, aliceBal - drops(20)), owners(alice, 0));
1603 
1605  // Small XRP payment allows later txs
1606  fillQueue(env, alice);
1607  checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
1608 
1609  aliceSeq = env.seq(alice);
1610  aliceBal = env.balance(alice);
1611 
1612  // If this payment succeeds, alice will
1613  // send just a bit of balance to charlie
1614  env(pay(alice, charlie, XRP(500)), queued);
1615 
1616  // And later transactions are just fine
1617  env(noop(alice), seq(aliceSeq + 1), queued);
1618  checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
1619 
1620  env.close();
1621  ++limit;
1622  checkMetrics(env, 0, limit * 2, 2, limit, 256);
1623 
1624  // The payment succeeds
1625  env.require(
1626  balance(alice, aliceBal - XRP(500) - drops(20)), owners(alice, 0));
1627 
1629  // Large IOU payment allows later txs
1630  auto const amount = USD(500000);
1631  env(trust(alice, USD(50000000)));
1632  env(trust(charlie, USD(50000000)));
1633  checkMetrics(env, 0, limit * 2, 4, limit, 256);
1634  // Close so we don't have to deal
1635  // with tx ordering in consensus.
1636  env.close();
1637 
1638  env(pay(gw, alice, amount));
1639  checkMetrics(env, 0, limit * 2, 1, limit, 256);
1640  // Close so we don't have to deal
1641  // with tx ordering in consensus.
1642  env.close();
1643 
1644  fillQueue(env, alice);
1645  checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
1646 
1647  aliceSeq = env.seq(alice);
1648  aliceBal = env.balance(alice);
1649  auto aliceUSD = env.balance(alice, USD);
1650 
1651  // If this payment succeeds, alice will
1652  // send her entire USD balance to charlie.
1653  env(pay(alice, charlie, amount), queued);
1654 
1655  // But that's fine, because it doesn't affect
1656  // alice's XRP balance (other than the fee, of course).
1657  env(noop(alice), seq(aliceSeq + 1), queued);
1658  checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
1659 
1660  env.close();
1661  ++limit;
1662  checkMetrics(env, 0, limit * 2, 2, limit, 256);
1663 
1664  // So once we close the ledger, alice has her
1665  // XRP balance, but her USD balance went to charlie.
1666  env.require(
1667  balance(alice, aliceBal - drops(20)),
1668  balance(alice, USD(0)),
1669  balance(charlie, aliceUSD),
1670  owners(alice, 1),
1671  owners(charlie, 1));
1672 
1674  // Large XRP to IOU payment doesn't block later txs.
1675 
1676  env(offer(gw, XRP(500000), USD(50000)));
1677  // Close so we don't have to deal
1678  // with tx ordering in consensus.
1679  env.close();
1680 
1681  fillQueue(env, charlie);
1682  checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
1683 
1684  aliceSeq = env.seq(alice);
1685  aliceBal = env.balance(alice);
1686  auto charlieUSD = env.balance(charlie, USD);
1687 
1688  // If this payment succeeds, and uses the
1689  // entire sendMax, alice will send her
1690  // entire XRP balance to charlie in the
1691  // form of USD.
1692  BEAST_EXPECT(XRP(60000) > aliceBal);
1693  env(pay(alice, charlie, USD(1000)), sendmax(XRP(60000)), queued);
1694 
1695  // But because the reserve is protected, another
1696  // transaction will be allowed to queue
1697  env(noop(alice), seq(aliceSeq + 1), queued);
1698  checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
1699 
1700  env.close();
1701  ++limit;
1702  checkMetrics(env, 0, limit * 2, 2, limit, 256);
1703 
1704  // So once we close the ledger, alice sent a payment
1705  // to charlie using only a portion of her XRP balance
1706  env.require(
1707  balance(alice, aliceBal - XRP(10000) - drops(20)),
1708  balance(alice, USD(0)),
1709  balance(charlie, charlieUSD + USD(1000)),
1710  owners(alice, 1),
1711  owners(charlie, 1));
1712 
1714  // Small XRP to IOU payment allows later txs.
1715 
1716  fillQueue(env, charlie);
1717  checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
1718 
1719  aliceSeq = env.seq(alice);
1720  aliceBal = env.balance(alice);
1721  charlieUSD = env.balance(charlie, USD);
1722 
1723  // If this payment succeeds, and uses the
1724  // entire sendMax, alice will only send
1725  // a portion of her XRP balance to charlie
1726  // in the form of USD.
1727  BEAST_EXPECT(aliceBal > XRP(6001));
1728  env(pay(alice, charlie, USD(500)), sendmax(XRP(6000)), queued);
1729 
1730  // And later transactions are just fine
1731  env(noop(alice), seq(aliceSeq + 1), queued);
1732  checkMetrics(env, 2, limit * 2, limit + 1, limit, 256);
1733 
1734  env.close();
1735  ++limit;
1736  checkMetrics(env, 0, limit * 2, 2, limit, 256);
1737 
1738  // So once we close the ledger, alice sent a payment
1739  // to charlie using only a portion of her XRP balance
1740  env.require(
1741  balance(alice, aliceBal - XRP(5000) - drops(20)),
1742  balance(alice, USD(0)),
1743  balance(charlie, charlieUSD + USD(500)),
1744  owners(alice, 1),
1745  owners(charlie, 1));
1746 
1748  // Edge case: what happens if the balance is below the reserve?
1749  env(noop(alice), fee(env.balance(alice) - drops(30)));
1750  env.close();
1751 
1752  fillQueue(env, charlie);
1753  checkMetrics(env, 0, limit * 2, limit + 1, limit, 256);
1754 
1755  aliceSeq = env.seq(alice);
1756  aliceBal = env.balance(alice);
1757  BEAST_EXPECT(aliceBal == drops(30));
1758 
1759  env(noop(alice), fee(drops(25)), queued);
1760  env(noop(alice), seq(aliceSeq + 1), ter(terINSUF_FEE_B));
1761  BEAST_EXPECT(env.balance(alice) == drops(30));
1762 
1763  checkMetrics(env, 1, limit * 2, limit + 1, limit, 256);
1764 
1765  env.close();
1766  ++limit;
1767  checkMetrics(env, 0, limit * 2, 1, limit, 256);
1768  BEAST_EXPECT(env.balance(alice) == drops(5));
1769  }
1770 
1771  void
1773  {
1774  using namespace jtx;
1775  using namespace std::chrono;
1776  Env env(*this, supported_amendments().set(featureTickets));
1777  auto const alice = Account("alice");
1778  env.memoize(alice);
1779  env.memoize("bob");
1780  env.memoize("carol");
1781  {
1782  Json::Value cancelOffer;
1783  cancelOffer[jss::Account] = alice.human();
1784  cancelOffer[jss::OfferSequence] = 3;
1785  cancelOffer[jss::TransactionType] = jss::OfferCancel;
1786  auto const jtx = env.jt(cancelOffer, seq(1), fee(10));
1787  auto const pf = preflight(
1788  env.app(),
1789  env.current()->rules(),
1790  *jtx.stx,
1791  tapNONE,
1792  env.journal);
1793  BEAST_EXPECT(pf.ter == tesSUCCESS);
1794  auto const conseq = calculateConsequences(pf);
1795  BEAST_EXPECT(conseq.category == TxConsequences::normal);
1796  BEAST_EXPECT(conseq.fee == drops(10));
1797  BEAST_EXPECT(conseq.potentialSpend == XRP(0));
1798  }
1799 
1800  {
1801  auto USD = alice["USD"];
1802 
1803  auto const jtx =
1804  env.jt(trust("carol", USD(50000000)), seq(1), fee(10));
1805  auto const pf = preflight(
1806  env.app(),
1807  env.current()->rules(),
1808  *jtx.stx,
1809  tapNONE,
1810  env.journal);
1811  BEAST_EXPECT(pf.ter == tesSUCCESS);
1812  auto const conseq = calculateConsequences(pf);
1813  BEAST_EXPECT(conseq.category == TxConsequences::normal);
1814  BEAST_EXPECT(conseq.fee == drops(10));
1815  BEAST_EXPECT(conseq.potentialSpend == XRP(0));
1816  }
1817 
1818  {
1819  auto const jtx =
1820  env.jt(ticket::create(alice, "bob", 60), seq(1), fee(10));
1821  auto const pf = preflight(
1822  env.app(),
1823  env.current()->rules(),
1824  *jtx.stx,
1825  tapNONE,
1826  env.journal);
1827  BEAST_EXPECT(pf.ter == tesSUCCESS);
1828  auto const conseq = calculateConsequences(pf);
1829  BEAST_EXPECT(conseq.category == TxConsequences::normal);
1830  BEAST_EXPECT(conseq.fee == drops(10));
1831  BEAST_EXPECT(conseq.potentialSpend == XRP(0));
1832  }
1833 
1834  {
1835  Json::Value cancelTicket;
1836  cancelTicket[jss::Account] = alice.human();
1837  cancelTicket["TicketID"] = to_string(uint256());
1838  cancelTicket[jss::TransactionType] = jss::TicketCancel;
1839  auto const jtx = env.jt(cancelTicket, seq(1), fee(10));
1840  auto const pf = preflight(
1841  env.app(),
1842  env.current()->rules(),
1843  *jtx.stx,
1844  tapNONE,
1845  env.journal);
1846  BEAST_EXPECT(pf.ter == tesSUCCESS);
1847  auto const conseq = calculateConsequences(pf);
1848  BEAST_EXPECT(conseq.category == TxConsequences::normal);
1849  BEAST_EXPECT(conseq.fee == drops(10));
1850  BEAST_EXPECT(conseq.potentialSpend == XRP(0));
1851  }
1852  }
1853 
1854  void
1856  {
1857  using namespace jtx;
1858  Env env(*this);
1859 
1860  auto fee = env.rpc("fee");
1861 
1862  if (BEAST_EXPECT(fee.isMember(jss::result)) &&
1863  BEAST_EXPECT(!RPC::contains_error(fee[jss::result])))
1864  {
1865  auto const& result = fee[jss::result];
1866  BEAST_EXPECT(
1867  result.isMember(jss::ledger_current_index) &&
1868  result[jss::ledger_current_index] == 3);
1869  BEAST_EXPECT(result.isMember(jss::current_ledger_size));
1870  BEAST_EXPECT(result.isMember(jss::current_queue_size));
1871  BEAST_EXPECT(result.isMember(jss::expected_ledger_size));
1872  BEAST_EXPECT(!result.isMember(jss::max_queue_size));
1873  BEAST_EXPECT(result.isMember(jss::drops));
1874  auto const& drops = result[jss::drops];
1875  BEAST_EXPECT(drops.isMember(jss::base_fee));
1876  BEAST_EXPECT(drops.isMember(jss::median_fee));
1877  BEAST_EXPECT(drops.isMember(jss::minimum_fee));
1878  BEAST_EXPECT(drops.isMember(jss::open_ledger_fee));
1879  BEAST_EXPECT(result.isMember(jss::levels));
1880  auto const& levels = result[jss::levels];
1881  BEAST_EXPECT(levels.isMember(jss::median_level));
1882  BEAST_EXPECT(levels.isMember(jss::minimum_level));
1883  BEAST_EXPECT(levels.isMember(jss::open_ledger_level));
1884  BEAST_EXPECT(levels.isMember(jss::reference_level));
1885  }
1886 
1887  env.close();
1888 
1889  fee = env.rpc("fee");
1890 
1891  if (BEAST_EXPECT(fee.isMember(jss::result)) &&
1892  BEAST_EXPECT(!RPC::contains_error(fee[jss::result])))
1893  {
1894  auto const& result = fee[jss::result];
1895  BEAST_EXPECT(
1896  result.isMember(jss::ledger_current_index) &&
1897  result[jss::ledger_current_index] == 4);
1898  BEAST_EXPECT(result.isMember(jss::current_ledger_size));
1899  BEAST_EXPECT(result.isMember(jss::current_queue_size));
1900  BEAST_EXPECT(result.isMember(jss::expected_ledger_size));
1901  BEAST_EXPECT(result.isMember(jss::max_queue_size));
1902  auto const& drops = result[jss::drops];
1903  BEAST_EXPECT(drops.isMember(jss::base_fee));
1904  BEAST_EXPECT(drops.isMember(jss::median_fee));
1905  BEAST_EXPECT(drops.isMember(jss::minimum_fee));
1906  BEAST_EXPECT(drops.isMember(jss::open_ledger_fee));
1907  BEAST_EXPECT(result.isMember(jss::levels));
1908  auto const& levels = result[jss::levels];
1909  BEAST_EXPECT(levels.isMember(jss::median_level));
1910  BEAST_EXPECT(levels.isMember(jss::minimum_level));
1911  BEAST_EXPECT(levels.isMember(jss::open_ledger_level));
1912  BEAST_EXPECT(levels.isMember(jss::reference_level));
1913  }
1914  }
1915 
1916  void
1918  {
1919  /* This test is based on a reported regression where a
1920  replacement candidate transaction found the tx it was trying
1921  to replace did not have `consequences` set
1922 
1923  Hypothesis: The queue had '22 through '25. At some point(s),
1924  both the original '22 and '23 expired and were removed from
1925  the queue. A second '22 was submitted, and the multi-tx logic
1926  did not kick in, because it matched the account's sequence
1927  number (a_seq == t_seq). The third '22 was submitted and found
1928  the '22 in the queue did not have consequences.
1929  */
1930  using namespace jtx;
1931 
1932  Env env(
1933  *this,
1934  makeConfig(
1935  {{"minimum_txn_in_ledger_standalone", "1"},
1936  {"ledgers_in_queue", "10"},
1937  {"maximum_txn_per_account", "20"}}));
1938 
1939  // Alice will recreate the scenario. Bob will block.
1940  auto const alice = Account("alice");
1941  auto const bob = Account("bob");
1942 
1943  env.fund(XRP(500000), noripple(alice, bob));
1944  checkMetrics(env, 0, boost::none, 2, 1, 256);
1945 
1946  auto const aliceSeq = env.seq(alice);
1947  BEAST_EXPECT(env.current()->info().seq == 3);
1948  env(noop(alice),
1949  seq(aliceSeq),
1950  json(R"({"LastLedgerSequence":5})"),
1951  ter(terQUEUED));
1952  env(noop(alice),
1953  seq(aliceSeq + 1),
1954  json(R"({"LastLedgerSequence":5})"),
1955  ter(terQUEUED));
1956  env(noop(alice),
1957  seq(aliceSeq + 2),
1958  json(R"({"LastLedgerSequence":10})"),
1959  ter(terQUEUED));
1960  env(noop(alice),
1961  seq(aliceSeq + 3),
1962  json(R"({"LastLedgerSequence":11})"),
1963  ter(terQUEUED));
1964  checkMetrics(env, 4, boost::none, 2, 1, 256);
1965  auto const bobSeq = env.seq(bob);
1966  // Ledger 4 gets 3,
1967  // Ledger 5 gets 4,
1968  // Ledger 6 gets 5.
1969  for (int i = 0; i < 3 + 4 + 5; ++i)
1970  {
1971  env(noop(bob), seq(bobSeq + i), fee(200), ter(terQUEUED));
1972  }
1973  checkMetrics(env, 4 + 3 + 4 + 5, boost::none, 2, 1, 256);
1974  // Close ledger 3
1975  env.close();
1976  checkMetrics(env, 4 + 4 + 5, 20, 3, 2, 256);
1977  // Close ledger 4
1978  env.close();
1979  checkMetrics(env, 4 + 5, 30, 4, 3, 256);
1980  // Close ledger 5
1981  env.close();
1982  // Alice's first two txs expired.
1983  checkMetrics(env, 2, 40, 5, 4, 256);
1984 
1985  // Because aliceSeq is missing, aliceSeq + 1 fails
1986  env(noop(alice), seq(aliceSeq + 1), ter(terPRE_SEQ));
1987 
1988  // Queue up a new aliceSeq tx.
1989  // This will only do some of the multiTx validation to
1990  // improve the chances that the orphaned txs can be
1991  // recovered. Because the cost of relaying the later txs
1992  // has already been paid, this tx could potentially be a
1993  // blocker.
1994  env(fset(alice, asfAccountTxnID), seq(aliceSeq), ter(terQUEUED));
1995  checkMetrics(env, 3, 40, 5, 4, 256);
1996 
1997  // Even though consequences were not computed, we can replace it.
1998  env(noop(alice), seq(aliceSeq), fee(20), ter(terQUEUED));
1999  checkMetrics(env, 3, 40, 5, 4, 256);
2000 
2001  // Queue up a new aliceSeq + 1 tx.
2002  // This tx will also only do some of the multiTx validation.
2003  env(fset(alice, asfAccountTxnID), seq(aliceSeq + 1), ter(terQUEUED));
2004  checkMetrics(env, 4, 40, 5, 4, 256);
2005 
2006  // Even though consequences were not computed, we can replace it,
2007  // too.
2008  env(noop(alice), seq(aliceSeq + 1), fee(20), ter(terQUEUED));
2009  checkMetrics(env, 4, 40, 5, 4, 256);
2010 
2011  // Close ledger 6
2012  env.close();
2013  // We expect that all of alice's queued tx's got into
2014  // the open ledger.
2015  checkMetrics(env, 0, 50, 4, 5, 256);
2016  BEAST_EXPECT(env.seq(alice) == aliceSeq + 4);
2017  }
2018 
2019  void
2021  {
2022  testcase("Autofilled sequence should account for TxQ");
2023  using namespace jtx;
2024  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "6"}}));
2025  Env_ss envs(env);
2026  auto const& txQ = env.app().getTxQ();
2027 
2028  auto const alice = Account("alice");
2029  auto const bob = Account("bob");
2030  env.fund(XRP(100000), alice, bob);
2031 
2032  fillQueue(env, alice);
2033  checkMetrics(env, 0, boost::none, 7, 6, 256);
2034 
2035  // Queue up several transactions for alice sign-and-submit
2036  auto const aliceSeq = env.seq(alice);
2037  auto const lastLedgerSeq = env.current()->info().seq + 2;
2038 
2040  for (int i = 0; i < 5; ++i)
2041  {
2042  if (i == 2)
2043  envs(
2044  noop(alice),
2045  fee(1000),
2046  seq(none),
2047  json(jss::LastLedgerSequence, lastLedgerSeq),
2049  else
2050  envs(noop(alice), fee(1000), seq(none), ter(terQUEUED))(
2051  submitParams);
2052  }
2053  checkMetrics(env, 5, boost::none, 7, 6, 256);
2054  {
2055  auto aliceStat = txQ.getAccountTxs(alice.id(), *env.current());
2056  auto seq = aliceSeq;
2057  BEAST_EXPECT(aliceStat.size() == 5);
2058  for (auto const& tx : aliceStat)
2059  {
2060  BEAST_EXPECT(tx.first == seq);
2061  BEAST_EXPECT(tx.second.feeLevel == FeeLevel64{25600});
2062  if (seq == aliceSeq + 2)
2063  {
2064  BEAST_EXPECT(
2065  tx.second.lastValid &&
2066  *tx.second.lastValid == lastLedgerSeq);
2067  }
2068  else
2069  {
2070  BEAST_EXPECT(!tx.second.lastValid);
2071  }
2072  ++seq;
2073  }
2074  }
2075  // Put some txs in the queue for bob.
2076  // Give them a higher fee so they'll beat alice's.
2077  for (int i = 0; i < 8; ++i)
2078  envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
2079  checkMetrics(env, 13, boost::none, 7, 6, 256);
2080 
2081  env.close();
2082  checkMetrics(env, 5, 14, 8, 7, 256);
2083  // Put some more txs in the queue for bob.
2084  // Give them a higher fee so they'll beat alice's.
2085  fillQueue(env, bob);
2086  for (int i = 0; i < 9; ++i)
2087  envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
2088  checkMetrics(env, 14, 14, 8, 7, 25601);
2089  env.close();
2090  // Put some more txs in the queue for bob.
2091  // Give them a higher fee so they'll beat alice's.
2092  fillQueue(env, bob);
2093  for (int i = 0; i < 10; ++i)
2094  envs(noop(bob), fee(2000), seq(none), ter(terQUEUED))();
2095  checkMetrics(env, 15, 16, 9, 8, 256);
2096  env.close();
2097  checkMetrics(env, 4, 18, 10, 9, 256);
2098  {
2099  // Bob has nothing left in the queue.
2100  auto bobStat = txQ.getAccountTxs(bob.id(), *env.current());
2101  BEAST_EXPECT(bobStat.empty());
2102  }
2103  // Verify alice's tx got dropped as we BEAST_EXPECT, and that there's
2104  // a gap in her queued txs.
2105  {
2106  auto aliceStat = txQ.getAccountTxs(alice.id(), *env.current());
2107  auto seq = aliceSeq;
2108  BEAST_EXPECT(aliceStat.size() == 4);
2109  for (auto const& tx : aliceStat)
2110  {
2111  // Skip over the missing one.
2112  if (seq == aliceSeq + 2)
2113  ++seq;
2114 
2115  BEAST_EXPECT(tx.first == seq);
2116  BEAST_EXPECT(tx.second.feeLevel == FeeLevel64{25600});
2117  BEAST_EXPECT(!tx.second.lastValid);
2118  ++seq;
2119  }
2120  }
2121  // Now, fill the gap.
2122  envs(noop(alice), fee(1000), seq(none), ter(terQUEUED))(submitParams);
2123  checkMetrics(env, 5, 18, 10, 9, 256);
2124  {
2125  auto aliceStat = txQ.getAccountTxs(alice.id(), *env.current());
2126  auto seq = aliceSeq;
2127  BEAST_EXPECT(aliceStat.size() == 5);
2128  for (auto const& tx : aliceStat)
2129  {
2130  BEAST_EXPECT(tx.first == seq);
2131  BEAST_EXPECT(tx.second.feeLevel == FeeLevel64{25600});
2132  BEAST_EXPECT(!tx.second.lastValid);
2133  ++seq;
2134  }
2135  }
2136 
2137  env.close();
2138  checkMetrics(env, 0, 20, 5, 10, 256);
2139  {
2140  // Bob's data has been cleaned up.
2141  auto bobStat = txQ.getAccountTxs(bob.id(), *env.current());
2142  BEAST_EXPECT(bobStat.empty());
2143  }
2144  {
2145  auto aliceStat = txQ.getAccountTxs(alice.id(), *env.current());
2146  BEAST_EXPECT(aliceStat.empty());
2147  }
2148  }
2149 
2150  void
2152  {
2153  using namespace jtx;
2154  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
2155  Env_ss envs(env);
2156 
2157  Account const alice{"alice"};
2158  env.fund(XRP(1000000), alice);
2159  env.close();
2160 
2161  auto const withQueue =
2162  R"({ "account": ")" + alice.human() + R"(", "queue": true })";
2163  auto const withoutQueue = R"({ "account": ")" + alice.human() + R"("})";
2164  auto const prevLedgerWithQueue = R"({ "account": ")" + alice.human() +
2165  R"(", "queue": true, "ledger_index": 3 })";
2166  BEAST_EXPECT(env.current()->info().seq > 3);
2167 
2168  {
2169  // account_info without the "queue" argument.
2170  auto const info = env.rpc("json", "account_info", withoutQueue);
2171  BEAST_EXPECT(
2172  info.isMember(jss::result) &&
2173  info[jss::result].isMember(jss::account_data));
2174  BEAST_EXPECT(!info[jss::result].isMember(jss::queue_data));
2175  }
2176  {
2177  // account_info with the "queue" argument.
2178  auto const info = env.rpc("json", "account_info", withQueue);
2179  BEAST_EXPECT(
2180  info.isMember(jss::result) &&
2181  info[jss::result].isMember(jss::account_data));
2182  auto const& result = info[jss::result];
2183  BEAST_EXPECT(result.isMember(jss::queue_data));
2184  auto const& queue_data = result[jss::queue_data];
2185  BEAST_EXPECT(queue_data.isObject());
2186  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
2187  BEAST_EXPECT(queue_data[jss::txn_count] == 0);
2188  BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
2189  BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
2190  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
2191  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
2192  BEAST_EXPECT(!queue_data.isMember(jss::transactions));
2193  }
2194  checkMetrics(env, 0, 6, 0, 3, 256);
2195 
2196  fillQueue(env, alice);
2197  checkMetrics(env, 0, 6, 4, 3, 256);
2198 
2199  {
2200  auto const info = env.rpc("json", "account_info", withQueue);
2201  BEAST_EXPECT(
2202  info.isMember(jss::result) &&
2203  info[jss::result].isMember(jss::account_data));
2204  auto const& result = info[jss::result];
2205  BEAST_EXPECT(result.isMember(jss::queue_data));
2206  auto const& queue_data = result[jss::queue_data];
2207  BEAST_EXPECT(queue_data.isObject());
2208  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
2209  BEAST_EXPECT(queue_data[jss::txn_count] == 0);
2210  BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
2211  BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
2212  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
2213  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
2214  BEAST_EXPECT(!queue_data.isMember(jss::transactions));
2215  }
2216 
2218  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
2219  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
2220  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
2221  envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams);
2222  checkMetrics(env, 4, 6, 4, 3, 256);
2223 
2224  {
2225  auto const info = env.rpc("json", "account_info", withQueue);
2226  BEAST_EXPECT(
2227  info.isMember(jss::result) &&
2228  info[jss::result].isMember(jss::account_data));
2229  auto const& result = info[jss::result];
2230  auto const& data = result[jss::account_data];
2231  BEAST_EXPECT(result.isMember(jss::queue_data));
2232  auto const& queue_data = result[jss::queue_data];
2233  BEAST_EXPECT(queue_data.isObject());
2234  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
2235  BEAST_EXPECT(queue_data[jss::txn_count] == 4);
2236  BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
2237  BEAST_EXPECT(
2238  queue_data[jss::lowest_sequence] == data[jss::Sequence]);
2239  BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
2240  BEAST_EXPECT(
2241  queue_data[jss::highest_sequence] ==
2242  data[jss::Sequence].asUInt() +
2243  queue_data[jss::txn_count].asUInt() - 1);
2244  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
2245  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
2246  BEAST_EXPECT(queue_data.isMember(jss::transactions));
2247  auto const& queued = queue_data[jss::transactions];
2248  BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
2249  for (unsigned i = 0; i < queued.size(); ++i)
2250  {
2251  auto const& item = queued[i];
2252  BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
2253  BEAST_EXPECT(item[jss::fee_level] == "2560");
2254  BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
2255 
2256  if (i == queued.size() - 1)
2257  {
2258  BEAST_EXPECT(!item.isMember(jss::fee));
2259  BEAST_EXPECT(!item.isMember(jss::max_spend_drops));
2260  BEAST_EXPECT(!item.isMember(jss::auth_change));
2261  }
2262  else
2263  {
2264  BEAST_EXPECT(item.isMember(jss::fee));
2265  BEAST_EXPECT(item[jss::fee] == "100");
2266  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
2267  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
2268  BEAST_EXPECT(item.isMember(jss::auth_change));
2269  BEAST_EXPECT(!item[jss::auth_change].asBool());
2270  }
2271  }
2272  }
2273 
2274  // Queue up a blocker
2275  envs(
2276  fset(alice, asfAccountTxnID),
2277  fee(100),
2278  seq(none),
2279  json(jss::LastLedgerSequence, 10),
2280  ter(terQUEUED))(submitParams);
2281  checkMetrics(env, 5, 6, 4, 3, 256);
2282 
2283  {
2284  auto const info = env.rpc("json", "account_info", withQueue);
2285  BEAST_EXPECT(
2286  info.isMember(jss::result) &&
2287  info[jss::result].isMember(jss::account_data));
2288  auto const& result = info[jss::result];
2289  auto const& data = result[jss::account_data];
2290  BEAST_EXPECT(result.isMember(jss::queue_data));
2291  auto const& queue_data = result[jss::queue_data];
2292  BEAST_EXPECT(queue_data.isObject());
2293  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
2294  BEAST_EXPECT(queue_data[jss::txn_count] == 5);
2295  BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
2296  BEAST_EXPECT(
2297  queue_data[jss::lowest_sequence] == data[jss::Sequence]);
2298  BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
2299  BEAST_EXPECT(
2300  queue_data[jss::highest_sequence] ==
2301  data[jss::Sequence].asUInt() +
2302  queue_data[jss::txn_count].asUInt() - 1);
2303  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
2304  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
2305  BEAST_EXPECT(queue_data.isMember(jss::transactions));
2306  auto const& queued = queue_data[jss::transactions];
2307  BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
2308  for (unsigned i = 0; i < queued.size(); ++i)
2309  {
2310  auto const& item = queued[i];
2311  BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
2312  BEAST_EXPECT(item[jss::fee_level] == "2560");
2313 
2314  if (i == queued.size() - 1)
2315  {
2316  BEAST_EXPECT(!item.isMember(jss::fee));
2317  BEAST_EXPECT(!item.isMember(jss::max_spend_drops));
2318  BEAST_EXPECT(!item.isMember(jss::auth_change));
2319  BEAST_EXPECT(item.isMember(jss::LastLedgerSequence));
2320  BEAST_EXPECT(item[jss::LastLedgerSequence] == 10);
2321  }
2322  else
2323  {
2324  BEAST_EXPECT(item.isMember(jss::fee));
2325  BEAST_EXPECT(item[jss::fee] == "100");
2326  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
2327  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
2328  BEAST_EXPECT(item.isMember(jss::auth_change));
2329  BEAST_EXPECT(!item[jss::auth_change].asBool());
2330  BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
2331  }
2332  }
2333  }
2334 
2335  envs(noop(alice), fee(100), seq(none), ter(telCAN_NOT_QUEUE_BLOCKED))(
2336  submitParams);
2337  checkMetrics(env, 5, 6, 4, 3, 256);
2338 
2339  {
2340  auto const info = env.rpc("json", "account_info", withQueue);
2341  BEAST_EXPECT(
2342  info.isMember(jss::result) &&
2343  info[jss::result].isMember(jss::account_data));
2344  auto const& result = info[jss::result];
2345  auto const& data = result[jss::account_data];
2346  BEAST_EXPECT(result.isMember(jss::queue_data));
2347  auto const& queue_data = result[jss::queue_data];
2348  BEAST_EXPECT(queue_data.isObject());
2349  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
2350  BEAST_EXPECT(queue_data[jss::txn_count] == 5);
2351  BEAST_EXPECT(queue_data.isMember(jss::lowest_sequence));
2352  BEAST_EXPECT(
2353  queue_data[jss::lowest_sequence] == data[jss::Sequence]);
2354  BEAST_EXPECT(queue_data.isMember(jss::highest_sequence));
2355  BEAST_EXPECT(
2356  queue_data[jss::highest_sequence] ==
2357  data[jss::Sequence].asUInt() +
2358  queue_data[jss::txn_count].asUInt() - 1);
2359  BEAST_EXPECT(queue_data.isMember(jss::auth_change_queued));
2360  BEAST_EXPECT(queue_data[jss::auth_change_queued].asBool());
2361  BEAST_EXPECT(queue_data.isMember(jss::max_spend_drops_total));
2362  BEAST_EXPECT(queue_data[jss::max_spend_drops_total] == "500");
2363  BEAST_EXPECT(queue_data.isMember(jss::transactions));
2364  auto const& queued = queue_data[jss::transactions];
2365  BEAST_EXPECT(queued.size() == queue_data[jss::txn_count]);
2366  for (unsigned i = 0; i < queued.size(); ++i)
2367  {
2368  auto const& item = queued[i];
2369  BEAST_EXPECT(item[jss::seq] == data[jss::Sequence].asInt() + i);
2370  BEAST_EXPECT(item[jss::fee_level] == "2560");
2371 
2372  if (i == queued.size() - 1)
2373  {
2374  BEAST_EXPECT(item.isMember(jss::fee));
2375  BEAST_EXPECT(item[jss::fee] == "100");
2376  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
2377  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
2378  BEAST_EXPECT(item.isMember(jss::auth_change));
2379  BEAST_EXPECT(item[jss::auth_change].asBool());
2380  BEAST_EXPECT(item.isMember(jss::LastLedgerSequence));
2381  BEAST_EXPECT(item[jss::LastLedgerSequence] == 10);
2382  }
2383  else
2384  {
2385  BEAST_EXPECT(item.isMember(jss::fee));
2386  BEAST_EXPECT(item[jss::fee] == "100");
2387  BEAST_EXPECT(item.isMember(jss::max_spend_drops));
2388  BEAST_EXPECT(item[jss::max_spend_drops] == "100");
2389  BEAST_EXPECT(item.isMember(jss::auth_change));
2390  BEAST_EXPECT(!item[jss::auth_change].asBool());
2391  BEAST_EXPECT(!item.isMember(jss::LastLedgerSequence));
2392  }
2393  }
2394  }
2395 
2396  {
2397  auto const info =
2398  env.rpc("json", "account_info", prevLedgerWithQueue);
2399  BEAST_EXPECT(
2400  info.isMember(jss::result) &&
2401  RPC::contains_error(info[jss::result]));
2402  }
2403 
2404  env.close();
2405  checkMetrics(env, 1, 8, 5, 4, 256);
2406  env.close();
2407  checkMetrics(env, 0, 10, 1, 5, 256);
2408 
2409  {
2410  auto const info = env.rpc("json", "account_info", withQueue);
2411  BEAST_EXPECT(
2412  info.isMember(jss::result) &&
2413  info[jss::result].isMember(jss::account_data));
2414  auto const& result = info[jss::result];
2415  BEAST_EXPECT(result.isMember(jss::queue_data));
2416  auto const& queue_data = result[jss::queue_data];
2417  BEAST_EXPECT(queue_data.isObject());
2418  BEAST_EXPECT(queue_data.isMember(jss::txn_count));
2419  BEAST_EXPECT(queue_data[jss::txn_count] == 0);
2420  BEAST_EXPECT(!queue_data.isMember(jss::lowest_sequence));
2421  BEAST_EXPECT(!queue_data.isMember(jss::highest_sequence));
2422  BEAST_EXPECT(!queue_data.isMember(jss::auth_change_queued));
2423  BEAST_EXPECT(!queue_data.isMember(jss::max_spend_drops_total));
2424  BEAST_EXPECT(!queue_data.isMember(jss::transactions));
2425  }
2426  }
2427 
2428  void
2430  {
2431  using namespace jtx;
2432  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
2433  Env_ss envs(env);
2434 
2435  Account const alice{"alice"};
2436  env.fund(XRP(1000000), alice);
2437  env.close();
2438 
2439  {
2440  auto const server_info = env.rpc("server_info");
2441  BEAST_EXPECT(
2442  server_info.isMember(jss::result) &&
2443  server_info[jss::result].isMember(jss::info));
2444  auto const& info = server_info[jss::result][jss::info];
2445  BEAST_EXPECT(
2446  info.isMember(jss::load_factor) && info[jss::load_factor] == 1);
2447  BEAST_EXPECT(!info.isMember(jss::load_factor_server));
2448  BEAST_EXPECT(!info.isMember(jss::load_factor_local));
2449  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
2450  BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
2451  }
2452  {
2453  auto const server_state = env.rpc("server_state");
2454  auto const& state = server_state[jss::result][jss::state];
2455  BEAST_EXPECT(
2456  state.isMember(jss::load_factor) &&
2457  state[jss::load_factor] == 256);
2458  BEAST_EXPECT(
2459  state.isMember(jss::load_base) && state[jss::load_base] == 256);
2460  BEAST_EXPECT(
2461  state.isMember(jss::load_factor_server) &&
2462  state[jss::load_factor_server] == 256);
2463  BEAST_EXPECT(
2464  state.isMember(jss::load_factor_fee_escalation) &&
2465  state[jss::load_factor_fee_escalation] == 256);
2466  BEAST_EXPECT(
2467  state.isMember(jss::load_factor_fee_queue) &&
2468  state[jss::load_factor_fee_queue] == 256);
2469  BEAST_EXPECT(
2470  state.isMember(jss::load_factor_fee_reference) &&
2471  state[jss::load_factor_fee_reference] == 256);
2472  }
2473 
2474  checkMetrics(env, 0, 6, 0, 3, 256);
2475 
2476  fillQueue(env, alice);
2477  checkMetrics(env, 0, 6, 4, 3, 256);
2478 
2479  auto aliceSeq = env.seq(alice);
2481  for (auto i = 0; i < 4; ++i)
2482  envs(noop(alice), fee(100), seq(aliceSeq + i), ter(terQUEUED))(
2483  submitParams);
2484  checkMetrics(env, 4, 6, 4, 3, 256);
2485 
2486  {
2487  auto const server_info = env.rpc("server_info");
2488  BEAST_EXPECT(
2489  server_info.isMember(jss::result) &&
2490  server_info[jss::result].isMember(jss::info));
2491  auto const& info = server_info[jss::result][jss::info];
2492  // Avoid double rounding issues by comparing to a range.
2493  BEAST_EXPECT(
2494  info.isMember(jss::load_factor) &&
2495  info[jss::load_factor] > 888.88 &&
2496  info[jss::load_factor] < 888.89);
2497  BEAST_EXPECT(
2498  info.isMember(jss::load_factor_server) &&
2499  info[jss::load_factor_server] == 1);
2500  BEAST_EXPECT(!info.isMember(jss::load_factor_local));
2501  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
2502  BEAST_EXPECT(
2503  info.isMember(jss::load_factor_fee_escalation) &&
2504  info[jss::load_factor_fee_escalation] > 888.88 &&
2505  info[jss::load_factor_fee_escalation] < 888.89);
2506  }
2507  {
2508  auto const server_state = env.rpc("server_state");
2509  auto const& state = server_state[jss::result][jss::state];
2510  BEAST_EXPECT(
2511  state.isMember(jss::load_factor) &&
2512  state[jss::load_factor] == 227555);
2513  BEAST_EXPECT(
2514  state.isMember(jss::load_base) && state[jss::load_base] == 256);
2515  BEAST_EXPECT(
2516  state.isMember(jss::load_factor_server) &&
2517  state[jss::load_factor_server] == 256);
2518  BEAST_EXPECT(
2519  state.isMember(jss::load_factor_fee_escalation) &&
2520  state[jss::load_factor_fee_escalation] == 227555);
2521  BEAST_EXPECT(
2522  state.isMember(jss::load_factor_fee_queue) &&
2523  state[jss::load_factor_fee_queue] == 256);
2524  BEAST_EXPECT(
2525  state.isMember(jss::load_factor_fee_reference) &&
2526  state[jss::load_factor_fee_reference] == 256);
2527  }
2528 
2529  env.app().getFeeTrack().setRemoteFee(256000);
2530 
2531  {
2532  auto const server_info = env.rpc("server_info");
2533  BEAST_EXPECT(
2534  server_info.isMember(jss::result) &&
2535  server_info[jss::result].isMember(jss::info));
2536  auto const& info = server_info[jss::result][jss::info];
2537  // Avoid double rounding issues by comparing to a range.
2538  BEAST_EXPECT(
2539  info.isMember(jss::load_factor) &&
2540  info[jss::load_factor] == 1000);
2541  BEAST_EXPECT(!info.isMember(jss::load_factor_server));
2542  BEAST_EXPECT(!info.isMember(jss::load_factor_local));
2543  BEAST_EXPECT(
2544  info.isMember(jss::load_factor_net) &&
2545  info[jss::load_factor_net] == 1000);
2546  BEAST_EXPECT(
2547  info.isMember(jss::load_factor_fee_escalation) &&
2548  info[jss::load_factor_fee_escalation] > 888.88 &&
2549  info[jss::load_factor_fee_escalation] < 888.89);
2550  }
2551  {
2552  auto const server_state = env.rpc("server_state");
2553  auto const& state = server_state[jss::result][jss::state];
2554  BEAST_EXPECT(
2555  state.isMember(jss::load_factor) &&
2556  state[jss::load_factor] == 256000);
2557  BEAST_EXPECT(
2558  state.isMember(jss::load_base) && state[jss::load_base] == 256);
2559  BEAST_EXPECT(
2560  state.isMember(jss::load_factor_server) &&
2561  state[jss::load_factor_server] == 256000);
2562  BEAST_EXPECT(
2563  state.isMember(jss::load_factor_fee_escalation) &&
2564  state[jss::load_factor_fee_escalation] == 227555);
2565  BEAST_EXPECT(
2566  state.isMember(jss::load_factor_fee_queue) &&
2567  state[jss::load_factor_fee_queue] == 256);
2568  BEAST_EXPECT(
2569  state.isMember(jss::load_factor_fee_reference) &&
2570  state[jss::load_factor_fee_reference] == 256);
2571  }
2572 
2573  env.app().getFeeTrack().setRemoteFee(256);
2574 
2575  // Increase the server load
2576  for (int i = 0; i < 5; ++i)
2577  env.app().getFeeTrack().raiseLocalFee();
2578  BEAST_EXPECT(env.app().getFeeTrack().getLoadFactor() == 625);
2579 
2580  {
2581  auto const server_info = env.rpc("server_info");
2582  BEAST_EXPECT(
2583  server_info.isMember(jss::result) &&
2584  server_info[jss::result].isMember(jss::info));
2585  auto const& info = server_info[jss::result][jss::info];
2586  // Avoid double rounding issues by comparing to a range.
2587  BEAST_EXPECT(
2588  info.isMember(jss::load_factor) &&
2589  info[jss::load_factor] > 888.88 &&
2590  info[jss::load_factor] < 888.89);
2591  // There can be a race between LoadManager lowering the fee,
2592  // and the call to server_info, so check a wide range.
2593  // The important thing is that it's not 1.
2594  BEAST_EXPECT(
2595  info.isMember(jss::load_factor_server) &&
2596  info[jss::load_factor_server] > 1.245 &&
2597  info[jss::load_factor_server] < 2.4415);
2598  BEAST_EXPECT(
2599  info.isMember(jss::load_factor_local) &&
2600  info[jss::load_factor_local] > 1.245 &&
2601  info[jss::load_factor_local] < 2.4415);
2602  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
2603  BEAST_EXPECT(
2604  info.isMember(jss::load_factor_fee_escalation) &&
2605  info[jss::load_factor_fee_escalation] > 888.88 &&
2606  info[jss::load_factor_fee_escalation] < 888.89);
2607  }
2608  {
2609  auto const server_state = env.rpc("server_state");
2610  auto const& state = server_state[jss::result][jss::state];
2611  BEAST_EXPECT(
2612  state.isMember(jss::load_factor) &&
2613  state[jss::load_factor] == 227555);
2614  BEAST_EXPECT(
2615  state.isMember(jss::load_base) && state[jss::load_base] == 256);
2616  // There can be a race between LoadManager lowering the fee,
2617  // and the call to server_info, so check a wide range.
2618  // The important thing is that it's not 256.
2619  BEAST_EXPECT(
2620  state.isMember(jss::load_factor_server) &&
2621  state[jss::load_factor_server] >= 320 &&
2622  state[jss::load_factor_server] <= 625);
2623  BEAST_EXPECT(
2624  state.isMember(jss::load_factor_fee_escalation) &&
2625  state[jss::load_factor_fee_escalation] == 227555);
2626  BEAST_EXPECT(
2627  state.isMember(jss::load_factor_fee_queue) &&
2628  state[jss::load_factor_fee_queue] == 256);
2629  BEAST_EXPECT(
2630  state.isMember(jss::load_factor_fee_reference) &&
2631  state[jss::load_factor_fee_reference] == 256);
2632  }
2633 
2634  env.close();
2635 
2636  {
2637  auto const server_info = env.rpc("server_info");
2638  BEAST_EXPECT(
2639  server_info.isMember(jss::result) &&
2640  server_info[jss::result].isMember(jss::info));
2641  auto const& info = server_info[jss::result][jss::info];
2642  // Avoid double rounding issues by comparing to a range.
2643 
2644  // There can be a race between LoadManager lowering the fee,
2645  // and the call to server_info, so check a wide range.
2646  // The important thing is that it's not 1.
2647  BEAST_EXPECT(
2648  info.isMember(jss::load_factor) &&
2649  info[jss::load_factor] > 1.245 &&
2650  info[jss::load_factor] < 2.4415);
2651  BEAST_EXPECT(!info.isMember(jss::load_factor_server));
2652  BEAST_EXPECT(
2653  info.isMember(jss::load_factor_local) &&
2654  info[jss::load_factor_local] > 1.245 &&
2655  info[jss::load_factor_local] < 2.4415);
2656  BEAST_EXPECT(!info.isMember(jss::load_factor_net));
2657  BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
2658  }
2659  {
2660  auto const server_state = env.rpc("server_state");
2661  auto const& state = server_state[jss::result][jss::state];
2662  BEAST_EXPECT(
2663  state.isMember(jss::load_factor) &&
2664  state[jss::load_factor] >= 320 &&
2665  state[jss::load_factor] <= 625);
2666  BEAST_EXPECT(
2667  state.isMember(jss::load_base) && state[jss::load_base] == 256);
2668  // There can be a race between LoadManager lowering the fee,
2669  // and the call to server_info, so check a wide range.
2670  // The important thing is that it's not 256.
2671  BEAST_EXPECT(
2672  state.isMember(jss::load_factor_server) &&
2673  state[jss::load_factor_server] >= 320 &&
2674  state[jss::load_factor_server] <= 625);
2675  BEAST_EXPECT(
2676  state.isMember(jss::load_factor_fee_escalation) &&
2677  state[jss::load_factor_fee_escalation] == 256);
2678  BEAST_EXPECT(
2679  state.isMember(jss::load_factor_fee_queue) &&
2680  state[jss::load_factor_fee_queue] == 256);
2681  BEAST_EXPECT(
2682  state.isMember(jss::load_factor_fee_reference) &&
2683  state[jss::load_factor_fee_reference] == 256);
2684  }
2685  }
2686 
2687  void
2689  {
2690  using namespace jtx;
2691 
2692  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
2693 
2694  Json::Value stream;
2695  stream[jss::streams] = Json::arrayValue;
2696  stream[jss::streams].append("server");
2697  auto wsc = makeWSClient(env.app().config());
2698  {
2699  auto jv = wsc->invoke("subscribe", stream);
2700  BEAST_EXPECT(jv[jss::status] == "success");
2701  }
2702 
2703  Account a{"a"}, b{"b"}, c{"c"}, d{"d"}, e{"e"}, f{"f"}, g{"g"}, h{"h"},
2704  i{"i"};
2705 
2706  // Fund the first few accounts at non escalated fee
2707  env.fund(XRP(50000), noripple(a, b, c, d));
2708  checkMetrics(env, 0, boost::none, 4, 3, 256);
2709 
2710  // First transaction establishes the messaging
2711  using namespace std::chrono_literals;
2712  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
2713  return jv[jss::type] == "serverStatus" &&
2714  jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
2715  jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
2716  jv.isMember(jss::load_factor_server) &&
2717  jv[jss::load_factor_server] == 256 &&
2718  jv.isMember(jss::load_factor_fee_escalation) &&
2719  jv[jss::load_factor_fee_escalation] == 256 &&
2720  jv.isMember(jss::load_factor_fee_queue) &&
2721  jv[jss::load_factor_fee_queue] == 256 &&
2722  jv.isMember(jss::load_factor_fee_reference) &&
2723  jv[jss::load_factor_fee_reference] == 256;
2724  }));
2725  // Last transaction escalates the fee
2726  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
2727  return jv[jss::type] == "serverStatus" &&
2728  jv.isMember(jss::load_factor) &&
2729  jv[jss::load_factor] == 227555 && jv.isMember(jss::load_base) &&
2730  jv[jss::load_base] == 256 &&
2731  jv.isMember(jss::load_factor_server) &&
2732  jv[jss::load_factor_server] == 256 &&
2733  jv.isMember(jss::load_factor_fee_escalation) &&
2734  jv[jss::load_factor_fee_escalation] == 227555 &&
2735  jv.isMember(jss::load_factor_fee_queue) &&
2736  jv[jss::load_factor_fee_queue] == 256 &&
2737  jv.isMember(jss::load_factor_fee_reference) &&
2738  jv[jss::load_factor_fee_reference] == 256;
2739  }));
2740 
2741  env.close();
2742 
2743  // Closing ledger should publish a status update
2744  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
2745  return jv[jss::type] == "serverStatus" &&
2746  jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
2747  jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
2748  jv.isMember(jss::load_factor_server) &&
2749  jv[jss::load_factor_server] == 256 &&
2750  jv.isMember(jss::load_factor_fee_escalation) &&
2751  jv[jss::load_factor_fee_escalation] == 256 &&
2752  jv.isMember(jss::load_factor_fee_queue) &&
2753  jv[jss::load_factor_fee_queue] == 256 &&
2754  jv.isMember(jss::load_factor_fee_reference) &&
2755  jv[jss::load_factor_fee_reference] == 256;
2756  }));
2757 
2758  checkMetrics(env, 0, 8, 0, 4, 256);
2759 
2760  // Fund then next few accounts at non escalated fee
2761  env.fund(XRP(50000), noripple(e, f, g, h, i));
2762 
2763  // Extra transactions with low fee are queued
2764  auto queued = ter(terQUEUED);
2765  env(noop(a), fee(10), queued);
2766  env(noop(b), fee(10), queued);
2767  env(noop(c), fee(10), queued);
2768  env(noop(d), fee(10), queued);
2769  env(noop(e), fee(10), queued);
2770  env(noop(f), fee(10), queued);
2771  env(noop(g), fee(10), queued);
2772  checkMetrics(env, 7, 8, 5, 4, 256);
2773 
2774  // Last transaction escalates the fee
2775  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
2776  return jv[jss::type] == "serverStatus" &&
2777  jv.isMember(jss::load_factor) &&
2778  jv[jss::load_factor] == 200000 && jv.isMember(jss::load_base) &&
2779  jv[jss::load_base] == 256 &&
2780  jv.isMember(jss::load_factor_server) &&
2781  jv[jss::load_factor_server] == 256 &&
2782  jv.isMember(jss::load_factor_fee_escalation) &&
2783  jv[jss::load_factor_fee_escalation] == 200000 &&
2784  jv.isMember(jss::load_factor_fee_queue) &&
2785  jv[jss::load_factor_fee_queue] == 256 &&
2786  jv.isMember(jss::load_factor_fee_reference) &&
2787  jv[jss::load_factor_fee_reference] == 256;
2788  }));
2789 
2790  env.close();
2791  // Ledger close publishes with escalated fees for queued transactions
2792  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
2793  return jv[jss::type] == "serverStatus" &&
2794  jv.isMember(jss::load_factor) &&
2795  jv[jss::load_factor] == 184320 && jv.isMember(jss::load_base) &&
2796  jv[jss::load_base] == 256 &&
2797  jv.isMember(jss::load_factor_server) &&
2798  jv[jss::load_factor_server] == 256 &&
2799  jv.isMember(jss::load_factor_fee_escalation) &&
2800  jv[jss::load_factor_fee_escalation] == 184320 &&
2801  jv.isMember(jss::load_factor_fee_queue) &&
2802  jv[jss::load_factor_fee_queue] == 256 &&
2803  jv.isMember(jss::load_factor_fee_reference) &&
2804  jv[jss::load_factor_fee_reference] == 256;
2805  }));
2806 
2807  env.close();
2808  // ledger close clears queue so fee is back to normal
2809  BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
2810  return jv[jss::type] == "serverStatus" &&
2811  jv.isMember(jss::load_factor) && jv[jss::load_factor] == 256 &&
2812  jv.isMember(jss::load_base) && jv[jss::load_base] == 256 &&
2813  jv.isMember(jss::load_factor_server) &&
2814  jv[jss::load_factor_server] == 256 &&
2815  jv.isMember(jss::load_factor_fee_escalation) &&
2816  jv[jss::load_factor_fee_escalation] == 256 &&
2817  jv.isMember(jss::load_factor_fee_queue) &&
2818  jv[jss::load_factor_fee_queue] == 256 &&
2819  jv.isMember(jss::load_factor_fee_reference) &&
2820  jv[jss::load_factor_fee_reference] == 256;
2821  }));
2822 
2823  BEAST_EXPECT(!wsc->findMsg(1s, [&](auto const& jv) {
2824  return jv[jss::type] == "serverStatus";
2825  }));
2826 
2827  auto jv = wsc->invoke("unsubscribe", stream);
2828  BEAST_EXPECT(jv[jss::status] == "success");
2829  }
2830 
2831  void
2833  {
2834  using namespace jtx;
2835 
2836  Env env(*this, makeConfig({{"minimum_txn_in_ledger_standalone", "3"}}));
2837  auto alice = Account("alice");
2838  auto bob = Account("bob");
2839 
2840  checkMetrics(env, 0, boost::none, 0, 3, 256);
2841  env.fund(XRP(50000000), alice, bob);
2842 
2843  fillQueue(env, alice);
2844 
2845  auto calcTotalFee = [&](std::int64_t alreadyPaid,
2846  boost::optional<std::size_t> numToClear =
2847  boost::none) -> std::uint64_t {
2848  auto totalFactor = 0;
2849  auto const metrics = env.app().getTxQ().getMetrics(*env.current());
2850  if (!numToClear)
2851  numToClear.emplace(metrics.txCount + 1);
2852  for (int i = 0; i < *numToClear; ++i)
2853  {
2854  auto inLedger = metrics.txInLedger + i;
2855  totalFactor += inLedger * inLedger;
2856  }
2857  auto result = toDrops(
2858  metrics.medFeeLevel * totalFactor /
2859  (metrics.txPerLedger * metrics.txPerLedger),
2860  env.current()->fees().base)
2861  .second.drops();
2862  // Subtract the fees already paid
2863  result -= alreadyPaid;
2864  // round up
2865  ++result;
2866  return result;
2867  };
2868 
2869  testcase("straightfoward positive case");
2870  {
2871  // Queue up some transactions at a too-low fee.
2872  auto aliceSeq = env.seq(alice);
2873  for (int i = 0; i < 2; ++i)
2874  {
2875  env(noop(alice), fee(100), seq(aliceSeq++), ter(terQUEUED));
2876  }
2877 
2878  // Queue up a transaction paying the open ledger fee
2879  // This will be the first tx to call the operative function,
2880  // but it won't succeed.
2881  env(noop(alice),
2882  openLedgerFee(env),
2883  seq(aliceSeq++),
2884  ter(terQUEUED));
2885 
2886  checkMetrics(env, 3, boost::none, 4, 3, 256);
2887 
2888  // Figure out how much it would cost to cover all the
2889  // queued txs + itself
2890  std::uint64_t totalFee1 = calcTotalFee(100 * 2 + 8889);
2891  --totalFee1;
2892 
2893  BEAST_EXPECT(totalFee1 == 60911);
2894  // Submit a transaction with that fee. It will get queued
2895  // because the fee level calculation rounds down. This is
2896  // the edge case test.
2897  env(noop(alice), fee(totalFee1), seq(aliceSeq++), ter(terQUEUED));
2898 
2899  checkMetrics(env, 4, boost::none, 4, 3, 256);
2900 
2901  // Now repeat the process including the new tx
2902  // and avoiding the rounding error
2903  std::uint64_t const totalFee2 =
2904  calcTotalFee(100 * 2 + 8889 + 60911);
2905  BEAST_EXPECT(totalFee2 == 35556);
2906  // Submit a transaction with that fee. It will succeed.
2907  env(noop(alice), fee(totalFee2), seq(aliceSeq++));
2908 
2909  checkMetrics(env, 0, boost::none, 9, 3, 256);
2910  }
2911 
2912  testcase("replace last tx with enough to clear queue");
2913  {
2914  // Queue up some transactions at a too-low fee.
2915  auto aliceSeq = env.seq(alice);
2916  for (int i = 0; i < 2; ++i)
2917  {
2918  env(noop(alice), fee(100), seq(aliceSeq++), ter(terQUEUED));
2919  }
2920 
2921  // Queue up a transaction paying the open ledger fee
2922  // This will be the first tx to call the operative function,
2923  // but it won't succeed.
2924  env(noop(alice),
2925  openLedgerFee(env),
2926  seq(aliceSeq++),
2927  ter(terQUEUED));
2928 
2929  checkMetrics(env, 3, boost::none, 9, 3, 256);
2930 
2931  // Figure out how much it would cost to cover all the
2932  // queued txs + itself
2933  auto const metrics = env.app().getTxQ().getMetrics(*env.current());
2934  std::uint64_t const totalFee =
2935  calcTotalFee(100 * 2, metrics.txCount);
2936  BEAST_EXPECT(totalFee == 167578);
2937  // Replacing the last tx with the large fee succeeds.
2938  --aliceSeq;
2939  env(noop(alice), fee(totalFee), seq(aliceSeq++));
2940 
2941  // The queue is clear
2942  checkMetrics(env, 0, boost::none, 12, 3, 256);
2943 
2944  env.close();
2945  checkMetrics(env, 0, 24, 0, 12, 256);
2946  }
2947 
2948  testcase("replace middle tx with enough to clear queue");
2949  {
2950  fillQueue(env, alice);
2951  // Queue up some transactions at a too-low fee.
2952  auto aliceSeq = env.seq(alice);
2953  for (int i = 0; i < 5; ++i)
2954  {
2955  env(noop(alice), fee(100), seq(aliceSeq++), ter(terQUEUED));
2956  }
2957 
2958  checkMetrics(env, 5, 24, 13, 12, 256);
2959 
2960  // Figure out how much it would cost to cover 3 txns
2961  std::uint64_t const totalFee = calcTotalFee(100 * 2, 3);
2962  BEAST_EXPECT(totalFee == 20287);
2963  // Replacing the last tx with the large fee succeeds.
2964  aliceSeq -= 3;
2965  env(noop(alice), fee(totalFee), seq(aliceSeq++));
2966 
2967  checkMetrics(env, 2, 24, 16, 12, 256);
2968  auto const aliceQueue =
2969  env.app().getTxQ().getAccountTxs(alice.id(), *env.current());
2970  BEAST_EXPECT(aliceQueue.size() == 2);
2971  auto seq = aliceSeq;
2972  for (auto const& tx : aliceQueue)
2973  {
2974  BEAST_EXPECT(tx.first == seq);
2975  BEAST_EXPECT(tx.second.feeLevel == FeeLevel64{2560});
2976  ++seq;
2977  }
2978 
2979  // Close the ledger to clear the queue
2980  env.close();
2981  checkMetrics(env, 0, 32, 2, 16, 256);
2982  }
2983 
2984  testcase("clear queue failure (load)");
2985  {
2986  fillQueue(env, alice);
2987  // Queue up some transactions at a too-low fee.
2988  auto aliceSeq = env.seq(alice);
2989  for (int i = 0; i < 2; ++i)
2990  {
2991  env(noop(alice), fee(200), seq(aliceSeq++), ter(terQUEUED));
2992  }
2993  for (int i = 0; i < 2; ++i)
2994  {
2995  env(noop(alice), fee(22), seq(aliceSeq++), ter(terQUEUED));
2996  }
2997 
2998  checkMetrics(env, 4, 32, 17, 16, 256);
2999 
3000  // Figure out how much it would cost to cover all the txns
3001  // + 1
3002  std::uint64_t const totalFee = calcTotalFee(200 * 2 + 22 * 2);
3003  BEAST_EXPECT(totalFee == 35006);
3004  // This fee should be enough, but oh no! Server load went up!
3005  auto& feeTrack = env.app().getFeeTrack();
3006  auto const origFee = feeTrack.getRemoteFee();
3007  feeTrack.setRemoteFee(origFee * 5);
3008  // Instead the tx gets queued, and all of the queued
3009  // txs stay in the queue.
3010  env(noop(alice), fee(totalFee), seq(aliceSeq++), ter(terQUEUED));
3011 
3012  // The original last transaction is still in the queue
3013  checkMetrics(env, 5, 32, 17, 16, 256);
3014 
3015  // With high load, some of the txs stay in the queue
3016  env.close();
3017  checkMetrics(env, 3, 34, 2, 17, 256);
3018 
3019  // Load drops back down
3020  feeTrack.setRemoteFee(origFee);
3021 
3022  // Because of the earlier failure, alice can not clear the queue,
3023  // no matter how high the fee
3024  fillQueue(env, bob);
3025  checkMetrics(env, 3, 34, 18, 17, 256);
3026 
3027  env(noop(alice), fee(XRP(1)), seq(aliceSeq++), ter(terQUEUED));
3028  checkMetrics(env, 4, 34, 18, 17, 256);
3029 
3030  // With normal load, those txs get into the ledger
3031  env.close();
3032  checkMetrics(env, 0, 36, 4, 18, 256);
3033  }
3034  }
3035 
3036  void
3038  {
3039  using namespace jtx;
3040  using namespace std::chrono_literals;
3041 
3042  {
3043  Env env(
3044  *this,
3045  makeConfig(
3046  {{"minimum_txn_in_ledger_standalone", "3"},
3047  {"normal_consensus_increase_percent", "25"},
3048  {"slow_consensus_decrease_percent", "50"},
3049  {"target_txn_in_ledger", "10"},
3050  {"maximum_txn_per_account", "200"}}));
3051  auto alice = Account("alice");
3052 
3053  checkMetrics(env, 0, boost::none, 0, 3, 256);
3054  env.fund(XRP(50000000), alice);
3055 
3056  fillQueue(env, alice);
3057  checkMetrics(env, 0, boost::none, 4, 3, 256);
3058  auto seqAlice = env.seq(alice);
3059  auto txCount = 140;
3060  for (int i = 0; i < txCount; ++i)
3061  env(noop(alice), seq(seqAlice++), ter(terQUEUED));
3062  checkMetrics(env, txCount, boost::none, 4, 3, 256);
3063 
3064  // Close a few ledgers successfully, so the limit grows
3065 
3066  env.close();
3067  // 4 + 25% = 5
3068  txCount -= 6;
3069  checkMetrics(env, txCount, 10, 6, 5, 257);
3070 
3071  env.close();
3072  // 6 + 25% = 7
3073  txCount -= 8;
3074  checkMetrics(env, txCount, 14, 8, 7, 257);
3075 
3076  env.close();
3077  // 8 + 25% = 10
3078  txCount -= 11;
3079  checkMetrics(env, txCount, 20, 11, 10, 257);
3080 
3081  env.close();
3082  // 11 + 25% = 13
3083  txCount -= 14;
3084  checkMetrics(env, txCount, 26, 14, 13, 257);
3085 
3086  env.close();
3087  // 14 + 25% = 17
3088  txCount -= 18;
3089  checkMetrics(env, txCount, 34, 18, 17, 257);
3090 
3091  env.close();
3092  // 18 + 25% = 22
3093  txCount -= 23;
3094  checkMetrics(env, txCount, 44, 23, 22, 257);
3095 
3096  env.close();
3097  // 23 + 25% = 28
3098  txCount -= 29;
3099  checkMetrics(env, txCount, 56, 29, 28, 256);
3100 
3101  // From 3 expected to 28 in 7 "fast" ledgers.
3102 
3103  // Close the ledger with a delay.
3104  env.close(env.now() + 5s, 10000ms);
3105  txCount -= 15;
3106  checkMetrics(env, txCount, 56, 15, 14, 256);
3107 
3108  // Close the ledger with a delay.
3109  env.close(env.now() + 5s, 10000ms);
3110  txCount -= 8;
3111  checkMetrics(env, txCount, 56, 8, 7, 256);
3112 
3113  // Close the ledger with a delay.
3114  env.close(env.now() + 5s, 10000ms);
3115  txCount -= 4;
3116  checkMetrics(env, txCount, 56, 4, 3, 256);
3117 
3118  // From 28 expected back down to 3 in 3 "slow" ledgers.
3119 
3120  // Confirm the minimum sticks
3121  env.close(env.now() + 5s, 10000ms);
3122  txCount -= 4;
3123  checkMetrics(env, txCount, 56, 4, 3, 256);
3124 
3125  BEAST_EXPECT(!txCount);
3126  }
3127 
3128  {
3129  Env env(
3130  *this,
3131  makeConfig(
3132  {{"minimum_txn_in_ledger_standalone", "3"},
3133  {"normal_consensus_increase_percent", "150"},
3134  {"slow_consensus_decrease_percent", "150"},
3135  {"target_txn_in_ledger", "10"},
3136  {"maximum_txn_per_account", "200"}}));
3137  auto alice = Account("alice");
3138 
3139  checkMetrics(env, 0, boost::none, 0, 3, 256);
3140  env.fund(XRP(50000000), alice);
3141 
3142  fillQueue(env, alice);
3143  checkMetrics(env, 0, boost::none, 4, 3, 256);
3144  auto seqAlice = env.seq(alice);
3145  auto txCount = 43;
3146  for (int i = 0; i < txCount; ++i)
3147  env(noop(alice), seq(seqAlice++), ter(terQUEUED));
3148  checkMetrics(env, txCount, boost::none, 4, 3, 256);
3149 
3150  // Close a few ledgers successfully, so the limit grows
3151 
3152  env.close();
3153  // 4 + 150% = 10
3154  txCount -= 11;
3155  checkMetrics(env, txCount, 20, 11, 10, 257);
3156 
3157  env.close();
3158  // 11 + 150% = 27
3159  txCount -= 28;
3160  checkMetrics(env, txCount, 54, 28, 27, 256);
3161 
3162  // From 3 expected to 28 in 7 "fast" ledgers.
3163 
3164  // Close the ledger with a delay.
3165  env.close(env.now() + 5s, 10000ms);
3166  txCount -= 4;
3167  checkMetrics(env, txCount, 54, 4, 3, 256);
3168 
3169  // From 28 expected back down to 3 in 3 "slow" ledgers.
3170 
3171  BEAST_EXPECT(!txCount);
3172  }
3173  }
3174 
3175  void
3176  run() override
3177  {
3178  testQueue();
3179  testLocalTxRetry();
3181  testZeroFeeTxn();
3185  testTieBreaking();
3186  testAcctTxnID();
3187  testMaximum();
3189  testBlockers();
3191  testConsequences();
3192  testRPC();
3195  testAccountInfo();
3196  testServerInfo();
3199  testScaling();
3200  }
3201 };
3202 
3204 
3205 } // namespace test
3206 } // namespace ripple
ripple::test::BEAST_DEFINE_TESTSUITE_PRIO
BEAST_DEFINE_TESTSUITE_PRIO(Flow, app, ripple, 2)
ripple::test::TxQ_test::envs
envs(noop(alice), fee(100), seq(none), ter(terQUEUED))(submitParams)
ripple::tecUNFUNDED_OFFER
@ tecUNFUNDED_OFFER
Definition: TER.h:242
ripple::test::jtx::json
Inject raw JSON.
Definition: jtx_json.h:31
ripple::test::TxQ_test::checkMetrics
void checkMetrics(jtx::Env &env, std::size_t expectedCount, boost::optional< std::size_t > expectedMaxCount, std::size_t expectedInLedger, std::size_t expectedPerLedger, std::uint64_t expectedMinFeeLevel, std::uint64_t expectedMedFeeLevel=256 *500)
Definition: TxQ_test.cpp:44
ripple::test::jtx::noop
Json::Value noop(Account const &account)
The null transaction.
Definition: noop.h:31
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::test::TxQ_test::testLastLedgerSeq
void testLastLedgerSeq()
Definition: TxQ_test.cpp:454
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:189
ripple::test::TxQ_test::withoutQueue
const auto withoutQueue
Definition: TxQ_test.cpp:2163
ripple::apply
std::pair< TER, bool > apply(Application &app, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
Definition: apply.cpp:109
ripple::test::jtx::ter
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
ripple::test::jtx::owners
Match the number of items in the account's owner directory.
Definition: owners.h:69
ripple::test::jtx::Env::require
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:464
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::test::jtx::balance
A balance matches.
Definition: balance.h:38
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:52
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:437
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::TxQ_test::testMaximum
void testMaximum()
Definition: TxQ_test.cpp:1155
ripple::test::jtx::require
Check a set of conditions.
Definition: require.h:63
ripple::TxConsequences::normal
@ normal
Moves currency around, creates offers, etc.
Definition: applySteps.h:132
ripple::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:141
ripple::telCAN_NOT_QUEUE_FULL
@ telCAN_NOT_QUEUE_FULL
Definition: TER.h:63
ripple::telCAN_NOT_QUEUE
@ telCAN_NOT_QUEUE
Definition: TER.h:58
ripple::test::TxQ_test::testServerInfo
void testServerInfo()
Definition: TxQ_test.cpp:2429
ripple::test::TxQ_test::testMultiTxnPerAccount
void testMultiTxnPerAccount()
Definition: TxQ_test.cpp:741
ripple::test::TxQ_test::testTecResult
void testTecResult()
Definition: TxQ_test.cpp:363
ripple::test::jtx::Env::balance
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition: Env.cpp:164
ripple::test::TxQ_test::submitParams
auto submitParams
Definition: TxQ_test.cpp:2217
ripple::test::TxQ_test::testLocalTxRetry
void testLocalTxRetry()
Definition: TxQ_test.cpp:398
ripple::test::TxQ_test::testZeroFeeTxn
void testZeroFeeTxn()
Definition: TxQ_test.cpp:563
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:238
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
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:404
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::tapNONE
@ tapNONE
Definition: ApplyView.h:31
ripple::test::TxQ_test::testPreclaimFailures
void testPreclaimFailures()
Definition: TxQ_test.cpp:668
ripple::test::TxQ_test::queued
auto const & queued
Definition: TxQ_test.cpp:2247
ripple::asfAccountTxnID
const std::uint32_t asfAccountTxnID
Definition: TxFlags.h:69
ripple::Application::getFeeTrack
virtual LoadFeeTrack & getFeeTrack()=0
ripple::terQUEUED
@ terQUEUED
Definition: TER.h:198
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:493
std::tie
T tie(T... args)
ripple::LoadFeeTrack::getRemoteFee
std::uint32_t getRemoteFee() const
Definition: LoadFeeTrack.h:66
ripple::test::TxQ_test::queue_data
auto const & queue_data
Definition: TxQ_test.cpp:2184
ripple::test::TxQ_test::testTieBreaking
void testTieBreaking()
Definition: TxQ_test.cpp:979
ripple::test::TxQ_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:127
ripple::TxQ
Transaction Queue.
Definition: TxQ.h:54
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::RPC::contains_error
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:218
ripple::test::TxQ_test::run
void run() override
Definition: TxQ_test.cpp:3176
ripple::test::TxQ_test::BEAST_EXPECT
BEAST_EXPECT(env.current() ->info().seq > 3)
ripple::test::jtx::Env::postconditions
void postconditions(JTx const &jt, TER ter, bool didApply)
Check expected postconditions of JTx submission.
Definition: Env.cpp:328
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::TxQ_test::result
auto const & result
Definition: TxQ_test.cpp:2182
ripple::test::TxQ_test::testAcctTxnID
void testAcctTxnID()
Definition: TxQ_test.cpp:1117
ripple::Application::getTxQ
virtual TxQ & getTxQ()=0
ripple::test::jtx::fset
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:28
ripple::telINSUF_FEE_P
@ telINSUF_FEE_P
Definition: TER.h:56
ripple::test::reserve
static XRPAmount reserve(jtx::Env &env, std::uint32_t count)
Definition: DepositAuth_test.cpp:29
ripple::test::TxQ_test::testInFlightBalance
void testInFlightBalance()
Definition: TxQ_test.cpp:1418
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:276
ripple::test::TxQ_test::testSignAndSubmitSequence
void testSignAndSubmitSequence()
Definition: TxQ_test.cpp:2020
ripple::test::TxQ_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:92
ripple::test::TxQ_test::testClearQueuedAccountTxs
void testClearQueuedAccountTxs()
Definition: TxQ_test.cpp:2832
std::runtime_error
STL class.
ripple::TxQ::getAccountTxs
std::map< TxSeq, AccountTxDetails const > getAccountTxs(AccountID const &account, ReadView const &view) const
Returns information about the transactions currently in the queue for the account.
Definition: TxQ.cpp:1373
ripple::temBAD_AMOUNT
@ temBAD_AMOUNT
Definition: TER.h:84
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::test::TxQ_test::testUnexpectedBalanceChange
void testUnexpectedBalanceChange()
Definition: TxQ_test.cpp:1251
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:69
std::uint64_t
ripple::featureTickets
const uint256 featureTickets
Definition: Feature.cpp:160
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:188
ripple::feeunit::TaggedFee
Definition: FeeUnits.h:70
std::map
STL class.
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::TxQ_test::testQueuedFailure
void testQueuedFailure()
Definition: TxQ_test.cpp:691
ripple::test::TxQ_test::testServerSubscribe
void testServerSubscribe()
Definition: TxQ_test.cpp:2688
ripple::test::jtx::fee
Set the fee on a JTx.
Definition: fee.h:34
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::TxQ_test::openLedgerFee
auto openLedgerFee(jtx::Env &env)
Definition: TxQ_test.cpp:79
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:32
ripple::test::TxQ_test::prevLedgerWithQueue
const auto prevLedgerWithQueue
Definition: TxQ_test.cpp:2164
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:63
ripple::LoadFeeTrack::getLoadFactor
std::uint32_t getLoadFactor() const
Definition: LoadFeeTrack.h:93
ripple::calculateConsequences
TxConsequences calculateConsequences(PreflightResult const &preflightResult)
Determine the XRP balance consequences if a transaction consumes the maximum XRP allowed.
Definition: applySteps.cpp:476
ripple::sfBalance
const SF_Amount sfBalance(access, STI_AMOUNT, 2, "Balance")
Definition: SField.h:440
ripple::LoadFeeTrack::raiseLocalFee
bool raiseLocalFee()
Definition: LoadFeeTrack.cpp:37
ripple::test::TxQ_test::testConsequences
void testConsequences()
Definition: TxQ_test.cpp:1772
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:261
ripple::test::TxQ_test::testScaling
void testScaling()
Definition: TxQ_test.cpp:3037
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:111
ripple::test::jtx::regkey
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Definition: regkey.cpp:28
ripple::test::TxQ_test::testExpirationReplacement
void testExpirationReplacement()
Definition: TxQ_test.cpp:1917
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:209
ripple::test::jtx::Env::le
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:197
ripple::TxQ::Metrics::txInLedger
std::size_t txInLedger
Number of transactions currently in the open ledger.
Definition: TxQ.h:190
ripple::toFeeLevel
std::pair< bool, FeeLevel64 > toFeeLevel(XRPAmount const &drops, XRPAmount const &baseFee)
Definition: TxQ.h:785
ripple::toDrops
std::pair< bool, XRPAmount > toDrops(FeeLevel< T > const &level, XRPAmount const &baseFee)
Definition: TxQ.h:779
ripple::test::jtx::Env::master
Account const & master
Definition: Env.h:119
ripple::tefWRONG_PRIOR
@ tefWRONG_PRIOR
Definition: TER.h:152
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:299
std::map::empty
T empty(T... args)
ripple::terPRE_SEQ
@ terPRE_SEQ
Definition: TER.h:194
std::size_t
ripple::test::TxQ_test::data
auto const & data
Definition: TxQ_test.cpp:2230
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::test::TxQ_test::fillQueue
void fillQueue(jtx::Env &env, jtx::Account const &account)
Definition: TxQ_test.cpp:71
ripple::test::TxQ_test::testQueue
void testQueue()
Definition: TxQ_test.cpp:173
ripple::TxQ::getMetrics
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
Definition: TxQ.cpp:1314
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:140
ripple::test::TxQ_test::testBlockers
void testBlockers()
Definition: TxQ_test.cpp:1347
std::unique_ptr
STL class.
ripple::telCAN_NOT_QUEUE_BALANCE
@ telCAN_NOT_QUEUE_BALANCE
Definition: TER.h:59
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:213
ripple::test::TxQ_test::testRPC
void testRPC()
Definition: TxQ_test.cpp:1855
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:297
ripple::test::TxQ_test
Definition: TxQ_test.cpp:41
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:114
ripple::test::TxQ_test::testAccountInfo
void testAccountInfo()
Definition: TxQ_test.cpp:2151
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:682
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::XRPAmount
Definition: XRPAmount.h:46
ripple::test::jtx::owner_count
Definition: owners.h:49
std::chrono