/** @file * Authoritative registry for every object type that can live in the XRP Ledger. * * Defines three tightly-coupled, protocol-level artifacts: * * 1. `LedgerEntryType` — the `uint16_t` wire discriminants stored inside every * serialized ledger object. * 2. `LedgerSpecificFlags` / per-object flag accessor functions / `getAllLedgerFlags()` * — flag bitmasks that modify ledger object behavior, together with Meyer's-singleton * accessors consumed by the `server_definitions` RPC endpoint. * 3. `LedgerFormats` — the singleton registry that maps each `LedgerEntryType` to its * `SOTemplate` (field presence schema). * * The `ledger_entries.macro` X-macro file is the single source of truth for all * per-type data; this header and `LedgerFormats.cpp` each include it with a different * macro definition to derive the enum and the format registration from the same table. * * @warning All numeric values defined here are embedded in serialized ledger objects * and transmitted over the wire. Changing them without corresponding amendment * machinery causes a hard fork. * * @ingroup protocol */ #pragma once // NOLINTBEGIN(readability-identifier-naming) #include #include #include #include namespace xrpl { /** Numeric type identifiers for every object type that can exist in the XRP Ledger. * * Each ledger object embeds its `LedgerEntryType` in the serialized form; this allows * the ledger layer to determine an object's type during iteration and to verify that * a hash lookup returned the expected kind of object. * * The concrete values are generated by the `ledger_entries.macro` X-macro, which is * the single source of truth for (tag, value, name, fields) tuples across the enum, * the `LedgerFormats` constructor, and any auto-generated protocol bindings. * * Beyond the macro-generated members, two sentinel pseudo-types (`ltANY`, `ltCHILD`) * are defined manually for use in keylet lookups where the precise object type is * unknown or irrelevant. * * @warning These values are stored in serialized ledger objects and are part of the * protocol. Changing them without special amendment handling causes a hard fork. * * @note Values outside the known range may be used internally, but passing them to * ledger-object APIs will result in an invariant failure. * * @note When retiring an entry type, mark its enumerator `[[deprecated]]` rather than * removing it. Removal would free the numeric slot for accidental reuse. * * @todo C++ enums cannot enforce uniqueness of values at compile time; duplicate IDs * can silently coexist. If the language gains that capability it should be used here. * * @ingroup protocol */ // Protocol-critical, hundreds of usages // NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) enum LedgerEntryType : std::uint16_t { #pragma push_macro("LEDGER_ENTRY") #undef LEDGER_ENTRY #define LEDGER_ENTRY(tag, value, ...) tag = value, #include #undef LEDGER_ENTRY #pragma pop_macro("LEDGER_ENTRY") //--------------------------------------------------------------------------- /** A special type, matching any ledger entry type. The value does not represent a concrete type, but rather is used in contexts where the specific type of a ledger object is unimportant, unknown or unavailable. Objects with this special type cannot be created or stored on the ledger. \sa keylet::unchecked */ ltANY = 0, /** A special type, matching any ledger type except directory nodes. The value does not represent a concrete type, but rather is used in contexts where the ledger object must not be a directory node but its specific type is otherwise unimportant, unknown or unavailable. Objects with this special type cannot be created or stored on the ledger. \sa keylet::child */ ltCHILD = 0x1CD2, //--------------------------------------------------------------------------- /** A legacy, deprecated type. \deprecated **This object type is not supported and should not be used.** Support for this type of object was never implemented. No objects of this type were ever created. */ ltNICKNAME [[deprecated("This object type is not supported and should not be used.")]] = 0x006e, /** A legacy, deprecated type. \deprecated **This object type is not supported and should not be used.** Support for this type of object was never implemented. No objects of this type were ever created. */ ltCONTRACT [[deprecated("This object type is not supported and should not be used.")]] = 0x0063, /** A legacy, deprecated type. \deprecated **This object type is not supported and should not be used.** Support for this type of object was never implemented. No objects of this type were ever created. */ ltGENERATOR_MAP [[deprecated("This object type is not supported and should not be used.")]] = 0x0067, }; /** Flat enum of all per-object flag bitmasks across every ledger entry type. * * Each enumerator is a named bit constant (e.g. `lsfRequireDestTag`, `lsfGlobalFreeze`) * that modifies the behavior of a specific ledger object type. The constants are * generated via the `XMACRO` / `TO_VALUE` pass below, which strips object-type grouping * and collects every flag name and value into a single flat enum. * * @note `LSF_FLAG2` is used when the same bit value appears in more than one object * type (currently `lsfMPTLocked = 0x00000001` shared between `MPTokenIssuance` and * `MPToken`). The second occurrence is silently omitted from this enum via the * `NULL_OUTPUT` helper to avoid a duplicate-enumerator warning, while still appearing * in the per-object flag maps returned by the getter functions below. * * @note Most object types use flag bits starting at `0x00010000`, reserving the low 16 * bits for future use. `DirNode`, `NFTokenOffer`, and the MPToken family deviate * from this convention and use the low-order bits — a legacy of their original * feature designs. * * @warning These values are stored in serialized ledger objects and form part of the * protocol. Changing them without amendment machinery causes a hard fork. * * @ingroup protocol */ #pragma push_macro("XMACRO") #pragma push_macro("TO_VALUE") #pragma push_macro("VALUE_TO_MAP") #pragma push_macro("NULL_NAME") #pragma push_macro("TO_MAP") #pragma push_macro("ALL_LEDGER_FLAGS") #undef XMACRO #undef TO_VALUE #undef VALUE_TO_MAP #undef NULL_NAME #undef TO_MAP #undef ALL_LEDGER_FLAGS // clang-format off #define XMACRO(LEDGER_OBJECT, LSF_FLAG, LSF_FLAG2) \ LEDGER_OBJECT(AccountRoot, \ LSF_FLAG(lsfPasswordSpent, 0x00010000) /* True, if password set fee is spent. */ \ LSF_FLAG(lsfRequireDestTag, 0x00020000) /* True, to require a DestinationTag for payments. */ \ LSF_FLAG(lsfRequireAuth, 0x00040000) /* True, to require a authorization to hold IOUs. */ \ LSF_FLAG(lsfDisallowXRP, 0x00080000) /* True, to disallow sending XRP. */ \ LSF_FLAG(lsfDisableMaster, 0x00100000) /* True, force regular key */ \ LSF_FLAG(lsfNoFreeze, 0x00200000) /* True, cannot freeze ripple states */ \ LSF_FLAG(lsfGlobalFreeze, 0x00400000) /* True, all assets frozen */ \ LSF_FLAG(lsfDefaultRipple, 0x00800000) /* True, incoming trust lines allow rippling by default */ \ LSF_FLAG(lsfDepositAuth, 0x01000000) /* True, all deposits require authorization */ \ LSF_FLAG(lsfDisallowIncomingNFTokenOffer, 0x04000000) /* True, reject new incoming NFT offers */ \ LSF_FLAG(lsfDisallowIncomingCheck, 0x08000000) /* True, reject new checks */ \ LSF_FLAG(lsfDisallowIncomingPayChan, 0x10000000) /* True, reject new paychans */ \ LSF_FLAG(lsfDisallowIncomingTrustline, 0x20000000) /* True, reject new trustlines (only if no issued assets) */ \ LSF_FLAG(lsfAllowTrustLineLocking, 0x40000000) /* True, enable trustline locking */ \ LSF_FLAG(lsfAllowTrustLineClawback, 0x80000000)) /* True, enable clawback */ \ \ LEDGER_OBJECT(Offer, \ LSF_FLAG(lsfPassive, 0x00010000) \ LSF_FLAG(lsfSell, 0x00020000) /* True, offer was placed as a sell. */ \ LSF_FLAG(lsfHybrid, 0x00040000)) /* True, offer is hybrid. */ \ \ LEDGER_OBJECT(RippleState, \ LSF_FLAG(lsfLowReserve, 0x00010000) /* True, if entry counts toward reserve. */ \ LSF_FLAG(lsfHighReserve, 0x00020000) \ LSF_FLAG(lsfLowAuth, 0x00040000) \ LSF_FLAG(lsfHighAuth, 0x00080000) \ LSF_FLAG(lsfLowNoRipple, 0x00100000) \ LSF_FLAG(lsfHighNoRipple, 0x00200000) \ LSF_FLAG(lsfLowFreeze, 0x00400000) /* True, low side has set freeze flag */ \ LSF_FLAG(lsfHighFreeze, 0x00800000) /* True, high side has set freeze flag */ \ LSF_FLAG(lsfAMMNode, 0x01000000) /* True, trust line to AMM. */ \ /* Used by client apps to identify payments via AMM. */ \ LSF_FLAG(lsfLowDeepFreeze, 0x02000000) /* True, low side has set deep freeze flag */ \ LSF_FLAG(lsfHighDeepFreeze, 0x04000000)) /* True, high side has set deep freeze flag */ \ \ LEDGER_OBJECT(SignerList, \ LSF_FLAG(lsfOneOwnerCount, 0x00010000)) /* True, uses only one OwnerCount */ \ \ LEDGER_OBJECT(DirNode, \ LSF_FLAG(lsfNFTokenBuyOffers, 0x00000001) \ LSF_FLAG(lsfNFTokenSellOffers, 0x00000002)) \ \ LEDGER_OBJECT(NFTokenOffer, \ LSF_FLAG(lsfSellNFToken, 0x00000001)) \ \ LEDGER_OBJECT(MPTokenIssuance, \ LSF_FLAG(lsfMPTLocked, 0x00000001) /* Also used in ltMPTOKEN */ \ LSF_FLAG(lsfMPTCanLock, 0x00000002) \ LSF_FLAG(lsfMPTRequireAuth, 0x00000004) \ LSF_FLAG(lsfMPTCanEscrow, 0x00000008) \ LSF_FLAG(lsfMPTCanTrade, 0x00000010) \ LSF_FLAG(lsfMPTCanTransfer, 0x00000020) \ LSF_FLAG(lsfMPTCanClawback, 0x00000040)) \ \ LEDGER_OBJECT(MPTokenIssuanceMutable, \ LSF_FLAG(lsmfMPTCanMutateCanLock, 0x00000002) \ LSF_FLAG(lsmfMPTCanMutateRequireAuth, 0x00000004) \ LSF_FLAG(lsmfMPTCanMutateCanEscrow, 0x00000008) \ LSF_FLAG(lsmfMPTCanMutateCanTrade, 0x00000010) \ LSF_FLAG(lsmfMPTCanMutateCanTransfer, 0x00000020) \ LSF_FLAG(lsmfMPTCanMutateCanClawback, 0x00000040) \ LSF_FLAG(lsmfMPTCanMutateMetadata, 0x00010000) \ LSF_FLAG(lsmfMPTCanMutateTransferFee, 0x00020000)) \ \ LEDGER_OBJECT(MPToken, \ LSF_FLAG2(lsfMPTLocked, 0x00000001) \ LSF_FLAG(lsfMPTAuthorized, 0x00000002) \ LSF_FLAG(lsfMPTAMM, 0x00000004)) \ \ LEDGER_OBJECT(Credential, \ LSF_FLAG(lsfAccepted, 0x00010000)) \ \ LEDGER_OBJECT(Vault, \ LSF_FLAG(lsfVaultPrivate, 0x00010000)) \ \ LEDGER_OBJECT(Loan, \ LSF_FLAG(lsfLoanDefault, 0x00010000) \ LSF_FLAG(lsfLoanImpaired, 0x00020000) \ LSF_FLAG(lsfLoanOverpayment, 0x00040000)) /* True, loan allows overpayments */ // clang-format on // Create all the flag values as an enum. // // example: // enum LedgerSpecificFlags { // lsfPasswordSpent = 0x00010000, // lsfRequireDestTag = 0x00020000, // ... // }; #define TO_VALUE(name, value) name = (value), #define NULL_NAME(name, values) values #define NULL_OUTPUT(name, value) // Bitwise flag enum // NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) enum LedgerSpecificFlags : std::uint32_t { XMACRO(NULL_NAME, TO_VALUE, NULL_OUTPUT) }; /** Map from flag name string to its `uint32_t` bitmask value for a single ledger object type. * * Each entry has the form `{"lsfFlagName", 0xXXXXXXXX}`. Per-object maps are returned * by the `getFlags()` inline functions generated below and are aggregated by * `getAllLedgerFlags()` for the `server_definitions` RPC response. */ using LedgerFlagMap = std::map; // Per-object flag getter functions: getAccountRootFlags(), getOfferFlags(), etc. // Each returns a const LedgerFlagMap& initialized once via Meyer's singleton. // See getAllLedgerFlags() for the aggregating accessor. #define VALUE_TO_MAP(name, value) {#name, value}, #define TO_MAP(name, values) \ inline LedgerFlagMap const& get##name##Flags() \ { \ static LedgerFlagMap const flags = {values}; \ return flags; \ } XMACRO(TO_MAP, VALUE_TO_MAP, VALUE_TO_MAP) /** Return the flags for all ledger object types, keyed by object type name. * * Aggregates every per-object `LedgerFlagMap` (produced by the `getFlags()` * inline functions above) into a single vector, where each element is a pair of * `(object-type-name, flag-map)`. The vector is initialized once via Meyer's singleton. * * This function is the sole data source for the `server_definitions` RPC endpoint, * which exposes the complete ledger flag catalogue to external API consumers. * * @return A stable `const` reference to the process-wide flag catalogue. */ #define ALL_LEDGER_FLAGS(name, values) {#name, get##name##Flags()}, inline std::vector> const& getAllLedgerFlags() { static std::vector> const flags = { XMACRO(ALL_LEDGER_FLAGS, NULL_OUTPUT, NULL_OUTPUT)}; return flags; } #undef XMACRO #undef TO_VALUE #undef VALUE_TO_MAP #undef NULL_NAME #undef NULL_OUTPUT #undef TO_MAP #undef ALL_LEDGER_FLAGS #pragma pop_macro("XMACRO") #pragma pop_macro("TO_VALUE") #pragma pop_macro("VALUE_TO_MAP") #pragma pop_macro("NULL_NAME") #pragma pop_macro("TO_MAP") #pragma pop_macro("ALL_LEDGER_FLAGS") //------------------------------------------------------------------------------ /** Singleton registry mapping every `LedgerEntryType` to its canonical field schema. * * Inherits from `KnownFormats` (CRTP), which provides * O(log n) lookup by type and by name, duplicate-registration detection, and stable * `Item` pointer identity. * * The registry is populated once, during static initialization, via the private * constructor's X-macro pass over `ledger_entries.macro`. Every registered entry * receives an `SOTemplate` built from its type-specific fields plus the three * common fields returned by `getCommonFields()` (`sfLedgerIndex`, `sfLedgerEntryType`, * `sfFlags`). * * Callers in the serialization, deserialization, and invariant-checking layers * access the registry through `getInstance()` to look up schemas by type. * * @see KnownFormats, LedgerEntryType, SOTemplate * @ingroup protocol */ class LedgerFormats : public KnownFormats { private: /** Populate the registry with all known ledger entry formats. * * Uses an X-macro pass over `ledger_entries.macro`, registering each entry type * by calling `KnownFormats::add()` with the entry's name, `LedgerEntryType` * discriminant, type-specific fields, and the common fields from `getCommonFields()`. * * If `ledger_entries.macro` contains a duplicate numeric type ID, `add()` calls * `logicError()` (process abort) during static initialization rather than silently * corrupting the registry. */ LedgerFormats(); public: /** Return the process-wide `LedgerFormats` singleton. * * Uses a function-local static (Meyer's singleton) for thread-safe, once-only * initialization guaranteed by C++11. The first call constructs the registry and * registers every known ledger entry type; subsequent calls return the same instance. * * @return A `const` reference to the global `LedgerFormats` instance. */ static LedgerFormats const& getInstance(); /** Return the three fields that every ledger entry must carry. * * The common fields are: * - `sfLedgerIndex` (`soeOPTIONAL`) — key of the entry in the SHAMap. * - `sfLedgerEntryType` (`soeREQUIRED`) — wire discriminant; must always be present. * - `sfFlags` (`soeREQUIRED`) — object flag bitmask; must always be present. * * These fields are injected into every `SOTemplate` by the constructor, so they do * not need to be listed in each entry type's individual field set in `ledger_entries.macro`. * The vector is initialized once on first call (function-local static). * * @return A stable `const` reference to the common-fields vector. */ static std::vector const& getCommonFields(); }; } // namespace xrpl // NOLINTEND(readability-identifier-naming)