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