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