|
rippled
|
Generic implementation of consensus algorithm. More...
#include <Consensus.h>

Classes | |
| class | MonitoredMode |
Public Types | |
| using | clock_type = beast::abstract_clock< std::chrono::steady_clock > |
| Clock type for measuring time within the consensus code. | |
Public Member Functions | |
| Consensus (Consensus &&) noexcept=default | |
| Consensus (clock_type const &clock, Adaptor &adaptor, beast::Journal j) | |
| Constructor. | |
| void | startRound (NetClock::time_point const &now, typename Ledger_t::ID const &prevLedgerID, Ledger_t prevLedger, hash_set< NodeID_t > const &nowUntrusted, bool proposing, std::unique_ptr< std::stringstream > const &clog={}) |
| Kick-off the next round of consensus. | |
| bool | peerProposal (NetClock::time_point const &now, PeerPosition_t const &newProposal) |
| A peer has proposed a new position, adjust our tracking. | |
| void | timerEntry (NetClock::time_point const &now, std::unique_ptr< std::stringstream > const &clog={}) |
| Call periodically to drive consensus forward. | |
| void | gotTxSet (NetClock::time_point const &now, TxSet_t const &txSet) |
| Process a transaction set acquired from the network. | |
| void | simulate (NetClock::time_point const &now, std::optional< std::chrono::milliseconds > consensusDelay) |
| Simulate the consensus process without any network traffic. | |
| Ledger_t::ID | prevLedgerID () const |
| Get the previous ledger ID. | |
| ConsensusPhase | phase () const |
| Json::Value | getJson (bool full) const |
| Get the Json state of the consensus process. | |
Private Types | |
| using | Ledger_t = typename Adaptor::Ledger_t |
| using | TxSet_t = typename Adaptor::TxSet_t |
| using | NodeID_t = typename Adaptor::NodeID_t |
| using | Tx_t = typename TxSet_t::Tx |
| using | PeerPosition_t = typename Adaptor::PeerPosition_t |
| using | Proposal_t = ConsensusProposal< NodeID_t, typename Ledger_t::ID, typename TxSet_t::ID > |
| using | Result = ConsensusResult< Adaptor > |
Private Member Functions | |
| void | startRoundInternal (NetClock::time_point const &now, typename Ledger_t::ID const &prevLedgerID, Ledger_t const &prevLedger, ConsensusMode mode, std::unique_ptr< std::stringstream > const &clog) |
| void | handleWrongLedger (typename Ledger_t::ID const &lgrId, std::unique_ptr< std::stringstream > const &clog) |
| void | checkLedger (std::unique_ptr< std::stringstream > const &clog) |
| Check if our previous ledger matches the network's. | |
| void | playbackProposals () |
| If we radically changed our consensus context for some reason, we need to replay recent proposals so that they're not lost. | |
| bool | peerProposalInternal (NetClock::time_point const &now, PeerPosition_t const &newProposal) |
| Handle a replayed or a new peer proposal. | |
| void | phaseOpen (std::unique_ptr< std::stringstream > const &clog) |
| Handle pre-close phase. | |
| void | phaseEstablish (std::unique_ptr< std::stringstream > const &clog) |
| Handle establish phase. | |
| bool | shouldPause (std::unique_ptr< std::stringstream > const &clog) const |
| Evaluate whether pausing increases likelihood of validation. | |
| void | closeLedger (std::unique_ptr< std::stringstream > const &clog) |
| void | updateOurPositions (std::unique_ptr< std::stringstream > const &clog) |
| bool | haveConsensus (std::unique_ptr< std::stringstream > const &clog) |
| void | createDisputes (TxSet_t const &o, std::unique_ptr< std::stringstream > const &clog={}) |
| void | updateDisputes (NodeID_t const &node, TxSet_t const &other) |
| void | leaveConsensus (std::unique_ptr< std::stringstream > const &clog) |
| NetClock::time_point | asCloseTime (NetClock::time_point raw) const |
Private Attributes | |
| Adaptor & | adaptor_ |
| ConsensusPhase | phase_ {ConsensusPhase::accepted} |
| MonitoredMode | mode_ {ConsensusMode::observing} |
| bool | firstRound_ = true |
| bool | haveCloseTimeConsensus_ = false |
| clock_type const & | clock_ |
| int | convergePercent_ {0} |
| ConsensusTimer | openTime_ |
| NetClock::duration | closeResolution_ = ledgerDefaultTimeResolution |
| ConsensusParms::AvalancheState | closeTimeAvalancheState_ |
| std::chrono::milliseconds | prevRoundTime_ |
| NetClock::time_point | now_ |
| NetClock::time_point | prevCloseTime_ |
| Ledger_t::ID | prevLedgerID_ |
| Ledger_t | previousLedger_ |
| hash_map< typename TxSet_t::ID, TxSet_t const > | acquired_ |
| std::optional< Result > | result_ |
| ConsensusCloseTimes | rawCloseTimes_ |
| std::size_t | peerUnchangedCounter_ = 0 |
| std::size_t | establishCounter_ = 0 |
| hash_map< NodeID_t, PeerPosition_t > | currPeerPositions_ |
| hash_map< NodeID_t, std::deque< PeerPosition_t > > | recentPeerPositions_ |
| std::size_t | prevProposers_ = 0 |
| hash_set< NodeID_t > | deadNodes_ |
| beast::Journal const | j_ |
Generic implementation of consensus algorithm.
Achieves consensus on the next ledger.
Two things need consensus:
The basic flow:
startRound places the node in the Open phase. In this phase, the node is waiting for transactions to include in its open ledger.timerEntry check if the node can close the ledger. Once the node Closes the open ledger, it transitions to the Establish phase. In this phase, the node shares/receives peer proposals on which transactions should be accepted in the closed ledger.timerEntry, the node determines it has reached consensus with its peers on which transactions to include. It transitions to the Accept phase. In this phase, the node works on applying the transactions to the prior ledger to generate a new closed ledger. Once the new ledger is completed, the node shares the validated ledger with the network, does some book-keeping, then makes a call to startRound to start the cycle again.This class uses a generic interface to allow adapting Consensus for specific applications. The Adaptor template implements a set of helper functions that plug the consensus algorithm into a specific application. It also identifies the types that play important roles in Consensus (transactions, ledgers, ...). The code stubs below outline the interface and type requirements. The traits types must be copy constructible and assignable.
| Adaptor | Defines types and provides helper functions needed to adapt Consensus to the larger application. |
Definition at line 278 of file Consensus.h.
|
private |
Definition at line 280 of file Consensus.h.
|
private |
Definition at line 281 of file Consensus.h.
|
private |
Definition at line 282 of file Consensus.h.
|
private |
Definition at line 283 of file Consensus.h.
|
private |
Definition at line 284 of file Consensus.h.
|
private |
Definition at line 285 of file Consensus.h.
|
private |
Definition at line 290 of file Consensus.h.
| using ripple::Consensus< Adaptor >::clock_type = beast::abstract_clock<std::chrono::steady_clock> |
Clock type for measuring time within the consensus code.
Definition at line 318 of file Consensus.h.
|
defaultnoexcept |
| ripple::Consensus< Adaptor >::Consensus | ( | clock_type const & | clock, |
| Adaptor & | adaptor, | ||
| beast::Journal | j | ||
| ) |
Constructor.
| clock | The clock used to internally sample consensus progress |
| adaptor | The instance of the adaptor class |
| j | The journal to log debug output |
Definition at line 620 of file Consensus.h.
| void ripple::Consensus< Adaptor >::startRound | ( | NetClock::time_point const & | now, |
| typename Ledger_t::ID const & | prevLedgerID, | ||
| Ledger_t | prevLedger, | ||
| hash_set< NodeID_t > const & | nowUntrusted, | ||
| bool | proposing, | ||
| std::unique_ptr< std::stringstream > const & | clog = {} |
||
| ) |
Kick-off the next round of consensus.
Called by the client code to start each round of consensus.
| now | The network adjusted time |
| prevLedgerID | the ID of the last ledger |
| prevLedger | The last ledger |
| nowUntrusted | ID of nodes that are newly untrusted this round |
| proposing | Whether we want to send proposals to peers this round. |
| clog | log object to which to append |
Definition at line 631 of file Consensus.h.
| bool ripple::Consensus< Adaptor >::peerProposal | ( | NetClock::time_point const & | now, |
| PeerPosition_t const & | newProposal | ||
| ) |
A peer has proposed a new position, adjust our tracking.
| now | The network adjusted time |
| newProposal | The new proposal from a peer |
Definition at line 724 of file Consensus.h.
| void ripple::Consensus< Adaptor >::timerEntry | ( | NetClock::time_point const & | now, |
| std::unique_ptr< std::stringstream > const & | clog = {} |
||
| ) |
Call periodically to drive consensus forward.
| now | The network adjusted time |
| clog | log object to which to append |
Definition at line 840 of file Consensus.h.
| void ripple::Consensus< Adaptor >::gotTxSet | ( | NetClock::time_point const & | now, |
| TxSet_t const & | txSet | ||
| ) |
Process a transaction set acquired from the network.
| now | The network adjusted time |
| txSet | the transaction set |
Definition at line 873 of file Consensus.h.
| void ripple::Consensus< Adaptor >::simulate | ( | NetClock::time_point const & | now, |
| std::optional< std::chrono::milliseconds > | consensusDelay | ||
| ) |
Simulate the consensus process without any network traffic.
The end result, is that consensus begins and completes as if everyone had agreed with whatever we propose.
This function is only called from the rpc "ledger_accept" path with the server in standalone mode and SHOULD NOT be used during the normal consensus process.
Simulate will call onForceAccept since clients are manually driving consensus to the accept phase.
| now | The current network adjusted time. |
| consensusDelay | Duration to delay between closing and accepting the ledger. Uses 100ms if unspecified. |
Definition at line 921 of file Consensus.h.
| Ledger_t::ID ripple::Consensus< Adaptor >::prevLedgerID | ( | ) | const |
Get the previous ledger ID.
The previous ledger is the last ledger seen by the consensus code and should correspond to the most recent validated ledger seen by this peer.
Definition at line 412 of file Consensus.h.
| ConsensusPhase ripple::Consensus< Adaptor >::phase | ( | ) | const |
Definition at line 418 of file Consensus.h.
| Json::Value ripple::Consensus< Adaptor >::getJson | ( | bool | full | ) | const |
Get the Json state of the consensus process.
Called by the consensus_info RPC.
| full | True if verbose response desired. |
Definition at line 945 of file Consensus.h.
|
private |
Definition at line 678 of file Consensus.h.
|
private |
Definition at line 1043 of file Consensus.h.
|
private |
Check if our previous ledger matches the network's.
If the previous ledger differs, we are no longer in sync with the network and need to bow out/switch modes.
Definition at line 1099 of file Consensus.h.
|
private |
If we radically changed our consensus context for some reason, we need to replay recent proposals so that they're not lost.
Definition at line 1132 of file Consensus.h.
|
private |
Handle a replayed or a new peer proposal.
Definition at line 745 of file Consensus.h.
|
private |
Handle pre-close phase.
In the pre-close phase, the ledger is open as we wait for new transactions. After enough time has elapsed, we will close the ledger, switch to the establish phase and start the consensus process.
Definition at line 1149 of file Consensus.h.
|
private |
Handle establish phase.
In the establish phase, the ledger has closed and we work with peers to reach consensus. Update our position only on the timer, and in this phase.
If we have consensus, move to the accepted phase.
Definition at line 1347 of file Consensus.h.
|
private |
Evaluate whether pausing increases likelihood of validation.
As a validator that has previously synced to the network, if our most recent locally-validated ledger did not also achieve full validation, then consider pausing for awhile based on the state of other validators.
Pausing may be beneficial in this situation if at least one validator is known to be on a sequence number earlier than ours. The minimum number of validators on the same sequence number does not guarantee consensus, and waiting for all validators may be too time-consuming. Therefore, a variable threshold is enacted based on the number of ledgers past network validation that we are on. For the first phase, the threshold is also the minimum required for quorum. For the last, no online validators can have a lower sequence number. For intermediate phases, the threshold is linear between the minimum required for quorum and 100%. For example, with 3 total phases and a quorum of 80%, the 2nd phase would be 90%. Once the final phase is reached, if consensus still fails to occur, the cycle is begun again at phase 1.
Maximum phase with distinct thresholds to determine how many validators must be on our same ledger sequence number. The threshold for the 1st (0) phase is >= the minimum number that can achieve quorum. Threshold for the maximum phase is 100% of all trusted validators. Progression from min to max phase is simply linear. If there are 5 phases (maxPausePhase = 4) and minimum quorum is 80%, then thresholds progress as follows: 0: >=80% 1: >=85% 2: >=90% 3: >=95% 4: =100%
No particular threshold guarantees consensus. Lower thresholds are easier to achieve than higher, but higher thresholds are more likely to reach consensus. Cycle through the phases if lack of synchronization continues.
Current information indicates that no phase is likely to be intrinsically better than any other: the lower the threshold, the less likely that up-to-date nodes will be able to reach consensus without the laggards. But the higher the threshold, the longer the likely resulting pause. 100% is slightly less desirable in the long run because the potential of a single dawdling peer to slow down everything else. So if we accept that no phase is any better than any other phase, but that all of them will potentially enable us to arrive at consensus, cycling through them seems to be appropriate. Further, if we do reach the point of having to cycle back around, then it's likely that something else out of the scope of this delay mechanism is wrong with the network.
Definition at line 1224 of file Consensus.h.
|
private |
Definition at line 1415 of file Consensus.h.
|
private |
Definition at line 1473 of file Consensus.h.
|
private |
Definition at line 1663 of file Consensus.h.
|
private |
Definition at line 1802 of file Consensus.h.
|
private |
Definition at line 1873 of file Consensus.h.
|
private |
Definition at line 1783 of file Consensus.h.
|
private |
Definition at line 1893 of file Consensus.h.
|
private |
Definition at line 546 of file Consensus.h.
|
private |
Definition at line 548 of file Consensus.h.
|
private |
Definition at line 549 of file Consensus.h.
|
private |
Definition at line 550 of file Consensus.h.
|
private |
Definition at line 551 of file Consensus.h.
|
private |
Definition at line 553 of file Consensus.h.
|
private |
Definition at line 557 of file Consensus.h.
|
private |
Definition at line 560 of file Consensus.h.
|
private |
Definition at line 562 of file Consensus.h.
|
private |
Definition at line 564 of file Consensus.h.
|
private |
Definition at line 568 of file Consensus.h.
|
private |
Definition at line 575 of file Consensus.h.
|
private |
Definition at line 576 of file Consensus.h.
|
private |
Definition at line 582 of file Consensus.h.
|
private |
Definition at line 584 of file Consensus.h.
|
private |
Definition at line 587 of file Consensus.h.
|
private |
Definition at line 589 of file Consensus.h.
|
private |
Definition at line 590 of file Consensus.h.
|
private |
Definition at line 594 of file Consensus.h.
|
private |
Definition at line 597 of file Consensus.h.
|
private |
Definition at line 603 of file Consensus.h.
|
private |
Definition at line 607 of file Consensus.h.
|
private |
Definition at line 610 of file Consensus.h.
|
private |
Definition at line 613 of file Consensus.h.
|
private |
Definition at line 616 of file Consensus.h.