mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-18 18:15:50 +00:00
Add account flags to account_info response: (#4459)
Previously, the object `account_data` in the `account_info` response contained a single field `Flags` that contains flags of an account. API consumers must perform bitwise operations on this field to retrieve the account flags. This change adds a new object, `account_flags`, at the top level of the `account_info` response `result`. The object contains relevant flags of the account. This makes it easier to write simple code to check a flag's value. The flags included may depend on the amendments that are enabled. Fix #2457.
This commit is contained in:
@@ -114,6 +114,7 @@ JSS(account); // in/out: many
|
||||
JSS(accountState); // out: LedgerToJson
|
||||
JSS(accountTreeHash); // out: ledger/Ledger.cpp
|
||||
JSS(account_data); // out: AccountInfo
|
||||
JSS(account_flags); // out: AccountInfo
|
||||
JSS(account_hash); // out: LedgerToJson
|
||||
JSS(account_id); // out: WalletPropose
|
||||
JSS(account_nfts); // out: AccountNFTs
|
||||
|
||||
@@ -77,6 +77,28 @@ doAccountInfo(RPC::JsonContext& context)
|
||||
if (jvAccepted)
|
||||
return jvAccepted;
|
||||
|
||||
static constexpr std::
|
||||
array<std::pair<std::string_view, LedgerSpecificFlags>, 9>
|
||||
lsFlags{
|
||||
{{"defaultRipple", lsfDefaultRipple},
|
||||
{"depositAuth", lsfDepositAuth},
|
||||
{"disableMasterKey", lsfDisableMaster},
|
||||
{"disallowIncomingXRP", lsfDisallowXRP},
|
||||
{"globalFreeze", lsfGlobalFreeze},
|
||||
{"noFreeze", lsfNoFreeze},
|
||||
{"passwordSpent", lsfPasswordSpent},
|
||||
{"requireAuthorization", lsfRequireAuth},
|
||||
{"requireDestinationTag", lsfRequireDestTag}}};
|
||||
|
||||
static constexpr std::
|
||||
array<std::pair<std::string_view, LedgerSpecificFlags>, 4>
|
||||
disallowIncomingFlags{
|
||||
{{"disallowIncomingNFTokenOffer",
|
||||
lsfDisallowIncomingNFTokenOffer},
|
||||
{"disallowIncomingCheck", lsfDisallowIncomingCheck},
|
||||
{"disallowIncomingPayChan", lsfDisallowIncomingPayChan},
|
||||
{"disallowIncomingTrustline", lsfDisallowIncomingTrustline}}};
|
||||
|
||||
auto const sleAccepted = ledger->read(keylet::account(accountID));
|
||||
if (sleAccepted)
|
||||
{
|
||||
@@ -94,6 +116,17 @@ doAccountInfo(RPC::JsonContext& context)
|
||||
RPC::injectSLE(jvAccepted, *sleAccepted);
|
||||
result[jss::account_data] = jvAccepted;
|
||||
|
||||
Json::Value acctFlags{Json::objectValue};
|
||||
for (auto const& lsf : lsFlags)
|
||||
acctFlags[lsf.first.data()] = sleAccepted->isFlag(lsf.second);
|
||||
|
||||
if (ledger->rules().enabled(featureDisallowIncoming))
|
||||
{
|
||||
for (auto const& lsf : disallowIncomingFlags)
|
||||
acctFlags[lsf.first.data()] = sleAccepted->isFlag(lsf.second);
|
||||
}
|
||||
result[jss::account_flags] = std::move(acctFlags);
|
||||
|
||||
// Return SignerList(s) if that is requested.
|
||||
if (params.isMember(jss::signer_lists) &&
|
||||
params[jss::signer_lists].asBool())
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
"Missing field 'account'.");
|
||||
}
|
||||
{
|
||||
// account_info with a malformed account sting.
|
||||
// account_info with a malformed account string.
|
||||
auto const info = env.rpc(
|
||||
"json",
|
||||
"account_info",
|
||||
@@ -491,6 +491,100 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testAccountFlags(FeatureBitset const& features)
|
||||
{
|
||||
using namespace jtx;
|
||||
|
||||
Env env(*this, features);
|
||||
Account const alice{"alice"};
|
||||
env.fund(XRP(1000), alice);
|
||||
|
||||
auto getAccountFlag = [&env, &alice](std::string_view fName) {
|
||||
auto const info = env.rpc(
|
||||
"json",
|
||||
"account_info",
|
||||
R"({"account" : ")" + alice.human() + R"("})");
|
||||
|
||||
std::optional<bool> res;
|
||||
if (info[jss::result][jss::status] == "success" &&
|
||||
info[jss::result][jss::account_flags].isMember(fName.data()))
|
||||
res.emplace(info[jss::result][jss::account_flags][fName.data()]
|
||||
.asBool());
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
static constexpr std::
|
||||
array<std::pair<std::string_view, std::uint32_t>, 7>
|
||||
asFlags{
|
||||
{{"defaultRipple", asfDefaultRipple},
|
||||
{"depositAuth", asfDepositAuth},
|
||||
{"disallowIncomingXRP", asfDisallowXRP},
|
||||
{"globalFreeze", asfGlobalFreeze},
|
||||
{"noFreeze", asfNoFreeze},
|
||||
{"requireAuthorization", asfRequireAuth},
|
||||
{"requireDestinationTag", asfRequireDest}}};
|
||||
|
||||
for (auto& asf : asFlags)
|
||||
{
|
||||
// Clear a flag and check that account_info returns results
|
||||
// as expected
|
||||
env(fclear(alice, asf.second));
|
||||
env.close();
|
||||
auto const f1 = getAccountFlag(asf.first);
|
||||
BEAST_EXPECT(f1.has_value());
|
||||
BEAST_EXPECT(!f1.value());
|
||||
|
||||
// Set a flag and check that account_info returns results
|
||||
// as expected
|
||||
env(fset(alice, asf.second));
|
||||
env.close();
|
||||
auto const f2 = getAccountFlag(asf.first);
|
||||
BEAST_EXPECT(f2.has_value());
|
||||
BEAST_EXPECT(f2.value());
|
||||
}
|
||||
|
||||
static constexpr std::
|
||||
array<std::pair<std::string_view, std::uint32_t>, 4>
|
||||
disallowIncomingFlags{
|
||||
{{"disallowIncomingCheck", asfDisallowIncomingCheck},
|
||||
{"disallowIncomingNFTokenOffer",
|
||||
asfDisallowIncomingNFTokenOffer},
|
||||
{"disallowIncomingPayChan", asfDisallowIncomingPayChan},
|
||||
{"disallowIncomingTrustline",
|
||||
asfDisallowIncomingTrustline}}};
|
||||
|
||||
if (features[featureDisallowIncoming])
|
||||
{
|
||||
for (auto& asf : disallowIncomingFlags)
|
||||
{
|
||||
// Clear a flag and check that account_info returns results
|
||||
// as expected
|
||||
env(fclear(alice, asf.second));
|
||||
env.close();
|
||||
auto const f1 = getAccountFlag(asf.first);
|
||||
BEAST_EXPECT(f1.has_value());
|
||||
BEAST_EXPECT(!f1.value());
|
||||
|
||||
// Set a flag and check that account_info returns results
|
||||
// as expected
|
||||
env(fset(alice, asf.second));
|
||||
env.close();
|
||||
auto const f2 = getAccountFlag(asf.first);
|
||||
BEAST_EXPECT(f2.has_value());
|
||||
BEAST_EXPECT(f2.value());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& asf : disallowIncomingFlags)
|
||||
{
|
||||
BEAST_EXPECT(!getAccountFlag(asf.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@@ -498,6 +592,11 @@ public:
|
||||
testSignerLists();
|
||||
testSignerListsApiVersion2();
|
||||
testSignerListsV2();
|
||||
|
||||
FeatureBitset const allFeatures{
|
||||
ripple::test::jtx::supported_amendments()};
|
||||
testAccountFlags(allFeatures);
|
||||
testAccountFlags(allFeatures - featureDisallowIncoming);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user