rippled
AccountInfo_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 
20 #include <ripple/protocol/Feature.h>
21 #include <ripple/protocol/jss.h>
22 #include <test/jtx.h>
23 
24 #include <ripple/resource/Charge.h>
25 #include <ripple/resource/Fees.h>
26 #include <ripple/rpc/GRPCHandlers.h>
27 #include <test/jtx/WSClient.h>
28 #include <test/rpc/GRPCTestClientBase.h>
29 
30 namespace ripple {
31 namespace test {
32 
33 class AccountInfo_test : public beast::unit_test::suite
34 {
35 public:
36  void
38  {
39  using namespace jtx;
40  Env env(*this);
41  {
42  // account_info with no account.
43  auto const info = env.rpc("json", "account_info", "{ }");
44  BEAST_EXPECT(
45  info[jss::result][jss::error_message] ==
46  "Missing field 'account'.");
47  }
48  {
49  // account_info with a malformed account sting.
50  auto const info = env.rpc(
51  "json",
52  "account_info",
53  "{\"account\": "
54  "\"n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV\"}");
55  BEAST_EXPECT(
56  info[jss::result][jss::error_message] == "Disallowed seed.");
57  }
58  {
59  // account_info with an account that's not in the ledger.
60  Account const bogie{"bogie"};
61  auto const info = env.rpc(
62  "json",
63  "account_info",
64  std::string("{ ") + "\"account\": \"" + bogie.human() + "\"}");
65  BEAST_EXPECT(
66  info[jss::result][jss::error_message] == "Account not found.");
67  }
68  }
69 
70  // Test the "signer_lists" argument in account_info.
71  void
73  {
74  using namespace jtx;
75  Env env(*this);
76  Account const alice{"alice"};
77  env.fund(XRP(1000), alice);
78 
79  auto const withoutSigners =
80  std::string("{ ") + "\"account\": \"" + alice.human() + "\"}";
81 
82  auto const withSigners = std::string("{ ") + "\"account\": \"" +
83  alice.human() + "\", " + "\"signer_lists\": true }";
84 
85  // Alice has no SignerList yet.
86  {
87  // account_info without the "signer_lists" argument.
88  auto const info = env.rpc("json", "account_info", withoutSigners);
89  BEAST_EXPECT(
90  info.isMember(jss::result) &&
91  info[jss::result].isMember(jss::account_data));
92  BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(
93  jss::signer_lists));
94  }
95  {
96  // account_info with the "signer_lists" argument.
97  auto const info = env.rpc("json", "account_info", withSigners);
98  BEAST_EXPECT(
99  info.isMember(jss::result) &&
100  info[jss::result].isMember(jss::account_data));
101  auto const& data = info[jss::result][jss::account_data];
102  BEAST_EXPECT(data.isMember(jss::signer_lists));
103  auto const& signerLists = data[jss::signer_lists];
104  BEAST_EXPECT(signerLists.isArray());
105  BEAST_EXPECT(signerLists.size() == 0);
106  }
107 
108  // Give alice a SignerList.
109  Account const bogie{"bogie"};
110 
111  Json::Value const smallSigners = signers(alice, 2, {{bogie, 3}});
112  env(smallSigners);
113  {
114  // account_info without the "signer_lists" argument.
115  auto const info = env.rpc("json", "account_info", withoutSigners);
116  BEAST_EXPECT(
117  info.isMember(jss::result) &&
118  info[jss::result].isMember(jss::account_data));
119  BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(
120  jss::signer_lists));
121  }
122  {
123  // account_info with the "signer_lists" argument.
124  auto const info = env.rpc("json", "account_info", withSigners);
125  BEAST_EXPECT(
126  info.isMember(jss::result) &&
127  info[jss::result].isMember(jss::account_data));
128  auto const& data = info[jss::result][jss::account_data];
129  BEAST_EXPECT(data.isMember(jss::signer_lists));
130  auto const& signerLists = data[jss::signer_lists];
131  BEAST_EXPECT(signerLists.isArray());
132  BEAST_EXPECT(signerLists.size() == 1);
133  auto const& signers = signerLists[0u];
134  BEAST_EXPECT(signers.isObject());
135  BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 2);
136  auto const& signerEntries = signers[sfSignerEntries.jsonName];
137  BEAST_EXPECT(signerEntries.size() == 1);
138  auto const& entry0 = signerEntries[0u][sfSignerEntry.jsonName];
139  BEAST_EXPECT(entry0[sfSignerWeight.jsonName] == 3);
140  }
141 
142  // Give alice a big signer list
143  Account const demon{"demon"};
144  Account const ghost{"ghost"};
145  Account const haunt{"haunt"};
146  Account const jinni{"jinni"};
147  Account const phase{"phase"};
148  Account const shade{"shade"};
149  Account const spook{"spook"};
150 
151  Json::Value const bigSigners = signers(
152  alice,
153  4,
154  {
155  {bogie, 1},
156  {demon, 1},
157  {ghost, 1},
158  {haunt, 1},
159  {jinni, 1},
160  {phase, 1},
161  {shade, 1},
162  {spook, 1},
163  });
164  env(bigSigners);
165  {
166  // account_info with the "signer_lists" argument.
167  auto const info = env.rpc("json", "account_info", withSigners);
168  BEAST_EXPECT(
169  info.isMember(jss::result) &&
170  info[jss::result].isMember(jss::account_data));
171  auto const& data = info[jss::result][jss::account_data];
172  BEAST_EXPECT(data.isMember(jss::signer_lists));
173  auto const& signerLists = data[jss::signer_lists];
174  BEAST_EXPECT(signerLists.isArray());
175  BEAST_EXPECT(signerLists.size() == 1);
176  auto const& signers = signerLists[0u];
177  BEAST_EXPECT(signers.isObject());
178  BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 4);
179  auto const& signerEntries = signers[sfSignerEntries.jsonName];
180  BEAST_EXPECT(signerEntries.size() == 8);
181  for (unsigned i = 0u; i < 8; ++i)
182  {
183  auto const& entry = signerEntries[i][sfSignerEntry.jsonName];
184  BEAST_EXPECT(entry.size() == 2);
185  BEAST_EXPECT(entry.isMember(sfAccount.jsonName));
186  BEAST_EXPECT(entry[sfSignerWeight.jsonName] == 1);
187  }
188  }
189  }
190 
191  // Test the "signer_lists" argument in account_info, with api_version 2.
192  void
194  {
195  using namespace jtx;
196  Env env{*this, envconfig([](std::unique_ptr<Config> c) {
197  c->loadFromString("\n[beta_rpc_api]\n1\n");
198  return c;
199  })};
200  Account const alice{"alice"};
201  env.fund(XRP(1000), alice);
202 
203  auto const withoutSigners = std::string("{ ") +
204  "\"api_version\": 2, \"account\": \"" + alice.human() + "\"}";
205 
206  auto const withSigners = std::string("{ ") +
207  "\"api_version\": 2, \"account\": \"" + alice.human() + "\", " +
208  "\"signer_lists\": true }";
209 
210  // Alice has no SignerList yet.
211  {
212  // account_info without the "signer_lists" argument.
213  auto const info = env.rpc("json", "account_info", withoutSigners);
214  BEAST_EXPECT(info.isMember(jss::result));
215  BEAST_EXPECT(!info[jss::result].isMember(jss::signer_lists));
216  }
217  {
218  // account_info with the "signer_lists" argument.
219  auto const info = env.rpc("json", "account_info", withSigners);
220  BEAST_EXPECT(info.isMember(jss::result));
221  auto const& data = info[jss::result];
222  BEAST_EXPECT(data.isMember(jss::signer_lists));
223  auto const& signerLists = data[jss::signer_lists];
224  BEAST_EXPECT(signerLists.isArray());
225  BEAST_EXPECT(signerLists.size() == 0);
226  }
227 
228  // Give alice a SignerList.
229  Account const bogie{"bogie"};
230 
231  Json::Value const smallSigners = signers(alice, 2, {{bogie, 3}});
232  env(smallSigners);
233  {
234  // account_info without the "signer_lists" argument.
235  auto const info = env.rpc("json", "account_info", withoutSigners);
236  BEAST_EXPECT(info.isMember(jss::result));
237  BEAST_EXPECT(!info[jss::result].isMember(jss::signer_lists));
238  }
239  {
240  // account_info with the "signer_lists" argument.
241  auto const info = env.rpc("json", "account_info", withSigners);
242  BEAST_EXPECT(info.isMember(jss::result));
243  auto const& data = info[jss::result];
244  BEAST_EXPECT(data.isMember(jss::signer_lists));
245  auto const& signerLists = data[jss::signer_lists];
246  BEAST_EXPECT(signerLists.isArray());
247  BEAST_EXPECT(signerLists.size() == 1);
248  auto const& signers = signerLists[0u];
249  BEAST_EXPECT(signers.isObject());
250  BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 2);
251  auto const& signerEntries = signers[sfSignerEntries.jsonName];
252  BEAST_EXPECT(signerEntries.size() == 1);
253  auto const& entry0 = signerEntries[0u][sfSignerEntry.jsonName];
254  BEAST_EXPECT(entry0[sfSignerWeight.jsonName] == 3);
255  }
256 
257  // Give alice a big signer list
258  Account const demon{"demon"};
259  Account const ghost{"ghost"};
260  Account const haunt{"haunt"};
261  Account const jinni{"jinni"};
262  Account const phase{"phase"};
263  Account const shade{"shade"};
264  Account const spook{"spook"};
265 
266  Json::Value const bigSigners = signers(
267  alice,
268  4,
269  {
270  {bogie, 1},
271  {demon, 1},
272  {ghost, 1},
273  {haunt, 1},
274  {jinni, 1},
275  {phase, 1},
276  {shade, 1},
277  {spook, 1},
278  });
279  env(bigSigners);
280  {
281  // account_info with the "signer_lists" argument.
282  auto const info = env.rpc("json", "account_info", withSigners);
283  BEAST_EXPECT(info.isMember(jss::result));
284  auto const& data = info[jss::result];
285  BEAST_EXPECT(data.isMember(jss::signer_lists));
286  auto const& signerLists = data[jss::signer_lists];
287  BEAST_EXPECT(signerLists.isArray());
288  BEAST_EXPECT(signerLists.size() == 1);
289  auto const& signers = signerLists[0u];
290  BEAST_EXPECT(signers.isObject());
291  BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 4);
292  auto const& signerEntries = signers[sfSignerEntries.jsonName];
293  BEAST_EXPECT(signerEntries.size() == 8);
294  for (unsigned i = 0u; i < 8; ++i)
295  {
296  auto const& entry = signerEntries[i][sfSignerEntry.jsonName];
297  BEAST_EXPECT(entry.size() == 2);
298  BEAST_EXPECT(entry.isMember(sfAccount.jsonName));
299  BEAST_EXPECT(entry[sfSignerWeight.jsonName] == 1);
300  }
301  }
302  }
303 
304  // Test the "signer_lists" argument in account_info, version 2 API.
305  void
307  {
308  using namespace jtx;
309  Env env(*this);
310  Account const alice{"alice"};
311  env.fund(XRP(1000), alice);
312 
313  auto const withoutSigners = std::string("{ ") +
314  "\"jsonrpc\": \"2.0\", "
315  "\"ripplerpc\": \"2.0\", "
316  "\"id\": 5, "
317  "\"method\": \"account_info\", "
318  "\"params\": { "
319  "\"account\": \"" +
320  alice.human() + "\"}}";
321 
322  auto const withSigners = std::string("{ ") +
323  "\"jsonrpc\": \"2.0\", "
324  "\"ripplerpc\": \"2.0\", "
325  "\"id\": 6, "
326  "\"method\": \"account_info\", "
327  "\"params\": { "
328  "\"account\": \"" +
329  alice.human() + "\", " + "\"signer_lists\": true }}";
330  // Alice has no SignerList yet.
331  {
332  // account_info without the "signer_lists" argument.
333  auto const info = env.rpc("json2", withoutSigners);
334  BEAST_EXPECT(
335  info.isMember(jss::result) &&
336  info[jss::result].isMember(jss::account_data));
337  BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(
338  jss::signer_lists));
339  BEAST_EXPECT(
340  info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
341  BEAST_EXPECT(
342  info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
343  BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 5);
344  }
345  {
346  // account_info with the "signer_lists" argument.
347  auto const info = env.rpc("json2", withSigners);
348  BEAST_EXPECT(
349  info.isMember(jss::result) &&
350  info[jss::result].isMember(jss::account_data));
351  auto const& data = info[jss::result][jss::account_data];
352  BEAST_EXPECT(data.isMember(jss::signer_lists));
353  auto const& signerLists = data[jss::signer_lists];
354  BEAST_EXPECT(signerLists.isArray());
355  BEAST_EXPECT(signerLists.size() == 0);
356  BEAST_EXPECT(
357  info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
358  BEAST_EXPECT(
359  info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
360  BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
361  }
362  {
363  // Do both of the above as a batch job
364  auto const info = env.rpc(
365  "json2", '[' + withoutSigners + ", " + withSigners + ']');
366  BEAST_EXPECT(
367  info[0u].isMember(jss::result) &&
368  info[0u][jss::result].isMember(jss::account_data));
369  BEAST_EXPECT(!info[0u][jss::result][jss::account_data].isMember(
370  jss::signer_lists));
371  BEAST_EXPECT(
372  info[0u].isMember(jss::jsonrpc) &&
373  info[0u][jss::jsonrpc] == "2.0");
374  BEAST_EXPECT(
375  info[0u].isMember(jss::ripplerpc) &&
376  info[0u][jss::ripplerpc] == "2.0");
377  BEAST_EXPECT(info[0u].isMember(jss::id) && info[0u][jss::id] == 5);
378 
379  BEAST_EXPECT(
380  info[1u].isMember(jss::result) &&
381  info[1u][jss::result].isMember(jss::account_data));
382  auto const& data = info[1u][jss::result][jss::account_data];
383  BEAST_EXPECT(data.isMember(jss::signer_lists));
384  auto const& signerLists = data[jss::signer_lists];
385  BEAST_EXPECT(signerLists.isArray());
386  BEAST_EXPECT(signerLists.size() == 0);
387  BEAST_EXPECT(
388  info[1u].isMember(jss::jsonrpc) &&
389  info[1u][jss::jsonrpc] == "2.0");
390  BEAST_EXPECT(
391  info[1u].isMember(jss::ripplerpc) &&
392  info[1u][jss::ripplerpc] == "2.0");
393  BEAST_EXPECT(info[1u].isMember(jss::id) && info[1u][jss::id] == 6);
394  }
395 
396  // Give alice a SignerList.
397  Account const bogie{"bogie"};
398 
399  Json::Value const smallSigners = signers(alice, 2, {{bogie, 3}});
400  env(smallSigners);
401  {
402  // account_info without the "signer_lists" argument.
403  auto const info = env.rpc("json2", withoutSigners);
404  BEAST_EXPECT(
405  info.isMember(jss::result) &&
406  info[jss::result].isMember(jss::account_data));
407  BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(
408  jss::signer_lists));
409  BEAST_EXPECT(
410  info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
411  BEAST_EXPECT(
412  info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
413  BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 5);
414  }
415  {
416  // account_info with the "signer_lists" argument.
417  auto const info = env.rpc("json2", withSigners);
418  BEAST_EXPECT(
419  info.isMember(jss::result) &&
420  info[jss::result].isMember(jss::account_data));
421  auto const& data = info[jss::result][jss::account_data];
422  BEAST_EXPECT(data.isMember(jss::signer_lists));
423  auto const& signerLists = data[jss::signer_lists];
424  BEAST_EXPECT(signerLists.isArray());
425  BEAST_EXPECT(signerLists.size() == 1);
426  auto const& signers = signerLists[0u];
427  BEAST_EXPECT(signers.isObject());
428  BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 2);
429  auto const& signerEntries = signers[sfSignerEntries.jsonName];
430  BEAST_EXPECT(signerEntries.size() == 1);
431  auto const& entry0 = signerEntries[0u][sfSignerEntry.jsonName];
432  BEAST_EXPECT(entry0[sfSignerWeight.jsonName] == 3);
433  BEAST_EXPECT(
434  info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
435  BEAST_EXPECT(
436  info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
437  BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
438  }
439 
440  // Give alice a big signer list
441  Account const demon{"demon"};
442  Account const ghost{"ghost"};
443  Account const haunt{"haunt"};
444  Account const jinni{"jinni"};
445  Account const phase{"phase"};
446  Account const shade{"shade"};
447  Account const spook{"spook"};
448 
449  Json::Value const bigSigners = signers(
450  alice,
451  4,
452  {
453  {bogie, 1},
454  {demon, 1},
455  {ghost, 1},
456  {haunt, 1},
457  {jinni, 1},
458  {phase, 1},
459  {shade, 1},
460  {spook, 1},
461  });
462  env(bigSigners);
463  {
464  // account_info with the "signer_lists" argument.
465  auto const info = env.rpc("json2", withSigners);
466  BEAST_EXPECT(
467  info.isMember(jss::result) &&
468  info[jss::result].isMember(jss::account_data));
469  auto const& data = info[jss::result][jss::account_data];
470  BEAST_EXPECT(data.isMember(jss::signer_lists));
471  auto const& signerLists = data[jss::signer_lists];
472  BEAST_EXPECT(signerLists.isArray());
473  BEAST_EXPECT(signerLists.size() == 1);
474  auto const& signers = signerLists[0u];
475  BEAST_EXPECT(signers.isObject());
476  BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 4);
477  auto const& signerEntries = signers[sfSignerEntries.jsonName];
478  BEAST_EXPECT(signerEntries.size() == 8);
479  for (unsigned i = 0u; i < 8; ++i)
480  {
481  auto const& entry = signerEntries[i][sfSignerEntry.jsonName];
482  BEAST_EXPECT(entry.size() == 2);
483  BEAST_EXPECT(entry.isMember(sfAccount.jsonName));
484  BEAST_EXPECT(entry[sfSignerWeight.jsonName] == 1);
485  }
486  BEAST_EXPECT(
487  info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
488  BEAST_EXPECT(
489  info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
490  BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
491  }
492  }
493 
494  // gRPC stuff
496  {
497  public:
498  org::xrpl::rpc::v1::GetAccountInfoRequest request;
499  org::xrpl::rpc::v1::GetAccountInfoResponse reply;
500 
501  explicit GetAccountInfoClient(std::string const& port)
502  : GRPCTestClientBase(port)
503  {
504  }
505 
506  void
508  {
509  status = stub_->GetAccountInfo(&context, request, &reply);
510  }
511  };
512 
513  void
515  {
516  testcase("gRPC simple");
517 
518  using namespace jtx;
520  std::string grpcPort = *(*config)["port_grpc"].get<std::string>("port");
521  Env env(*this, std::move(config));
522  Account const alice{"alice"};
523  env.fund(drops(1000 * 1000 * 1000), alice);
524 
525  {
526  // most simple case
527  GetAccountInfoClient client(grpcPort);
528  client.request.mutable_account()->set_address(alice.human());
529  client.GetAccountInfo();
530  if (!BEAST_EXPECT(client.status.ok()))
531  {
532  return;
533  }
534  BEAST_EXPECT(
535  client.reply.account_data().account().value().address() ==
536  alice.human());
537  }
538  {
539  GetAccountInfoClient client(grpcPort);
540  client.request.mutable_account()->set_address(alice.human());
541  client.request.set_queue(true);
542  client.request.mutable_ledger()->set_sequence(3);
543  client.GetAccountInfo();
544  if (!BEAST_EXPECT(client.status.ok()))
545  return;
546  BEAST_EXPECT(
547  client.reply.account_data()
548  .balance()
549  .value()
550  .xrp_amount()
551  .drops() == 1000 * 1000 * 1000);
552  BEAST_EXPECT(
553  client.reply.account_data().account().value().address() ==
554  alice.human());
555  BEAST_EXPECT(
556  client.reply.account_data().sequence().value() ==
557  env.seq(alice));
558  BEAST_EXPECT(client.reply.queue_data().txn_count() == 0);
559  }
560  }
561 
562  void
564  {
565  testcase("gRPC errors");
566 
567  using namespace jtx;
569  std::string grpcPort = *(*config)["port_grpc"].get<std::string>("port");
570  Env env(*this, std::move(config));
571  auto getClient = [&grpcPort]() {
572  return GetAccountInfoClient(grpcPort);
573  };
574  Account const alice{"alice"};
575  env.fund(drops(1000 * 1000 * 1000), alice);
576 
577  {
578  // bad address
579  auto client = getClient();
580  client.request.mutable_account()->set_address("deadbeef");
581  client.GetAccountInfo();
582  BEAST_EXPECT(!client.status.ok());
583  }
584  {
585  // no account
586  Account const bogie{"bogie"};
587  auto client = getClient();
588  client.request.mutable_account()->set_address(bogie.human());
589  client.GetAccountInfo();
590  BEAST_EXPECT(!client.status.ok());
591  }
592  {
593  // bad ledger_index
594  auto client = getClient();
595  client.request.mutable_account()->set_address(alice.human());
596  client.request.mutable_ledger()->set_sequence(0);
597  client.GetAccountInfo();
598  BEAST_EXPECT(!client.status.ok());
599  }
600  }
601 
602  void
604  {
605  testcase("gRPC singer lists");
606 
607  using namespace jtx;
609  std::string grpcPort = *(*config)["port_grpc"].get<std::string>("port");
610  Env env(*this, std::move(config));
611  auto getClient = [&grpcPort]() {
612  return GetAccountInfoClient(grpcPort);
613  };
614 
615  Account const alice{"alice"};
616  env.fund(drops(1000 * 1000 * 1000), alice);
617 
618  {
619  auto client = getClient();
620  client.request.mutable_account()->set_address(alice.human());
621  client.request.set_signer_lists(true);
622  client.GetAccountInfo();
623  if (!BEAST_EXPECT(client.status.ok()))
624  return;
625  BEAST_EXPECT(client.reply.signer_list().signer_entries_size() == 0);
626  }
627 
628  // Give alice a SignerList.
629  Account const bogie{"bogie"};
630  Json::Value const smallSigners = signers(alice, 2, {{bogie, 3}});
631  env(smallSigners);
632  {
633  auto client = getClient();
634  client.request.mutable_account()->set_address(alice.human());
635  client.request.set_signer_lists(false);
636  client.GetAccountInfo();
637  if (!BEAST_EXPECT(client.status.ok()))
638  return;
639  BEAST_EXPECT(client.reply.signer_list().signer_entries_size() == 0);
640  }
641  {
642  auto client = getClient();
643  client.request.mutable_account()->set_address(alice.human());
644  client.request.set_signer_lists(true);
645  client.GetAccountInfo();
646  if (!BEAST_EXPECT(client.status.ok()))
647  {
648  return;
649  }
650  BEAST_EXPECT(
651  client.reply.account_data().owner_count().value() == 1);
652  BEAST_EXPECT(client.reply.signer_list().signer_entries_size() == 1);
653  }
654 
655  // Give alice a big signer list
656  Account const demon{"demon"};
657  Account const ghost{"ghost"};
658  Account const haunt{"haunt"};
659  Account const jinni{"jinni"};
660  Account const phase{"phase"};
661  Account const shade{"shade"};
662  Account const spook{"spook"};
663  Json::Value const bigSigners = signers(
664  alice,
665  4,
666  {
667  {bogie, 1},
668  {demon, 1},
669  {ghost, 1},
670  {haunt, 1},
671  {jinni, 1},
672  {phase, 1},
673  {shade, 1},
674  {spook, 1},
675  });
676  env(bigSigners);
677 
678  std::set<std::string> accounts;
679  accounts.insert(bogie.human());
680  accounts.insert(demon.human());
681  accounts.insert(ghost.human());
682  accounts.insert(haunt.human());
683  accounts.insert(jinni.human());
684  accounts.insert(phase.human());
685  accounts.insert(shade.human());
686  accounts.insert(spook.human());
687  {
688  auto client = getClient();
689  client.request.mutable_account()->set_address(alice.human());
690  client.request.set_signer_lists(true);
691  client.GetAccountInfo();
692  if (!BEAST_EXPECT(client.status.ok()))
693  {
694  return;
695  }
696  BEAST_EXPECT(
697  client.reply.account_data().owner_count().value() == 1);
698  auto& signerList = client.reply.signer_list();
699  BEAST_EXPECT(signerList.signer_quorum().value() == 4);
700  BEAST_EXPECT(signerList.signer_entries_size() == 8);
701  for (int i = 0; i < 8; ++i)
702  {
703  BEAST_EXPECT(
704  signerList.signer_entries(i).signer_weight().value() == 1);
705  BEAST_EXPECT(
706  accounts.erase(signerList.signer_entries(i)
707  .account()
708  .value()
709  .address()) == 1);
710  }
711  BEAST_EXPECT(accounts.size() == 0);
712  }
713  }
714 
715  void
716  run() override
717  {
718  testErrors();
719  testSignerLists();
722  testSimpleGrpc();
723  testErrorsGrpc();
725  }
726 };
727 
728 BEAST_DEFINE_TESTSUITE(AccountInfo, app, ripple);
729 
730 } // namespace test
731 } // namespace ripple
ripple::sfSignerWeight
const SF_UINT16 sfSignerWeight
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
std::string
STL class.
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
ripple::test::AccountInfo_test::run
void run() override
Definition: AccountInfo_test.cpp:716
ripple::test::AccountInfo_test::testSignerListsV2
void testSignerListsV2()
Definition: AccountInfo_test.cpp:306
ripple::test::GRPCTestClientBase::stub_
std::unique_ptr< org::xrpl::rpc::v1::XRPLedgerAPIService::Stub > stub_
Definition: GRPCTestClientBase.h:44
std::set::size
T size(T... args)
ripple::test::jtx::addGrpcConfig
std::unique_ptr< Config > addGrpcConfig(std::unique_ptr< Config >)
add a grpc address and port to config
Definition: envconfig.cpp:113
ripple::test::AccountInfo_test::GetAccountInfoClient::request
org::xrpl::rpc::v1::GetAccountInfoRequest request
Definition: AccountInfo_test.cpp:498
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:49
ripple::test::AccountInfo_test::testErrorsGrpc
void testErrorsGrpc()
Definition: AccountInfo_test.cpp:563
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:133
ripple::test::GRPCTestClientBase::status
grpc::Status status
Definition: GRPCTestClientBase.h:42
ripple::test::GRPCTestClientBase
Definition: GRPCTestClientBase.h:29
ripple::sfSignerQuorum
const SF_UINT32 sfSignerQuorum
ripple::test::AccountInfo_test::GetAccountInfoClient::GetAccountInfoClient
GetAccountInfoClient(std::string const &port)
Definition: AccountInfo_test.cpp:501
ripple::test::AccountInfo_test
Definition: AccountInfo_test.cpp:33
ripple::test::AccountInfo_test::testSignerListsGrpc
void testSignerListsGrpc()
Definition: AccountInfo_test.cpp:603
ripple::test::AccountInfo_test::GetAccountInfoClient::reply
org::xrpl::rpc::v1::GetAccountInfoResponse reply
Definition: AccountInfo_test.cpp:499
std::set::erase
T erase(T... args)
ripple::test::AccountInfo_test::testSimpleGrpc
void testSimpleGrpc()
Definition: AccountInfo_test.cpp:514
ripple::test::AccountInfo_test::testSignerLists
void testSignerLists()
Definition: AccountInfo_test.cpp:72
ripple::test::AccountInfo_test::GetAccountInfoClient
Definition: AccountInfo_test.cpp:495
ripple::sfSignerEntry
const SField sfSignerEntry
ripple::test::GRPCTestClientBase::context
grpc::ClientContext context
Definition: GRPCTestClientBase.h:43
ripple::test::AccountInfo_test::GetAccountInfoClient::GetAccountInfo
void GetAccountInfo()
Definition: AccountInfo_test.cpp:507
ripple::sfSignerEntries
const SField sfSignerEntries
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
std::set::insert
T insert(T... args)
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:225
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::sfAccount
const SF_ACCOUNT sfAccount
std::unique_ptr
STL class.
ripple::test::AccountInfo_test::testErrors
void testErrors()
Definition: AccountInfo_test.cpp:37
std::set< std::string >
ripple::test::AccountInfo_test::testSignerListsApiVersion2
void testSignerListsApiVersion2()
Definition: AccountInfo_test.cpp:193
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
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)