diff --git a/content/concepts/payment-system-basics/ledgers.md b/content/concepts/payment-system-basics/ledgers.md index e4116e4f04..93c0d7b298 100644 --- a/content/concepts/payment-system-basics/ledgers.md +++ b/content/concepts/payment-system-basics/ledgers.md @@ -23,10 +23,28 @@ As its name might suggest, a ledger's state tree is a tree data structure. Each In the case of transactions, the identifying hash is based on the signed transaction instructions, but the contents of the transaction object when you look it up also contain the results and metadata of the transaction, which are not taken into account when generating the hash. +## Open, Closed, and Validated Ledgers + +The `rippled` server makes a distinction between ledger versions that are _open_, _closed_, and _validated_. A server has one open ledger, any number of closed but unvalidated ledgers, and an immutable history of validated ledgers. The following table summarizes the difference: + +| Ledger Type: | Open | Closed | Validated | +|:---------------------------------|:----------------------------|:-------------------------------------------|:--| +| **Purpose:** | Temporary workspace | Proposed next state | Confirmed previous state | +| **Number used:** | 1 | Any number, but usually 0 or 1 | One per ledger index, growing over time | +| **Can contents change?** | Yes | No, but the whole ledger could be replaced | Never | +| **Transactions are applied in:** | The order they are received | Canonical order | Canonical order | + +Unintuitively, the XRP Ledger never "closes" an open ledger to convert it into a closed ledger. Instead, the server throws away the open ledger, creates a new closed ledger by applying transactions on top of a previous closed ledger, then creates a new open ledger using the latest closed ledger as a base. This is a consequence of [how consensus solves the double-spend problem](consensus-principles-and-rules.html#simplifying-the-problem). + +For an open ledger, servers apply transactions in the order those transactions appear, but different servers may see transactions in different orders. Since there is no central timekeeper to decide which transaction was actually first, servers may disagree on the exact order of transactions that were sent around the same time. Thus, the process for calculating a closed ledger version that is eligible for [validation](consensus.html#validation) is different than the process of building an open ledger from proposed transactions in the order they arrive. To create a "closed" ledger, each XRP Ledger server starts with a set of transactions and a previous, or "parent", ledger version. The server puts the transactions in a canonical order, then applies them to the previous ledger in that order. The canonical order is designed to be deterministic and efficient, but hard to game, to increase the difficulty of front-running Offers in the [decentralized exchange](decentralized-exchange.html). + +Thus, an open ledger is only ever used as a temporary workspace, which is a major reason why transactions' [tentative results may vary from their final results](finality-of-results.html). + ## See Also -For more information about ledger headers, ledger object IDs, and ledger object types, see [Ledger Data Formats](ledger-data-formats.html) +- For more information about ledger headers, ledger object IDs, and ledger object types, see [Ledger Data Formats](ledger-data-formats.html) +- For information on how servers track the history of changes to ledger state, see [Ledger History](ledger-history.html) diff --git a/content/concepts/payment-system-basics/transaction-basics/finality-of-results.md b/content/concepts/payment-system-basics/transaction-basics/finality-of-results.md index 99c8da5668..b46957c959 100644 --- a/content/concepts/payment-system-basics/transaction-basics/finality-of-results.md +++ b/content/concepts/payment-system-basics/transaction-basics/finality-of-results.md @@ -1,12 +1,12 @@ # Finality of Results -The order in which transactions apply to the consensus ledger is not final until a ledger is closed and the exact transaction set is approved by the consensus process. A transaction that succeeded initially could still fail, and a transaction that failed initially could still succeed. Additionally, a transaction that was rejected by the consensus process in one round could achieve consensus in a later round. +The order in which transactions apply to the consensus [ledger](ledgers.html) is not final until a ledger is closed and the exact transaction set is approved by the [consensus process](intro-to-consensus.html). A transaction that succeeded initially could still fail, and a transaction that failed initially could still succeed. Additionally, a transaction that was rejected by the consensus process in one round could achieve consensus in a later round. A validated ledger can include successful transactions (`tes` result codes) as well as failed transactions (`tec` result codes). No transaction with any other result is included in a ledger. For any other result code, it can be difficult to determine if the result is final. The following table summarizes when a transaction's outcome is final, based on the result code from submitting the transaction: -| Error Code | Finality | +| Result Code | Finality | |:----------------|:-----------------------------------------------------------| | `tesSUCCESS` | Final when included in a validated ledger | | Any `tec` code | Final when included in a validated ledger | @@ -15,3 +15,41 @@ For any other result code, it can be difficult to determine if the result is fin | `tefMAX_LEDGER` | Final when a validated ledger has a sequence number higher than the transaction's `LastLedgerSequence` field, and no validated ledger includes the transaction | Any other transaction result is potentially not final. In that case, the transaction could still succeed or fail later, especially if conditions change such that the transaction is no longer prevented from applying. For example, trying to send a non-XRP currency to an account that does not exist yet would fail, but it could succeed if another transaction sends enough XRP to create the destination account. A server might even store a temporarily-failed, signed transaction and then successfully apply it later without asking first. + +## How can non-final results change? + +When you initially submit a transaction, the `rippled` server tentatively applies that transaction to its current open ledger, then returns the tentative [transaction results](transaction-results.html) from doing so. However, the transaction's final result may be very different than its tentative results, for several reasons: + +- The transaction may be delayed until a later ledger version, or may never be included in a validated ledger. For the most part, the XRP Ledger follows a principle that all valid transactions should be processed as soon as possible. However, there are exceptions, including: + + - If a proposed transaction has not been relayed to a majority of validators by the time a [consensus round](consensus.html) begins, it may be postponed until the next ledger version, to give the remaining validators time to fetch the transaction and confirm that it is valid. + + - If an address sends two different transactions using the same sequence number, at most one of those transactions can become validated. If those transactions are relayed through the network in different paths, a tentatively-successful transaction that some servers saw first may end up failing because the other, conflicting transaction reached a majority of servers first. + + - To protect the network from spam, all transactions must destroy a [transaction cost](transaction-cost.html) in XRP to be relayed throughout the XRP Ledger peer-to-peer network. If heavy load on the peer-to-peer network causes the transaction cost to increase, a transaction that tentatively succeeded may not get relayed to enough servers to achieve a consensus, or may be [queued](transaction-queue.html) for later. + + - Temporary internet outages or delays may prevent a proposed transaction from being successfully relayed before the transaction's intended expiration, as set by the `LastLedgerSequence` field. (If the transaction does not have an expiration, then it remains valid and could succeed any amount of time later, which can be undesirable in its own way. See [Reliable Transaction Submission](reliable-transaction-submission.html) for details.) + + - Combinations of two or more of these factors can also occur. + +- The [order transactions apply in a closed ledger](ledgers.html#open-closed-and-validated-ledgers) is usually different than the order those transactions were tentatively applied to a current open ledger; depending on the transactions involved, this can cause a tentatively-successful transaction to fail or a tentatively-failed transaction to succeed. Some examples include: + + - If two transactions would each fully consume the same [Offer](offers.html) in the [decentralized exchange](decentralized-exchange.html), whichever one comes first succeeds, and the other fails. Since the order in which those transactions apply may change, the one that succeeded can fail and the one that failed can succeed. Since offers can be partially executed, they could also still succeed, but to a greater or lesser extent. + + - If a [cross-currency payment](cross-currency-payments.html) succeeds by consuming an [Offer](offers.html) in the [decentralized exchange](decentralized-exchange.html), but a different transaction consumes or creates offers in the same order book, the cross-currency payment may succeed with a different exchange rate than it had when it executed tentatively. If it was a [partial payment](partial-payments.html), it could also deliver a different amount. + + - A [Payment transaction][] that tentatively failed because the sender did not have enough funds may later succeed because another transaction delivering the necessary funds came first in the canonical order. The reverse is also possible: a transaction that tentatively succeeded may fail because a transaction delivering the necessary funds did not come first after being put into canonical order. + + **Tip:** For this reason, when running tests against the XRP Ledger, be sure to wait for a ledger close in between transactions if you have several accounts affecting the same data. If you are testing against a server in [stand-alone-mode](rippled-server-modes.html#reasons-to-run-a-rippled-server-in-stand-alone-mode), you must [manually close the ledger](advance-the-ledger-in-stand-alone-mode.html) in such cases. + + +## See Also + +- [Look up Transaction Results](look-up-transaction-results.html) +- [Transaction Results Reference](transaction-results.html) + + + +{% include '_snippets/rippled-api-links.md' %} +{% include '_snippets/tx-type-links.md' %} +{% include '_snippets/rippled_versions.md' %}