Generic implementation of consensus algorithm.
template< class Adaptor> class Consensus
Name |
Description |
---|---|
Clock type for measuring time within the consensus code. |
Name |
Description |
---|---|
Constructor. |
|
Get the Json state of the consensus process. |
|
Process a transaction set acquired from the network. |
|
A peer has proposed a new position, adjust our tracking. |
|
Get the previous ledger ID. |
|
Simulate the consensus process without any network traffic. |
|
Kick-off the next round of consensus. |
|
Call periodically to drive consensus forward. |
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 Close
s
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.
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.
// A single transaction struct Tx { // Unique identifier of transaction using ID = ...; ID id() const; }; // A set of transactions struct TxSet { // Unique ID of TxSet (not of Tx) using ID = ...; // Type of individual transaction comprising the TxSet using Tx = Tx; bool exists(Tx::ID const &) const; // Return value should have semantics like Tx const * Tx const * find(Tx::ID const &) const ; ID const & id() const; // Return set of transactions that are not common to this set or other // boolean indicates which set it was in std::map<Tx::ID, bool> compare(TxSet const & other) const; // A mutable view of transactions struct MutableTxSet { MutableTxSet(TxSet const &); bool insert(Tx const &); bool erase(Tx::ID const &); }; // Construct from a mutable view. TxSet(MutableTxSet const &); // Alternatively, if the TxSet is itself mutable // just alias MutableTxSet = TxSet }; // Agreed upon state that consensus transactions will modify struct Ledger { using ID = ...; using Seq = ...; // Unique identifier of ledgerr ID const id() const; Seq seq() const; auto closeTimeResolution() const; auto closeAgree() const; auto closeTime() const; auto parentCloseTime() const; Json::Value getJson() const; }; // Wraps a peer's ConsensusProposal struct PeerPosition { ConsensusProposal< std::uint32_t, //NodeID, typename Ledger::ID, typename TxSet::ID> const & proposal() const; }; class Adaptor { public: //----------------------------------------------------------------------- // Define consensus types using Ledger_t = Ledger; using NodeID_t = std::uint32_t; using TxSet_t = TxSet; using PeerPosition_t = PeerPosition; //----------------------------------------------------------------------- // // Attempt to acquire a specific ledger. boost::optional<Ledger> acquireLedger(Ledger::ID const & ledgerID); // Acquire the transaction set associated with a proposed position. boost::optional<TxSet> acquireTxSet(TxSet::ID const & setID); // Whether any transactions are in the open ledger bool hasOpenTransactions() const; // Number of proposers that have validated the given ledger std::size_t proposersValidated(Ledger::ID const & prevLedger) const; // Number of proposers that have validated a ledger descended from the // given ledger; if prevLedger.id() != prevLedgerID, use prevLedgerID // for the determination std::size_t proposersFinished(Ledger conost & prev, Ledger::ID const & prevLedger) const; // Return the ID of the last closed (and validated) ledger that the // application thinks consensus should use as the prior ledger. Ledger::ID getPrevLedger(Ledger::ID const & prevLedgerID, Ledger const & prevLedger, Mode mode); // Called whenever consensus operating mode changes void onModeChange(ConsensusMode before, ConsensusMode after); // Called when ledger closes Result onClose(Ledger const &, Ledger const & prev, Mode mode); // Called when ledger is accepted by consensus void onAccept(Result const & result, RCLCxLedger const & prevLedger, NetClock::duration closeResolution, CloseTimes const & rawCloseTimes, Mode const & mode); // Called when ledger was forcibly accepted by consensus via the simulate // function. void onForceAccept(Result const & result, RCLCxLedger const & prevLedger, NetClock::duration closeResolution, CloseTimes const & rawCloseTimes, Mode const & mode); // Propose the position to peers. void propose(ConsensusProposal<...> const & pos); // Share a received peer proposal with other peer's. void share(PeerPosition_t const & prop); // Share a disputed transaction with peers void share(Txn const & tx); // Share given transaction set with peers void share(TxSet const &s); // Consensus timing parameters and constants ConsensusParms const & parms() const; };
Type |
Description |
---|---|
|
Defines types and provides helper functions needed to adapt |6|Consensus to the larger application. |
#include <ripple/consensus/Consensus.h>