21#include <xrpl/protocol/Feature.h>
22#include <xrpl/protocol/jss.h>
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>
44 auto const info = env.
rpc(
"json",
"account_info",
"{ }");
46 info[jss::result][jss::error_message] ==
47 "Missing field 'account'.");
51 auto const info = env.
rpc(
55 "\"n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV\"}");
59 info[jss::result][jss::error_message] ==
"Account malformed.");
64 auto const info = env.
rpc(
67 R
"({ "account": ")" + bogie.human() + R"("})");
71 info[jss::result][jss::error_message] == "Account not found.");
76 env.
rpc(
"json",
"account_info", R
"({"account": "foo"})");
80 info[jss::result][jss::error_message] == "Account malformed.");
85 auto testInvalidAccountParam = [&](
auto const& param) {
87 params[jss::account] = param;
89 "json",
"account_info",
to_string(params))[jss::result];
90 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
92 jrr[jss::error_message] ==
"Invalid field 'account'.");
95 testInvalidAccountParam(1);
96 testInvalidAccountParam(1.1);
97 testInvalidAccountParam(
true);
105 auto testInvalidIdentParam = [&](
auto const& param) {
107 params[jss::ident] = param;
109 "json",
"account_info",
to_string(params))[jss::result];
110 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
112 jrr[jss::error_message] ==
"Invalid field 'ident'.");
115 testInvalidIdentParam(1);
116 testInvalidIdentParam(1.1);
117 testInvalidIdentParam(
true);
132 env.fund(
XRP(1000), alice);
134 auto const withoutSigners =
135 std::string(
"{ ") +
"\"account\": \"" + alice.human() +
"\"}";
137 auto const withSigners =
std::string(
"{ ") +
"\"account\": \"" +
138 alice.human() +
"\", " +
"\"signer_lists\": true }";
143 auto const info = env.rpc(
"json",
"account_info", withoutSigners);
145 info.isMember(jss::result) &&
146 info[jss::result].isMember(jss::account_data));
147 BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(
152 auto const info = env.rpc(
"json",
"account_info", withSigners);
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);
164 Account
const bogie{
"bogie"};
170 auto const info = env.rpc(
"json",
"account_info", withoutSigners);
172 info.isMember(jss::result) &&
173 info[jss::result].isMember(jss::account_data));
174 BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(
179 auto const info = env.rpc(
"json",
"account_info", withSigners);
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];
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);
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"};
222 auto const info = env.rpc(
"json",
"account_info", withSigners);
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];
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)
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);
248 testSignerListsApiVersion2()
253 Account
const alice{
"alice"};
254 env.fund(
XRP(1000), alice);
257 "\"api_version\": 2, \"account\": \"" + alice.human() +
"\"}";
260 "\"api_version\": 2, \"account\": \"" + alice.human() +
"\", " +
261 "\"signer_lists\": true }";
263 auto const withSignersAsString =
std::string(
"{ ") +
264 "\"api_version\": 2, \"account\": \"" + alice.human() +
"\", " +
265 "\"signer_lists\": asdfggh }";
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));
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);
286 Account
const bogie{
"bogie"};
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));
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];
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);
316 env.rpc(
"json",
"account_info", withSignersAsString);
317 BEAST_EXPECT(info[jss::status] ==
"error");
318 BEAST_EXPECT(info[jss::error] ==
"invalidParams");
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"};
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];
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)
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);
375 Account
const alice{
"alice"};
376 env.fund(
XRP(1000), alice);
379 "\"jsonrpc\": \"2.0\", "
380 "\"ripplerpc\": \"2.0\", "
382 "\"method\": \"account_info\", "
385 alice.human() +
"\"}}";
388 "\"jsonrpc\": \"2.0\", "
389 "\"ripplerpc\": \"2.0\", "
391 "\"method\": \"account_info\", "
394 alice.human() +
"\", " +
"\"signer_lists\": true }}";
398 auto const info = env.rpc(
"json2", withoutSigners);
400 info.isMember(jss::result) &&
401 info[jss::result].isMember(jss::account_data));
402 BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(
405 info.isMember(jss::jsonrpc) && info[jss::jsonrpc] ==
"2.0");
407 info.isMember(jss::ripplerpc) && info[jss::ripplerpc] ==
"2.0");
408 BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 5);
412 auto const info = env.rpc(
"json2", withSigners);
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);
422 info.isMember(jss::jsonrpc) && info[jss::jsonrpc] ==
"2.0");
424 info.isMember(jss::ripplerpc) && info[jss::ripplerpc] ==
"2.0");
425 BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
429 auto const info = env.rpc(
430 "json2",
'[' + withoutSigners +
", " + withSigners +
']');
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(
437 info[0u].isMember(jss::jsonrpc) &&
438 info[0u][jss::jsonrpc] ==
"2.0");
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);
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);
453 info[1u].isMember(jss::jsonrpc) &&
454 info[1u][jss::jsonrpc] ==
"2.0");
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);
462 Account
const bogie{
"bogie"};
468 auto const info = env.rpc(
"json2", withoutSigners);
470 info.isMember(jss::result) &&
471 info[jss::result].isMember(jss::account_data));
472 BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(
475 info.isMember(jss::jsonrpc) && info[jss::jsonrpc] ==
"2.0");
477 info.isMember(jss::ripplerpc) && info[jss::ripplerpc] ==
"2.0");
478 BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 5);
482 auto const info = env.rpc(
"json2", withSigners);
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];
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);
499 info.isMember(jss::jsonrpc) && info[jss::jsonrpc] ==
"2.0");
501 info.isMember(jss::ripplerpc) && info[jss::ripplerpc] ==
"2.0");
502 BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
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"};
530 auto const info = env.rpc(
"json2", withSigners);
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];
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)
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);
552 info.isMember(jss::jsonrpc) && info[jss::jsonrpc] ==
"2.0");
554 info.isMember(jss::ripplerpc) && info[jss::ripplerpc] ==
"2.0");
555 BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
560 testAccountFlags(FeatureBitset
const& features)
565 Env env(*
this, features);
566 Account
const alice{
"alice"};
567 Account
const bob{
"bob"};
568 env.fund(
XRP(1000), alice, bob);
570 auto getAccountFlag = [&env](
572 Account
const& account) {
573 auto const info = env.rpc(
576 R
"({"account" : ")" + account.human() + R"("})");
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()]
587 static constexpr std::
588 array<std::pair<std::string_view, std::uint32_t>, 7>
598 for (
auto& asf : asFlags)
602 env(
fclear(alice, asf.second));
604 auto const f1 = getAccountFlag(asf.first, alice);
605 BEAST_EXPECT(f1.has_value());
606 BEAST_EXPECT(!f1.value());
610 env(
fset(alice, asf.second));
612 auto const f2 = getAccountFlag(asf.first, alice);
613 BEAST_EXPECT(f2.has_value());
614 BEAST_EXPECT(f2.value());
617 static constexpr std::
618 array<std::pair<std::string_view, std::uint32_t>, 4>
619 disallowIncomingFlags{
621 {
"disallowIncomingNFTokenOffer",
624 {
"disallowIncomingTrustline",
627 if (features[featureDisallowIncoming])
629 for (
auto& asf : disallowIncomingFlags)
633 env(
fclear(alice, asf.second));
635 auto const f1 = getAccountFlag(asf.first, alice);
636 BEAST_EXPECT(f1.has_value());
637 BEAST_EXPECT(!f1.value());
641 env(
fset(alice, asf.second));
643 auto const f2 = getAccountFlag(asf.first, alice);
644 BEAST_EXPECT(f2.has_value());
645 BEAST_EXPECT(f2.value());
650 for (
auto& asf : disallowIncomingFlags)
652 BEAST_EXPECT(!getAccountFlag(asf.first, alice));
657 allowTrustLineClawbackFlag{
660 if (features[featureClawback])
664 getAccountFlag(allowTrustLineClawbackFlag.first, bob);
665 BEAST_EXPECT(f1.has_value());
666 BEAST_EXPECT(!f1.value());
669 env(
fset(bob, allowTrustLineClawbackFlag.second));
672 getAccountFlag(allowTrustLineClawbackFlag.first, bob);
673 BEAST_EXPECT(f2.has_value());
674 BEAST_EXPECT(f2.value());
679 !getAccountFlag(allowTrustLineClawbackFlag.first, bob));
688 testSignerListsApiVersion2();
691 FeatureBitset
const allFeatures{
693 testAccountFlags(allFeatures);
694 testAccountFlags(allFeatures - featureDisallowIncoming);
696 allFeatures - featureDisallowIncoming - featureClawback);
testcase_t testcase
Memberspace for declaring test cases.
virtual void run()=0
Runs the suite.
Immutable cryptographic account descriptor.
A transaction testing environment.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Set the expected result code for a JTx The test will fail if the code doesn't match.
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Json::Value signers(Account const &account, std::uint32_t quorum, std::vector< signer > const &v)
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
XRP_t const XRP
Converts to XRP Issue or STAmount.
FeatureBitset supported_amendments()
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::uint32_t asfGlobalFreeze
constexpr std::uint32_t asfDepositAuth
constexpr std::uint32_t asfDisallowIncomingNFTokenOffer
constexpr std::uint32_t asfRequireDest
constexpr std::uint32_t asfNoFreeze
constexpr std::uint32_t asfDisallowIncomingTrustline
constexpr std::uint32_t asfDefaultRipple
constexpr std::uint32_t asfDisallowIncomingCheck
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t asfDisallowIncomingPayChan
constexpr std::uint32_t asfAllowTrustLineClawback
constexpr std::uint32_t asfRequireAuth
constexpr std::uint32_t asfDisallowXRP