rippled
AccountTx_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2017 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/beast/unit_test.h>
21 #include <ripple/protocol/ErrorCodes.h>
22 #include <ripple/protocol/jss.h>
23 #include <ripple/rpc/impl/RPCHelpers.h>
24 #include <test/jtx.h>
25 
26 #include <boost/container/flat_set.hpp>
27 
28 namespace ripple {
29 
30 namespace test {
31 
32 class AccountTx_test : public beast::unit_test::suite
33 {
34  // A data structure used to describe the basic structure of a
35  // transactions array node as returned by the account_tx RPC command.
36  struct NodeSanity
37  {
38  int const index;
40  boost::container::flat_set<std::string> created;
41  boost::container::flat_set<std::string> deleted;
42  boost::container::flat_set<std::string> modified;
43 
45  int idx,
46  Json::StaticString const& t,
50  : index(idx), txType(t)
51  {
52  auto buildSet = [](auto&& init) {
53  boost::container::flat_set<std::string> r;
54  r.reserve(init.size());
55  for (auto&& s : init)
56  r.insert(s);
57  return r;
58  };
59 
60  created = buildSet(c);
61  deleted = buildSet(d);
62  modified = buildSet(m);
63  }
64  };
65 
66  // A helper method tests can use to validate returned JSON vs NodeSanity.
67  void
68  checkSanity(Json::Value const& txNode, NodeSanity const& sane)
69  {
70  BEAST_EXPECT(txNode[jss::validated].asBool() == true);
71  BEAST_EXPECT(
72  txNode[jss::tx][sfTransactionType.jsonName].asString() ==
73  sane.txType);
74 
75  // Make sure all of the expected node types are present.
76  boost::container::flat_set<std::string> createdNodes;
77  boost::container::flat_set<std::string> deletedNodes;
78  boost::container::flat_set<std::string> modifiedNodes;
79 
80  for (Json::Value const& metaNode :
81  txNode[jss::meta][sfAffectedNodes.jsonName])
82  {
83  if (metaNode.isMember(sfCreatedNode.jsonName))
84  createdNodes.insert(
86  .asString());
87 
88  else if (metaNode.isMember(sfDeletedNode.jsonName))
89  deletedNodes.insert(
91  .asString());
92 
93  else if (metaNode.isMember(sfModifiedNode.jsonName))
94  modifiedNodes.insert(metaNode[sfModifiedNode.jsonName]
96  .asString());
97 
98  else
99  fail(
100  "Unexpected or unlabeled node type in metadata.",
101  __FILE__,
102  __LINE__);
103  }
104 
105  BEAST_EXPECT(createdNodes == sane.created);
106  BEAST_EXPECT(deletedNodes == sane.deleted);
107  BEAST_EXPECT(modifiedNodes == sane.modified);
108  };
109 
110  void
112  {
113  using namespace test::jtx;
114 
115  Env env(*this);
116  Account A1{"A1"};
117  env.fund(XRP(10000), A1);
118  env.close();
119 
120  // Ledger 3 has the two txs associated with funding the account
121  // All other ledgers have no txs
122 
123  auto hasTxs = [](Json::Value const& j) {
124  return j.isMember(jss::result) &&
125  (j[jss::result][jss::status] == "success") &&
126  (j[jss::result][jss::transactions].size() == 2) &&
127  (j[jss::result][jss::transactions][0u][jss::tx]
128  [jss::TransactionType] == jss::AccountSet) &&
129  (j[jss::result][jss::transactions][1u][jss::tx]
130  [jss::TransactionType] == jss::Payment);
131  };
132 
133  auto noTxs = [](Json::Value const& j) {
134  return j.isMember(jss::result) &&
135  (j[jss::result][jss::status] == "success") &&
136  (j[jss::result][jss::transactions].size() == 0);
137  };
138 
139  auto isErr = [](Json::Value const& j, error_code_i code) {
140  return j.isMember(jss::result) &&
141  j[jss::result].isMember(jss::error) &&
142  j[jss::result][jss::error] == RPC::get_error_info(code).token;
143  };
144 
145  Json::Value jParms;
146 
147  BEAST_EXPECT(isErr(
148  env.rpc("json", "account_tx", to_string(jParms)),
150 
151  jParms[jss::account] = "0xDEADBEEF";
152 
153  BEAST_EXPECT(isErr(
154  env.rpc("json", "account_tx", to_string(jParms)),
156 
157  jParms[jss::account] = A1.human();
158  BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(jParms))));
159 
160  // Ledger min/max index
161  {
162  Json::Value p{jParms};
163  p[jss::ledger_index_min] = -1;
164  p[jss::ledger_index_max] = -1;
165  BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
166 
167  p[jss::ledger_index_min] = 0;
168  p[jss::ledger_index_max] = 100;
169  BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
170 
171  p[jss::ledger_index_min] = 1;
172  p[jss::ledger_index_max] = 2;
173  BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p))));
174 
175  p[jss::ledger_index_min] = 2;
176  p[jss::ledger_index_max] = 1;
177  BEAST_EXPECT(isErr(
178  env.rpc("json", "account_tx", to_string(p)),
181  }
182 
183  // Ledger index min only
184  {
185  Json::Value p{jParms};
186  p[jss::ledger_index_min] = -1;
187  BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
188 
189  p[jss::ledger_index_min] = 1;
190  BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
191 
192  p[jss::ledger_index_min] = env.current()->info().seq;
193  BEAST_EXPECT(isErr(
194  env.rpc("json", "account_tx", to_string(p)),
197  }
198 
199  // Ledger index max only
200  {
201  Json::Value p{jParms};
202  p[jss::ledger_index_max] = -1;
203  BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
204 
205  p[jss::ledger_index_max] = env.current()->info().seq;
206  BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
207 
208  p[jss::ledger_index_max] = env.closed()->info().seq;
209  BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
210 
211  p[jss::ledger_index_max] = env.closed()->info().seq - 1;
212  BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p))));
213  }
214 
215  // Ledger Sequence
216  {
217  Json::Value p{jParms};
218 
219  p[jss::ledger_index] = env.closed()->info().seq;
220  BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
221 
222  p[jss::ledger_index] = env.closed()->info().seq - 1;
223  BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p))));
224 
225  p[jss::ledger_index] = env.current()->info().seq;
226  BEAST_EXPECT(isErr(
227  env.rpc("json", "account_tx", to_string(p)),
229 
230  p[jss::ledger_index] = env.current()->info().seq + 1;
231  BEAST_EXPECT(isErr(
232  env.rpc("json", "account_tx", to_string(p)), rpcLGR_NOT_FOUND));
233  }
234 
235  // Ledger Hash
236  {
237  Json::Value p{jParms};
238 
239  p[jss::ledger_hash] = to_string(env.closed()->info().hash);
240  BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
241 
242  p[jss::ledger_hash] = to_string(env.closed()->info().parentHash);
243  BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p))));
244  }
245  }
246 
247  void
249  {
250  // Get results for all transaction types that can be associated
251  // with an account. Start by generating all transaction types.
252  using namespace test::jtx;
253  using namespace std::chrono_literals;
254 
255  Env env(*this);
256  Account const alice{"alice"};
257  Account const alie{"alie"};
258  Account const gw{"gw"};
259  auto const USD{gw["USD"]};
260 
261  env.fund(XRP(1000000), alice, gw);
262  env.close();
263 
264  // AccountSet
265  env(noop(alice));
266 
267  // Payment
268  env(pay(alice, gw, XRP(100)));
269 
270  // Regular key set
271  env(regkey(alice, alie));
272  env.close();
273 
274  // Trust and Offers
275  env(trust(alice, USD(200)), sig(alie));
276  std::uint32_t const offerSeq{env.seq(alice)};
277  env(offer(alice, USD(50), XRP(150)), sig(alie));
278  env.close();
279 
280  env(offer_cancel(alice, offerSeq), sig(alie));
281  env.close();
282 
283  // SignerListSet
284  env(signers(alice, 1, {{"bogie", 1}, {"demon", 1}}), sig(alie));
285 
286  // Escrow
287  {
288  // Create an escrow. Requires either a CancelAfter or FinishAfter.
289  auto escrow = [](Account const& account,
290  Account const& to,
291  STAmount const& amount) {
292  Json::Value escro;
293  escro[jss::TransactionType] = jss::EscrowCreate;
294  escro[jss::Flags] = tfUniversal;
295  escro[jss::Account] = account.human();
296  escro[jss::Destination] = to.human();
297  escro[jss::Amount] = amount.getJson(JsonOptions::none);
298  return escro;
299  };
300 
301  NetClock::time_point const nextTime{env.now() + 2s};
302 
303  Json::Value escrowWithFinish{escrow(alice, alice, XRP(500))};
304  escrowWithFinish[sfFinishAfter.jsonName] =
305  nextTime.time_since_epoch().count();
306 
307  std::uint32_t const escrowFinishSeq{env.seq(alice)};
308  env(escrowWithFinish, sig(alie));
309 
310  Json::Value escrowWithCancel{escrow(alice, alice, XRP(500))};
311  escrowWithCancel[sfFinishAfter.jsonName] =
312  nextTime.time_since_epoch().count();
313  escrowWithCancel[sfCancelAfter.jsonName] =
314  nextTime.time_since_epoch().count() + 1;
315 
316  std::uint32_t const escrowCancelSeq{env.seq(alice)};
317  env(escrowWithCancel, sig(alie));
318  env.close();
319 
320  {
321  Json::Value escrowFinish;
322  escrowFinish[jss::TransactionType] = jss::EscrowFinish;
323  escrowFinish[jss::Flags] = tfUniversal;
324  escrowFinish[jss::Account] = alice.human();
325  escrowFinish[sfOwner.jsonName] = alice.human();
326  escrowFinish[sfOfferSequence.jsonName] = escrowFinishSeq;
327  env(escrowFinish, sig(alie));
328  }
329  {
330  Json::Value escrowCancel;
331  escrowCancel[jss::TransactionType] = jss::EscrowCancel;
332  escrowCancel[jss::Flags] = tfUniversal;
333  escrowCancel[jss::Account] = alice.human();
334  escrowCancel[sfOwner.jsonName] = alice.human();
335  escrowCancel[sfOfferSequence.jsonName] = escrowCancelSeq;
336  env(escrowCancel, sig(alie));
337  }
338  env.close();
339  }
340 
341  // PayChan
342  {
343  std::uint32_t payChanSeq{env.seq(alice)};
344  Json::Value payChanCreate;
345  payChanCreate[jss::TransactionType] = jss::PaymentChannelCreate;
346  payChanCreate[jss::Flags] = tfUniversal;
347  payChanCreate[jss::Account] = alice.human();
348  payChanCreate[jss::Destination] = gw.human();
349  payChanCreate[jss::Amount] =
350  XRP(500).value().getJson(JsonOptions::none);
351  payChanCreate[sfSettleDelay.jsonName] =
352  NetClock::duration{100s}.count();
353  payChanCreate[sfPublicKey.jsonName] = strHex(alice.pk().slice());
354  env(payChanCreate, sig(alie));
355  env.close();
356 
357  std::string const payChanIndex{
358  strHex(keylet::payChan(alice, gw, payChanSeq).key)};
359 
360  {
361  Json::Value payChanFund;
362  payChanFund[jss::TransactionType] = jss::PaymentChannelFund;
363  payChanFund[jss::Flags] = tfUniversal;
364  payChanFund[jss::Account] = alice.human();
365  payChanFund[sfChannel.jsonName] = payChanIndex;
366  payChanFund[jss::Amount] =
367  XRP(200).value().getJson(JsonOptions::none);
368  env(payChanFund, sig(alie));
369  env.close();
370  }
371  {
372  Json::Value payChanClaim;
373  payChanClaim[jss::TransactionType] = jss::PaymentChannelClaim;
374  payChanClaim[jss::Flags] = tfClose;
375  payChanClaim[jss::Account] = gw.human();
376  payChanClaim[sfChannel.jsonName] = payChanIndex;
377  payChanClaim[sfPublicKey.jsonName] = strHex(alice.pk().slice());
378  env(payChanClaim);
379  env.close();
380  }
381  }
382 
383  // Check
384  {
385  auto const aliceCheckId = keylet::check(alice, env.seq(alice)).key;
386  env(check::create(alice, gw, XRP(300)), sig(alie));
387 
388  auto const gwCheckId = keylet::check(gw, env.seq(gw)).key;
389  env(check::create(gw, alice, XRP(200)));
390  env.close();
391 
392  env(check::cash(alice, gwCheckId, XRP(200)), sig(alie));
393  env(check::cancel(alice, aliceCheckId), sig(alie));
394  env.close();
395  }
396  {
397  // Deposit preauthorization with a Ticket.
398  std::uint32_t const tktSeq{env.seq(alice) + 1};
399  env(ticket::create(alice, 1), sig(alie));
400  env.close();
401 
402  env(deposit::auth(alice, gw), ticket::use(tktSeq), sig(alie));
403  env.close();
404  }
405 
406  // Setup is done. Look at the transactions returned by account_tx.
407  Json::Value params;
408  params[jss::account] = alice.human();
409  params[jss::ledger_index_min] = -1;
410  params[jss::ledger_index_max] = -1;
411 
412  Json::Value const result{
413  env.rpc("json", "account_tx", to_string(params))};
414 
415  BEAST_EXPECT(result[jss::result][jss::status] == "success");
416  BEAST_EXPECT(result[jss::result][jss::transactions].isArray());
417 
418  Json::Value const& txs{result[jss::result][jss::transactions]};
419 
420  // clang-format off
421  // Do a sanity check on each returned transaction. They should
422  // be returned in the reverse order of application to the ledger.
423  static const NodeSanity sanity[]{
424  // txType, created, deleted, modified
425  {0, jss::DepositPreauth, {jss::DepositPreauth}, {jss::Ticket}, {jss::AccountRoot, jss::DirectoryNode}},
426  {1, jss::TicketCreate, {jss::Ticket}, {}, {jss::AccountRoot, jss::DirectoryNode}},
427  {2, jss::CheckCancel, {}, {jss::Check}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
428  {3, jss::CheckCash, {}, {jss::Check}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
429  {4, jss::CheckCreate, {jss::Check}, {}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
430  {5, jss::CheckCreate, {jss::Check}, {}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
431  {6, jss::PaymentChannelClaim, {}, {jss::PayChannel}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
432  {7, jss::PaymentChannelFund, {}, {}, {jss::AccountRoot, jss::PayChannel}},
433  {8, jss::PaymentChannelCreate, {jss::PayChannel}, {}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
434  {9, jss::EscrowCancel, {}, {jss::Escrow}, {jss::AccountRoot, jss::DirectoryNode}},
435  {10, jss::EscrowFinish, {}, {jss::Escrow}, {jss::AccountRoot, jss::DirectoryNode}},
436  {11, jss::EscrowCreate, {jss::Escrow}, {}, {jss::AccountRoot, jss::DirectoryNode}},
437  {12, jss::EscrowCreate, {jss::Escrow}, {}, {jss::AccountRoot, jss::DirectoryNode}},
438  {13, jss::SignerListSet, {jss::SignerList}, {}, {jss::AccountRoot, jss::DirectoryNode}},
439  {14, jss::OfferCancel, {}, {jss::Offer, jss::DirectoryNode}, {jss::AccountRoot, jss::DirectoryNode}},
440  {15, jss::OfferCreate, {jss::Offer, jss::DirectoryNode}, {}, {jss::AccountRoot, jss::DirectoryNode}},
441  {16, jss::TrustSet, {jss::RippleState, jss::DirectoryNode, jss::DirectoryNode}, {}, {jss::AccountRoot, jss::AccountRoot}},
442  {17, jss::SetRegularKey, {}, {}, {jss::AccountRoot}},
443  {18, jss::Payment, {}, {}, {jss::AccountRoot, jss::AccountRoot}},
444  {19, jss::AccountSet, {}, {}, {jss::AccountRoot}},
445  {20, jss::AccountSet, {}, {}, {jss::AccountRoot}},
446  {21, jss::Payment, {jss::AccountRoot}, {}, {jss::AccountRoot}},
447  };
448  // clang-format on
449 
450  BEAST_EXPECT(
451  std::size(sanity) == result[jss::result][jss::transactions].size());
452 
453  for (unsigned int index{0}; index < std::size(sanity); ++index)
454  {
455  checkSanity(txs[index], sanity[index]);
456  }
457  }
458 
459  void
461  {
462  // Verify that if an account is resurrected then the account_tx RPC
463  // command still recovers all transactions on that account before
464  // and after resurrection.
465  using namespace test::jtx;
466  using namespace std::chrono_literals;
467 
468  Env env(*this);
469  Account const alice{"alice"};
470  Account const becky{"becky"};
471 
472  env.fund(XRP(10000), alice, becky);
473  env.close();
474 
475  // Verify that becky's account root is present.
476  Keylet const beckyAcctKey{keylet::account(becky.id())};
477  BEAST_EXPECT(env.closed()->exists(beckyAcctKey));
478 
479  // becky does an AccountSet .
480  env(noop(becky));
481 
482  // Close enough ledgers to be able to delete becky's account.
483  std::uint32_t const ledgerCount{
484  env.current()->seq() + 257 - env.seq(becky)};
485 
486  for (std::uint32_t i = 0; i < ledgerCount; ++i)
487  env.close();
488 
489  auto const beckyPreDelBalance{env.balance(becky)};
490 
491  auto const acctDelFee{drops(env.current()->fees().increment)};
492  env(acctdelete(becky, alice), fee(acctDelFee));
493  env.close();
494 
495  // Verify that becky's account root is gone.
496  BEAST_EXPECT(!env.closed()->exists(beckyAcctKey));
497  env.close();
498 
499  // clang-format off
500  // Do a sanity check on each returned transaction. They should
501  // be returned in the reverse order of application to the ledger.
502  //
503  // Note that the first two transactions in sanity have not occurred
504  // yet. We'll see those after becky's account is resurrected.
505  static const NodeSanity sanity[]
506  {
507  // txType, created, deleted, modified
508 /* becky pays alice */ { 0, jss::Payment, {}, {}, {jss::AccountRoot, jss::AccountRoot}},
509 /* alice resurrects becky's acct */ { 1, jss::Payment, {jss::AccountRoot}, {}, {jss::AccountRoot}},
510 /* becky deletes her account */ { 2, jss::AccountDelete, {}, {jss::AccountRoot}, {jss::AccountRoot}},
511 /* becky's noop */ { 3, jss::AccountSet, {}, {}, {jss::AccountRoot}},
512 /* "fund" sets flags */ { 4, jss::AccountSet, {}, {}, {jss::AccountRoot}},
513 /* "fund" creates becky's acct */ { 5, jss::Payment, {jss::AccountRoot}, {}, {jss::AccountRoot}}
514  };
515  // clang-format on
516 
517  // Verify that we can recover becky's account_tx information even
518  // after the account is deleted.
519  {
520  Json::Value params;
521  params[jss::account] = becky.human();
522  params[jss::ledger_index_min] = -1;
523  params[jss::ledger_index_max] = -1;
524 
525  Json::Value const result{
526  env.rpc("json", "account_tx", to_string(params))};
527 
528  BEAST_EXPECT(result[jss::result][jss::status] == "success");
529  BEAST_EXPECT(result[jss::result][jss::transactions].isArray());
530 
531  // The first two transactions listed in sanity haven't happened yet.
532  constexpr unsigned int beckyDeletedOffest = 2;
533  BEAST_EXPECT(
534  std::size(sanity) ==
535  result[jss::result][jss::transactions].size() +
536  beckyDeletedOffest);
537 
538  Json::Value const& txs{result[jss::result][jss::transactions]};
539 
540  for (unsigned int index = beckyDeletedOffest;
541  index < std::size(sanity);
542  ++index)
543  {
544  checkSanity(txs[index - beckyDeletedOffest], sanity[index]);
545  }
546  }
547 
548  // All it takes is a large enough XRP payment to resurrect
549  // becky's account. Try too small a payment.
550  env(pay(alice,
551  becky,
552  drops(env.current()->fees().accountReserve(0)) - XRP(1)),
554  env.close();
555 
556  // Actually resurrect becky's account.
557  env(pay(alice, becky, XRP(45)));
558  env.close();
559 
560  // becky's account root should be back.
561  BEAST_EXPECT(env.closed()->exists(beckyAcctKey));
562  BEAST_EXPECT(env.balance(becky) == XRP(45));
563 
564  // becky pays alice.
565  env(pay(becky, alice, XRP(20)));
566  env.close();
567 
568  // Setup is done. Look at the transactions returned by account_tx.
569  // Verify that account_tx locates all of becky's transactions.
570  Json::Value params;
571  params[jss::account] = becky.human();
572  params[jss::ledger_index_min] = -1;
573  params[jss::ledger_index_max] = -1;
574 
575  Json::Value const result{
576  env.rpc("json", "account_tx", to_string(params))};
577 
578  BEAST_EXPECT(result[jss::result][jss::status] == "success");
579  BEAST_EXPECT(result[jss::result][jss::transactions].isArray());
580 
581  BEAST_EXPECT(
582  std::size(sanity) == result[jss::result][jss::transactions].size());
583 
584  Json::Value const& txs{result[jss::result][jss::transactions]};
585 
586  for (unsigned int index = 0; index < std::size(sanity); ++index)
587  {
588  checkSanity(txs[index], sanity[index]);
589  }
590  }
591 
592 public:
593  void
594  run() override
595  {
596  testParameters();
597  testContents();
599  }
600 };
601 BEAST_DEFINE_TESTSUITE(AccountTx, app, ripple);
602 
603 } // namespace test
604 } // namespace ripple
ripple::test::AccountTx_test::testParameters
void testParameters()
Definition: AccountTx_test.cpp:111
ripple::test::AccountTx_test::NodeSanity::NodeSanity
NodeSanity(int idx, Json::StaticString const &t, std::initializer_list< char const * > c, std::initializer_list< char const * > d, std::initializer_list< char const * > m)
Definition: AccountTx_test.cpp:44
ripple::sfOfferSequence
const SF_UINT32 sfOfferSequence
ripple::test::AccountTx_test::NodeSanity::txType
Json::StaticString const & txType
Definition: AccountTx_test.cpp:39
ripple::test::jtx::noop
Json::Value noop(Account const &account)
The null transaction.
Definition: noop.h:31
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::Keylet
A pair of SHAMap key and LedgerEntryType.
Definition: Keylet.h:38
ripple::rpcLGR_IDXS_INVALID
@ rpcLGR_IDXS_INVALID
Definition: ErrorCodes.h:112
std::string
STL class.
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
ripple::HashPrefix::txNode
@ txNode
transaction plus metadata
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
ripple::RPC::get_error_info
ErrorInfo const & get_error_info(error_code_i code)
Returns an ErrorInfo that reflects the error code.
Definition: ErrorCodes.cpp:170
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::Env::closed
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
Definition: Env.cpp:115
ripple::sfOwner
const SF_ACCOUNT sfOwner
std::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
std::chrono::duration
ripple::test::jtx::offer_cancel
Json::Value offer_cancel(Account const &account, std::uint32_t offerSeq)
Cancel an offer.
Definition: offer.cpp:45
ripple::tfClose
constexpr std::uint32_t tfClose
Definition: TxFlags.h:123
ripple::test::AccountTx_test::NodeSanity::index
const int index
Definition: AccountTx_test.cpp:38
ripple::test::AccountTx_test::NodeSanity
Definition: AccountTx_test.cpp:36
ripple::test::jtx::Env::balance
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition: Env.cpp:183
ripple::test::AccountTx_test::testContents
void testContents()
Definition: AccountTx_test.cpp:248
ripple::rpcLGR_NOT_FOUND
@ rpcLGR_NOT_FOUND
Definition: ErrorCodes.h:72
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:136
ripple::sfDeletedNode
const SField sfDeletedNode
ripple::error_code_i
error_code_i
Definition: ErrorCodes.h:40
ripple::tecNO_DST_INSUF_XRP
@ tecNO_DST_INSUF_XRP
Definition: TER.h:258
ripple::Keylet::key
uint256 key
Definition: Keylet.h:40
ripple::sfTransactionType
const SF_UINT16 sfTransactionType
ripple::test::AccountTx_test::run
void run() override
Definition: AccountTx_test.cpp:594
ripple::test::jtx::ticket::use
Set a ticket sequence on a JTx.
Definition: ticket.h:47
ripple::sfSettleDelay
const SF_UINT32 sfSettleDelay
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:133
ripple::JsonOptions::none
@ none
ripple::sfAffectedNodes
const SField sfAffectedNodes
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::sfModifiedNode
const SField sfModifiedNode
ripple::STAmount
Definition: STAmount.h:45
ripple::test::AccountTx_test::NodeSanity::deleted
boost::container::flat_set< std::string > deleted
Definition: AccountTx_test.cpp:41
std::chrono::time_point
ripple::test::AccountTx_test
Definition: AccountTx_test.cpp:32
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
std::uint32_t
ripple::test::jtx::sig
Set the regular signature on a JTx.
Definition: sig.h:34
ripple::test::jtx::Env::seq
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:207
ripple::test::jtx::fee
Set the fee on a JTx.
Definition: fee.h:35
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::rpcACT_MALFORMED
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
ripple::sfLedgerEntryType
const SF_UINT16 sfLedgerEntryType
ripple::test::AccountTx_test::testAccountDelete
void testAccountDelete()
Definition: AccountTx_test.cpp:460
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 network time.
Definition: Env.h:264
ripple::keylet::payChan
Keylet payChan(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Definition: Indexes.cpp:324
ripple::rpcLGR_NOT_VALIDATED
@ rpcLGR_NOT_VALIDATED
Definition: ErrorCodes.h:73
ripple::test::jtx::regkey
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Definition: regkey.cpp:28
Json::StaticString
Lightweight wrapper to tag static string.
Definition: json_value.h:60
ripple::test::AccountTx_test::checkSanity
void checkSanity(Json::Value const &txNode, NodeSanity const &sane)
Definition: AccountTx_test.cpp:68
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
ripple::sfCreatedNode
const SField sfCreatedNode
ripple::RPC::apiMaximumSupportedVersion
constexpr unsigned int apiMaximumSupportedVersion
Definition: RPCHelpers.h:244
ripple::test::jtx::acctdelete
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
Definition: acctdelete.cpp:29
std::chrono::duration::count
T count(T... args)
ripple::sfCancelAfter
const SF_UINT32 sfCancelAfter
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::sfFinishAfter
const SF_UINT32 sfFinishAfter
ripple::sfChannel
const SF_UINT256 sfChannel
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::rpcINVALID_LGR_RANGE
@ rpcINVALID_LGR_RANGE
Definition: ErrorCodes.h:136
ripple::test::AccountTx_test::NodeSanity::modified
boost::container::flat_set< std::string > modified
Definition: AccountTx_test.cpp:42
ripple::test::AccountTx_test::NodeSanity::created
boost::container::flat_set< std::string > created
Definition: AccountTx_test.cpp:40
ripple::tfUniversal
constexpr std::uint32_t tfUniversal
Definition: TxFlags.h:59
ripple::keylet::check
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition: Indexes.cpp:281
ripple::sfPublicKey
const SF_VL sfPublicKey
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:300
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::RPC::ErrorInfo::token
Json::StaticString token
Definition: ErrorCodes.h:199
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
std::initializer_list
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)