rippled
ReducedOffer_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2022 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/protocol/Feature.h>
21 #include <ripple/protocol/Quality.h>
22 #include <ripple/protocol/jss.h>
23 #include <test/jtx.h>
24 
25 namespace ripple {
26 namespace test {
27 
28 class ReducedOffer_test : public beast::unit_test::suite
29 {
30  static auto
32  jtx::Env& env,
33  jtx::Account const& acct,
34  std::uint32_t offer_seq)
35  {
36  Json::Value jvParams;
37  jvParams[jss::offer][jss::account] = acct.human();
38  jvParams[jss::offer][jss::seq] = offer_seq;
39  return env.rpc(
40  "json", "ledger_entry", to_string(jvParams))[jss::result];
41  }
42 
43  static bool
45  jtx::Env& env,
46  jtx::Account const& acct,
47  std::uint32_t offerSeq)
48  {
49  Json::Value ledgerOffer = ledgerEntryOffer(env, acct, offerSeq);
50  return !(
51  ledgerOffer.isMember(jss::error) &&
52  ledgerOffer[jss::error].asString() == "entryNotFound");
53  }
54 
55  // Common code to clean up unneeded offers.
56  static void
58  jtx::Env& env,
59  jtx::Account const& acct1,
60  jtx::Account const& acct2,
61  std::uint32_t acct1OfferSeq,
62  std::uint32_t acct2OfferSeq)
63  {
64  env(offer_cancel(acct1, acct1OfferSeq));
65  env(offer_cancel(acct2, acct2OfferSeq));
66  env.close();
67  }
68 
69 public:
70  void
72  {
73  testcase("exercise partial cross new XRP/IOU offer Q change");
74 
75  using namespace jtx;
76 
77  auto const gw = Account{"gateway"};
78  auto const alice = Account{"alice"};
79  auto const bob = Account{"bob"};
80  auto const USD = gw["USD"];
81 
82  // Make one test run without fixReducedOffersV1 and one with.
83  for (FeatureBitset features :
86  {
87  Env env{*this, features};
88 
89  // Make sure none of the offers we generate are under funded.
90  env.fund(XRP(10'000'000), gw, alice, bob);
91  env.close();
92 
93  env(trust(alice, USD(10'000'000)));
94  env(trust(bob, USD(10'000'000)));
95  env.close();
96 
97  env(pay(gw, bob, USD(10'000'000)));
98  env.close();
99 
100  // Lambda that:
101  // 1. Exercises one offer pair,
102  // 2. Collects the results, and
103  // 3. Cleans up for the next offer pair.
104  // Returns 1 if the crossed offer has a bad rate for the book.
105  auto exerciseOfferPair =
106  [this, &env, &alice, &bob](
107  Amounts const& inLedger,
108  Amounts const& newOffer) -> unsigned int {
109  // Put inLedger offer in the ledger so newOffer can cross it.
110  std::uint32_t const aliceOfferSeq = env.seq(alice);
111  env(offer(alice, inLedger.in, inLedger.out));
112  env.close();
113 
114  // Now alice's offer will partially cross bob's offer.
115  STAmount const initialRate = Quality(newOffer).rate();
116  std::uint32_t const bobOfferSeq = env.seq(bob);
117  STAmount const bobInitialBalance = env.balance(bob);
118  STAmount const bobsFee = drops(10);
119  env(offer(bob, newOffer.in, newOffer.out, tfSell),
120  fee(bobsFee));
121  env.close();
122  STAmount const bobFinalBalance = env.balance(bob);
123 
124  // alice's offer should be fully crossed and so gone from
125  // the ledger.
126  if (!BEAST_EXPECT(!offerInLedger(env, alice, aliceOfferSeq)))
127  // If the in-ledger offer was not consumed then further
128  // results are meaningless.
129  return 1;
130 
131  // bob's offer should be in the ledger, but reduced in size.
132  unsigned int badRate = 1;
133  {
134  Json::Value bobOffer =
135  ledgerEntryOffer(env, bob, bobOfferSeq);
136 
137  STAmount const reducedTakerGets = amountFromJson(
138  sfTakerGets, bobOffer[jss::node][sfTakerGets.jsonName]);
139  STAmount const reducedTakerPays = amountFromJson(
140  sfTakerPays, bobOffer[jss::node][sfTakerPays.jsonName]);
141  STAmount const bobGot =
142  env.balance(bob) + bobsFee - bobInitialBalance;
143  BEAST_EXPECT(reducedTakerPays < newOffer.in);
144  BEAST_EXPECT(reducedTakerGets < newOffer.out);
145  STAmount const inLedgerRate =
146  Quality(Amounts{reducedTakerPays, reducedTakerGets})
147  .rate();
148 
149  badRate = inLedgerRate > initialRate ? 1 : 0;
150 
151  // If the inLedgerRate is less than initial rate, then
152  // incrementing the mantissa of the reduced taker pays
153  // should result in a rate higher than initial. Check
154  // this to verify that the largest allowable TakerPays
155  // was computed.
156  if (badRate == 0)
157  {
158  STAmount const tweakedTakerPays =
159  reducedTakerPays + drops(1);
160  STAmount const tweakedRate =
161  Quality(Amounts{tweakedTakerPays, reducedTakerGets})
162  .rate();
163  BEAST_EXPECT(tweakedRate > initialRate);
164  }
165 #if 0
166  std::cout << "Placed rate: " << initialRate
167  << "; in-ledger rate: " << inLedgerRate
168  << "; TakerPays: " << reducedTakerPays
169  << "; TakerGets: " << reducedTakerGets
170  << "; bob already got: " << bobGot << std::endl;
171 // #else
172  std::string_view filler =
173  inLedgerRate > initialRate ? "**" : " ";
174  std::cout << "| `" << reducedTakerGets << "` | `"
175  << reducedTakerPays << "` | `" << initialRate
176  << "` | " << filler << "`" << inLedgerRate << "`"
177  << filler << " |`" << std::endl;
178 #endif
179  }
180 
181  // In preparation for the next iteration make sure the two
182  // offers are gone from the ledger.
183  cleanupOldOffers(env, alice, bob, aliceOfferSeq, bobOfferSeq);
184  return badRate;
185  };
186 
187  // bob's offer (the new offer) is the same every time:
188  Amounts const bobsOffer{
189  STAmount(XRP(1)), STAmount(USD.issue(), 1, 0)};
190 
191  // alice's offer has a slightly smaller TakerPays with each
192  // iteration. This should mean that the size of the offer bob
193  // places in the ledger should increase with each iteration.
194  unsigned int blockedCount = 0;
195  for (std::uint64_t mantissaReduce = 1'000'000'000ull;
196  mantissaReduce <= 5'000'000'000ull;
197  mantissaReduce += 20'000'000ull)
198  {
199  STAmount aliceUSD{
200  bobsOffer.out.issue(),
201  bobsOffer.out.mantissa() - mantissaReduce,
202  bobsOffer.out.exponent()};
203  STAmount aliceXRP{
204  bobsOffer.in.issue(), bobsOffer.in.mantissa() - 1};
205  Amounts alicesOffer{aliceUSD, aliceXRP};
206  blockedCount += exerciseOfferPair(alicesOffer, bobsOffer);
207  }
208 
209  // If fixReducedOffersV1 is enabled, then none of the test cases
210  // should produce a potentially blocking rate.
211  //
212  // Also verify that if fixReducedOffersV1 is not enabled then
213  // some of the test cases produced a potentially blocking rate.
214  if (features[fixReducedOffersV1])
215  {
216  BEAST_EXPECT(blockedCount == 0);
217  }
218  else
219  {
220  BEAST_EXPECT(blockedCount >= 170);
221  }
222  }
223  }
224 
225  void
227  {
228  testcase("exercise partial cross old XRP/IOU offer Q change");
229 
230  using namespace jtx;
231 
232  auto const gw = Account{"gateway"};
233  auto const alice = Account{"alice"};
234  auto const bob = Account{"bob"};
235  auto const USD = gw["USD"];
236 
237  // Make one test run without fixReducedOffersV1 and one with.
238  for (FeatureBitset features :
241  {
242  // Make sure none of the offers we generate are under funded.
243  Env env{*this, features};
244  env.fund(XRP(10'000'000), gw, alice, bob);
245  env.close();
246 
247  env(trust(alice, USD(10'000'000)));
248  env(trust(bob, USD(10'000'000)));
249  env.close();
250 
251  env(pay(gw, alice, USD(10'000'000)));
252  env.close();
253 
254  // Lambda that:
255  // 1. Exercises one offer pair,
256  // 2. Collects the results, and
257  // 3. Cleans up for the next offer pair.
258  auto exerciseOfferPair =
259  [this, &env, &alice, &bob](
260  Amounts const& inLedger,
261  Amounts const& newOffer) -> unsigned int {
262  // Get the inLedger offer into the ledger so newOffer can cross
263  // it.
264  STAmount const initialRate = Quality(inLedger).rate();
265  std::uint32_t const aliceOfferSeq = env.seq(alice);
266  env(offer(alice, inLedger.in, inLedger.out));
267  env.close();
268 
269  // Now bob's offer will partially cross alice's offer.
270  std::uint32_t const bobOfferSeq = env.seq(bob);
271  STAmount const aliceInitialBalance = env.balance(alice);
272  env(offer(bob, newOffer.in, newOffer.out));
273  env.close();
274  STAmount const aliceFinalBalance = env.balance(alice);
275 
276  // bob's offer should not have made it into the ledger.
277  if (!BEAST_EXPECT(!offerInLedger(env, bob, bobOfferSeq)))
278  {
279  // If the in-ledger offer was not consumed then further
280  // results are meaningless.
282  env, alice, bob, aliceOfferSeq, bobOfferSeq);
283  return 1;
284  }
285  // alice's offer should still be in the ledger, but reduced in
286  // size.
287  unsigned int badRate = 1;
288  {
289  Json::Value aliceOffer =
290  ledgerEntryOffer(env, alice, aliceOfferSeq);
291 
292  STAmount const reducedTakerGets = amountFromJson(
293  sfTakerGets,
294  aliceOffer[jss::node][sfTakerGets.jsonName]);
295  STAmount const reducedTakerPays = amountFromJson(
296  sfTakerPays,
297  aliceOffer[jss::node][sfTakerPays.jsonName]);
298  STAmount const aliceGot =
299  env.balance(alice) - aliceInitialBalance;
300  BEAST_EXPECT(reducedTakerPays < inLedger.in);
301  BEAST_EXPECT(reducedTakerGets < inLedger.out);
302  STAmount const inLedgerRate =
303  Quality(Amounts{reducedTakerPays, reducedTakerGets})
304  .rate();
305  badRate = inLedgerRate > initialRate ? 1 : 0;
306 
307  // If the inLedgerRate is less than initial rate, then
308  // incrementing the mantissa of the reduced taker pays
309  // should result in a rate higher than initial. Check
310  // this to verify that the largest allowable TakerPays
311  // was computed.
312  if (badRate == 0)
313  {
314  STAmount const tweakedTakerPays =
315  reducedTakerPays + drops(1);
316  STAmount const tweakedRate =
317  Quality(Amounts{tweakedTakerPays, reducedTakerGets})
318  .rate();
319  BEAST_EXPECT(tweakedRate > initialRate);
320  }
321 #if 0
322  std::cout << "Placed rate: " << initialRate
323  << "; in-ledger rate: " << inLedgerRate
324  << "; TakerPays: " << reducedTakerPays
325  << "; TakerGets: " << reducedTakerGets
326  << "; alice already got: " << aliceGot
327  << std::endl;
328 // #else
329  std::string_view filler = badRate ? "**" : " ";
330  std::cout << "| `" << reducedTakerGets << "` | `"
331  << reducedTakerPays << "` | `" << initialRate
332  << "` | " << filler << "`" << inLedgerRate << "`"
333  << filler << " | `" << aliceGot << "` |"
334  << std::endl;
335 #endif
336  }
337 
338  // In preparation for the next iteration make sure the two
339  // offers are gone from the ledger.
340  cleanupOldOffers(env, alice, bob, aliceOfferSeq, bobOfferSeq);
341  return badRate;
342  };
343 
344  // alice's offer (the old offer) is the same every time:
345  Amounts const aliceOffer{
346  STAmount(XRP(1)), STAmount(USD.issue(), 1, 0)};
347 
348  // bob's offer has a slightly smaller TakerPays with each iteration.
349  // This should mean that the size of the offer alice leaves in the
350  // ledger should increase with each iteration.
351  unsigned int blockedCount = 0;
352  for (std::uint64_t mantissaReduce = 1'000'000'000ull;
353  mantissaReduce <= 4'000'000'000ull;
354  mantissaReduce += 20'000'000ull)
355  {
356  STAmount bobUSD{
357  aliceOffer.out.issue(),
358  aliceOffer.out.mantissa() - mantissaReduce,
359  aliceOffer.out.exponent()};
360  STAmount bobXRP{
361  aliceOffer.in.issue(), aliceOffer.in.mantissa() - 1};
362  Amounts bobsOffer{bobUSD, bobXRP};
363 
364  blockedCount += exerciseOfferPair(aliceOffer, bobsOffer);
365  }
366 
367  // If fixReducedOffersV1 is enabled, then none of the test cases
368  // should produce a potentially blocking rate.
369  //
370  // Also verify that if fixReducedOffersV1 is not enabled then
371  // some of the test cases produced a potentially blocking rate.
372  if (features[fixReducedOffersV1])
373  {
374  BEAST_EXPECT(blockedCount == 0);
375  }
376  else
377  {
378  BEAST_EXPECT(blockedCount > 10);
379  }
380  }
381  }
382 
383  void
385  {
386  testcase("exercise underfunded XRP/IOU offer Q change");
387 
388  // Bob places an offer that is not fully funded.
389  //
390  // This unit test compares the behavior of this situation before and
391  // after applying the fixReducedOffersV1 amendment.
392 
393  using namespace jtx;
394  auto const alice = Account{"alice"};
395  auto const bob = Account{"bob"};
396  auto const gw = Account{"gw"};
397  auto const USD = gw["USD"];
398 
399  // Make one test run without fixReducedOffersV1 and one with.
400  for (FeatureBitset features :
403  {
404  Env env{*this, features};
405 
406  env.fund(XRP(10000), alice, bob, gw);
407  env.close();
408  env.trust(USD(1000), alice, bob);
409 
410  int blockedOrderBookCount = 0;
411  for (STAmount initialBobUSD = USD(0.45); initialBobUSD <= USD(1);
412  initialBobUSD += USD(0.025))
413  {
414  // underfund bob's offer
415  env(pay(gw, bob, initialBobUSD));
416  env.close();
417 
418  std::uint32_t const bobOfferSeq = env.seq(bob);
419  env(offer(bob, drops(2), USD(1)));
420  env.close();
421 
422  // alice places an offer that would cross bob's if bob's were
423  // well funded.
424  std::uint32_t const aliceOfferSeq = env.seq(alice);
425  env(offer(alice, USD(1), drops(2)));
426  env.close();
427 
428  // We want to detect order book blocking. If:
429  // 1. bob's offer is still in the ledger and
430  // 2. alice received no USD
431  // then we use that as evidence that bob's offer blocked the
432  // order book.
433  {
434  bool const bobsOfferGone =
435  !offerInLedger(env, bob, bobOfferSeq);
436  STAmount const aliceBalanceUSD = env.balance(alice, USD);
437 
438  // Sanity check the ledger if alice got USD.
439  if (aliceBalanceUSD.signum() > 0)
440  {
441  BEAST_EXPECT(aliceBalanceUSD == initialBobUSD);
442  BEAST_EXPECT(env.balance(bob, USD) == USD(0));
443  BEAST_EXPECT(bobsOfferGone);
444  }
445 
446  // Track occurrences of order book blocking.
447  if (!bobsOfferGone && aliceBalanceUSD.signum() == 0)
448  {
449  ++blockedOrderBookCount;
450  }
451 
452  // In preparation for the next iteration clean up any
453  // leftover offers.
455  env, alice, bob, aliceOfferSeq, bobOfferSeq);
456 
457  // Zero out alice's and bob's USD balances.
458  if (STAmount const aliceBalance = env.balance(alice, USD);
459  aliceBalance.signum() > 0)
460  env(pay(alice, gw, aliceBalance));
461 
462  if (STAmount const bobBalance = env.balance(bob, USD);
463  bobBalance.signum() > 0)
464  env(pay(bob, gw, bobBalance));
465 
466  env.close();
467  }
468  }
469 
470  // If fixReducedOffersV1 is enabled, then none of the test cases
471  // should produce a potentially blocking rate.
472  //
473  // Also verify that if fixReducedOffersV1 is not enabled then
474  // some of the test cases produced a potentially blocking rate.
475  if (features[fixReducedOffersV1])
476  {
477  BEAST_EXPECT(blockedOrderBookCount == 0);
478  }
479  else
480  {
481  BEAST_EXPECT(blockedOrderBookCount > 15);
482  }
483  }
484  }
485 
486  void
488  {
489  testcase("exercise underfunded IOU/IOU offer Q change");
490 
491  // Bob places an IOU/IOU offer that is not fully funded.
492  //
493  // This unit test compares the behavior of this situation before and
494  // after applying the fixReducedOffersV1 amendment.
495 
496  using namespace jtx;
497  using namespace std::chrono_literals;
498  auto const alice = Account{"alice"};
499  auto const bob = Account{"bob"};
500  auto const gw = Account{"gw"};
501 
502  auto const USD = gw["USD"];
503  auto const EUR = gw["EUR"];
504 
505  STAmount const tinyUSD(USD.issue(), /*mantissa*/ 1, /*exponent*/ -81);
506 
507  // Make one test run without fixReducedOffersV1 and one with.
508  for (FeatureBitset features :
511  {
512  Env env{*this, features};
513 
514  env.fund(XRP(10000), alice, bob, gw);
515  env.close();
516  env.trust(USD(1000), alice, bob);
517  env.trust(EUR(1000), alice, bob);
518 
519  STAmount const eurOffer(
520  EUR.issue(), /*mantissa*/ 2957, /*exponent*/ -76);
521  STAmount const usdOffer(
522  USD.issue(), /*mantissa*/ 7109, /*exponent*/ -76);
523 
524  STAmount const endLoop(
525  USD.issue(), /*mantissa*/ 50, /*exponent*/ -81);
526 
527  int blockedOrderBookCount = 0;
528  for (STAmount initialBobUSD = tinyUSD; initialBobUSD <= endLoop;
529  initialBobUSD += tinyUSD)
530  {
531  // underfund bob's offer
532  env(pay(gw, bob, initialBobUSD));
533  env(pay(gw, alice, EUR(100)));
534  env.close();
535 
536  // This offer is underfunded
537  std::uint32_t bobOfferSeq = env.seq(bob);
538  env(offer(bob, eurOffer, usdOffer));
539  env.close();
540  env.require(offers(bob, 1));
541 
542  // alice places an offer that crosses bob's.
543  std::uint32_t aliceOfferSeq = env.seq(alice);
544  env(offer(alice, usdOffer, eurOffer));
545  env.close();
546 
547  // Examine the aftermath of alice's offer.
548  {
549  bool const bobsOfferGone =
550  !offerInLedger(env, bob, bobOfferSeq);
551  STAmount aliceBalanceUSD = env.balance(alice, USD);
552 #if 0
553  std::cout
554  << "bobs initial: " << initialBobUSD
555  << "; alice final: " << aliceBalanceUSD
556  << "; bobs offer: " << bobsOfferJson.toStyledString()
557  << std::endl;
558 #endif
559  // Sanity check the ledger if alice got USD.
560  if (aliceBalanceUSD.signum() > 0)
561  {
562  BEAST_EXPECT(aliceBalanceUSD == initialBobUSD);
563  BEAST_EXPECT(env.balance(bob, USD) == USD(0));
564  BEAST_EXPECT(bobsOfferGone);
565  }
566 
567  // Track occurrences of order book blocking.
568  if (!bobsOfferGone && aliceBalanceUSD.signum() == 0)
569  {
570  ++blockedOrderBookCount;
571  }
572  }
573 
574  // In preparation for the next iteration clean up any
575  // leftover offers.
576  cleanupOldOffers(env, alice, bob, aliceOfferSeq, bobOfferSeq);
577 
578  // Zero out alice's and bob's IOU balances.
579  auto zeroBalance = [&env, &gw](
580  Account const& acct, IOU const& iou) {
581  if (STAmount const balance = env.balance(acct, iou);
582  balance.signum() > 0)
583  env(pay(acct, gw, balance));
584  };
585 
586  zeroBalance(alice, EUR);
587  zeroBalance(alice, USD);
588  zeroBalance(bob, EUR);
589  zeroBalance(bob, USD);
590  env.close();
591  }
592 
593  // If fixReducedOffersV1 is enabled, then none of the test cases
594  // should produce a potentially blocking rate.
595  //
596  // Also verify that if fixReducedOffersV1 is not enabled then
597  // some of the test cases produced a potentially blocking rate.
598  if (features[fixReducedOffersV1])
599  {
600  BEAST_EXPECT(blockedOrderBookCount == 0);
601  }
602  else
603  {
604  BEAST_EXPECT(blockedOrderBookCount > 20);
605  }
606  }
607  }
608 
609  void
610  run() override
611  {
616  }
617 };
618 
619 BEAST_DEFINE_TESTSUITE_PRIO(ReducedOffer, tx, ripple, 2);
620 
621 } // namespace test
622 } // namespace ripple
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
ripple::test::jtx::Env::rpc
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:711
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:350
std::string_view
STL class.
ripple::test::ReducedOffer_test::offerInLedger
static bool offerInLedger(jtx::Env &env, jtx::Account const &acct, std::uint32_t offerSeq)
Definition: ReducedOffer_test.cpp:44
ripple::test::ReducedOffer_test::ledgerEntryOffer
static auto ledgerEntryOffer(jtx::Env &env, jtx::Account const &acct, std::uint32_t offer_seq)
Definition: ReducedOffer_test.cpp:31
ripple::test::jtx::balance
A balance matches.
Definition: balance.h:38
ripple::fixReducedOffersV1
const uint256 fixReducedOffersV1
ripple::test::jtx::offer_cancel
Json::Value offer_cancel(Account const &account, std::uint32_t offerSeq)
Cancel an offer.
Definition: offer.cpp:45
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:113
ripple::STAmount::signum
int signum() const noexcept
Definition: STAmount.h:368
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:165
ripple::test::BEAST_DEFINE_TESTSUITE_PRIO
BEAST_DEFINE_TESTSUITE_PRIO(AccountDelete, app, ripple, 2)
ripple::test::ReducedOffer_test::testUnderFundedIouIouQChange
void testUnderFundedIouIouQChange()
Definition: ReducedOffer_test.cpp:487
std::cout
ripple::sfTakerPays
const SF_AMOUNT sfTakerPays
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
ripple::STAmount
Definition: STAmount.h:46
ripple::sfTakerGets
const SF_AMOUNT sfTakerGets
ripple::test::ReducedOffer_test::testUnderFundedXrpIouQChange
void testUnderFundedXrpIouQChange()
Definition: ReducedOffer_test.cpp:384
ripple::amountFromJson
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition: STAmount.cpp:927
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
std::uint32_t
ripple::test::jtx::fee
Set the fee on a JTx.
Definition: fee.h:35
ripple::test::ReducedOffer_test
Definition: ReducedOffer_test.cpp:28
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::tfSell
constexpr std::uint32_t tfSell
Definition: TxFlags.h:97
std::endl
T endl(T... args)
ripple::test::jtx::IOU
Converts to IOU Issue or STAmount.
Definition: amount.h:291
ripple::FeatureBitset
Definition: Feature.h:113
ripple::test::ReducedOffer_test::testPartialCrossNewXrpIouQChange
void testPartialCrossNewXrpIouQChange()
Definition: ReducedOffer_test.cpp:71
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::test::ReducedOffer_test::run
void run() override
Definition: ReducedOffer_test.cpp:610
ripple::test::ReducedOffer_test::cleanupOldOffers
static void cleanupOldOffers(jtx::Env &env, jtx::Account const &acct1, jtx::Account const &acct2, std::uint32_t acct1OfferSeq, std::uint32_t acct2OfferSeq)
Definition: ReducedOffer_test.cpp:57
ripple::test::jtx::balance::balance
balance(Account const &account, none_t)
Definition: balance.h:46
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::jtx::owner_count
Definition: owners.h:49
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
ripple::test::jtx::rate
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Definition: rate.cpp:30
ripple::test::ReducedOffer_test::testPartialCrossOldXrpIouQChange
void testPartialCrossOldXrpIouQChange()
Definition: ReducedOffer_test.cpp:226