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 string.
50  auto const info = env.rpc(
51  "json",
52  "account_info",
53  "{\"account\": "
54  "\"n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV\"}");
55  BEAST_EXPECT(
56  info[jss::result][jss::error_code] == rpcACT_MALFORMED);
57  BEAST_EXPECT(
58  info[jss::result][jss::error_message] == "Account malformed.");
59  }
60  {
61  // account_info with an account that's not in the ledger.
62  Account const bogie{"bogie"};
63  auto const info = env.rpc(
64  "json",
65  "account_info",
66  R"({ "account": ")" + bogie.human() + R"("})");
67  BEAST_EXPECT(
68  info[jss::result][jss::error_code] == rpcACT_NOT_FOUND);
69  BEAST_EXPECT(
70  info[jss::result][jss::error_message] == "Account not found.");
71  }
72  {
73  // Cannot use a seed as account
74  auto const info =
75  env.rpc("json", "account_info", R"({"account": "foo"})");
76  BEAST_EXPECT(
77  info[jss::result][jss::error_code] == rpcACT_MALFORMED);
78  BEAST_EXPECT(
79  info[jss::result][jss::error_message] == "Account malformed.");
80  }
81  }
82 
83  // Test the "signer_lists" argument in account_info.
84  void
85  testSignerLists()
86  {
87  using namespace jtx;
88  Env env(*this);
89  Account const alice{"alice"};
90  env.fund(XRP(1000), alice);
91 
92  auto const withoutSigners =
93  std::string("{ ") + "\"account\": \"" + alice.human() + "\"}";
94 
95  auto const withSigners = std::string("{ ") + "\"account\": \"" +
96  alice.human() + "\", " + "\"signer_lists\": true }";
97 
98  // Alice has no SignerList yet.
99  {
100  // account_info without the "signer_lists" argument.
101  auto const info = env.rpc("json", "account_info", withoutSigners);
102  BEAST_EXPECT(
103  info.isMember(jss::result) &&
104  info[jss::result].isMember(jss::account_data));
105  BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(
106  jss::signer_lists));
107  }
108  {
109  // account_info with the "signer_lists" argument.
110  auto const info = env.rpc("json", "account_info", withSigners);
111  BEAST_EXPECT(
112  info.isMember(jss::result) &&
113  info[jss::result].isMember(jss::account_data));
114  auto const& data = info[jss::result][jss::account_data];
115  BEAST_EXPECT(data.isMember(jss::signer_lists));
116  auto const& signerLists = data[jss::signer_lists];
117  BEAST_EXPECT(signerLists.isArray());
118  BEAST_EXPECT(signerLists.size() == 0);
119  }
120 
121  // Give alice a SignerList.
122  Account const bogie{"bogie"};
123 
124  Json::Value const smallSigners = signers(alice, 2, {{bogie, 3}});
125  env(smallSigners);
126  {
127  // account_info without the "signer_lists" argument.
128  auto const info = env.rpc("json", "account_info", withoutSigners);
129  BEAST_EXPECT(
130  info.isMember(jss::result) &&
131  info[jss::result].isMember(jss::account_data));
132  BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(
133  jss::signer_lists));
134  }
135  {
136  // account_info with the "signer_lists" argument.
137  auto const info = env.rpc("json", "account_info", withSigners);
138  BEAST_EXPECT(
139  info.isMember(jss::result) &&
140  info[jss::result].isMember(jss::account_data));
141  auto const& data = info[jss::result][jss::account_data];
142  BEAST_EXPECT(data.isMember(jss::signer_lists));
143  auto const& signerLists = data[jss::signer_lists];
144  BEAST_EXPECT(signerLists.isArray());
145  BEAST_EXPECT(signerLists.size() == 1);
146  auto const& signers = signerLists[0u];
147  BEAST_EXPECT(signers.isObject());
148  BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 2);
149  auto const& signerEntries = signers[sfSignerEntries.jsonName];
150  BEAST_EXPECT(signerEntries.size() == 1);
151  auto const& entry0 = signerEntries[0u][sfSignerEntry.jsonName];
152  BEAST_EXPECT(entry0[sfSignerWeight.jsonName] == 3);
153  }
154 
155  // Give alice a big signer list
156  Account const demon{"demon"};
157  Account const ghost{"ghost"};
158  Account const haunt{"haunt"};
159  Account const jinni{"jinni"};
160  Account const phase{"phase"};
161  Account const shade{"shade"};
162  Account const spook{"spook"};
163 
164  Json::Value const bigSigners = signers(
165  alice,
166  4,
167  {
168  {bogie, 1},
169  {demon, 1},
170  {ghost, 1},
171  {haunt, 1},
172  {jinni, 1},
173  {phase, 1},
174  {shade, 1},
175  {spook, 1},
176  });
177  env(bigSigners);
178  {
179  // account_info with the "signer_lists" argument.
180  auto const info = env.rpc("json", "account_info", withSigners);
181  BEAST_EXPECT(
182  info.isMember(jss::result) &&
183  info[jss::result].isMember(jss::account_data));
184  auto const& data = info[jss::result][jss::account_data];
185  BEAST_EXPECT(data.isMember(jss::signer_lists));
186  auto const& signerLists = data[jss::signer_lists];
187  BEAST_EXPECT(signerLists.isArray());
188  BEAST_EXPECT(signerLists.size() == 1);
189  auto const& signers = signerLists[0u];
190  BEAST_EXPECT(signers.isObject());
191  BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 4);
192  auto const& signerEntries = signers[sfSignerEntries.jsonName];
193  BEAST_EXPECT(signerEntries.size() == 8);
194  for (unsigned i = 0u; i < 8; ++i)
195  {
196  auto const& entry = signerEntries[i][sfSignerEntry.jsonName];
197  BEAST_EXPECT(entry.size() == 2);
198  BEAST_EXPECT(entry.isMember(sfAccount.jsonName));
199  BEAST_EXPECT(entry[sfSignerWeight.jsonName] == 1);
200  }
201  }
202  }
203 
204  // Test the "signer_lists" argument in account_info, with api_version 2.
205  void
206  testSignerListsApiVersion2()
207  {
208  using namespace jtx;
209  Env env{*this};
210  Account const alice{"alice"};
211  env.fund(XRP(1000), alice);
212 
213  auto const withoutSigners = std::string("{ ") +
214  "\"api_version\": 2, \"account\": \"" + alice.human() + "\"}";
215 
216  auto const withSigners = std::string("{ ") +
217  "\"api_version\": 2, \"account\": \"" + alice.human() + "\", " +
218  "\"signer_lists\": true }";
219 
220  auto const withSignersAsString = std::string("{ ") +
221  "\"api_version\": 2, \"account\": \"" + alice.human() + "\", " +
222  "\"signer_lists\": asdfggh }";
223 
224  // Alice has no SignerList yet.
225  {
226  // account_info without the "signer_lists" argument.
227  auto const info = env.rpc("json", "account_info", withoutSigners);
228  BEAST_EXPECT(info.isMember(jss::result));
229  BEAST_EXPECT(!info[jss::result].isMember(jss::signer_lists));
230  }
231  {
232  // account_info with the "signer_lists" argument.
233  auto const info = env.rpc("json", "account_info", withSigners);
234  BEAST_EXPECT(info.isMember(jss::result));
235  auto const& data = info[jss::result];
236  BEAST_EXPECT(data.isMember(jss::signer_lists));
237  auto const& signerLists = data[jss::signer_lists];
238  BEAST_EXPECT(signerLists.isArray());
239  BEAST_EXPECT(signerLists.size() == 0);
240  }
241 
242  // Give alice a SignerList.
243  Account const bogie{"bogie"};
244 
245  Json::Value const smallSigners = signers(alice, 2, {{bogie, 3}});
246  env(smallSigners);
247  {
248  // account_info without the "signer_lists" argument.
249  auto const info = env.rpc("json", "account_info", withoutSigners);
250  BEAST_EXPECT(info.isMember(jss::result));
251  BEAST_EXPECT(!info[jss::result].isMember(jss::signer_lists));
252  }
253  {
254  // account_info with the "signer_lists" argument.
255  auto const info = env.rpc("json", "account_info", withSigners);
256  BEAST_EXPECT(info.isMember(jss::result));
257  auto const& data = info[jss::result];
258  BEAST_EXPECT(data.isMember(jss::signer_lists));
259  auto const& signerLists = data[jss::signer_lists];
260  BEAST_EXPECT(signerLists.isArray());
261  BEAST_EXPECT(signerLists.size() == 1);
262  auto const& signers = signerLists[0u];
263  BEAST_EXPECT(signers.isObject());
264  BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 2);
265  auto const& signerEntries = signers[sfSignerEntries.jsonName];
266  BEAST_EXPECT(signerEntries.size() == 1);
267  auto const& entry0 = signerEntries[0u][sfSignerEntry.jsonName];
268  BEAST_EXPECT(entry0[sfSignerWeight.jsonName] == 3);
269  }
270  {
271  // account_info with "signer_lists" as not bool should error out
272  auto const info =
273  env.rpc("json", "account_info", withSignersAsString);
274  BEAST_EXPECT(info[jss::status] == "error");
275  BEAST_EXPECT(info[jss::error] == "invalidParams");
276  }
277 
278  // Give alice a big signer list
279  Account const demon{"demon"};
280  Account const ghost{"ghost"};
281  Account const haunt{"haunt"};
282  Account const jinni{"jinni"};
283  Account const phase{"phase"};
284  Account const shade{"shade"};
285  Account const spook{"spook"};
286 
287  Json::Value const bigSigners = signers(
288  alice,
289  4,
290  {
291  {bogie, 1},
292  {demon, 1},
293  {ghost, 1},
294  {haunt, 1},
295  {jinni, 1},
296  {phase, 1},
297  {shade, 1},
298  {spook, 1},
299  });
300  env(bigSigners);
301  {
302  // account_info with the "signer_lists" argument.
303  auto const info = env.rpc("json", "account_info", withSigners);
304  BEAST_EXPECT(info.isMember(jss::result));
305  auto const& data = info[jss::result];
306  BEAST_EXPECT(data.isMember(jss::signer_lists));
307  auto const& signerLists = data[jss::signer_lists];
308  BEAST_EXPECT(signerLists.isArray());
309  BEAST_EXPECT(signerLists.size() == 1);
310  auto const& signers = signerLists[0u];
311  BEAST_EXPECT(signers.isObject());
312  BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 4);
313  auto const& signerEntries = signers[sfSignerEntries.jsonName];
314  BEAST_EXPECT(signerEntries.size() == 8);
315  for (unsigned i = 0u; i < 8; ++i)
316  {
317  auto const& entry = signerEntries[i][sfSignerEntry.jsonName];
318  BEAST_EXPECT(entry.size() == 2);
319  BEAST_EXPECT(entry.isMember(sfAccount.jsonName));
320  BEAST_EXPECT(entry[sfSignerWeight.jsonName] == 1);
321  }
322  }
323  }
324 
325  // Test the "signer_lists" argument in account_info, version 2 API.
326  void
327  testSignerListsV2()
328  {
329  using namespace jtx;
330  Env env(*this);
331  Account const alice{"alice"};
332  env.fund(XRP(1000), alice);
333 
334  auto const withoutSigners = std::string("{ ") +
335  "\"jsonrpc\": \"2.0\", "
336  "\"ripplerpc\": \"2.0\", "
337  "\"id\": 5, "
338  "\"method\": \"account_info\", "
339  "\"params\": { "
340  "\"account\": \"" +
341  alice.human() + "\"}}";
342 
343  auto const withSigners = std::string("{ ") +
344  "\"jsonrpc\": \"2.0\", "
345  "\"ripplerpc\": \"2.0\", "
346  "\"id\": 6, "
347  "\"method\": \"account_info\", "
348  "\"params\": { "
349  "\"account\": \"" +
350  alice.human() + "\", " + "\"signer_lists\": true }}";
351  // Alice has no SignerList yet.
352  {
353  // account_info without the "signer_lists" argument.
354  auto const info = env.rpc("json2", withoutSigners);
355  BEAST_EXPECT(
356  info.isMember(jss::result) &&
357  info[jss::result].isMember(jss::account_data));
358  BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(
359  jss::signer_lists));
360  BEAST_EXPECT(
361  info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
362  BEAST_EXPECT(
363  info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
364  BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 5);
365  }
366  {
367  // account_info with the "signer_lists" argument.
368  auto const info = env.rpc("json2", withSigners);
369  BEAST_EXPECT(
370  info.isMember(jss::result) &&
371  info[jss::result].isMember(jss::account_data));
372  auto const& data = info[jss::result][jss::account_data];
373  BEAST_EXPECT(data.isMember(jss::signer_lists));
374  auto const& signerLists = data[jss::signer_lists];
375  BEAST_EXPECT(signerLists.isArray());
376  BEAST_EXPECT(signerLists.size() == 0);
377  BEAST_EXPECT(
378  info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
379  BEAST_EXPECT(
380  info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
381  BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
382  }
383  {
384  // Do both of the above as a batch job
385  auto const info = env.rpc(
386  "json2", '[' + withoutSigners + ", " + withSigners + ']');
387  BEAST_EXPECT(
388  info[0u].isMember(jss::result) &&
389  info[0u][jss::result].isMember(jss::account_data));
390  BEAST_EXPECT(!info[0u][jss::result][jss::account_data].isMember(
391  jss::signer_lists));
392  BEAST_EXPECT(
393  info[0u].isMember(jss::jsonrpc) &&
394  info[0u][jss::jsonrpc] == "2.0");
395  BEAST_EXPECT(
396  info[0u].isMember(jss::ripplerpc) &&
397  info[0u][jss::ripplerpc] == "2.0");
398  BEAST_EXPECT(info[0u].isMember(jss::id) && info[0u][jss::id] == 5);
399 
400  BEAST_EXPECT(
401  info[1u].isMember(jss::result) &&
402  info[1u][jss::result].isMember(jss::account_data));
403  auto const& data = info[1u][jss::result][jss::account_data];
404  BEAST_EXPECT(data.isMember(jss::signer_lists));
405  auto const& signerLists = data[jss::signer_lists];
406  BEAST_EXPECT(signerLists.isArray());
407  BEAST_EXPECT(signerLists.size() == 0);
408  BEAST_EXPECT(
409  info[1u].isMember(jss::jsonrpc) &&
410  info[1u][jss::jsonrpc] == "2.0");
411  BEAST_EXPECT(
412  info[1u].isMember(jss::ripplerpc) &&
413  info[1u][jss::ripplerpc] == "2.0");
414  BEAST_EXPECT(info[1u].isMember(jss::id) && info[1u][jss::id] == 6);
415  }
416 
417  // Give alice a SignerList.
418  Account const bogie{"bogie"};
419 
420  Json::Value const smallSigners = signers(alice, 2, {{bogie, 3}});
421  env(smallSigners);
422  {
423  // account_info without the "signer_lists" argument.
424  auto const info = env.rpc("json2", withoutSigners);
425  BEAST_EXPECT(
426  info.isMember(jss::result) &&
427  info[jss::result].isMember(jss::account_data));
428  BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(
429  jss::signer_lists));
430  BEAST_EXPECT(
431  info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
432  BEAST_EXPECT(
433  info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
434  BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 5);
435  }
436  {
437  // account_info with the "signer_lists" argument.
438  auto const info = env.rpc("json2", withSigners);
439  BEAST_EXPECT(
440  info.isMember(jss::result) &&
441  info[jss::result].isMember(jss::account_data));
442  auto const& data = info[jss::result][jss::account_data];
443  BEAST_EXPECT(data.isMember(jss::signer_lists));
444  auto const& signerLists = data[jss::signer_lists];
445  BEAST_EXPECT(signerLists.isArray());
446  BEAST_EXPECT(signerLists.size() == 1);
447  auto const& signers = signerLists[0u];
448  BEAST_EXPECT(signers.isObject());
449  BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 2);
450  auto const& signerEntries = signers[sfSignerEntries.jsonName];
451  BEAST_EXPECT(signerEntries.size() == 1);
452  auto const& entry0 = signerEntries[0u][sfSignerEntry.jsonName];
453  BEAST_EXPECT(entry0[sfSignerWeight.jsonName] == 3);
454  BEAST_EXPECT(
455  info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
456  BEAST_EXPECT(
457  info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
458  BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
459  }
460 
461  // Give alice a big signer list
462  Account const demon{"demon"};
463  Account const ghost{"ghost"};
464  Account const haunt{"haunt"};
465  Account const jinni{"jinni"};
466  Account const phase{"phase"};
467  Account const shade{"shade"};
468  Account const spook{"spook"};
469 
470  Json::Value const bigSigners = signers(
471  alice,
472  4,
473  {
474  {bogie, 1},
475  {demon, 1},
476  {ghost, 1},
477  {haunt, 1},
478  {jinni, 1},
479  {phase, 1},
480  {shade, 1},
481  {spook, 1},
482  });
483  env(bigSigners);
484  {
485  // account_info with the "signer_lists" argument.
486  auto const info = env.rpc("json2", withSigners);
487  BEAST_EXPECT(
488  info.isMember(jss::result) &&
489  info[jss::result].isMember(jss::account_data));
490  auto const& data = info[jss::result][jss::account_data];
491  BEAST_EXPECT(data.isMember(jss::signer_lists));
492  auto const& signerLists = data[jss::signer_lists];
493  BEAST_EXPECT(signerLists.isArray());
494  BEAST_EXPECT(signerLists.size() == 1);
495  auto const& signers = signerLists[0u];
496  BEAST_EXPECT(signers.isObject());
497  BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 4);
498  auto const& signerEntries = signers[sfSignerEntries.jsonName];
499  BEAST_EXPECT(signerEntries.size() == 8);
500  for (unsigned i = 0u; i < 8; ++i)
501  {
502  auto const& entry = signerEntries[i][sfSignerEntry.jsonName];
503  BEAST_EXPECT(entry.size() == 2);
504  BEAST_EXPECT(entry.isMember(sfAccount.jsonName));
505  BEAST_EXPECT(entry[sfSignerWeight.jsonName] == 1);
506  }
507  BEAST_EXPECT(
508  info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
509  BEAST_EXPECT(
510  info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
511  BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
512  }
513  }
514 
515  void
516  testAccountFlags(FeatureBitset const& features)
517  {
518  using namespace jtx;
519 
520  Env env(*this, features);
521  Account const alice{"alice"};
522  Account const bob{"bob"};
523  env.fund(XRP(1000), alice, bob);
524 
525  auto getAccountFlag = [&env](
526  std::string_view fName,
527  Account const& account) {
528  auto const info = env.rpc(
529  "json",
530  "account_info",
531  R"({"account" : ")" + account.human() + R"("})");
532 
534  if (info[jss::result][jss::status] == "success" &&
535  info[jss::result][jss::account_flags].isMember(fName.data()))
536  res.emplace(info[jss::result][jss::account_flags][fName.data()]
537  .asBool());
538 
539  return res;
540  };
541 
542  static constexpr std::
543  array<std::pair<std::string_view, std::uint32_t>, 7>
544  asFlags{
545  {{"defaultRipple", asfDefaultRipple},
546  {"depositAuth", asfDepositAuth},
547  {"disallowIncomingXRP", asfDisallowXRP},
548  {"globalFreeze", asfGlobalFreeze},
549  {"noFreeze", asfNoFreeze},
550  {"requireAuthorization", asfRequireAuth},
551  {"requireDestinationTag", asfRequireDest}}};
552 
553  for (auto& asf : asFlags)
554  {
555  // Clear a flag and check that account_info returns results
556  // as expected
557  env(fclear(alice, asf.second));
558  env.close();
559  auto const f1 = getAccountFlag(asf.first, alice);
560  BEAST_EXPECT(f1.has_value());
561  BEAST_EXPECT(!f1.value());
562 
563  // Set a flag and check that account_info returns results
564  // as expected
565  env(fset(alice, asf.second));
566  env.close();
567  auto const f2 = getAccountFlag(asf.first, alice);
568  BEAST_EXPECT(f2.has_value());
569  BEAST_EXPECT(f2.value());
570  }
571 
572  static constexpr std::
573  array<std::pair<std::string_view, std::uint32_t>, 4>
574  disallowIncomingFlags{
575  {{"disallowIncomingCheck", asfDisallowIncomingCheck},
576  {"disallowIncomingNFTokenOffer",
578  {"disallowIncomingPayChan", asfDisallowIncomingPayChan},
579  {"disallowIncomingTrustline",
581 
582  if (features[featureDisallowIncoming])
583  {
584  for (auto& asf : disallowIncomingFlags)
585  {
586  // Clear a flag and check that account_info returns results
587  // as expected
588  env(fclear(alice, asf.second));
589  env.close();
590  auto const f1 = getAccountFlag(asf.first, alice);
591  BEAST_EXPECT(f1.has_value());
592  BEAST_EXPECT(!f1.value());
593 
594  // Set a flag and check that account_info returns results
595  // as expected
596  env(fset(alice, asf.second));
597  env.close();
598  auto const f2 = getAccountFlag(asf.first, alice);
599  BEAST_EXPECT(f2.has_value());
600  BEAST_EXPECT(f2.value());
601  }
602  }
603  else
604  {
605  for (auto& asf : disallowIncomingFlags)
606  {
607  BEAST_EXPECT(!getAccountFlag(asf.first, alice));
608  }
609  }
610 
612  allowTrustLineClawbackFlag{
613  "allowTrustLineClawback", asfAllowTrustLineClawback};
614 
615  if (features[featureClawback])
616  {
617  // must use bob's account because alice has noFreeze set
618  auto const f1 =
619  getAccountFlag(allowTrustLineClawbackFlag.first, bob);
620  BEAST_EXPECT(f1.has_value());
621  BEAST_EXPECT(!f1.value());
622 
623  // Set allowTrustLineClawback
624  env(fset(bob, allowTrustLineClawbackFlag.second));
625  env.close();
626  auto const f2 =
627  getAccountFlag(allowTrustLineClawbackFlag.first, bob);
628  BEAST_EXPECT(f2.has_value());
629  BEAST_EXPECT(f2.value());
630  }
631  else
632  {
633  BEAST_EXPECT(
634  !getAccountFlag(allowTrustLineClawbackFlag.first, bob));
635  }
636  }
637 
638  void
639  run() override
640  {
641  testErrors();
642  testSignerLists();
643  testSignerListsApiVersion2();
644  testSignerListsV2();
645 
646  FeatureBitset const allFeatures{
648  testAccountFlags(allFeatures);
649  testAccountFlags(allFeatures - featureDisallowIncoming);
650  testAccountFlags(
651  allFeatures - featureDisallowIncoming - featureClawback);
652  }
653 };
654 
655 BEAST_DEFINE_TESTSUITE(AccountInfo, app, ripple);
656 
657 } // namespace test
658 } // 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
ripple::asfDisallowXRP
constexpr std::uint32_t asfDisallowXRP
Definition: TxFlags.h:76
ripple::asfDepositAuth
constexpr std::uint32_t asfDepositAuth
Definition: TxFlags.h:82
std::string
STL class.
ripple::keylet::signers
Keylet signers(AccountID const &account) noexcept
A SignerList.
Definition: Indexes.cpp:285
ripple::test::jtx::Env::rpc
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:711
ripple::featureClawback
const uint256 featureClawback
std::string_view
STL class.
std::pair
ripple::asfNoFreeze
constexpr std::uint32_t asfNoFreeze
Definition: TxFlags.h:79
std::optional::emplace
T emplace(T... args)
ripple::asfDisallowIncomingPayChan
constexpr std::uint32_t asfDisallowIncomingPayChan
Definition: TxFlags.h:89
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:165
ripple::sfSignerQuorum
const SF_UINT32 sfSignerQuorum
ripple::asfDisallowIncomingTrustline
constexpr std::uint32_t asfDisallowIncomingTrustline
Definition: TxFlags.h:90
ripple::asfDisallowIncomingCheck
constexpr std::uint32_t asfDisallowIncomingCheck
Definition: TxFlags.h:88
ripple::featureDisallowIncoming
const uint256 featureDisallowIncoming
ripple::test::AccountInfo_test
Definition: AccountInfo_test.cpp:33
ripple::rpcACT_NOT_FOUND
@ rpcACT_NOT_FOUND
Definition: ErrorCodes.h:70
ripple::test::jtx::fset
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:28
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
ripple::test::jtx::fclear
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition: flags.h:40
ripple::sfSignerEntry
const SField sfSignerEntry
ripple::sfSignerEntries
const SField sfSignerEntries
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::rpcACT_MALFORMED
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
ripple::asfRequireAuth
constexpr std::uint32_t asfRequireAuth
Definition: TxFlags.h:75
ripple::asfDefaultRipple
constexpr std::uint32_t asfDefaultRipple
Definition: TxFlags.h:81
ripple::asfRequireDest
constexpr std::uint32_t asfRequireDest
Definition: TxFlags.h:74
ripple::asfGlobalFreeze
constexpr std::uint32_t asfGlobalFreeze
Definition: TxFlags.h:80
std::optional< bool >
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::asfAllowTrustLineClawback
constexpr std::uint32_t asfAllowTrustLineClawback
Definition: TxFlags.h:91
std::data
T data(T... args)
ripple::test::AccountInfo_test::testErrors
void testErrors()
Definition: AccountInfo_test.cpp:37
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::asfDisallowIncomingNFTokenOffer
constexpr std::uint32_t asfDisallowIncomingNFTokenOffer
Definition: TxFlags.h:87
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)