rippled
Freeze_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2016 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 #include <ripple/protocol/AccountID.h>
20 #include <ripple/protocol/Feature.h>
21 #include <ripple/protocol/SField.h>
22 #include <ripple/protocol/TxFlags.h>
23 #include <ripple/protocol/jss.h>
24 #include <test/jtx.h>
25 
26 namespace ripple {
27 
28 class Freeze_test : public beast::unit_test::suite
29 {
30  static Json::Value
32  {
33  Json::Value jq;
34  jq[jss::account] = account.human();
35  return env.rpc("json", "account_lines", to_string(jq))[jss::result];
36  }
37 
38  static Json::Value
40  test::jtx::Env& env,
41  test::jtx::Account const& account,
42  bool current = false)
43  {
44  Json::Value jq;
45  jq[jss::account] = account.human();
46  jq[jss::ledger_index] = current ? "current" : "validated";
47  return env.rpc("json", "account_offers", to_string(jq))[jss::result];
48  }
49 
50  static bool
51  checkArraySize(Json::Value const& val, unsigned int size)
52  {
53  return val.isArray() && val.size() == size;
54  }
55 
56  void
58  {
59  testcase("RippleState Freeze");
60 
61  using namespace test::jtx;
62  Env env(*this, features);
63 
64  Account G1{"G1"};
65  Account alice{"alice"};
66  Account bob{"bob"};
67 
68  env.fund(XRP(1000), G1, alice, bob);
69  env.close();
70 
71  env.trust(G1["USD"](100), bob);
72  env.trust(G1["USD"](100), alice);
73  env.close();
74 
75  env(pay(G1, bob, G1["USD"](10)));
76  env(pay(G1, alice, G1["USD"](100)));
77  env.close();
78 
79  env(offer(alice, XRP(500), G1["USD"](100)));
80  env.close();
81 
82  {
83  auto lines = getAccountLines(env, bob);
84  if (!BEAST_EXPECT(checkArraySize(lines[jss::lines], 1u)))
85  return;
86  BEAST_EXPECT(lines[jss::lines][0u][jss::account] == G1.human());
87  BEAST_EXPECT(lines[jss::lines][0u][jss::limit] == "100");
88  BEAST_EXPECT(lines[jss::lines][0u][jss::balance] == "10");
89  }
90 
91  {
92  auto lines = getAccountLines(env, alice);
93  if (!BEAST_EXPECT(checkArraySize(lines[jss::lines], 1u)))
94  return;
95  BEAST_EXPECT(lines[jss::lines][0u][jss::account] == G1.human());
96  BEAST_EXPECT(lines[jss::lines][0u][jss::limit] == "100");
97  BEAST_EXPECT(lines[jss::lines][0u][jss::balance] == "100");
98  }
99 
100  {
101  // Account with line unfrozen (proving operations normally work)
102  // test: can make Payment on that line
103  env(pay(alice, bob, G1["USD"](1)));
104 
105  // test: can receive Payment on that line
106  env(pay(bob, alice, G1["USD"](1)));
107  env.close();
108  }
109 
110  {
111  // Is created via a TrustSet with SetFreeze flag
112  // test: sets LowFreeze | HighFreeze flags
113  env(trust(G1, bob["USD"](0), tfSetFreeze));
114  auto affected = env.meta()->getJson(
116  if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
117  return;
118  auto ff =
120  BEAST_EXPECT(
121  ff[sfLowLimit.fieldName] ==
122  G1["USD"](0).value().getJson(JsonOptions::none));
123  BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfLowFreeze);
124  BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze));
125  env.close();
126  }
127 
128  {
129  // Account with line frozen by issuer
130  // test: can buy more assets on that line
131  env(offer(bob, G1["USD"](5), XRP(25)));
132  auto affected = env.meta()->getJson(
134  if (!BEAST_EXPECT(checkArraySize(affected, 5u)))
135  return;
136  auto ff =
138  BEAST_EXPECT(
139  ff[sfHighLimit.fieldName] ==
140  bob["USD"](100).value().getJson(JsonOptions::none));
141  auto amt = STAmount{Issue{to_currency("USD"), noAccount()}, -15}
142  .value()
143  .getJson(JsonOptions::none);
144  BEAST_EXPECT(ff[sfBalance.fieldName] == amt);
145  env.close();
146  }
147 
148  {
149  // test: can not sell assets from that line
150  env(offer(bob, XRP(1), G1["USD"](5)), ter(tecUNFUNDED_OFFER));
151 
152  // test: can receive Payment on that line
153  env(pay(alice, bob, G1["USD"](1)));
154 
155  // test: can not make Payment from that line
156  env(pay(bob, alice, G1["USD"](1)), ter(tecPATH_DRY));
157  }
158 
159  {
160  // check G1 account lines
161  // test: shows freeze
162  auto lines = getAccountLines(env, G1);
163  Json::Value bobLine;
164  for (auto const& it : lines[jss::lines])
165  {
166  if (it[jss::account] == bob.human())
167  {
168  bobLine = it;
169  break;
170  }
171  }
172  if (!BEAST_EXPECT(bobLine))
173  return;
174  BEAST_EXPECT(bobLine[jss::freeze] == true);
175  BEAST_EXPECT(bobLine[jss::balance] == "-16");
176  }
177 
178  {
179  // test: shows freeze peer
180  auto lines = getAccountLines(env, bob);
181  Json::Value g1Line;
182  for (auto const& it : lines[jss::lines])
183  {
184  if (it[jss::account] == G1.human())
185  {
186  g1Line = it;
187  break;
188  }
189  }
190  if (!BEAST_EXPECT(g1Line))
191  return;
192  BEAST_EXPECT(g1Line[jss::freeze_peer] == true);
193  BEAST_EXPECT(g1Line[jss::balance] == "16");
194  }
195 
196  {
197  // Is cleared via a TrustSet with ClearFreeze flag
198  // test: sets LowFreeze | HighFreeze flags
199  env(trust(G1, bob["USD"](0), tfClearFreeze));
200  auto affected = env.meta()->getJson(
202  if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
203  return;
204  auto ff =
206  BEAST_EXPECT(
207  ff[sfLowLimit.fieldName] ==
208  G1["USD"](0).value().getJson(JsonOptions::none));
209  BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowFreeze));
210  BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze));
211  env.close();
212  }
213  }
214 
215  void
217  {
218  testcase("Global Freeze");
219 
220  using namespace test::jtx;
221  Env env(*this, features);
222 
223  Account G1{"G1"};
224  Account A1{"A1"};
225  Account A2{"A2"};
226  Account A3{"A3"};
227  Account A4{"A4"};
228 
229  env.fund(XRP(12000), G1);
230  env.fund(XRP(1000), A1);
231  env.fund(XRP(20000), A2, A3, A4);
232  env.close();
233 
234  env.trust(G1["USD"](1200), A1);
235  env.trust(G1["USD"](200), A2);
236  env.trust(G1["BTC"](100), A3);
237  env.trust(G1["BTC"](100), A4);
238  env.close();
239 
240  env(pay(G1, A1, G1["USD"](1000)));
241  env(pay(G1, A2, G1["USD"](100)));
242  env(pay(G1, A3, G1["BTC"](100)));
243  env(pay(G1, A4, G1["BTC"](100)));
244  env.close();
245 
246  env(offer(G1, XRP(10000), G1["USD"](100)), txflags(tfPassive));
247  env(offer(G1, G1["USD"](100), XRP(10000)), txflags(tfPassive));
248  env(offer(A1, XRP(10000), G1["USD"](100)), txflags(tfPassive));
249  env(offer(A2, G1["USD"](100), XRP(10000)), txflags(tfPassive));
250  env.close();
251 
252  {
253  // Is toggled via AccountSet using SetFlag and ClearFlag
254  // test: SetFlag GlobalFreeze
255  env.require(nflags(G1, asfGlobalFreeze));
256  env(fset(G1, asfGlobalFreeze));
257  env.require(flags(G1, asfGlobalFreeze));
258  env.require(nflags(G1, asfNoFreeze));
259 
260  // test: ClearFlag GlobalFreeze
261  env(fclear(G1, asfGlobalFreeze));
262  env.require(nflags(G1, asfGlobalFreeze));
263  env.require(nflags(G1, asfNoFreeze));
264  }
265 
266  {
267  // Account without GlobalFreeze (proving operations normally work)
268  // test: visible offers where taker_pays is unfrozen issuer
269  auto offers = env.rpc(
270  "book_offers",
271  std::string("USD/") + G1.human(),
272  "XRP")[jss::result][jss::offers];
273  if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
274  return;
275  std::set<std::string> accounts;
276  for (auto const& offer : offers)
277  {
278  accounts.insert(offer[jss::Account].asString());
279  }
280  BEAST_EXPECT(accounts.find(A2.human()) != std::end(accounts));
281  BEAST_EXPECT(accounts.find(G1.human()) != std::end(accounts));
282 
283  // test: visible offers where taker_gets is unfrozen issuer
284  offers = env.rpc(
285  "book_offers",
286  "XRP",
287  std::string("USD/") + G1.human())[jss::result][jss::offers];
288  if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
289  return;
290  accounts.clear();
291  for (auto const& offer : offers)
292  {
293  accounts.insert(offer[jss::Account].asString());
294  }
295  BEAST_EXPECT(accounts.find(A1.human()) != std::end(accounts));
296  BEAST_EXPECT(accounts.find(G1.human()) != std::end(accounts));
297  }
298 
299  {
300  // Offers/Payments
301  // test: assets can be bought on the market
302  env(offer(A3, G1["BTC"](1), XRP(1)));
303 
304  // test: assets can be sold on the market
305  env(offer(A4, XRP(1), G1["BTC"](1)));
306 
307  // test: direct issues can be sent
308  env(pay(G1, A2, G1["USD"](1)));
309 
310  // test: direct redemptions can be sent
311  env(pay(A2, G1, G1["USD"](1)));
312 
313  // test: via rippling can be sent
314  env(pay(A2, A1, G1["USD"](1)));
315 
316  // test: via rippling can be sent back
317  env(pay(A1, A2, G1["USD"](1)));
318  }
319 
320  {
321  // Account with GlobalFreeze
322  // set GlobalFreeze first
323  // test: SetFlag GlobalFreeze will toggle back to freeze
324  env.require(nflags(G1, asfGlobalFreeze));
325  env(fset(G1, asfGlobalFreeze));
326  env.require(flags(G1, asfGlobalFreeze));
327  env.require(nflags(G1, asfNoFreeze));
328 
329  // test: assets can't be bought on the market
330  env(offer(A3, G1["BTC"](1), XRP(1)), ter(tecFROZEN));
331 
332  // test: assets can't be sold on the market
333  env(offer(A4, XRP(1), G1["BTC"](1)), ter(tecFROZEN));
334  }
335 
336  {
337  // offers are filtered (seems to be broken?)
338  // test: account_offers always shows own offers
339  auto offers = getAccountOffers(env, G1)[jss::offers];
340  if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
341  return;
342 
343  // test: book_offers shows offers
344  // (should these actually be filtered?)
345  offers = env.rpc(
346  "book_offers",
347  "XRP",
348  std::string("USD/") + G1.human())[jss::result][jss::offers];
349  if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
350  return;
351 
352  offers = env.rpc(
353  "book_offers",
354  std::string("USD/") + G1.human(),
355  "XRP")[jss::result][jss::offers];
356  if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
357  return;
358  }
359 
360  {
361  // Payments
362  // test: direct issues can be sent
363  env(pay(G1, A2, G1["USD"](1)));
364 
365  // test: direct redemptions can be sent
366  env(pay(A2, G1, G1["USD"](1)));
367 
368  // test: via rippling cant be sent
369  env(pay(A2, A1, G1["USD"](1)), ter(tecPATH_DRY));
370  }
371  }
372 
373  void
375  {
376  testcase("No Freeze");
377 
378  using namespace test::jtx;
379  Env env(*this, features);
380 
381  Account G1{"G1"};
382  Account A1{"A1"};
383 
384  env.fund(XRP(12000), G1);
385  env.fund(XRP(1000), A1);
386  env.close();
387 
388  env.trust(G1["USD"](1000), A1);
389  env.close();
390 
391  env(pay(G1, A1, G1["USD"](1000)));
392  env.close();
393 
394  // TrustSet NoFreeze
395  // test: should set NoFreeze in Flags
396  env.require(nflags(G1, asfNoFreeze));
397  env(fset(G1, asfNoFreeze));
398  env.require(flags(G1, asfNoFreeze));
399  env.require(nflags(G1, asfGlobalFreeze));
400 
401  // test: cannot be cleared
402  env(fclear(G1, asfNoFreeze));
403  env.require(flags(G1, asfNoFreeze));
404  env.require(nflags(G1, asfGlobalFreeze));
405 
406  // test: can set GlobalFreeze
407  env(fset(G1, asfGlobalFreeze));
408  env.require(flags(G1, asfNoFreeze));
409  env.require(flags(G1, asfGlobalFreeze));
410 
411  // test: cannot unset GlobalFreeze
412  env(fclear(G1, asfGlobalFreeze));
413  env.require(flags(G1, asfNoFreeze));
414  env.require(flags(G1, asfGlobalFreeze));
415 
416  // test: trustlines can't be frozen
417  env(trust(G1, A1["USD"](0), tfSetFreeze));
418  auto affected =
419  env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName];
420  if (!BEAST_EXPECT(checkArraySize(affected, 1u)))
421  return;
422 
423  auto let =
425  BEAST_EXPECT(let == jss::AccountRoot);
426  }
427 
428  void
430  {
431  testcase("Offers for Frozen Trust Lines");
432 
433  using namespace test::jtx;
434  Env env(*this, features);
435 
436  Account G1{"G1"};
437  Account A2{"A2"};
438  Account A3{"A3"};
439  Account A4{"A4"};
440 
441  env.fund(XRP(1000), G1, A3, A4);
442  env.fund(XRP(2000), A2);
443  env.close();
444 
445  env.trust(G1["USD"](1000), A2);
446  env.trust(G1["USD"](2000), A3);
447  env.trust(G1["USD"](2000), A4);
448  env.close();
449 
450  env(pay(G1, A3, G1["USD"](2000)));
451  env(pay(G1, A4, G1["USD"](2000)));
452  env.close();
453 
454  env(offer(A3, XRP(1000), G1["USD"](1000)), txflags(tfPassive));
455  env.close();
456 
457  // removal after successful payment
458  // test: make a payment with partially consuming offer
459  env(pay(A2, G1, G1["USD"](1)), paths(G1["USD"]), sendmax(XRP(1)));
460  env.close();
461 
462  // test: offer was only partially consumed
463  auto offers = getAccountOffers(env, A3)[jss::offers];
464  if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
465  return;
466  BEAST_EXPECT(
467  offers[0u][jss::taker_gets] ==
468  G1["USD"](999).value().getJson(JsonOptions::none));
469 
470  // test: someone else creates an offer providing liquidity
471  env(offer(A4, XRP(999), G1["USD"](999)));
472  env.close();
473 
474  // test: owner of partially consumed offers line is frozen
475  env(trust(G1, A3["USD"](0), tfSetFreeze));
476  auto affected =
477  env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName];
478  if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
479  return;
480  auto ff =
482  BEAST_EXPECT(
483  ff[sfHighLimit.fieldName] ==
484  G1["USD"](0).value().getJson(JsonOptions::none));
485  BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowFreeze));
486  BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfHighFreeze);
487  env.close();
488 
489  // verify offer on the books
490  offers = getAccountOffers(env, A3)[jss::offers];
491  if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
492  return;
493 
494  // test: Can make a payment via the new offer
495  env(pay(A2, G1, G1["USD"](1)), paths(G1["USD"]), sendmax(XRP(1)));
496  env.close();
497 
498  // test: Partially consumed offer was removed by tes* payment
499  offers = getAccountOffers(env, A3)[jss::offers];
500  if (!BEAST_EXPECT(checkArraySize(offers, 0u)))
501  return;
502 
503  // removal buy successful OfferCreate
504  // test: freeze the new offer
505  env(trust(G1, A4["USD"](0), tfSetFreeze));
506  affected =
507  env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName];
508  if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
509  return;
510  ff = affected[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
511  BEAST_EXPECT(
512  ff[sfLowLimit.fieldName] ==
513  G1["USD"](0).value().getJson(JsonOptions::none));
514  BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfLowFreeze);
515  BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze));
516  env.close();
517 
518  // test: can no longer create a crossing offer
519  env(offer(A2, G1["USD"](999), XRP(999)));
520  affected =
521  env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName];
522  if (!BEAST_EXPECT(checkArraySize(affected, 8u)))
523  return;
524  auto created = affected[0u][sfCreatedNode.fieldName];
525  BEAST_EXPECT(
526  created[sfNewFields.fieldName][jss::Account] == A2.human());
527  env.close();
528 
529  // test: offer was removed by offer_create
530  offers = getAccountOffers(env, A4)[jss::offers];
531  if (!BEAST_EXPECT(checkArraySize(offers, 0u)))
532  return;
533  }
534 
535 public:
536  void
537  run() override
538  {
539  auto testAll = [this](FeatureBitset features) {
540  testRippleState(features);
541  testGlobalFreeze(features);
542  testNoFreeze(features);
543  testOffersWhenFrozen(features);
544  };
545  using namespace test::jtx;
546  auto const sa = supported_amendments();
547  testAll(sa - featureFlowCross);
548  testAll(sa);
549  }
550 };
551 
552 BEAST_DEFINE_TESTSUITE(Freeze, app, ripple);
553 } // namespace ripple
ripple::tecUNFUNDED_OFFER
@ tecUNFUNDED_OFFER
Definition: TER.h:251
ripple::to_currency
bool to_currency(Currency &currency, std::string const &code)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:80
ripple::tecFROZEN
@ tecFROZEN
Definition: TER.h:270
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
std::string
STL class.
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::Freeze_test::testOffersWhenFrozen
void testOffersWhenFrozen(FeatureBitset features)
Definition: Freeze_test.cpp:429
ripple::asfNoFreeze
constexpr std::uint32_t asfNoFreeze
Definition: TxFlags.h:79
std::set::find
T find(T... args)
ripple::SField::fieldName
const std::string fieldName
Definition: SField.h:132
ripple::Freeze_test::checkArraySize
static bool checkArraySize(Json::Value const &val, unsigned int size)
Definition: Freeze_test.cpp:51
ripple::sfFinalFields
const SField sfFinalFields
ripple::tfPassive
constexpr std::uint32_t tfPassive
Definition: TxFlags.h:93
std::set::clear
T clear(T... args)
ripple::sfLowLimit
const SF_AMOUNT sfLowLimit
ripple::Freeze_test::getAccountOffers
static Json::Value getAccountOffers(test::jtx::Env &env, test::jtx::Account const &account, bool current=false)
Definition: Freeze_test.cpp:39
ripple::Freeze_test::testGlobalFreeze
void testGlobalFreeze(FeatureBitset features)
Definition: Freeze_test.cpp:216
ripple::sfNewFields
const SField sfNewFields
ripple::JsonOptions::none
@ none
ripple::Freeze_test::getAccountLines
static Json::Value getAccountLines(test::jtx::Env &env, test::jtx::Account const &account)
Definition: Freeze_test.cpp:31
ripple::sfAffectedNodes
const SField sfAffectedNodes
ripple::sfModifiedNode
const SField sfModifiedNode
ripple::STAmount
Definition: STAmount.h:45
ripple::Freeze_test::testNoFreeze
void testNoFreeze(FeatureBitset features)
Definition: Freeze_test.cpp:374
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
ripple::Freeze_test::testRippleState
void testRippleState(FeatureBitset features)
Definition: Freeze_test.cpp:57
ripple::ValStatus::current
@ current
This was a new validation and was added.
ripple::sfHighLimit
const SF_AMOUNT sfHighLimit
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
ripple::lsfHighFreeze
@ lsfHighFreeze
Definition: LedgerFormats.h:259
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:296
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::sfLedgerEntryType
const SF_UINT16 sfLedgerEntryType
ripple::tfSetFreeze
constexpr std::uint32_t tfSetFreeze
Definition: TxFlags.h:111
std::set::insert
T insert(T... args)
ripple::sfCreatedNode
const SField sfCreatedNode
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::FeatureBitset
Definition: Feature.h:113
ripple::tecPATH_DRY
@ tecPATH_DRY
Definition: TER.h:261
ripple::asfGlobalFreeze
constexpr std::uint32_t asfGlobalFreeze
Definition: TxFlags.h:80
ripple::tfClearFreeze
constexpr std::uint32_t tfClearFreeze
Definition: TxFlags.h:112
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::Freeze_test::run
void run() override
Definition: Freeze_test.cpp:537
std::end
T end(T... args)
ripple::lsfLowFreeze
@ lsfLowFreeze
Definition: LedgerFormats.h:258
ripple::featureFlowCross
const uint256 featureFlowCross
std::set< std::string >
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:175
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
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:687
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::Freeze_test
Definition: Freeze_test.cpp:28