Merge pull request #458 from mDuo13/consensus_diagrams
Consensus diagrams
2211
content/_img-sources/consensus-with-queue.svg
Normal file
|
After Width: | Height: | Size: 433 KiB |
@@ -1 +0,0 @@
|
||||
https://docs.google.com/drawings/d/15rIV9apyiVZo6lquys3CBSY9iyiMc0ZorMXOzYN4lW8/edit?usp=sharing
|
||||
@@ -6,35 +6,36 @@ This article provides a high level overview of the XRP Ledger, the information i
|
||||
|
||||
When building applications on the XRP Ledger, it is important to understand this process, so as not to be surprised by the behavior of XRP Ledger APIs and their effects.
|
||||
|
||||
**Caution:** Transactions are not applied to the XRP Ledger instantaneously; it takes some time for the effects of transactions to be applied. During this process, [`rippled` APIs](rippled-api.html) may return provisional results that should not be mistaken for the final, immutable results of a transaction. Immutable results can only be determined by looking at validated ledgers.
|
||||
|
||||
## Introduction
|
||||
|
||||
The peer-to-peer XRP Ledger network provides a worldwide, shared ledger, which gives applications authoritative information about the state of its contents. This state information includes:
|
||||
|
||||
- settings for each [account](accounts.html)
|
||||
- balances between accounts (trust lines)
|
||||
- balances of XRP and [issued currencies](issued-currencies.html)
|
||||
- offers in the distributed exchange
|
||||
- network settings, such as [transaction costs](transaction-cost.html) and [reserve](reserves.html) amounts
|
||||
- a time stamp
|
||||
- a timestamp
|
||||
|
||||
For a full, technical description of which data is included in a ledger version, see the [Ledger Format Reference](ledger-data-formats.html).
|
||||
|
||||
[](img/ledger-components.png)
|
||||
[](img/anatomy-of-a-ledger-complete.png)
|
||||
|
||||
_Figure 1: XRP Ledger Elements_
|
||||
|
||||
The XRP Ledger has a new ledger version every several seconds. The ledger versions that preceded it form the ledger history. Even the most recent validated ledger is part of history, as it represents the state of the network as of a short time ago. In the present, the network is evaluating transactions which may be applied and finalized in the next ledger version.
|
||||
The XRP Ledger has a new ledger version every several seconds. When the network agrees on the contents of a ledger version, that ledger version is _validated_, and its contents can never change. The validated ledger versions that preceded it form the ledger history. Even the most recent validated ledger is part of history, as it represents the state of the network as of a short time ago. In the present, the network is evaluating transactions which may be applied and finalized in the next ledger version. While this evaluation is happening, the network has candidate ledger versions that are not yet validated.
|
||||
|
||||
[](img/ledger-history.png)
|
||||
|
||||
_Figure 2: XRP Ledger Sequence and History_
|
||||
|
||||
A ledger instance is identified by its _sequence number_ <a href="#footnote_1" id="footnote_from_1"><sup>1</sup></a>, also called a _ledger index_. Ledgers are numbered incrementally. If the last validated ledger is N, the previous was N-1 and the next is N+1. The N+1 ledger is produced by applying a set of transactions to ledger N.
|
||||
A ledger version has two identifiers. One identifier is its _ledger index_, also called a _sequence number_. Ledger versions are numbered incrementally. For example, if the current ledger version has ledger index of 100, the previous has ledger index 99 and the next has ledger index 101. The other identifier is a _ledger hash_, which is a digital fingerprint of the ledger's contents.
|
||||
|
||||
User level changes to the ledger are the results of transactions. Examples of [transactions](transaction-formats.html) include payments, changes to account settings or trust lines, and offers to trade. Each transaction authorizes changes to the ledger and is cryptographically signed by an account owner. Transactions are the only way to authorize changes to an account.
|
||||
As servers propose transactions to apply to the ledger, they may create several candidate ledger versions with slightly different contents. These candidate ledger versions have the same ledger index but different ledger hashes. Of the many candidates, only one can become validated. All the other candidate ledger versions are discarded. Thus, there is exactly one validated ledger hash for each ledger index in history.
|
||||
|
||||
A ledger instance also contains a set of transactions and metadata about those transactions. The transactions are those that have been applied to the prior ledger to create the new instance. The metadata records precisely the effects of the transaction on the ledger.
|
||||
User level changes to the ledger are the results of transactions. Examples of [transactions](transaction-formats.html) include payments, changes to account settings or trust lines, and offers to trade. Each transaction authorizes one or more changes to the ledger, and is cryptographically signed by an account owner. Transactions are the only way to authorize changes to an account, or to change anything else in the ledger.
|
||||
|
||||
Each ledger version also contains a set of transactions and metadata about those transactions. The transactions it includes are only the ones that have been applied to the previous ledger version to create the new ledger version. The metadata records the exact effects of the transaction on the ledger's state data.
|
||||
|
||||
[](img/ledger-changes.png)
|
||||
|
||||
@@ -42,73 +43,94 @@ _Figure 3: Transactions Applied to Ledger Version_
|
||||
|
||||
The set of transactions included in a ledger instance are recorded in that ledger and allow auditability of the XRP Ledger history. If an account balance is different in ledger N+1 than it was in ledger N, then ledger N+1 contains the transaction(s) responsible for the change.
|
||||
|
||||
Transactions that appear in a validated ledger may have succeeded in changing the ledger, or may have been processed without doing the requested action. Successful transactions have the **tesSUCCESS** [result code](transaction-results.html) which indicates the requested changes are applied to the ledger and a fee was claimed. Other transactions in the ledger have **tec** class result codes, which indicate transactions that only claim a fee and perform no other changes <a href="#footnote_2" id="footnote_from_2"><sup>2</sup></a>.
|
||||
Transactions that appear in a validated ledger may have succeeded in changing the ledger, or may have been processed without doing the requested action. Successful transactions have the **tesSUCCESS** [result code](transaction-results.html) which indicates the requested changes are applied to the ledger. Failed transactions in the ledger have **tec** class result codes.<a href="#footnote_1" id="from_footnote_1"><sup>1</sup></a>
|
||||
|
||||
Transactions of the **tec** class are included with the ledger because they change an account balance when claiming a fee.
|
||||
All transactions included in a ledger destroy some XRP as a [transaction cost](transaction-cost.html), regardless of whether they had a **tes** or **tec** code. The exact amount of XRP to destroy is defined by the signed transaction instructions.
|
||||
|
||||
In addition to the **tes** and **tec** class result codes, there are **ter**, **tef** and **tem** class codes. The latter three indicate provisional failures returned by API calls. Only **tes** and **tec** codes appear in ledgers.
|
||||
In addition to the **tes** and **tec** class result codes, there are **ter**, **tef** and **tem** class codes. The latter three indicate provisional failures returned by API calls. Only **tes** and **tec** codes appear in ledgers. Transactions that are not included in ledgers cannot have any effect on the ledger state (including XRP balances), but transitions that provisionally failed may still end up succeeding.
|
||||
|
||||
When working with [`rippled` APIs](rippled-api.html), applications must distinguish between candidate transactions proposed for inclusion in a ledger versus validated transactions which are included in a validated ledger. Only transaction results found in a validated ledger are immutable. A candidate transaction may or may not ever be included in a validated ledger.
|
||||
|
||||
Important: Some [`rippled` APIs](rippled-api.html) provide provisional results, based on candidate transactions <a href="#footnote_3" id="footnote_from_3"><sup>3</sup></a>. Applications should never rely on provisional results to determine the final outcome of a transaction. The only way to know with certainty that a transaction finally succeeded is to check the status of the transaction until it is both in a validated ledger and has result code tesSUCCESS. If the transaction is in a validated ledger with any other result code, it has failed. If the ledger specified in a transaction’s [`LastLedgerSequence`](transaction-common-fields.html) has been validated, yet the transaction does not appear in that ledger or any before it, then that transaction has failed and can never appear in any ledger. An outcome is final only for transactions that appear in a validated ledger or can never appear because of `LastLedgerSequence` restrictions as explained later in this document.
|
||||
Important: Some [`rippled` APIs](rippled-api.html) provide provisional results, based on candidate transactions <a href="#footnote_2" id="from_footnote_2"><sup>2</sup></a>. Applications should never rely on provisional results to determine the final outcome of a transaction. The only way to know with certainty that a transaction finally succeeded is to check the status of the transaction until it is both in a validated ledger and has result code tesSUCCESS. If the transaction is in a validated ledger with any other result code, it has failed. If the ledger specified in a transaction’s [`LastLedgerSequence`](transaction-common-fields.html) has been validated, yet the transaction does not appear in that ledger or any before it, then that transaction has failed and can never appear in any ledger. An outcome is final only for transactions that appear in a validated ledger or can never appear because of `LastLedgerSequence` restrictions as explained later in this document.
|
||||
|
||||
## The XRP Ledger Protocol – Consensus and Validation
|
||||
|
||||
The peer-to-peer XRP Ledger network consists of many distributed servers, called nodes, that accept and process transactions. Client applications sign and send transactions to nodes, which relay these candidate transactions throughout the network for processing. Examples of client applications include mobile and web wallets, gateways to financial institutions, and electronic trading platforms.
|
||||
The peer-to-peer XRP Ledger network consists of many independent XRP Ledger servers (typically running [`rippled`](the-rippled-server.html)) that accept and process transactions. Client applications sign and send transactions to XRP Ledger servers, which relay these candidate transactions throughout the network for processing. Examples of client applications include mobile and web wallets, gateways to financial institutions, and electronic trading platforms.
|
||||
|
||||
[](img/xrp-ledger-network.png)
|
||||
|
||||
_Figure 4: Participants in the XRP Ledger Protocol_
|
||||
|
||||
The nodes that receive, relay and process transactions may be either tracking nodes or validating nodes. Tracking nodes’ primary functions include distributing transactions from clients and responding to queries about the ledger. Validating nodes perform the same functions as tracking nodes and additionally contribute to advancing the ledger sequence <a href="#footnote_4" id="footnote_from_4"><sup>4</sup></a>.
|
||||
The servers that receive, relay and process transactions may be either tracking servers or validators. The major functions of tracking servers include distributing transactions from clients and responding to queries about the ledger. Validating servers perform the same functions as tracking servers and also contribute to advancing the ledger sequence <a href="#footnote_3" id="from_footnote_3"><sup>3</sup></a>.
|
||||
|
||||
While accepting transactions submitted by client applications, each tracking node uses the last validated ledger as a starting point. The accepted transactions are candidates. The nodes relay their candidate transactions to their peers, allowing the candidate transactions to propagate throughout the network. Ideally, each candidate transaction would be known to all nodes, allowing each to consider the same set of transactions to apply to the last validated ledger. As transactions take time to propagate however, the nodes do not work with the same set of candidate transactions at all times. To account for this, the XRP Ledger uses a process called consensus to ensure that the same transactions are processed and validated ledgers are consistent across the peer-to-peer XRP Ledger network.
|
||||
While accepting transactions submitted by client applications, each tracking server uses the last validated ledger as a starting point. The accepted transactions are candidates. The servers relay their candidate transactions to their peers, allowing the candidate transactions to propagate throughout the network. Ideally, each candidate transaction would be known to all servers, allowing each to consider the same set of transactions to apply to the last validated ledger. As transactions take time to propagate however, the servers do not work with the same set of candidate transactions at all times. To account for this, the XRP Ledger uses a process called consensus to ensure that the same transactions are processed and validated ledgers are consistent across the peer-to-peer XRP Ledger network.
|
||||
|
||||
### Consensus
|
||||
|
||||
The nodes on the network share information about candidate transactions. Through the consensus process, validating nodes agree on a specific subset of the candidate transactions to be considered for the next ledger. Consensus is an iterative process in which nodes relay proposals, or sets of candidate transactions. Nodes communicate and update proposals until a supermajority <a href="#footnote_5" id="footnote_from_5"><sup>5</sup></a> of peers agree on the same set of candidate transactions.
|
||||
The servers on the network share information about candidate transactions. Through the consensus process, validators agree on a specific subset of the candidate transactions to be considered for the next ledger. Consensus is an iterative process in which servers relay proposals, or sets of candidate transactions. Servers communicate and update proposals until a supermajority <a href="#footnote_4" id="from_footnote_4"><sup>4</sup></a> of chosen validators agree on the same set of candidate transactions.
|
||||
|
||||
During consensus, each node evaluates proposals from a specific set of peers, called chosen validators <a href="#footnote_6" id="footnote_from_6"><sup>6</sup></a>. Chosen validators represent a subset of the network which, when taken collectively, is "trusted" not to collude in an attempt to defraud the node evaluating the proposals. This definition of "trust" does not require that each individual chosen validator is trusted. Rather, validators are chosen based on the expectation they will not collude in a coordinated effort to falsify data relayed to the network <a href="#footnote_7" id="footnote_from_7"><sup>7</sup></a>. <!-- STYLE_OVERRIDE: will -->
|
||||
During consensus, each server evaluates proposals from a specific set of servers, known as that server's trusted validators, or _Unique Node List (UNL)_.<a href="#footnote_5" id="from_footnote_5"><sup>5</sup></a> Trusted validators represent a subset of the network which, when taken collectively, is "trusted" not to collude in an attempt to defraud the server evaluating the proposals. This definition of "trust" does not require that each individual chosen validator is trusted. Rather, validators are chosen based on the expectation they will not collude in a coordinated effort to falsify data relayed to the network <a href="#footnote_6" id="from_footnote_6"><sup>6</sup></a>. <!-- STYLE_OVERRIDE: will -->
|
||||
|
||||
[](img/consensus-candidate-transaction-sets.png)
|
||||
[](img/consensus-rounds.png)
|
||||
|
||||
_Figure 5: Validators Propose Transaction Sets — At the start of consensus, nodes work with different sets of transactions. Rounds of proposals determine which transactions to apply to the ledger, and which must wait for a later round of consensus._
|
||||
_Figure 5: Validators Propose and Revise Transaction Sets — At the start of consensus, validators may have different sets of transactions. In later rounds, servers modify their proposals to match what their trusted validators proposed. This process determines which transactions they should apply to the ledger version currently being discussed, and which they should postpone for later ledger versions._
|
||||
|
||||
Candidate transactions which fail to be included in the agreed-upon proposal remain candidate transactions. They may be considered again in the next round of consensus.
|
||||
Candidate transactions that are not included in the agreed-upon proposal remain candidate transactions. They may be considered again in for the next ledger version. Typically, a transaction which is omitted from one ledger version is included in the next ledger version.
|
||||
|
||||
[](img/consensus-agreed-transaction-set.png)
|
||||
|
||||
_Figure 6: Through Consensus, Nodes Agree On Transaction Set — Nodes apply the agreed-upon set of transactions (shown in green) to the last validated ledger. Transactions not in the set (in red) may be agreed upon in the next round._
|
||||
|
||||
Typically, a transaction which does not pass one round of consensus succeeds in the following round. However, in some circumstances, a transaction could fail to pass consensus indefinitely. One such circumstance is if the network increases the base fee to a value higher than the transaction provides. The transaction could potentially succeed if the fees are lowered at some point in the future.
|
||||
|
||||
The [`LastLedgerSequence` transaction field](transaction-common-fields.html) is a mechanism to expire such a transaction if it does not execute in a reasonable time frame. Applications should include a `LastLedgerSequence` parameter with each transaction. This ensures a transaction either succeeds or fails on or before the specified ledger sequence number, thus limiting the amount of time an application must wait before obtaining a definitive transaction result. For more information, see [Reliable Transaction Submission](reliable-transaction-submission.html).
|
||||
In some circumstances, a transaction could fail to achieve consensus indefinitely. One such circumstance is if the network increases the required [transaction cost](transaction-cost.html) to a value higher than the transaction provides. The transaction could potentially succeed if the fees are lowered at some point in the future. To ensure that a transaction either succeeds or fails within a limited amount of time, transactions can be set to expire if they are not processed by a certain ledger index. For more information, see [Reliable Transaction Submission](reliable-transaction-submission.html).
|
||||
|
||||
### Validation
|
||||
|
||||
When a round of consensus completes, each node computes a new ledger by applying the candidate transactions in the consensus transaction set to the last validated ledger.
|
||||
Validation is the second stage of the overall consensus process, which verifies that the servers got the same results and declares a ledger version final. In rare cases, the first stage of [consensus can fail](consensus-principles-and-rules.html#consensus-can-fail); validation provides a confirmation afterward so that servers can recognize this and act accordingly.
|
||||
|
||||
[](img/consensus-calculate-validation.png)
|
||||
Validation can be broken up into roughly two parts:
|
||||
|
||||
_Figure 7: A Network Node Calculates a Ledger Validation — Each tracking node applies agreed-upon transactions to the last validated ledger. Validating nodes send their results to the entire network._
|
||||
- Calculating the resulting ledger version from an agreed-upon transaction set.
|
||||
- Comparing results and declaring the ledger version validated if enough trusted validators agree.
|
||||
|
||||
The validating nodes calculate a new version of the ledger and relay their results to the network, each sending a signed hash of the ledger it calculated based on the candidate transactions proposed during consensus. These signed hashes, called validations, allow each node to compare the ledger it computed with those of its peers.
|
||||
#### Calculate and Share Validations
|
||||
|
||||
When the consensus process completes, each server independently computes a new ledger from the agreed-upon set of transactions. Each server calculates the results by following the same rules, which can be summarized as follows:
|
||||
|
||||
1. Start with the previous validated ledger.
|
||||
|
||||
2. Place the agreed-upon transaction set in _canonical order_ so that every server processes them the same way.
|
||||
|
||||
[Canonical order](https://github.com/ripple/rippled/blob/8429dd67e60ba360da591bfa905b58a35638fda1/src/ripple/app/misc/CanonicalTXSet.cpp#L25-L36) is not the order the transactions were received, because servers may receive the same transactions in different order. To prevent participants from competing over transaction ordering, canonical order is hard to manipulate.
|
||||
|
||||
3. Process each transaction according to its instructions, in order. Update the ledger's state data accordingly.
|
||||
|
||||
If the transaction cannot be successfully executed, include the transaction with a [`tec`-class result code](tec-codes.html).<a href="#footnote_1" id="from_footnote_1"><sup>1</sup></a>
|
||||
|
||||
For certain "retriable" transaction failures, instead move the transaction to the end of the canonical order to be retried after other transactions in the same ledger version have executed.
|
||||
|
||||
4. Update the ledger header with the appropriate metadata.
|
||||
|
||||
This includes data such as the ledger index, the identifying hash of the previous validated ledger (this one's "parent"), this ledger version's approximate close time, and the cryptographic hashes of this ledger's contents.
|
||||
|
||||
5. Calculate the identifying hash of the new ledger version.
|
||||
|
||||
|
||||
[](img/consensus-calculate-validation.png)
|
||||
|
||||
_Figure 7: An XRP Ledger Server Calculates a Ledger Validation — Each server applies agreed-upon transactions to the previous validated ledger. Validators send their results to the entire network._
|
||||
|
||||
#### Compare Results
|
||||
|
||||
Validators each relay their results in the form of a signed message containing the hash of the ledger version they calculated. These messages, called _validations_, allow each server to compare the ledger it computed with those of its peers.
|
||||
|
||||
[](img/consensus-declare-validation.png)
|
||||
|
||||
_Figure 8: Ledger is Validated When Supermajority of Peers Calculate the Same Result — Nodes compare their calculated ledger with the hashes received from chosen validators. If not in agreement, the node must re-calculate or retrieve the correct ledger._
|
||||
_Figure 8: Ledger is Validated When Supermajority of Peers Calculate the Same Result — Each server compares its calculated ledger with the hashes received from its chosen validators. If not in agreement, the server must recalculate or retrieve the correct ledger._
|
||||
|
||||
Nodes of the network recognize a ledger instance as validated when a supermajority of the peers have signed and broadcast the same validation hash <a href="#footnote_8" id="footnote_from_8"><sup>8</sup></a>. Going forward, transactions are applied to this updated and now validated ledger with sequence number N+1.
|
||||
Servers in the network recognize a ledger instance as validated when a supermajority of the peers have signed and broadcast the same validation hash <a href="#footnote_7" id="from_footnote_7"><sup>7</sup></a>. Going forward, transactions are applied to this updated and now validated ledger with sequence number N+1.
|
||||
|
||||
In cases where a node is in the minority, having computed a ledger that differs from its peers, the node disregards the ledger it computed <a href="#footnote_9" id="footnote_from_9"><sup>9</sup></a>. It recomputes the correct ledger, or retrieves the correct ledger as needed.
|
||||
In cases where a server is in the minority, having computed a ledger that differs from its peers, the server disregards the ledger it computed <a href="#footnote_8" id="from_footnote_8"><sup>8</sup></a>. It recomputes the correct ledger, or retrieves the correct ledger as needed.
|
||||
|
||||
If the network fails to achieve supermajority agreement on validations, this implies that transaction volume was too high or network latency too great for the consensus process to produce consistent proposals. In this case, the nodes repeat the consensus process. As time passes since consensus began, it becomes increasingly likely that a majority of the nodes have received the same set of candidate transactions, as each consensus round reduces disagreement. The XRP Ledger dynamically adjusts [transaction costs](transaction-cost.html) and the time to wait for consensus in response to these conditions.
|
||||
If the network fails to achieve supermajority agreement on validations, this implies that transaction volume was too high or network latency too great for the consensus process to produce consistent proposals. In this case, the servers repeat the consensus process. As time passes since consensus began, it becomes increasingly likely that a majority of the servers have received the same set of candidate transactions, as each consensus round reduces disagreement. The XRP Ledger dynamically adjusts [transaction costs](transaction-cost.html) and the time to wait for consensus in response to these conditions.
|
||||
|
||||
[](img/consensus-validated-ledger.png)
|
||||
Once they reach supermajority agreement on validations, the servers work with the new validated ledger, sequence number N+1. The consensus and validation process repeats <a href="#footnote_9" id="from_footnote_9"><sup>9</sup></a>, considering candidate transactions that were not included in the last round along with new transactions submitted in the meantime.
|
||||
|
||||
_Figure 9: Network Recognises the New Validated Ledger Version — At the end of a round of the consensus process, nodes have an updated validated ledger._
|
||||
|
||||
Once they reach supermajority agreement on validations, the nodes work with the new validated ledger, sequence number N+1. The consensus and validation process repeats <a href="#footnote_10" id="footnote_from_10"><sup>10</sup></a>, considering candidate transactions that were not included in the last round along with new transactions submitted in the meantime.
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
@@ -136,7 +158,7 @@ Best practices for applications submitting transactions include:
|
||||
- Transactions with result code **tesSUCCESS** and `"validated": true` have immutably succeeded.
|
||||
- Transactions with other result codes and `"validated": true` have immutably failed.
|
||||
- Transactions that fail to appear in any validated ledger up to and including the validated ledger identified by the transaction’s `LastLedgerSequence` have immutably failed.
|
||||
- Take care to use a node with a continuous ledger history to detect this case <a href="#footnote_11" id="footnote_from_11"><sup>11</sup></a>.
|
||||
- Take care to use a server with a continuous ledger history to detect this case <a href="#footnote_10" id="from_footnote_10"><sup>10</sup></a>.
|
||||
- It may be necessary to check the status of a transaction repeatedly until the ledger identified by `LastLedgerSequence` is validated.
|
||||
|
||||
## Further Resources
|
||||
@@ -150,24 +172,22 @@ Best practices for applications submitting transactions include:
|
||||
|
||||
## End Notes
|
||||
|
||||
<a href="#footnote_from_1" id="footnote_1"><sup>1</sup></a> – A ledger instance can also be uniquely identified by its hash, which is a digital fingerprint of its contents.
|
||||
<a href="#from_footnote_1" id="footnote_1"><sup>1</sup></a> – Transactions with **tec** result codes do not perform the requested action, but do have effects on the ledger. To prevent abuse of the network and to pay for the cost of distributing the transaction, they destroy the XRP transaction cost. To not block other transactions submitted by the same sender around the same time, they increment the sender's account sequence number. They sometimes also perform maintenance such as deleting expired objects or unfunded trade offers.
|
||||
|
||||
<a href="#footnote_from_2" id="footnote_2"><sup>2</sup></a> – Transactions with **tec** result codes are included in ledgers and not do the requested action. The rationale for this is that multiple transactions may be submitted in sequence, with the order of processing determined by a sequence number associated with an account (not to be confused with the ledger sequence number). To prevent a hold on account sequence numbers which would block later transactions, the transaction is processed to consume the sequence number. Additionally, transactions which are distributed to the network must claim a fee to prevent network abuse.
|
||||
<a href="#from_footnote_2" id="footnote_2"><sup>2</sup></a> – For example, consider a scenario where Alice has $100, and sends all of it to Bob. If an application first submits that payment transaction, then immediately after checks Alice’s balance, the API returns $0. This value is based on the provisional result of a candidate transaction. There are circumstances in which the payment fails and Alice’s balance remains $100 (or, due to other transactions, become some other amount). The only way to know with certainty that Alice’s payment to Bob succeeded is to check the status of the transaction until it is both in a validated ledger and has result code **tesSUCCESS**. If the transaction is in a validated ledger with any other result code, the payment has failed.
|
||||
|
||||
<a href="#footnote_from_3" id="footnote_3"><sup>3</sup></a> – For example, consider a scenario where Alice has $100, and sends all of it to Bob. If an application first submits that payment transaction, then immediately after checks Alice’s balance, the API returns $0. This value is based on the provisional result of a candidate transaction. There are circumstances in which the payment fails and Alice’s balance remains $100 (or, due to other transactions, become some other amount). The only way to know with certainty that Alice’s payment to Bob succeeded is to check the status of the transaction until it is both in a validated ledger and has result code **tesSUCCESS**. If the transaction is in a validated ledger with any other result code, the payment has failed.
|
||||
<a href="#from_footnote_3" id="footnote_3"><sup>3</sup></a> – Strictly speaking, validators are a subset of tracking servers. They provide the same features and additionally send "validation" messages. Tracking servers may be further categorized by whether they keep full vs. partial ledger history.
|
||||
|
||||
<a href="#footnote_from_4" id="footnote_4"><sup>4</sup></a> – Strictly speaking, validating nodes are a subset of tracking nodes. They provide the same features and additionally create "validations." Tracking nodes may be further categorized by whether they keep full vs. partial ledger history.
|
||||
<a href="#from_footnote_4" id="footnote_4"><sup>4</sup></a> – Transactions fail to pass a round of consensus when the percentage of peers recognizing the transaction falls below a threshold. Each round is an iterative process. At the start of the first round, at least 50% of peers must agree. The final threshold for a consensus round is 80% agreement. These specific values are subject to change
|
||||
|
||||
<a href="#footnote_from_5" id="footnote_5"><sup>5</sup></a> – Transactions fail to pass a round of consensus when the percentage of peers recognizing the transaction falls below a threshold. Each round is an iterative process. At the start of the first round, at least 50% of peers must agree. The final threshold for a consensus round is 80% agreement. These specific values are subject to change
|
||||
<a href="#from_footnote_5" id="footnote_5"><sup>5</sup></a> – Each server defines its own trusted validators, but the consistency of the network depends on different servers choosing lists that have a high degree of overlap. For this reason, Ripple publishes a list of recommended validators.
|
||||
|
||||
<a href="#footnote_from_6" id="footnote_6"><sup>6</sup></a> – Sometimes referred to as a Unique Node List (UNL).
|
||||
<a href="#from_footnote_6" id="footnote_6"><sup>6</sup></a> – If proposals from all validators were evaluated, instead of exclusively from the validators chosen not to collude, a malicious attacker could run more validators to gain disproportionate power over the validation process, so they could introduce invalid transactions or omit valid transactions from proposals. The chosen validator list [defends against Sybil attacks](consensus-protections.html#sybil-attacks).
|
||||
|
||||
<a href="#footnote_from_7" id="footnote_7"><sup>7</sup></a> – If proposals from all validators were evaluated, instead of exclusively from the validators chosen not to collude, a malicious attacker could spin up enough validating nodes to form a colluding supermajority to introduce invalid transactions or omit valid transactions from proposals. The chosen validator list defends against Sybil attacks.
|
||||
<a href="#from_footnote_7" id="footnote_7"><sup>7</sup></a> – The supermajority threshold, as of November 2014, requires that at least 80% of peers must agree for a ledger to be validated. This happens to be the same percentage required by a round of consensus. Both thresholds are subject to change and need not be equal.
|
||||
|
||||
<a href="#footnote_from_8" id="footnote_8"><sup>8</sup></a> – The supermajority threshold, as of November 2014, requires that at least 80% of peers must agree for a ledger to be validated. This happens to be the same percentage required by a round of consensus. Both thresholds are subject to change and need not be equal.
|
||||
<a href="#from_footnote_8" id="footnote_8"><sup>8</sup></a> – In practice, the server detects that it is in the minority before receiving validations from all peers. It knows when it receives non-matching validations from over 20% of peers that its validation cannot meet the 80% threshold. At that point, it can begin to recalculate a ledger.
|
||||
|
||||
<a href="#footnote_from_9" id="footnote_9"><sup>9</sup></a> – In practice, the node detects that it is in the minority before receiving validations from all peers. It knows when it receives non-matching validations from over 20% of peers that its validation cannot meet the 80% threshold. At that point, it can begin to recalculate a ledger.
|
||||
<a href="#from_footnote_9" id="footnote_9"><sup>9</sup></a> – In practice, the XRP Ledger runs more efficiently by starting a new round of consensus concurrently, before validation has completed.
|
||||
|
||||
<a href="#footnote_from_10" id="footnote_10"><sup>10</sup></a> – In practice, the XRP Ledger runs more efficiently by starting a new round of consensus concurrently, before validation has completed.
|
||||
|
||||
<a href="#footnote_from_11" id="footnote_11"><sup>11</sup></a> – A `rippled` server can respond to API requests even without a complete ledger history. Interruptions in service or network connectivity can lead to missing ledgers, or gaps, in the node’s ledger history. Over time, if configured to, `rippled` fills in gaps in its history. When testing for missing transactions, it is important to verify against a node with continuous complete ledgers from the time the transaction was submitted until its LastLedgerSequence. Use the RPC server_state to determine which complete_ledgers are available to a particular node.
|
||||
<a href="#from_footnote_10" id="footnote_10"><sup>10</sup></a> – A `rippled` server can respond to API requests even without a complete ledger history. Interruptions in service or network connectivity can lead to missing ledgers, or gaps, in the server’s ledger history. Over time, if configured to, `rippled` fills in gaps in its history. When testing for missing transactions, it is important to verify against a server with continuous complete ledgers from the time the transaction was submitted until its LastLedgerSequence. Use the RPC server_state to determine which complete_ledgers are available to a particular server.
|
||||
|
||||
69
content/concepts/consensus-network/transaction-queue.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Transaction Queue
|
||||
|
||||
The `rippled` server uses a transaction queue to help enforce the [open ledger cost](transaction-cost.html#open-ledger-cost). The open ledger cost sets a target number of transactions in a given ledger, and escalates the required transaction cost very quickly when the open ledger surpasses this size. Rather than discarding transactions that cannot pay the escalated transaction cost, `rippled` tries to put them in a transaction queue, which it uses to build the next ledger.
|
||||
|
||||
## Transaction Queue and Consensus
|
||||
|
||||
The transaction queue plays an important role in selecting the transactions that are included or excluded from a given ledger version in the consensus process. The following steps describe how the transaction queue relates to the [consensus process](consensus.html).
|
||||
|
||||
[](img/consensus-with-queue.png)
|
||||
|
||||
1. **Consensus Round 1** - Each validator proposes a set of transactions to be included in the next ledger version. Each also keeps a queue of candidate transactions not currently proposed.
|
||||
|
||||
2. **Consensus Round 2** - If a validator removes a transaction from its proposal in later rounds, it adds that transaction to its queue.
|
||||
|
||||
3. **Consensus Round N** - The consensus process continues until enough servers agree on a transaction set.
|
||||
|
||||
4. **Validation** - Servers confirm that they built the same resulting ledger and declare it validated.
|
||||
|
||||
5. **Building the Next Proposal** - Each validator prepares its proposal for the next ledger version, starting with queued transactions.
|
||||
|
||||
6. **Adding to the Queue** - If the next proposed ledger is already full, incoming transactions are queued for a later ledger version. (Transactions that pay the [open ledger cost](transaction-cost.html#open-ledger-cost) can still get into the next proposed ledger even if it's "full", but the open ledger cost grows exponentially with each transaction added this way.)
|
||||
|
||||
After this step, the process repeats from the beginning.
|
||||
|
||||
**Note:** Technically, several of the steps described in the above process occur in parallel, because each server is always listening for new transactions, and starts preparing its next ledger proposal while the consensus process for the previous ledger version is ongoing.
|
||||
|
||||
## Queuing Restrictions
|
||||
|
||||
The `rippled` server uses a variety of heuristics to estimate which transactions are "likely to be included in a ledger." The current implementation uses the following rules to decide which transactions to queue:
|
||||
|
||||
* Transactions must be properly-formed and [authorized](transaction-basics.html#authorizing-transactions) with valid signatures.
|
||||
* Transactions with an `AccountTxnID` field cannot be queued.
|
||||
* A single sending address can have at most 10 transactions queued at the same time. In order for a transaction to be queued, the sender must have enough XRP to pay all the XRP costs of all the sender's queued transactions including both the `Fee` fields and the sum of the XRP that each transaction could send. [New in: rippled 0.32.0][]
|
||||
* If a transaction affects how the sending address authorizes transactions, no other transactions from the same address can be queued behind it. [New in: rippled 0.32.0][]
|
||||
* If a transaction includes a `LastLedgerSequence` field, the value of that field must be at least **the current ledger index + 2**.
|
||||
|
||||
### Fee Averaging
|
||||
|
||||
[New in: rippled 0.33.0][]
|
||||
|
||||
If a sending address has one or more transactions queued, that sender can "push" the existing queued transactions into the open ledger by submitting a new transaction with a high enough transaction cost to pay for all of them. Specifically, the new transaction must pay a high enough transaction cost to cover the [open ledger cost](transaction-cost.html#open-ledger-cost) of itself and each other transaction from the same sender before it in the queue. (Keep in mind that the open ledger cost increases exponentially each time a transaction pays it.) The transactions must still follow the other [queuing restrictions](#queuing-restrictions) and the sending address must have enough XRP to pay the transaction costs of all the queued transactions.
|
||||
|
||||
This feature helps you work around a particular situation. If you submitted one or more transactions with a low cost that were queued, you cannot send new transactions from the same address unless you do one of the following:
|
||||
|
||||
* Wait for the queued transactions to be included in a validated ledger, _or_
|
||||
* Wait for the queued transactions to be permanently invalidated if the transactions have the [`LastLedgerSequence` field](reliable-transaction-submission.html#lastledgersequence) set, _or_
|
||||
* [Cancel the queued transactions](cancel-or-skip-a-transaction.html) by submitting a new transaction with the same sequence number and a higher transaction cost.
|
||||
|
||||
If none of the above occur, transactions can stay in the queue for a theoretically unlimited amount of time, while other senders can "cut in line" by submitting transactions with higher transaction costs. Since signed transactions are immutable, you cannot increase the transaction cost of the queued transactions to increase their priority. If you do not want to invalidate the previously submitted transactions, fee averaging provides a workaround. If you increase the transaction cost of your new transaction to compensate, you can ensure the queued transactions are included in an open ledger right away.
|
||||
|
||||
## Order Within the Queue
|
||||
|
||||
Within the transaction queue, transactions are ranked so that transactions paying a higher transaction cost come first. This ranking is not by the transactions' _absolute_ XRP cost, but by costs _relative to the [minimum cost for that type of transaction](transaction-cost.html#special-transaction-costs)_. Transactions that pay the same transaction cost are ranked in the order the server received them. Other factors may also affect the order of transactions in the queue; for example, transactions from the same sender are sorted by their `Sequence` numbers so that they are submitted in order.
|
||||
|
||||
The precise order of transactions in the queue decides which transactions get added to the next in-progress ledger version in cases where there are more transactions in the queue than the expected size of the next ledger version. The order of the transactions **does not affect the order the transactions are executed within a validated ledger**. In each validated ledger version, the transaction set for that version executes in [canonical order](consensus.html#calculate-and-share-validations).
|
||||
|
||||
**Note:** When `rippled` queues a transaction, the provisional [transaction response code](transaction-results.html) is `terQUEUED`. This means that the transaction is likely to succeed in a future ledger version. As with all provisional response codes, the outcome of the transaction is not final until the transaction is either included in a validated ledger, or [rendered permanently invalid](finality-of-results.html).
|
||||
|
||||
|
||||
## See Also
|
||||
|
||||
- [Transaction Cost](transaction-cost.html) for information on why the transaction cost exists and how the XRP Ledger enforces it.
|
||||
- [Consensus](consensus.html) for a detailed description of how the consensus process approves transactions.
|
||||
|
||||
|
||||
<!--{# common link defs #}-->
|
||||
{% include '_snippets/rippled-api-links.md' %}
|
||||
{% include '_snippets/tx-type-links.md' %}
|
||||
{% include '_snippets/rippled_versions.md' %}
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
The XRP Ledger is a shared, global ledger that is open to all. Individual participants can trust the integrity of the ledger without having to trust any single institution to manage it. The `rippled` server software accomplishes this by managing a ledger database that can only be updated according to very specific rules. Each instance of `rippled` keeps a full copy of the ledger, and the peer-to-peer network of `rippled` servers distributes candidate transactions among themselves. The consensus process determines which transactions get applied to each new version of the ledger. See also: [The Consensus Process](consensus.html).
|
||||
|
||||

|
||||

|
||||
|
||||
The shared global ledger is actually a series of individual ledgers, or ledger versions, which `rippled` keeps in its internal database. Every ledger version has a [Ledger Index][] which identifies the order in which ledgers occur. Each closed ledger version also has an identifying hash value, which uniquely identifies the contents of that ledger. At any given time, a `rippled` instance has an in-progress "current" open ledger, plus some number of closed ledgers that have not yet been approved by consensus, and any number of historical ledgers that have been validated by consensus. Only the validated ledgers are certain to be correct and immutable.
|
||||
|
||||
A single ledger version consists of several parts:
|
||||
|
||||

|
||||

|
||||
|
||||
* A **header** - The [Ledger Index][], hashes of its other contents, and other metadata.
|
||||
* A **transaction tree** - The [transactions](transaction-formats.html) that were applied to the previous ledger to make this one. Transactions are the _only_ way to change the ledger.
|
||||
|
||||
@@ -60,34 +60,7 @@ See also: [Fee Escalation explanation in `rippled` repository](https://github.co
|
||||
|
||||
When `rippled` receives a transaction that meets the server's local load cost but not the [open ledger cost](#open-ledger-cost), the server estimates whether the transaction is "likely to be included" in a later ledger. If so, the server adds the transaction to the transaction queue and relays the transaction to other members of the network. Otherwise, the server discards the transaction. The server tries to minimize the amount of network load caused by transactions that would not pay a transaction cost, since [the transaction cost only applies when a transaction is included in a validated ledger](#transaction-costs-and-failed-transactions).
|
||||
|
||||
When the current open ledger closes and the server starts a new open ledger, the server starts taking transactions from the queue to include in the new open ledger. The transaction queue is sorted with the transactions that would pay the highest transaction cost first, proportional to the [reference cost](#reference-transaction-cost) of those transactions. Transactions that pay the same transaction cost are queued in the order the server receives them.
|
||||
|
||||
**Note:** When `rippled` queues a transaction, the provisional [transaction response code](transaction-results.html) is `terQUEUED`. This means that the transaction is likely to succeed in a future ledger version. As with all provisional response codes, the outcome of the transaction is not final until the transaction is either included in a validated ledger, or [rendered permanently invalid](finality-of-results.html).
|
||||
|
||||
#### Queuing Restrictions
|
||||
|
||||
The `rippled` server uses a variety of heuristics to estimate which transactions are "likely to be included in a ledger." The current implementation uses the following rules to decide which transactions to queue:
|
||||
|
||||
* Transactions must be properly-formed and [authorized](transaction-basics.html#authorizing-transactions) with valid signatures.
|
||||
* Transactions with an `AccountTxnID` field cannot be queued.
|
||||
* A single sending address can have at most 10 transactions queued at the same time. In order for a transaction to be queued, the sender must have enough XRP to pay all the XRP costs of all the sender's queued transactions including both the `Fee` fields and the sum of the XRP that each transaction could send. [New in: rippled 0.32.0][]
|
||||
* If a transaction affects how the sending address authorizes transactions, no other transactions from the same address can be queued behind it. [New in: rippled 0.32.0][]
|
||||
* If the transaction includes a `LastLedgerSequence` field, the value of that field must be at least **the current ledger index + 2**.
|
||||
|
||||
#### Fee Averaging
|
||||
|
||||
[New in: rippled 0.33.0][]
|
||||
|
||||
If a sending address has one or more transactions queued, that sender can "push" the existing queued transactions into the open ledger by submitting a new transaction with a high enough transaction cost to pay for all of them. Specifically, the new transaction must increase the total transaction cost of the queued transactions from the same sending address, including the new transaction, to cover the [open ledger cost](#open-ledger-cost) of each transaction as it gets added to the ledger. The total must include the increased open ledger cost for each new transaction. The transactions must still follow the other [queuing restrictions](#queuing-restrictions) and the sending address must have enough XRP to pay the transaction costs of all the queued transactions.
|
||||
|
||||
This feature helps you work around a particular situation. If you submitted one or more transactions with a low cost, which got queued, you cannot send new transactions from the same address unless you do one of the following:
|
||||
|
||||
* Wait for the queued transactions to be included in a validated ledger, _or_
|
||||
* Wait for the queued transactions to be permanently invalidated if the transactions have the [`LastLedgerSequence` field](reliable-transaction-submission.html#lastledgersequence) set, _or_
|
||||
* [Cancel the queued transactions](cancel-or-skip-a-transaction.html) by submitting a new transaction with the same sequence number.
|
||||
|
||||
If none of the above occur, transactions can stay in the queue for a theoretically unlimited amount of time, while other senders can "cut in line" by submitting transactions with higher transaction costs. Since signed transactions are immutable, you cannot increase the transaction cost of the queued transactions to increase their priority. If you do not want to invalidate the previously submitted transactions, fee averaging provides a workaround. If you increase the transaction cost of your new transaction to compensate, you can ensure the queued transactions are included in an open ledger right away.
|
||||
|
||||
For more information on queued transactions, see [Transaction Queue](transaction-queue.html).
|
||||
|
||||
## Reference Transaction Cost
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ Using the history sharding feature, individual `rippled` servers can contribute
|
||||
|
||||
[](img/xrp-ledger-network-ledger-store-and-shard-store.png)
|
||||
|
||||
<!-- Diagram source: https://docs.google.com/presentation/d/1mg2jZQwgfLCIhOU8Mr5aOiYpIgbIgk3ymBoDb2hh7_s/edit#slide=id.g417450e8da_0_316 -->
|
||||
|
||||
## Acquiring and Sharing History Shards
|
||||
|
||||
`rippled` servers acquire and store history shards only if configured to do so. For those servers, acquiring shards begins after synchronizing with the network and backfilling ledger history to the configured number of recent ledgers. During this time of lower network activity, a `rippled` server set to maintain a `shard_db` randomly chooses a shard to add to its shard store. To increase the probability for an even distribution of the network ledger history, shards are randomly selected for acquisition, and the current shard is given no special consideration.
|
||||
|
||||
@@ -9,7 +9,7 @@ These codes indicate an error in the local server processing the transaction; it
|
||||
| `telBAD_DOMAIN` | The transaction specified a domain value (for example, the `Domain` field of an [AccountSet transaction][]) that cannot be used, probably because it is too long to store in the ledger. |
|
||||
| `telBAD_PATH_COUNT` | The transaction contains too many paths for the local server to process. |
|
||||
| `telBAD_PUBLIC_KEY` | The transaction specified a public key value (for example, as the `MessageKey` field of an [AccountSet transaction][]) that cannot be used, probably because it is too long. |
|
||||
| `telCAN_NOT_QUEUE` | The transaction did not meet the [open ledger cost](transaction-cost.html), but this server did not queue this transaction because it did not meet the [queuing restrictions](transaction-cost.html#queuing-restrictions). For example, a transaction returns this code when the sender already has 10 other transactions in the queue. You can try again later or sign and submit a replacement transaction with a higher transaction cost in the `Fee` field. |
|
||||
| `telCAN_NOT_QUEUE` | The transaction did not meet the [open ledger cost](transaction-cost.html), but this server did not queue this transaction because it did not meet the [queuing restrictions](transaction-queue.html#queuing-restrictions). For example, a transaction returns this code when the sender already has 10 other transactions in the queue. You can try again later or sign and submit a replacement transaction with a higher transaction cost in the `Fee` field. |
|
||||
| `telCAN_NOT_QUEUE_BALANCE` | The transaction did not meet the [open ledger cost](transaction-cost.html) and also was not added to the transaction queue because the sum of potential XRP costs of already-queued transactions is greater than the expected balance of the account. You can try again later, or try submitting to a different server. [New in: rippled 0.70.2][] |
|
||||
| `telCAN_NOT_QUEUE_BLOCKS` | The transaction did not meet the [open ledger cost](transaction-cost.html) and also was not added to the transaction queue. This transaction could not replace an existing transaction in the queue because it would block already-queued transactions from the same sender by changing authorization methods. (This includes all [SetRegularKey][] and [SignerListSet][] transactions, as well as [AccountSet][] transactions that change the RequireAuth/OptionalAuth, DisableMaster, or AccountTxnID flags.) You can try again later, or try submitting to a different server. [New in: rippled 0.70.2][] |
|
||||
| `telCAN_NOT_QUEUE_BLOCKED` | The transaction did not meet the [open ledger cost](transaction-cost.html) and also was not added to the transaction queue because a transaction queued ahead of it from the same sender blocks it. (This includes all [SetRegularKey][] and [SignerListSet][] transactions, as well as [AccountSet][] transactions that change the RequireAuth/OptionalAuth, DisableMaster, or AccountTxnID flags.) You can try again later, or try submitting to a different server. [New in: rippled 0.70.2][] |
|
||||
|
||||
@@ -463,6 +463,15 @@ pages:
|
||||
targets:
|
||||
- local
|
||||
|
||||
- md: concepts/consensus-network/transaction-queue.md
|
||||
html: transaction-queue.html
|
||||
funnel: Docs
|
||||
doc_type: Concepts
|
||||
category: Consensus Network
|
||||
blurb: Understand how transactions can be queued before reaching consensus.
|
||||
targets:
|
||||
- local
|
||||
|
||||
- md: concepts/consensus-network/amendments.md
|
||||
html: amendments.html
|
||||
funnel: Docs
|
||||
|
||||
BIN
img/anatomy-of-a-ledger-complete.png
Normal file
|
After Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 238 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 80 KiB |
BIN
img/consensus-with-queue.png
Normal file
|
After Width: | Height: | Size: 261 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 140 KiB |