xrpld
Loading...
Searching...
No Matches
AccountInfo_test.cpp
1
2#include <test/jtx/Account.h>
3#include <test/jtx/Env.h>
4#include <test/jtx/amount.h>
5#include <test/jtx/flags.h>
6#include <test/jtx/multisign.h>
7
8#include <xrpl/beast/unit_test/suite.h>
9#include <xrpl/json/json_value.h>
10#include <xrpl/json/to_string.h>
11#include <xrpl/protocol/ErrorCodes.h>
12#include <xrpl/protocol/Feature.h>
13#include <xrpl/protocol/SField.h>
14#include <xrpl/protocol/TxFlags.h>
15#include <xrpl/protocol/jss.h>
16
17#include <array>
18#include <cstdint>
19#include <optional>
20#include <string_view>
21#include <utility>
22
23namespace xrpl::test {
24
26{
27public:
28 void
30 {
31 testcase("Errors");
32 using namespace jtx;
33 Env env(*this);
34 {
35 // account_info with no account.
36 auto const info = env.rpc("json", "account_info", "{ }");
37 BEAST_EXPECT(info[jss::result][jss::error_message] == "Missing field 'account'.");
38 }
39 {
40 // account_info with a malformed account string.
41 auto const info = env.rpc(
42 "json",
43 "account_info",
44 "{\"account\": "
45 "\"n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV\"}");
46 BEAST_EXPECT(info[jss::result][jss::error_code] == RpcActMalformed);
47 BEAST_EXPECT(info[jss::result][jss::error_message] == "Account malformed.");
48 }
49 {
50 // account_info with an account that's not in the ledger.
51 Account const bogie{"bogie"};
52 json::Value params;
53 params[jss::account] = bogie.human();
54 auto const info = env.rpc("json", "account_info", to_string(params));
55 BEAST_EXPECT(info[jss::result][jss::error_code] == RpcActNotFound);
56 BEAST_EXPECT(info[jss::result][jss::error_message] == "Account not found.");
57 }
58 {
59 // Cannot use a seed as account
60 auto const info = env.rpc("json", "account_info", R"({"account": "foo"})");
61 BEAST_EXPECT(info[jss::result][jss::error_code] == RpcActMalformed);
62 BEAST_EXPECT(info[jss::result][jss::error_message] == "Account malformed.");
63 }
64 {
65 // Cannot pass a non-string into the `account` param
66
67 auto testInvalidAccountParam = [&](auto const& param) {
68 json::Value params;
69 params[jss::account] = param;
70 auto jrr = env.rpc("json", "account_info", to_string(params))[jss::result];
71 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
72 BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'.");
73 };
74
75 testInvalidAccountParam(1);
76 testInvalidAccountParam(1.1);
77 testInvalidAccountParam(true);
78 testInvalidAccountParam(json::Value(json::ValueType::Null));
79 testInvalidAccountParam(json::Value(json::ValueType::Object));
80 testInvalidAccountParam(json::Value(json::ValueType::Array));
81 }
82 {
83 // Cannot pass a non-string into the `ident` param
84
85 auto testInvalidIdentParam = [&](auto const& param) {
86 json::Value params;
87 params[jss::ident] = param;
88 auto jrr = env.rpc("json", "account_info", to_string(params))[jss::result];
89 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
90 BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'ident'.");
91 };
92
93 testInvalidIdentParam(1);
94 testInvalidIdentParam(1.1);
95 testInvalidIdentParam(true);
96 testInvalidIdentParam(json::Value(json::ValueType::Null));
97 testInvalidIdentParam(json::Value(json::ValueType::Object));
98 testInvalidIdentParam(json::Value(json::ValueType::Array));
99 }
100 }
101
102 // Test the "signer_lists" argument in account_info.
103 void
105 {
106 testcase("Signer lists");
107 using namespace jtx;
108 Env env(*this);
109 Account const alice{"alice"};
110 env.fund(XRP(1000), alice);
111
112 json::Value withoutSigners;
113 withoutSigners[jss::account] = alice.human();
114
115 json::Value withSigners;
116 withSigners[jss::account] = alice.human();
117 withSigners[jss::signer_lists] = true;
118
119 // Alice has no SignerList yet.
120 {
121 // account_info without the "signer_lists" argument.
122 auto const info = env.rpc("json", "account_info", to_string(withoutSigners));
123 BEAST_EXPECT(
124 info.isMember(jss::result) && info[jss::result].isMember(jss::account_data));
125 BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(jss::signer_lists));
126 }
127 {
128 // account_info with the "signer_lists" argument.
129 auto const info = env.rpc("json", "account_info", to_string(withSigners));
130 BEAST_EXPECT(
131 info.isMember(jss::result) && info[jss::result].isMember(jss::account_data));
132 auto const& data = info[jss::result][jss::account_data];
133 BEAST_EXPECT(data.isMember(jss::signer_lists));
134 auto const& signerLists = data[jss::signer_lists];
135 BEAST_EXPECT(signerLists.isArray());
136 BEAST_EXPECT(signerLists.size() == 0);
137 }
138
139 // Give alice a SignerList.
140 Account const bogie{"bogie"};
141
142 json::Value const smallSigners = signers(alice, 2, {{bogie, 3}});
143 env(smallSigners);
144 {
145 // account_info without the "signer_lists" argument.
146 auto const info = env.rpc("json", "account_info", to_string(withoutSigners));
147 BEAST_EXPECT(
148 info.isMember(jss::result) && info[jss::result].isMember(jss::account_data));
149 BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(jss::signer_lists));
150 }
151 {
152 // account_info with the "signer_lists" argument.
153 auto const info = env.rpc("json", "account_info", to_string(withSigners));
154 BEAST_EXPECT(
155 info.isMember(jss::result) && info[jss::result].isMember(jss::account_data));
156 auto const& data = info[jss::result][jss::account_data];
157 BEAST_EXPECT(data.isMember(jss::signer_lists));
158 auto const& signerLists = data[jss::signer_lists];
159 BEAST_EXPECT(signerLists.isArray());
160 BEAST_EXPECT(signerLists.size() == 1);
161 auto const& signers = signerLists[0u];
162 BEAST_EXPECT(signers.isObject());
163 BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 2);
164 auto const& signerEntries = signers[sfSignerEntries.jsonName];
165 BEAST_EXPECT(signerEntries.size() == 1);
166 auto const& entry0 = signerEntries[0u][sfSignerEntry.jsonName];
167 BEAST_EXPECT(entry0[sfSignerWeight.jsonName] == 3);
168 }
169
170 // Give alice a big signer list
171 Account const demon{"demon"};
172 Account const ghost{"ghost"};
173 Account const haunt{"haunt"};
174 Account const jinni{"jinni"};
175 Account const phase{"phase"};
176 Account const shade{"shade"};
177 Account const spook{"spook"};
178
179 json::Value const bigSigners = signers(
180 alice,
181 4,
182 {
183 {bogie, 1},
184 {demon, 1},
185 {ghost, 1},
186 {haunt, 1},
187 {jinni, 1},
188 {phase, 1},
189 {shade, 1},
190 {spook, 1},
191 });
192 env(bigSigners);
193 {
194 // account_info with the "signer_lists" argument.
195 auto const info = env.rpc("json", "account_info", to_string(withSigners));
196 BEAST_EXPECT(
197 info.isMember(jss::result) && info[jss::result].isMember(jss::account_data));
198 auto const& data = info[jss::result][jss::account_data];
199 BEAST_EXPECT(data.isMember(jss::signer_lists));
200 auto const& signerLists = data[jss::signer_lists];
201 BEAST_EXPECT(signerLists.isArray());
202 BEAST_EXPECT(signerLists.size() == 1);
203 auto const& signers = signerLists[0u];
204 BEAST_EXPECT(signers.isObject());
205 BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 4);
206 auto const& signerEntries = signers[sfSignerEntries.jsonName];
207 BEAST_EXPECT(signerEntries.size() == 8);
208 for (unsigned i = 0u; i < 8; ++i)
209 {
210 auto const& entry = signerEntries[i][sfSignerEntry.jsonName];
211 BEAST_EXPECT(entry.size() == 2);
212 BEAST_EXPECT(entry.isMember(sfAccount.jsonName));
213 BEAST_EXPECT(entry[sfSignerWeight.jsonName] == 1);
214 }
215 }
216 }
217
218 // Test the "signer_lists" argument in account_info, with api_version 2.
219 void
221 {
222 testcase("Signer lists APIv2");
223 using namespace jtx;
224 Env env{*this};
225 Account const alice{"alice"};
226 env.fund(XRP(1000), alice);
227
228 json::Value withoutSigners;
229 withoutSigners[jss::api_version] = 2;
230 withoutSigners[jss::account] = alice.human();
231
232 json::Value withSigners;
233 withSigners[jss::api_version] = 2;
234 withSigners[jss::account] = alice.human();
235 withSigners[jss::signer_lists] = true;
236
237 auto const withSignersAsString = std::string("{ ") + "\"api_version\": 2, \"account\": \"" +
238 alice.human() + "\", " + "\"signer_lists\": asdfggh }";
239
240 // Alice has no SignerList yet.
241 {
242 // account_info without the "signer_lists" argument.
243 auto const info = env.rpc("json", "account_info", to_string(withoutSigners));
244 BEAST_EXPECT(info.isMember(jss::result));
245 BEAST_EXPECT(!info[jss::result].isMember(jss::signer_lists));
246 }
247 {
248 // account_info with the "signer_lists" argument.
249 auto const info = env.rpc("json", "account_info", to_string(withSigners));
250 BEAST_EXPECT(info.isMember(jss::result));
251 auto const& data = info[jss::result];
252 BEAST_EXPECT(data.isMember(jss::signer_lists));
253 auto const& signerLists = data[jss::signer_lists];
254 BEAST_EXPECT(signerLists.isArray());
255 BEAST_EXPECT(signerLists.size() == 0);
256 }
257
258 // Give alice a SignerList.
259 Account const bogie{"bogie"};
260
261 json::Value const smallSigners = signers(alice, 2, {{bogie, 3}});
262 env(smallSigners);
263 {
264 // account_info without the "signer_lists" argument.
265 auto const info = env.rpc("json", "account_info", to_string(withoutSigners));
266 BEAST_EXPECT(info.isMember(jss::result));
267 BEAST_EXPECT(!info[jss::result].isMember(jss::signer_lists));
268 }
269 {
270 // account_info with the "signer_lists" argument.
271 auto const info = env.rpc("json", "account_info", to_string(withSigners));
272 BEAST_EXPECT(info.isMember(jss::result));
273 auto const& data = info[jss::result];
274 BEAST_EXPECT(data.isMember(jss::signer_lists));
275 auto const& signerLists = data[jss::signer_lists];
276 BEAST_EXPECT(signerLists.isArray());
277 BEAST_EXPECT(signerLists.size() == 1);
278 auto const& signers = signerLists[0u];
279 BEAST_EXPECT(signers.isObject());
280 BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 2);
281 auto const& signerEntries = signers[sfSignerEntries.jsonName];
282 BEAST_EXPECT(signerEntries.size() == 1);
283 auto const& entry0 = signerEntries[0u][sfSignerEntry.jsonName];
284 BEAST_EXPECT(entry0[sfSignerWeight.jsonName] == 3);
285 }
286 {
287 // account_info with "signer_lists" as not bool should error out
288 auto const info = env.rpc("json", "account_info", withSignersAsString);
289 BEAST_EXPECT(info[jss::status] == "error");
290 BEAST_EXPECT(info[jss::error] == "invalidParams");
291 }
292
293 // Give alice a big signer list
294 Account const demon{"demon"};
295 Account const ghost{"ghost"};
296 Account const haunt{"haunt"};
297 Account const jinni{"jinni"};
298 Account const phase{"phase"};
299 Account const shade{"shade"};
300 Account const spook{"spook"};
301
302 json::Value const bigSigners = signers(
303 alice,
304 4,
305 {
306 {bogie, 1},
307 {demon, 1},
308 {ghost, 1},
309 {haunt, 1},
310 {jinni, 1},
311 {phase, 1},
312 {shade, 1},
313 {spook, 1},
314 });
315 env(bigSigners);
316 {
317 // account_info with the "signer_lists" argument.
318 auto const info = env.rpc("json", "account_info", to_string(withSigners));
319 BEAST_EXPECT(info.isMember(jss::result));
320 auto const& data = info[jss::result];
321 BEAST_EXPECT(data.isMember(jss::signer_lists));
322 auto const& signerLists = data[jss::signer_lists];
323 BEAST_EXPECT(signerLists.isArray());
324 BEAST_EXPECT(signerLists.size() == 1);
325 auto const& signers = signerLists[0u];
326 BEAST_EXPECT(signers.isObject());
327 BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 4);
328 auto const& signerEntries = signers[sfSignerEntries.jsonName];
329 BEAST_EXPECT(signerEntries.size() == 8);
330 for (unsigned i = 0u; i < 8; ++i)
331 {
332 auto const& entry = signerEntries[i][sfSignerEntry.jsonName];
333 BEAST_EXPECT(entry.size() == 2);
334 BEAST_EXPECT(entry.isMember(sfAccount.jsonName));
335 BEAST_EXPECT(entry[sfSignerWeight.jsonName] == 1);
336 }
337 }
338 }
339
340 // Test the "signer_lists" argument in account_info, version 2 API.
341 void
343 {
344 testcase("Signer lists v2");
345 using namespace jtx;
346 Env env(*this);
347 Account const alice{"alice"};
348 env.fund(XRP(1000), alice);
349
350 auto const withoutSigners = std::string("{ ") +
351 "\"jsonrpc\": \"2.0\", "
352 "\"ripplerpc\": \"2.0\", "
353 "\"id\": 5, "
354 "\"method\": \"account_info\", "
355 "\"params\": { "
356 "\"account\": \"" +
357 alice.human() + "\"}}";
358
359 auto const withSigners = std::string("{ ") +
360 "\"jsonrpc\": \"2.0\", "
361 "\"ripplerpc\": \"2.0\", "
362 "\"id\": 6, "
363 "\"method\": \"account_info\", "
364 "\"params\": { "
365 "\"account\": \"" +
366 alice.human() + "\", " + "\"signer_lists\": true }}";
367 // Alice has no SignerList yet.
368 {
369 // account_info without the "signer_lists" argument.
370 auto const info = env.rpc("json2", withoutSigners);
371 BEAST_EXPECT(
372 info.isMember(jss::result) && info[jss::result].isMember(jss::account_data));
373 BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(jss::signer_lists));
374 BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
375 BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
376 BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 5);
377 }
378 {
379 // account_info with the "signer_lists" argument.
380 auto const info = env.rpc("json2", withSigners);
381 BEAST_EXPECT(
382 info.isMember(jss::result) && info[jss::result].isMember(jss::account_data));
383 auto const& data = info[jss::result][jss::account_data];
384 BEAST_EXPECT(data.isMember(jss::signer_lists));
385 auto const& signerLists = data[jss::signer_lists];
386 BEAST_EXPECT(signerLists.isArray());
387 BEAST_EXPECT(signerLists.size() == 0);
388 BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
389 BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
390 BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
391 }
392 {
393 // Do both of the above as a batch job
394 auto const info = env.rpc("json2", '[' + withoutSigners + ", " + withSigners + ']');
395 BEAST_EXPECT(
396 info[0u].isMember(jss::result) &&
397 info[0u][jss::result].isMember(jss::account_data));
398 BEAST_EXPECT(!info[0u][jss::result][jss::account_data].isMember(jss::signer_lists));
399 BEAST_EXPECT(info[0u].isMember(jss::jsonrpc) && info[0u][jss::jsonrpc] == "2.0");
400 BEAST_EXPECT(info[0u].isMember(jss::ripplerpc) && info[0u][jss::ripplerpc] == "2.0");
401 BEAST_EXPECT(info[0u].isMember(jss::id) && info[0u][jss::id] == 5);
402
403 BEAST_EXPECT(
404 info[1u].isMember(jss::result) &&
405 info[1u][jss::result].isMember(jss::account_data));
406 auto const& data = info[1u][jss::result][jss::account_data];
407 BEAST_EXPECT(data.isMember(jss::signer_lists));
408 auto const& signerLists = data[jss::signer_lists];
409 BEAST_EXPECT(signerLists.isArray());
410 BEAST_EXPECT(signerLists.size() == 0);
411 BEAST_EXPECT(info[1u].isMember(jss::jsonrpc) && info[1u][jss::jsonrpc] == "2.0");
412 BEAST_EXPECT(info[1u].isMember(jss::ripplerpc) && info[1u][jss::ripplerpc] == "2.0");
413 BEAST_EXPECT(info[1u].isMember(jss::id) && info[1u][jss::id] == 6);
414 }
415
416 // Give alice a SignerList.
417 Account const bogie{"bogie"};
418
419 json::Value const smallSigners = signers(alice, 2, {{bogie, 3}});
420 env(smallSigners);
421 {
422 // account_info without the "signer_lists" argument.
423 auto const info = env.rpc("json2", withoutSigners);
424 BEAST_EXPECT(
425 info.isMember(jss::result) && info[jss::result].isMember(jss::account_data));
426 BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(jss::signer_lists));
427 BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
428 BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
429 BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 5);
430 }
431 {
432 // account_info with the "signer_lists" argument.
433 auto const info = env.rpc("json2", withSigners);
434 BEAST_EXPECT(
435 info.isMember(jss::result) && info[jss::result].isMember(jss::account_data));
436 auto const& data = info[jss::result][jss::account_data];
437 BEAST_EXPECT(data.isMember(jss::signer_lists));
438 auto const& signerLists = data[jss::signer_lists];
439 BEAST_EXPECT(signerLists.isArray());
440 BEAST_EXPECT(signerLists.size() == 1);
441 auto const& signers = signerLists[0u];
442 BEAST_EXPECT(signers.isObject());
443 BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 2);
444 auto const& signerEntries = signers[sfSignerEntries.jsonName];
445 BEAST_EXPECT(signerEntries.size() == 1);
446 auto const& entry0 = signerEntries[0u][sfSignerEntry.jsonName];
447 BEAST_EXPECT(entry0[sfSignerWeight.jsonName] == 3);
448 BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
449 BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
450 BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
451 }
452
453 // Give alice a big signer list
454 Account const demon{"demon"};
455 Account const ghost{"ghost"};
456 Account const haunt{"haunt"};
457 Account const jinni{"jinni"};
458 Account const phase{"phase"};
459 Account const shade{"shade"};
460 Account const spook{"spook"};
461
462 json::Value const bigSigners = signers(
463 alice,
464 4,
465 {
466 {bogie, 1},
467 {demon, 1},
468 {ghost, 1},
469 {haunt, 1},
470 {jinni, 1},
471 {phase, 1},
472 {shade, 1},
473 {spook, 1},
474 });
475 env(bigSigners);
476 {
477 // account_info with the "signer_lists" argument.
478 auto const info = env.rpc("json2", withSigners);
479 BEAST_EXPECT(
480 info.isMember(jss::result) && info[jss::result].isMember(jss::account_data));
481 auto const& data = info[jss::result][jss::account_data];
482 BEAST_EXPECT(data.isMember(jss::signer_lists));
483 auto const& signerLists = data[jss::signer_lists];
484 BEAST_EXPECT(signerLists.isArray());
485 BEAST_EXPECT(signerLists.size() == 1);
486 auto const& signers = signerLists[0u];
487 BEAST_EXPECT(signers.isObject());
488 BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 4);
489 auto const& signerEntries = signers[sfSignerEntries.jsonName];
490 BEAST_EXPECT(signerEntries.size() == 8);
491 for (unsigned i = 0u; i < 8; ++i)
492 {
493 auto const& entry = signerEntries[i][sfSignerEntry.jsonName];
494 BEAST_EXPECT(entry.size() == 2);
495 BEAST_EXPECT(entry.isMember(sfAccount.jsonName));
496 BEAST_EXPECT(entry[sfSignerWeight.jsonName] == 1);
497 }
498 BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
499 BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
500 BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
501 }
502 }
503
504 void
506 {
507 testcase("Account flags");
508 using namespace jtx;
509
510 Env env(*this, features);
511 Account const alice{"alice"};
512 Account const bob{"bob"};
513 env.fund(XRP(1000), alice, bob);
514
515 auto getAccountFlag = [&env](std::string_view fName, Account const& account) {
516 json::Value params;
517 params[jss::account] = account.human();
518 auto const info = env.rpc("json", "account_info", to_string(params));
519 auto const name = std::string(fName);
520
522 if (info[jss::result][jss::status] == "success" &&
523 info[jss::result][jss::account_flags].isMember(name))
524 res.emplace(info[jss::result][jss::account_flags][name].asBool());
525
526 return res;
527 };
528
529 static constexpr std::array<std::pair<std::string_view, std::uint32_t>, 7> kAsFlags{
530 {{"defaultRipple", asfDefaultRipple},
531 {"depositAuth", asfDepositAuth},
532 {"disallowIncomingXRP", asfDisallowXRP},
533 {"globalFreeze", asfGlobalFreeze},
534 {"noFreeze", asfNoFreeze},
535 {"requireAuthorization", asfRequireAuth},
536 {"requireDestinationTag", asfRequireDest}}};
537
538 for (auto& asf : kAsFlags)
539 {
540 // Clear a flag and check that account_info returns results
541 // as expected
542 env(fclear(alice, asf.second));
543 env.close();
544 auto const f1 = getAccountFlag(asf.first, alice);
545 BEAST_EXPECT(f1.has_value());
546 BEAST_EXPECT(!f1.value()); // NOLINT(bugprone-unchecked-optional-access)
547
548 // Set a flag and check that account_info returns results
549 // as expected
550 env(fset(alice, asf.second));
551 env.close();
552 auto const f2 = getAccountFlag(asf.first, alice);
553 BEAST_EXPECT(f2.has_value());
554 BEAST_EXPECT(f2.value()); // NOLINT(bugprone-unchecked-optional-access)
555 }
556
558 kDisallowIncomingFlags{
559 {{"disallowIncomingCheck", asfDisallowIncomingCheck},
560 {"disallowIncomingNFTokenOffer", asfDisallowIncomingNFTokenOffer},
561 {"disallowIncomingPayChan", asfDisallowIncomingPayChan},
562 {"disallowIncomingTrustline", asfDisallowIncomingTrustline}}};
563
564 for (auto& asf : kDisallowIncomingFlags)
565 {
566 // Clear a flag and check that account_info returns results
567 // as expected
568 env(fclear(alice, asf.second));
569 env.close();
570 auto const f1 = getAccountFlag(asf.first, alice);
571 BEAST_EXPECT(f1.has_value());
572 BEAST_EXPECT(!f1.value()); // NOLINT(bugprone-unchecked-optional-access)
573
574 // Set a flag and check that account_info returns results
575 // as expected
576 env(fset(alice, asf.second));
577 env.close();
578 auto const f2 = getAccountFlag(asf.first, alice);
579 BEAST_EXPECT(f2.has_value());
580 BEAST_EXPECT(f2.value()); // NOLINT(bugprone-unchecked-optional-access)
581 }
582
583 static constexpr std::pair<std::string_view, std::uint32_t> kAllowTrustLineClawbackFlag{
584 "allowTrustLineClawback", asfAllowTrustLineClawback};
585
586 // must use bob's account because alice has noFreeze set
587 auto const f1 = getAccountFlag(kAllowTrustLineClawbackFlag.first, bob);
588 BEAST_EXPECT(f1.has_value());
589 BEAST_EXPECT(!f1.value()); // NOLINT(bugprone-unchecked-optional-access)
590
591 // Set allowTrustLineClawback
592 env(fset(bob, kAllowTrustLineClawbackFlag.second));
593 env.close();
594 auto const f2 = getAccountFlag(kAllowTrustLineClawbackFlag.first, bob);
595 BEAST_EXPECT(f2.has_value());
596 BEAST_EXPECT(f2.value()); // NOLINT(bugprone-unchecked-optional-access)
597
598 static constexpr std::pair<std::string_view, std::uint32_t> kAllowTrustLineLockingFlag{
599 "allowTrustLineLocking", asfAllowTrustLineLocking};
600
601 if (features[featureTokenEscrow])
602 {
603 auto const f1 = getAccountFlag(kAllowTrustLineLockingFlag.first, bob);
604 BEAST_EXPECT(f1.has_value());
605 BEAST_EXPECT(!f1.value()); // NOLINT(bugprone-unchecked-optional-access)
606
607 // Set allowTrustLineLocking
608 env(fset(bob, kAllowTrustLineLockingFlag.second));
609 env.close();
610 auto const f2 = getAccountFlag(kAllowTrustLineLockingFlag.first, bob);
611 BEAST_EXPECT(f2.has_value());
612 BEAST_EXPECT(f2.value()); // NOLINT(bugprone-unchecked-optional-access)
613 }
614 else
615 {
616 BEAST_EXPECT(!getAccountFlag(kAllowTrustLineLockingFlag.first, bob));
617 }
618 }
619
620 void
632};
633
634BEAST_DEFINE_TESTSUITE(AccountInfo, rpc, xrpl);
635
636} // namespace xrpl::test
A testsuite class.
Definition suite.h:50
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:149
Represents a JSON value.
Definition json_value.h:130
UInt size() const
Number of values in array or object.
bool isMember(char const *key) const
Return true if the object has a member named key.
void testAccountFlags(FeatureBitset const &features)
void run() override
Runs the suite.
Immutable cryptographic account descriptor.
Definition jtx/Account.h:17
std::string const & human() const
Returns the human readable public key.
Definition jtx/Account.h:92
A transaction testing environment.
Definition Env.h:143
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:133
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:296
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:864
T emplace(T... args)
@ Array
array value (ordered list)
Definition json_value.h:25
@ Object
object value (collection of name/value pairs).
Definition json_value.h:26
@ Null
'null' value
Definition json_value.h:19
XrpT const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:92
json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition flags.h:102
FeatureBitset testableAmendments()
Definition Env.h:76
json::Value signers(Account const &account, std::uint32_t quorum, std::vector< Signer > const &v)
Definition multisign.cpp:31
json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition flags.cpp:15
FeatureBitset allFeatures()
Returns all testable amendments.
Definition TxTest.cpp:42
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ RpcActNotFound
Definition ErrorCodes.h:52
@ RpcActMalformed
Definition ErrorCodes.h:72
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633