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 <ripple/beast/unit_test.h>
20 #include <ripple/protocol/SField.h>
21 #include <ripple/protocol/jss.h>
22 #include <cstdlib>
23 #include <test/jtx.h>
24 
25 #include <ripple/rpc/GRPCHandlers.h>
26 #include <ripple/rpc/impl/RPCHelpers.h>
27 #include <test/rpc/GRPCTestClientBase.h>
28 
29 namespace ripple {
30 
31 class AccountTxPaging_test : public beast::unit_test::suite
32 {
33  bool
34  checkTransaction(Json::Value const& tx, int sequence, int ledger)
35  {
36  return (
37  tx[jss::tx][jss::Sequence].asInt() == sequence &&
38  tx[jss::tx][jss::ledger_index].asInt() == ledger);
39  }
40 
41  auto
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[sfChannel.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[sfChannel.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  auto const aliceCheckId = keylet::check(alice, env.seq(alice)).key;
714  env(check::create(alice, gw, XRP(300)), sig(alie));
715 
716  auto txn = env.tx();
717  auto const gwCheckId = keylet::check(gw, env.seq(gw)).key;
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(res.transactions().size() == std::size(txCheck)))
1875  return;
1876  for (int i = 0; i < res.transactions().size(); ++i)
1877  {
1878  BEAST_EXPECT(doCheck(res.transactions()[i], txCheck[i]));
1879  BEAST_EXPECT(doMetaCheck(res.transactions()[i], txMetaCheck[i]));
1880  }
1881 
1882  // test binary representation
1883  std::tie(res, status) = nextBinary(grpcPort, env, alice.human());
1884 
1885  // txns vector does not contain the first two transactions returned by
1886  // account_tx
1887  if (!BEAST_EXPECT(res.transactions().size() == txns.size() + 2))
1888  return;
1889 
1890  std::reverse(txns.begin(), txns.end());
1891  for (int i = 0; i < txns.size(); ++i)
1892  {
1893  auto toByteString = [](auto data) {
1894  const char* bytes = reinterpret_cast<const char*>(data.data());
1895  return std::string(bytes, data.size());
1896  };
1897 
1898  auto tx = txns[i];
1899  Serializer s = tx->getSerializer();
1900  std::string bin = toByteString(s);
1901 
1902  BEAST_EXPECT(res.transactions(i).transaction_binary() == bin);
1903  }
1904  }
1905 
1906  void
1908  {
1909  testcase("Test Account_tx Grpc");
1910 
1911  using namespace test::jtx;
1912  std::unique_ptr<Config> config = envconfig(addGrpcConfig);
1913  std::string grpcPort = *(*config)["port_grpc"].get<std::string>("port");
1914  Env env(*this, std::move(config));
1915 
1916  Account A1{"A1"};
1917  Account A2{"A2"};
1918  Account A3{"A3"};
1919 
1920  env.fund(XRP(10000), A1, A2, A3);
1921  env.close();
1922 
1923  env.trust(A3["USD"](1000), A1);
1924  env.trust(A2["USD"](1000), A1);
1925  env.trust(A3["USD"](1000), A2);
1926  env.close();
1927 
1928  for (auto i = 0; i < 5; ++i)
1929  {
1930  env(pay(A2, A1, A2["USD"](2)));
1931  env(pay(A3, A1, A3["USD"](2)));
1932  env(offer(A1, XRP(11), A1["USD"](1)));
1933  env(offer(A2, XRP(10), A2["USD"](1)));
1934  env(offer(A3, XRP(9), A3["USD"](1)));
1935  env.close();
1936  }
1937 
1938  /* The sequence/ledger for A3 are as follows:
1939  * seq ledger_index
1940  * 3 ----> 3
1941  * 1 ----> 3
1942  * 2 ----> 4
1943  * 2 ----> 4
1944  * 2 ----> 5
1945  * 3 ----> 5
1946  * 4 ----> 6
1947  * 5 ----> 6
1948  * 6 ----> 7
1949  * 7 ----> 7
1950  * 8 ----> 8
1951  * 9 ----> 8
1952  * 10 ----> 9
1953  * 11 ----> 9
1954  */
1955 
1956  // page through the results in several ways.
1957  {
1958  // limit = 2, 3 batches giving the first 6 txs
1959  auto [res, status] = next(grpcPort, env, A3.human(), 2, 5, 2, true);
1960 
1961  auto txs = res.transactions();
1962  if (!BEAST_EXPECT(txs.size() == 2))
1963  return;
1964 
1965  BEAST_EXPECT(checkTransaction(txs[0u], 3, 3));
1966  BEAST_EXPECT(checkTransaction(txs[1u], 3, 3));
1967  if (!BEAST_EXPECT(res.has_marker()))
1968  return;
1969 
1970  std::tie(res, status) = next(
1971  grpcPort, env, A3.human(), 2, 5, 2, true, res.mutable_marker());
1972  txs = res.transactions();
1973  if (!BEAST_EXPECT(txs.size() == 2))
1974  return;
1975  BEAST_EXPECT(checkTransaction(txs[0u], 4, 4));
1976  BEAST_EXPECT(checkTransaction(txs[1u], 4, 4));
1977  if (!BEAST_EXPECT(res.has_marker()))
1978  return;
1979 
1980  std::tie(res, status) = next(
1981  grpcPort, env, A3.human(), 2, 5, 2, true, res.mutable_marker());
1982  txs = res.transactions();
1983  if (!BEAST_EXPECT(txs.size() == 2))
1984  return;
1985  BEAST_EXPECT(checkTransaction(txs[0u], 4, 5));
1986  BEAST_EXPECT(checkTransaction(txs[1u], 5, 5));
1987  BEAST_EXPECT(!res.has_marker());
1988  return;
1989  }
1990 
1991  {
1992  // limit 1, 3 requests giving the first 3 txs
1993  auto [res, status] = next(grpcPort, env, A3.human(), 3, 9, 1, true);
1994  auto txs = res.transactions();
1995  if (!BEAST_EXPECT(txs.size() == 1))
1996  return;
1997  BEAST_EXPECT(checkTransaction(txs[0u], 3, 3));
1998  if (!BEAST_EXPECT(res.has_marker()))
1999  return;
2000 
2001  std::tie(res, status) = next(
2002  grpcPort, env, A3.human(), 3, 9, 1, true, res.mutable_marker());
2003  txs = res.transactions();
2004  if (!BEAST_EXPECT(txs.size() == 1))
2005  return;
2006  BEAST_EXPECT(checkTransaction(txs[0u], 3, 3));
2007  if (!BEAST_EXPECT(res.has_marker()))
2008  return;
2009 
2010  std::tie(res, status) = next(
2011  grpcPort, env, A3.human(), 3, 9, 1, true, res.mutable_marker());
2012  txs = res.transactions();
2013  if (!BEAST_EXPECT(txs.size() == 1))
2014  return;
2015  BEAST_EXPECT(checkTransaction(txs[0u], 4, 4));
2016  if (!BEAST_EXPECT(res.has_marker()))
2017  return;
2018 
2019  // continue with limit 3, to end of all txs
2020  std::tie(res, status) = next(
2021  grpcPort, env, A3.human(), 3, 9, 3, true, res.mutable_marker());
2022  txs = res.transactions();
2023  if (!BEAST_EXPECT(txs.size() == 3))
2024  return;
2025  BEAST_EXPECT(checkTransaction(txs[0u], 4, 4));
2026  BEAST_EXPECT(checkTransaction(txs[1u], 4, 5));
2027  BEAST_EXPECT(checkTransaction(txs[2u], 5, 5));
2028  if (!BEAST_EXPECT(res.has_marker()))
2029  return;
2030 
2031  std::tie(res, status) = next(
2032  grpcPort, env, A3.human(), 3, 9, 3, true, res.mutable_marker());
2033  txs = res.transactions();
2034  if (!BEAST_EXPECT(txs.size() == 3))
2035  return;
2036  BEAST_EXPECT(checkTransaction(txs[0u], 6, 6));
2037  BEAST_EXPECT(checkTransaction(txs[1u], 7, 6));
2038  BEAST_EXPECT(checkTransaction(txs[2u], 8, 7));
2039  if (!BEAST_EXPECT(res.has_marker()))
2040  return;
2041 
2042  std::tie(res, status) = next(
2043  grpcPort, env, A3.human(), 3, 9, 3, true, res.mutable_marker());
2044  txs = res.transactions();
2045  if (!BEAST_EXPECT(txs.size() == 3))
2046  return;
2047  BEAST_EXPECT(checkTransaction(txs[0u], 9, 7));
2048  BEAST_EXPECT(checkTransaction(txs[1u], 10, 8));
2049  BEAST_EXPECT(checkTransaction(txs[2u], 11, 8));
2050  if (!BEAST_EXPECT(res.has_marker()))
2051  return;
2052 
2053  std::tie(res, status) = next(
2054  grpcPort, env, A3.human(), 3, 9, 3, true, res.mutable_marker());
2055  txs = res.transactions();
2056  if (!BEAST_EXPECT(txs.size() == 2))
2057  return;
2058  BEAST_EXPECT(checkTransaction(txs[0u], 12, 9));
2059  BEAST_EXPECT(checkTransaction(txs[1u], 13, 9));
2060  BEAST_EXPECT(!res.has_marker());
2061  }
2062 
2063  {
2064  // limit 2, descending, 2 batches giving last 4 txs
2065  auto [res, status] =
2066  next(grpcPort, env, A3.human(), 3, 9, 2, false);
2067  auto txs = res.transactions();
2068  if (!BEAST_EXPECT(txs.size() == 2))
2069  return;
2070  BEAST_EXPECT(checkTransaction(txs[0u], 13, 9));
2071  BEAST_EXPECT(checkTransaction(txs[1u], 12, 9));
2072  if (!BEAST_EXPECT(res.has_marker()))
2073  return;
2074 
2075  std::tie(res, status) = next(
2076  grpcPort,
2077  env,
2078  A3.human(),
2079  3,
2080  9,
2081  2,
2082  false,
2083  res.mutable_marker());
2084  txs = res.transactions();
2085  if (!BEAST_EXPECT(txs.size() == 2))
2086  return;
2087  BEAST_EXPECT(checkTransaction(txs[0u], 11, 8));
2088  BEAST_EXPECT(checkTransaction(txs[1u], 10, 8));
2089  if (!BEAST_EXPECT(res.has_marker()))
2090  return;
2091 
2092  // continue with limit 3 until all txs have been seen
2093  std::tie(res, status) = next(
2094  grpcPort,
2095  env,
2096  A3.human(),
2097  3,
2098  9,
2099  3,
2100  false,
2101  res.mutable_marker());
2102  txs = res.transactions();
2103  if (!BEAST_EXPECT(txs.size() == 3))
2104  return;
2105  BEAST_EXPECT(checkTransaction(txs[0u], 9, 7));
2106  BEAST_EXPECT(checkTransaction(txs[1u], 8, 7));
2107  BEAST_EXPECT(checkTransaction(txs[2u], 7, 6));
2108  if (!BEAST_EXPECT(res.has_marker()))
2109  return;
2110 
2111  std::tie(res, status) = next(
2112  grpcPort,
2113  env,
2114  A3.human(),
2115  3,
2116  9,
2117  3,
2118  false,
2119  res.mutable_marker());
2120  txs = res.transactions();
2121  if (!BEAST_EXPECT(txs.size() == 3))
2122  return;
2123  BEAST_EXPECT(checkTransaction(txs[0u], 6, 6));
2124  BEAST_EXPECT(checkTransaction(txs[1u], 5, 5));
2125  BEAST_EXPECT(checkTransaction(txs[2u], 4, 5));
2126  if (!BEAST_EXPECT(res.has_marker()))
2127  return;
2128 
2129  std::tie(res, status) = next(
2130  grpcPort,
2131  env,
2132  A3.human(),
2133  3,
2134  9,
2135  3,
2136  false,
2137  res.mutable_marker());
2138  txs = res.transactions();
2139  if (!BEAST_EXPECT(txs.size() == 3))
2140  return;
2141  BEAST_EXPECT(checkTransaction(txs[0u], 4, 4));
2142  BEAST_EXPECT(checkTransaction(txs[1u], 4, 4));
2143  BEAST_EXPECT(checkTransaction(txs[2u], 3, 3));
2144  if (!BEAST_EXPECT(res.has_marker()))
2145  return;
2146 
2147  std::tie(res, status) = next(
2148  grpcPort,
2149  env,
2150  A3.human(),
2151  3,
2152  9,
2153  3,
2154  false,
2155  res.mutable_marker());
2156  txs = res.transactions();
2157  if (!BEAST_EXPECT(txs.size() == 1))
2158  return;
2159  BEAST_EXPECT(checkTransaction(txs[0u], 3, 3));
2160  BEAST_EXPECT(!res.has_marker());
2161  }
2162  }
2163 
2164 public:
2165  void
2166  run() override
2167  {
2172  }
2173 };
2174 
2175 BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple);
2176 
2177 } // namespace ripple
ripple::AccountTxPaging_test
Definition: AccountTxPaging_test.cpp:31
ripple::sfOfferSequence
const SF_UINT32 sfOfferSequence
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:2166
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::sfOwner
const SF_ACCOUNT sfOwner
ripple::test::GRPCTestClientBase::stub_
std::unique_ptr< org::xrpl::rpc::v1::XRPLedgerAPIService::Stub > stub_
Definition: GRPCTestClientBase.h:44
ripple::tfClose
const std::uint32_t tfClose
Definition: TxFlags.h:106
ripple::AccountTxPaging_test::checkTransaction
bool checkTransaction(Json::Value const &tx, int sequence, int ledger)
Definition: AccountTxPaging_test.cpp:34
std::vector
STL class.
std::vector::size
T size(T... args)
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:42
ripple::AccountTxPaging_test::GrpcAccountTxClient::AccountTx
void AccountTx()
Definition: AccountTxPaging_test.cpp:278
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:133
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:42
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::Keylet::key
uint256 key
Definition: Keylet.h:41
ripple::base_uint< 256 >
ripple::AccountTxPaging_test::testAccountTxPagingGrpc
void testAccountTxPagingGrpc()
Definition: AccountTxPaging_test.cpp:1907
ripple::sfSettleDelay
const SF_UINT32 sfSettleDelay
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:43
ripple::tfUniversal
const std::uint32_t tfUniversal
Definition: TxFlags.h:49
ripple::sfChannel
const SF_HASH256 sfChannel
ripple::Serializer
Definition: Serializer.h:39
ripple::AccountTxPaging_test::TxCheck::ledgerIndex
uint32_t ledgerIndex
Definition: AccountTxPaging_test.cpp:534
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::keylet::payChan
Keylet payChan(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Definition: Indexes.cpp:325
std::vector::begin
T begin(T... args)
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
std::chrono::duration::count
T count(T... args)
ripple::AccountTxPaging_test::GrpcAccountTxClient::reply
org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse reply
Definition: AccountTxPaging_test.cpp:270
ripple::sfCancelAfter
const SF_UINT32 sfCancelAfter
ripple::sfFinishAfter
const SF_UINT32 sfFinishAfter
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:45
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::keylet::check
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition: Indexes.cpp:282
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::sfPublicKey
const SF_VL sfPublicKey
ripple::AccountTxPaging_test::testAccountTxContentsGrpc
void testAccountTxContentsGrpc()
Definition: AccountTxPaging_test.cpp:541
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:115
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:684
Json::Value
Represents a JSON value.
Definition: json_value.h:145