rippled
AccountTxPaging_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 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 <test/jtx.h>
20 #include <ripple/beast/unit_test.h>
21 #include <ripple/protocol/jss.h>
22 #include <ripple/protocol/SField.h>
23 #include <cstdlib>
24 
25 #include <ripple/rpc/GRPCHandlers.h>
26 #include <ripple/rpc/impl/RPCHelpers.h>
27 #include <test/rpc/GRPCTestClientBase.h>
28 
29 
30 namespace ripple {
31 
32 class AccountTxPaging_test : public beast::unit_test::suite
33 {
34  bool
35  checkTransaction (Json::Value const& tx, int sequence, int ledger)
36  {
37  return (
38  tx[jss::tx][jss::Sequence].asInt() == sequence &&
39  tx[jss::tx][jss::ledger_index].asInt() == ledger);
40  }
41 
42  auto next(
43  test::jtx::Env & env,
44  test::jtx::Account const& account,
45  int ledger_min,
46  int ledger_max,
47  int limit,
48  bool forward,
49  Json::Value const& marker = Json::nullValue)
50  {
51  Json::Value jvc;
52  jvc[jss::account] = account.human();
53  jvc[jss::ledger_index_min] = ledger_min;
54  jvc[jss::ledger_index_max] = ledger_max;
55  jvc[jss::forward] = forward;
56  jvc[jss::limit] = limit;
57  if (marker)
58  jvc[jss::marker] = marker;
59 
60  return env.rpc("json", "account_tx", to_string(jvc))[jss::result];
61  }
62 
63  void
65  {
66  testcase("Paging for Single Account");
67  using namespace test::jtx;
68 
69  Env env(*this);
70  Account A1 {"A1"};
71  Account A2 {"A2"};
72  Account A3 {"A3"};
73 
74  env.fund(XRP(10000), A1, A2, A3);
75  env.close();
76 
77  env.trust(A3["USD"](1000), A1);
78  env.trust(A2["USD"](1000), A1);
79  env.trust(A3["USD"](1000), A2);
80  env.close();
81 
82  for (auto i = 0; i < 5; ++i)
83  {
84  env(pay(A2, A1, A2["USD"](2)));
85  env(pay(A3, A1, A3["USD"](2)));
86  env(offer(A1, XRP(11), A1["USD"](1)));
87  env(offer(A2, XRP(10), A2["USD"](1)));
88  env(offer(A3, XRP(9), A3["USD"](1)));
89  env.close();
90  }
91 
92  /* The sequence/ledger for A3 are as follows:
93  * seq ledger_index
94  * 3 ----> 3
95  * 1 ----> 3
96  * 2 ----> 4
97  * 2 ----> 4
98  * 2 ----> 5
99  * 3 ----> 5
100  * 4 ----> 6
101  * 5 ----> 6
102  * 6 ----> 7
103  * 7 ----> 7
104  * 8 ----> 8
105  * 9 ----> 8
106  * 10 ----> 9
107  * 11 ----> 9
108  */
109 
110  // page through the results in several ways.
111  {
112  // limit = 2, 3 batches giving the first 6 txs
113  auto jrr = next(env, A3, 2, 5, 2, true);
114  auto txs = jrr[jss::transactions];
115  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 2))
116  return;
117  BEAST_EXPECT(checkTransaction (txs[0u], 3, 3));
118  BEAST_EXPECT(checkTransaction (txs[1u], 3, 3));
119  if(! BEAST_EXPECT(jrr[jss::marker]))
120  return;
121 
122  jrr = next(env, A3, 2, 5, 2, true, jrr[jss::marker]);
123  txs = jrr[jss::transactions];
124  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 2))
125  return;
126  BEAST_EXPECT(checkTransaction (txs[0u], 4, 4));
127  BEAST_EXPECT(checkTransaction (txs[1u], 4, 4));
128  if(! BEAST_EXPECT(jrr[jss::marker]))
129  return;
130 
131  jrr = next(env, A3, 2, 5, 2, true, jrr[jss::marker]);
132  txs = jrr[jss::transactions];
133  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 2))
134  return;
135  BEAST_EXPECT(checkTransaction (txs[0u], 4, 5));
136  BEAST_EXPECT(checkTransaction (txs[1u], 5, 5));
137  BEAST_EXPECT(! jrr[jss::marker]);
138  }
139 
140  {
141  // limit 1, 3 requests giving the first 3 txs
142  auto jrr = next(env, A3, 3, 9, 1, true);
143  auto txs = jrr[jss::transactions];
144  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 1))
145  return;
146  BEAST_EXPECT(checkTransaction (txs[0u], 3, 3));
147  if(! BEAST_EXPECT(jrr[jss::marker]))
148  return;
149 
150  jrr = next(env, A3, 3, 9, 1, true, jrr[jss::marker]);
151  txs = jrr[jss::transactions];
152  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 1))
153  return;
154  BEAST_EXPECT(checkTransaction (txs[0u], 3, 3));
155  if(! BEAST_EXPECT(jrr[jss::marker]))
156  return;
157 
158  jrr = next(env, A3, 3, 9, 1, true, jrr[jss::marker]);
159  txs = jrr[jss::transactions];
160  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 1))
161  return;
162  BEAST_EXPECT(checkTransaction (txs[0u], 4, 4));
163  if(! BEAST_EXPECT(jrr[jss::marker]))
164  return;
165 
166  // continue with limit 3, to end of all txs
167  jrr = next(env, A3, 3, 9, 3, true, jrr[jss::marker]);
168  txs = jrr[jss::transactions];
169  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 3))
170  return;
171  BEAST_EXPECT(checkTransaction (txs[0u], 4, 4));
172  BEAST_EXPECT(checkTransaction (txs[1u], 4, 5));
173  BEAST_EXPECT(checkTransaction (txs[2u], 5, 5));
174  if(! BEAST_EXPECT(jrr[jss::marker]))
175  return;
176 
177  jrr = next(env, A3, 3, 9, 3, true, jrr[jss::marker]);
178  txs = jrr[jss::transactions];
179  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 3))
180  return;
181  BEAST_EXPECT(checkTransaction (txs[0u], 6, 6));
182  BEAST_EXPECT(checkTransaction (txs[1u], 7, 6));
183  BEAST_EXPECT(checkTransaction (txs[2u], 8, 7));
184  if(! BEAST_EXPECT(jrr[jss::marker]))
185  return;
186 
187  jrr = next(env, A3, 3, 9, 3, true, jrr[jss::marker]);
188  txs = jrr[jss::transactions];
189  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 3))
190  return;
191  BEAST_EXPECT(checkTransaction (txs[0u], 9, 7));
192  BEAST_EXPECT(checkTransaction (txs[1u], 10, 8));
193  BEAST_EXPECT(checkTransaction (txs[2u], 11, 8));
194  if(! BEAST_EXPECT(jrr[jss::marker]))
195  return;
196 
197  jrr = next(env, A3, 3, 9, 3, true, jrr[jss::marker]);
198  txs = jrr[jss::transactions];
199  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 2))
200  return;
201  BEAST_EXPECT(checkTransaction (txs[0u], 12, 9));
202  BEAST_EXPECT(checkTransaction (txs[1u], 13, 9));
203  BEAST_EXPECT(! jrr[jss::marker]);
204  }
205 
206  {
207  // limit 2, descending, 2 batches giving last 4 txs
208  auto jrr = next(env, A3, 3, 9, 2, false);
209  auto txs = jrr[jss::transactions];
210  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 2))
211  return;
212  BEAST_EXPECT(checkTransaction (txs[0u], 13, 9));
213  BEAST_EXPECT(checkTransaction (txs[1u], 12, 9));
214  if(! BEAST_EXPECT(jrr[jss::marker]))
215  return;
216 
217  jrr = next(env, A3, 3, 9, 2, false, jrr[jss::marker]);
218  txs = jrr[jss::transactions];
219  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 2))
220  return;
221  BEAST_EXPECT(checkTransaction (txs[0u], 11, 8));
222  BEAST_EXPECT(checkTransaction (txs[1u], 10, 8));
223  if(! BEAST_EXPECT(jrr[jss::marker]))
224  return;
225 
226  // continue with limit 3 until all txs have been seen
227  jrr = next(env, A3, 3, 9, 3, false, jrr[jss::marker]);
228  txs = jrr[jss::transactions];
229  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 3))
230  return;
231  BEAST_EXPECT(checkTransaction (txs[0u], 9, 7));
232  BEAST_EXPECT(checkTransaction (txs[1u], 8, 7));
233  BEAST_EXPECT(checkTransaction (txs[2u], 7, 6));
234  if(! BEAST_EXPECT(jrr[jss::marker]))
235  return;
236 
237  jrr = next(env, A3, 3, 9, 3, false, jrr[jss::marker]);
238  txs = jrr[jss::transactions];
239  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 3))
240  return;
241  BEAST_EXPECT(checkTransaction (txs[0u], 6, 6));
242  BEAST_EXPECT(checkTransaction (txs[1u], 5, 5));
243  BEAST_EXPECT(checkTransaction (txs[2u], 4, 5));
244  if(! BEAST_EXPECT(jrr[jss::marker]))
245  return;
246 
247  jrr = next(env, A3, 3, 9, 3, false, jrr[jss::marker]);
248  txs = jrr[jss::transactions];
249  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 3))
250  return;
251  BEAST_EXPECT(checkTransaction (txs[0u], 4, 4));
252  BEAST_EXPECT(checkTransaction (txs[1u], 4, 4));
253  BEAST_EXPECT(checkTransaction (txs[2u], 3, 3));
254  if(! BEAST_EXPECT(jrr[jss::marker]))
255  return;
256 
257  jrr = next(env, A3, 3, 9, 3, false, jrr[jss::marker]);
258  txs = jrr[jss::transactions];
259  if (! BEAST_EXPECT(txs.isArray() && txs.size() == 1))
260  return;
261  BEAST_EXPECT(checkTransaction (txs[0u], 3, 3));
262  BEAST_EXPECT(! jrr[jss::marker]);
263  }
264  }
265 
267  {
268  public:
269  org::xrpl::rpc::v1::GetAccountTransactionHistoryRequest request;
270  org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse reply;
271 
272  explicit GrpcAccountTxClient(std::string const& port)
273  : GRPCTestClientBase(port)
274  {
275  }
276 
277  void
279  {
280  status =
281  stub_->GetAccountTransactionHistory(&context, request, &reply);
282  }
283  };
284 
285  bool
287  org::xrpl::rpc::v1::GetTransactionResponse const& tx,
288  int sequence,
289  int ledger)
290  {
291  return (
292  tx.transaction().sequence().value() == sequence &&
293  tx.ledger_index() == ledger);
294  }
295 
296  std::pair<
297  org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse,
298  grpc::Status>
300  std::string grpcPort,
301  test::jtx::Env& env,
302  std::string const& account = "",
303  int ledger_min = -1,
304  int ledger_max = -1,
305  int limit = -1,
306  bool forward = false,
307  org::xrpl::rpc::v1::Marker* marker = nullptr)
308  {
309  GrpcAccountTxClient client{grpcPort};
310  auto& request = client.request;
311  if (account != "")
312  request.mutable_account()->set_address(account);
313  if (ledger_min != -1)
314  request.mutable_ledger_range()->set_ledger_index_min(ledger_min);
315  if (ledger_max != -1)
316  request.mutable_ledger_range()->set_ledger_index_max(ledger_max);
317  request.set_forward(forward);
318  request.set_binary(true);
319  if (limit != -1)
320  request.set_limit(limit);
321  if (marker)
322  {
323  *request.mutable_marker() = *marker;
324  }
325 
326  client.AccountTx();
327  return {client.reply, client.status};
328  }
329 
330  std::pair<
331  org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse,
332  grpc::Status>
334  std::string grpcPort,
335  test::jtx::Env& env,
336  std::string const& account = "",
337  int ledger_min = -1,
338  int ledger_max = -1,
339  int limit = -1,
340  bool forward = false,
341  org::xrpl::rpc::v1::Marker* marker = nullptr)
342  {
343  GrpcAccountTxClient client{grpcPort};
344  auto& request = client.request;
345  if (account != "")
346  request.mutable_account()->set_address(account);
347  if (ledger_min != -1)
348  request.mutable_ledger_range()->set_ledger_index_min(ledger_min);
349  if (ledger_max != -1)
350  request.mutable_ledger_range()->set_ledger_index_max(ledger_max);
351  request.set_forward(forward);
352  if (limit != -1)
353  request.set_limit(limit);
354  if (marker)
355  {
356  *request.mutable_marker() = *marker;
357  }
358 
359  client.AccountTx();
360  return {client.reply, client.status};
361  }
362 
363  std::pair<
364  org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse,
365  grpc::Status>
367  std::string grpcPort,
368  test::jtx::Env& env,
369  std::string const& account = "",
370  int ledger_seq = -1,
371  int limit = -1,
372  bool forward = false,
373  org::xrpl::rpc::v1::Marker* marker = nullptr)
374  {
375  GrpcAccountTxClient client{grpcPort};
376  auto& request = client.request;
377  if (account != "")
378  request.mutable_account()->set_address(account);
379  if (ledger_seq != -1)
380  request.mutable_ledger_specifier()->set_sequence(ledger_seq);
381  request.set_forward(forward);
382  if (limit != -1)
383  request.set_limit(limit);
384  if (marker)
385  {
386  *request.mutable_marker() = *marker;
387  }
388 
389  client.AccountTx();
390  return {client.reply, client.status};
391  }
392 
393  std::pair<
394  org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse,
395  grpc::Status>
397  std::string grpcPort,
398  test::jtx::Env& env,
399  std::string const& account = "",
400  uint256 const& hash = beast::zero,
401  int limit = -1,
402  bool forward = false,
403  org::xrpl::rpc::v1::Marker* marker = nullptr)
404  {
405  GrpcAccountTxClient client{grpcPort};
406  auto& request = client.request;
407  if (account != "")
408  request.mutable_account()->set_address(account);
409  if (hash != beast::zero)
410  request.mutable_ledger_specifier()->set_hash(
411  hash.data(), hash.size());
412  request.set_forward(forward);
413  if (limit != -1)
414  request.set_limit(limit);
415  if (marker)
416  {
417  *request.mutable_marker() = *marker;
418  }
419 
420  client.AccountTx();
421  return {client.reply, client.status};
422  }
423 
424  void
426  {
427  testcase("Test Account_tx Grpc");
428 
429  using namespace test::jtx;
430  std::unique_ptr<Config> config = envconfig(addGrpcConfig);
431  std::string grpcPort = *(*config)["port_grpc"].get<std::string>("port");
432  Env env(*this, std::move(config));
433 
434  Account A1{"A1"};
435  env.fund(XRP(10000), A1);
436  env.close();
437 
438  // Ledger 3 has the two txs associated with funding the account
439  // All other ledgers have no txs
440 
441  auto hasTxs = [](auto res) {
442  return res.second.error_code() == 0 &&
443  (res.first.transactions().size() == 2) &&
444  //(res.transactions()[0u].transaction().has_account_set()) &&
445  (res.first.transactions()[1u].transaction().has_payment());
446  };
447  auto noTxs = [](auto res) {
448  return res.second.error_code() == 0 &&
449  (res.first.transactions().size() == 0);
450  };
451 
452  auto isErr = [](auto res, auto expect) {
453  return res.second.error_code() == expect;
454  };
455 
456  BEAST_EXPECT(
457  isErr(next(grpcPort, env, ""), grpc::StatusCode::INVALID_ARGUMENT));
458 
459  BEAST_EXPECT(isErr(
460  next(grpcPort, env, "0xDEADBEEF"),
461  grpc::StatusCode::INVALID_ARGUMENT));
462 
463  BEAST_EXPECT(hasTxs(next(grpcPort, env, A1.human())));
464 
465  // Ledger min/max index
466  {
467  BEAST_EXPECT(hasTxs(next(grpcPort, env, A1.human())));
468 
469  BEAST_EXPECT(hasTxs(next(grpcPort, env, A1.human(), 0, 100)));
470 
471  BEAST_EXPECT(noTxs(next(grpcPort, env, A1.human(), 1, 2)));
472 
473  BEAST_EXPECT(isErr(
474  next(grpcPort, env, A1.human(), 2, 1),
475  grpc::StatusCode::INVALID_ARGUMENT));
476  }
477 
478  // Ledger index min only
479  {
480  BEAST_EXPECT(hasTxs(next(grpcPort, env, A1.human(), -1)));
481 
482  BEAST_EXPECT(hasTxs(next(grpcPort, env, A1.human(), 1)));
483 
484  BEAST_EXPECT(isErr(
485  next(grpcPort, env, A1.human(), env.current()->info().seq),
486  grpc::StatusCode::INVALID_ARGUMENT));
487  }
488 
489  // Ledger index max only
490  {
491  BEAST_EXPECT(hasTxs(next(grpcPort, env, A1.human(), -1, -1)));
492 
493  BEAST_EXPECT(hasTxs(next(
494  grpcPort, env, A1.human(), -1, env.current()->info().seq)));
495 
496  BEAST_EXPECT(hasTxs(
497  next(grpcPort, env, A1.human(), -1, env.closed()->info().seq)));
498 
499  BEAST_EXPECT(noTxs(next(
500  grpcPort, env, A1.human(), -1, env.closed()->info().seq - 1)));
501  }
502  // Ledger Sequence
503  {
504  BEAST_EXPECT(hasTxs(nextWithSeq(
505  grpcPort, env, A1.human(), env.closed()->info().seq)));
506 
507  BEAST_EXPECT(noTxs(nextWithSeq(
508  grpcPort, env, A1.human(), env.closed()->info().seq - 1)));
509 
510  BEAST_EXPECT(isErr(
511  nextWithSeq(
512  grpcPort, env, A1.human(), env.current()->info().seq),
513  grpc::StatusCode::INVALID_ARGUMENT));
514 
515  BEAST_EXPECT(isErr(
516  nextWithSeq(
517  grpcPort, env, A1.human(), env.current()->info().seq + 1),
518  grpc::StatusCode::NOT_FOUND));
519  }
520 
521  // Ledger Hash
522  {
523  BEAST_EXPECT(hasTxs(nextWithHash(
524  grpcPort, env, A1.human(), env.closed()->info().hash)));
525 
526  BEAST_EXPECT(noTxs(nextWithHash(
527  grpcPort, env, A1.human(), env.closed()->info().parentHash)));
528  }
529  }
530 
531  struct TxCheck
532  {
533  uint32_t sequence;
534  uint32_t ledgerIndex;
536  std::function<bool(org::xrpl::rpc::v1::Transaction const& res)>
538  };
539 
540  void
542  {
543  testcase("Test AccountTx context grpc");
544  // Get results for all transaction types that can be associated
545  // with an account. Start by generating all transaction types.
546  using namespace test::jtx;
547  using namespace std::chrono_literals;
548 
549  std::unique_ptr<Config> config = envconfig(addGrpcConfig);
550  std::string grpcPort = *(*config)["port_grpc"].get<std::string>("port");
551  Env env(*this, std::move(config));
552  // Set time to this value (or greater) to get delivered_amount in meta
553  env.timeKeeper().set(NetClock::time_point{446000001s});
554  Account const alice{"alice"};
555  Account const alie{"alie"};
556  Account const gw{"gw"};
557  auto const USD{gw["USD"]};
558 
560 
561  env.fund(XRP(1000000), alice, gw);
562  env.close();
563 
564  // AccountSet
565  env(noop(alice));
566 
567  txns.emplace_back(env.tx());
568  // Payment
569  env(pay(alice, gw, XRP(100)), stag(42), dtag(24), last_ledger_seq(20));
570 
571  txns.emplace_back(env.tx());
572  // Regular key set
573  env(regkey(alice, alie));
574  env.close();
575 
576  txns.emplace_back(env.tx());
577  // Trust and Offers
578  env(trust(alice, USD(200)), sig(alie));
579 
580  txns.emplace_back(env.tx());
581  std::uint32_t const offerSeq{env.seq(alice)};
582  env(offer(alice, USD(50), XRP(150)), sig(alie));
583 
584  txns.emplace_back(env.tx());
585  env.close();
586 
587  {
588  Json::Value cancelOffer;
589  cancelOffer[jss::Account] = alice.human();
590  cancelOffer[jss::OfferSequence] = offerSeq;
591  cancelOffer[jss::TransactionType] = jss::OfferCancel;
592  env(cancelOffer, sig(alie));
593  }
594  env.close();
595 
596  txns.emplace_back(env.tx());
597 
598  // SignerListSet
599  env(signers(alice, 1, {{"bogie", 1}, {"demon", 1}, {gw, 1}}),
600  sig(alie));
601 
602  txns.emplace_back(env.tx());
603  // Escrow
604  {
605  // Create an escrow. Requires either a CancelAfter or FinishAfter.
606  auto escrow = [](Account const& account,
607  Account const& to,
608  STAmount const& amount) {
609  Json::Value escro;
610  escro[jss::TransactionType] = jss::EscrowCreate;
611  escro[jss::Flags] = tfUniversal;
612  escro[jss::Account] = account.human();
613  escro[jss::Destination] = to.human();
614  escro[jss::Amount] = amount.getJson(JsonOptions::none);
615  return escro;
616  };
617 
618  NetClock::time_point const nextTime{env.now() + 2s};
619 
620  Json::Value escrowWithFinish{escrow(alice, alice, XRP(500))};
621  escrowWithFinish[sfFinishAfter.jsonName] =
622  nextTime.time_since_epoch().count();
623 
624  std::uint32_t const escrowFinishSeq{env.seq(alice)};
625  env(escrowWithFinish, sig(alie));
626 
627  txns.emplace_back(env.tx());
628  Json::Value escrowWithCancel{escrow(alice, alice, XRP(500))};
629  escrowWithCancel[sfFinishAfter.jsonName] =
630  nextTime.time_since_epoch().count();
631  escrowWithCancel[sfCancelAfter.jsonName] =
632  nextTime.time_since_epoch().count() + 1;
633 
634  std::uint32_t const escrowCancelSeq{env.seq(alice)};
635  env(escrowWithCancel, sig(alie));
636  env.close();
637 
638  txns.emplace_back(env.tx());
639  {
640  Json::Value escrowFinish;
641  escrowFinish[jss::TransactionType] = jss::EscrowFinish;
642  escrowFinish[jss::Flags] = tfUniversal;
643  escrowFinish[jss::Account] = alice.human();
644  escrowFinish[sfOwner.jsonName] = alice.human();
645  escrowFinish[sfOfferSequence.jsonName] = escrowFinishSeq;
646  env(escrowFinish, sig(alie));
647 
648  txns.emplace_back(env.tx());
649  }
650  {
651  Json::Value escrowCancel;
652  escrowCancel[jss::TransactionType] = jss::EscrowCancel;
653  escrowCancel[jss::Flags] = tfUniversal;
654  escrowCancel[jss::Account] = alice.human();
655  escrowCancel[sfOwner.jsonName] = alice.human();
656  escrowCancel[sfOfferSequence.jsonName] = escrowCancelSeq;
657  env(escrowCancel, sig(alie));
658 
659  txns.emplace_back(env.tx());
660  }
661  env.close();
662  }
663 
664  // PayChan
665  {
666  std::uint32_t payChanSeq{env.seq(alice)};
667  Json::Value payChanCreate;
668  payChanCreate[jss::TransactionType] = jss::PaymentChannelCreate;
669  payChanCreate[jss::Flags] = tfUniversal;
670  payChanCreate[jss::Account] = alice.human();
671  payChanCreate[jss::Destination] = gw.human();
672  payChanCreate[jss::Amount] =
673  XRP(500).value().getJson(JsonOptions::none);
674  payChanCreate[sfSettleDelay.jsonName] =
675  NetClock::duration{100s}.count();
676  payChanCreate[sfPublicKey.jsonName] = strHex(alice.pk().slice());
677  env(payChanCreate, sig(alie));
678  env.close();
679 
680  txns.emplace_back(env.tx());
681  std::string const payChanIndex{
682  strHex(keylet::payChan(alice, gw, payChanSeq).key)};
683 
684  {
685  Json::Value payChanFund;
686  payChanFund[jss::TransactionType] = jss::PaymentChannelFund;
687  payChanFund[jss::Flags] = tfUniversal;
688  payChanFund[jss::Account] = alice.human();
689  payChanFund[sfPayChannel.jsonName] = payChanIndex;
690  payChanFund[jss::Amount] =
691  XRP(200).value().getJson(JsonOptions::none);
692  env(payChanFund, sig(alie));
693  env.close();
694 
695  txns.emplace_back(env.tx());
696  }
697  {
698  Json::Value payChanClaim;
699  payChanClaim[jss::TransactionType] = jss::PaymentChannelClaim;
700  payChanClaim[jss::Flags] = tfClose;
701  payChanClaim[jss::Account] = gw.human();
702  payChanClaim[sfPayChannel.jsonName] = payChanIndex;
703  payChanClaim[sfPublicKey.jsonName] = strHex(alice.pk().slice());
704  env(payChanClaim);
705  env.close();
706 
707  txns.emplace_back(env.tx());
708  }
709  }
710 
711  // Check
712  {
713  uint256 const aliceCheckId{getCheckIndex(alice, env.seq(alice))};
714  env(check::create(alice, gw, XRP(300)), sig(alie));
715 
716  auto txn = env.tx();
717  uint256 const gwCheckId{getCheckIndex(gw, env.seq(gw))};
718  env(check::create(gw, alice, XRP(200)));
719  env.close();
720 
721  // need to switch the order of the previous 2 txns, since they are
722  // in the same ledger and account_tx returns them in a different
723  // order
724  txns.emplace_back(env.tx());
725  txns.emplace_back(txn);
726  env(check::cash(alice, gwCheckId, XRP(200)), sig(alie));
727 
728  txns.emplace_back(env.tx());
729  env(check::cancel(alice, aliceCheckId), sig(alie));
730 
731  txns.emplace_back(env.tx());
732  env.close();
733  }
734 
735  // Deposit preauthorization.
736  env(deposit::auth(alice, gw), sig(alie));
737  env.close();
738 
739  txns.emplace_back(env.tx());
740  // Multi Sig with memo
741  auto const baseFee = env.current()->fees().base;
742  env(noop(alice),
743  msig(gw),
744  fee(2 * baseFee),
745  memo("data", "format", "type"));
746  env.close();
747 
748  txns.emplace_back(env.tx());
749  if (!BEAST_EXPECT(txns.size() == 20))
750  return;
751  // Setup is done. Look at the transactions returned by account_tx.
752 
753  static const TxCheck txCheck[]{
754  {21,
755  15,
756  strHex(txns[txns.size() - 1]->getTransactionID()),
757  [this, &txns](auto res) {
758  auto txnJson =
759  txns[txns.size() - 1]->getJson(JsonOptions::none);
760  return BEAST_EXPECT(res.has_account_set()) &&
761  BEAST_EXPECT(res.has_fee()) &&
762  BEAST_EXPECT(res.fee().drops() == 20) &&
763  BEAST_EXPECT(res.memos_size() == 1) &&
764  BEAST_EXPECT(res.memos(0).has_memo_data()) &&
765  BEAST_EXPECT(res.memos(0).memo_data().value() == "data") &&
766  BEAST_EXPECT(res.memos(0).has_memo_format()) &&
767  BEAST_EXPECT(
768  res.memos(0).memo_format().value() == "format") &&
769  BEAST_EXPECT(res.memos(0).has_memo_type()) &&
770  BEAST_EXPECT(res.memos(0).memo_type().value() == "type") &&
771  BEAST_EXPECT(res.has_signing_public_key()) &&
772  BEAST_EXPECT(res.signing_public_key().value() == "") &&
773  BEAST_EXPECT(res.signers_size() == 1) &&
774  BEAST_EXPECT(res.signers(0).has_account()) &&
775  BEAST_EXPECT(
776  res.signers(0).account().value().address() ==
777  txnJson["Signers"][0u]["Signer"]["Account"]) &&
778  BEAST_EXPECT(res.signers(0).has_transaction_signature()) &&
779  BEAST_EXPECT(
780  strHex(res.signers(0)
781  .transaction_signature()
782  .value()) ==
783  txnJson["Signers"][0u]["Signer"]["TxnSignature"]) &&
784  BEAST_EXPECT(res.signers(0).has_signing_public_key()) &&
785  BEAST_EXPECT(
786  strHex(
787  res.signers(0).signing_public_key().value()) ==
788  txnJson["Signers"][0u]["Signer"]["SigningPubKey"]);
789  }},
790  {20,
791  14,
792  strHex(txns[txns.size() - 2]->getTransactionID()),
793  [&txns, this](auto res) {
794  return BEAST_EXPECT(res.has_deposit_preauth()) &&
795  BEAST_EXPECT(
796  res.deposit_preauth()
797  .authorize()
798  .value()
799  .address() ==
800  // TODO do them all like this
801  txns[txns.size() - 2]->getJson(
802  JsonOptions::none)["Authorize"]);
803  }},
804  {19,
805  13,
806  strHex(txns[txns.size() - 3]->getTransactionID()),
807  [&txns, this](auto res) {
808  return BEAST_EXPECT(res.has_check_cancel()) &&
809  BEAST_EXPECT(
810  strHex(res.check_cancel().check_id().value()) ==
811 
812  txns[txns.size() - 3]->getJson(
813  JsonOptions::none)["CheckID"]);
814  }},
815  {18,
816  13,
817  strHex(txns[txns.size() - 4]->getTransactionID()),
818  [&txns, this](auto res) {
819  auto txnJson =
820  txns[txns.size() - 4]->getJson(JsonOptions::none);
821  return BEAST_EXPECT(res.has_check_cash()) &&
822  BEAST_EXPECT(
823  strHex(res.check_cash().check_id().value()) ==
824  txnJson["CheckID"]) &&
825  BEAST_EXPECT(res.check_cash()
826  .amount()
827  .value()
828  .has_xrp_amount()) &&
829  BEAST_EXPECT(
830  res.check_cash()
831  .amount()
832  .value()
833  .xrp_amount()
834  .drops() == txnJson["Amount"].asUInt());
835  }},
836  {17,
837  12,
838  strHex(txns[txns.size() - 5]->getTransactionID()),
839  [&txns, this](auto res) {
840  auto txnJson =
841  txns[txns.size() - 5]->getJson(JsonOptions::none);
842  return BEAST_EXPECT(res.has_check_create()) &&
843  BEAST_EXPECT(
844  res.check_create()
845  .destination()
846  .value()
847  .address() == txnJson["Destination"]) &&
848  BEAST_EXPECT(res.check_create()
849  .send_max()
850  .value()
851  .has_xrp_amount()) &&
852  BEAST_EXPECT(
853  res.check_create()
854  .send_max()
855  .value()
856  .xrp_amount()
857  .drops() == txnJson["SendMax"].asUInt());
858  }},
859  {5,
860  12,
861  strHex(txns[txns.size() - 6]->getTransactionID()),
862  [&txns, this](auto res) {
863  auto txnJson =
864  txns[txns.size() - 6]->getJson(JsonOptions::none);
865  return BEAST_EXPECT(res.has_check_create()) &&
866  BEAST_EXPECT(
867  res.check_create()
868  .destination()
869  .value()
870  .address() == txnJson["Destination"]) &&
871  BEAST_EXPECT(res.check_create()
872  .send_max()
873  .value()
874  .has_xrp_amount()) &&
875  BEAST_EXPECT(
876  res.check_create()
877  .send_max()
878  .value()
879  .xrp_amount()
880  .drops() ==
881 
882  txnJson["SendMax"].asUInt());
883  }},
884  {4,
885  11,
886  strHex(txns[txns.size() - 7]->getTransactionID()),
887  [&txns, this](auto res) {
888  auto txnJson =
889  txns[txns.size() - 7]->getJson(JsonOptions::none);
890  return BEAST_EXPECT(res.has_payment_channel_claim()) &&
891  BEAST_EXPECT(
892  strHex(res.payment_channel_claim()
893  .channel()
894  .value()) == txnJson["Channel"]) &&
895  BEAST_EXPECT(
896  strHex(res.payment_channel_claim()
897  .public_key()
898  .value()) == txnJson["PublicKey"]);
899  }},
900  {16,
901  10,
902  strHex(txns[txns.size() - 8]->getTransactionID()),
903  [&txns, this](auto res) {
904  auto txnJson =
905  txns[txns.size() - 8]->getJson(JsonOptions::none);
906  return BEAST_EXPECT(res.has_payment_channel_fund()) &&
907  BEAST_EXPECT(
908  strHex(
909  res.payment_channel_fund().channel().value()) ==
910  txnJson["Channel"]) &&
911  BEAST_EXPECT(res.payment_channel_fund()
912  .amount()
913  .value()
914  .has_xrp_amount()) &&
915  BEAST_EXPECT(
916  res.payment_channel_fund()
917  .amount()
918  .value()
919  .xrp_amount()
920  .drops() == txnJson["Amount"].asUInt());
921  }},
922  {15,
923  9,
924  strHex(txns[txns.size() - 9]->getTransactionID()),
925  [&txns, this](auto res) {
926  auto txnJson =
927  txns[txns.size() - 9]->getJson(JsonOptions::none);
928  return BEAST_EXPECT(res.has_payment_channel_create()) &&
929  BEAST_EXPECT(res.payment_channel_create()
930  .amount()
931  .value()
932  .has_xrp_amount()) &&
933  BEAST_EXPECT(
934  res.payment_channel_create()
935  .amount()
936  .value()
937  .xrp_amount()
938  .drops() == txnJson["Amount"].asUInt()) &&
939  BEAST_EXPECT(
940  res.payment_channel_create()
941  .destination()
942  .value()
943  .address() == txnJson["Destination"]) &&
944  BEAST_EXPECT(
945  res.payment_channel_create()
946  .settle_delay()
947  .value() == txnJson["SettleDelay"].asUInt()) &&
948  BEAST_EXPECT(
949  strHex(res.payment_channel_create()
950  .public_key()
951  .value()) == txnJson["PublicKey"]);
952  }},
953  {14,
954  8,
955  strHex(txns[txns.size() - 10]->getTransactionID()),
956  [&txns, this](auto res) {
957  auto txnJson =
958  txns[txns.size() - 10]->getJson(JsonOptions::none);
959  return BEAST_EXPECT(res.has_escrow_cancel()) &&
960  BEAST_EXPECT(
961  res.escrow_cancel().owner().value().address() ==
962  txnJson["Owner"]) &&
963  BEAST_EXPECT(
964  res.escrow_cancel().offer_sequence().value() ==
965  txnJson["OfferSequence"].asUInt()
966 
967  );
968  }},
969  {13,
970  8,
971  strHex(txns[txns.size() - 11]->getTransactionID()),
972  [&txns, this](auto res) {
973  auto txnJson =
974  txns[txns.size() - 11]->getJson(JsonOptions::none);
975  return BEAST_EXPECT(res.has_escrow_finish()) &&
976  BEAST_EXPECT(
977  res.escrow_finish().owner().value().address() ==
978  txnJson["Owner"]) &&
979  BEAST_EXPECT(
980  res.escrow_finish().offer_sequence().value() ==
981  txnJson["OfferSequence"].asUInt()
982 
983  );
984  }},
985  {12,
986  7,
987  strHex(txns[txns.size() - 12]->getTransactionID()),
988  [&txns, this](auto res) {
989  auto txnJson =
990  txns[txns.size() - 12]->getJson(JsonOptions::none);
991  return BEAST_EXPECT(res.has_escrow_create()) &&
992  BEAST_EXPECT(res.escrow_create()
993  .amount()
994  .value()
995  .has_xrp_amount()) &&
996  BEAST_EXPECT(
997  res.escrow_create()
998  .amount()
999  .value()
1000  .xrp_amount()
1001  .drops() == txnJson["Amount"].asUInt()) &&
1002  BEAST_EXPECT(
1003  res.escrow_create()
1004  .destination()
1005  .value()
1006  .address() == txnJson["Destination"]) &&
1007  BEAST_EXPECT(
1008  res.escrow_create().cancel_after().value() ==
1009  txnJson["CancelAfter"].asUInt()) &&
1010  BEAST_EXPECT(
1011  res.escrow_create().finish_after().value() ==
1012  txnJson["FinishAfter"].asUInt());
1013  }},
1014  {11,
1015  7,
1016  strHex(txns[txns.size() - 13]->getTransactionID()),
1017  [&txns, this](auto res) {
1018  auto txnJson =
1019  txns[txns.size() - 13]->getJson(JsonOptions::none);
1020  return BEAST_EXPECT(res.has_escrow_create()) &&
1021  BEAST_EXPECT(res.escrow_create()
1022  .amount()
1023  .value()
1024  .has_xrp_amount()) &&
1025  BEAST_EXPECT(
1026  res.escrow_create()
1027  .amount()
1028  .value()
1029  .xrp_amount()
1030  .drops() == txnJson["Amount"].asUInt()) &&
1031  BEAST_EXPECT(
1032  res.escrow_create()
1033  .destination()
1034  .value()
1035  .address() == txnJson["Destination"]) &&
1036  BEAST_EXPECT(
1037  res.escrow_create().finish_after().value() ==
1038  txnJson["FinishAfter"].asUInt());
1039  }},
1040  {10,
1041  7,
1042  strHex(txns[txns.size() - 14]->getTransactionID()),
1043  [&txns, this](auto res) {
1044  auto txnJson =
1045  txns[txns.size() - 14]->getJson(JsonOptions::none);
1046  return BEAST_EXPECT(res.has_signer_list_set()) &&
1047  BEAST_EXPECT(
1048  res.signer_list_set().signer_quorum().value() ==
1049  txnJson["SignerQuorum"].asUInt()) &&
1050  BEAST_EXPECT(
1051  res.signer_list_set().signer_entries().size() ==
1052  3) &&
1053  BEAST_EXPECT(
1054  res.signer_list_set()
1055  .signer_entries()[0]
1056  .account()
1057  .value()
1058  .address() ==
1059  txnJson["SignerEntries"][0u]["SignerEntry"]
1060  ["Account"]) &&
1061  BEAST_EXPECT(
1062  res.signer_list_set()
1063  .signer_entries()[0]
1064  .signer_weight()
1065  .value() ==
1066  txnJson["SignerEntries"][0u]["SignerEntry"]
1067  ["SignerWeight"]
1068  .asUInt()) &&
1069  BEAST_EXPECT(
1070  res.signer_list_set()
1071  .signer_entries()[1]
1072  .account()
1073  .value()
1074  .address() ==
1075  txnJson["SignerEntries"][1u]["SignerEntry"]
1076  ["Account"]) &&
1077  BEAST_EXPECT(
1078  res.signer_list_set()
1079  .signer_entries()[1]
1080  .signer_weight()
1081  .value() ==
1082  txnJson["SignerEntries"][1u]["SignerEntry"]
1083  ["SignerWeight"]
1084  .asUInt()) &&
1085  BEAST_EXPECT(
1086  res.signer_list_set()
1087  .signer_entries()[2]
1088  .account()
1089  .value()
1090  .address() ==
1091  txnJson["SignerEntries"][2u]["SignerEntry"]
1092  ["Account"]) &&
1093  BEAST_EXPECT(
1094  res.signer_list_set()
1095  .signer_entries()[2]
1096  .signer_weight()
1097  .value() ==
1098  txnJson["SignerEntries"][2u]["SignerEntry"]
1099  ["SignerWeight"]
1100  .asUInt());
1101  }},
1102  {9,
1103  6,
1104  strHex(txns[txns.size() - 15]->getTransactionID()),
1105  [&txns, this](auto res) {
1106  auto txnJson =
1107  txns[txns.size() - 15]->getJson(JsonOptions::none);
1108  return BEAST_EXPECT(res.has_offer_cancel()) &&
1109  BEAST_EXPECT(
1110  res.offer_cancel().offer_sequence().value() ==
1111  txnJson["OfferSequence"].asUInt());
1112  }},
1113  {8,
1114  5,
1115  strHex(txns[txns.size() - 16]->getTransactionID()),
1116  [&txns, this](auto res) {
1117  auto txnJson =
1118  txns[txns.size() - 16]->getJson(JsonOptions::none);
1119  return BEAST_EXPECT(res.has_offer_create()) &&
1120  BEAST_EXPECT(res.offer_create()
1121  .taker_gets()
1122  .value()
1123  .has_xrp_amount()) &&
1124  BEAST_EXPECT(
1125  res.offer_create()
1126  .taker_gets()
1127  .value()
1128  .xrp_amount()
1129  .drops() == txnJson["TakerGets"].asUInt()) &&
1130  BEAST_EXPECT(res.offer_create()
1131  .taker_pays()
1132  .value()
1133  .has_issued_currency_amount()) &&
1134  BEAST_EXPECT(
1135  res.offer_create()
1136  .taker_pays()
1137  .value()
1138  .issued_currency_amount()
1139  .currency()
1140  .name() == txnJson["TakerPays"]["currency"]) &&
1141  BEAST_EXPECT(
1142  res.offer_create()
1143  .taker_pays()
1144  .value()
1145  .issued_currency_amount()
1146  .value() == txnJson["TakerPays"]["value"]) &&
1147  BEAST_EXPECT(
1148  res.offer_create()
1149  .taker_pays()
1150  .value()
1151  .issued_currency_amount()
1152  .issuer()
1153  .address() == txnJson["TakerPays"]["issuer"]);
1154  }},
1155  {7,
1156  5,
1157  strHex(txns[txns.size() - 17]->getTransactionID()),
1158  [&txns, this](auto res) {
1159  auto txnJson =
1160  txns[txns.size() - 17]->getJson(JsonOptions::none);
1161  return BEAST_EXPECT(res.has_trust_set()) &&
1162  BEAST_EXPECT(res.trust_set()
1163  .limit_amount()
1164  .value()
1165  .has_issued_currency_amount()) &&
1166  BEAST_EXPECT(
1167  res.trust_set()
1168  .limit_amount()
1169  .value()
1170  .issued_currency_amount()
1171  .currency()
1172  .name() ==
1173  txnJson["LimitAmount"]["currency"]) &&
1174  BEAST_EXPECT(
1175  res.trust_set()
1176  .limit_amount()
1177  .value()
1178  .issued_currency_amount()
1179  .value() == txnJson["LimitAmount"]["value"]) &&
1180  BEAST_EXPECT(
1181  res.trust_set()
1182  .limit_amount()
1183  .value()
1184  .issued_currency_amount()
1185  .issuer()
1186  .address() == txnJson["LimitAmount"]["issuer"]);
1187  }},
1188  {6,
1189  4,
1190  strHex(txns[txns.size() - 18]->getTransactionID()),
1191  [&txns, this](auto res) {
1192  auto txnJson =
1193  txns[txns.size() - 18]->getJson(JsonOptions::none);
1194  return BEAST_EXPECT(res.has_set_regular_key()) &&
1195  BEAST_EXPECT(
1196  res.set_regular_key()
1197  .regular_key()
1198  .value()
1199  .address() == txnJson["RegularKey"]);
1200  }},
1201  {5,
1202  4,
1203  strHex(txns[txns.size() - 19]->getTransactionID()),
1204  [&txns, this](auto res) {
1205  auto txnJson =
1206  txns[txns.size() - 19]->getJson(JsonOptions::none);
1207  return BEAST_EXPECT(res.has_payment()) &&
1208  BEAST_EXPECT(
1209  res.payment().amount().value().has_xrp_amount()) &&
1210  BEAST_EXPECT(
1211  res.payment()
1212  .amount()
1213  .value()
1214  .xrp_amount()
1215  .drops() == txnJson["Amount"].asUInt()) &&
1216  BEAST_EXPECT(
1217  res.payment().destination().value().address() ==
1218  txnJson["Destination"]) &&
1219  BEAST_EXPECT(res.has_source_tag()) &&
1220  BEAST_EXPECT(
1221  res.source_tag().value() ==
1222  txnJson["SourceTag"].asUInt()) &&
1223  BEAST_EXPECT(res.payment().has_destination_tag()) &&
1224  BEAST_EXPECT(
1225  res.payment().destination_tag().value() ==
1226  txnJson["DestinationTag"].asUInt()) &&
1227  BEAST_EXPECT(res.has_last_ledger_sequence()) &&
1228  BEAST_EXPECT(
1229  res.last_ledger_sequence().value() ==
1230  txnJson["LastLedgerSequence"].asUInt()) &&
1231  BEAST_EXPECT(res.has_transaction_signature()) &&
1232  BEAST_EXPECT(res.has_account()) &&
1233  BEAST_EXPECT(
1234  res.account().value().address() ==
1235  txnJson["Account"]) &&
1236  BEAST_EXPECT(res.has_flags()) &&
1237  BEAST_EXPECT(
1238  res.flags().value() == txnJson["Flags"].asUInt());
1239  }},
1240  {4,
1241  4,
1242  strHex(txns[txns.size() - 20]->getTransactionID()),
1243  [this](auto res) { return BEAST_EXPECT(res.has_account_set()); }},
1244  {3,
1245  3,
1246  "9CE54C3B934E473A995B477E92EC229F99CED5B62BF4D2ACE4DC42719103AE2F",
1247  [this](auto res) {
1248  return BEAST_EXPECT(res.has_account_set()) &&
1249  BEAST_EXPECT(res.account_set().set_flag().value() == 8);
1250  }},
1251  {1,
1252  3,
1253  "2B5054734FA43C6C7B54F61944FAD6178ACD5D0272B39BA7FCD32A5D3932FBFF",
1254  [&alice, this](auto res) {
1255  return BEAST_EXPECT(res.has_payment()) &&
1256  BEAST_EXPECT(
1257  res.payment().amount().value().has_xrp_amount()) &&
1258  BEAST_EXPECT(
1259  res.payment()
1260  .amount()
1261  .value()
1262  .xrp_amount()
1263  .drops() == 1000000000010) &&
1264  BEAST_EXPECT(
1265  res.payment().destination().value().address() ==
1266  alice.human());
1267  }}};
1268 
1269  using MetaCheck =
1270  std::function<bool(org::xrpl::rpc::v1::Meta const& res)>;
1271  static const MetaCheck txMetaCheck[]{
1272  {[this](auto meta) {
1273  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1274  BEAST_EXPECT(meta.affected_nodes_size() == 1) &&
1275  BEAST_EXPECT(
1276  std::count_if(
1277  meta.affected_nodes().begin(),
1278  meta.affected_nodes().end(),
1279  [](org::xrpl::rpc::v1::AffectedNode const&
1280  entry) {
1281  return entry.ledger_entry_type() ==
1282  org::xrpl::rpc::v1::LedgerEntryType::
1283  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1284  }) == 1);
1285  }},
1286  {[this](auto meta) {
1287  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1288  BEAST_EXPECT(meta.affected_nodes_size() == 3) &&
1289  BEAST_EXPECT(
1290  std::count_if(
1291  meta.affected_nodes().begin(),
1292  meta.affected_nodes().end(),
1293  [](auto entry) {
1294  return entry.ledger_entry_type() ==
1295  org::xrpl::rpc::v1::LedgerEntryType::
1296  LEDGER_ENTRY_TYPE_DEPOSIT_PREAUTH;
1297  }) == 1) &&
1298  BEAST_EXPECT(
1299  std::count_if(
1300  meta.affected_nodes().begin(),
1301 
1302  meta.affected_nodes().end(),
1303  [](auto entry) {
1304  return entry.ledger_entry_type() ==
1305  org::xrpl::rpc::v1::LedgerEntryType::
1306  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1307  }) == 1) &&
1308  BEAST_EXPECT(
1309  std::count_if(
1310  meta.affected_nodes().begin(),
1311  meta.affected_nodes().end(),
1312  [](auto entry) {
1313  return entry.ledger_entry_type() ==
1314  org::xrpl::rpc::v1::LedgerEntryType::
1315  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1316  }) == 1);
1317  }},
1318  {[this](auto meta) {
1319  return BEAST_EXPECT(meta.transaction_index() == 1) &&
1320  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1321  BEAST_EXPECT(
1322  std::count_if(
1323  meta.affected_nodes().begin(),
1324  meta.affected_nodes().end(),
1325  [](auto entry) {
1326  return entry.ledger_entry_type() ==
1327  org::xrpl::rpc::v1::LedgerEntryType::
1328  LEDGER_ENTRY_TYPE_CHECK;
1329  }) == 1) &&
1330  BEAST_EXPECT(
1331  std::count_if(
1332  meta.affected_nodes().begin(),
1333  meta.affected_nodes().end(),
1334  [](auto entry) {
1335  return entry.ledger_entry_type() ==
1336  org::xrpl::rpc::v1::LedgerEntryType::
1337  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1338  }) == 2) &&
1339  BEAST_EXPECT(
1340  std::count_if(
1341  meta.affected_nodes().begin(),
1342  meta.affected_nodes().end(),
1343  [](auto entry) {
1344  return entry.ledger_entry_type() ==
1345  org::xrpl::rpc::v1::LedgerEntryType::
1346  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1347  }) == 2);
1348  }},
1349  {[this](auto meta) {
1350  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1351  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1352  BEAST_EXPECT(
1353  std::count_if(
1354  meta.affected_nodes().begin(),
1355  meta.affected_nodes().end(),
1356  [](auto entry) {
1357  return entry.ledger_entry_type() ==
1358  org::xrpl::rpc::v1::LedgerEntryType::
1359  LEDGER_ENTRY_TYPE_CHECK;
1360  }) == 1) &&
1361  BEAST_EXPECT(
1362  std::count_if(
1363  meta.affected_nodes().begin(),
1364  meta.affected_nodes().end(),
1365  [](auto entry) {
1366  return entry.ledger_entry_type() ==
1367  org::xrpl::rpc::v1::LedgerEntryType::
1368  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1369  }) == 2) &&
1370  BEAST_EXPECT(
1371  std::count_if(
1372  meta.affected_nodes().begin(),
1373  meta.affected_nodes().end(),
1374  [](auto entry) {
1375  return entry.ledger_entry_type() ==
1376  org::xrpl::rpc::v1::LedgerEntryType::
1377  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1378  }) == 2);
1379  }},
1380  {[this](auto meta) {
1381  return BEAST_EXPECT(meta.transaction_index() == 1) &&
1382  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1383  BEAST_EXPECT(
1384  std::count_if(
1385  meta.affected_nodes().begin(),
1386  meta.affected_nodes().end(),
1387  [](auto entry) {
1388  return entry.ledger_entry_type() ==
1389  org::xrpl::rpc::v1::LedgerEntryType::
1390  LEDGER_ENTRY_TYPE_CHECK;
1391  }) == 1) &&
1392  BEAST_EXPECT(
1393  std::count_if(
1394  meta.affected_nodes().begin(),
1395  meta.affected_nodes().end(),
1396  [](auto entry) {
1397  return entry.ledger_entry_type() ==
1398  org::xrpl::rpc::v1::LedgerEntryType::
1399  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1400  }) == 2) &&
1401  BEAST_EXPECT(
1402  std::count_if(
1403  meta.affected_nodes().begin(),
1404  meta.affected_nodes().end(),
1405  [](auto entry) {
1406  return entry.ledger_entry_type() ==
1407  org::xrpl::rpc::v1::LedgerEntryType::
1408  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1409  }) == 2);
1410  }},
1411  {[this](auto meta) {
1412  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1413  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1414  BEAST_EXPECT(
1415  std::count_if(
1416  meta.affected_nodes().begin(),
1417  meta.affected_nodes().end(),
1418  [](auto entry) {
1419  return entry.ledger_entry_type() ==
1420  org::xrpl::rpc::v1::LedgerEntryType::
1421  LEDGER_ENTRY_TYPE_CHECK;
1422  }) == 1) &&
1423  BEAST_EXPECT(
1424  std::count_if(
1425  meta.affected_nodes().begin(),
1426  meta.affected_nodes().end(),
1427  [](auto entry) {
1428  return entry.ledger_entry_type() ==
1429  org::xrpl::rpc::v1::LedgerEntryType::
1430  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1431  }) == 2) &&
1432  BEAST_EXPECT(
1433  std::count_if(
1434  meta.affected_nodes().begin(),
1435  meta.affected_nodes().end(),
1436  [](auto entry) {
1437  return entry.ledger_entry_type() ==
1438  org::xrpl::rpc::v1::LedgerEntryType::
1439  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1440  }) == 2);
1441  }},
1442  {[this](auto meta) {
1443  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1444  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1445  BEAST_EXPECT(
1446  std::count_if(
1447  meta.affected_nodes().begin(),
1448  meta.affected_nodes().end(),
1449  [](auto entry) {
1450  return entry.ledger_entry_type() ==
1451  org::xrpl::rpc::v1::LedgerEntryType::
1452  LEDGER_ENTRY_TYPE_PAY_CHANNEL;
1453  }) == 1) &&
1454  BEAST_EXPECT(
1455  std::count_if(
1456  meta.affected_nodes().begin(),
1457  meta.affected_nodes().end(),
1458  [](auto entry) {
1459  return entry.ledger_entry_type() ==
1460  org::xrpl::rpc::v1::LedgerEntryType::
1461  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1462  }) == 2) &&
1463  BEAST_EXPECT(
1464  std::count_if(
1465  meta.affected_nodes().begin(),
1466  meta.affected_nodes().end(),
1467  [](auto entry) {
1468  return entry.ledger_entry_type() ==
1469  org::xrpl::rpc::v1::LedgerEntryType::
1470  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1471  }) == 2);
1472  }},
1473  {[this](auto meta) {
1474  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1475  BEAST_EXPECT(meta.affected_nodes_size() == 2) &&
1476 
1477  BEAST_EXPECT(
1478  std::count_if(
1479  meta.affected_nodes().begin(),
1480  meta.affected_nodes().end(),
1481  [](auto entry) {
1482  return entry.ledger_entry_type() ==
1483  org::xrpl::rpc::v1::LedgerEntryType::
1484  LEDGER_ENTRY_TYPE_PAY_CHANNEL;
1485  }) == 1) &&
1486  BEAST_EXPECT(
1487  std::count_if(
1488  meta.affected_nodes().begin(),
1489  meta.affected_nodes().end(),
1490  [](auto entry) {
1491  return entry.ledger_entry_type() ==
1492  org::xrpl::rpc::v1::LedgerEntryType::
1493  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1494  }) == 1);
1495  }},
1496  {[this](auto meta) {
1497  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1498  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1499 
1500  BEAST_EXPECT(
1501  std::count_if(
1502  meta.affected_nodes().begin(),
1503  meta.affected_nodes().end(),
1504  [](auto entry) {
1505  return entry.ledger_entry_type() ==
1506  org::xrpl::rpc::v1::LedgerEntryType::
1507  LEDGER_ENTRY_TYPE_PAY_CHANNEL;
1508  }) == 1) &&
1509  BEAST_EXPECT(
1510  std::count_if(
1511  meta.affected_nodes().begin(),
1512  meta.affected_nodes().end(),
1513  [](auto entry) {
1514  return entry.ledger_entry_type() ==
1515  org::xrpl::rpc::v1::LedgerEntryType::
1516  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1517  }) == 2) &&
1518  BEAST_EXPECT(
1519  std::count_if(
1520  meta.affected_nodes().begin(),
1521  meta.affected_nodes().end(),
1522  [](auto entry) {
1523  return entry.ledger_entry_type() ==
1524  org::xrpl::rpc::v1::LedgerEntryType::
1525  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1526  }) == 2);
1527  }},
1528  {[this](auto meta) {
1529  return BEAST_EXPECT(meta.transaction_index() == 1) &&
1530  BEAST_EXPECT(meta.affected_nodes_size() == 3) &&
1531  BEAST_EXPECT(
1532  std::count_if(
1533  meta.affected_nodes().begin(),
1534  meta.affected_nodes().end(),
1535  [](auto entry) {
1536  return entry.ledger_entry_type() ==
1537  org::xrpl::rpc::v1::LedgerEntryType::
1538  LEDGER_ENTRY_TYPE_ESCROW;
1539  }) == 1) &&
1540  BEAST_EXPECT(
1541  std::count_if(
1542  meta.affected_nodes().begin(),
1543  meta.affected_nodes().end(),
1544  [](auto entry) {
1545  return entry.ledger_entry_type() ==
1546  org::xrpl::rpc::v1::LedgerEntryType::
1547  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1548  }) == 1) &&
1549  BEAST_EXPECT(
1550  std::count_if(
1551  meta.affected_nodes().begin(),
1552  meta.affected_nodes().end(),
1553  [](auto entry) {
1554  return entry.ledger_entry_type() ==
1555  org::xrpl::rpc::v1::LedgerEntryType::
1556  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1557  }) == 1);
1558  }},
1559  {[this](auto meta) {
1560  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1561  BEAST_EXPECT(meta.affected_nodes_size() == 3) &&
1562  BEAST_EXPECT(
1563  std::count_if(
1564  meta.affected_nodes().begin(),
1565  meta.affected_nodes().end(),
1566  [](auto entry) {
1567  return entry.ledger_entry_type() ==
1568  org::xrpl::rpc::v1::LedgerEntryType::
1569  LEDGER_ENTRY_TYPE_ESCROW;
1570  }) == 1) &&
1571  BEAST_EXPECT(
1572  std::count_if(
1573  meta.affected_nodes().begin(),
1574  meta.affected_nodes().end(),
1575  [](auto entry) {
1576  return entry.ledger_entry_type() ==
1577  org::xrpl::rpc::v1::LedgerEntryType::
1578  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1579  }) == 1) &&
1580  BEAST_EXPECT(
1581  std::count_if(
1582  meta.affected_nodes().begin(),
1583  meta.affected_nodes().end(),
1584  [](auto entry) {
1585  return entry.ledger_entry_type() ==
1586  org::xrpl::rpc::v1::LedgerEntryType::
1587  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1588  }) == 1);
1589  }},
1590  {[this](auto meta) {
1591  return BEAST_EXPECT(meta.transaction_index() == 2) &&
1592  BEAST_EXPECT(meta.affected_nodes_size() == 3) &&
1593 
1594  BEAST_EXPECT(
1595  std::count_if(
1596  meta.affected_nodes().begin(),
1597  meta.affected_nodes().end(),
1598  [](auto entry) {
1599  return entry.ledger_entry_type() ==
1600  org::xrpl::rpc::v1::LedgerEntryType::
1601  LEDGER_ENTRY_TYPE_ESCROW;
1602  }) == 1) &&
1603  BEAST_EXPECT(
1604  std::count_if(
1605  meta.affected_nodes().begin(),
1606  meta.affected_nodes().end(),
1607  [](auto entry) {
1608  return entry.ledger_entry_type() ==
1609  org::xrpl::rpc::v1::LedgerEntryType::
1610  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1611  }) == 1) &&
1612  BEAST_EXPECT(
1613  std::count_if(
1614  meta.affected_nodes().begin(),
1615  meta.affected_nodes().end(),
1616  [](auto entry) {
1617  return entry.ledger_entry_type() ==
1618  org::xrpl::rpc::v1::LedgerEntryType::
1619  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1620  }) == 1);
1621  }},
1622  {[this](auto meta) {
1623  return BEAST_EXPECT(meta.transaction_index() == 1) &&
1624  BEAST_EXPECT(meta.affected_nodes_size() == 3) &&
1625 
1626  BEAST_EXPECT(
1627  std::count_if(
1628  meta.affected_nodes().begin(),
1629  meta.affected_nodes().end(),
1630  [](auto entry) {
1631  return entry.ledger_entry_type() ==
1632  org::xrpl::rpc::v1::LedgerEntryType::
1633  LEDGER_ENTRY_TYPE_ESCROW;
1634  }) == 1) &&
1635  BEAST_EXPECT(
1636  std::count_if(
1637  meta.affected_nodes().begin(),
1638  meta.affected_nodes().end(),
1639  [](auto entry) {
1640  return entry.ledger_entry_type() ==
1641  org::xrpl::rpc::v1::LedgerEntryType::
1642  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1643  }) == 1) &&
1644  BEAST_EXPECT(
1645  std::count_if(
1646  meta.affected_nodes().begin(),
1647  meta.affected_nodes().end(),
1648  [](auto entry) {
1649  return entry.ledger_entry_type() ==
1650  org::xrpl::rpc::v1::LedgerEntryType::
1651  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1652  }) == 1);
1653  }},
1654  {[this](auto meta) {
1655  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1656  BEAST_EXPECT(meta.affected_nodes_size() == 3) &&
1657  BEAST_EXPECT(
1658  std::count_if(
1659  meta.affected_nodes().begin(),
1660  meta.affected_nodes().end(),
1661  [](auto entry) {
1662  return entry.ledger_entry_type() ==
1663  org::xrpl::rpc::v1::LedgerEntryType::
1664  LEDGER_ENTRY_TYPE_SIGNER_LIST;
1665  }) == 1) &&
1666  BEAST_EXPECT(
1667  std::count_if(
1668  meta.affected_nodes().begin(),
1669  meta.affected_nodes().end(),
1670  [](auto entry) {
1671  return entry.ledger_entry_type() ==
1672  org::xrpl::rpc::v1::LedgerEntryType::
1673  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1674  }) == 1) &&
1675  BEAST_EXPECT(
1676  std::count_if(
1677  meta.affected_nodes().begin(),
1678  meta.affected_nodes().end(),
1679  [](auto entry) {
1680  return entry.ledger_entry_type() ==
1681  org::xrpl::rpc::v1::LedgerEntryType::
1682  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1683  }) == 1);
1684  }},
1685  {[this](auto meta) {
1686  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1687  BEAST_EXPECT(meta.affected_nodes_size() == 4) &&
1688  BEAST_EXPECT(
1689  std::count_if(
1690  meta.affected_nodes().begin(),
1691  meta.affected_nodes().end(),
1692  [](auto entry) {
1693  return entry.ledger_entry_type() ==
1694  org::xrpl::rpc::v1::LedgerEntryType::
1695  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1696  }) == 2) &&
1697  BEAST_EXPECT(
1698  std::count_if(
1699  meta.affected_nodes().begin(),
1700  meta.affected_nodes().end(),
1701  [](auto entry) {
1702  return entry.ledger_entry_type() ==
1703  org::xrpl::rpc::v1::LedgerEntryType::
1704  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1705  }) == 1) &&
1706  BEAST_EXPECT(
1707  std::count_if(
1708  meta.affected_nodes().begin(),
1709  meta.affected_nodes().end(),
1710  [](auto entry) {
1711  return entry.ledger_entry_type() ==
1712  org::xrpl::rpc::v1::LedgerEntryType::
1713  LEDGER_ENTRY_TYPE_OFFER;
1714  }) == 1);
1715  }},
1716  {[this](auto meta) {
1717  return BEAST_EXPECT(meta.transaction_index() == 1) &&
1718  BEAST_EXPECT(meta.affected_nodes_size() == 4) &&
1719 
1720  BEAST_EXPECT(
1721  std::count_if(
1722  meta.affected_nodes().begin(),
1723  meta.affected_nodes().end(),
1724  [](auto entry) {
1725  return entry.ledger_entry_type() ==
1726  org::xrpl::rpc::v1::LedgerEntryType::
1727  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1728  }) == 2) &&
1729  BEAST_EXPECT(
1730  std::count_if(
1731  meta.affected_nodes().begin(),
1732  meta.affected_nodes().end(),
1733  [](auto entry) {
1734  return entry.ledger_entry_type() ==
1735  org::xrpl::rpc::v1::LedgerEntryType::
1736  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1737  }) == 1) &&
1738  BEAST_EXPECT(
1739  std::count_if(
1740  meta.affected_nodes().begin(),
1741  meta.affected_nodes().end(),
1742  [](auto entry) {
1743  return entry.ledger_entry_type() ==
1744  org::xrpl::rpc::v1::LedgerEntryType::
1745  LEDGER_ENTRY_TYPE_OFFER;
1746  }) == 1);
1747  }},
1748  {[this](auto meta) {
1749  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1750  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1751  BEAST_EXPECT(
1752  std::count_if(
1753  meta.affected_nodes().begin(),
1754  meta.affected_nodes().end(),
1755  [](auto entry) {
1756  return entry.ledger_entry_type() ==
1757  org::xrpl::rpc::v1::LedgerEntryType::
1758  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1759  }) == 2) &&
1760  BEAST_EXPECT(
1761  std::count_if(
1762  meta.affected_nodes().begin(),
1763  meta.affected_nodes().end(),
1764  [](auto entry) {
1765  return entry.ledger_entry_type() ==
1766  org::xrpl::rpc::v1::LedgerEntryType::
1767  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1768  }) == 2) &&
1769  BEAST_EXPECT(
1770  std::count_if(
1771  meta.affected_nodes().begin(),
1772  meta.affected_nodes().end(),
1773  [](auto entry) {
1774  return entry.ledger_entry_type() ==
1775  org::xrpl::rpc::v1::LedgerEntryType::
1776  LEDGER_ENTRY_TYPE_RIPPLE_STATE;
1777  }) == 1);
1778  }},
1779  {[this](auto meta) {
1780  return BEAST_EXPECT(meta.transaction_index() == 2) &&
1781  BEAST_EXPECT(meta.affected_nodes_size() == 1) &&
1782  BEAST_EXPECT(
1783  std::count_if(
1784  meta.affected_nodes().begin(),
1785  meta.affected_nodes().end(),
1786  [](auto entry) {
1787  return entry.ledger_entry_type() ==
1788  org::xrpl::rpc::v1::LedgerEntryType::
1789  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1790  }) == 1);
1791  }},
1792  {[this](auto meta) {
1793  return BEAST_EXPECT(meta.transaction_index() == 1) &&
1794  BEAST_EXPECT(meta.affected_nodes_size() == 2) &&
1795  BEAST_EXPECT(
1796  std::count_if(
1797  meta.affected_nodes().begin(),
1798  meta.affected_nodes().end(),
1799  [](auto entry) {
1800  return entry.ledger_entry_type() ==
1801  org::xrpl::rpc::v1::LedgerEntryType::
1802  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1803  }) == 2);
1804  }},
1805  {[this](auto meta) {
1806  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1807  BEAST_EXPECT(meta.affected_nodes_size() == 1) &&
1808  BEAST_EXPECT(
1809  std::count_if(
1810  meta.affected_nodes().begin(),
1811  meta.affected_nodes().end(),
1812  [](auto entry) {
1813  return entry.ledger_entry_type() ==
1814  org::xrpl::rpc::v1::LedgerEntryType::
1815  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1816  }) == 1);
1817  }},
1818  {[this](auto meta) {
1819  return BEAST_EXPECT(meta.transaction_index() == 2) &&
1820  BEAST_EXPECT(meta.affected_nodes_size() == 1) &&
1821  BEAST_EXPECT(
1822  std::count_if(
1823  meta.affected_nodes().begin(),
1824  meta.affected_nodes().end(),
1825  [](auto entry) {
1826  return entry.ledger_entry_type() ==
1827  org::xrpl::rpc::v1::LedgerEntryType::
1828  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1829  }) == 1);
1830  }},
1831  {[this](auto meta) {
1832  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1833  BEAST_EXPECT(meta.affected_nodes_size() == 2) &&
1834  BEAST_EXPECT(
1835  std::count_if(
1836  meta.affected_nodes().begin(),
1837  meta.affected_nodes().end(),
1838  [](auto entry) {
1839  return entry.ledger_entry_type() ==
1840  org::xrpl::rpc::v1::LedgerEntryType::
1841  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1842  }) == 2);
1843  }}};
1844 
1845  auto doCheck = [this](auto txn, auto txCheck) {
1846  return BEAST_EXPECT(txn.has_transaction()) &&
1847  BEAST_EXPECT(txn.validated()) &&
1848  BEAST_EXPECT(strHex(txn.hash()) == txCheck.hash) &&
1849  BEAST_EXPECT(txn.ledger_index() == txCheck.ledgerIndex) &&
1850  BEAST_EXPECT(
1851  txn.transaction().sequence().value() ==
1852  txCheck.sequence) &&
1853  txCheck.checkTxn(txn.transaction());
1854  };
1855 
1856  auto doMetaCheck = [this](auto txn, auto txMetaCheck) {
1857  return BEAST_EXPECT(txn.has_meta()) &&
1858  BEAST_EXPECT(txn.meta().has_transaction_result()) &&
1859  BEAST_EXPECT(
1860  txn.meta().transaction_result().result_type() ==
1861  org::xrpl::rpc::v1::TransactionResult::
1862  RESULT_TYPE_TES) &&
1863  BEAST_EXPECT(
1864  txn.meta().transaction_result().result() ==
1865  "tesSUCCESS") &&
1866  txMetaCheck(txn.meta());
1867  };
1868 
1869  auto [res, status] = next(grpcPort, env, alice.human());
1870 
1871  if (!BEAST_EXPECT(status.error_code() == 0))
1872  return;
1873 
1874  if (!BEAST_EXPECT(
1875  res.transactions().size() ==
1876  std::extent<decltype(txCheck)>::value))
1877  return;
1878  for (int i = 0; i < res.transactions().size(); ++i)
1879  {
1880  BEAST_EXPECT(doCheck(res.transactions()[i], txCheck[i]));
1881  BEAST_EXPECT(doMetaCheck(res.transactions()[i], txMetaCheck[i]));
1882  }
1883 
1884  // test binary representation
1885  std::tie(res, status) = nextBinary(grpcPort, env, alice.human());
1886 
1887  // txns vector does not contain the first two transactions returned by
1888  // account_tx
1889  if (!BEAST_EXPECT(res.transactions().size() == txns.size() + 2))
1890  return;
1891 
1892  std::reverse(txns.begin(), txns.end());
1893  for (int i = 0; i < txns.size(); ++i)
1894  {
1895  auto toByteString = [](auto data) {
1896  const char* bytes = reinterpret_cast<const char*>(data.data());
1897  return std::string(bytes, data.size());
1898  };
1899 
1900  auto tx = txns[i];
1901  Serializer s = tx->getSerializer();
1902  std::string bin = toByteString(s);
1903 
1904  BEAST_EXPECT(res.transactions(i).transaction_binary() == bin);
1905  }
1906  }
1907 
1908  void
1910  {
1911  testcase("Test Account_tx Grpc");
1912 
1913  using namespace test::jtx;
1914  std::unique_ptr<Config> config = envconfig(addGrpcConfig);
1915  std::string grpcPort = *(*config)["port_grpc"].get<std::string>("port");
1916  Env env(*this, std::move(config));
1917 
1918  Account A1{"A1"};
1919  Account A2{"A2"};
1920  Account A3{"A3"};
1921 
1922  env.fund(XRP(10000), A1, A2, A3);
1923  env.close();
1924 
1925  env.trust(A3["USD"](1000), A1);
1926  env.trust(A2["USD"](1000), A1);
1927  env.trust(A3["USD"](1000), A2);
1928  env.close();
1929 
1930  for (auto i = 0; i < 5; ++i)
1931  {
1932  env(pay(A2, A1, A2["USD"](2)));
1933  env(pay(A3, A1, A3["USD"](2)));
1934  env(offer(A1, XRP(11), A1["USD"](1)));
1935  env(offer(A2, XRP(10), A2["USD"](1)));
1936  env(offer(A3, XRP(9), A3["USD"](1)));
1937  env.close();
1938  }
1939 
1940  /* The sequence/ledger for A3 are as follows:
1941  * seq ledger_index
1942  * 3 ----> 3
1943  * 1 ----> 3
1944  * 2 ----> 4
1945  * 2 ----> 4
1946  * 2 ----> 5
1947  * 3 ----> 5
1948  * 4 ----> 6
1949  * 5 ----> 6
1950  * 6 ----> 7
1951  * 7 ----> 7
1952  * 8 ----> 8
1953  * 9 ----> 8
1954  * 10 ----> 9
1955  * 11 ----> 9
1956  */
1957 
1958  // page through the results in several ways.
1959  {
1960  // limit = 2, 3 batches giving the first 6 txs
1961  auto [res, status] = next(grpcPort, env, A3.human(), 2, 5, 2, true);
1962 
1963  auto txs = res.transactions();
1964  if (!BEAST_EXPECT(txs.size() == 2))
1965  return;
1966 
1967  BEAST_EXPECT(checkTransaction(txs[0u], 3, 3));
1968  BEAST_EXPECT(checkTransaction(txs[1u], 3, 3));
1969  if (!BEAST_EXPECT(res.has_marker()))
1970  return;
1971 
1972  std::tie(res, status) = next(
1973  grpcPort, env, A3.human(), 2, 5, 2, true, res.mutable_marker());
1974  txs = res.transactions();
1975  if (!BEAST_EXPECT(txs.size() == 2))
1976  return;
1977  BEAST_EXPECT(checkTransaction(txs[0u], 4, 4));
1978  BEAST_EXPECT(checkTransaction(txs[1u], 4, 4));
1979  if (!BEAST_EXPECT(res.has_marker()))
1980  return;
1981 
1982  std::tie(res, status) = next(
1983  grpcPort, env, A3.human(), 2, 5, 2, true, res.mutable_marker());
1984  txs = res.transactions();
1985  if (!BEAST_EXPECT(txs.size() == 2))
1986  return;
1987  BEAST_EXPECT(checkTransaction(txs[0u], 4, 5));
1988  BEAST_EXPECT(checkTransaction(txs[1u], 5, 5));
1989  BEAST_EXPECT(!res.has_marker());
1990  return;
1991  }
1992 
1993  {
1994  // limit 1, 3 requests giving the first 3 txs
1995  auto [res, status] = next(grpcPort, env, A3.human(), 3, 9, 1, true);
1996  auto txs = res.transactions();
1997  if (!BEAST_EXPECT(txs.size() == 1))
1998  return;
1999  BEAST_EXPECT(checkTransaction(txs[0u], 3, 3));
2000  if (!BEAST_EXPECT(res.has_marker()))
2001  return;
2002 
2003  std::tie(res, status) = next(
2004  grpcPort, env, A3.human(), 3, 9, 1, true, res.mutable_marker());
2005  txs = res.transactions();
2006  if (!BEAST_EXPECT(txs.size() == 1))
2007  return;
2008  BEAST_EXPECT(checkTransaction(txs[0u], 3, 3));
2009  if (!BEAST_EXPECT(res.has_marker()))
2010  return;
2011 
2012  std::tie(res, status) = next(
2013  grpcPort, env, A3.human(), 3, 9, 1, true, res.mutable_marker());
2014  txs = res.transactions();
2015  if (!BEAST_EXPECT(txs.size() == 1))
2016  return;
2017  BEAST_EXPECT(checkTransaction(txs[0u], 4, 4));
2018  if (!BEAST_EXPECT(res.has_marker()))
2019  return;
2020 
2021  // continue with limit 3, to end of all txs
2022  std::tie(res, status) = next(
2023  grpcPort, env, A3.human(), 3, 9, 3, true, res.mutable_marker());
2024  txs = res.transactions();
2025  if (!BEAST_EXPECT(txs.size() == 3))
2026  return;
2027  BEAST_EXPECT(checkTransaction(txs[0u], 4, 4));
2028  BEAST_EXPECT(checkTransaction(txs[1u], 4, 5));
2029  BEAST_EXPECT(checkTransaction(txs[2u], 5, 5));
2030  if (!BEAST_EXPECT(res.has_marker()))
2031  return;
2032 
2033  std::tie(res, status) = next(
2034  grpcPort, env, A3.human(), 3, 9, 3, true, res.mutable_marker());
2035  txs = res.transactions();
2036  if (!BEAST_EXPECT(txs.size() == 3))
2037  return;
2038  BEAST_EXPECT(checkTransaction(txs[0u], 6, 6));
2039  BEAST_EXPECT(checkTransaction(txs[1u], 7, 6));
2040  BEAST_EXPECT(checkTransaction(txs[2u], 8, 7));
2041  if (!BEAST_EXPECT(res.has_marker()))
2042  return;
2043 
2044  std::tie(res, status) = next(
2045  grpcPort, env, A3.human(), 3, 9, 3, true, res.mutable_marker());
2046  txs = res.transactions();
2047  if (!BEAST_EXPECT(txs.size() == 3))
2048  return;
2049  BEAST_EXPECT(checkTransaction(txs[0u], 9, 7));
2050  BEAST_EXPECT(checkTransaction(txs[1u], 10, 8));
2051  BEAST_EXPECT(checkTransaction(txs[2u], 11, 8));
2052  if (!BEAST_EXPECT(res.has_marker()))
2053  return;
2054 
2055  std::tie(res, status) = next(
2056  grpcPort, env, A3.human(), 3, 9, 3, true, res.mutable_marker());
2057  txs = res.transactions();
2058  if (!BEAST_EXPECT(txs.size() == 2))
2059  return;
2060  BEAST_EXPECT(checkTransaction(txs[0u], 12, 9));
2061  BEAST_EXPECT(checkTransaction(txs[1u], 13, 9));
2062  BEAST_EXPECT(!res.has_marker());
2063  }
2064 
2065  {
2066  // limit 2, descending, 2 batches giving last 4 txs
2067  auto [res, status] =
2068  next(grpcPort, env, A3.human(), 3, 9, 2, false);
2069  auto txs = res.transactions();
2070  if (!BEAST_EXPECT(txs.size() == 2))
2071  return;
2072  BEAST_EXPECT(checkTransaction(txs[0u], 13, 9));
2073  BEAST_EXPECT(checkTransaction(txs[1u], 12, 9));
2074  if (!BEAST_EXPECT(res.has_marker()))
2075  return;
2076 
2077  std::tie(res, status) = next(
2078  grpcPort,
2079  env,
2080  A3.human(),
2081  3,
2082  9,
2083  2,
2084  false,
2085  res.mutable_marker());
2086  txs = res.transactions();
2087  if (!BEAST_EXPECT(txs.size() == 2))
2088  return;
2089  BEAST_EXPECT(checkTransaction(txs[0u], 11, 8));
2090  BEAST_EXPECT(checkTransaction(txs[1u], 10, 8));
2091  if (!BEAST_EXPECT(res.has_marker()))
2092  return;
2093 
2094  // continue with limit 3 until all txs have been seen
2095  std::tie(res, status) = next(
2096  grpcPort,
2097  env,
2098  A3.human(),
2099  3,
2100  9,
2101  3,
2102  false,
2103  res.mutable_marker());
2104  txs = res.transactions();
2105  if (!BEAST_EXPECT(txs.size() == 3))
2106  return;
2107  BEAST_EXPECT(checkTransaction(txs[0u], 9, 7));
2108  BEAST_EXPECT(checkTransaction(txs[1u], 8, 7));
2109  BEAST_EXPECT(checkTransaction(txs[2u], 7, 6));
2110  if (!BEAST_EXPECT(res.has_marker()))
2111  return;
2112 
2113  std::tie(res, status) = next(
2114  grpcPort,
2115  env,
2116  A3.human(),
2117  3,
2118  9,
2119  3,
2120  false,
2121  res.mutable_marker());
2122  txs = res.transactions();
2123  if (!BEAST_EXPECT(txs.size() == 3))
2124  return;
2125  BEAST_EXPECT(checkTransaction(txs[0u], 6, 6));
2126  BEAST_EXPECT(checkTransaction(txs[1u], 5, 5));
2127  BEAST_EXPECT(checkTransaction(txs[2u], 4, 5));
2128  if (!BEAST_EXPECT(res.has_marker()))
2129  return;
2130 
2131  std::tie(res, status) = next(
2132  grpcPort,
2133  env,
2134  A3.human(),
2135  3,
2136  9,
2137  3,
2138  false,
2139  res.mutable_marker());
2140  txs = res.transactions();
2141  if (!BEAST_EXPECT(txs.size() == 3))
2142  return;
2143  BEAST_EXPECT(checkTransaction(txs[0u], 4, 4));
2144  BEAST_EXPECT(checkTransaction(txs[1u], 4, 4));
2145  BEAST_EXPECT(checkTransaction(txs[2u], 3, 3));
2146  if (!BEAST_EXPECT(res.has_marker()))
2147  return;
2148 
2149  std::tie(res, status) = next(
2150  grpcPort,
2151  env,
2152  A3.human(),
2153  3,
2154  9,
2155  3,
2156  false,
2157  res.mutable_marker());
2158  txs = res.transactions();
2159  if (!BEAST_EXPECT(txs.size() == 1))
2160  return;
2161  BEAST_EXPECT(checkTransaction(txs[0u], 3, 3));
2162  BEAST_EXPECT(!res.has_marker());
2163  }
2164  }
2165 
2166 public:
2167  void
2168  run() override
2169  {
2174  }
2175 };
2176 
2177 BEAST_DEFINE_TESTSUITE(AccountTxPaging,app,ripple);
2178 
2179 }
2180 
ripple::AccountTxPaging_test
Definition: AccountTxPaging_test.cpp:32
std::string
STL class.
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::AccountTxPaging_test::run
void run() override
Definition: AccountTxPaging_test.cpp:2168
ripple::AccountTxPaging_test::TxCheck::hash
std::string hash
Definition: AccountTxPaging_test.cpp:535
ripple::AccountTxPaging_test::TxCheck::checkTxn
std::function< bool(org::xrpl::rpc::v1::Transaction const &res)> checkTxn
Definition: AccountTxPaging_test.cpp:537
ripple::AccountTxPaging_test::GrpcAccountTxClient::request
org::xrpl::rpc::v1::GetAccountTransactionHistoryRequest request
Definition: AccountTxPaging_test.cpp:269
ripple::AccountTxPaging_test::GrpcAccountTxClient
Definition: AccountTxPaging_test.cpp:266
std::pair
ripple::test::GRPCTestClientBase::stub_
std::unique_ptr< org::xrpl::rpc::v1::XRPLedgerAPIService::Stub > stub_
Definition: GRPCTestClientBase.h:43
ripple::tfClose
const std::uint32_t tfClose
Definition: TxFlags.h:103
ripple::AccountTxPaging_test::checkTransaction
bool checkTransaction(Json::Value const &tx, int sequence, int ledger)
Definition: AccountTxPaging_test.cpp:35
std::vector
STL class.
std::vector::size
T size(T... args)
ripple::keylet::payChan
Keylet payChan(AccountID const &source, AccountID const &dst, std::uint32_t seq)
A PaymentChannel.
Definition: Indexes.cpp:350
std::chrono::duration
ripple::AccountTxPaging_test::TxCheck::sequence
uint32_t sequence
Definition: AccountTxPaging_test.cpp:533
std::reverse
T reverse(T... args)
std::function
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::sfPayChannel
const SF_U256 sfPayChannel(access, STI_HASH256, 22, "Channel")
Definition: SField.h:418
ripple::AccountTxPaging_test::GrpcAccountTxClient::AccountTx
void AccountTx()
Definition: AccountTxPaging_test.cpp:278
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:140
ripple::AccountTxPaging_test::nextWithHash
std::pair< org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse, grpc::Status > nextWithHash(std::string grpcPort, test::jtx::Env &env, std::string const &account="", uint256 const &hash=beast::zero, int limit=-1, bool forward=false, org::xrpl::rpc::v1::Marker *marker=nullptr)
Definition: AccountTxPaging_test.cpp:396
ripple::test::GRPCTestClientBase::status
grpc::Status status
Definition: GRPCTestClientBase.h:41
ripple::sfFinishAfter
const SF_U32 sfFinishAfter(access, STI_UINT32, 37, "FinishAfter")
Definition: SField.h:374
ripple::test::GRPCTestClientBase
Definition: GRPCTestClientBase.h:29
ripple::test::GRPCTestClientBase::GRPCTestClientBase
GRPCTestClientBase(std::string const &port)
Definition: GRPCTestClientBase.h:31
std::tie
T tie(T... args)
ripple::base_uint< 256 >
ripple::AccountTxPaging_test::testAccountTxPagingGrpc
void testAccountTxPagingGrpc()
Definition: AccountTxPaging_test.cpp:1909
ripple::getCheckIndex
uint256 getCheckIndex(AccountID const &account, std::uint32_t uSequence)
Definition: Indexes.cpp:186
std::extent
ripple::sfOwner
const SF_Account sfOwner(access, STI_ACCOUNT, 2, "Owner")
Definition: SField.h:461
ripple::AccountTxPaging_test::next
std::pair< org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse, grpc::Status > next(std::string grpcPort, test::jtx::Env &env, std::string const &account="", int ledger_min=-1, int ledger_max=-1, int limit=-1, bool forward=false, org::xrpl::rpc::v1::Marker *marker=nullptr)
Definition: AccountTxPaging_test.cpp:333
ripple::JsonOptions::none
@ none
ripple::AccountTxPaging_test::testAccountTxPaging
void testAccountTxPaging()
Definition: AccountTxPaging_test.cpp:64
ripple::AccountTxPaging_test::checkTransaction
bool checkTransaction(org::xrpl::rpc::v1::GetTransactionResponse const &tx, int sequence, int ledger)
Definition: AccountTxPaging_test.cpp:286
ripple::STAmount
Definition: STAmount.h:42
std::chrono::time_point
std::uint32_t
ripple::AccountTxPaging_test::TxCheck
Definition: AccountTxPaging_test.cpp:531
ripple::test::GRPCTestClientBase::context
grpc::ClientContext context
Definition: GRPCTestClientBase.h:42
ripple::tfUniversal
const std::uint32_t tfUniversal
Definition: TxFlags.h:49
ripple::Serializer
Definition: Serializer.h:43
ripple::AccountTxPaging_test::TxCheck::ledgerIndex
uint32_t ledgerIndex
Definition: AccountTxPaging_test.cpp:534
ripple::sfPublicKey
const SF_Blob sfPublicKey(access, STI_VL, 1, "PublicKey")
Definition: SField.h:440
ripple::AccountTxPaging_test::testAccountTxParametersGrpc
void testAccountTxParametersGrpc()
Definition: AccountTxPaging_test.cpp:425
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
cstdlib
ripple::AccountTxPaging_test::next
auto next(test::jtx::Env &env, test::jtx::Account const &account, int ledger_min, int ledger_max, int limit, bool forward, Json::Value const &marker=Json::nullValue)
Definition: AccountTxPaging_test.cpp:42
ripple::sfOfferSequence
const SF_U32 sfOfferSequence(access, STI_UINT32, 25, "OfferSequence")
Definition: SField.h:362
std::vector::begin
T begin(T... args)
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:38
std::chrono::duration::count
T count(T... args)
ripple::sfSettleDelay
const SF_U32 sfSettleDelay(access, STI_UINT32, 39, "SettleDelay")
Definition: SField.h:376
ripple::AccountTxPaging_test::GrpcAccountTxClient::reply
org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse reply
Definition: AccountTxPaging_test.cpp:270
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:70
std::vector::end
T end(T... args)
ripple::AccountTxPaging_test::nextBinary
std::pair< org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse, grpc::Status > nextBinary(std::string grpcPort, test::jtx::Env &env, std::string const &account="", int ledger_min=-1, int ledger_max=-1, int limit=-1, bool forward=false, org::xrpl::rpc::v1::Marker *marker=nullptr)
Definition: AccountTxPaging_test.cpp:299
ripple::AccountTxPaging_test::GrpcAccountTxClient::GrpcAccountTxClient
GrpcAccountTxClient(std::string const &port)
Definition: AccountTxPaging_test.cpp:272
std::unique_ptr
STL class.
ripple::AccountTxPaging_test::nextWithSeq
std::pair< org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse, grpc::Status > nextWithSeq(std::string grpcPort, test::jtx::Env &env, std::string const &account="", int ledger_seq=-1, int limit=-1, bool forward=false, org::xrpl::rpc::v1::Marker *marker=nullptr)
Definition: AccountTxPaging_test.cpp:366
ripple::sfCancelAfter
const SF_U32 sfCancelAfter(access, STI_UINT32, 36, "CancelAfter")
Definition: SField.h:373
ripple::AccountTxPaging_test::testAccountTxContentsGrpc
void testAccountTxContentsGrpc()
Definition: AccountTxPaging_test.cpp:541
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:117
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
Json::Value
Represents a JSON value.
Definition: json_value.h:141