diff --git a/include/xrpl/protocol/TER.h b/include/xrpl/protocol/TER.h index c89610f354..083fbdf8b6 100644 --- a/include/xrpl/protocol/TER.h +++ b/include/xrpl/protocol/TER.h @@ -1,3 +1,15 @@ +/** @file + * Transaction Engine Result (TER) code taxonomy for the XRP Ledger. + * + * Defines the six result-code enumerations (tel/tem/tef/ter/tes/tec), + * the strongly-typed `TERSubset` wrapper that enforces which + * categories are permitted in a given context, the `NotTEC` and `TER` + * aliases, comparison operators, and lookup utilities. + * + * Every code value is part of the wire protocol: numeric values are + * stored in ledger metadata and consumed by `ripple-binary-codec`. + * @see https://xrpl.org/transaction-results.html + */ #pragma once // NOLINTBEGIN(readability-identifier-naming) @@ -12,15 +24,29 @@ namespace xrpl { -// See https://xrpl.org/transaction-results.html -// -// "Transaction Engine Result" -// or Transaction ERror. -// +/** Underlying integer type shared by all TER code enumerations. + * + * Using a named typedef allows `TERSubset` to store a plain `int` + * without naming a specific enum, and lets `TERtoInt` overloads share + * a single return type that triggers the comparison-operator SFINAE. + * + * @see https://xrpl.org/transaction-results.html + */ using TERUnderlyingType = int; //------------------------------------------------------------------------------ +/** Local-error result codes (range −399..−300). + * + * A `tel` result means this node alone rejected the transaction; the + * decision is not propagated to the network. The transaction is not + * forwarded to peers and no fee check is performed. Common causes: + * fee below the local minimum, or path counts that exceed node-local + * limits. These codes are only valid during non-consensus processing. + * + * @note Numeric values are stable and encoded in `ripple-binary-codec`. + * Never renumber or remove existing enumerators. + */ // Protocol-critical, mixed with custom TER wrapper type, hundreds of usages // NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) enum TELcodes : TERUnderlyingType { @@ -28,11 +54,6 @@ enum TELcodes : TERUnderlyingType { // Exact numbers are used in ripple-binary-codec: // https://github.com/XRPLF/xrpl.js/blob/main/packages/ripple-binary-codec/src/enums/definitions.json // Use tokens. - - // -399 .. -300: L Local error (transaction fee inadequate, exceeds local - // limit) Only valid during non-consensus processing. Implications: - // - Not forwarded - // - No fee check telLOCAL_ERROR = -399, telBAD_DOMAIN, telBAD_PATH_COUNT, @@ -54,6 +75,15 @@ enum TELcodes : TERUnderlyingType { //------------------------------------------------------------------------------ +/** Malformed-transaction result codes (range −299..−200). + * + * A `tem` result means the transaction is structurally corrupt and + * cannot succeed in any possible ledger state. The transaction is + * rejected without being applied or forwarded, and no fee is charged. + * + * @note Numeric values are stable and encoded in `ripple-binary-codec`. + * Never renumber or remove existing enumerators. + */ // Protocol-critical, mixed with custom TER wrapper type, hundreds of usages // NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) enum TEMcodes : TERUnderlyingType { @@ -61,15 +91,6 @@ enum TEMcodes : TERUnderlyingType { // Exact numbers are used in ripple-binary-codec: // https://github.com/XRPLF/xrpl.js/blob/main/packages/ripple-binary-codec/src/enums/definitions.json // Use tokens. - - // -299 .. -200: M Malformed (bad signature) - // Causes: - // - Transaction corrupt. - // Implications: - // - Not applied - // - Not forwarded - // - Reject - // - Cannot succeed in any imagined ledger. temMALFORMED = -299, temBAD_AMOUNT, @@ -106,8 +127,8 @@ enum TEMcodes : TERUnderlyingType { temCANNOT_PREAUTH_SELF, temINVALID_COUNT, - temUNCERTAIN, // An internal intermediate result; should never be returned. - temUNKNOWN, // An internal intermediate result; should never be returned. + temUNCERTAIN, ///< Internal sentinel — in the process of determining a result; never returned to callers. + temUNKNOWN, ///< Internal sentinel — logic not yet implemented; never returned to callers. temSEQ_AND_TICKET, temBAD_NFTOKEN_TRANSFER_FEE, @@ -132,6 +153,17 @@ enum TEMcodes : TERUnderlyingType { //------------------------------------------------------------------------------ +/** Failure result codes (range −199..−100). + * + * A `tef` result means the transaction cannot be applied because of the + * current ledger state (e.g., sequence already used, bad signature, or + * an unexpected C++ exception). The transaction is not applied, not + * forwarded, and no fee is charged. Unlike `tem`, a `tef` transaction + * could theoretically succeed in a different ledger state. + * + * @note Numeric values are stable and encoded in `ripple-binary-codec`. + * Never renumber or remove existing enumerators. + */ // Protocol-critical, mixed with custom TER wrapper type, hundreds of usages // NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) enum TEFcodes : TERUnderlyingType { @@ -139,19 +171,6 @@ enum TEFcodes : TERUnderlyingType { // Exact numbers are used in ripple-binary-codec: // https://github.com/XRPLF/xrpl.js/blob/main/packages/ripple-binary-codec/src/enums/definitions.json // Use tokens. - - // -199 .. -100: F - // Failure (sequence number previously used) - // - // Causes: - // - Transaction cannot succeed because of ledger state. - // - Unexpected ledger state. - // - C++ exception. - // - // Implications: - // - Not applied - // - Not forwarded - // - Could succeed in an imagined ledger. tefFAILURE = -199, tefALREADY, tefBAD_ADD_AUTH, @@ -178,6 +197,18 @@ enum TEFcodes : TERUnderlyingType { //------------------------------------------------------------------------------ +/** Retry result codes (range −99..−1). + * + * A `ter` result means the transaction cannot succeed right now, but + * might succeed after other transactions are applied — for example, + * if the sequence number is too high or there are insufficient funds + * for the fee. The transaction is not applied and leaves a sequence + * gap that can block later transactions. It may be held in the + * transaction queue (`terQUEUED`) to retry when fee levels drop. + * + * @note Numeric values are stable and encoded in `ripple-binary-codec`. + * Never renumber or remove existing enumerators. + */ // Protocol-critical, mixed with custom TER wrapper type, hundreds of usages // NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) enum TERcodes : TERUnderlyingType { @@ -185,23 +216,6 @@ enum TERcodes : TERUnderlyingType { // Exact numbers are used in ripple-binary-codec: // https://github.com/XRPLF/xrpl.js/blob/main/packages/ripple-binary-codec/src/enums/definitions.json // Use tokens. - - // -99 .. -1: R Retry - // sequence too high, no funds for txn fee, originating -account - // non-existent - // - // Cause: - // Prior application of another, possibly non-existent, transaction could - // allow this transaction to succeed. - // - // Implications: - // - Not applied - // - May be forwarded - // - Results indicating the txn was forwarded: terQUEUED - // - All others are not forwarded. - // - Might succeed later - // - Hold - // - Makes hole in sequence which jams transactions. terRETRY = -99, terFUNDS_SPENT, // DEPRECATED. terINSUF_FEE_B, // Can't pay fee, therefore don't burden network. @@ -224,57 +238,50 @@ enum TERcodes : TERUnderlyingType { //------------------------------------------------------------------------------ +/** Success result code (value 0). + * + * `tesSUCCESS` is the sole member: the transaction was applied to the + * ledger and forwarded to peers. Its numeric value (0) is stored in + * ledger metadata and must never change. + * + * @note `TERSubset::operator bool()` returns `false` for this code + * (success = falsy), mirroring the conventional C error-code idiom. + */ // Protocol-critical, mixed with custom TER wrapper type, hundreds of usages // NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) enum TEScodes : TERUnderlyingType { // Note: Exact number must stay stable. This code is stored by value // in metadata for historic transactions. - - // 0: S Success (success) - // Causes: - // - Success. - // Implications: - // - Applied - // - Forwarded tesSUCCESS = 0 }; //------------------------------------------------------------------------------ +/** Fee-claim result codes (range 100..255). + * + * A `tec` result means the fee is consumed and the sequence number is + * spent, but no other effect is applied to the ledger. The transaction + * is still applied and forwarded to peers. Typical causes: a payment + * with no valid path, or a transaction that is logically invalid but + * well-formed enough to charge a fee. + * + * When `tapRETRY` is set during application, `tec` codes are demoted + * to `terRETRY` so the transaction can be retried rather than + * consuming the sequence number. + * + * @note **DO NOT CHANGE THESE NUMBERS.** They are stored by value in + * ledger metadata and parsed by external tools such as + * `ripple-binary-codec`. Append new codes; never renumber or remove. + * @note Naming convention: use `tecNO_ENTRY` when the primary ledger + * object targeted by the transaction is missing; use + * `tecOBJECT_NOT_FOUND` when an auxiliary object required to + * complete the transaction cannot be found. + */ // Protocol-critical, mixed with custom TER wrapper type, hundreds of usages // NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) enum TECcodes : TERUnderlyingType { // Note: Exact numbers must stay stable. These codes are stored by // value in metadata for historic transactions. - - // 100 .. 255 C - // Claim fee only (ripple transaction with no good paths, pay to - // non-existent account, no path) - // - // Causes: - // - Success, but does not achieve optimal result. - // - Invalid transaction or no effect, but claim fee to use the sequence - // number. - // - // Implications: - // - Applied - // - Forwarded - // - // Only allowed as a return code of appliedTransaction when !tapRETRY. - // Otherwise, treated as terRETRY. - // - // DO NOT CHANGE THESE NUMBERS: They appear in ledger meta data. - // - // Note: - // tecNO_ENTRY is often used interchangeably with tecOBJECT_NOT_FOUND. - // While there does not seem to be a clear rule which to use when, the - // following guidance will help to keep errors consistent with the - // majority of (but not all) transaction types: - // - tecNO_ENTRY : cannot find the primary ledger object on which the - // transaction is being attempted - // - tecOBJECT_NOT_FOUND : cannot find the additional object(s) needed to - // complete the transaction - tecCLAIM = 100, tecPATH_PARTIAL = 101, tecUNFUNDED_ADD = 102, // Unused legacy code @@ -362,37 +369,56 @@ enum TECcodes : TERUnderlyingType { //------------------------------------------------------------------------------ -// For generic purposes, a free function that returns the value of a TE*codes. +/** Convert a TEL/TEM/TEF/TER/TES/TEC code to its underlying integer value. + * + * These overloads form the single conversion point used by `TERSubset`, + * comparison operators, and any code that needs to inspect the raw + * integer. A free-function overload set is used rather than an explicit + * conversion operator on `TERSubset` to prevent silent implicit + * conversions in constructor-initialization contexts (e.g., `Status(TER)` + * would compile silently even with `explicit` — a named function does not). + * + * A matching `friend` overload for `TERSubset` is defined inside + * the class template; the six overloads below cover the raw enum types. + * + * @param v The enum code to convert. + * @return The underlying `int` value of `v`. + */ constexpr TERUnderlyingType TERtoInt(TELcodes v) { return safeCast(v); } +/** @copydoc TERtoInt(TELcodes) */ constexpr TERUnderlyingType TERtoInt(TEMcodes v) { return safeCast(v); } +/** @copydoc TERtoInt(TELcodes) */ constexpr TERUnderlyingType TERtoInt(TEFcodes v) { return safeCast(v); } +/** @copydoc TERtoInt(TELcodes) */ constexpr TERUnderlyingType TERtoInt(TERcodes v) { return safeCast(v); } +/** @copydoc TERtoInt(TELcodes) */ constexpr TERUnderlyingType TERtoInt(TEScodes v) { return safeCast(v); } +/** @copydoc TERtoInt(TELcodes) */ constexpr TERUnderlyingType TERtoInt(TECcodes v) { @@ -400,15 +426,37 @@ TERtoInt(TECcodes v) } //------------------------------------------------------------------------------ -// Template class that is specific to selected ranges of error codes. The -// Trait tells std::enable_if which ranges are allowed. + +/** Strongly-typed wrapper around a TER integer that restricts which + * result-code categories may be implicitly assigned or constructed. + * + * The `Trait` policy class template determines which `TE*codes` enum + * types are accepted. A specialization of `Trait` that inherits from + * `std::true_type` permits `T`; one inheriting from `std::false_type` + * rejects it at compile time via `std::enable_if`. This provides + * category-level type safety without runtime overhead. + * + * Two concrete aliases are provided: + * - `NotTEC` — permits `tel`, `tem`, `tef`, `ter`, `tes`; **excludes + * `tec`**. Used as the return type of `preflight()` to prevent fee-theft + * via unsigned transactions (see `CanCvtToNotTEC`). + * - `TER` — permits all six categories including `tec` and `NotTEC` + * (widening assignment from `NotTEC` to `TER` is always valid). + * + * Default-constructs to `tesSUCCESS`. Truthy (`operator bool`) when the + * stored code is anything other than `tesSUCCESS`. + * + * @tparam Trait A class template whose specializations for each `TE*codes` + * type inherit from `std::true_type` (allowed) or `std::false_type` + * (disallowed). + */ template