refactor: Use shared ledger and tx type tables from rpcspec (#3174)

This commit is contained in:
Alex Kremer
2026-09-08 17:23:30 +01:00
committed by GitHub
parent db12445b50
commit 08255c4f9e
13 changed files with 38 additions and 313 deletions

View File

@@ -8,6 +8,6 @@ namespace rpc {
* @brief A wrapper around bool that allows conversion from any JSON value.
*
*/
using JsonBool = spec::JsonBool;
using JsonBool = rpc::spec::JsonBool;
} // namespace rpc

View File

@@ -4,7 +4,6 @@
#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>
@@ -12,6 +11,7 @@
#include <boost/json/value_to.hpp>
#include <fmt/format.h>
#include <rpcspec/Errors.hpp>
#include <rpcspec/LedgerTypes.hpp>
#include <xrpl/basics/StringUtilities.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/AccountID.h>
@@ -117,7 +117,7 @@ CustomValidator CustomValidators::ledgerTypeValidator =
}
auto const type =
util::LedgerTypes::getLedgerEntryTypeFromStr(boost::json::value_to<std::string>(value));
rpc::spec::ledgerEntryTypeFromStr(boost::json::value_to<std::string>(value));
if (type == xrpl::ltANY) {
return Error{
Status{RippledError::RpcInvalidParams, fmt::format("Invalid field '{}'.", key)}
@@ -176,9 +176,8 @@ CustomValidator CustomValidators::accountTypeValidator =
}};
}
auto const type = util::LedgerTypes::getAccountOwnedLedgerTypeFromStr(
boost::json::value_to<std::string>(value)
);
auto const type =
rpc::spec::accountOwnedLedgerTypeFromStr(boost::json::value_to<std::string>(value));
if (type == xrpl::ltANY) {
return Error{
Status{RippledError::RpcInvalidParams, fmt::format("Invalid field '{}'.", key)}

View File

@@ -12,6 +12,7 @@
#include <boost/json/value.hpp>
#include <boost/json/value_to.hpp>
#include <rpcspec/Errors.hpp>
#include <rpcspec/LedgerTypes.hpp>
#include <xrpl/basics/strHex.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
@@ -160,7 +161,7 @@ tag_invoke(boost::json::value_to_tag<AccountObjectsHandler::Input>, boost::json:
}
if (jsonObject.contains(JS(type))) {
input.type = util::LedgerTypes::getAccountOwnedLedgerTypeFromStr(
input.type = rpc::spec::accountOwnedLedgerTypeFromStr(
boost::json::value_to<std::string>(jv.at(JS(type)))
);
}

View File

@@ -10,13 +10,13 @@
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/Validators.hpp"
#include "util/TxUtils.hpp"
#include "util/log/Logger.hpp"
#include <boost/json/array.hpp>
#include <boost/json/conversion.hpp>
#include <boost/json/object.hpp>
#include <boost/json/value.hpp>
#include <rpcspec/TxTypes.hpp>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/TxFormats.h>
#include <xrpl/protocol/jss.h>
@@ -114,7 +114,9 @@ public:
static RpcSpecConstRef
spec([[maybe_unused]] uint32_t apiVersion)
{
auto const& typesKeysInLowercase = util::getTxTypesInLowercase();
// TODO: goes away when account_tx moves to the shared spec, where the tx_type
// validator calls this internally.
auto const& typesKeysInLowercase = rpc::spec::txTypesInLowercase();
static auto const kRpcSpecForV1 = RpcSpec{
{JS(account), validation::Required{}, validation::CustomValidators::accountValidator},
{JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator},

View File

@@ -6,7 +6,6 @@
#include "rpc/common/Types.hpp"
#include "util/Assert.hpp"
#include "util/JsonUtils.hpp"
#include "util/LedgerUtils.hpp"
#include "util/log/Logger.hpp"
#include <boost/json/conversion.hpp>
@@ -14,6 +13,7 @@
#include <boost/json/value.hpp>
#include <boost/json/value_to.hpp>
#include <rpcspec/Errors.hpp>
#include <rpcspec/LedgerTypes.hpp>
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/strHex.h>
#include <xrpl/protocol/LedgerFormats.h>
@@ -215,9 +215,8 @@ tag_invoke(boost::json::value_to_tag<LedgerDataHandler::Input>, boost::json::val
}
if (jsonObject.contains(JS(type))) {
input.type = util::LedgerTypes::getLedgerEntryTypeFromStr(
boost::json::value_to<std::string>(jv.at(JS(type)))
);
input.type =
rpc::spec::ledgerEntryTypeFromStr(boost::json::value_to<std::string>(jv.at(JS(type))));
}
return input;

View File

@@ -9,13 +9,13 @@
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/Validators.hpp"
#include "util/TxUtils.hpp"
#include "util/log/Logger.hpp"
#include <boost/json/array.hpp>
#include <boost/json/conversion.hpp>
#include <boost/json/object.hpp>
#include <boost/json/value.hpp>
#include <rpcspec/TxTypes.hpp>
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/jss.h>
@@ -124,7 +124,9 @@ public:
static RpcSpecConstRef
spec([[maybe_unused]] uint32_t apiVersion)
{
auto const& typesKeysInLowercase = util::getTxTypesInLowercase();
// TODO: goes away when mptoken_issuance_history moves to the shared spec, where the
// validator calls this internally.
auto const& typesKeysInLowercase = rpc::spec::txTypesInLowercase();
static auto const kRpcSpec = RpcSpec{
{JS(mpt_issuance_id),
validation::Required{},

View File

@@ -33,8 +33,6 @@ target_sources(
Taggable.cpp
TerminationHandler.cpp
TimeUtils.cpp
TxUtils.cpp
LedgerUtils.cpp
MPTIssuanceUtils.cpp
config/Array.cpp
config/ArrayView.cpp
@@ -60,6 +58,7 @@ target_link_libraries(
fmt::fmt
openssl::openssl
xrpl::libxrpl
rpcspec::rpcspec
Threads::Threads
clio_options
clio_rpc_center

View File

@@ -1,72 +0,0 @@
#include "util/LedgerUtils.hpp"
#include "util/JsonUtils.hpp"
#include <xrpl/protocol/LedgerFormats.h>
#include <algorithm>
#include <functional>
#include <optional>
#include <string>
#include <unordered_map>
namespace util {
xrpl::LedgerEntryType
LedgerTypes::getLedgerEntryTypeFromStr(std::string const& entryName)
{
if (auto const result = getLedgerTypeAttributeFromStr(entryName); result.has_value()) {
return result->get().type_;
}
return xrpl::ltANY;
}
xrpl::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 xrpl::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 kNameMap = []() {
std::unordered_map<std::string, std::reference_wrapper<impl::LedgerTypeAttribute const>>
map;
std::ranges::for_each(kLedgerTypes, [&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 kRpcNameMap = []() {
std::unordered_map<std::string, std::reference_wrapper<impl::LedgerTypeAttribute const>>
map;
std::ranges::for_each(kLedgerTypes, [&map](auto const& item) {
map.insert({item.rpcName_, item});
});
return map;
}();
if (auto const it = kRpcNameMap.find(entryName); it != kRpcNameMap.end()) {
return it->second;
}
auto const entryNameLowercase = util::toLower(entryName);
if (auto const it = kNameMap.find(entryNameLowercase); it != kNameMap.end()) {
return it->second;
}
return std::nullopt;
}
} // namespace util

View File

@@ -1,8 +1,7 @@
#pragma once
#include "rpc/JS.hpp"
#include <fmt/format.h>
#include <rpcspec/LedgerTypes.hpp>
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/StringUtilities.h>
#include <xrpl/basics/strHex.h>
@@ -12,158 +11,19 @@
#include <algorithm>
#include <array>
#include <functional>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_set>
#include <vector>
namespace util {
class LedgerTypes;
namespace impl {
class LedgerTypeAttribute {
enum class LedgerCategory {
Invalid,
AccountOwned, // The ledger object is owned by account
Chain, // The ledger object is shared across the chain
DeletionBlocker // The ledger object is owned by account and it blocks deletion
};
xrpl::LedgerEntryType type_ = xrpl::ltANY;
char const* name_ = nullptr;
char const* rpcName_ = nullptr;
LedgerCategory category_ = LedgerCategory::Invalid;
constexpr LedgerTypeAttribute(
char const* name,
char const* rpcName,
xrpl::LedgerEntryType type,
LedgerCategory category
)
: type_{type}, name_{name}, rpcName_{rpcName}, category_{category}
{
}
public:
static constexpr LedgerTypeAttribute
chainLedgerType(char const* name, char const* rpcName, xrpl::LedgerEntryType type)
{
return LedgerTypeAttribute(name, rpcName, type, LedgerCategory::Chain);
}
static constexpr LedgerTypeAttribute
accountOwnedLedgerType(char const* name, char const* rpcName, xrpl::LedgerEntryType type)
{
return LedgerTypeAttribute(name, rpcName, type, LedgerCategory::AccountOwned);
}
static constexpr LedgerTypeAttribute
deletionBlockerLedgerType(char const* name, char const* rpcName, xrpl::LedgerEntryType type)
{
return LedgerTypeAttribute(name, rpcName, type, LedgerCategory::DeletionBlocker);
}
friend class util::LedgerTypes;
};
} // namespace impl
/**
* @brief A helper class that provides lists of different ledger type category.
*
*/
class LedgerTypes {
using LedgerTypeAttribute = impl::LedgerTypeAttribute;
using LedgerTypeAttributeList = LedgerTypeAttribute[];
static constexpr LedgerTypeAttributeList const kLedgerTypes{
LedgerTypeAttribute::accountOwnedLedgerType(
JS(AccountRoot),
JS(account),
xrpl::ltACCOUNT_ROOT
),
LedgerTypeAttribute::chainLedgerType(JS(Amendments), JS(amendments), xrpl::ltAMENDMENTS),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(Check), JS(check), xrpl::ltCHECK),
LedgerTypeAttribute::accountOwnedLedgerType(
JS(DepositPreauth),
JS(deposit_preauth),
xrpl::ltDEPOSIT_PREAUTH
),
// dir node belongs to account, but can not be filtered from account_objects
LedgerTypeAttribute::chainLedgerType(JS(DirectoryNode), JS(directory), xrpl::ltDIR_NODE),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(Escrow), JS(escrow), xrpl::ltESCROW),
LedgerTypeAttribute::chainLedgerType(JS(FeeSettings), JS(fee), xrpl::ltFEE_SETTINGS),
LedgerTypeAttribute::chainLedgerType(JS(LedgerHashes), JS(hashes), xrpl::ltLEDGER_HASHES),
LedgerTypeAttribute::accountOwnedLedgerType(JS(Offer), JS(offer), xrpl::ltOFFER),
LedgerTypeAttribute::deletionBlockerLedgerType(
JS(PayChannel),
JS(payment_channel),
xrpl::ltPAYCHAN
),
LedgerTypeAttribute::accountOwnedLedgerType(
JS(SignerList),
JS(signer_list),
xrpl::ltSIGNER_LIST
),
LedgerTypeAttribute::deletionBlockerLedgerType(
JS(RippleState),
JS(state),
xrpl::ltRIPPLE_STATE
),
LedgerTypeAttribute::accountOwnedLedgerType(JS(Ticket), JS(ticket), xrpl::ltTICKET),
LedgerTypeAttribute::accountOwnedLedgerType(
JS(NFTokenOffer),
JS(nft_offer),
xrpl::ltNFTOKEN_OFFER
),
LedgerTypeAttribute::deletionBlockerLedgerType(
JS(NFTokenPage),
JS(nft_page),
xrpl::ltNFTOKEN_PAGE
),
LedgerTypeAttribute::accountOwnedLedgerType(JS(AMM), JS(amm), xrpl::ltAMM),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(Bridge), JS(bridge), xrpl::ltBRIDGE),
LedgerTypeAttribute::deletionBlockerLedgerType(
JS(XChainOwnedClaimID),
JS(xchain_owned_claim_id),
xrpl::ltXCHAIN_OWNED_CLAIM_ID
),
LedgerTypeAttribute::deletionBlockerLedgerType(
JS(XChainOwnedCreateAccountClaimID),
JS(xchain_owned_create_account_claim_id),
xrpl::ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID
),
LedgerTypeAttribute::accountOwnedLedgerType(JS(DID), JS(did), xrpl::ltDID),
LedgerTypeAttribute::accountOwnedLedgerType(JS(Oracle), JS(oracle), xrpl::ltORACLE),
LedgerTypeAttribute::accountOwnedLedgerType(
JS(Credential),
JS(credential),
xrpl::ltCREDENTIAL
),
LedgerTypeAttribute::accountOwnedLedgerType(JS(Vault), JS(vault), xrpl::ltVAULT),
// loan broker is a pseudo-account object, like AMM and Vault
LedgerTypeAttribute::accountOwnedLedgerType(
JS(LoanBroker),
JS(loan_broker),
xrpl::ltLOAN_BROKER
),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(Loan), JS(loan), xrpl::ltLOAN),
LedgerTypeAttribute::chainLedgerType(JS(NegativeUNL), JS(nunl), xrpl::ltNEGATIVE_UNL),
LedgerTypeAttribute::deletionBlockerLedgerType(
JS(MPTokenIssuance),
JS(mpt_issuance),
xrpl::ltMPTOKEN_ISSUANCE
),
LedgerTypeAttribute::deletionBlockerLedgerType(JS(MPToken), JS(mptoken), xrpl::ltMPTOKEN),
LedgerTypeAttribute::deletionBlockerLedgerType(
JS(PermissionedDomain),
JS(permissioned_domain),
xrpl::ltPERMISSIONED_DOMAIN
),
LedgerTypeAttribute::accountOwnedLedgerType(JS(Delegate), JS(delegate), xrpl::ltDELEGATE),
};
static constexpr auto const& kLedgerTypes = rpc::spec::kLedgerTypesTable;
public:
/**
@@ -173,9 +33,9 @@ public:
static constexpr auto
getLedgerEntryTypeStrList()
{
std::array<char const*, std::size(kLedgerTypes)> res{};
std::array<std::string_view, std::size(kLedgerTypes)> res{};
std::ranges::transform(kLedgerTypes, std::begin(res), [](auto const& item) {
return item.rpcName_;
return item.rpcName;
});
return res;
}
@@ -189,7 +49,7 @@ public:
getDeletionBlockerLedgerTypes()
{
constexpr auto kFilter = [](auto const& item) {
return item.category_ == LedgerTypeAttribute::LedgerCategory::DeletionBlocker;
return item.category == rpc::spec::LedgerCategory::DeletionBlocker;
};
constexpr auto kDeletionBlockersCount =
@@ -198,36 +58,12 @@ public:
auto it = std::begin(res);
std::ranges::for_each(kLedgerTypes, [&](auto const& item) {
if (kFilter(item)) {
*it = item.type_;
*it = item.type;
++it;
}
});
return res;
}
/**
* @brief Returns the xrpl::LedgerEntryType from the given string.
*
* @param entryName The name or canonical name (case-insensitive) of the ledger entry type for
* all categories
* @return The xrpl::LedgerEntryType of the given string, returns ltANY if not found.
*/
static xrpl::LedgerEntryType
getLedgerEntryTypeFromStr(std::string const& entryName);
/**
* @brief Returns the xrpl::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 xrpl::LedgerEntryType of the given string, returns ltANY if not found.
*/
static xrpl::LedgerEntryType
getAccountOwnedLedgerTypeFromStr(std::string const& entryName);
private:
static std::optional<std::reference_wrapper<impl::LedgerTypeAttribute const>>
getLedgerTypeAttributeFromStr(std::string const& entryName);
};
/**

View File

@@ -1,33 +0,0 @@
#include "util/JsonUtils.hpp"
#include <xrpl/protocol/TxFormats.h>
#include <algorithm>
#include <iterator>
#include <string>
#include <unordered_set>
namespace util {
/**
* @brief Get the transaction types in lowercase
*
* @return The transaction types in lowercase
*/
[[nodiscard]] std::unordered_set<std::string> const&
getTxTypesInLowercase()
{
static std::unordered_set<std::string> const kTypesKeysInLowercase = []() {
std::unordered_set<std::string> keys;
std::transform(
xrpl::TxFormats::getInstance().begin(),
xrpl::TxFormats::getInstance().end(),
std::inserter(keys, keys.begin()),
[](auto const& pair) { return util::toLower(pair.getName()); }
);
return keys;
}();
return kTypesKeysInLowercase;
}
} // namespace util

View File

@@ -1,9 +0,0 @@
#pragma once
#include <string>
#include <unordered_set>
namespace util {
[[nodiscard]] std::unordered_set<std::string> const&
getTxTypesInLowercase();
} // namespace util

View File

@@ -2,6 +2,7 @@
#include "util/LedgerUtils.hpp"
#include <gtest/gtest.h>
#include <rpcspec/LedgerTypes.hpp>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/jss.h>
@@ -55,16 +56,16 @@ TEST(LedgerUtilsTests, LedgerObjectTypeList)
TEST(LedgerUtilsTests, StrToType)
{
EXPECT_EQ(util::LedgerTypes::getLedgerEntryTypeFromStr("mess"), xrpl::ltANY);
EXPECT_EQ(util::LedgerTypes::getLedgerEntryTypeFromStr("tomato"), xrpl::ltANY);
EXPECT_EQ(util::LedgerTypes::getLedgerEntryTypeFromStr("account"), xrpl::ltACCOUNT_ROOT);
EXPECT_EQ(util::LedgerTypes::getLedgerEntryTypeFromStr("AccoUnt"), xrpl::ltANY);
EXPECT_EQ(util::LedgerTypes::getLedgerEntryTypeFromStr("AccountRoot"), xrpl::ltACCOUNT_ROOT);
EXPECT_EQ(util::LedgerTypes::getLedgerEntryTypeFromStr("ACCOUNTRoot"), xrpl::ltACCOUNT_ROOT);
EXPECT_EQ(rpc::spec::ledgerEntryTypeFromStr("mess"), xrpl::ltANY);
EXPECT_EQ(rpc::spec::ledgerEntryTypeFromStr("tomato"), xrpl::ltANY);
EXPECT_EQ(rpc::spec::ledgerEntryTypeFromStr("account"), xrpl::ltACCOUNT_ROOT);
EXPECT_EQ(rpc::spec::ledgerEntryTypeFromStr("AccoUnt"), xrpl::ltANY);
EXPECT_EQ(rpc::spec::ledgerEntryTypeFromStr("AccountRoot"), xrpl::ltACCOUNT_ROOT);
EXPECT_EQ(rpc::spec::ledgerEntryTypeFromStr("ACCOUNTRoot"), xrpl::ltACCOUNT_ROOT);
constexpr auto kTypes = util::LedgerTypes::getLedgerEntryTypeStrList();
std::ranges::for_each(kTypes, [](auto const& typeStr) {
EXPECT_NE(util::LedgerTypes::getLedgerEntryTypeFromStr(typeStr), xrpl::ltANY);
EXPECT_NE(rpc::spec::ledgerEntryTypeFromStr(std::string{typeStr}), xrpl::ltANY);
});
}
@@ -193,7 +194,7 @@ class LedgerEntryTypeFromStrTest : public ::testing::TestWithParam<LedgerEntryTy
TEST_P(LedgerEntryTypeFromStrTest, GetLedgerEntryTypeFromStr)
{
auto const& param = GetParam();
auto const result = util::LedgerTypes::getLedgerEntryTypeFromStr(param.input);
auto const result = rpc::spec::ledgerEntryTypeFromStr(param.input);
EXPECT_EQ(result, param.expected) << param.input;
}
@@ -217,7 +218,7 @@ class AccountOwnedLedgerTypeFromStrTest : public ::testing::TestWithParam<Ledger
TEST_P(AccountOwnedLedgerTypeFromStrTest, GetAccountOwnedLedgerTypeFromStr)
{
auto const& param = GetParam();
auto const result = util::LedgerTypes::getAccountOwnedLedgerTypeFromStr(param.input);
auto const result = rpc::spec::accountOwnedLedgerTypeFromStr(param.input);
EXPECT_EQ(result, param.expected);
}

View File

@@ -1,7 +1,7 @@
#include "util/JsonUtils.hpp"
#include "util/TxUtils.hpp"
#include <gtest/gtest.h>
#include <rpcspec/TxTypes.hpp>
#include <xrpl/protocol/TxFormats.h>
#include <algorithm>
@@ -10,7 +10,7 @@
TEST(TxUtilTests, txTypesInLowercase)
{
auto const& types = util::getTxTypesInLowercase();
auto const& types = rpc::spec::txTypesInLowercase();
ASSERT_TRUE(
std::size_t(
std::distance(