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