|
| | Consensus (Consensus &&) noexcept=default |
| |
| | Consensus (clock_type const &clock, Adaptor &adaptor, beast::Journal j) |
| | Constructor. More...
|
| |
| void | startRound (NetClock::time_point const &now, typename Ledger_t::ID const &prevLedgerID, Ledger_t prevLedger, hash_set< NodeID_t > const &nowUntrusted, bool proposing) |
| | Kick-off the next round of consensus. More...
|
| |
| bool | peerProposal (NetClock::time_point const &now, PeerPosition_t const &newProposal) |
| | A peer has proposed a new position, adjust our tracking. More...
|
| |
| void | timerEntry (NetClock::time_point const &now) |
| | Call periodically to drive consensus forward. More...
|
| |
| void | gotTxSet (NetClock::time_point const &now, TxSet_t const &txSet) |
| | Process a transaction set acquired from the network. More...
|
| |
| void | simulate (NetClock::time_point const &now, std::optional< std::chrono::milliseconds > consensusDelay) |
| | Simulate the consensus process without any network traffic. More...
|
| |
| Ledger_t::ID | prevLedgerID () const |
| | Get the previous ledger ID. More...
|
| |
| ConsensusPhase | phase () const |
| |
| Json::Value | getJson (bool full) const |
| | Get the Json state of the consensus process. More...
|
| |
template<class Adaptor>
class ripple::Consensus< Adaptor >
Generic implementation of consensus algorithm.
Achieves consensus on the next ledger.
Two things need consensus:
- The set of transactions included in the ledger.
- The close time for the ledger.
The basic flow:
- A call to
startRound places the node in the Open phase. In this phase, the node is waiting for transactions to include in its open ledger.
- Successive calls to
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.
- During a subsequent call to
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.
- Warning
- The generic implementation is not thread safe and the public methods are not intended to be run concurrently. When in a concurrent environment, the application is responsible for ensuring thread-safety. Simply locking whenever touching the Consensus instance is one option.
struct Tx
{
using ID = ...;
ID id() const;
};
struct TxSet
{
using ID = ...;
using Tx = Tx;
bool exists(Tx::ID const &) const;
Tx const * find(Tx::ID const &) const ;
ID const & id() const;
struct MutableTxSet
{
MutableTxSet(TxSet const &);
bool insert(Tx const &);
bool erase(Tx::ID
const &);
};
TxSet(MutableTxSet const &);
};
struct Ledger
{
using ID = ...;
using Seq = ...;
ID const id() const;
Seq seq() const;
auto closeTimeResolution() const;
auto closeAgree() const;
auto closeTime() const;
auto parentCloseTime() const;
};
struct PeerPosition
{
ConsensusProposal<
typename Ledger::ID,
typename TxSet::ID> const &
};
class Adaptor
{
public:
using Ledger_t = Ledger;
using TxSet_t = TxSet;
using PeerPosition_t = PeerPosition;
bool hasOpenTransactions() const;
std::size_t proposersValidated(Ledger::ID
const & prevLedger)
const;
std::size_t proposersFinished(Ledger
const & prevLedger,
Ledger::ID const & prevLedger) const;
Ledger::ID getPrevLedger(Ledger::ID const & prevLedgerID,
Ledger const & prevLedger,
Mode mode);
void onModeChange(ConsensusMode before, ConsensusMode after);
Result onClose(Ledger
const &, Ledger
const & prev, Mode mode);
void onAccept(Result const & result,
RCLCxLedger const & prevLedger,
NetClock::duration closeResolution,
CloseTimes const & rawCloseTimes,
Mode const & mode);
void onForceAccept(Result const & result,
RCLCxLedger const & prevLedger,
NetClock::duration closeResolution,
CloseTimes const & rawCloseTimes,
Mode const & mode);
void propose(ConsensusProposal<...> const & pos);
void share(PeerPosition_t const & prop);
void share(Txn const & tx);
void share(TxSet const &s);
ConsensusParms const &
parms() const;
};
Result
Possible results from activating a slot.
void erase(STObject &st, TypedField< U > const &f)
Remove a field in an STObject.
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
@ proposal
proposal for signing
- Template Parameters
-
| Adaptor | Defines types and provides helper functions needed to adapt Consensus to the larger application. |
Definition at line 287 of file Consensus.h.
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.
- Returns
- Whether to pause to wait for lagging proposers.
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 1150 of file Consensus.h.