mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-18 17:45:48 +00:00
Migrate thread safety to RCLConsensus (RIPD-1389):
Moves thread safety from generic Consensus to RCLConsensus and switch generic Consensus to adaptor design.
This commit is contained in:
@@ -1099,6 +1099,10 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\app\misc\impl\ValidatorKeys.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\app\misc\impl\ValidatorList.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
@@ -1131,6 +1135,8 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\app\misc\TxQ.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\app\misc\ValidatorKeys.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\app\misc\ValidatorList.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\app\misc\ValidatorSite.h">
|
||||
@@ -1865,6 +1871,8 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\consensus\ConsensusProposal.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\consensus\ConsensusTypes.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\consensus\DisputedTx.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\consensus\LedgerTiming.h">
|
||||
@@ -4323,6 +4331,10 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\test\app\ValidatorKeys_test.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\test\app\ValidatorList_test.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
|
||||
@@ -1635,6 +1635,9 @@
|
||||
<ClCompile Include="..\..\src\ripple\app\misc\impl\TxQ.cpp">
|
||||
<Filter>ripple\app\misc\impl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\app\misc\impl\ValidatorKeys.cpp">
|
||||
<Filter>ripple\app\misc\impl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\app\misc\impl\ValidatorList.cpp">
|
||||
<Filter>ripple\app\misc\impl</Filter>
|
||||
</ClCompile>
|
||||
@@ -1671,6 +1674,9 @@
|
||||
<ClInclude Include="..\..\src\ripple\app\misc\TxQ.h">
|
||||
<Filter>ripple\app\misc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\app\misc\ValidatorKeys.h">
|
||||
<Filter>ripple\app\misc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\app\misc\ValidatorList.h">
|
||||
<Filter>ripple\app\misc</Filter>
|
||||
</ClInclude>
|
||||
@@ -2511,6 +2517,9 @@
|
||||
<ClInclude Include="..\..\src\ripple\consensus\ConsensusProposal.h">
|
||||
<Filter>ripple\consensus</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\consensus\ConsensusTypes.h">
|
||||
<Filter>ripple\consensus</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\consensus\DisputedTx.h">
|
||||
<Filter>ripple\consensus</Filter>
|
||||
</ClInclude>
|
||||
@@ -5121,6 +5130,9 @@
|
||||
<ClCompile Include="..\..\src\test\app\TxQ_test.cpp">
|
||||
<Filter>test\app</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\test\app\ValidatorKeys_test.cpp">
|
||||
<Filter>test\app</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\test\app\ValidatorList_test.cpp">
|
||||
<Filter>test\app</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -480,69 +480,87 @@ struct Ledger
|
||||
//... implementation specific
|
||||
};
|
||||
```
|
||||
[heading Generic Consensus Interface]
|
||||
|
||||
Following the
|
||||
[@https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern CRTP]
|
||||
idiom, generic =Consensus= relies on a deriving class implementing a set of
|
||||
helpers and callbacks that encapsulate implementation specific details of the
|
||||
algorithm. Below are excerpts of the generic consensus implementation and of
|
||||
helper types that will interact with the concrete implementing class.
|
||||
|
||||
[heading PeerProposal] The =PeerProposal= type represents the signed position taken
|
||||
by a peer during consensus. The only type requirement is owning an instance of a
|
||||
generic =ConsensusProposal=.
|
||||
```
|
||||
|
||||
// Represents our proposed position or a peer's proposed position
|
||||
// and is provided with the generic code
|
||||
template <class NodeID_t, class LedgerID_t, class Position_t> class ConsensusProposal;
|
||||
|
||||
struct PeerPosition
|
||||
{
|
||||
ConsensusProposal<
|
||||
NodeID_t,
|
||||
typename Ledger::ID,
|
||||
typename TxSet::ID> const &
|
||||
proposal() const;
|
||||
|
||||
// ... implementation specific
|
||||
};
|
||||
```
|
||||
[heading Generic Consensus Interface]
|
||||
|
||||
The generic =Consensus= relies on =Adaptor= template class to implement a set
|
||||
of helper functions that plug the consensus algorithm into a specific application.
|
||||
The =Adaptor= class also defines the types above needed by the algorithm. Below
|
||||
are excerpts of the generic consensus implementation and of helper types that will
|
||||
interact with the concrete implementing class.
|
||||
|
||||
```
|
||||
// Represents a transction under dispute this round
|
||||
template <class Tx_t, class NodeID_t> class DisputedTx;
|
||||
|
||||
template <class Derived, class Traits> class Consensus
|
||||
// Represents how the node participates in Consensus this round
|
||||
enum class ConsensusMode { proposing, observing, wrongLedger, switchedLedger};
|
||||
|
||||
// Measure duration of phases of consensus
|
||||
class ConsensusTimer
|
||||
{
|
||||
protected:
|
||||
enum class Mode { proposing, observing, wrongLedger, switchedLedger};
|
||||
|
||||
// Measure duration of phases of consensus
|
||||
class Stopwatch
|
||||
{
|
||||
public:
|
||||
std::chrono::milliseconds read() const;
|
||||
// details omitted ...
|
||||
};
|
||||
|
||||
// Initial ledger close times, not rounded by closeTimeResolution
|
||||
// Used to gauge degree of synchronization between a node and its peers
|
||||
struct CloseTimes
|
||||
{
|
||||
std::map<NetClock::time_point, int> peers;
|
||||
NetClock::time_point self;
|
||||
};
|
||||
|
||||
// Encapsulates the result of consensus.
|
||||
struct Result
|
||||
{
|
||||
//! The set of transactions consensus agrees go in the ledger
|
||||
TxSet_t set;
|
||||
|
||||
//! Our proposed position on transactions/close time
|
||||
Proposal_t position;
|
||||
|
||||
//! Transactions which are under dispute with our peers
|
||||
using Dispute_t = DisputedTx<Tx_t, NodeID_t>;
|
||||
hash_map<typename Tx_t::ID, Dispute_t> disputes;
|
||||
|
||||
// Set of TxSet ids we have already compared/created disputes
|
||||
hash_set<typename TxSet_t::ID> compares;
|
||||
|
||||
// Measures the duration of the establish phase for this consensus round
|
||||
Stopwatch roundTime;
|
||||
|
||||
// Indicates state in which consensus ended. Once in the accept phase
|
||||
// will be either Yes or MovedOn
|
||||
ConsensusState state = ConsensusState::No;
|
||||
};
|
||||
|
||||
public:
|
||||
std::chrono::milliseconds read() const;
|
||||
// details omitted ...
|
||||
};
|
||||
|
||||
// Initial ledger close times, not rounded by closeTimeResolution
|
||||
// Used to gauge degree of synchronization between a node and its peers
|
||||
struct ConsensusCloseTimes
|
||||
{
|
||||
std::map<NetClock::time_point, int> peers;
|
||||
NetClock::time_point self;
|
||||
};
|
||||
|
||||
// Encapsulates the result of consensus.
|
||||
template <class Adaptor>
|
||||
struct ConsensusResult
|
||||
{
|
||||
//! The set of transactions consensus agrees go in the ledger
|
||||
Adaptor::TxSet_t set;
|
||||
|
||||
//! Our proposed position on transactions/close time
|
||||
ConsensusProposal<...> position;
|
||||
|
||||
//! Transactions which are under dispute with our peers
|
||||
hash_map<Adaptor::Tx_t::ID, DisputedTx<...>> disputes;
|
||||
|
||||
// Set of TxSet ids we have already compared/created disputes
|
||||
hash_set<typename Adaptor::TxSet_t::ID> compares;
|
||||
|
||||
// Measures the duration of the establish phase for this consensus round
|
||||
ConsensusTimer roundTime;
|
||||
|
||||
// Indicates state in which consensus ended. Once in the accept phase
|
||||
// will be either Yes or MovedOn
|
||||
ConsensusState state = ConsensusState::No;
|
||||
};
|
||||
|
||||
template <class Adaptor>
|
||||
class Consensus
|
||||
{
|
||||
public:
|
||||
Consensus(clock_type, Adaptor &, beast::journal);
|
||||
|
||||
// Kick-off the next round of consensus.
|
||||
void startRound(
|
||||
NetClock::time_point const& now,
|
||||
@@ -568,26 +586,20 @@ public:
|
||||
The stub below shows the set of callback/helper functions required in the implementing class.
|
||||
|
||||
```
|
||||
struct Traits
|
||||
struct Adaptor
|
||||
{
|
||||
using Ledger_t = Ledger;
|
||||
using TxSet_t = TxSet;
|
||||
using NodeID_t = ...; // Integer-like std::uint32_t to uniquely identify a node
|
||||
using Ledger_t = Ledger;
|
||||
using TxSet_t = TxSet;
|
||||
using PeerProposal_t = PeerProposal;
|
||||
using NodeID_t = ...; // Integer-like std::uint32_t to uniquely identify a node
|
||||
|
||||
};
|
||||
|
||||
class ConsensusImp : public Consensus<ConsensusImp, Traits>
|
||||
{
|
||||
// Attempt to acquire a specific ledger from the network.
|
||||
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);
|
||||
|
||||
// Get peers' proposed positions. Returns an iterable
|
||||
// with value_type convertable to ConsensusPosition<...>
|
||||
auto const & proposals(Ledger::ID const & ledgerID);
|
||||
|
||||
// Whether any transactions are in the open ledger
|
||||
bool hasOpenTransactions() const;
|
||||
|
||||
@@ -602,24 +614,27 @@ class ConsensusImp : public Consensus<ConsensusImp, Traits>
|
||||
// application thinks consensus should use as the prior ledger.
|
||||
Ledger::ID getPrevLedger(Ledger::ID const & prevLedgerID,
|
||||
Ledger const & prevLedger,
|
||||
Mode mode);
|
||||
ConsensusMode mode);
|
||||
|
||||
// Called when consensus operating mode changes
|
||||
void onModeChange(ConsensuMode before, ConsensusMode after);
|
||||
|
||||
// Called when ledger closes. Implementation should generate an initial Result
|
||||
// with position based on the current open ledger's transactions.
|
||||
Result onClose(Ledger const &, Ledger const & prev, Mode mode);
|
||||
ConsensusResult onClose(Ledger const &, Ledger const & prev, ConsensusMode mode);
|
||||
|
||||
// Called when ledger is accepted by consensus
|
||||
void onAccept(Result const & result,
|
||||
void onAccept(ConsensusResult const & result,
|
||||
RCLCxLedger const & prevLedger,
|
||||
NetClock::duration closeResolution,
|
||||
CloseTimes const & rawCloseTimes,
|
||||
Mode const & mode);
|
||||
ConsensusCloseTimes const & rawCloseTimes,
|
||||
ConsensusMode const & mode);
|
||||
|
||||
// Propose the position to peers.
|
||||
void propose(ConsensusProposal<...> const & pos);
|
||||
|
||||
// Relay a received peer proposal on to other peer's.
|
||||
void relay(ConsensusProposal<...> const & pos);
|
||||
void relay(PeerPosition_t const & pos);
|
||||
|
||||
// Relay a disputed transaction to peers
|
||||
void relay(TxSet::Tx const & tx);
|
||||
|
||||
@@ -111,6 +111,7 @@ INPUT = \
|
||||
../src/test/jtx/WSClient.h \
|
||||
../src/ripple/consensus/Consensus.h \
|
||||
../src/ripple/consensus/ConsensusProposal.h \
|
||||
../src/ripple/consensus/ConsensusTypes.h \
|
||||
../src/ripple/consensus/DisputedTx.h \
|
||||
../src/ripple/consensus/LedgerTiming.h \
|
||||
../src/ripple/consensus/Validations.h \
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <ripple/app/misc/LoadFeeTrack.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/app/misc/TxQ.h>
|
||||
#include <ripple/app/misc/ValidatorKeys.h>
|
||||
#include <ripple/app/misc/ValidatorList.h>
|
||||
#include <ripple/app/tx/apply.h>
|
||||
#include <ripple/basics/make_lock.h>
|
||||
@@ -48,21 +49,45 @@ RCLConsensus::RCLConsensus(
|
||||
LedgerMaster& ledgerMaster,
|
||||
LocalTxs& localTxs,
|
||||
InboundTransactions& inboundTransactions,
|
||||
typename Base::clock_type const& clock,
|
||||
Consensus<Adaptor>::clock_type const& clock,
|
||||
ValidatorKeys const& validatorKeys,
|
||||
beast::Journal journal)
|
||||
: Base(clock, ConsensusParms{}, journal)
|
||||
, app_(app)
|
||||
, feeVote_(std::move(feeVote))
|
||||
, ledgerMaster_(ledgerMaster)
|
||||
, localTxs_(localTxs)
|
||||
, inboundTransactions_{inboundTransactions}
|
||||
: adaptor_(
|
||||
app,
|
||||
std::move(feeVote),
|
||||
ledgerMaster,
|
||||
localTxs,
|
||||
inboundTransactions,
|
||||
validatorKeys,
|
||||
journal)
|
||||
, consensus_(clock, adaptor_, journal)
|
||||
, j_(journal)
|
||||
, nodeID_{calcNodeID(app.nodeIdentity().first)}
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
RCLConsensus::Adaptor::Adaptor(
|
||||
Application& app,
|
||||
std::unique_ptr<FeeVote>&& feeVote,
|
||||
LedgerMaster& ledgerMaster,
|
||||
LocalTxs& localTxs,
|
||||
InboundTransactions& inboundTransactions,
|
||||
ValidatorKeys const& validatorKeys,
|
||||
beast::Journal journal)
|
||||
: app_(app)
|
||||
, feeVote_(std::move(feeVote))
|
||||
, ledgerMaster_(ledgerMaster)
|
||||
, localTxs_(localTxs)
|
||||
, inboundTransactions_{inboundTransactions}
|
||||
, j_(journal)
|
||||
, nodeID_{calcNodeID(app.nodeIdentity().first)}
|
||||
, valPublic_{validatorKeys.publicKey}
|
||||
, valSecret_{validatorKeys.secretKey}
|
||||
{
|
||||
}
|
||||
|
||||
boost::optional<RCLCxLedger>
|
||||
RCLConsensus::acquireLedger(LedgerHash const& ledger)
|
||||
RCLConsensus::Adaptor::acquireLedger(LedgerHash const& ledger)
|
||||
{
|
||||
// we need to switch the ledger we're working from
|
||||
auto buildLCL = ledgerMaster_.getLedgerByHash(ledger);
|
||||
@@ -96,37 +121,9 @@ RCLConsensus::acquireLedger(LedgerHash const& ledger)
|
||||
return RCLCxLedger(buildLCL);
|
||||
}
|
||||
|
||||
std::vector<RCLCxPeerPos>
|
||||
RCLConsensus::proposals(LedgerHash const& prevLedger)
|
||||
{
|
||||
std::vector<RCLCxPeerPos> ret;
|
||||
{
|
||||
std::lock_guard<std::mutex> _(peerPositionsLock_);
|
||||
|
||||
for (auto const& it : peerPositions_)
|
||||
for (auto const& pos : it.second)
|
||||
if (pos->proposal().prevLedger() == prevLedger)
|
||||
ret.emplace_back(*pos);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::storeProposal(RCLCxPeerPos::ref peerPos, NodeID const& nodeID)
|
||||
{
|
||||
std::lock_guard<std::mutex> _(peerPositionsLock_);
|
||||
|
||||
auto& props = peerPositions_[nodeID];
|
||||
|
||||
if (props.size() >= 10)
|
||||
props.pop_front();
|
||||
|
||||
props.push_back(peerPos);
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::relay(RCLCxPeerPos const& peerPos)
|
||||
RCLConsensus::Adaptor::relay(RCLCxPeerPos const& peerPos)
|
||||
{
|
||||
protocol::TMProposeSet prop;
|
||||
|
||||
@@ -140,17 +137,17 @@ RCLConsensus::relay(RCLCxPeerPos const& peerPos)
|
||||
prop.set_previousledger(
|
||||
proposal.prevLedger().begin(), proposal.position().size());
|
||||
|
||||
auto const pk = peerPos.getPublicKey().slice();
|
||||
auto const pk = peerPos.publicKey().slice();
|
||||
prop.set_nodepubkey(pk.data(), pk.size());
|
||||
|
||||
auto const sig = peerPos.getSignature();
|
||||
auto const sig = peerPos.signature();
|
||||
prop.set_signature(sig.data(), sig.size());
|
||||
|
||||
app_.overlay().relay(prop, peerPos.getSuppressionID());
|
||||
app_.overlay().relay(prop, peerPos.suppressionID());
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::relay(RCLCxTx const& tx)
|
||||
RCLConsensus::Adaptor::relay(RCLCxTx const& tx)
|
||||
{
|
||||
// If we didn't relay this transaction recently, relay it to all peers
|
||||
if (app_.getHashRouter().shouldRelay(tx.id()))
|
||||
@@ -166,7 +163,7 @@ RCLConsensus::relay(RCLCxTx const& tx)
|
||||
}
|
||||
}
|
||||
void
|
||||
RCLConsensus::propose(RCLCxPeerPos::Proposal const& proposal)
|
||||
RCLConsensus::Adaptor::propose(RCLCxPeerPos::Proposal const& proposal)
|
||||
{
|
||||
JLOG(j_.trace()) << "We propose: "
|
||||
<< (proposal.isBowOut()
|
||||
@@ -199,13 +196,13 @@ RCLConsensus::propose(RCLCxPeerPos::Proposal const& proposal)
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::relay(RCLTxSet const& set)
|
||||
RCLConsensus::Adaptor::relay(RCLTxSet const& set)
|
||||
{
|
||||
inboundTransactions_.giveSet(set.id(), set.map_, false);
|
||||
}
|
||||
|
||||
boost::optional<RCLTxSet>
|
||||
RCLConsensus::acquireTxSet(RCLTxSet::ID const& setId)
|
||||
RCLConsensus::Adaptor::acquireTxSet(RCLTxSet::ID const& setId)
|
||||
{
|
||||
if (auto set = inboundTransactions_.getSet(setId, true))
|
||||
{
|
||||
@@ -215,32 +212,32 @@ RCLConsensus::acquireTxSet(RCLTxSet::ID const& setId)
|
||||
}
|
||||
|
||||
bool
|
||||
RCLConsensus::hasOpenTransactions() const
|
||||
RCLConsensus::Adaptor::hasOpenTransactions() const
|
||||
{
|
||||
return !app_.openLedger().empty();
|
||||
}
|
||||
|
||||
std::size_t
|
||||
RCLConsensus::proposersValidated(LedgerHash const& h) const
|
||||
RCLConsensus::Adaptor::proposersValidated(LedgerHash const& h) const
|
||||
{
|
||||
return app_.getValidations().numTrustedForLedger(h);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
RCLConsensus::proposersFinished(LedgerHash const& h) const
|
||||
RCLConsensus::Adaptor::proposersFinished(LedgerHash const& h) const
|
||||
{
|
||||
return app_.getValidations().getNodesAfter(h);
|
||||
}
|
||||
|
||||
uint256
|
||||
RCLConsensus::getPrevLedger(
|
||||
RCLConsensus::Adaptor::getPrevLedger(
|
||||
uint256 ledgerID,
|
||||
RCLCxLedger const& ledger,
|
||||
Mode mode)
|
||||
ConsensusMode mode)
|
||||
{
|
||||
uint256 parentID;
|
||||
// Only set the parent ID if we believe ledger is the right ledger
|
||||
if (mode != Mode::wrongLedger)
|
||||
if (mode != ConsensusMode::wrongLedger)
|
||||
parentID = ledger.parentID();
|
||||
|
||||
// Get validators that are on our ledger, or "close" to being on
|
||||
@@ -265,28 +262,27 @@ RCLConsensus::getPrevLedger(
|
||||
|
||||
if (netLgr != ledgerID)
|
||||
{
|
||||
if (mode != Mode::wrongLedger)
|
||||
if (mode != ConsensusMode::wrongLedger)
|
||||
app_.getOPs().consensusViewChange();
|
||||
|
||||
if (auto stream = j_.debug())
|
||||
{
|
||||
for (auto& it : vals)
|
||||
stream << "V: " << it.first << ", " << it.second.count;
|
||||
stream << getJson(true);
|
||||
}
|
||||
}
|
||||
|
||||
return netLgr;
|
||||
}
|
||||
|
||||
RCLConsensus::Result
|
||||
RCLConsensus::onClose(
|
||||
auto
|
||||
RCLConsensus::Adaptor::onClose(
|
||||
RCLCxLedger const& ledger,
|
||||
NetClock::time_point const& closeTime,
|
||||
Mode mode)
|
||||
ConsensusMode mode) -> Result
|
||||
{
|
||||
const bool wrongLCL = mode == Mode::wrongLedger;
|
||||
const bool proposing = mode == Mode::proposing;
|
||||
const bool wrongLCL = mode == ConsensusMode::wrongLedger;
|
||||
const bool proposing = mode == ConsensusMode::proposing;
|
||||
|
||||
notify(protocol::neCLOSING_LEDGER, ledger, !wrongLCL);
|
||||
|
||||
@@ -346,47 +342,68 @@ RCLConsensus::onClose(
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::onForceAccept(
|
||||
RCLConsensus::Adaptor::onForceAccept(
|
||||
Result const& result,
|
||||
RCLCxLedger const& prevLedger,
|
||||
NetClock::duration const& closeResolution,
|
||||
CloseTimes const& rawCloseTimes,
|
||||
Mode const& mode)
|
||||
ConsensusCloseTimes const& rawCloseTimes,
|
||||
ConsensusMode const& mode,
|
||||
Json::Value && consensusJson)
|
||||
{
|
||||
doAccept(result, prevLedger, closeResolution, rawCloseTimes, mode);
|
||||
doAccept(
|
||||
result,
|
||||
prevLedger,
|
||||
closeResolution,
|
||||
rawCloseTimes,
|
||||
mode,
|
||||
std::move(consensusJson));
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::onAccept(
|
||||
RCLConsensus::Adaptor::onAccept(
|
||||
Result const& result,
|
||||
RCLCxLedger const& prevLedger,
|
||||
NetClock::duration const& closeResolution,
|
||||
CloseTimes const& rawCloseTimes,
|
||||
Mode const& mode)
|
||||
ConsensusCloseTimes const& rawCloseTimes,
|
||||
ConsensusMode const& mode,
|
||||
Json::Value && consensusJson)
|
||||
{
|
||||
app_.getJobQueue().addJob(
|
||||
jtACCEPT, "acceptLedger", [&, that = this->shared_from_this() ](auto&) {
|
||||
// note that no lock is held inside this thread, which
|
||||
// is fine since once a ledger is accepted, consensus
|
||||
// will not touch any internal state until startRound is called
|
||||
that->doAccept(
|
||||
result, prevLedger, closeResolution, rawCloseTimes, mode);
|
||||
that->app_.getOPs().endConsensus();
|
||||
jtACCEPT,
|
||||
"acceptLedger",
|
||||
[&, cj = std::move(consensusJson) ](auto&) mutable {
|
||||
// Note that no lock is held or acquired during this job.
|
||||
// This is because generic Consensus guarantees that once a ledger
|
||||
// is accepted, the consensus results and capture by reference state
|
||||
// will not change until startRound is called (which happens via
|
||||
// endConsensus).
|
||||
this->doAccept(
|
||||
result,
|
||||
prevLedger,
|
||||
closeResolution,
|
||||
rawCloseTimes,
|
||||
mode,
|
||||
std::move(cj));
|
||||
this->app_.getOPs().endConsensus();
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::doAccept(
|
||||
RCLConsensus::Adaptor::doAccept(
|
||||
Result const& result,
|
||||
RCLCxLedger const& prevLedger,
|
||||
NetClock::duration closeResolution,
|
||||
CloseTimes const& rawCloseTimes,
|
||||
Mode const& mode)
|
||||
ConsensusCloseTimes const& rawCloseTimes,
|
||||
ConsensusMode const& mode,
|
||||
Json::Value && consensusJson)
|
||||
{
|
||||
prevProposers_ = result.proposers;
|
||||
prevRoundTime_ = result.roundTime.read();
|
||||
|
||||
bool closeTimeCorrect;
|
||||
|
||||
const bool proposing = mode == Mode::proposing;
|
||||
const bool haveCorrectLCL = mode != Mode::wrongLedger;
|
||||
const bool proposing = mode == ConsensusMode::proposing;
|
||||
const bool haveCorrectLCL = mode != ConsensusMode::wrongLedger;
|
||||
const bool consensusFail = result.state == ConsensusState::MovedOn;
|
||||
|
||||
auto consensusCloseTime = result.position.closeTime();
|
||||
@@ -447,7 +464,7 @@ RCLConsensus::doAccept(
|
||||
JLOG(j_.info()) << "CNF buildLCL " << newLCLHash;
|
||||
|
||||
// See if we can accept a ledger as fully-validated
|
||||
ledgerMaster_.consensusBuilt(sharedLCL.ledger_, getJson(true));
|
||||
ledgerMaster_.consensusBuilt(sharedLCL.ledger_, std::move(consensusJson));
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
{
|
||||
@@ -538,7 +555,7 @@ RCLConsensus::doAccept(
|
||||
// we entered the round with the network,
|
||||
// see how close our close time is to other node's
|
||||
// close time reports, and update our clock.
|
||||
if ((mode == Mode::proposing || mode == Mode::observing) && !consensusFail)
|
||||
if ((mode == ConsensusMode::proposing || mode == ConsensusMode::observing) && !consensusFail)
|
||||
{
|
||||
auto closeTime = rawCloseTimes.self;
|
||||
|
||||
@@ -577,7 +594,7 @@ RCLConsensus::doAccept(
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::notify(
|
||||
RCLConsensus::Adaptor::notify(
|
||||
protocol::NodeEvent ne,
|
||||
RCLCxLedger const& ledger,
|
||||
bool haveCorrectLCL)
|
||||
@@ -713,7 +730,7 @@ applyTransactions(
|
||||
}
|
||||
|
||||
RCLCxLedger
|
||||
RCLConsensus::buildLCL(
|
||||
RCLConsensus::Adaptor::buildLCL(
|
||||
RCLCxLedger const& previousLedger,
|
||||
RCLTxSet const& set,
|
||||
NetClock::time_point closeTime,
|
||||
@@ -809,7 +826,7 @@ RCLConsensus::buildLCL(
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::validate(RCLCxLedger const& ledger, bool proposing)
|
||||
RCLConsensus::Adaptor::validate(RCLCxLedger const& ledger, bool proposing)
|
||||
{
|
||||
auto validationTime = app_.timeKeeper().closeTime();
|
||||
if (validationTime <= lastValidationTime_)
|
||||
@@ -852,37 +869,26 @@ RCLConsensus::validate(RCLCxLedger const& ledger, bool proposing)
|
||||
Json::Value
|
||||
RCLConsensus::getJson(bool full) const
|
||||
{
|
||||
auto ret = Base::getJson(full);
|
||||
ret["validating"] = validating_;
|
||||
Json::Value ret;
|
||||
{
|
||||
ScopedLockType _{mutex_};
|
||||
ret = consensus_.getJson(full);
|
||||
}
|
||||
ret["validating"] = adaptor_.validating();
|
||||
return ret;
|
||||
}
|
||||
|
||||
PublicKey const&
|
||||
RCLConsensus::getValidationPublicKey() const
|
||||
{
|
||||
return valPublic_;
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::setValidationKeys(
|
||||
SecretKey const& valSecret,
|
||||
PublicKey const& valPublic)
|
||||
{
|
||||
valSecret_ = valSecret;
|
||||
valPublic_ = valPublic;
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::timerEntry(NetClock::time_point const& now)
|
||||
{
|
||||
try
|
||||
{
|
||||
Base::timerEntry(now);
|
||||
ScopedLockType _{mutex_};
|
||||
consensus_.timerEntry(now);
|
||||
}
|
||||
catch (SHAMapMissingNode const& mn)
|
||||
{
|
||||
// This should never happen
|
||||
leaveConsensus();
|
||||
JLOG(j_.error()) << "Missing node during consensus process " << mn;
|
||||
Rethrow();
|
||||
}
|
||||
@@ -893,31 +899,45 @@ RCLConsensus::gotTxSet(NetClock::time_point const& now, RCLTxSet const& txSet)
|
||||
{
|
||||
try
|
||||
{
|
||||
Base::gotTxSet(now, txSet);
|
||||
ScopedLockType _{mutex_};
|
||||
consensus_.gotTxSet(now, txSet);
|
||||
}
|
||||
catch (SHAMapMissingNode const& mn)
|
||||
{
|
||||
// This should never happen
|
||||
leaveConsensus();
|
||||
JLOG(j_.error()) << "Missing node during consensus process " << mn;
|
||||
Rethrow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! @see Consensus::simulate
|
||||
|
||||
void
|
||||
RCLConsensus::startRound(
|
||||
RCLConsensus::simulate(
|
||||
NetClock::time_point const& now,
|
||||
RCLCxLedger::ID const& prevLgrId,
|
||||
RCLCxLedger const& prevLgr)
|
||||
boost::optional<std::chrono::milliseconds> consensusDelay)
|
||||
{
|
||||
ScopedLockType _{mutex_};
|
||||
consensus_.simulate(now, consensusDelay);
|
||||
}
|
||||
|
||||
bool
|
||||
RCLConsensus::peerProposal(
|
||||
NetClock::time_point const& now,
|
||||
RCLCxPeerPos const& newProposal)
|
||||
{
|
||||
ScopedLockType _{mutex_};
|
||||
return consensus_.peerProposal(now, newProposal);
|
||||
}
|
||||
|
||||
bool
|
||||
RCLConsensus::Adaptor::preStartRound(RCLCxLedger const & prevLgr)
|
||||
{
|
||||
// We have a key, and we have some idea what the ledger is
|
||||
validating_ =
|
||||
!app_.getOPs().isNeedNetworkLedger() && (valPublic_.size() != 0);
|
||||
|
||||
// propose only if we're in sync with the network (and validating)
|
||||
bool proposing =
|
||||
validating_ && (app_.getOPs().getOperatingMode() == NetworkOPs::omFULL);
|
||||
|
||||
if (validating_)
|
||||
{
|
||||
JLOG(j_.info()) << "Entering consensus process, validating";
|
||||
@@ -931,6 +951,19 @@ RCLConsensus::startRound(
|
||||
// Notify inbOund ledgers that we are starting a new round
|
||||
inboundTransactions_.newRound(prevLgr.seq());
|
||||
|
||||
Base::startRound(now, prevLgrId, prevLgr, proposing);
|
||||
// propose only if we're in sync with the network (and validating)
|
||||
return validating_ &&
|
||||
(app_.getOPs().getOperatingMode() == NetworkOPs::omFULL);
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::startRound(
|
||||
NetClock::time_point const& now,
|
||||
RCLCxLedger::ID const& prevLgrId,
|
||||
RCLCxLedger const& prevLgr)
|
||||
{
|
||||
ScopedLockType _{mutex_};
|
||||
consensus_.startRound(
|
||||
now, prevLgrId, prevLgr, adaptor_.preStartRound(prevLgr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,34 +34,332 @@
|
||||
#include <ripple/protocol/RippleLedgerHash.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <ripple/shamap/SHAMap.h>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class InboundTransactions;
|
||||
class LocalTxs;
|
||||
class LedgerMaster;
|
||||
class ValidatorKeys;
|
||||
|
||||
//! Types used to adapt consensus for RCL
|
||||
struct RCLCxTraits
|
||||
{
|
||||
//! Ledger type presented to Consensus
|
||||
using Ledger_t = RCLCxLedger;
|
||||
//! Peer identifier type used in Consensus
|
||||
using NodeID_t = NodeID;
|
||||
//! TxSet type presented to Consensus
|
||||
using TxSet_t = RCLTxSet;
|
||||
};
|
||||
|
||||
/** Adapts the generic Consensus algorithm for use by RCL.
|
||||
|
||||
@note The enabled_shared_from_this base allows the application to properly
|
||||
create a shared instance of RCLConsensus for use in the accept logic..
|
||||
/** Manages the generic consensus algorithm for use by the RCL.
|
||||
*/
|
||||
class RCLConsensus final : public Consensus<RCLConsensus, RCLCxTraits>,
|
||||
public std::enable_shared_from_this<RCLConsensus>,
|
||||
public CountedObject<RCLConsensus>
|
||||
class RCLConsensus
|
||||
{
|
||||
using Base = Consensus<RCLConsensus, RCLCxTraits>;
|
||||
// Implements the Adaptor template interface required by Consensus.
|
||||
class Adaptor
|
||||
{
|
||||
Application& app_;
|
||||
std::unique_ptr<FeeVote> feeVote_;
|
||||
LedgerMaster& ledgerMaster_;
|
||||
LocalTxs& localTxs_;
|
||||
InboundTransactions& inboundTransactions_;
|
||||
beast::Journal j_;
|
||||
|
||||
NodeID const nodeID_;
|
||||
PublicKey const valPublic_;
|
||||
SecretKey const valSecret_;
|
||||
|
||||
// Ledger we most recently needed to acquire
|
||||
LedgerHash acquiringLedger_;
|
||||
ConsensusParms parms_;
|
||||
|
||||
// The timestamp of the last validation we used
|
||||
NetClock::time_point lastValidationTime_;
|
||||
|
||||
// These members are queried via public accesors and are atomic for
|
||||
// thread safety.
|
||||
std::atomic<bool> validating_{false};
|
||||
std::atomic<std::size_t> prevProposers_{0};
|
||||
std::atomic<std::chrono::milliseconds> prevRoundTime_{
|
||||
std::chrono::milliseconds{0}};
|
||||
std::atomic<ConsensusMode> mode_{ConsensusMode::observing};
|
||||
|
||||
public:
|
||||
using Ledger_t = RCLCxLedger;
|
||||
using NodeID_t = NodeID;
|
||||
using TxSet_t = RCLTxSet;
|
||||
using PeerPosition_t = RCLCxPeerPos;
|
||||
|
||||
using Result = ConsensusResult<Adaptor>;
|
||||
|
||||
Adaptor(
|
||||
Application& app,
|
||||
std::unique_ptr<FeeVote>&& feeVote,
|
||||
LedgerMaster& ledgerMaster,
|
||||
LocalTxs& localTxs,
|
||||
InboundTransactions& inboundTransactions,
|
||||
ValidatorKeys const & validatorKeys,
|
||||
beast::Journal journal);
|
||||
|
||||
bool
|
||||
validating() const
|
||||
{
|
||||
return validating_;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
prevProposers() const
|
||||
{
|
||||
return prevProposers_;
|
||||
}
|
||||
|
||||
std::chrono::milliseconds
|
||||
prevRoundTime() const
|
||||
{
|
||||
return prevRoundTime_;
|
||||
}
|
||||
|
||||
ConsensusMode
|
||||
mode() const
|
||||
{
|
||||
return mode_;
|
||||
}
|
||||
|
||||
/** Called before kicking off a new consensus round.
|
||||
|
||||
@param prevLedger Ledger that will be prior ledger for next round
|
||||
@return Whether we enter the round proposing
|
||||
*/
|
||||
bool
|
||||
preStartRound(RCLCxLedger const & prevLedger);
|
||||
|
||||
/** Consensus simulation parameters
|
||||
*/
|
||||
ConsensusParms const&
|
||||
parms() const
|
||||
{
|
||||
return parms_;
|
||||
}
|
||||
|
||||
private:
|
||||
//---------------------------------------------------------------------
|
||||
// The following members implement the generic Consensus requirements
|
||||
// and are marked private to indicate ONLY Consensus<Adaptor> will call
|
||||
// them (via friendship). Since they are callled only from Consenus<Adaptor>
|
||||
// methods and since RCLConsensus::consensus_ should only be accessed
|
||||
// under lock, these will only be called under lock.
|
||||
//
|
||||
// In general, the idea is that there is only ONE thread that is running
|
||||
// consensus code at anytime. The only special case is the dispatched
|
||||
// onAccept call, which does not take a lock and relies on Consensus not
|
||||
// changing state until a future call to startRound.
|
||||
friend class Consensus<Adaptor>;
|
||||
|
||||
/** Attempt to acquire a specific ledger.
|
||||
|
||||
If not available, asynchronously acquires from the network.
|
||||
|
||||
@param ledger The ID/hash of the ledger acquire
|
||||
@return Optional ledger, will be seated if we locally had the ledger
|
||||
*/
|
||||
boost::optional<RCLCxLedger>
|
||||
acquireLedger(LedgerHash const& ledger);
|
||||
|
||||
/** Relay the given proposal to all peers
|
||||
|
||||
@param peerPos The peer position to relay.
|
||||
*/
|
||||
void
|
||||
relay(RCLCxPeerPos const& peerPos);
|
||||
|
||||
/** Relay disputed transacction to peers.
|
||||
|
||||
Only relay if the provided transaction hasn't been shared recently.
|
||||
|
||||
@param tx The disputed transaction to relay.
|
||||
*/
|
||||
void
|
||||
relay(RCLCxTx const& tx);
|
||||
|
||||
/** Acquire the transaction set associated with a proposal.
|
||||
|
||||
If the transaction set is not available locally, will attempt
|
||||
acquire it from the network.
|
||||
|
||||
@param setId The transaction set ID associated with the proposal
|
||||
@return Optional set of transactions, seated if available.
|
||||
*/
|
||||
boost::optional<RCLTxSet>
|
||||
acquireTxSet(RCLTxSet::ID const& setId);
|
||||
|
||||
/** Whether the open ledger has any transactions
|
||||
*/
|
||||
bool
|
||||
hasOpenTransactions() const;
|
||||
|
||||
/** Number of proposers that have vallidated the given ledger
|
||||
|
||||
@param h The hash of the ledger of interest
|
||||
@return the number of proposers that validated a ledger
|
||||
*/
|
||||
std::size_t
|
||||
proposersValidated(LedgerHash const& h) const;
|
||||
|
||||
/** Number of proposers that have validated a ledger descended from
|
||||
requested ledger.
|
||||
|
||||
@param h The hash of the ledger of interest.
|
||||
@return The number of validating peers that have validated a ledger
|
||||
succeeding the one provided.
|
||||
*/
|
||||
std::size_t
|
||||
proposersFinished(LedgerHash const& h) const;
|
||||
|
||||
/** Propose the given position to my peers.
|
||||
|
||||
@param proposal Our proposed position
|
||||
*/
|
||||
void
|
||||
propose(RCLCxPeerPos::Proposal const& proposal);
|
||||
|
||||
/** Relay the given tx set to peers.
|
||||
|
||||
@param set The TxSet to share.
|
||||
*/
|
||||
void
|
||||
relay(RCLTxSet const& set);
|
||||
|
||||
/** Get the ID of the previous ledger/last closed ledger(LCL) on the
|
||||
network
|
||||
|
||||
@param ledgerID ID of previous ledger used by consensus
|
||||
@param ledger Previous ledger consensus has available
|
||||
@param mode Current consensus mode
|
||||
@return The id of the last closed network
|
||||
|
||||
@note ledgerID may not match ledger.id() if we haven't acquired
|
||||
the ledger matching ledgerID from the network
|
||||
*/
|
||||
uint256
|
||||
getPrevLedger(
|
||||
uint256 ledgerID,
|
||||
RCLCxLedger const& ledger,
|
||||
ConsensusMode mode);
|
||||
|
||||
void
|
||||
onModeChange(ConsensusMode before, ConsensusMode after)
|
||||
{
|
||||
mode_ = after;
|
||||
}
|
||||
|
||||
/** Close the open ledger and return initial consensus position.
|
||||
|
||||
@param ledger the ledger we are changing to
|
||||
@param closeTime When consensus closed the ledger
|
||||
@param mode Current consensus mode
|
||||
@return Tentative consensus result
|
||||
*/
|
||||
Result
|
||||
onClose(
|
||||
RCLCxLedger const& ledger,
|
||||
NetClock::time_point const& closeTime,
|
||||
ConsensusMode mode);
|
||||
|
||||
/** Process the accepted ledger.
|
||||
|
||||
@param result The result of consensus
|
||||
@param prevLedger The closed ledger consensus worked from
|
||||
@param closeResolution The resolution used in agreeing on an
|
||||
effective closeTime
|
||||
@param rawCloseTimes The unrounded closetimes of ourself and our
|
||||
peers
|
||||
@param mode Our participating mode at the time consensus was
|
||||
declared
|
||||
@param consensusJson Json representation of consensus state
|
||||
*/
|
||||
void
|
||||
onAccept(
|
||||
Result const& result,
|
||||
RCLCxLedger const& prevLedger,
|
||||
NetClock::duration const& closeResolution,
|
||||
ConsensusCloseTimes const& rawCloseTimes,
|
||||
ConsensusMode const& mode,
|
||||
Json::Value&& consensusJson);
|
||||
|
||||
/** Process the accepted ledger that was a result of simulation/force
|
||||
accept.
|
||||
|
||||
@ref onAccept
|
||||
*/
|
||||
void
|
||||
onForceAccept(
|
||||
Result const& result,
|
||||
RCLCxLedger const& prevLedger,
|
||||
NetClock::duration const& closeResolution,
|
||||
ConsensusCloseTimes const& rawCloseTimes,
|
||||
ConsensusMode const& mode,
|
||||
Json::Value&& consensusJson);
|
||||
|
||||
/** Notify peers of a consensus state change
|
||||
|
||||
@param ne Event type for notification
|
||||
@param ledger The ledger at the time of the state change
|
||||
@param haveCorrectLCL Whether we believ we have the correct LCL.
|
||||
*/
|
||||
void
|
||||
notify(
|
||||
protocol::NodeEvent ne,
|
||||
RCLCxLedger const& ledger,
|
||||
bool haveCorrectLCL);
|
||||
|
||||
/** Accept a new ledger based on the given transactions.
|
||||
|
||||
@ref onAccept
|
||||
*/
|
||||
void
|
||||
doAccept(
|
||||
Result const& result,
|
||||
RCLCxLedger const& prevLedger,
|
||||
NetClock::duration closeResolution,
|
||||
ConsensusCloseTimes const& rawCloseTimes,
|
||||
ConsensusMode const& mode,
|
||||
Json::Value&& consensusJson);
|
||||
|
||||
/** Build the new last closed ledger.
|
||||
|
||||
Accept the given the provided set of consensus transactions and
|
||||
build the last closed ledger. Since consensus just agrees on which
|
||||
transactions to apply, but not whether they make it into the closed
|
||||
ledger, this function also populates retriableTxs with those that
|
||||
can be retried in the next round.
|
||||
|
||||
@param previousLedger Prior ledger building upon
|
||||
@param set The set of transactions to apply to the ledger
|
||||
@param closeTime The the ledger closed
|
||||
@param closeTimeCorrect Whether consensus agreed on close time
|
||||
@param closeResolution Resolution used to determine consensus close
|
||||
time
|
||||
@param roundTime Duration of this consensus rorund
|
||||
@param retriableTxs Populate with transactions to retry in next
|
||||
round
|
||||
@return The newly built ledger
|
||||
*/
|
||||
RCLCxLedger
|
||||
buildLCL(
|
||||
RCLCxLedger const& previousLedger,
|
||||
RCLTxSet const& set,
|
||||
NetClock::time_point closeTime,
|
||||
bool closeTimeCorrect,
|
||||
NetClock::duration closeResolution,
|
||||
std::chrono::milliseconds roundTime,
|
||||
CanonicalTXSet& retriableTxs);
|
||||
|
||||
/** Validate the given ledger and share with peers as necessary
|
||||
|
||||
@param ledger The ledger to validate
|
||||
@param proposing Whether we were proposing transactions while
|
||||
generating this ledger. If we are not proposing,
|
||||
a validation can still be sent to inform peers that
|
||||
we know we aren't fully participating in consensus
|
||||
but are still around and trying to catch up.
|
||||
*/
|
||||
void
|
||||
validate(RCLCxLedger const& ledger, bool proposing);
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
//! Constructor
|
||||
@@ -71,7 +369,8 @@ public:
|
||||
LedgerMaster& ledgerMaster,
|
||||
LocalTxs& localTxs,
|
||||
InboundTransactions& inboundTransactions,
|
||||
typename Base::clock_type const& clock,
|
||||
Consensus<Adaptor>::clock_type const& clock,
|
||||
ValidatorKeys const & validatorKeys,
|
||||
beast::Journal journal);
|
||||
|
||||
RCLConsensus(RCLConsensus const&) = delete;
|
||||
@@ -79,310 +378,96 @@ public:
|
||||
RCLConsensus&
|
||||
operator=(RCLConsensus const&) = delete;
|
||||
|
||||
static char const*
|
||||
getCountedObjectName()
|
||||
{
|
||||
return "Consensus";
|
||||
}
|
||||
|
||||
/** Save the given consensus proposed by a peer with nodeID for later
|
||||
use in consensus.
|
||||
|
||||
@param peerPos Proposed peer position
|
||||
@param nodeID ID of peer
|
||||
*/
|
||||
void
|
||||
storeProposal(RCLCxPeerPos::ref peerPos, NodeID const& nodeID);
|
||||
|
||||
//! Whether we are validating consensus ledgers.
|
||||
bool
|
||||
validating() const
|
||||
{
|
||||
return validating_;
|
||||
return adaptor_.validating();
|
||||
}
|
||||
|
||||
bool
|
||||
haveCorrectLCL() const
|
||||
//! Get the number of proposing peers that participated in the previous
|
||||
//! round.
|
||||
std::size_t
|
||||
prevProposers() const
|
||||
{
|
||||
return mode() != Mode::wrongLedger;
|
||||
return adaptor_.prevProposers();
|
||||
}
|
||||
|
||||
bool
|
||||
proposing() const
|
||||
{
|
||||
return mode() == Mode::proposing;
|
||||
}
|
||||
/** Get duration of the previous round.
|
||||
|
||||
/** Get the Json state of the consensus process.
|
||||
The duration of the round is the establish phase, measured from closing
|
||||
the open ledger to accepting the consensus result.
|
||||
|
||||
Called by the consensus_info RPC.
|
||||
|
||||
@param full True if verbose response desired.
|
||||
@return The Json state.
|
||||
@return Last round duration in milliseconds
|
||||
*/
|
||||
std::chrono::milliseconds
|
||||
prevRoundTime() const
|
||||
{
|
||||
return adaptor_.prevRoundTime();
|
||||
}
|
||||
|
||||
//! @see Consensus::mode
|
||||
ConsensusMode
|
||||
mode() const
|
||||
{
|
||||
return adaptor_.mode();
|
||||
}
|
||||
|
||||
//! @see Consensus::getJson
|
||||
Json::Value
|
||||
getJson(bool full) const;
|
||||
|
||||
//! See Consensus::startRound
|
||||
//! @see Consensus::startRound
|
||||
void
|
||||
startRound(
|
||||
NetClock::time_point const& now,
|
||||
RCLCxLedger::ID const& prevLgrId,
|
||||
RCLCxLedger const& prevLgr);
|
||||
|
||||
//! See Consensus::timerEntry
|
||||
//! @see Consensus::timerEntry
|
||||
void
|
||||
timerEntry(NetClock::time_point const& now);
|
||||
|
||||
//! See Consensus::gotTxSet
|
||||
//! @see Consensus::gotTxSet
|
||||
void
|
||||
gotTxSet(NetClock::time_point const& now, RCLTxSet const& txSet);
|
||||
|
||||
/** Returns validation public key */
|
||||
PublicKey const&
|
||||
getValidationPublicKey() const;
|
||||
// @see Consensus::prevLedgerID
|
||||
RCLCxLedger::ID
|
||||
prevLedgerID() const
|
||||
{
|
||||
ScopedLockType _{mutex_};
|
||||
return consensus_.prevLedgerID();
|
||||
}
|
||||
|
||||
/** Set validation private and public key pair. */
|
||||
//! @see Consensus::simulate
|
||||
void
|
||||
setValidationKeys(SecretKey const& valSecret, PublicKey const& valPublic);
|
||||
simulate(
|
||||
NetClock::time_point const& now,
|
||||
boost::optional<std::chrono::milliseconds> consensusDelay);
|
||||
|
||||
//! @see Consensus::proposal
|
||||
bool
|
||||
peerProposal(
|
||||
NetClock::time_point const& now,
|
||||
RCLCxPeerPos const& newProposal);
|
||||
|
||||
ConsensusParms const &
|
||||
parms() const
|
||||
{
|
||||
return adaptor_.parms();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Consensus<RCLConsensus, RCLCxTraits>;
|
||||
// Since Consensus does not provide intrinsic thread-safety, this mutex
|
||||
// guards all calls to consensus_. adaptor_ uses atomics internally
|
||||
// to allow concurrent access of its data members that have getters.
|
||||
mutable std::recursive_mutex mutex_;
|
||||
using ScopedLockType = std::lock_guard <std::recursive_mutex>;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Consensus type requirements.
|
||||
|
||||
/** Attempt to acquire a specific ledger.
|
||||
|
||||
If not available, asynchronously acquires from the network.
|
||||
|
||||
@param ledger The ID/hash of the ledger acquire
|
||||
@return Optional ledger, will be seated if we locally had the ledger
|
||||
*/
|
||||
boost::optional<RCLCxLedger>
|
||||
acquireLedger(LedgerHash const& ledger);
|
||||
|
||||
/** Get peers' proposed positions.
|
||||
@param prevLedger The base ledger which proposals are based on
|
||||
@return The set of proposals
|
||||
*/
|
||||
std::vector<RCLCxPeerPos>
|
||||
proposals(LedgerHash const& prevLedger);
|
||||
|
||||
/** Relay the given proposal to all peers
|
||||
|
||||
@param peerPos The peer position to relay.
|
||||
*/
|
||||
void
|
||||
relay(RCLCxPeerPos const& peerPos);
|
||||
|
||||
/** Relay disputed transacction to peers.
|
||||
|
||||
Only relay if the provided transaction hasn't been shared recently.
|
||||
|
||||
@param tx The disputed transaction to relay.
|
||||
*/
|
||||
void
|
||||
relay(RCLCxTx const& tx);
|
||||
|
||||
/** Acquire the transaction set associated with a proposal.
|
||||
|
||||
If the transaction set is not available locally, will attempt acquire it
|
||||
from the network.
|
||||
|
||||
@param setId The transaction set ID associated with the proposal
|
||||
@return Optional set of transactions, seated if available.
|
||||
*/
|
||||
boost::optional<RCLTxSet>
|
||||
acquireTxSet(RCLTxSet::ID const& setId);
|
||||
|
||||
/** Whether the open ledger has any transactions
|
||||
*/
|
||||
bool
|
||||
hasOpenTransactions() const;
|
||||
|
||||
/** Number of proposers that have vallidated the given ledger
|
||||
|
||||
@param h The hash of the ledger of interest
|
||||
@return the number of proposers that validated a ledger
|
||||
*/
|
||||
std::size_t
|
||||
proposersValidated(LedgerHash const& h) const;
|
||||
|
||||
/** Number of proposers that have validated a ledger descended from
|
||||
requested ledger.
|
||||
|
||||
@param h The hash of the ledger of interest.
|
||||
@return The number of validating peers that have validated a ledger
|
||||
succeeding the one provided.
|
||||
*/
|
||||
std::size_t
|
||||
proposersFinished(LedgerHash const& h) const;
|
||||
|
||||
/** Propose the given position to my peers.
|
||||
|
||||
@param proposal Our proposed position
|
||||
*/
|
||||
void
|
||||
propose(RCLCxPeerPos::Proposal const& proposal);
|
||||
|
||||
/** Relay the given tx set to peers.
|
||||
|
||||
@param set The TxSet to share.
|
||||
*/
|
||||
void
|
||||
relay(RCLTxSet const& set);
|
||||
|
||||
/** Get the ID of the previous ledger/last closed ledger(LCL) on the network
|
||||
|
||||
@param ledgerID ID of previous ledger used by consensus
|
||||
@param ledger Previous ledger consensus has available
|
||||
@param mode Current consensus mode
|
||||
@return The id of the last closed network
|
||||
|
||||
@note ledgerID may not match ledger.id() if we haven't acquired
|
||||
the ledger matching ledgerID from the network
|
||||
*/
|
||||
uint256
|
||||
getPrevLedger(
|
||||
uint256 ledgerID,
|
||||
RCLCxLedger const& ledger,
|
||||
Mode mode);
|
||||
|
||||
/** Close the open ledger and return initial consensus position.
|
||||
|
||||
@param ledger the ledger we are changing to
|
||||
@param closeTime When consensus closed the ledger
|
||||
@param mode Current consensus mode
|
||||
@return Tentative consensus result
|
||||
*/
|
||||
Result
|
||||
onClose(
|
||||
RCLCxLedger const& ledger,
|
||||
NetClock::time_point const& closeTime,
|
||||
Mode mode);
|
||||
|
||||
/** Process the accepted ledger.
|
||||
|
||||
Accepting a ledger may be expensive, so this function can dispatch
|
||||
that call to another thread if desired.
|
||||
|
||||
@param result The result of consensus
|
||||
@param prevLedger The closed ledger consensus worked from
|
||||
@param closeResolution The resolution used in agreeing on an effective
|
||||
closeTiem
|
||||
@param rawCloseTimes The unrounded closetimes of ourself and our peers
|
||||
@param mode Our participating mode at the time consensus was declared
|
||||
*/
|
||||
void
|
||||
onAccept(
|
||||
Result const& result,
|
||||
RCLCxLedger const& prevLedger,
|
||||
NetClock::duration const & closeResolution,
|
||||
CloseTimes const& rawCloseTimes,
|
||||
Mode const& mode);
|
||||
|
||||
/** Process the accepted ledger that was a result of simulation/force
|
||||
accept.
|
||||
|
||||
@ref onAccept
|
||||
*/
|
||||
void
|
||||
onForceAccept(
|
||||
Result const& result,
|
||||
RCLCxLedger const& prevLedger,
|
||||
NetClock::duration const &closeResolution,
|
||||
CloseTimes const& rawCloseTimes,
|
||||
Mode const& mode);
|
||||
|
||||
//!-------------------------------------------------------------------------
|
||||
// Additional members (not directly required by Consensus interface)
|
||||
/** Notify peers of a consensus state change
|
||||
|
||||
@param ne Event type for notification
|
||||
@param ledger The ledger at the time of the state change
|
||||
@param haveCorrectLCL Whether we believ we have the correct LCL.
|
||||
*/
|
||||
void
|
||||
notify(
|
||||
protocol::NodeEvent ne,
|
||||
RCLCxLedger const& ledger,
|
||||
bool haveCorrectLCL);
|
||||
|
||||
/** Accept a new ledger based on the given transactions.
|
||||
|
||||
@ref onAccept
|
||||
*/
|
||||
void
|
||||
doAccept(
|
||||
Result const& result,
|
||||
RCLCxLedger const& prevLedger,
|
||||
NetClock::duration closeResolution,
|
||||
CloseTimes const& rawCloseTimes,
|
||||
Mode const& mode);
|
||||
|
||||
/** Build the new last closed ledger.
|
||||
|
||||
Accept the given the provided set of consensus transactions and build
|
||||
the last closed ledger. Since consensus just agrees on which
|
||||
transactions to apply, but not whether they make it into the closed
|
||||
ledger, this function also populates retriableTxs with those that can
|
||||
be retried in the next round.
|
||||
|
||||
@param previousLedger Prior ledger building upon
|
||||
@param set The set of transactions to apply to the ledger
|
||||
@param closeTime The the ledger closed
|
||||
@param closeTimeCorrect Whether consensus agreed on close time
|
||||
@param closeResolution Resolution used to determine consensus close time
|
||||
@param roundTime Duration of this consensus rorund
|
||||
@param retriableTxs Populate with transactions to retry in next round
|
||||
@return The newly built ledger
|
||||
*/
|
||||
RCLCxLedger
|
||||
buildLCL(
|
||||
RCLCxLedger const& previousLedger,
|
||||
RCLTxSet const& set,
|
||||
NetClock::time_point closeTime,
|
||||
bool closeTimeCorrect,
|
||||
NetClock::duration closeResolution,
|
||||
std::chrono::milliseconds roundTime,
|
||||
CanonicalTXSet& retriableTxs);
|
||||
|
||||
/** Validate the given ledger and share with peers as necessary
|
||||
|
||||
@param ledger The ledger to validate
|
||||
@param proposing Whether we were proposing transactions while generating
|
||||
this ledger. If we are not proposing, a validation
|
||||
can still be sent to inform peers that we know we
|
||||
aren't fully participating in consensus but are still
|
||||
around and trying to catch up.
|
||||
*/
|
||||
void
|
||||
validate(RCLCxLedger const& ledger, bool proposing);
|
||||
|
||||
//!-------------------------------------------------------------------------
|
||||
Application& app_;
|
||||
std::unique_ptr<FeeVote> feeVote_;
|
||||
LedgerMaster& ledgerMaster_;
|
||||
LocalTxs& localTxs_;
|
||||
InboundTransactions& inboundTransactions_;
|
||||
Adaptor adaptor_;
|
||||
Consensus<Adaptor> consensus_;
|
||||
beast::Journal j_;
|
||||
|
||||
NodeID nodeID_;
|
||||
PublicKey valPublic_;
|
||||
SecretKey valSecret_;
|
||||
LedgerHash acquiringLedger_;
|
||||
|
||||
// The timestamp of the last validation we used, in network time. This is
|
||||
// only used for our own validations.
|
||||
NetClock::time_point lastValidationTime_;
|
||||
|
||||
using PeerPositions = hash_map<NodeID, std::deque<RCLCxPeerPos::pointer>>;
|
||||
PeerPositions peerPositions_;
|
||||
std::mutex peerPositionsLock_;
|
||||
|
||||
bool validating_ = false;
|
||||
bool simulating_ = false;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -33,14 +33,16 @@ RCLCxPeerPos::RCLCxPeerPos(
|
||||
Slice const& signature,
|
||||
uint256 const& suppression,
|
||||
Proposal&& proposal)
|
||||
: proposal_{std::move(proposal)}
|
||||
, mSuppression{suppression}
|
||||
, publicKey_{publicKey}
|
||||
, signature_{signature}
|
||||
: data_{std::make_shared<Data>(
|
||||
publicKey,
|
||||
signature,
|
||||
suppression,
|
||||
std::move(proposal))}
|
||||
{
|
||||
}
|
||||
|
||||
uint256
|
||||
RCLCxPeerPos::getSigningHash() const
|
||||
RCLCxPeerPos::signingHash() const
|
||||
{
|
||||
return sha512Half(
|
||||
HashPrefix::proposal,
|
||||
@@ -53,16 +55,18 @@ RCLCxPeerPos::getSigningHash() const
|
||||
bool
|
||||
RCLCxPeerPos::checkSign() const
|
||||
{
|
||||
return verifyDigest(publicKey_, getSigningHash(), signature_, false);
|
||||
return verifyDigest(
|
||||
publicKey(), signingHash(), signature(), false);
|
||||
}
|
||||
|
||||
|
||||
Json::Value
|
||||
RCLCxPeerPos::getJson() const
|
||||
{
|
||||
auto ret = proposal().getJson();
|
||||
|
||||
if (publicKey_.size())
|
||||
ret[jss::peer_id] = toBase58(TokenType::TOKEN_NODE_PUBLIC, publicKey_);
|
||||
if (publicKey().size())
|
||||
ret[jss::peer_id] = toBase58(TokenType::TOKEN_NODE_PUBLIC, publicKey());
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -87,4 +91,16 @@ proposalUniqueId(
|
||||
return s.getSHA512Half();
|
||||
}
|
||||
|
||||
RCLCxPeerPos::Data::Data(
|
||||
PublicKey const& publicKey,
|
||||
Slice const& signature,
|
||||
uint256 const& suppress,
|
||||
Proposal&& proposal)
|
||||
: publicKey_{publicKey}
|
||||
, signature_{signature}
|
||||
, supression_{suppress}
|
||||
, proposal_{std::move(proposal)}
|
||||
{
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -36,19 +36,12 @@ namespace ripple {
|
||||
|
||||
/** A peer's signed, proposed position for use in RCLConsensus.
|
||||
|
||||
Carries a ConsensusProposal signed by a peer.
|
||||
Carries a ConsensusProposal signed by a peer. Provides value semantics
|
||||
but manages shared storage of the peer position internally.
|
||||
*/
|
||||
class RCLCxPeerPos : public CountedObject<RCLCxPeerPos>
|
||||
class RCLCxPeerPos
|
||||
{
|
||||
public:
|
||||
static char const*
|
||||
getCountedObjectName()
|
||||
{
|
||||
return "RCLCxPeerPos";
|
||||
}
|
||||
using pointer = std::shared_ptr<RCLCxPeerPos>;
|
||||
using ref = const pointer&;
|
||||
|
||||
//< The type of the proposed position
|
||||
using Proposal = ConsensusProposal<NodeID, uint256, uint256>;
|
||||
|
||||
@@ -70,7 +63,7 @@ public:
|
||||
|
||||
//! Create the signing hash for the proposal
|
||||
uint256
|
||||
getSigningHash() const;
|
||||
signingHash() const;
|
||||
|
||||
//! Verify the signing hash of the proposal
|
||||
bool
|
||||
@@ -78,45 +71,59 @@ public:
|
||||
|
||||
//! Signature of the proposal (not necessarily verified)
|
||||
Slice
|
||||
getSignature() const
|
||||
signature() const
|
||||
{
|
||||
return signature_;
|
||||
return data_->signature_;
|
||||
}
|
||||
|
||||
//! Public key of peer that sent the proposal
|
||||
PublicKey const&
|
||||
getPublicKey() const
|
||||
publicKey() const
|
||||
{
|
||||
return publicKey_;
|
||||
return data_->publicKey_;
|
||||
}
|
||||
|
||||
//! ?????
|
||||
uint256 const&
|
||||
getSuppressionID() const
|
||||
suppressionID() const
|
||||
{
|
||||
return mSuppression;
|
||||
return data_->supression_;
|
||||
}
|
||||
|
||||
//! The consensus proposal
|
||||
Proposal const&
|
||||
Proposal const &
|
||||
proposal() const
|
||||
{
|
||||
return proposal_;
|
||||
return data_->proposal_;
|
||||
}
|
||||
|
||||
/// @cond Ignore
|
||||
//! Add a conversion operator to conform to the Consensus interface
|
||||
operator Proposal const&() const
|
||||
{
|
||||
return proposal_;
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
//! JSON representation of proposal
|
||||
Json::Value
|
||||
getJson() const;
|
||||
|
||||
private:
|
||||
|
||||
struct Data : public CountedObject<Data>
|
||||
{
|
||||
PublicKey publicKey_;
|
||||
Buffer signature_;
|
||||
uint256 supression_;
|
||||
Proposal proposal_;
|
||||
|
||||
Data(
|
||||
PublicKey const& publicKey,
|
||||
Slice const& signature,
|
||||
uint256 const& suppress,
|
||||
Proposal&& proposal);
|
||||
|
||||
static char const*
|
||||
getCountedObjectName()
|
||||
{
|
||||
return "RCLCxPeerPos::Data";
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<Data> data_;
|
||||
|
||||
template <class Hasher>
|
||||
void
|
||||
hash_append(Hasher& h) const
|
||||
@@ -129,10 +136,6 @@ private:
|
||||
hash_append(h, proposal().position());
|
||||
}
|
||||
|
||||
Proposal proposal_;
|
||||
uint256 mSuppression;
|
||||
PublicKey publicKey_;
|
||||
Buffer signature_;
|
||||
};
|
||||
|
||||
/** Calculate a unique identifier for a signed proposal.
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <ripple/app/misc/SHAMapStore.h>
|
||||
#include <ripple/app/misc/TxQ.h>
|
||||
#include <ripple/app/misc/ValidatorSite.h>
|
||||
#include <ripple/app/misc/ValidatorKeys.h>
|
||||
#include <ripple/app/paths/PathRequests.h>
|
||||
#include <ripple/app/tx/apply.h>
|
||||
#include <ripple/basics/ResolverAsio.h>
|
||||
@@ -305,6 +306,7 @@ public:
|
||||
std::unique_ptr <CollectorManager> m_collectorManager;
|
||||
CachedSLEs cachedSLEs_;
|
||||
std::pair<PublicKey, SecretKey> nodeIdentity_;
|
||||
ValidatorKeys const validatorKeys_;
|
||||
|
||||
std::unique_ptr <Resource::Manager> m_resourceManager;
|
||||
|
||||
@@ -394,8 +396,8 @@ public:
|
||||
|
||||
, m_collectorManager (CollectorManager::New (
|
||||
config_->section (SECTION_INSIGHT), logs_->journal("Collector")))
|
||||
|
||||
, cachedSLEs_ (std::chrono::minutes(1), stopwatch())
|
||||
, validatorKeys_(*config_, m_journal)
|
||||
|
||||
, m_resourceManager (Resource::make_Manager (
|
||||
m_collectorManager->collector(), logs_->journal("Resource")))
|
||||
@@ -445,7 +447,7 @@ public:
|
||||
|
||||
, m_networkOPs (make_NetworkOPs (*this, stopwatch(),
|
||||
config_->standalone(), config_->NETWORK_QUORUM, config_->START_VALID,
|
||||
*m_jobQueue, *m_ledgerMaster, *m_jobQueue,
|
||||
*m_jobQueue, *m_ledgerMaster, *m_jobQueue, validatorKeys_,
|
||||
logs_->journal("NetworkOPs")))
|
||||
|
||||
, cluster_ (std::make_unique<Cluster> (
|
||||
@@ -570,6 +572,13 @@ public:
|
||||
return nodeIdentity_;
|
||||
}
|
||||
|
||||
virtual
|
||||
PublicKey const &
|
||||
getValidationPublicKey() const override
|
||||
{
|
||||
return validatorKeys_.publicKey;
|
||||
}
|
||||
|
||||
NetworkOPs& getOPs () override
|
||||
{
|
||||
return *m_networkOPs;
|
||||
@@ -1086,38 +1095,11 @@ bool ApplicationImp::setup()
|
||||
}
|
||||
|
||||
{
|
||||
PublicKey valPublic;
|
||||
SecretKey valSecret;
|
||||
std::string manifest;
|
||||
if (config().exists (SECTION_VALIDATOR_TOKEN))
|
||||
{
|
||||
if (auto const token = ValidatorToken::make_ValidatorToken (
|
||||
config().section (SECTION_VALIDATOR_TOKEN).lines ()))
|
||||
{
|
||||
valSecret = token->validationSecret;
|
||||
valPublic = derivePublicKey (KeyType::secp256k1, valSecret);
|
||||
manifest = std::move(token->manifest);
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(m_journal.fatal()) <<
|
||||
"Invalid entry in validator token configuration.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (config().exists (SECTION_VALIDATION_SEED))
|
||||
{
|
||||
auto const seed = parseBase58<Seed>(
|
||||
config().section (SECTION_VALIDATION_SEED).lines ().front());
|
||||
if (!seed)
|
||||
Throw<std::runtime_error> (
|
||||
"Invalid seed specified in [" SECTION_VALIDATION_SEED "]");
|
||||
valSecret = generateSecretKey (KeyType::secp256k1, *seed);
|
||||
valPublic = derivePublicKey (KeyType::secp256k1, valSecret);
|
||||
}
|
||||
if(validatorKeys_.configInvalid())
|
||||
return false;
|
||||
|
||||
if (!validatorManifests_->load (
|
||||
getWalletDB (), "ValidatorManifests", manifest,
|
||||
getWalletDB (), "ValidatorManifests", validatorKeys_.manifest,
|
||||
config().section (SECTION_VALIDATOR_KEY_REVOCATION).values ()))
|
||||
{
|
||||
JLOG(m_journal.fatal()) << "Invalid configured validator manifest.";
|
||||
@@ -1127,11 +1109,9 @@ bool ApplicationImp::setup()
|
||||
publisherManifests_->load (
|
||||
getWalletDB (), "PublisherManifests");
|
||||
|
||||
m_networkOPs->setValidationKeys (valSecret, valPublic);
|
||||
|
||||
// Setup trusted validators
|
||||
if (!validators_->load (
|
||||
valPublic,
|
||||
validatorKeys_.publicKey,
|
||||
config().section (SECTION_VALIDATORS).values (),
|
||||
config().section (SECTION_VALIDATOR_LIST_KEYS).values ()))
|
||||
{
|
||||
|
||||
@@ -150,6 +150,10 @@ public:
|
||||
std::pair<PublicKey, SecretKey> const&
|
||||
nodeIdentity () = 0;
|
||||
|
||||
virtual
|
||||
PublicKey const &
|
||||
getValidationPublicKey() const = 0;
|
||||
|
||||
virtual Resource::Manager& getResourceManager () = 0;
|
||||
virtual PathRequests& getPathRequests () = 0;
|
||||
virtual SHAMapStore& getSHAMapStore () = 0;
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <ripple/app/misc/LoadFeeTrack.h>
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
#include <ripple/app/misc/TxQ.h>
|
||||
#include <ripple/app/misc/ValidatorKeys.h>
|
||||
#include <ripple/app/misc/ValidatorList.h>
|
||||
#include <ripple/app/misc/impl/AccountTxPaging.h>
|
||||
#include <ripple/app/tx/apply.h>
|
||||
@@ -187,7 +188,7 @@ public:
|
||||
Application& app, clock_type& clock, bool standalone,
|
||||
std::size_t network_quorum, bool start_valid, JobQueue& job_queue,
|
||||
LedgerMaster& ledgerMaster, Stoppable& parent,
|
||||
beast::Journal journal)
|
||||
ValidatorKeys const & validatorKeys, beast::Journal journal)
|
||||
: NetworkOPs (parent)
|
||||
, app_ (app)
|
||||
, m_clock (clock)
|
||||
@@ -198,14 +199,15 @@ public:
|
||||
, m_amendmentBlocked (false)
|
||||
, m_heartbeatTimer (this)
|
||||
, m_clusterTimer (this)
|
||||
, mConsensus (std::make_shared<RCLConsensus>(app,
|
||||
, mConsensus (app,
|
||||
make_FeeVote(setup_FeeVote (app_.config().section ("voting")),
|
||||
app_.logs().journal("FeeVote")),
|
||||
ledgerMaster,
|
||||
*m_localTX,
|
||||
app.getInboundTransactions(),
|
||||
stopwatch(),
|
||||
app_.logs().journal("LedgerConsensus")))
|
||||
validatorKeys,
|
||||
app_.logs().journal("LedgerConsensus"))
|
||||
, m_ledgerMaster (ledgerMaster)
|
||||
, m_job_queue (job_queue)
|
||||
, m_standalone (standalone)
|
||||
@@ -296,7 +298,7 @@ public:
|
||||
|
||||
// Ledger proposal/close functions.
|
||||
void processTrustedProposal (
|
||||
RCLCxPeerPos::pointer proposal,
|
||||
RCLCxPeerPos proposal,
|
||||
std::shared_ptr<protocol::TMProposeSet> set,
|
||||
NodeID const &node) override;
|
||||
|
||||
@@ -323,7 +325,6 @@ private:
|
||||
std::shared_ptr<Ledger const> const& newLCL);
|
||||
bool checkLastClosedLedger (
|
||||
const Overlay::PeerSequence&, uint256& networkClosed);
|
||||
void tryStartConsensus ();
|
||||
|
||||
public:
|
||||
bool beginConsensus (uint256 const& networkClosed) override;
|
||||
@@ -360,15 +361,7 @@ public:
|
||||
}
|
||||
void setAmendmentBlocked () override;
|
||||
void consensusViewChange () override;
|
||||
PublicKey const& getValidationPublicKey () const override
|
||||
{
|
||||
return mConsensus->getValidationPublicKey ();
|
||||
}
|
||||
void setValidationKeys (
|
||||
SecretKey const& valSecret, PublicKey const& valPublic) override
|
||||
{
|
||||
mConsensus->setValidationKeys (valSecret, valPublic);
|
||||
}
|
||||
|
||||
Json::Value getConsensusInfo () override;
|
||||
Json::Value getServerInfo (bool human, bool admin) override;
|
||||
void clearLedgerFetch () override;
|
||||
@@ -549,7 +542,7 @@ private:
|
||||
DeadlineTimer m_clusterTimer;
|
||||
JobCounter jobCounter_;
|
||||
|
||||
std::shared_ptr<RCLConsensus> mConsensus;
|
||||
RCLConsensus mConsensus;
|
||||
|
||||
LedgerMaster& m_ledgerMaster;
|
||||
std::shared_ptr<InboundLedger> mAcquiringLedger;
|
||||
@@ -651,7 +644,7 @@ void NetworkOPsImp::setStateTimer ()
|
||||
|
||||
void NetworkOPsImp::setHeartbeatTimer ()
|
||||
{
|
||||
m_heartbeatTimer.setExpiration (mConsensus->parms().ledgerGRANULARITY);
|
||||
m_heartbeatTimer.setExpiration (mConsensus.parms().ledgerGRANULARITY);
|
||||
}
|
||||
|
||||
void NetworkOPsImp::setClusterTimer ()
|
||||
@@ -697,7 +690,7 @@ void NetworkOPsImp::processHeartbeatTimer ()
|
||||
<< "Node count (" << numPeers << ") "
|
||||
<< "has fallen below quorum (" << m_network_quorum << ").";
|
||||
}
|
||||
// We do not call mConsensus->timerEntry until there
|
||||
// We do not call mConsensus.timerEntry until there
|
||||
// are enough peers providing meaningful inputs to consensus
|
||||
setHeartbeatTimer ();
|
||||
|
||||
@@ -720,7 +713,7 @@ void NetworkOPsImp::processHeartbeatTimer ()
|
||||
|
||||
}
|
||||
|
||||
mConsensus->timerEntry (app_.timeKeeper().closeTime());
|
||||
mConsensus.timerEntry (app_.timeKeeper().closeTime());
|
||||
|
||||
setHeartbeatTimer ();
|
||||
}
|
||||
@@ -775,13 +768,17 @@ void NetworkOPsImp::processClusterTimer ()
|
||||
|
||||
std::string NetworkOPsImp::strOperatingMode () const
|
||||
{
|
||||
if (mMode == omFULL && mConsensus->haveCorrectLCL())
|
||||
if (mMode == omFULL)
|
||||
{
|
||||
if (mConsensus->proposing ())
|
||||
return "proposing";
|
||||
auto const mode = mConsensus.mode();
|
||||
if (mode != ConsensusMode::wrongLedger)
|
||||
{
|
||||
if (mode == ConsensusMode::proposing)
|
||||
return "proposing";
|
||||
|
||||
if (mConsensus->validating ())
|
||||
return "validating";
|
||||
if (mConsensus.validating())
|
||||
return "validating";
|
||||
}
|
||||
}
|
||||
|
||||
return states_[mMode];
|
||||
@@ -1252,46 +1249,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void NetworkOPsImp::tryStartConsensus ()
|
||||
{
|
||||
uint256 networkClosed;
|
||||
bool ledgerChange = checkLastClosedLedger (
|
||||
app_.overlay ().getActivePeers (), networkClosed);
|
||||
|
||||
if (networkClosed.isZero ())
|
||||
return;
|
||||
|
||||
// WRITEME: Unless we are in omFULL and in the process of doing a consensus,
|
||||
// we must count how many nodes share our LCL, how many nodes disagree with
|
||||
// our LCL, and how many validations our LCL has. We also want to check
|
||||
// timing to make sure there shouldn't be a newer LCL. We need this
|
||||
// information to do the next three tests.
|
||||
|
||||
if (((mMode == omCONNECTED) || (mMode == omSYNCING)) && !ledgerChange)
|
||||
{
|
||||
// Count number of peers that agree with us and UNL nodes whose
|
||||
// validations we have for LCL. If the ledger is good enough, go to
|
||||
// omTRACKING - TODO
|
||||
if (!mNeedNetworkLedger)
|
||||
setMode (omTRACKING);
|
||||
}
|
||||
|
||||
if (((mMode == omCONNECTED) || (mMode == omTRACKING)) && !ledgerChange)
|
||||
{
|
||||
// check if the ledger is good enough to go to omFULL
|
||||
// Note: Do not go to omFULL if we don't have the previous ledger
|
||||
// check if the ledger is bad enough to go to omCONNECTED -- TODO
|
||||
auto current = m_ledgerMaster.getCurrentLedger();
|
||||
if (app_.timeKeeper().now() <
|
||||
(current->info().parentCloseTime + 2* current->info().closeTimeResolution))
|
||||
{
|
||||
setMode (omFULL);
|
||||
}
|
||||
}
|
||||
|
||||
beginConsensus (networkClosed);
|
||||
}
|
||||
|
||||
bool NetworkOPsImp::checkLastClosedLedger (
|
||||
const Overlay::PeerSequence& peerList, uint256& networkClosed)
|
||||
{
|
||||
@@ -1527,7 +1484,7 @@ bool NetworkOPsImp::beginConsensus (uint256 const& networkClosed)
|
||||
app_.validators().onConsensusStart (
|
||||
app_.getValidations().getCurrentPublicKeys ());
|
||||
|
||||
mConsensus->startRound (
|
||||
mConsensus.startRound (
|
||||
app_.timeKeeper().closeTime(),
|
||||
networkClosed,
|
||||
prevLedger);
|
||||
@@ -1538,19 +1495,19 @@ bool NetworkOPsImp::beginConsensus (uint256 const& networkClosed)
|
||||
|
||||
uint256 NetworkOPsImp::getConsensusLCL ()
|
||||
{
|
||||
return mConsensus->prevLedgerID ();
|
||||
return mConsensus.prevLedgerID ();
|
||||
}
|
||||
|
||||
void NetworkOPsImp::processTrustedProposal (
|
||||
RCLCxPeerPos::pointer peerPos,
|
||||
RCLCxPeerPos peerPos,
|
||||
std::shared_ptr<protocol::TMProposeSet> set,
|
||||
NodeID const& node)
|
||||
{
|
||||
mConsensus->storeProposal (peerPos, node);
|
||||
|
||||
if (mConsensus->peerProposal (
|
||||
app_.timeKeeper().closeTime(), peerPos->proposal()))
|
||||
app_.overlay().relay(*set, peerPos->getSuppressionID());
|
||||
if (mConsensus.peerProposal(
|
||||
app_.timeKeeper().closeTime(), peerPos))
|
||||
{
|
||||
app_.overlay().relay(*set, peerPos.suppressionID());
|
||||
}
|
||||
else
|
||||
JLOG(m_journal.info()) << "Not relaying trusted proposal";
|
||||
}
|
||||
@@ -1573,7 +1530,7 @@ NetworkOPsImp::mapComplete (
|
||||
|
||||
// We acquired it because consensus asked us to
|
||||
if (fromAcquire)
|
||||
mConsensus->gotTxSet (
|
||||
mConsensus.gotTxSet (
|
||||
app_.timeKeeper().closeTime(),
|
||||
RCLTxSet{map});
|
||||
}
|
||||
@@ -1591,7 +1548,42 @@ void NetworkOPsImp::endConsensus ()
|
||||
}
|
||||
}
|
||||
|
||||
tryStartConsensus();
|
||||
uint256 networkClosed;
|
||||
bool ledgerChange = checkLastClosedLedger (
|
||||
app_.overlay ().getActivePeers (), networkClosed);
|
||||
|
||||
if (networkClosed.isZero ())
|
||||
return;
|
||||
|
||||
// WRITEME: Unless we are in omFULL and in the process of doing a consensus,
|
||||
// we must count how many nodes share our LCL, how many nodes disagree with
|
||||
// our LCL, and how many validations our LCL has. We also want to check
|
||||
// timing to make sure there shouldn't be a newer LCL. We need this
|
||||
// information to do the next three tests.
|
||||
|
||||
if (((mMode == omCONNECTED) || (mMode == omSYNCING)) && !ledgerChange)
|
||||
{
|
||||
// Count number of peers that agree with us and UNL nodes whose
|
||||
// validations we have for LCL. If the ledger is good enough, go to
|
||||
// omTRACKING - TODO
|
||||
if (!mNeedNetworkLedger)
|
||||
setMode (omTRACKING);
|
||||
}
|
||||
|
||||
if (((mMode == omCONNECTED) || (mMode == omTRACKING)) && !ledgerChange)
|
||||
{
|
||||
// check if the ledger is good enough to go to omFULL
|
||||
// Note: Do not go to omFULL if we don't have the previous ledger
|
||||
// check if the ledger is bad enough to go to omCONNECTED -- TODO
|
||||
auto current = m_ledgerMaster.getCurrentLedger();
|
||||
if (app_.timeKeeper().now() <
|
||||
(current->info().parentCloseTime + 2* current->info().closeTimeResolution))
|
||||
{
|
||||
setMode (omFULL);
|
||||
}
|
||||
}
|
||||
|
||||
beginConsensus (networkClosed);
|
||||
}
|
||||
|
||||
void NetworkOPsImp::consensusViewChange ()
|
||||
@@ -2125,7 +2117,7 @@ bool NetworkOPsImp::recvValidation (
|
||||
|
||||
Json::Value NetworkOPsImp::getConsensusInfo ()
|
||||
{
|
||||
return mConsensus->getJson (true);
|
||||
return mConsensus.getJson (true);
|
||||
}
|
||||
|
||||
Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin)
|
||||
@@ -2151,7 +2143,7 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin)
|
||||
|
||||
if (admin)
|
||||
{
|
||||
if (getValidationPublicKey().size ())
|
||||
if (!app_.getValidationPublicKey().empty())
|
||||
{
|
||||
info[jss::pubkey_validator] = toBase58 (
|
||||
TokenType::TOKEN_NODE_PUBLIC,
|
||||
@@ -2181,23 +2173,23 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin)
|
||||
info[jss::peers] = Json::UInt (app_.overlay ().size ());
|
||||
|
||||
Json::Value lastClose = Json::objectValue;
|
||||
lastClose[jss::proposers] = Json::UInt(mConsensus->prevProposers());
|
||||
lastClose[jss::proposers] = Json::UInt(mConsensus.prevProposers());
|
||||
|
||||
if (human)
|
||||
{
|
||||
lastClose[jss::converge_time_s] =
|
||||
std::chrono::duration<double>{
|
||||
mConsensus->prevRoundTime()}.count();
|
||||
mConsensus.prevRoundTime()}.count();
|
||||
}
|
||||
else
|
||||
{
|
||||
lastClose[jss::converge_time] =
|
||||
Json::Int (mConsensus->prevRoundTime().count());
|
||||
Json::Int (mConsensus.prevRoundTime().count());
|
||||
}
|
||||
|
||||
info[jss::last_close] = lastClose;
|
||||
|
||||
// info[jss::consensus] = mConsensus->getJson();
|
||||
// info[jss::consensus] = mConsensus.getJson();
|
||||
|
||||
if (admin)
|
||||
info[jss::load] = m_job_queue.getJson ();
|
||||
@@ -2771,7 +2763,7 @@ std::uint32_t NetworkOPsImp::acceptLedger (
|
||||
// FIXME Could we improve on this and remove the need for a specialized
|
||||
// API in Consensus?
|
||||
beginConsensus (m_ledgerMaster.getClosedLedger()->info().hash);
|
||||
mConsensus->simulate (app_.timeKeeper().closeTime(), consensusDelay);
|
||||
mConsensus.simulate (app_.timeKeeper().closeTime(), consensusDelay);
|
||||
return m_ledgerMaster.getCurrentLedger ()->info().seq;
|
||||
}
|
||||
|
||||
@@ -3368,10 +3360,10 @@ std::unique_ptr<NetworkOPs>
|
||||
make_NetworkOPs (Application& app, NetworkOPs::clock_type& clock, bool standalone,
|
||||
std::size_t network_quorum, bool startvalid,
|
||||
JobQueue& job_queue, LedgerMaster& ledgerMaster,
|
||||
Stoppable& parent, beast::Journal journal)
|
||||
Stoppable& parent, ValidatorKeys const & validatorKeys, beast::Journal journal)
|
||||
{
|
||||
return std::make_unique<NetworkOPsImp> (app, clock, standalone, network_quorum,
|
||||
startvalid, job_queue, ledgerMaster, parent, journal);
|
||||
startvalid, job_queue, ledgerMaster, parent, validatorKeys, journal);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace ripple {
|
||||
class Peer;
|
||||
class LedgerMaster;
|
||||
class Transaction;
|
||||
class ValidatorKeys;
|
||||
|
||||
// This is the primary interface into the "client" portion of the program.
|
||||
// Code that wants to do normal operations on the network such as
|
||||
@@ -150,7 +151,7 @@ public:
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// ledger proposal/close functions
|
||||
virtual void processTrustedProposal (RCLCxPeerPos::pointer peerPos,
|
||||
virtual void processTrustedProposal (RCLCxPeerPos peerPos,
|
||||
std::shared_ptr<protocol::TMProposeSet> set,
|
||||
NodeID const& node) = 0;
|
||||
|
||||
@@ -174,9 +175,6 @@ public:
|
||||
virtual bool isAmendmentBlocked () = 0;
|
||||
virtual void setAmendmentBlocked () = 0;
|
||||
virtual void consensusViewChange () = 0;
|
||||
virtual PublicKey const& getValidationPublicKey () const = 0;
|
||||
virtual void setValidationKeys (
|
||||
SecretKey const& valSecret, PublicKey const& valPublic) = 0;
|
||||
|
||||
virtual Json::Value getConsensusInfo () = 0;
|
||||
virtual Json::Value getServerInfo (bool human, bool admin) = 0;
|
||||
@@ -242,7 +240,7 @@ std::unique_ptr<NetworkOPs>
|
||||
make_NetworkOPs (Application& app, NetworkOPs::clock_type& clock, bool standalone,
|
||||
std::size_t network_quorum, bool start_valid,
|
||||
JobQueue& job_queue, LedgerMaster& ledgerMaster,
|
||||
Stoppable& parent, beast::Journal journal);
|
||||
Stoppable& parent, ValidatorKeys const & validatorKeys, beast::Journal journal);
|
||||
|
||||
} // ripple
|
||||
|
||||
|
||||
54
src/ripple/app/misc/ValidatorKeys.h
Normal file
54
src/ripple/app/misc/ValidatorKeys.h
Normal file
@@ -0,0 +1,54 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012-2017 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_APP_MISC_VALIDATOR_KEYS_H_INCLUDED
|
||||
#define RIPPLE_APP_MISC_VALIDATOR_KEYS_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/protocol/PublicKey.h>
|
||||
#include <ripple/protocol/SecretKey.h>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class Config;
|
||||
|
||||
/** Validator keys and manifest as set in configuration file. Values will be
|
||||
empty if not configured as a validator or not configured with a manifest.
|
||||
*/
|
||||
class ValidatorKeys
|
||||
{
|
||||
public:
|
||||
PublicKey publicKey;
|
||||
SecretKey secretKey;
|
||||
std::string manifest;
|
||||
ValidatorKeys(Config const& config, beast::Journal j);
|
||||
|
||||
bool configInvalid() const
|
||||
{
|
||||
return configInvalid_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool configInvalid_ = false; //< Set to true if config was invalid
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
73
src/ripple/app/misc/impl/ValidatorKeys.cpp
Normal file
73
src/ripple/app/misc/impl/ValidatorKeys.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/app/misc/ValidatorKeys.h>
|
||||
|
||||
#include <ripple/app/misc/Manifest.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
|
||||
namespace ripple {
|
||||
ValidatorKeys::ValidatorKeys(Config const& config, beast::Journal j)
|
||||
{
|
||||
if (config.exists(SECTION_VALIDATOR_TOKEN) &&
|
||||
config.exists(SECTION_VALIDATION_SEED))
|
||||
{
|
||||
configInvalid_ = true;
|
||||
JLOG(j.fatal()) << "Cannot specify both [" SECTION_VALIDATION_SEED
|
||||
"] and [" SECTION_VALIDATOR_TOKEN "]";
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.exists(SECTION_VALIDATOR_TOKEN))
|
||||
{
|
||||
if (auto const token = ValidatorToken::make_ValidatorToken(
|
||||
config.section(SECTION_VALIDATOR_TOKEN).lines()))
|
||||
{
|
||||
secretKey = token->validationSecret;
|
||||
publicKey = derivePublicKey(KeyType::secp256k1, secretKey);
|
||||
manifest = std::move(token->manifest);
|
||||
}
|
||||
else
|
||||
{
|
||||
configInvalid_ = true;
|
||||
JLOG(j.fatal())
|
||||
<< "Invalid token specified in [" SECTION_VALIDATOR_TOKEN "]";
|
||||
}
|
||||
}
|
||||
else if (config.exists(SECTION_VALIDATION_SEED))
|
||||
{
|
||||
auto const seed = parseBase58<Seed>(
|
||||
config.section(SECTION_VALIDATION_SEED).lines().front());
|
||||
if (!seed)
|
||||
{
|
||||
configInvalid_ = true;
|
||||
JLOG(j.fatal()) <<
|
||||
"Invalid seed specified in [" SECTION_VALIDATION_SEED "]";
|
||||
}
|
||||
else
|
||||
{
|
||||
secretKey = generateSecretKey(KeyType::secp256k1, *seed);
|
||||
publicKey = derivePublicKey(KeyType::secp256k1, secretKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace ripple
|
||||
File diff suppressed because it is too large
Load Diff
242
src/ripple/consensus/ConsensusTypes.h
Normal file
242
src/ripple/consensus/ConsensusTypes.h
Normal file
@@ -0,0 +1,242 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012-2017 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CONSENSUS_CONSENSUS_TYPES_H_INCLUDED
|
||||
#define RIPPLE_CONSENSUS_CONSENSUS_TYPES_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/chrono.h>
|
||||
#include <ripple/consensus/ConsensusProposal.h>
|
||||
#include <ripple/consensus/DisputedTx.h>
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Represents how a node currently participates in Consensus.
|
||||
|
||||
A node participates in consensus in varying modes, depending on how
|
||||
the node was configured by its operator and how well it stays in sync
|
||||
with the network during consensus.
|
||||
|
||||
@code
|
||||
proposing observing
|
||||
\ /
|
||||
\---> wrongLedger <---/
|
||||
^
|
||||
|
|
||||
|
|
||||
v
|
||||
switchedLedger
|
||||
@endcode
|
||||
|
||||
We enter the round proposing or observing. If we detect we are working
|
||||
on the wrong prior ledger, we go to wrongLedger and attempt to acquire
|
||||
the right one. Once we acquire the right one, we go to the switchedLedger
|
||||
mode. It is possible we fall behind again and find there is a new better
|
||||
ledger, moving back and forth between wrongLedger and switchLedger as
|
||||
we attempt to catch up.
|
||||
*/
|
||||
enum class ConsensusMode {
|
||||
//! We are normal participant in consensus and propose our position
|
||||
proposing,
|
||||
//! We are observing peer positions, but not proposing our position
|
||||
observing,
|
||||
//! We have the wrong ledger and are attempting to acquire it
|
||||
wrongLedger,
|
||||
//! We switched ledgers since we started this consensus round but are now
|
||||
//! running on what we believe is the correct ledger. This mode is as
|
||||
//! if we entered the round observing, but is used to indicate we did
|
||||
//! have the wrongLedger at some point.
|
||||
switchedLedger
|
||||
};
|
||||
|
||||
inline std::string
|
||||
to_string(ConsensusMode m)
|
||||
{
|
||||
switch (m)
|
||||
{
|
||||
case ConsensusMode::proposing:
|
||||
return "proposing";
|
||||
case ConsensusMode::observing:
|
||||
return "observing";
|
||||
case ConsensusMode::wrongLedger:
|
||||
return "wrongLedger";
|
||||
case ConsensusMode::switchedLedger:
|
||||
return "switchedLedger";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/** Phases of consensus for a single ledger round.
|
||||
|
||||
@code
|
||||
"close" "accept"
|
||||
open ------- > establish ---------> accepted
|
||||
^ | |
|
||||
|---------------| |
|
||||
^ "startRound" |
|
||||
|------------------------------------|
|
||||
@endcode
|
||||
|
||||
The typical transition goes from open to establish to accepted and
|
||||
then a call to startRound begins the process anew. However, if a wrong prior
|
||||
ledger is detected and recovered during the establish or accept phase,
|
||||
consensus will internally go back to open (see Consensus::handleWrongLedger).
|
||||
*/
|
||||
enum class ConsensusPhase {
|
||||
//! We haven't closed our ledger yet, but others might have
|
||||
open,
|
||||
|
||||
//! Establishing consensus by exchanging proposals with our peers
|
||||
establish,
|
||||
|
||||
//! We have accepted a new last closed ledger and are waiting on a call
|
||||
//! to startRound to begin the next consensus round. No changes
|
||||
//! to consensus phase occur while in this phase.
|
||||
accepted,
|
||||
};
|
||||
|
||||
inline std::string
|
||||
to_string(ConsensusPhase p)
|
||||
{
|
||||
switch (p)
|
||||
{
|
||||
case ConsensusPhase::open:
|
||||
return "open";
|
||||
case ConsensusPhase::establish:
|
||||
return "establish";
|
||||
case ConsensusPhase::accepted:
|
||||
return "accepted";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/** Measures the duration of phases of consensus
|
||||
*/
|
||||
class ConsensusTimer
|
||||
{
|
||||
using time_point = std::chrono::steady_clock::time_point;
|
||||
time_point start_;
|
||||
std::chrono::milliseconds dur_;
|
||||
|
||||
public:
|
||||
std::chrono::milliseconds
|
||||
read() const
|
||||
{
|
||||
return dur_;
|
||||
}
|
||||
|
||||
void
|
||||
tick(std::chrono::milliseconds fixed)
|
||||
{
|
||||
dur_ += fixed;
|
||||
}
|
||||
|
||||
void
|
||||
reset(time_point tp)
|
||||
{
|
||||
start_ = tp;
|
||||
dur_ = std::chrono::milliseconds{0};
|
||||
}
|
||||
|
||||
void
|
||||
tick(time_point tp)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
dur_ = duration_cast<milliseconds>(tp - start_);
|
||||
}
|
||||
};
|
||||
|
||||
/** Stores the set of initial close times
|
||||
|
||||
The initial consensus proposal from each peer has that peer's view of
|
||||
when the ledger closed. This object stores all those close times for
|
||||
analysis of clock drift between peerss.
|
||||
*/
|
||||
struct ConsensusCloseTimes
|
||||
{
|
||||
//! Close time estimates, keep ordered for predictable traverse
|
||||
std::map<NetClock::time_point, int> peers;
|
||||
|
||||
//! Our close time estimate
|
||||
NetClock::time_point self;
|
||||
};
|
||||
|
||||
/** Whether we have or don't have a consensus */
|
||||
enum class ConsensusState {
|
||||
No, //!< We do not have consensus
|
||||
MovedOn, //!< The network has consensus without us
|
||||
Yes //!< We have consensus along with the network
|
||||
};
|
||||
|
||||
/** Encapsulates the result of consensus.
|
||||
|
||||
Stores all relevant data for the outcome of consensus on a single
|
||||
ledger.
|
||||
|
||||
@tparam Traits Traits class defining the concrete consensus types used
|
||||
by the application.
|
||||
*/
|
||||
template <class Traits>
|
||||
struct ConsensusResult
|
||||
{
|
||||
using Ledger_t = typename Traits::Ledger_t;
|
||||
using TxSet_t = typename Traits::TxSet_t;
|
||||
using NodeID_t = typename Traits::NodeID_t;
|
||||
|
||||
using Tx_t = typename TxSet_t::Tx;
|
||||
using Proposal_t = ConsensusProposal<
|
||||
NodeID_t,
|
||||
typename Ledger_t::ID,
|
||||
typename TxSet_t::ID>;
|
||||
using Dispute_t = DisputedTx<Tx_t, NodeID_t>;
|
||||
|
||||
ConsensusResult(TxSet_t&& s, Proposal_t&& p)
|
||||
: set{std::move(s)}, position{std::move(p)}
|
||||
{
|
||||
assert(set.id() == position.position());
|
||||
}
|
||||
|
||||
//! The set of transactions consensus agrees go in the ledger
|
||||
TxSet_t set;
|
||||
|
||||
//! Our proposed position on transactions/close time
|
||||
Proposal_t position;
|
||||
|
||||
//! Transactions which are under dispute with our peers
|
||||
hash_map<typename Tx_t::ID, Dispute_t> disputes;
|
||||
|
||||
// Set of TxSet ids we have already compared/created disputes
|
||||
hash_set<typename TxSet_t::ID> compares;
|
||||
|
||||
// Measures the duration of the establish phase for this consensus round
|
||||
ConsensusTimer roundTime;
|
||||
|
||||
// Indicates state in which consensus ended. Once in the accept phase
|
||||
// will be either Yes or MovedOn
|
||||
ConsensusState state = ConsensusState::No;
|
||||
|
||||
// The number of peers proposing during the round
|
||||
std::size_t proposers = 0;
|
||||
};
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -1094,7 +1094,7 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMTransaction> const& m)
|
||||
flags |= SF_TRUSTED;
|
||||
}
|
||||
|
||||
if (! app_.getOPs().getValidationPublicKey().size())
|
||||
if (app_.getValidationPublicKey().empty())
|
||||
{
|
||||
// For now, be paranoid and have each validator
|
||||
// check each transaction, regardless of source
|
||||
@@ -1256,8 +1256,8 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMProposeSet> const& m)
|
||||
return;
|
||||
}
|
||||
|
||||
if (app_.getOPs().getValidationPublicKey().size() &&
|
||||
publicKey == app_.getOPs().getValidationPublicKey())
|
||||
if (!app_.getValidationPublicKey().empty() &&
|
||||
publicKey == app_.getValidationPublicKey())
|
||||
{
|
||||
JLOG(p_journal_.trace()) << "Proposal: self";
|
||||
return;
|
||||
@@ -1283,7 +1283,7 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMProposeSet> const& m)
|
||||
JLOG(p_journal_.trace()) <<
|
||||
"Proposal: " << (isTrusted ? "trusted" : "UNTRUSTED");
|
||||
|
||||
auto proposal = std::make_shared<RCLCxPeerPos> (
|
||||
auto proposal = RCLCxPeerPos(
|
||||
publicKey, signature, suppression,
|
||||
RCLCxPeerPos::Proposal{prevLedger, set.proposeseq (), proposeHash, closeTime,
|
||||
app_.timeKeeper().closeTime(),calcNodeID(publicKey)});
|
||||
@@ -1889,7 +1889,7 @@ PeerImp::checkTransaction (int flags,
|
||||
void
|
||||
PeerImp::checkPropose (Job& job,
|
||||
std::shared_ptr <protocol::TMProposeSet> const& packet,
|
||||
RCLCxPeerPos::pointer peerPos)
|
||||
RCLCxPeerPos peerPos)
|
||||
{
|
||||
bool isTrusted = (job.getType () == jtPROPOSAL_t);
|
||||
|
||||
@@ -1899,7 +1899,7 @@ PeerImp::checkPropose (Job& job,
|
||||
assert (packet);
|
||||
protocol::TMProposeSet& set = *packet;
|
||||
|
||||
if (! cluster() && !peerPos->checkSign ())
|
||||
if (! cluster() && !peerPos.checkSign ())
|
||||
{
|
||||
JLOG(p_journal_.warn()) <<
|
||||
"Proposal fails sig check";
|
||||
@@ -1914,12 +1914,12 @@ PeerImp::checkPropose (Job& job,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (app_.getOPs().getConsensusLCL() == peerPos->proposal().prevLedger())
|
||||
if (app_.getOPs().getConsensusLCL() == peerPos.proposal().prevLedger())
|
||||
{
|
||||
// relay untrusted proposal
|
||||
JLOG(p_journal_.trace()) <<
|
||||
"relaying UNTRUSTED proposal";
|
||||
overlay_.relay(set, peerPos->getSuppressionID());
|
||||
overlay_.relay(set, peerPos.suppressionID());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -451,7 +451,7 @@ private:
|
||||
void
|
||||
checkPropose (Job& job,
|
||||
std::shared_ptr<protocol::TMProposeSet> const& packet,
|
||||
RCLCxPeerPos::pointer peerPos);
|
||||
RCLCxPeerPos peerPos);
|
||||
|
||||
void
|
||||
checkValidation (STValidation::pointer val,
|
||||
|
||||
@@ -87,6 +87,12 @@ public:
|
||||
return size_;
|
||||
}
|
||||
|
||||
bool
|
||||
empty() const noexcept
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
Slice
|
||||
slice() const noexcept
|
||||
{
|
||||
|
||||
@@ -33,3 +33,4 @@
|
||||
#include <ripple/app/misc/impl/TxQ.cpp>
|
||||
#include <ripple/app/misc/impl/ValidatorList.cpp>
|
||||
#include <ripple/app/misc/impl/ValidatorSite.cpp>
|
||||
#include <ripple/app/misc/impl/ValidatorKeys.cpp>
|
||||
|
||||
150
src/test/app/ValidatorKeys_test.cpp
Normal file
150
src/test/app/ValidatorKeys_test.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright 2017 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/misc/ValidatorKeys.h>
|
||||
#include <ripple/beast/unit_test.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
class ValidatorKeys_test : public beast::unit_test::suite
|
||||
{
|
||||
// Used with [validation_seed]
|
||||
const std::string seed = "shUwVw52ofnCUX5m7kPTKzJdr4HEH";
|
||||
|
||||
// Used with [validation_token]
|
||||
const std::string tokenSecretStr =
|
||||
"paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi";
|
||||
|
||||
const std::vector<std::string> tokenBlob = {
|
||||
" "
|
||||
"eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n",
|
||||
" \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFuaWZl "
|
||||
" \n",
|
||||
"\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZDeE"
|
||||
"\n",
|
||||
"\t "
|
||||
"hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG\t "
|
||||
"\t\n",
|
||||
"bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUzZQU2\n",
|
||||
"hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZeXd1\n",
|
||||
"NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZWRGdj\n",
|
||||
"VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==\n"};
|
||||
|
||||
const std::string tokenManifest =
|
||||
"JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/vCxHXXLplc2GnMhAkE1agqXxBwD"
|
||||
"wDbID6OMSYuM0FDAlpAgNk8SKFn7MO2fdkcwRQIhAOngu9sAKqXYouJ+l2V0W+sAOkVB"
|
||||
"+ZRS6PShlJAfUsXfAiBsVJGesaadOJc/aAZokS1vymGmVrlHPKWX3Yywu6in8HASQKPu"
|
||||
"gBD67kMaRFGvmpATHlGKJdvDFlWPYy5AqDedFv5TJa2w0i21eq3MYywLVJZnFOr7C0kw"
|
||||
"2AiTzSCjIzditQ8=";
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
beast::Journal j;
|
||||
|
||||
// Keys when using [validation_seed]
|
||||
auto const seedSecretKey =
|
||||
generateSecretKey(KeyType::secp256k1, *parseBase58<Seed>(seed));
|
||||
auto const seedPublicKey =
|
||||
derivePublicKey(KeyType::secp256k1, seedSecretKey);
|
||||
|
||||
// Keys when using [validation_token]
|
||||
auto const tokenSecretKey = *parseBase58<SecretKey>(
|
||||
TokenType::TOKEN_NODE_PRIVATE, tokenSecretStr);
|
||||
|
||||
auto const tokenPublicKey =
|
||||
derivePublicKey(KeyType::secp256k1, tokenSecretKey);
|
||||
|
||||
{
|
||||
// No config -> no key but valid
|
||||
Config c;
|
||||
ValidatorKeys k{c, j};
|
||||
BEAST_EXPECT(k.publicKey.size() == 0);
|
||||
BEAST_EXPECT(k.manifest.empty());
|
||||
BEAST_EXPECT(!k.configInvalid());
|
||||
|
||||
}
|
||||
{
|
||||
// validation seed section -> empty manifest and valid seeds
|
||||
Config c;
|
||||
c.section(SECTION_VALIDATION_SEED).append(seed);
|
||||
|
||||
ValidatorKeys k{c, j};
|
||||
BEAST_EXPECT(k.publicKey == seedPublicKey);
|
||||
BEAST_EXPECT(k.secretKey == seedSecretKey);
|
||||
BEAST_EXPECT(k.manifest.empty());
|
||||
BEAST_EXPECT(!k.configInvalid());
|
||||
}
|
||||
|
||||
{
|
||||
// validation seed bad seed -> invalid
|
||||
Config c;
|
||||
c.section(SECTION_VALIDATION_SEED).append("badseed");
|
||||
|
||||
ValidatorKeys k{c, j};
|
||||
BEAST_EXPECT(k.configInvalid());
|
||||
BEAST_EXPECT(k.publicKey.size() == 0);
|
||||
BEAST_EXPECT(k.manifest.empty());
|
||||
}
|
||||
|
||||
{
|
||||
// validator token
|
||||
Config c;
|
||||
c.section(SECTION_VALIDATOR_TOKEN).append(tokenBlob);
|
||||
ValidatorKeys k{c, j};
|
||||
|
||||
BEAST_EXPECT(k.publicKey == tokenPublicKey);
|
||||
BEAST_EXPECT(k.secretKey == tokenSecretKey);
|
||||
BEAST_EXPECT(k.manifest == tokenManifest);
|
||||
BEAST_EXPECT(!k.configInvalid());
|
||||
}
|
||||
{
|
||||
// invalid validator token
|
||||
Config c;
|
||||
c.section(SECTION_VALIDATOR_TOKEN).append("badtoken");
|
||||
ValidatorKeys k{c, j};
|
||||
BEAST_EXPECT(k.configInvalid());
|
||||
BEAST_EXPECT(k.publicKey.size() == 0);
|
||||
BEAST_EXPECT(k.manifest.empty());
|
||||
}
|
||||
|
||||
{
|
||||
// Cannot specify both
|
||||
Config c;
|
||||
c.section(SECTION_VALIDATION_SEED).append(seed);
|
||||
c.section(SECTION_VALIDATOR_TOKEN).append(tokenBlob);
|
||||
ValidatorKeys k{c, j};
|
||||
|
||||
BEAST_EXPECT(k.configInvalid());
|
||||
BEAST_EXPECT(k.publicKey.size() == 0);
|
||||
BEAST_EXPECT(k.manifest.empty());
|
||||
}
|
||||
|
||||
}
|
||||
}; // namespace test
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(ValidatorKeys, app, ripple);
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
@@ -21,7 +21,8 @@
|
||||
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
|
||||
#include <ripple/consensus/Consensus.h>
|
||||
#include <ripple/consensus/ConsensusProposal.h>
|
||||
#include <test/csf/Ledger.h>
|
||||
#include <test/csf/Tx.h>
|
||||
#include <test/csf/UNL.h>
|
||||
@@ -115,20 +116,43 @@ public:
|
||||
directly from the generic types.
|
||||
*/
|
||||
using Proposal = ConsensusProposal<PeerID, Ledger::ID, TxSetType>;
|
||||
class PeerPosition
|
||||
{
|
||||
public:
|
||||
PeerPosition(Proposal const & p)
|
||||
: proposal_(p)
|
||||
{
|
||||
}
|
||||
|
||||
struct Traits
|
||||
Proposal const&
|
||||
proposal() const
|
||||
{
|
||||
return proposal_;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
getJson() const
|
||||
{
|
||||
return proposal_.getJson();
|
||||
}
|
||||
|
||||
private:
|
||||
Proposal proposal_;
|
||||
};
|
||||
|
||||
|
||||
/** Represents a single node participating in the consensus process.
|
||||
It implements the Adaptor requirements of generic Consensus.
|
||||
*/
|
||||
struct Peer
|
||||
{
|
||||
using Ledger_t = Ledger;
|
||||
using NodeID_t = PeerID;
|
||||
using TxSet_t = TxSet;
|
||||
};
|
||||
using PeerPosition_t = PeerPosition;
|
||||
using Result = ConsensusResult<Peer>;
|
||||
|
||||
/** Represents a single node participating in the consensus process.
|
||||
It implements the Callbacks required by Consensus.
|
||||
*/
|
||||
struct Peer : public Consensus<Peer, Traits>
|
||||
{
|
||||
using Base = Consensus<Peer, Traits>;
|
||||
Consensus<Peer> consensus;
|
||||
|
||||
//! Our unique ID
|
||||
PeerID id;
|
||||
@@ -172,12 +196,17 @@ struct Peer : public Consensus<Peer, Traits>
|
||||
bool validating_ = true;
|
||||
bool proposing_ = true;
|
||||
|
||||
ConsensusParms parms_;
|
||||
std::size_t prevProposers_ = 0;
|
||||
std::chrono::milliseconds prevRoundTime_;
|
||||
|
||||
//! All peers start from the default constructed ledger
|
||||
Peer(PeerID i, BasicNetwork<Peer*>& n, UNL const& u, ConsensusParms p)
|
||||
: Consensus<Peer, Traits>(n.clock(), p, beast::Journal{})
|
||||
: consensus(n.clock(), *this, beast::Journal{})
|
||||
, id{i}
|
||||
, net{n}
|
||||
, unl(u)
|
||||
, parms_(p)
|
||||
{
|
||||
ledgers[lastClosedLedger.id()] = lastClosedLedger;
|
||||
}
|
||||
@@ -210,12 +239,6 @@ struct Peer : public Consensus<Peer, Traits>
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto const&
|
||||
proposals(Ledger::ID const& ledgerHash)
|
||||
{
|
||||
return peerPositions_[ledgerHash];
|
||||
}
|
||||
|
||||
TxSet const*
|
||||
acquireTxSet(TxSet::ID const& setId)
|
||||
{
|
||||
@@ -245,17 +268,17 @@ struct Peer : public Consensus<Peer, Traits>
|
||||
}
|
||||
|
||||
Result
|
||||
onClose(Ledger const& prevLedger, NetClock::time_point closeTime, Mode mode)
|
||||
onClose(Ledger const& prevLedger, NetClock::time_point closeTime, ConsensusMode mode)
|
||||
{
|
||||
TxSet res{openTxs};
|
||||
|
||||
return Result{TxSet{openTxs},
|
||||
Proposal{prevLedger.id(),
|
||||
return Result(TxSet{openTxs},
|
||||
Proposal(prevLedger.id(),
|
||||
Proposal::seqJoin,
|
||||
res.id(),
|
||||
closeTime,
|
||||
now(),
|
||||
id}};
|
||||
id));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -263,10 +286,17 @@ struct Peer : public Consensus<Peer, Traits>
|
||||
Result const& result,
|
||||
Ledger const& prevLedger,
|
||||
NetClock::duration const& closeResolution,
|
||||
CloseTimes const& rawCloseTimes,
|
||||
Mode const& mode)
|
||||
ConsensusCloseTimes const& rawCloseTimes,
|
||||
ConsensusMode const& mode,
|
||||
Json::Value && consensusJson)
|
||||
{
|
||||
onAccept(result, prevLedger, closeResolution, rawCloseTimes, mode);
|
||||
onAccept(
|
||||
result,
|
||||
prevLedger,
|
||||
closeResolution,
|
||||
rawCloseTimes,
|
||||
mode,
|
||||
std::move(consensusJson));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -274,8 +304,9 @@ struct Peer : public Consensus<Peer, Traits>
|
||||
Result const& result,
|
||||
Ledger const& prevLedger,
|
||||
NetClock::duration const& closeResolution,
|
||||
CloseTimes const& rawCloseTimes,
|
||||
Mode const& mode)
|
||||
ConsensusCloseTimes const& rawCloseTimes,
|
||||
ConsensusMode const& mode,
|
||||
Json::Value && consensusJson)
|
||||
{
|
||||
auto newLedger = prevLedger.close(
|
||||
result.set.txs_,
|
||||
@@ -283,7 +314,8 @@ struct Peer : public Consensus<Peer, Traits>
|
||||
rawCloseTimes.self,
|
||||
result.position.closeTime() != NetClock::time_point{});
|
||||
ledgers[newLedger.id()] = newLedger;
|
||||
|
||||
prevProposers_ = result.proposers;
|
||||
prevRoundTime_ = result.roundTime.read();
|
||||
lastClosedLedger = newLedger;
|
||||
|
||||
auto it =
|
||||
@@ -304,16 +336,16 @@ struct Peer : public Consensus<Peer, Traits>
|
||||
// TODO: reconsider this and instead just save LCL generated here?
|
||||
if (completedLedgers <= targetLedgers)
|
||||
{
|
||||
startRound(
|
||||
consensus.startRound(
|
||||
now(), lastClosedLedger.id(), lastClosedLedger, proposing_);
|
||||
}
|
||||
}
|
||||
|
||||
Ledger::ID
|
||||
getPrevLedger(Ledger::ID const& ledgerID, Ledger const& ledger, Mode mode)
|
||||
getPrevLedger(Ledger::ID const& ledgerID, Ledger const& ledger, ConsensusMode mode)
|
||||
{
|
||||
// TODO: Use generic validation code
|
||||
if (mode != Mode::wrongLedger && ledgerID.seq > 0 &&
|
||||
if (mode != ConsensusMode::wrongLedger && ledgerID.seq > 0 &&
|
||||
ledger.id().seq > 0)
|
||||
return peerValidations.getBestLCL(ledgerID, ledger.parentID());
|
||||
return ledgerID;
|
||||
@@ -323,24 +355,31 @@ struct Peer : public Consensus<Peer, Traits>
|
||||
propose(Proposal const& pos)
|
||||
{
|
||||
if (proposing_)
|
||||
relay(pos);
|
||||
relay(PeerPosition(pos));
|
||||
}
|
||||
|
||||
ConsensusParms const &
|
||||
parms() const
|
||||
{
|
||||
return parms_;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// non-callback helpers
|
||||
void
|
||||
receive(Proposal const& p)
|
||||
receive(PeerPosition const& peerPos)
|
||||
{
|
||||
Proposal const & p = peerPos.proposal();
|
||||
if (unl.find(p.nodeID()) == unl.end())
|
||||
return;
|
||||
|
||||
// TODO: Be sure this is a new proposal!!!!!
|
||||
// TODO: Supress repeats more efficiently
|
||||
auto& dest = peerPositions_[p.prevLedger()];
|
||||
if (std::find(dest.begin(), dest.end(), p) != dest.end())
|
||||
return;
|
||||
|
||||
dest.push_back(p);
|
||||
peerProposal(now(), p);
|
||||
consensus.peerProposal(now(), peerPos);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -349,7 +388,7 @@ struct Peer : public Consensus<Peer, Traits>
|
||||
// save and map complete?
|
||||
auto it = txSets.insert(std::make_pair(txs.id(), txs));
|
||||
if (it.second)
|
||||
gotTxSet(now(), txs);
|
||||
consensus.gotTxSet(now(), txs);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -392,7 +431,7 @@ struct Peer : public Consensus<Peer, Traits>
|
||||
void
|
||||
timerEntry()
|
||||
{
|
||||
Base::timerEntry(now());
|
||||
consensus.timerEntry(now());
|
||||
// only reschedule if not completed
|
||||
if (completedLedgers < targetLedgers)
|
||||
net.timer(parms().ledgerGRANULARITY, [&]() { timerEntry(); });
|
||||
@@ -406,7 +445,7 @@ struct Peer : public Consensus<Peer, Traits>
|
||||
// so there is no gaurantee that bestLCL == lastClosedLedger.id()
|
||||
auto bestLCL = peerValidations.getBestLCL(
|
||||
lastClosedLedger.id(), lastClosedLedger.parentID());
|
||||
startRound(now(), bestLCL, lastClosedLedger, proposing_);
|
||||
consensus.startRound(now(), bestLCL, lastClosedLedger, proposing_);
|
||||
}
|
||||
|
||||
NetClock::time_point
|
||||
@@ -435,6 +474,28 @@ struct Peer : public Consensus<Peer, Traits>
|
||||
else
|
||||
net.timer(when, std::forward<T>(what));
|
||||
}
|
||||
|
||||
Ledger::ID
|
||||
prevLedgerID()
|
||||
{
|
||||
return consensus.prevLedgerID();
|
||||
}
|
||||
|
||||
std::size_t
|
||||
prevProposers()
|
||||
{
|
||||
return prevProposers_;
|
||||
}
|
||||
|
||||
std::chrono::milliseconds
|
||||
prevRoundTime()
|
||||
{
|
||||
return prevRoundTime_;
|
||||
}
|
||||
|
||||
// Not interested in tracking consensus mode
|
||||
void
|
||||
onModeChange(ConsensusMode, ConsensusMode) {}
|
||||
};
|
||||
|
||||
} // csf
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <test/app/Transaction_ordering_test.cpp>
|
||||
#include <test/app/TrustAndBalance_test.cpp>
|
||||
#include <test/app/TxQ_test.cpp>
|
||||
#include <test/app/ValidatorKeys_test.cpp>
|
||||
#include <test/app/ValidatorList_test.cpp>
|
||||
#include <test/app/ValidatorSite_test.cpp>
|
||||
#include <test/app/SetTrust_test.cpp>
|
||||
|
||||
Reference in New Issue
Block a user