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  env(offer_cancel(alice, offerSeq), sig(alie));
588  env.close();
589 
590  txns.emplace_back(env.tx());
591 
592  // SignerListSet
593  env(signers(alice, 1, {{"bogie", 1}, {"demon", 1}, {gw, 1}}),
594  sig(alie));
595 
596  txns.emplace_back(env.tx());
597  // Escrow
598  {
599  // Create an escrow. Requires either a CancelAfter or FinishAfter.
600  auto escrow = [](Account const& account,
601  Account const& to,
602  STAmount const& amount) {
603  Json::Value escro;
604  escro[jss::TransactionType] = jss::EscrowCreate;
605  escro[jss::Flags] = tfUniversal;
606  escro[jss::Account] = account.human();
607  escro[jss::Destination] = to.human();
608  escro[jss::Amount] = amount.getJson(JsonOptions::none);
609  return escro;
610  };
611 
612  NetClock::time_point const nextTime{env.now() + 2s};
613 
614  Json::Value escrowWithFinish{escrow(alice, alice, XRP(500))};
615  escrowWithFinish[sfFinishAfter.jsonName] =
616  nextTime.time_since_epoch().count();
617 
618  std::uint32_t const escrowFinishSeq{env.seq(alice)};
619  env(escrowWithFinish, sig(alie));
620 
621  txns.emplace_back(env.tx());
622  Json::Value escrowWithCancel{escrow(alice, alice, XRP(500))};
623  escrowWithCancel[sfFinishAfter.jsonName] =
624  nextTime.time_since_epoch().count();
625  escrowWithCancel[sfCancelAfter.jsonName] =
626  nextTime.time_since_epoch().count() + 1;
627 
628  std::uint32_t const escrowCancelSeq{env.seq(alice)};
629  env(escrowWithCancel, sig(alie));
630  env.close();
631 
632  txns.emplace_back(env.tx());
633  {
634  Json::Value escrowFinish;
635  escrowFinish[jss::TransactionType] = jss::EscrowFinish;
636  escrowFinish[jss::Flags] = tfUniversal;
637  escrowFinish[jss::Account] = alice.human();
638  escrowFinish[sfOwner.jsonName] = alice.human();
639  escrowFinish[sfOfferSequence.jsonName] = escrowFinishSeq;
640  env(escrowFinish, sig(alie));
641 
642  txns.emplace_back(env.tx());
643  }
644  {
645  Json::Value escrowCancel;
646  escrowCancel[jss::TransactionType] = jss::EscrowCancel;
647  escrowCancel[jss::Flags] = tfUniversal;
648  escrowCancel[jss::Account] = alice.human();
649  escrowCancel[sfOwner.jsonName] = alice.human();
650  escrowCancel[sfOfferSequence.jsonName] = escrowCancelSeq;
651  env(escrowCancel, sig(alie));
652 
653  txns.emplace_back(env.tx());
654  }
655  env.close();
656  }
657 
658  // PayChan
659  {
660  std::uint32_t payChanSeq{env.seq(alice)};
661  Json::Value payChanCreate;
662  payChanCreate[jss::TransactionType] = jss::PaymentChannelCreate;
663  payChanCreate[jss::Flags] = tfUniversal;
664  payChanCreate[jss::Account] = alice.human();
665  payChanCreate[jss::Destination] = gw.human();
666  payChanCreate[jss::Amount] =
667  XRP(500).value().getJson(JsonOptions::none);
668  payChanCreate[sfSettleDelay.jsonName] =
669  NetClock::duration{100s}.count();
670  payChanCreate[sfPublicKey.jsonName] = strHex(alice.pk().slice());
671  env(payChanCreate, sig(alie));
672  env.close();
673 
674  txns.emplace_back(env.tx());
675  std::string const payChanIndex{
676  strHex(keylet::payChan(alice, gw, payChanSeq).key)};
677 
678  {
679  Json::Value payChanFund;
680  payChanFund[jss::TransactionType] = jss::PaymentChannelFund;
681  payChanFund[jss::Flags] = tfUniversal;
682  payChanFund[jss::Account] = alice.human();
683  payChanFund[sfChannel.jsonName] = payChanIndex;
684  payChanFund[jss::Amount] =
685  XRP(200).value().getJson(JsonOptions::none);
686  env(payChanFund, sig(alie));
687  env.close();
688 
689  txns.emplace_back(env.tx());
690  }
691  {
692  Json::Value payChanClaim;
693  payChanClaim[jss::TransactionType] = jss::PaymentChannelClaim;
694  payChanClaim[jss::Flags] = tfClose;
695  payChanClaim[jss::Account] = gw.human();
696  payChanClaim[sfChannel.jsonName] = payChanIndex;
697  payChanClaim[sfPublicKey.jsonName] = strHex(alice.pk().slice());
698  env(payChanClaim);
699  env.close();
700 
701  txns.emplace_back(env.tx());
702  }
703  }
704 
705  // Check
706  {
707  auto const aliceCheckId = keylet::check(alice, env.seq(alice)).key;
708  env(check::create(alice, gw, XRP(300)), sig(alie));
709 
710  auto txn = env.tx();
711  auto const gwCheckId = keylet::check(gw, env.seq(gw)).key;
712  env(check::create(gw, alice, XRP(200)));
713  env.close();
714 
715  // need to switch the order of the previous 2 txns, since they are
716  // in the same ledger and account_tx returns them in a different
717  // order
718  txns.emplace_back(env.tx());
719  txns.emplace_back(txn);
720  env(check::cash(alice, gwCheckId, XRP(200)), sig(alie));
721 
722  txns.emplace_back(env.tx());
723  env(check::cancel(alice, aliceCheckId), sig(alie));
724 
725  txns.emplace_back(env.tx());
726  env.close();
727  }
728 
729  // Deposit preauthorization.
730  env(deposit::auth(alice, gw), sig(alie));
731  env.close();
732 
733  txns.emplace_back(env.tx());
734  // Multi Sig with memo
735  auto const baseFee = env.current()->fees().base;
736  env(noop(alice),
737  msig(gw),
738  fee(2 * baseFee),
739  memo("data", "format", "type"));
740  env.close();
741 
742  txns.emplace_back(env.tx());
743  if (!BEAST_EXPECT(txns.size() == 20))
744  return;
745  // Setup is done. Look at the transactions returned by account_tx.
746 
747  static const TxCheck txCheck[]{
748  {21,
749  15,
750  strHex(txns[txns.size() - 1]->getTransactionID()),
751  [this, &txns](auto res) {
752  auto txnJson =
753  txns[txns.size() - 1]->getJson(JsonOptions::none);
754  return BEAST_EXPECT(res.has_account_set()) &&
755  BEAST_EXPECT(res.has_fee()) &&
756  BEAST_EXPECT(res.fee().drops() == 20) &&
757  BEAST_EXPECT(res.memos_size() == 1) &&
758  BEAST_EXPECT(res.memos(0).has_memo_data()) &&
759  BEAST_EXPECT(res.memos(0).memo_data().value() == "data") &&
760  BEAST_EXPECT(res.memos(0).has_memo_format()) &&
761  BEAST_EXPECT(
762  res.memos(0).memo_format().value() == "format") &&
763  BEAST_EXPECT(res.memos(0).has_memo_type()) &&
764  BEAST_EXPECT(res.memos(0).memo_type().value() == "type") &&
765  BEAST_EXPECT(res.has_signing_public_key()) &&
766  BEAST_EXPECT(res.signing_public_key().value() == "") &&
767  BEAST_EXPECT(res.signers_size() == 1) &&
768  BEAST_EXPECT(res.signers(0).has_account()) &&
769  BEAST_EXPECT(
770  res.signers(0).account().value().address() ==
771  txnJson["Signers"][0u]["Signer"]["Account"]) &&
772  BEAST_EXPECT(res.signers(0).has_transaction_signature()) &&
773  BEAST_EXPECT(
774  strHex(res.signers(0)
775  .transaction_signature()
776  .value()) ==
777  txnJson["Signers"][0u]["Signer"]["TxnSignature"]) &&
778  BEAST_EXPECT(res.signers(0).has_signing_public_key()) &&
779  BEAST_EXPECT(
780  strHex(
781  res.signers(0).signing_public_key().value()) ==
782  txnJson["Signers"][0u]["Signer"]["SigningPubKey"]);
783  }},
784  {20,
785  14,
786  strHex(txns[txns.size() - 2]->getTransactionID()),
787  [&txns, this](auto res) {
788  return BEAST_EXPECT(res.has_deposit_preauth()) &&
789  BEAST_EXPECT(
790  res.deposit_preauth()
791  .authorize()
792  .value()
793  .address() ==
794  // TODO do them all like this
795  txns[txns.size() - 2]->getJson(
796  JsonOptions::none)["Authorize"]);
797  }},
798  {19,
799  13,
800  strHex(txns[txns.size() - 3]->getTransactionID()),
801  [&txns, this](auto res) {
802  return BEAST_EXPECT(res.has_check_cancel()) &&
803  BEAST_EXPECT(
804  strHex(res.check_cancel().check_id().value()) ==
805 
806  txns[txns.size() - 3]->getJson(
807  JsonOptions::none)["CheckID"]);
808  }},
809  {18,
810  13,
811  strHex(txns[txns.size() - 4]->getTransactionID()),
812  [&txns, this](auto res) {
813  auto txnJson =
814  txns[txns.size() - 4]->getJson(JsonOptions::none);
815  return BEAST_EXPECT(res.has_check_cash()) &&
816  BEAST_EXPECT(
817  strHex(res.check_cash().check_id().value()) ==
818  txnJson["CheckID"]) &&
819  BEAST_EXPECT(res.check_cash()
820  .amount()
821  .value()
822  .has_xrp_amount()) &&
823  BEAST_EXPECT(
824  res.check_cash()
825  .amount()
826  .value()
827  .xrp_amount()
828  .drops() == txnJson["Amount"].asUInt());
829  }},
830  {17,
831  12,
832  strHex(txns[txns.size() - 5]->getTransactionID()),
833  [&txns, this](auto res) {
834  auto txnJson =
835  txns[txns.size() - 5]->getJson(JsonOptions::none);
836  return BEAST_EXPECT(res.has_check_create()) &&
837  BEAST_EXPECT(
838  res.check_create()
839  .destination()
840  .value()
841  .address() == txnJson["Destination"]) &&
842  BEAST_EXPECT(res.check_create()
843  .send_max()
844  .value()
845  .has_xrp_amount()) &&
846  BEAST_EXPECT(
847  res.check_create()
848  .send_max()
849  .value()
850  .xrp_amount()
851  .drops() == txnJson["SendMax"].asUInt());
852  }},
853  {5,
854  12,
855  strHex(txns[txns.size() - 6]->getTransactionID()),
856  [&txns, this](auto res) {
857  auto txnJson =
858  txns[txns.size() - 6]->getJson(JsonOptions::none);
859  return BEAST_EXPECT(res.has_check_create()) &&
860  BEAST_EXPECT(
861  res.check_create()
862  .destination()
863  .value()
864  .address() == txnJson["Destination"]) &&
865  BEAST_EXPECT(res.check_create()
866  .send_max()
867  .value()
868  .has_xrp_amount()) &&
869  BEAST_EXPECT(
870  res.check_create()
871  .send_max()
872  .value()
873  .xrp_amount()
874  .drops() ==
875 
876  txnJson["SendMax"].asUInt());
877  }},
878  {4,
879  11,
880  strHex(txns[txns.size() - 7]->getTransactionID()),
881  [&txns, this](auto res) {
882  auto txnJson =
883  txns[txns.size() - 7]->getJson(JsonOptions::none);
884  return BEAST_EXPECT(res.has_payment_channel_claim()) &&
885  BEAST_EXPECT(
886  strHex(res.payment_channel_claim()
887  .channel()
888  .value()) == txnJson["Channel"]) &&
889  BEAST_EXPECT(
890  strHex(res.payment_channel_claim()
891  .public_key()
892  .value()) == txnJson["PublicKey"]);
893  }},
894  {16,
895  10,
896  strHex(txns[txns.size() - 8]->getTransactionID()),
897  [&txns, this](auto res) {
898  auto txnJson =
899  txns[txns.size() - 8]->getJson(JsonOptions::none);
900  return BEAST_EXPECT(res.has_payment_channel_fund()) &&
901  BEAST_EXPECT(
902  strHex(
903  res.payment_channel_fund().channel().value()) ==
904  txnJson["Channel"]) &&
905  BEAST_EXPECT(res.payment_channel_fund()
906  .amount()
907  .value()
908  .has_xrp_amount()) &&
909  BEAST_EXPECT(
910  res.payment_channel_fund()
911  .amount()
912  .value()
913  .xrp_amount()
914  .drops() == txnJson["Amount"].asUInt());
915  }},
916  {15,
917  9,
918  strHex(txns[txns.size() - 9]->getTransactionID()),
919  [&txns, this](auto res) {
920  auto txnJson =
921  txns[txns.size() - 9]->getJson(JsonOptions::none);
922  return BEAST_EXPECT(res.has_payment_channel_create()) &&
923  BEAST_EXPECT(res.payment_channel_create()
924  .amount()
925  .value()
926  .has_xrp_amount()) &&
927  BEAST_EXPECT(
928  res.payment_channel_create()
929  .amount()
930  .value()
931  .xrp_amount()
932  .drops() == txnJson["Amount"].asUInt()) &&
933  BEAST_EXPECT(
934  res.payment_channel_create()
935  .destination()
936  .value()
937  .address() == txnJson["Destination"]) &&
938  BEAST_EXPECT(
939  res.payment_channel_create()
940  .settle_delay()
941  .value() == txnJson["SettleDelay"].asUInt()) &&
942  BEAST_EXPECT(
943  strHex(res.payment_channel_create()
944  .public_key()
945  .value()) == txnJson["PublicKey"]);
946  }},
947  {14,
948  8,
949  strHex(txns[txns.size() - 10]->getTransactionID()),
950  [&txns, this](auto res) {
951  auto txnJson =
952  txns[txns.size() - 10]->getJson(JsonOptions::none);
953  return BEAST_EXPECT(res.has_escrow_cancel()) &&
954  BEAST_EXPECT(
955  res.escrow_cancel().owner().value().address() ==
956  txnJson["Owner"]) &&
957  BEAST_EXPECT(
958  res.escrow_cancel().offer_sequence().value() ==
959  txnJson["OfferSequence"].asUInt()
960 
961  );
962  }},
963  {13,
964  8,
965  strHex(txns[txns.size() - 11]->getTransactionID()),
966  [&txns, this](auto res) {
967  auto txnJson =
968  txns[txns.size() - 11]->getJson(JsonOptions::none);
969  return BEAST_EXPECT(res.has_escrow_finish()) &&
970  BEAST_EXPECT(
971  res.escrow_finish().owner().value().address() ==
972  txnJson["Owner"]) &&
973  BEAST_EXPECT(
974  res.escrow_finish().offer_sequence().value() ==
975  txnJson["OfferSequence"].asUInt()
976 
977  );
978  }},
979  {12,
980  7,
981  strHex(txns[txns.size() - 12]->getTransactionID()),
982  [&txns, this](auto res) {
983  auto txnJson =
984  txns[txns.size() - 12]->getJson(JsonOptions::none);
985  return BEAST_EXPECT(res.has_escrow_create()) &&
986  BEAST_EXPECT(res.escrow_create()
987  .amount()
988  .value()
989  .has_xrp_amount()) &&
990  BEAST_EXPECT(
991  res.escrow_create()
992  .amount()
993  .value()
994  .xrp_amount()
995  .drops() == txnJson["Amount"].asUInt()) &&
996  BEAST_EXPECT(
997  res.escrow_create()
998  .destination()
999  .value()
1000  .address() == txnJson["Destination"]) &&
1001  BEAST_EXPECT(
1002  res.escrow_create().cancel_after().value() ==
1003  txnJson["CancelAfter"].asUInt()) &&
1004  BEAST_EXPECT(
1005  res.escrow_create().finish_after().value() ==
1006  txnJson["FinishAfter"].asUInt());
1007  }},
1008  {11,
1009  7,
1010  strHex(txns[txns.size() - 13]->getTransactionID()),
1011  [&txns, this](auto res) {
1012  auto txnJson =
1013  txns[txns.size() - 13]->getJson(JsonOptions::none);
1014  return BEAST_EXPECT(res.has_escrow_create()) &&
1015  BEAST_EXPECT(res.escrow_create()
1016  .amount()
1017  .value()
1018  .has_xrp_amount()) &&
1019  BEAST_EXPECT(
1020  res.escrow_create()
1021  .amount()
1022  .value()
1023  .xrp_amount()
1024  .drops() == txnJson["Amount"].asUInt()) &&
1025  BEAST_EXPECT(
1026  res.escrow_create()
1027  .destination()
1028  .value()
1029  .address() == txnJson["Destination"]) &&
1030  BEAST_EXPECT(
1031  res.escrow_create().finish_after().value() ==
1032  txnJson["FinishAfter"].asUInt());
1033  }},
1034  {10,
1035  7,
1036  strHex(txns[txns.size() - 14]->getTransactionID()),
1037  [&txns, this](auto res) {
1038  auto txnJson =
1039  txns[txns.size() - 14]->getJson(JsonOptions::none);
1040  return BEAST_EXPECT(res.has_signer_list_set()) &&
1041  BEAST_EXPECT(
1042  res.signer_list_set().signer_quorum().value() ==
1043  txnJson["SignerQuorum"].asUInt()) &&
1044  BEAST_EXPECT(
1045  res.signer_list_set().signer_entries().size() ==
1046  3) &&
1047  BEAST_EXPECT(
1048  res.signer_list_set()
1049  .signer_entries()[0]
1050  .account()
1051  .value()
1052  .address() ==
1053  txnJson["SignerEntries"][0u]["SignerEntry"]
1054  ["Account"]) &&
1055  BEAST_EXPECT(
1056  res.signer_list_set()
1057  .signer_entries()[0]
1058  .signer_weight()
1059  .value() ==
1060  txnJson["SignerEntries"][0u]["SignerEntry"]
1061  ["SignerWeight"]
1062  .asUInt()) &&
1063  BEAST_EXPECT(
1064  res.signer_list_set()
1065  .signer_entries()[1]
1066  .account()
1067  .value()
1068  .address() ==
1069  txnJson["SignerEntries"][1u]["SignerEntry"]
1070  ["Account"]) &&
1071  BEAST_EXPECT(
1072  res.signer_list_set()
1073  .signer_entries()[1]
1074  .signer_weight()
1075  .value() ==
1076  txnJson["SignerEntries"][1u]["SignerEntry"]
1077  ["SignerWeight"]
1078  .asUInt()) &&
1079  BEAST_EXPECT(
1080  res.signer_list_set()
1081  .signer_entries()[2]
1082  .account()
1083  .value()
1084  .address() ==
1085  txnJson["SignerEntries"][2u]["SignerEntry"]
1086  ["Account"]) &&
1087  BEAST_EXPECT(
1088  res.signer_list_set()
1089  .signer_entries()[2]
1090  .signer_weight()
1091  .value() ==
1092  txnJson["SignerEntries"][2u]["SignerEntry"]
1093  ["SignerWeight"]
1094  .asUInt());
1095  }},
1096  {9,
1097  6,
1098  strHex(txns[txns.size() - 15]->getTransactionID()),
1099  [&txns, this](auto res) {
1100  auto txnJson =
1101  txns[txns.size() - 15]->getJson(JsonOptions::none);
1102  return BEAST_EXPECT(res.has_offer_cancel()) &&
1103  BEAST_EXPECT(
1104  res.offer_cancel().offer_sequence().value() ==
1105  txnJson["OfferSequence"].asUInt());
1106  }},
1107  {8,
1108  5,
1109  strHex(txns[txns.size() - 16]->getTransactionID()),
1110  [&txns, this](auto res) {
1111  auto txnJson =
1112  txns[txns.size() - 16]->getJson(JsonOptions::none);
1113  return BEAST_EXPECT(res.has_offer_create()) &&
1114  BEAST_EXPECT(res.offer_create()
1115  .taker_gets()
1116  .value()
1117  .has_xrp_amount()) &&
1118  BEAST_EXPECT(
1119  res.offer_create()
1120  .taker_gets()
1121  .value()
1122  .xrp_amount()
1123  .drops() == txnJson["TakerGets"].asUInt()) &&
1124  BEAST_EXPECT(res.offer_create()
1125  .taker_pays()
1126  .value()
1127  .has_issued_currency_amount()) &&
1128  BEAST_EXPECT(
1129  res.offer_create()
1130  .taker_pays()
1131  .value()
1132  .issued_currency_amount()
1133  .currency()
1134  .name() == txnJson["TakerPays"]["currency"]) &&
1135  BEAST_EXPECT(
1136  res.offer_create()
1137  .taker_pays()
1138  .value()
1139  .issued_currency_amount()
1140  .value() == txnJson["TakerPays"]["value"]) &&
1141  BEAST_EXPECT(
1142  res.offer_create()
1143  .taker_pays()
1144  .value()
1145  .issued_currency_amount()
1146  .issuer()
1147  .address() == txnJson["TakerPays"]["issuer"]);
1148  }},
1149  {7,
1150  5,
1151  strHex(txns[txns.size() - 17]->getTransactionID()),
1152  [&txns, this](auto res) {
1153  auto txnJson =
1154  txns[txns.size() - 17]->getJson(JsonOptions::none);
1155  return BEAST_EXPECT(res.has_trust_set()) &&
1156  BEAST_EXPECT(res.trust_set()
1157  .limit_amount()
1158  .value()
1159  .has_issued_currency_amount()) &&
1160  BEAST_EXPECT(
1161  res.trust_set()
1162  .limit_amount()
1163  .value()
1164  .issued_currency_amount()
1165  .currency()
1166  .name() ==
1167  txnJson["LimitAmount"]["currency"]) &&
1168  BEAST_EXPECT(
1169  res.trust_set()
1170  .limit_amount()
1171  .value()
1172  .issued_currency_amount()
1173  .value() == txnJson["LimitAmount"]["value"]) &&
1174  BEAST_EXPECT(
1175  res.trust_set()
1176  .limit_amount()
1177  .value()
1178  .issued_currency_amount()
1179  .issuer()
1180  .address() == txnJson["LimitAmount"]["issuer"]);
1181  }},
1182  {6,
1183  4,
1184  strHex(txns[txns.size() - 18]->getTransactionID()),
1185  [&txns, this](auto res) {
1186  auto txnJson =
1187  txns[txns.size() - 18]->getJson(JsonOptions::none);
1188  return BEAST_EXPECT(res.has_set_regular_key()) &&
1189  BEAST_EXPECT(
1190  res.set_regular_key()
1191  .regular_key()
1192  .value()
1193  .address() == txnJson["RegularKey"]);
1194  }},
1195  {5,
1196  4,
1197  strHex(txns[txns.size() - 19]->getTransactionID()),
1198  [&txns, this](auto res) {
1199  auto txnJson =
1200  txns[txns.size() - 19]->getJson(JsonOptions::none);
1201  return BEAST_EXPECT(res.has_payment()) &&
1202  BEAST_EXPECT(
1203  res.payment().amount().value().has_xrp_amount()) &&
1204  BEAST_EXPECT(
1205  res.payment()
1206  .amount()
1207  .value()
1208  .xrp_amount()
1209  .drops() == txnJson["Amount"].asUInt()) &&
1210  BEAST_EXPECT(
1211  res.payment().destination().value().address() ==
1212  txnJson["Destination"]) &&
1213  BEAST_EXPECT(res.has_source_tag()) &&
1214  BEAST_EXPECT(
1215  res.source_tag().value() ==
1216  txnJson["SourceTag"].asUInt()) &&
1217  BEAST_EXPECT(res.payment().has_destination_tag()) &&
1218  BEAST_EXPECT(
1219  res.payment().destination_tag().value() ==
1220  txnJson["DestinationTag"].asUInt()) &&
1221  BEAST_EXPECT(res.has_last_ledger_sequence()) &&
1222  BEAST_EXPECT(
1223  res.last_ledger_sequence().value() ==
1224  txnJson["LastLedgerSequence"].asUInt()) &&
1225  BEAST_EXPECT(res.has_transaction_signature()) &&
1226  BEAST_EXPECT(res.has_account()) &&
1227  BEAST_EXPECT(
1228  res.account().value().address() ==
1229  txnJson["Account"]) &&
1230  BEAST_EXPECT(res.has_flags()) &&
1231  BEAST_EXPECT(
1232  res.flags().value() == txnJson["Flags"].asUInt());
1233  }},
1234  {4,
1235  4,
1236  strHex(txns[txns.size() - 20]->getTransactionID()),
1237  [this](auto res) { return BEAST_EXPECT(res.has_account_set()); }},
1238  {3,
1239  3,
1240  "9CE54C3B934E473A995B477E92EC229F99CED5B62BF4D2ACE4DC42719103AE2F",
1241  [this](auto res) {
1242  return BEAST_EXPECT(res.has_account_set()) &&
1243  BEAST_EXPECT(res.account_set().set_flag().value() == 8);
1244  }},
1245  {1,
1246  3,
1247  "2B5054734FA43C6C7B54F61944FAD6178ACD5D0272B39BA7FCD32A5D3932FBFF",
1248  [&alice, this](auto res) {
1249  return BEAST_EXPECT(res.has_payment()) &&
1250  BEAST_EXPECT(
1251  res.payment().amount().value().has_xrp_amount()) &&
1252  BEAST_EXPECT(
1253  res.payment()
1254  .amount()
1255  .value()
1256  .xrp_amount()
1257  .drops() == 1000000000010) &&
1258  BEAST_EXPECT(
1259  res.payment().destination().value().address() ==
1260  alice.human());
1261  }}};
1262 
1263  using MetaCheck =
1264  std::function<bool(org::xrpl::rpc::v1::Meta const& res)>;
1265  static const MetaCheck txMetaCheck[]{
1266  {[this](auto meta) {
1267  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1268  BEAST_EXPECT(meta.affected_nodes_size() == 1) &&
1269  BEAST_EXPECT(
1270  std::count_if(
1271  meta.affected_nodes().begin(),
1272  meta.affected_nodes().end(),
1273  [](org::xrpl::rpc::v1::AffectedNode const&
1274  entry) {
1275  return entry.ledger_entry_type() ==
1276  org::xrpl::rpc::v1::LedgerEntryType::
1277  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1278  }) == 1);
1279  }},
1280  {[this](auto meta) {
1281  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1282  BEAST_EXPECT(meta.affected_nodes_size() == 3) &&
1283  BEAST_EXPECT(
1284  std::count_if(
1285  meta.affected_nodes().begin(),
1286  meta.affected_nodes().end(),
1287  [](auto entry) {
1288  return entry.ledger_entry_type() ==
1289  org::xrpl::rpc::v1::LedgerEntryType::
1290  LEDGER_ENTRY_TYPE_DEPOSIT_PREAUTH;
1291  }) == 1) &&
1292  BEAST_EXPECT(
1293  std::count_if(
1294  meta.affected_nodes().begin(),
1295 
1296  meta.affected_nodes().end(),
1297  [](auto entry) {
1298  return entry.ledger_entry_type() ==
1299  org::xrpl::rpc::v1::LedgerEntryType::
1300  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1301  }) == 1) &&
1302  BEAST_EXPECT(
1303  std::count_if(
1304  meta.affected_nodes().begin(),
1305  meta.affected_nodes().end(),
1306  [](auto entry) {
1307  return entry.ledger_entry_type() ==
1308  org::xrpl::rpc::v1::LedgerEntryType::
1309  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1310  }) == 1);
1311  }},
1312  {[this](auto meta) {
1313  return BEAST_EXPECT(meta.transaction_index() == 1) &&
1314  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1315  BEAST_EXPECT(
1316  std::count_if(
1317  meta.affected_nodes().begin(),
1318  meta.affected_nodes().end(),
1319  [](auto entry) {
1320  return entry.ledger_entry_type() ==
1321  org::xrpl::rpc::v1::LedgerEntryType::
1322  LEDGER_ENTRY_TYPE_CHECK;
1323  }) == 1) &&
1324  BEAST_EXPECT(
1325  std::count_if(
1326  meta.affected_nodes().begin(),
1327  meta.affected_nodes().end(),
1328  [](auto entry) {
1329  return entry.ledger_entry_type() ==
1330  org::xrpl::rpc::v1::LedgerEntryType::
1331  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1332  }) == 2) &&
1333  BEAST_EXPECT(
1334  std::count_if(
1335  meta.affected_nodes().begin(),
1336  meta.affected_nodes().end(),
1337  [](auto entry) {
1338  return entry.ledger_entry_type() ==
1339  org::xrpl::rpc::v1::LedgerEntryType::
1340  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1341  }) == 2);
1342  }},
1343  {[this](auto meta) {
1344  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1345  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1346  BEAST_EXPECT(
1347  std::count_if(
1348  meta.affected_nodes().begin(),
1349  meta.affected_nodes().end(),
1350  [](auto entry) {
1351  return entry.ledger_entry_type() ==
1352  org::xrpl::rpc::v1::LedgerEntryType::
1353  LEDGER_ENTRY_TYPE_CHECK;
1354  }) == 1) &&
1355  BEAST_EXPECT(
1356  std::count_if(
1357  meta.affected_nodes().begin(),
1358  meta.affected_nodes().end(),
1359  [](auto entry) {
1360  return entry.ledger_entry_type() ==
1361  org::xrpl::rpc::v1::LedgerEntryType::
1362  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1363  }) == 2) &&
1364  BEAST_EXPECT(
1365  std::count_if(
1366  meta.affected_nodes().begin(),
1367  meta.affected_nodes().end(),
1368  [](auto entry) {
1369  return entry.ledger_entry_type() ==
1370  org::xrpl::rpc::v1::LedgerEntryType::
1371  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1372  }) == 2);
1373  }},
1374  {[this](auto meta) {
1375  return BEAST_EXPECT(meta.transaction_index() == 1) &&
1376  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1377  BEAST_EXPECT(
1378  std::count_if(
1379  meta.affected_nodes().begin(),
1380  meta.affected_nodes().end(),
1381  [](auto entry) {
1382  return entry.ledger_entry_type() ==
1383  org::xrpl::rpc::v1::LedgerEntryType::
1384  LEDGER_ENTRY_TYPE_CHECK;
1385  }) == 1) &&
1386  BEAST_EXPECT(
1387  std::count_if(
1388  meta.affected_nodes().begin(),
1389  meta.affected_nodes().end(),
1390  [](auto entry) {
1391  return entry.ledger_entry_type() ==
1392  org::xrpl::rpc::v1::LedgerEntryType::
1393  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1394  }) == 2) &&
1395  BEAST_EXPECT(
1396  std::count_if(
1397  meta.affected_nodes().begin(),
1398  meta.affected_nodes().end(),
1399  [](auto entry) {
1400  return entry.ledger_entry_type() ==
1401  org::xrpl::rpc::v1::LedgerEntryType::
1402  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1403  }) == 2);
1404  }},
1405  {[this](auto meta) {
1406  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1407  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1408  BEAST_EXPECT(
1409  std::count_if(
1410  meta.affected_nodes().begin(),
1411  meta.affected_nodes().end(),
1412  [](auto entry) {
1413  return entry.ledger_entry_type() ==
1414  org::xrpl::rpc::v1::LedgerEntryType::
1415  LEDGER_ENTRY_TYPE_CHECK;
1416  }) == 1) &&
1417  BEAST_EXPECT(
1418  std::count_if(
1419  meta.affected_nodes().begin(),
1420  meta.affected_nodes().end(),
1421  [](auto entry) {
1422  return entry.ledger_entry_type() ==
1423  org::xrpl::rpc::v1::LedgerEntryType::
1424  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1425  }) == 2) &&
1426  BEAST_EXPECT(
1427  std::count_if(
1428  meta.affected_nodes().begin(),
1429  meta.affected_nodes().end(),
1430  [](auto entry) {
1431  return entry.ledger_entry_type() ==
1432  org::xrpl::rpc::v1::LedgerEntryType::
1433  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1434  }) == 2);
1435  }},
1436  {[this](auto meta) {
1437  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1438  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1439  BEAST_EXPECT(
1440  std::count_if(
1441  meta.affected_nodes().begin(),
1442  meta.affected_nodes().end(),
1443  [](auto entry) {
1444  return entry.ledger_entry_type() ==
1445  org::xrpl::rpc::v1::LedgerEntryType::
1446  LEDGER_ENTRY_TYPE_PAY_CHANNEL;
1447  }) == 1) &&
1448  BEAST_EXPECT(
1449  std::count_if(
1450  meta.affected_nodes().begin(),
1451  meta.affected_nodes().end(),
1452  [](auto entry) {
1453  return entry.ledger_entry_type() ==
1454  org::xrpl::rpc::v1::LedgerEntryType::
1455  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1456  }) == 2) &&
1457  BEAST_EXPECT(
1458  std::count_if(
1459  meta.affected_nodes().begin(),
1460  meta.affected_nodes().end(),
1461  [](auto entry) {
1462  return entry.ledger_entry_type() ==
1463  org::xrpl::rpc::v1::LedgerEntryType::
1464  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1465  }) == 2);
1466  }},
1467  {[this](auto meta) {
1468  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1469  BEAST_EXPECT(meta.affected_nodes_size() == 2) &&
1470 
1471  BEAST_EXPECT(
1472  std::count_if(
1473  meta.affected_nodes().begin(),
1474  meta.affected_nodes().end(),
1475  [](auto entry) {
1476  return entry.ledger_entry_type() ==
1477  org::xrpl::rpc::v1::LedgerEntryType::
1478  LEDGER_ENTRY_TYPE_PAY_CHANNEL;
1479  }) == 1) &&
1480  BEAST_EXPECT(
1481  std::count_if(
1482  meta.affected_nodes().begin(),
1483  meta.affected_nodes().end(),
1484  [](auto entry) {
1485  return entry.ledger_entry_type() ==
1486  org::xrpl::rpc::v1::LedgerEntryType::
1487  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1488  }) == 1);
1489  }},
1490  {[this](auto meta) {
1491  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1492  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1493 
1494  BEAST_EXPECT(
1495  std::count_if(
1496  meta.affected_nodes().begin(),
1497  meta.affected_nodes().end(),
1498  [](auto entry) {
1499  return entry.ledger_entry_type() ==
1500  org::xrpl::rpc::v1::LedgerEntryType::
1501  LEDGER_ENTRY_TYPE_PAY_CHANNEL;
1502  }) == 1) &&
1503  BEAST_EXPECT(
1504  std::count_if(
1505  meta.affected_nodes().begin(),
1506  meta.affected_nodes().end(),
1507  [](auto entry) {
1508  return entry.ledger_entry_type() ==
1509  org::xrpl::rpc::v1::LedgerEntryType::
1510  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1511  }) == 2) &&
1512  BEAST_EXPECT(
1513  std::count_if(
1514  meta.affected_nodes().begin(),
1515  meta.affected_nodes().end(),
1516  [](auto entry) {
1517  return entry.ledger_entry_type() ==
1518  org::xrpl::rpc::v1::LedgerEntryType::
1519  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1520  }) == 2);
1521  }},
1522  {[this](auto meta) {
1523  return BEAST_EXPECT(meta.transaction_index() == 1) &&
1524  BEAST_EXPECT(meta.affected_nodes_size() == 3) &&
1525  BEAST_EXPECT(
1526  std::count_if(
1527  meta.affected_nodes().begin(),
1528  meta.affected_nodes().end(),
1529  [](auto entry) {
1530  return entry.ledger_entry_type() ==
1531  org::xrpl::rpc::v1::LedgerEntryType::
1532  LEDGER_ENTRY_TYPE_ESCROW;
1533  }) == 1) &&
1534  BEAST_EXPECT(
1535  std::count_if(
1536  meta.affected_nodes().begin(),
1537  meta.affected_nodes().end(),
1538  [](auto entry) {
1539  return entry.ledger_entry_type() ==
1540  org::xrpl::rpc::v1::LedgerEntryType::
1541  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1542  }) == 1) &&
1543  BEAST_EXPECT(
1544  std::count_if(
1545  meta.affected_nodes().begin(),
1546  meta.affected_nodes().end(),
1547  [](auto entry) {
1548  return entry.ledger_entry_type() ==
1549  org::xrpl::rpc::v1::LedgerEntryType::
1550  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1551  }) == 1);
1552  }},
1553  {[this](auto meta) {
1554  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1555  BEAST_EXPECT(meta.affected_nodes_size() == 3) &&
1556  BEAST_EXPECT(
1557  std::count_if(
1558  meta.affected_nodes().begin(),
1559  meta.affected_nodes().end(),
1560  [](auto entry) {
1561  return entry.ledger_entry_type() ==
1562  org::xrpl::rpc::v1::LedgerEntryType::
1563  LEDGER_ENTRY_TYPE_ESCROW;
1564  }) == 1) &&
1565  BEAST_EXPECT(
1566  std::count_if(
1567  meta.affected_nodes().begin(),
1568  meta.affected_nodes().end(),
1569  [](auto entry) {
1570  return entry.ledger_entry_type() ==
1571  org::xrpl::rpc::v1::LedgerEntryType::
1572  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1573  }) == 1) &&
1574  BEAST_EXPECT(
1575  std::count_if(
1576  meta.affected_nodes().begin(),
1577  meta.affected_nodes().end(),
1578  [](auto entry) {
1579  return entry.ledger_entry_type() ==
1580  org::xrpl::rpc::v1::LedgerEntryType::
1581  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1582  }) == 1);
1583  }},
1584  {[this](auto meta) {
1585  return BEAST_EXPECT(meta.transaction_index() == 2) &&
1586  BEAST_EXPECT(meta.affected_nodes_size() == 3) &&
1587 
1588  BEAST_EXPECT(
1589  std::count_if(
1590  meta.affected_nodes().begin(),
1591  meta.affected_nodes().end(),
1592  [](auto entry) {
1593  return entry.ledger_entry_type() ==
1594  org::xrpl::rpc::v1::LedgerEntryType::
1595  LEDGER_ENTRY_TYPE_ESCROW;
1596  }) == 1) &&
1597  BEAST_EXPECT(
1598  std::count_if(
1599  meta.affected_nodes().begin(),
1600  meta.affected_nodes().end(),
1601  [](auto entry) {
1602  return entry.ledger_entry_type() ==
1603  org::xrpl::rpc::v1::LedgerEntryType::
1604  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1605  }) == 1) &&
1606  BEAST_EXPECT(
1607  std::count_if(
1608  meta.affected_nodes().begin(),
1609  meta.affected_nodes().end(),
1610  [](auto entry) {
1611  return entry.ledger_entry_type() ==
1612  org::xrpl::rpc::v1::LedgerEntryType::
1613  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1614  }) == 1);
1615  }},
1616  {[this](auto meta) {
1617  return BEAST_EXPECT(meta.transaction_index() == 1) &&
1618  BEAST_EXPECT(meta.affected_nodes_size() == 3) &&
1619 
1620  BEAST_EXPECT(
1621  std::count_if(
1622  meta.affected_nodes().begin(),
1623  meta.affected_nodes().end(),
1624  [](auto entry) {
1625  return entry.ledger_entry_type() ==
1626  org::xrpl::rpc::v1::LedgerEntryType::
1627  LEDGER_ENTRY_TYPE_ESCROW;
1628  }) == 1) &&
1629  BEAST_EXPECT(
1630  std::count_if(
1631  meta.affected_nodes().begin(),
1632  meta.affected_nodes().end(),
1633  [](auto entry) {
1634  return entry.ledger_entry_type() ==
1635  org::xrpl::rpc::v1::LedgerEntryType::
1636  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1637  }) == 1) &&
1638  BEAST_EXPECT(
1639  std::count_if(
1640  meta.affected_nodes().begin(),
1641  meta.affected_nodes().end(),
1642  [](auto entry) {
1643  return entry.ledger_entry_type() ==
1644  org::xrpl::rpc::v1::LedgerEntryType::
1645  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1646  }) == 1);
1647  }},
1648  {[this](auto meta) {
1649  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1650  BEAST_EXPECT(meta.affected_nodes_size() == 3) &&
1651  BEAST_EXPECT(
1652  std::count_if(
1653  meta.affected_nodes().begin(),
1654  meta.affected_nodes().end(),
1655  [](auto entry) {
1656  return entry.ledger_entry_type() ==
1657  org::xrpl::rpc::v1::LedgerEntryType::
1658  LEDGER_ENTRY_TYPE_SIGNER_LIST;
1659  }) == 1) &&
1660  BEAST_EXPECT(
1661  std::count_if(
1662  meta.affected_nodes().begin(),
1663  meta.affected_nodes().end(),
1664  [](auto entry) {
1665  return entry.ledger_entry_type() ==
1666  org::xrpl::rpc::v1::LedgerEntryType::
1667  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1668  }) == 1) &&
1669  BEAST_EXPECT(
1670  std::count_if(
1671  meta.affected_nodes().begin(),
1672  meta.affected_nodes().end(),
1673  [](auto entry) {
1674  return entry.ledger_entry_type() ==
1675  org::xrpl::rpc::v1::LedgerEntryType::
1676  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1677  }) == 1);
1678  }},
1679  {[this](auto meta) {
1680  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1681  BEAST_EXPECT(meta.affected_nodes_size() == 4) &&
1682  BEAST_EXPECT(
1683  std::count_if(
1684  meta.affected_nodes().begin(),
1685  meta.affected_nodes().end(),
1686  [](auto entry) {
1687  return entry.ledger_entry_type() ==
1688  org::xrpl::rpc::v1::LedgerEntryType::
1689  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1690  }) == 2) &&
1691  BEAST_EXPECT(
1692  std::count_if(
1693  meta.affected_nodes().begin(),
1694  meta.affected_nodes().end(),
1695  [](auto entry) {
1696  return entry.ledger_entry_type() ==
1697  org::xrpl::rpc::v1::LedgerEntryType::
1698  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1699  }) == 1) &&
1700  BEAST_EXPECT(
1701  std::count_if(
1702  meta.affected_nodes().begin(),
1703  meta.affected_nodes().end(),
1704  [](auto entry) {
1705  return entry.ledger_entry_type() ==
1706  org::xrpl::rpc::v1::LedgerEntryType::
1707  LEDGER_ENTRY_TYPE_OFFER;
1708  }) == 1);
1709  }},
1710  {[this](auto meta) {
1711  return BEAST_EXPECT(meta.transaction_index() == 1) &&
1712  BEAST_EXPECT(meta.affected_nodes_size() == 4) &&
1713 
1714  BEAST_EXPECT(
1715  std::count_if(
1716  meta.affected_nodes().begin(),
1717  meta.affected_nodes().end(),
1718  [](auto entry) {
1719  return entry.ledger_entry_type() ==
1720  org::xrpl::rpc::v1::LedgerEntryType::
1721  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1722  }) == 2) &&
1723  BEAST_EXPECT(
1724  std::count_if(
1725  meta.affected_nodes().begin(),
1726  meta.affected_nodes().end(),
1727  [](auto entry) {
1728  return entry.ledger_entry_type() ==
1729  org::xrpl::rpc::v1::LedgerEntryType::
1730  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1731  }) == 1) &&
1732  BEAST_EXPECT(
1733  std::count_if(
1734  meta.affected_nodes().begin(),
1735  meta.affected_nodes().end(),
1736  [](auto entry) {
1737  return entry.ledger_entry_type() ==
1738  org::xrpl::rpc::v1::LedgerEntryType::
1739  LEDGER_ENTRY_TYPE_OFFER;
1740  }) == 1);
1741  }},
1742  {[this](auto meta) {
1743  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1744  BEAST_EXPECT(meta.affected_nodes_size() == 5) &&
1745  BEAST_EXPECT(
1746  std::count_if(
1747  meta.affected_nodes().begin(),
1748  meta.affected_nodes().end(),
1749  [](auto entry) {
1750  return entry.ledger_entry_type() ==
1751  org::xrpl::rpc::v1::LedgerEntryType::
1752  LEDGER_ENTRY_TYPE_DIRECTORY_NODE;
1753  }) == 2) &&
1754  BEAST_EXPECT(
1755  std::count_if(
1756  meta.affected_nodes().begin(),
1757  meta.affected_nodes().end(),
1758  [](auto entry) {
1759  return entry.ledger_entry_type() ==
1760  org::xrpl::rpc::v1::LedgerEntryType::
1761  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1762  }) == 2) &&
1763  BEAST_EXPECT(
1764  std::count_if(
1765  meta.affected_nodes().begin(),
1766  meta.affected_nodes().end(),
1767  [](auto entry) {
1768  return entry.ledger_entry_type() ==
1769  org::xrpl::rpc::v1::LedgerEntryType::
1770  LEDGER_ENTRY_TYPE_RIPPLE_STATE;
1771  }) == 1);
1772  }},
1773  {[this](auto meta) {
1774  return BEAST_EXPECT(meta.transaction_index() == 2) &&
1775  BEAST_EXPECT(meta.affected_nodes_size() == 1) &&
1776  BEAST_EXPECT(
1777  std::count_if(
1778  meta.affected_nodes().begin(),
1779  meta.affected_nodes().end(),
1780  [](auto entry) {
1781  return entry.ledger_entry_type() ==
1782  org::xrpl::rpc::v1::LedgerEntryType::
1783  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1784  }) == 1);
1785  }},
1786  {[this](auto meta) {
1787  return BEAST_EXPECT(meta.transaction_index() == 1) &&
1788  BEAST_EXPECT(meta.affected_nodes_size() == 2) &&
1789  BEAST_EXPECT(
1790  std::count_if(
1791  meta.affected_nodes().begin(),
1792  meta.affected_nodes().end(),
1793  [](auto entry) {
1794  return entry.ledger_entry_type() ==
1795  org::xrpl::rpc::v1::LedgerEntryType::
1796  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1797  }) == 2);
1798  }},
1799  {[this](auto meta) {
1800  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1801  BEAST_EXPECT(meta.affected_nodes_size() == 1) &&
1802  BEAST_EXPECT(
1803  std::count_if(
1804  meta.affected_nodes().begin(),
1805  meta.affected_nodes().end(),
1806  [](auto entry) {
1807  return entry.ledger_entry_type() ==
1808  org::xrpl::rpc::v1::LedgerEntryType::
1809  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1810  }) == 1);
1811  }},
1812  {[this](auto meta) {
1813  return BEAST_EXPECT(meta.transaction_index() == 2) &&
1814  BEAST_EXPECT(meta.affected_nodes_size() == 1) &&
1815  BEAST_EXPECT(
1816  std::count_if(
1817  meta.affected_nodes().begin(),
1818  meta.affected_nodes().end(),
1819  [](auto entry) {
1820  return entry.ledger_entry_type() ==
1821  org::xrpl::rpc::v1::LedgerEntryType::
1822  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1823  }) == 1);
1824  }},
1825  {[this](auto meta) {
1826  return BEAST_EXPECT(meta.transaction_index() == 0) &&
1827  BEAST_EXPECT(meta.affected_nodes_size() == 2) &&
1828  BEAST_EXPECT(
1829  std::count_if(
1830  meta.affected_nodes().begin(),
1831  meta.affected_nodes().end(),
1832  [](auto entry) {
1833  return entry.ledger_entry_type() ==
1834  org::xrpl::rpc::v1::LedgerEntryType::
1835  LEDGER_ENTRY_TYPE_ACCOUNT_ROOT;
1836  }) == 2);
1837  }}};
1838 
1839  auto doCheck = [this](auto txn, auto txCheck) {
1840  return BEAST_EXPECT(txn.has_transaction()) &&
1841  BEAST_EXPECT(txn.validated()) &&
1842  BEAST_EXPECT(strHex(txn.hash()) == txCheck.hash) &&
1843  BEAST_EXPECT(txn.ledger_index() == txCheck.ledgerIndex) &&
1844  BEAST_EXPECT(
1845  txn.transaction().sequence().value() ==
1846  txCheck.sequence) &&
1847  txCheck.checkTxn(txn.transaction());
1848  };
1849 
1850  auto doMetaCheck = [this](auto txn, auto txMetaCheck) {
1851  return BEAST_EXPECT(txn.has_meta()) &&
1852  BEAST_EXPECT(txn.meta().has_transaction_result()) &&
1853  BEAST_EXPECT(
1854  txn.meta().transaction_result().result_type() ==
1855  org::xrpl::rpc::v1::TransactionResult::
1856  RESULT_TYPE_TES) &&
1857  BEAST_EXPECT(
1858  txn.meta().transaction_result().result() ==
1859  "tesSUCCESS") &&
1860  txMetaCheck(txn.meta());
1861  };
1862 
1863  auto [res, status] = next(grpcPort, env, alice.human());
1864 
1865  if (!BEAST_EXPECT(status.error_code() == 0))
1866  return;
1867 
1868  if (!BEAST_EXPECT(res.transactions().size() == std::size(txCheck)))
1869  return;
1870  for (int i = 0; i < res.transactions().size(); ++i)
1871  {
1872  BEAST_EXPECT(doCheck(res.transactions()[i], txCheck[i]));
1873  BEAST_EXPECT(doMetaCheck(res.transactions()[i], txMetaCheck[i]));
1874  }
1875 
1876  // test binary representation
1877  std::tie(res, status) = nextBinary(grpcPort, env, alice.human());
1878 
1879  // txns vector does not contain the first two transactions returned by
1880  // account_tx
1881  if (!BEAST_EXPECT(res.transactions().size() == txns.size() + 2))
1882  return;
1883 
1884  std::reverse(txns.begin(), txns.end());
1885  for (int i = 0; i < txns.size(); ++i)
1886  {
1887  auto toByteString = [](auto data) {
1888  const char* bytes = reinterpret_cast<const char*>(data.data());
1889  return std::string(bytes, data.size());
1890  };
1891 
1892  auto tx = txns[i];
1893  Serializer s = tx->getSerializer();
1894  std::string bin = toByteString(s);
1895 
1896  BEAST_EXPECT(res.transactions(i).transaction_binary() == bin);
1897  }
1898  }
1899 
1900  void
1902  {
1903  testcase("Test Account_tx Grpc");
1904 
1905  using namespace test::jtx;
1906  std::unique_ptr<Config> config = envconfig(addGrpcConfig);
1907  std::string grpcPort = *(*config)["port_grpc"].get<std::string>("port");
1908  Env env(*this, std::move(config));
1909 
1910  Account A1{"A1"};
1911  Account A2{"A2"};
1912  Account A3{"A3"};
1913 
1914  env.fund(XRP(10000), A1, A2, A3);
1915  env.close();
1916 
1917  env.trust(A3["USD"](1000), A1);
1918  env.trust(A2["USD"](1000), A1);
1919  env.trust(A3["USD"](1000), A2);
1920  env.close();
1921 
1922  for (auto i = 0; i < 5; ++i)
1923  {
1924  env(pay(A2, A1, A2["USD"](2)));
1925  env(pay(A3, A1, A3["USD"](2)));
1926  env(offer(A1, XRP(11), A1["USD"](1)));
1927  env(offer(A2, XRP(10), A2["USD"](1)));
1928  env(offer(A3, XRP(9), A3["USD"](1)));
1929  env.close();
1930  }
1931 
1932  /* The sequence/ledger for A3 are as follows:
1933  * seq ledger_index
1934  * 3 ----> 3
1935  * 1 ----> 3
1936  * 2 ----> 4
1937  * 2 ----> 4
1938  * 2 ----> 5
1939  * 3 ----> 5
1940  * 4 ----> 6
1941  * 5 ----> 6
1942  * 6 ----> 7
1943  * 7 ----> 7
1944  * 8 ----> 8
1945  * 9 ----> 8
1946  * 10 ----> 9
1947  * 11 ----> 9
1948  */
1949 
1950  // page through the results in several ways.
1951  {
1952  // limit = 2, 3 batches giving the first 6 txs
1953  auto [res, status] = next(grpcPort, env, A3.human(), 2, 5, 2, true);
1954 
1955  auto txs = res.transactions();
1956  if (!BEAST_EXPECT(txs.size() == 2))
1957  return;
1958 
1959  BEAST_EXPECT(checkTransaction(txs[0u], 3, 3));
1960  BEAST_EXPECT(checkTransaction(txs[1u], 3, 3));
1961  if (!BEAST_EXPECT(res.has_marker()))
1962  return;
1963 
1964  std::tie(res, status) = next(
1965  grpcPort, env, A3.human(), 2, 5, 2, true, res.mutable_marker());
1966  txs = res.transactions();
1967  if (!BEAST_EXPECT(txs.size() == 2))
1968  return;
1969  BEAST_EXPECT(checkTransaction(txs[0u], 4, 4));
1970  BEAST_EXPECT(checkTransaction(txs[1u], 4, 4));
1971  if (!BEAST_EXPECT(res.has_marker()))
1972  return;
1973 
1974  std::tie(res, status) = next(
1975  grpcPort, env, A3.human(), 2, 5, 2, true, res.mutable_marker());
1976  txs = res.transactions();
1977  if (!BEAST_EXPECT(txs.size() == 2))
1978  return;
1979  BEAST_EXPECT(checkTransaction(txs[0u], 4, 5));
1980  BEAST_EXPECT(checkTransaction(txs[1u], 5, 5));
1981  BEAST_EXPECT(!res.has_marker());
1982  return;
1983  }
1984 
1985  {
1986  // limit 1, 3 requests giving the first 3 txs
1987  auto [res, status] = next(grpcPort, env, A3.human(), 3, 9, 1, true);
1988  auto txs = res.transactions();
1989  if (!BEAST_EXPECT(txs.size() == 1))
1990  return;
1991  BEAST_EXPECT(checkTransaction(txs[0u], 3, 3));
1992  if (!BEAST_EXPECT(res.has_marker()))
1993  return;
1994 
1995  std::tie(res, status) = next(
1996  grpcPort, env, A3.human(), 3, 9, 1, true, res.mutable_marker());
1997  txs = res.transactions();
1998  if (!BEAST_EXPECT(txs.size() == 1))
1999  return;
2000  BEAST_EXPECT(checkTransaction(txs[0u], 3, 3));
2001  if (!BEAST_EXPECT(res.has_marker()))
2002  return;
2003 
2004  std::tie(res, status) = next(
2005  grpcPort, env, A3.human(), 3, 9, 1, true, res.mutable_marker());
2006  txs = res.transactions();
2007  if (!BEAST_EXPECT(txs.size() == 1))
2008  return;
2009  BEAST_EXPECT(checkTransaction(txs[0u], 4, 4));
2010  if (!BEAST_EXPECT(res.has_marker()))
2011  return;
2012 
2013  // continue with limit 3, to end of all txs
2014  std::tie(res, status) = next(
2015  grpcPort, env, A3.human(), 3, 9, 3, true, res.mutable_marker());
2016  txs = res.transactions();
2017  if (!BEAST_EXPECT(txs.size() == 3))
2018  return;
2019  BEAST_EXPECT(checkTransaction(txs[0u], 4, 4));
2020  BEAST_EXPECT(checkTransaction(txs[1u], 4, 5));
2021  BEAST_EXPECT(checkTransaction(txs[2u], 5, 5));
2022  if (!BEAST_EXPECT(res.has_marker()))
2023  return;
2024 
2025  std::tie(res, status) = next(
2026  grpcPort, env, A3.human(), 3, 9, 3, true, res.mutable_marker());
2027  txs = res.transactions();
2028  if (!BEAST_EXPECT(txs.size() == 3))
2029  return;
2030  BEAST_EXPECT(checkTransaction(txs[0u], 6, 6));
2031  BEAST_EXPECT(checkTransaction(txs[1u], 7, 6));
2032  BEAST_EXPECT(checkTransaction(txs[2u], 8, 7));
2033  if (!BEAST_EXPECT(res.has_marker()))
2034  return;
2035 
2036  std::tie(res, status) = next(
2037  grpcPort, env, A3.human(), 3, 9, 3, true, res.mutable_marker());
2038  txs = res.transactions();
2039  if (!BEAST_EXPECT(txs.size() == 3))
2040  return;
2041  BEAST_EXPECT(checkTransaction(txs[0u], 9, 7));
2042  BEAST_EXPECT(checkTransaction(txs[1u], 10, 8));
2043  BEAST_EXPECT(checkTransaction(txs[2u], 11, 8));
2044  if (!BEAST_EXPECT(res.has_marker()))
2045  return;
2046 
2047  std::tie(res, status) = next(
2048  grpcPort, env, A3.human(), 3, 9, 3, true, res.mutable_marker());
2049  txs = res.transactions();
2050  if (!BEAST_EXPECT(txs.size() == 2))
2051  return;
2052  BEAST_EXPECT(checkTransaction(txs[0u], 12, 9));
2053  BEAST_EXPECT(checkTransaction(txs[1u], 13, 9));
2054  BEAST_EXPECT(!res.has_marker());
2055  }
2056 
2057  {
2058  // limit 2, descending, 2 batches giving last 4 txs
2059  auto [res, status] =
2060  next(grpcPort, env, A3.human(), 3, 9, 2, false);
2061  auto txs = res.transactions();
2062  if (!BEAST_EXPECT(txs.size() == 2))
2063  return;
2064  BEAST_EXPECT(checkTransaction(txs[0u], 13, 9));
2065  BEAST_EXPECT(checkTransaction(txs[1u], 12, 9));
2066  if (!BEAST_EXPECT(res.has_marker()))
2067  return;
2068 
2069  std::tie(res, status) = next(
2070  grpcPort,
2071  env,
2072  A3.human(),
2073  3,
2074  9,
2075  2,
2076  false,
2077  res.mutable_marker());
2078  txs = res.transactions();
2079  if (!BEAST_EXPECT(txs.size() == 2))
2080  return;
2081  BEAST_EXPECT(checkTransaction(txs[0u], 11, 8));
2082  BEAST_EXPECT(checkTransaction(txs[1u], 10, 8));
2083  if (!BEAST_EXPECT(res.has_marker()))
2084  return;
2085 
2086  // continue with limit 3 until all txs have been seen
2087  std::tie(res, status) = next(
2088  grpcPort,
2089  env,
2090  A3.human(),
2091  3,
2092  9,
2093  3,
2094  false,
2095  res.mutable_marker());
2096  txs = res.transactions();
2097  if (!BEAST_EXPECT(txs.size() == 3))
2098  return;
2099  BEAST_EXPECT(checkTransaction(txs[0u], 9, 7));
2100  BEAST_EXPECT(checkTransaction(txs[1u], 8, 7));
2101  BEAST_EXPECT(checkTransaction(txs[2u], 7, 6));
2102  if (!BEAST_EXPECT(res.has_marker()))
2103  return;
2104 
2105  std::tie(res, status) = next(
2106  grpcPort,
2107  env,
2108  A3.human(),
2109  3,
2110  9,
2111  3,
2112  false,
2113  res.mutable_marker());
2114  txs = res.transactions();
2115  if (!BEAST_EXPECT(txs.size() == 3))
2116  return;
2117  BEAST_EXPECT(checkTransaction(txs[0u], 6, 6));
2118  BEAST_EXPECT(checkTransaction(txs[1u], 5, 5));
2119  BEAST_EXPECT(checkTransaction(txs[2u], 4, 5));
2120  if (!BEAST_EXPECT(res.has_marker()))
2121  return;
2122 
2123  std::tie(res, status) = next(
2124  grpcPort,
2125  env,
2126  A3.human(),
2127  3,
2128  9,
2129  3,
2130  false,
2131  res.mutable_marker());
2132  txs = res.transactions();
2133  if (!BEAST_EXPECT(txs.size() == 3))
2134  return;
2135  BEAST_EXPECT(checkTransaction(txs[0u], 4, 4));
2136  BEAST_EXPECT(checkTransaction(txs[1u], 4, 4));
2137  BEAST_EXPECT(checkTransaction(txs[2u], 3, 3));
2138  if (!BEAST_EXPECT(res.has_marker()))
2139  return;
2140 
2141  std::tie(res, status) = next(
2142  grpcPort,
2143  env,
2144  A3.human(),
2145  3,
2146  9,
2147  3,
2148  false,
2149  res.mutable_marker());
2150  txs = res.transactions();
2151  if (!BEAST_EXPECT(txs.size() == 1))
2152  return;
2153  BEAST_EXPECT(checkTransaction(txs[0u], 3, 3));
2154  BEAST_EXPECT(!res.has_marker());
2155  }
2156  }
2157 
2158 public:
2159  void
2160  run() override
2161  {
2166  }
2167 };
2168 
2169 BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple);
2170 
2171 } // 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:2160
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::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::tfClose
constexpr std::uint32_t tfClose
Definition: TxFlags.h:114
ripple::AccountTxPaging_test::TxCheck::sequence
uint32_t sequence
Definition: AccountTxPaging_test.cpp:533
std::reverse
T reverse(T... args)
std::function
ripple::AccountTxPaging_test::GrpcAccountTxClient::AccountTx
void AccountTx()
Definition: AccountTxPaging_test.cpp:278
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:136
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:40
ripple::base_uint< 256 >
ripple::AccountTxPaging_test::testAccountTxPagingGrpc
void testAccountTxPagingGrpc()
Definition: AccountTxPaging_test.cpp:1901
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:44
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::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:324
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::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::sfFinishAfter
const SF_UINT32 sfFinishAfter
ripple::sfChannel
const SF_UINT256 sfChannel
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
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::tfUniversal
constexpr std::uint32_t tfUniversal
Definition: TxFlags.h:57
ripple::keylet::check
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition: Indexes.cpp:281
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:116
ripple::test::jtx::Env::rpc
Json::Value rpc(std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:684
Json::Value
Represents a JSON value.
Definition: json_value.h:145