From c7bfd6a7e1028caabc54343eff67bb5ae9c93384 Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Thu, 16 Jul 2026 20:01:49 -0400 Subject: [PATCH] feat: export ledger name spaces via server_definitions --- include/xrpl/protocol/Indexes.h | 35 ++++++++ .../protocol/detail/ledger_name_spaces.macro | 59 +++++++++++++ include/xrpl/protocol/jss.h | 1 + src/libxrpl/protocol/Indexes.cpp | 82 ++++++------------- src/test/rpc/ServerDefinitions_test.cpp | 16 ++++ .../server_info/ServerDefinitions.cpp | 7 ++ 6 files changed, 141 insertions(+), 59 deletions(-) create mode 100644 include/xrpl/protocol/detail/ledger_name_spaces.macro diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h index 07493da0bd..7edb079ca7 100644 --- a/include/xrpl/protocol/Indexes.h +++ b/include/xrpl/protocol/Indexes.h @@ -17,11 +17,46 @@ #include #include #include +#include #include +#include #include namespace xrpl { +/** + * Type-specific prefix for calculating ledger indices. + * + * The identifier for a given object within the ledger is calculated based + * on some object-specific parameters. To ensure that different types of + * objects have different indices, even if they happen to use the same set + * of parameters, we use "tagged hashing" by adding a type-specific prefix. + * + * The name spaces are listed in detail/ledger_name_spaces.macro. + */ +#pragma push_macro("LEDGER_NAME_SPACE") +#undef LEDGER_NAME_SPACE +#pragma push_macro("LEDGER_NAME_SPACE_DEPRECATED") +#undef LEDGER_NAME_SPACE_DEPRECATED + +#define LEDGER_NAME_SPACE(name, value) name = (value), +#define LEDGER_NAME_SPACE_DEPRECATED(name, value) name [[deprecated]] = (value), + +enum class LedgerNameSpace : std::uint16_t { +#include +}; + +#undef LEDGER_NAME_SPACE_DEPRECATED +#pragma pop_macro("LEDGER_NAME_SPACE_DEPRECATED") +#undef LEDGER_NAME_SPACE +#pragma pop_macro("LEDGER_NAME_SPACE") + +/** + * The name->value map of active (non-deprecated) ledger name spaces. + */ +std::map const& +ledgerNameSpaceMap(); + class SeqProxy; /** * Keylet computation functions. diff --git a/include/xrpl/protocol/detail/ledger_name_spaces.macro b/include/xrpl/protocol/detail/ledger_name_spaces.macro new file mode 100644 index 0000000000..f8397c9318 --- /dev/null +++ b/include/xrpl/protocol/detail/ledger_name_spaces.macro @@ -0,0 +1,59 @@ +#if !defined(LEDGER_NAME_SPACE) +#error "undefined macro: LEDGER_NAME_SPACE" +#endif +#if !defined(LEDGER_NAME_SPACE_DEPRECATED) +#error "undefined macro: LEDGER_NAME_SPACE_DEPRECATED" +#endif + +// Active ledger name spaces. +// +// @note These values are part of the protocol and *CANNOT* be arbitrarily +// changed. If they were, on-ledger objects may no longer be able to +// be located or addressed. +// +// Additions to this list are OK, but changing existing entries to +// assign them a different values should never be needed. +// +// Entries that are removed should be moved to the deprecated list +// below to prevent accidental reuse. +LEDGER_NAME_SPACE(Account, 'a') +LEDGER_NAME_SPACE(DirNode, 'd') +LEDGER_NAME_SPACE(TrustLine, 'r') +LEDGER_NAME_SPACE(Offer, 'o') +LEDGER_NAME_SPACE(OwnerDir, 'O') +LEDGER_NAME_SPACE(BookDir, 'B') +LEDGER_NAME_SPACE(SkipList, 's') +LEDGER_NAME_SPACE(Escrow, 'u') +LEDGER_NAME_SPACE(Amendments, 'f') +LEDGER_NAME_SPACE(FeeSettings, 'e') +LEDGER_NAME_SPACE(Ticket, 'T') +LEDGER_NAME_SPACE(SignerList, 'S') +LEDGER_NAME_SPACE(XRPPaymentChannel, 'x') +LEDGER_NAME_SPACE(Check, 'C') +LEDGER_NAME_SPACE(DepositPreauth, 'p') +LEDGER_NAME_SPACE(DepositPreauthCredentials, 'P') +LEDGER_NAME_SPACE(NegativeUnl, 'N') +LEDGER_NAME_SPACE(NftokenOffer, 'q') +LEDGER_NAME_SPACE(NftokenBuyOffers, 'h') +LEDGER_NAME_SPACE(NftokenSellOffers, 'i') +LEDGER_NAME_SPACE(Amm, 'A') +LEDGER_NAME_SPACE(Bridge, 'H') +LEDGER_NAME_SPACE(XchainClaimId, 'Q') +LEDGER_NAME_SPACE(XchainCreateAccountClaimId, 'K') +LEDGER_NAME_SPACE(Did, 'I') +LEDGER_NAME_SPACE(Oracle, 'R') +LEDGER_NAME_SPACE(MPTokenIssuance, '~') +LEDGER_NAME_SPACE(MPToken, 't') +LEDGER_NAME_SPACE(Credential, 'D') +LEDGER_NAME_SPACE(PermissionedDomain, 'm') +LEDGER_NAME_SPACE(Delegate, 'E') +LEDGER_NAME_SPACE(Vault, 'V') +LEDGER_NAME_SPACE(LoanBroker, 'l') // lower-case L +LEDGER_NAME_SPACE(Loan, 'L') +LEDGER_NAME_SPACE(Sponsorship, '>') + +// No longer used or supported. Left here to reserve the space to avoid +// accidental reuse, and intentionally not exported to clients. +LEDGER_NAME_SPACE_DEPRECATED(Contract, 'c') +LEDGER_NAME_SPACE_DEPRECATED(Generator, 'g') +LEDGER_NAME_SPACE_DEPRECATED(Nickname, 'n') diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index 63e877ca31..19e0b399cc 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -350,6 +350,7 @@ JSS(LEDGER_ENTRY_TYPES); // out: RPC server_definitions // matches definitions.json format JSS(LEDGER_ENTRY_FLAGS); // out: RPC server_definitions JSS(LEDGER_ENTRY_FORMATS); // out: RPC server_definitions +JSS(LEDGER_NAME_SPACES); // out: RPC server_definitions JSS(levels); // LogLevels JSS(limit); // in/out: AccountTx*, AccountOffers, AccountLines, AccountObjects // in: LedgerData, BookOffers diff --git a/src/libxrpl/protocol/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp index 95416d0f2a..ba264257f6 100644 --- a/src/libxrpl/protocol/Indexes.cpp +++ b/src/libxrpl/protocol/Indexes.cpp @@ -26,7 +26,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -50,66 +52,28 @@ std::array, 6> const kDirectAccountKeylets{ .includeInTests = true}, {.function = &keylet::did, .expectedLEName = jss::DID, .includeInTests = true}}}; -/** - * Type-specific prefix for calculating ledger indices. - * - * The identifier for a given object within the ledger is calculated based - * on some object-specific parameters. To ensure that different types of - * objects have different indices, even if they happen to use the same set - * of parameters, we use "tagged hashing" by adding a type-specific prefix. - * - * @note These values are part of the protocol and *CANNOT* be arbitrarily - * changed. If they were, on-ledger objects may no longer be able to - * be located or addressed. - * - * Additions to this list are OK, but changing existing entries to - * assign them a different values should never be needed. - * - * Entries that are removed should be moved to the bottom of the enum - * and marked as [[deprecated]] to prevent accidental reuse. - */ -enum class LedgerNameSpace : std::uint16_t { - Account = 'a', - DirNode = 'd', - TrustLine = 'r', - Offer = 'o', - OwnerDir = 'O', - BookDir = 'B', - SkipList = 's', - Escrow = 'u', - Amendments = 'f', - FeeSettings = 'e', - Ticket = 'T', - SignerList = 'S', - XRPPaymentChannel = 'x', - Check = 'C', - DepositPreauth = 'p', - DepositPreauthCredentials = 'P', - NegativeUnl = 'N', - NftokenOffer = 'q', - NftokenBuyOffers = 'h', - NftokenSellOffers = 'i', - Amm = 'A', - Bridge = 'H', - XchainClaimId = 'Q', - XchainCreateAccountClaimId = 'K', - Did = 'I', - Oracle = 'R', - MPTokenIssuance = '~', - MPToken = 't', - Credential = 'D', - PermissionedDomain = 'm', - Delegate = 'E', - Vault = 'V', - LoanBroker = 'l', // lower-case L - Loan = 'L', - Sponsorship = '>', +std::map const& +ledgerNameSpaceMap() +{ +#pragma push_macro("LEDGER_NAME_SPACE") +#undef LEDGER_NAME_SPACE +#pragma push_macro("LEDGER_NAME_SPACE_DEPRECATED") +#undef LEDGER_NAME_SPACE_DEPRECATED - // No longer used or supported. Left here to reserve the space to avoid accidental reuse. - Contract [[deprecated]] = 'c', - Generator [[deprecated]] = 'g', - Nickname [[deprecated]] = 'n', -}; +#define LEDGER_NAME_SPACE(name, value) {#name, static_cast(LedgerNameSpace::name)}, +#define LEDGER_NAME_SPACE_DEPRECATED(name, value) + + static std::map const kMap{ +#include + }; + +#undef LEDGER_NAME_SPACE_DEPRECATED +#pragma pop_macro("LEDGER_NAME_SPACE_DEPRECATED") +#undef LEDGER_NAME_SPACE +#pragma pop_macro("LEDGER_NAME_SPACE") + + return kMap; +} template static uint256 diff --git a/src/test/rpc/ServerDefinitions_test.cpp b/src/test/rpc/ServerDefinitions_test.cpp index 0cf6b315e0..b4dd9a7c41 100644 --- a/src/test/rpc/ServerDefinitions_test.cpp +++ b/src/test/rpc/ServerDefinitions_test.cpp @@ -31,6 +31,7 @@ public: BEAST_EXPECT(result[jss::result][jss::status] == "success"); BEAST_EXPECT(result[jss::result].isMember(jss::FIELDS)); BEAST_EXPECT(result[jss::result].isMember(jss::LEDGER_ENTRY_TYPES)); + BEAST_EXPECT(result[jss::result].isMember(jss::LEDGER_NAME_SPACES)); BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_RESULTS)); BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_TYPES)); BEAST_EXPECT(result[jss::result].isMember(jss::TYPES)); @@ -107,6 +108,18 @@ public: BEAST_EXPECT(result[jss::result][jss::TRANSACTION_TYPES]["Payment"].asUInt() == 0); BEAST_EXPECT(result[jss::result][jss::TYPES]["AccountID"].asUInt() == 8); + // test the properties of the LEDGER_NAME_SPACES section + { + json::Value const& nameSpaces = result[jss::result][jss::LEDGER_NAME_SPACES]; + BEAST_EXPECT(nameSpaces["Account"].asUInt() == 97); // 'a' + BEAST_EXPECT(nameSpaces["Vault"].asUInt() == 86); // 'V' + + // deprecated name spaces are not exported + BEAST_EXPECT(!nameSpaces.isMember("Contract")); + BEAST_EXPECT(!nameSpaces.isMember("Generator")); + BEAST_EXPECT(!nameSpaces.isMember("Nickname")); + } + // test the properties of the LEDGER_ENTRY_FLAGS section { BEAST_EXPECT(result[jss::result].isMember(jss::LEDGER_ENTRY_FLAGS)); @@ -441,6 +454,7 @@ public: BEAST_EXPECT(!result[jss::result].isMember(jss::LEDGER_ENTRY_TYPES)); BEAST_EXPECT(!result[jss::result].isMember(jss::LEDGER_ENTRY_FLAGS)); BEAST_EXPECT(!result[jss::result].isMember(jss::LEDGER_ENTRY_FORMATS)); + BEAST_EXPECT(!result[jss::result].isMember(jss::LEDGER_NAME_SPACES)); BEAST_EXPECT(!result[jss::result].isMember(jss::TRANSACTION_RESULTS)); BEAST_EXPECT(!result[jss::result].isMember(jss::TRANSACTION_TYPES)); BEAST_EXPECT(!result[jss::result].isMember(jss::TRANSACTION_FLAGS)); @@ -464,6 +478,7 @@ public: BEAST_EXPECT(result[jss::result].isMember(jss::LEDGER_ENTRY_TYPES)); BEAST_EXPECT(result[jss::result].isMember(jss::LEDGER_ENTRY_FLAGS)); BEAST_EXPECT(result[jss::result].isMember(jss::LEDGER_ENTRY_FORMATS)); + BEAST_EXPECT(result[jss::result].isMember(jss::LEDGER_NAME_SPACES)); BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_RESULTS)); BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_TYPES)); BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_FLAGS)); @@ -486,6 +501,7 @@ public: jss::LEDGER_ENTRY_FLAGS, jss::LEDGER_ENTRY_FORMATS, jss::LEDGER_ENTRY_TYPES, + jss::LEDGER_NAME_SPACES, jss::TRANSACTION_FLAGS, jss::TRANSACTION_FORMATS, jss::TRANSACTION_RESULTS, diff --git a/src/xrpld/rpc/handlers/server_info/ServerDefinitions.cpp b/src/xrpld/rpc/handlers/server_info/ServerDefinitions.cpp index cce1b3e07f..7ed51b5aff 100644 --- a/src/xrpld/rpc/handlers/server_info/ServerDefinitions.cpp +++ b/src/xrpld/rpc/handlers/server_info/ServerDefinitions.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -358,6 +359,12 @@ ServerDefinitions::ServerDefinitions() : defs_{json::ValueType::Object} defs_[jss::ACCOUNT_SET_FLAGS][name] = value; } + defs_[jss::LEDGER_NAME_SPACES] = json::ValueType::Object; + for (auto const& [name, value] : ledgerNameSpaceMap()) + { + defs_[jss::LEDGER_NAME_SPACES][name] = value; + } + // generate hash { std::string const out = json::FastWriter().write(defs_);