fix: Support canonical names for type in account_objects (#2437)

Fix: https://github.com/XRPLF/clio/issues/2275

---------
Co-authored-by: Sergey Kuznetsov <skuznetsov@ripple.com>
This commit is contained in:
emrearıyürek
2025-09-03 18:06:21 +02:00
committed by GitHub
parent 3a667f558c
commit 90ac03cae7
10 changed files with 307 additions and 124 deletions

View File

@@ -23,6 +23,7 @@
#include "rpc/RPCHelpers.hpp"
#include "rpc/common/Types.hpp"
#include "util/AccountUtils.hpp"
#include "util/LedgerUtils.hpp"
#include "util/TimeUtils.hpp"
#include <boost/json/object.hpp>
@@ -120,6 +121,18 @@ CustomValidator CustomValidators::ledgerIndexValidator =
return MaybeError{};
}};
CustomValidator CustomValidators::ledgerTypeValidator =
CustomValidator{[](boost::json::value const& value, std::string_view key) -> MaybeError {
if (!value.is_string())
return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}', not string.", key)}};
auto const type = util::LedgerTypes::getLedgerEntryTypeFromStr(boost::json::value_to<std::string>(value));
if (type == ripple::ltANY)
return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)}};
return MaybeError{};
}};
CustomValidator CustomValidators::accountValidator =
CustomValidator{[](boost::json::value const& value, std::string_view key) -> MaybeError {
if (!value.is_string())
@@ -160,6 +173,19 @@ CustomValidator CustomValidators::accountMarkerValidator =
return MaybeError{};
}};
CustomValidator CustomValidators::accountTypeValidator =
CustomValidator{[](boost::json::value const& value, std::string_view key) -> MaybeError {
if (!value.is_string())
return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}', not string.", key)}};
auto const type =
util::LedgerTypes::getAccountOwnedLedgerTypeFromStr(boost::json::value_to<std::string>(value));
if (type == ripple::ltANY)
return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)}};
return MaybeError{};
}};
CustomValidator CustomValidators::currencyValidator =
CustomValidator{[](boost::json::value const& value, std::string_view key) -> MaybeError {
if (!value.is_string())

View File

@@ -486,6 +486,14 @@ struct CustomValidators final {
*/
static CustomValidator ledgerIndexValidator;
/**
* @brief Provides a validator for ledger type.
*
* A type accepts canonical names of ledger entry types (case insensitive) or short names.
* Used by ledger_data.
*/
static CustomValidator ledgerTypeValidator;
/**
* @brief Provides a commonly used validator for accounts.
*
@@ -508,6 +516,14 @@ struct CustomValidators final {
*/
static CustomValidator accountMarkerValidator;
/**
* @brief Provides a validator for account type.
*
* A type accepts canonical names of owned ledger entry types (case insensitive) or short names.
* Used by account_objects.
*/
static CustomValidator accountTypeValidator;
/**
* @brief Provides a commonly used validator for uint160(AccountID) hex string.
*

View File

@@ -32,7 +32,6 @@
#include <boost/json/value_to.hpp>
#include <xrpl/basics/strHex.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/LedgerHeader.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/jss.h>
@@ -160,7 +159,8 @@ tag_invoke(boost::json::value_to_tag<AccountObjectsHandler::Input>, boost::json:
}
if (jsonObject.contains(JS(type)))
input.type = util::LedgerTypes::getLedgerEntryTypeFromStr(boost::json::value_to<std::string>(jv.at(JS(type))));
input.type =
util::LedgerTypes::getAccountOwnedLedgerTypeFromStr(boost::json::value_to<std::string>(jv.at(JS(type))));
if (jsonObject.contains(JS(limit)))
input.limit = jv.at(JS(limit)).as_int64();

View File

@@ -25,11 +25,9 @@
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/Validators.hpp"
#include "util/LedgerUtils.hpp"
#include <boost/json/conversion.hpp>
#include <boost/json/value.hpp>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/jss.h>
@@ -107,7 +105,6 @@ public:
static RpcSpecConstRef
spec([[maybe_unused]] uint32_t apiVersion)
{
auto const& accountOwnedTypes = util::LedgerTypes::getAccountOwnedLedgerTypeStrList();
static auto const kRPC_SPEC = RpcSpec{
{JS(account), validation::Required{}, validation::CustomValidators::accountValidator},
{JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator},
@@ -116,9 +113,7 @@ public:
validation::Type<uint32_t>{},
validation::Min(1u),
modifiers::Clamp<int32_t>(kLIMIT_MIN, kLIMIT_MAX)},
{JS(type),
validation::Type<std::string>{},
validation::OneOf<std::string>(accountOwnedTypes.cbegin(), accountOwnedTypes.cend())},
{JS(type), validation::CustomValidators::accountTypeValidator},
{JS(marker), validation::CustomValidators::accountMarkerValidator},
{JS(deletion_blockers_only), validation::Type<bool>{}},
};

View File

@@ -34,7 +34,6 @@
#include <boost/json/value_to.hpp>
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/strHex.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/LedgerHeader.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/Serializer.h>

View File

@@ -20,14 +20,12 @@
#pragma once
#include "data/BackendInterface.hpp"
#include "rpc/Errors.hpp"
#include "rpc/JS.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/MetaProcessors.hpp"
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/Validators.hpp"
#include "util/LedgerUtils.hpp"
#include "util/log/Logger.hpp"
#include <boost/json/array.hpp>
@@ -36,7 +34,6 @@
#include <boost/json/value.hpp>
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/jss.h>
#include <cstdint>
@@ -113,7 +110,6 @@ public:
static RpcSpecConstRef
spec([[maybe_unused]] uint32_t apiVersion)
{
auto const& ledgerTypeStrs = util::LedgerTypes::getLedgerEntryTypeStrList();
static auto const kRPC_SPEC = RpcSpec{
{JS(binary), validation::Type<bool>{}},
{"out_of_order", validation::Type<bool>{}},
@@ -123,11 +119,7 @@ public:
{JS(marker),
validation::Type<uint32_t, std::string>{},
meta::IfType<std::string>{validation::CustomValidators::uint256HexStringValidator}},
{JS(type),
meta::WithCustomError{
validation::Type<std::string>{}, Status{ripple::rpcINVALID_PARAMS, "Invalid field 'type', not string."}
},
validation::OneOf<std::string>(ledgerTypeStrs.cbegin(), ledgerTypeStrs.cend())},
{JS(type), validation::CustomValidators::ledgerTypeValidator},
{JS(ledger), check::Deprecated{}},
};
return kRPC_SPEC;

View File

@@ -19,9 +19,14 @@
#include "util/LedgerUtils.hpp"
#include "util/JsonUtils.hpp"
#include <boost/algorithm/string.hpp>
#include <xrpl/protocol/LedgerFormats.h>
#include <algorithm>
#include <functional>
#include <optional>
#include <string>
#include <unordered_map>
@@ -30,16 +35,52 @@ namespace util {
ripple::LedgerEntryType
LedgerTypes::getLedgerEntryTypeFromStr(std::string const& entryName)
{
static std::unordered_map<std::string, ripple::LedgerEntryType> kTYPE_MAP = []() {
std::unordered_map<std::string, ripple::LedgerEntryType> map;
std::ranges::for_each(kLEDGER_TYPES, [&map](auto const& item) { map[item.name_] = item.type_; });
return map;
}();
if (auto const result = getLedgerTypeAttributeFromStr(entryName); result.has_value()) {
return result->get().type_;
}
return ripple::ltANY;
}
if (!kTYPE_MAP.contains(entryName))
return ripple::ltANY;
ripple::LedgerEntryType
LedgerTypes::getAccountOwnedLedgerTypeFromStr(std::string const& entryName)
{
if (auto const result = getLedgerTypeAttributeFromStr(entryName);
result.has_value() && result->get().category_ != LedgerTypeAttribute::LedgerCategory::Chain) {
return result->get().type_;
}
return kTYPE_MAP.at(entryName);
return ripple::ltANY;
}
std::optional<std::reference_wrapper<impl::LedgerTypeAttribute const>>
LedgerTypes::getLedgerTypeAttributeFromStr(std::string const& entryName)
{
static std::unordered_map<std::string, std::reference_wrapper<impl::LedgerTypeAttribute const>> const kNAME_MAP =
[]() {
std::unordered_map<std::string, std::reference_wrapper<impl::LedgerTypeAttribute const>> map;
std::ranges::for_each(kLEDGER_TYPES, [&map](auto const& item) {
map.insert({util::toLower(item.name_), item});
});
return map;
}();
static std::unordered_map<std::string, std::reference_wrapper<impl::LedgerTypeAttribute const>> const
kRPC_NAME_MAP = []() {
std::unordered_map<std::string, std::reference_wrapper<impl::LedgerTypeAttribute const>> map;
std::ranges::for_each(kLEDGER_TYPES, [&map](auto const& item) { map.insert({item.rpcName_, item}); });
return map;
}();
if (auto const it = kRPC_NAME_MAP.find(entryName); it != kRPC_NAME_MAP.end()) {
return it->second;
}
auto const entryNameLowercase = util::toLower(entryName);
if (auto const it = kNAME_MAP.find(entryNameLowercase); it != kNAME_MAP.end()) {
return it->second;
}
return std::nullopt;
}
} // namespace util

View File

@@ -31,6 +31,8 @@
#include <algorithm>
#include <array>
#include <functional>
#include <optional>
#include <string>
#include <unordered_set>
#include <vector>
@@ -40,6 +42,7 @@ namespace util {
class LedgerTypes;
namespace impl {
class LedgerTypeAttribute {
enum class LedgerCategory {
Invalid,
@@ -50,33 +53,40 @@ class LedgerTypeAttribute {
ripple::LedgerEntryType type_ = ripple::ltANY;
char const* name_ = nullptr;
char const* rpcName_ = nullptr;
LedgerCategory category_ = LedgerCategory::Invalid;
constexpr LedgerTypeAttribute(char const* name, ripple::LedgerEntryType type, LedgerCategory category)
: type_(type), name_(name), category_(category)
constexpr LedgerTypeAttribute(
char const* name,
char const* rpcName,
ripple::LedgerEntryType type,
LedgerCategory category
)
: type_{type}, name_{name}, rpcName_{rpcName}, category_{category}
{
}
public:
static constexpr LedgerTypeAttribute
chainLedgerType(char const* name, ripple::LedgerEntryType type)
chainLedgerType(char const* name, char const* rpcName, ripple::LedgerEntryType type)
{
return LedgerTypeAttribute(name, type, LedgerCategory::Chain);
return LedgerTypeAttribute(name, rpcName, type, LedgerCategory::Chain);
}
static constexpr LedgerTypeAttribute
accountOwnedLedgerType(char const* name, ripple::LedgerEntryType type)
accountOwnedLedgerType(char const* name, char const* rpcName, ripple::LedgerEntryType type)
{
return LedgerTypeAttribute(name, type, LedgerCategory::AccountOwned);
return LedgerTypeAttribute(name, rpcName, type, LedgerCategory::AccountOwned);
}
static constexpr LedgerTypeAttribute
deletionBlockerLedgerType(char const* name, ripple::LedgerEntryType type)
deletionBlockerLedgerType(char const* name, char const* rpcName, ripple::LedgerEntryType type)
{
return LedgerTypeAttribute(name, type, LedgerCategory::DeletionBlocker);
return LedgerTypeAttribute(name, rpcName, type, LedgerCategory::DeletionBlocker);
}
friend class util::LedgerTypes;
};
} // namespace impl
/**
@@ -88,38 +98,51 @@ class LedgerTypes {
using LedgerTypeAttributeList = LedgerTypeAttribute[];
static constexpr LedgerTypeAttributeList const kLEDGER_TYPES{
LedgerTypeAttribute::accountOwnedLedgerType(JS(account), ripple::ltACCOUNT_ROOT),
LedgerTypeAttribute::chainLedgerType(JS(amendments), ripple::ltAMENDMENTS),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(check), ripple::ltCHECK),
LedgerTypeAttribute::accountOwnedLedgerType(JS(deposit_preauth), ripple::ltDEPOSIT_PREAUTH),
LedgerTypeAttribute::accountOwnedLedgerType(JS(AccountRoot), JS(account), ripple::ltACCOUNT_ROOT),
LedgerTypeAttribute::chainLedgerType(JS(Amendments), JS(amendments), ripple::ltAMENDMENTS),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(Check), JS(check), ripple::ltCHECK),
LedgerTypeAttribute::accountOwnedLedgerType(JS(DepositPreauth), JS(deposit_preauth), ripple::ltDEPOSIT_PREAUTH),
// dir node belongs to account, but can not be filtered from account_objects
LedgerTypeAttribute::chainLedgerType(JS(directory), ripple::ltDIR_NODE),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(escrow), ripple::ltESCROW),
LedgerTypeAttribute::chainLedgerType(JS(fee), ripple::ltFEE_SETTINGS),
LedgerTypeAttribute::chainLedgerType(JS(hashes), ripple::ltLEDGER_HASHES),
LedgerTypeAttribute::accountOwnedLedgerType(JS(offer), ripple::ltOFFER),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(payment_channel), ripple::ltPAYCHAN),
LedgerTypeAttribute::accountOwnedLedgerType(JS(signer_list), ripple::ltSIGNER_LIST),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(state), ripple::ltRIPPLE_STATE),
LedgerTypeAttribute::accountOwnedLedgerType(JS(ticket), ripple::ltTICKET),
LedgerTypeAttribute::accountOwnedLedgerType(JS(nft_offer), ripple::ltNFTOKEN_OFFER),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(nft_page), ripple::ltNFTOKEN_PAGE),
LedgerTypeAttribute::accountOwnedLedgerType(JS(amm), ripple::ltAMM),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(bridge), ripple::ltBRIDGE),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(xchain_owned_claim_id), ripple::ltXCHAIN_OWNED_CLAIM_ID),
LedgerTypeAttribute::chainLedgerType(JS(DirectoryNode), JS(directory), ripple::ltDIR_NODE),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(Escrow), JS(escrow), ripple::ltESCROW),
LedgerTypeAttribute::chainLedgerType(JS(FeeSettings), JS(fee), ripple::ltFEE_SETTINGS),
LedgerTypeAttribute::chainLedgerType(JS(LedgerHashes), JS(hashes), ripple::ltLEDGER_HASHES),
LedgerTypeAttribute::accountOwnedLedgerType(JS(Offer), JS(offer), ripple::ltOFFER),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(PayChannel), JS(payment_channel), ripple::ltPAYCHAN),
LedgerTypeAttribute::accountOwnedLedgerType(JS(SignerList), JS(signer_list), ripple::ltSIGNER_LIST),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(RippleState), JS(state), ripple::ltRIPPLE_STATE),
LedgerTypeAttribute::accountOwnedLedgerType(JS(Ticket), JS(ticket), ripple::ltTICKET),
LedgerTypeAttribute::accountOwnedLedgerType(JS(NFTokenOffer), JS(nft_offer), ripple::ltNFTOKEN_OFFER),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(NFTokenPage), JS(nft_page), ripple::ltNFTOKEN_PAGE),
LedgerTypeAttribute::accountOwnedLedgerType(JS(AMM), JS(amm), ripple::ltAMM),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(Bridge), JS(bridge), ripple::ltBRIDGE),
LedgerTypeAttribute::deletionBlockerLedgerType(
JS(XChainOwnedClaimID),
JS(xchain_owned_claim_id),
ripple::ltXCHAIN_OWNED_CLAIM_ID
),
LedgerTypeAttribute::deletionBlockerLedgerType(
JS(XChainOwnedCreateAccountClaimID),
JS(xchain_owned_create_account_claim_id),
ripple::ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID
),
LedgerTypeAttribute::accountOwnedLedgerType(JS(did), ripple::ltDID),
LedgerTypeAttribute::accountOwnedLedgerType(JS(oracle), ripple::ltORACLE),
LedgerTypeAttribute::accountOwnedLedgerType(JS(credential), ripple::ltCREDENTIAL),
LedgerTypeAttribute::accountOwnedLedgerType(JS(vault), ripple::ltVAULT),
LedgerTypeAttribute::chainLedgerType(JS(nunl), ripple::ltNEGATIVE_UNL),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(mpt_issuance), ripple::ltMPTOKEN_ISSUANCE),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(mptoken), ripple::ltMPTOKEN),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(permissioned_domain), ripple::ltPERMISSIONED_DOMAIN),
LedgerTypeAttribute::accountOwnedLedgerType(JS(delegate), ripple::ltDELEGATE),
LedgerTypeAttribute::accountOwnedLedgerType(JS(DID), JS(did), ripple::ltDID),
LedgerTypeAttribute::accountOwnedLedgerType(JS(Oracle), JS(oracle), ripple::ltORACLE),
LedgerTypeAttribute::accountOwnedLedgerType(JS(Credential), JS(credential), ripple::ltCREDENTIAL),
LedgerTypeAttribute::accountOwnedLedgerType(JS(Vault), JS(vault), ripple::ltVAULT),
LedgerTypeAttribute::chainLedgerType(JS(NegativeUNL), JS(nunl), ripple::ltNEGATIVE_UNL),
LedgerTypeAttribute::deletionBlockerLedgerType(
JS(MPTokenIssuance),
JS(mpt_issuance),
ripple::ltMPTOKEN_ISSUANCE
),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(MPToken), JS(mptoken), ripple::ltMPTOKEN),
LedgerTypeAttribute::deletionBlockerLedgerType(
JS(PermissionedDomain),
JS(permissioned_domain),
ripple::ltPERMISSIONED_DOMAIN
),
LedgerTypeAttribute::accountOwnedLedgerType(JS(Delegate), JS(delegate), ripple::ltDELEGATE),
};
public:
@@ -131,32 +154,7 @@ public:
getLedgerEntryTypeStrList()
{
std::array<char const*, std::size(kLEDGER_TYPES)> res{};
std::ranges::transform(kLEDGER_TYPES, std::begin(res), [](auto const& item) { return item.name_; });
return res;
}
/**
* @brief Returns a list of all account owned ledger entry type as string.
*
* @return A list of all account owned ledger entry type as string.
*/
static constexpr auto
getAccountOwnedLedgerTypeStrList()
{
constexpr auto kFILTER = [](auto const& item) {
return item.category_ != LedgerTypeAttribute::LedgerCategory::Chain;
};
constexpr auto kACCOUNT_OWNED_COUNT =
std::count_if(std::begin(kLEDGER_TYPES), std::end(kLEDGER_TYPES), kFILTER);
std::array<char const*, kACCOUNT_OWNED_COUNT> res{};
auto it = std::begin(res);
std::ranges::for_each(kLEDGER_TYPES, [&](auto const& item) {
if (kFILTER(item)) {
*it = item.name_;
++it;
}
});
std::ranges::transform(kLEDGER_TYPES, std::begin(res), [](auto const& item) { return item.rpcName_; });
return res;
}
@@ -188,11 +186,25 @@ public:
/**
* @brief Returns the ripple::LedgerEntryType from the given string.
*
* @param entryName The name of the ledger entry type
* @param entryName The name or canonical name (case-insensitive) of the ledger entry type for all categories
* @return The ripple::LedgerEntryType of the given string, returns ltANY if not found.
*/
static ripple::LedgerEntryType
getLedgerEntryTypeFromStr(std::string const& entryName);
/**
* @brief Returns the ripple::LedgerEntryType from the given string.
*
* @param entryName The name or canonical name (case-insensitive) of the ledger entry type for account owned
* category
* @return The ripple::LedgerEntryType of the given string, returns ltANY if not found.
*/
static ripple::LedgerEntryType
getAccountOwnedLedgerTypeFromStr(std::string const& entryName);
private:
static std::optional<std::reference_wrapper<impl::LedgerTypeAttribute const>>
getLedgerTypeAttributeFromStr(std::string const& entryName);
};
/**

View File

@@ -110,7 +110,7 @@ generateTestValuesForParametersTest()
.testName = "TypeNotString",
.testJson = R"JSON({"account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", "type": 1})JSON",
.expectedError = "invalidParams",
.expectedErrorMessage = "Invalid parameters."
.expectedErrorMessage = "Invalid field 'type', not string."
},
AccountObjectsParamTestCaseBundle{
.testName = "TypeInvalid",

View File

@@ -26,7 +26,9 @@
#include <algorithm>
#include <iterator>
#include <string>
#include <string_view>
#include <vector>
TEST(LedgerUtilsTests, LedgerObjectTypeList)
{
@@ -68,46 +70,14 @@ TEST(LedgerUtilsTests, LedgerObjectTypeList)
}));
}
TEST(LedgerUtilsTests, AccountOwnedTypeList)
{
constexpr auto kACCOUNT_OWNED = util::LedgerTypes::getAccountOwnedLedgerTypeStrList();
static constexpr char const* kCORRECT_TYPES[] = {
JS(account),
JS(check),
JS(deposit_preauth),
JS(escrow),
JS(offer),
JS(payment_channel),
JS(signer_list),
JS(state),
JS(ticket),
JS(nft_offer),
JS(nft_page),
JS(amm),
JS(bridge),
JS(xchain_owned_claim_id),
JS(xchain_owned_create_account_claim_id),
JS(did),
JS(oracle),
JS(credential),
JS(mpt_issuance),
JS(mptoken),
JS(permissioned_domain),
JS(vault),
JS(delegate)
};
static_assert(std::size(kCORRECT_TYPES) == kACCOUNT_OWNED.size());
static_assert(std::ranges::all_of(kCORRECT_TYPES, [&kACCOUNT_OWNED](std::string_view type) {
return std::ranges::find(kACCOUNT_OWNED, type) != std::cend(kACCOUNT_OWNED);
}));
}
TEST(LedgerUtilsTests, StrToType)
{
EXPECT_EQ(util::LedgerTypes::getLedgerEntryTypeFromStr("mess"), ripple::ltANY);
EXPECT_EQ(util::LedgerTypes::getLedgerEntryTypeFromStr("tomato"), ripple::ltANY);
EXPECT_EQ(util::LedgerTypes::getLedgerEntryTypeFromStr("account"), ripple::ltACCOUNT_ROOT);
EXPECT_EQ(util::LedgerTypes::getLedgerEntryTypeFromStr("AccoUnt"), ripple::ltANY);
EXPECT_EQ(util::LedgerTypes::getLedgerEntryTypeFromStr("AccountRoot"), ripple::ltACCOUNT_ROOT);
EXPECT_EQ(util::LedgerTypes::getLedgerEntryTypeFromStr("ACCOUNTRoot"), ripple::ltACCOUNT_ROOT);
constexpr auto kTYPES = util::LedgerTypes::getLedgerEntryTypeStrList();
std::ranges::for_each(kTYPES, [](auto const& typeStr) {
@@ -139,3 +109,135 @@ TEST(LedgerUtilsTests, DeletionBlockerTypes)
std::cend(kDELETION_BLOCKERS);
}));
}
struct LedgerEntryTypeParam {
std::string input;
ripple::LedgerEntryType expected;
};
static LedgerEntryTypeParam const kCHAIN_TEST_CASES[] = {
// Using RPC name with exact match
{.input = "amendments", .expected = ripple::ltAMENDMENTS},
{.input = "directory", .expected = ripple::ltDIR_NODE},
{.input = "fee", .expected = ripple::ltFEE_SETTINGS},
{.input = "hashes", .expected = ripple::ltLEDGER_HASHES},
{.input = "nunl", .expected = ripple::ltNEGATIVE_UNL},
// Using canonical name with exact match
{.input = "Amendments", .expected = ripple::ltAMENDMENTS},
{.input = "DirectoryNode", .expected = ripple::ltDIR_NODE},
{.input = "FeeSettings", .expected = ripple::ltFEE_SETTINGS},
{.input = "LedgerHashes", .expected = ripple::ltLEDGER_HASHES},
{.input = "NegativeUNL", .expected = ripple::ltNEGATIVE_UNL}
};
static LedgerEntryTypeParam const kACCOUNT_OWNED_TEST_CASES[] = {
// Using RPC name with exact match
{.input = "account", .expected = ripple::ltACCOUNT_ROOT},
{.input = "check", .expected = ripple::ltCHECK},
{.input = "deposit_preauth", .expected = ripple::ltDEPOSIT_PREAUTH},
{.input = "escrow", .expected = ripple::ltESCROW},
{.input = "offer", .expected = ripple::ltOFFER},
{.input = "payment_channel", .expected = ripple::ltPAYCHAN},
{.input = "signer_list", .expected = ripple::ltSIGNER_LIST},
{.input = "state", .expected = ripple::ltRIPPLE_STATE},
{.input = "ticket", .expected = ripple::ltTICKET},
{.input = "nft_offer", .expected = ripple::ltNFTOKEN_OFFER},
{.input = "nft_page", .expected = ripple::ltNFTOKEN_PAGE},
{.input = "amm", .expected = ripple::ltAMM},
{.input = "bridge", .expected = ripple::ltBRIDGE},
{.input = "xchain_owned_claim_id", .expected = ripple::ltXCHAIN_OWNED_CLAIM_ID},
{.input = "xchain_owned_create_account_claim_id", .expected = ripple::ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID},
{.input = "did", .expected = ripple::ltDID},
{.input = "oracle", .expected = ripple::ltORACLE},
{.input = "credential", .expected = ripple::ltCREDENTIAL},
{.input = "mpt_issuance", .expected = ripple::ltMPTOKEN_ISSUANCE},
{.input = "mptoken", .expected = ripple::ltMPTOKEN},
{.input = "permissioned_domain", .expected = ripple::ltPERMISSIONED_DOMAIN},
{.input = "vault", .expected = ripple::ltVAULT},
{.input = "delegate", .expected = ripple::ltDELEGATE},
// Using canonical name with exact match
{.input = "AccountRoot", .expected = ripple::ltACCOUNT_ROOT},
{.input = "Check", .expected = ripple::ltCHECK},
{.input = "DepositPreauth", .expected = ripple::ltDEPOSIT_PREAUTH},
{.input = "Escrow", .expected = ripple::ltESCROW},
{.input = "Offer", .expected = ripple::ltOFFER},
{.input = "PayChannel", .expected = ripple::ltPAYCHAN},
{.input = "SignerList", .expected = ripple::ltSIGNER_LIST},
{.input = "RippleState", .expected = ripple::ltRIPPLE_STATE},
{.input = "Ticket", .expected = ripple::ltTICKET},
{.input = "NFTokenOffer", .expected = ripple::ltNFTOKEN_OFFER},
{.input = "NFTokenPage", .expected = ripple::ltNFTOKEN_PAGE},
{.input = "AMM", .expected = ripple::ltAMM},
{.input = "Bridge", .expected = ripple::ltBRIDGE},
{.input = "XChainOwnedClaimID", .expected = ripple::ltXCHAIN_OWNED_CLAIM_ID},
{.input = "XChainOwnedCreateAccountClaimID", .expected = ripple::ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID},
{.input = "DID", .expected = ripple::ltDID},
{.input = "Oracle", .expected = ripple::ltORACLE},
{.input = "Credential", .expected = ripple::ltCREDENTIAL},
{.input = "MPTokenIssuance", .expected = ripple::ltMPTOKEN_ISSUANCE},
{.input = "MPToken", .expected = ripple::ltMPTOKEN},
{.input = "PermissionedDomain", .expected = ripple::ltPERMISSIONED_DOMAIN},
{.input = "Vault", .expected = ripple::ltVAULT},
{.input = "Delegate", .expected = ripple::ltDELEGATE}
};
static LedgerEntryTypeParam const kCASE_INSENSITIVE_TEST_CASES[] = {
// With canonical name in mixedcase
{.input = "mPtOKenIssuance", .expected = ripple::ltMPTOKEN_ISSUANCE},
// With canonical name in lowercase
{.input = "mptokenissuance", .expected = ripple::ltMPTOKEN_ISSUANCE},
};
static LedgerEntryTypeParam const kINVALID_TEST_CASES[] = {
{.input = "", .expected = ripple::ltANY},
{.input = "1234", .expected = ripple::ltANY},
{.input = "unknown", .expected = ripple::ltANY},
// With RPC name with inexact match
{.input = "MPT_Issuance", .expected = ripple::ltANY}
};
class LedgerEntryTypeFromStrTest : public ::testing::TestWithParam<LedgerEntryTypeParam> {};
TEST_P(LedgerEntryTypeFromStrTest, GetLedgerEntryTypeFromStr)
{
auto const& param = GetParam();
auto const result = util::LedgerTypes::getLedgerEntryTypeFromStr(param.input);
EXPECT_EQ(result, param.expected) << param.input;
}
INSTANTIATE_TEST_SUITE_P(
LedgerUtilsTests,
LedgerEntryTypeFromStrTest,
::testing::ValuesIn([]() {
std::vector<LedgerEntryTypeParam> v;
v.insert(v.end(), std::begin(kCHAIN_TEST_CASES), std::end(kCHAIN_TEST_CASES));
v.insert(v.end(), std::begin(kACCOUNT_OWNED_TEST_CASES), std::end(kACCOUNT_OWNED_TEST_CASES));
v.insert(v.end(), std::begin(kCASE_INSENSITIVE_TEST_CASES), std::end(kCASE_INSENSITIVE_TEST_CASES));
v.insert(v.end(), std::begin(kINVALID_TEST_CASES), std::end(kINVALID_TEST_CASES));
return v;
}())
);
class AccountOwnedLedgerTypeFromStrTest : public ::testing::TestWithParam<LedgerEntryTypeParam> {};
TEST_P(AccountOwnedLedgerTypeFromStrTest, GetAccountOwnedLedgerTypeFromStr)
{
auto const& param = GetParam();
auto const result = util::LedgerTypes::getAccountOwnedLedgerTypeFromStr(param.input);
EXPECT_EQ(result, param.expected);
}
INSTANTIATE_TEST_SUITE_P(
LedgerUtilsTests,
AccountOwnedLedgerTypeFromStrTest,
::testing::ValuesIn([]() {
std::vector<LedgerEntryTypeParam> v;
v.insert(v.end(), std::begin(kACCOUNT_OWNED_TEST_CASES), std::end(kACCOUNT_OWNED_TEST_CASES));
v.insert(v.end(), std::begin(kCASE_INSENSITIVE_TEST_CASES), std::end(kCASE_INSENSITIVE_TEST_CASES));
v.insert(v.end(), std::begin(kINVALID_TEST_CASES), std::end(kINVALID_TEST_CASES));
v.push_back({"amendments", ripple::ltANY}); // chain type should return ltANY
return v;
}())
);