3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/UnorderedContainers.h>
5#include <xrpl/basics/chrono.h>
6#include <xrpl/beast/clock/abstract_clock.h>
7#include <xrpl/beast/utility/Journal.h>
8#include <xrpl/beast/utility/instrumentation.h>
9#include <xrpl/consensus/ConsensusParms.h>
10#include <xrpl/consensus/ConsensusProposal.h>
11#include <xrpl/consensus/ConsensusTypes.h>
12#include <xrpl/json/json_value.h>
13#include <xrpl/json/json_writer.h>
14#include <xrpl/ledger/LedgerTiming.h>
54 std::size_t prevProposers,
55 std::size_t proposersClosed,
56 std::size_t proposersValidated,
57 std::chrono::milliseconds prevRoundTime,
58 std::chrono::milliseconds timeSincePrevClose,
59 std::chrono::milliseconds openTime,
60 std::chrono::milliseconds idleInterval,
63 std::unique_ptr<std::stringstream>
const& clog = {});
87 std::size_t prevProposers,
88 std::size_t currentProposers,
89 std::size_t currentAgree,
90 std::size_t currentFinished,
91 std::chrono::milliseconds previousAgreeTime,
92 std::chrono::milliseconds currentAgreeTime,
97 std::unique_ptr<std::stringstream>
const& clog = {});
288template <
class Adaptor>
319 a.onModeChange(
mode_, mode);
364 std::unique_ptr<
std::stringstream> const& clog = {});
634template <
class Adaptor>
638 JLOG(
j_.debug()) <<
"Creating consensus object";
641template <
class Adaptor>
663 for (
NodeID_t const& n : nowUntrusted)
674 prevLedger = *newLedger;
686template <
class Adaptor>
696 JLOG(
j_.debug()) <<
"transitioned to ConsensusPhase::Open ";
697 CLOG(clog) <<
"startRoundInternal transitioned to ConsensusPhase::Open, "
698 "previous ledgerID: "
699 <<
prevLedgerID <<
", seq: " << prevLedger.seq() <<
". ";
721 CLOG(clog) <<
"number of peer proposals,previous proposers: " <<
currPeerPositions_.size()
727 CLOG(clog) <<
"consider closing the ledger immediately. ";
732template <
class Adaptor>
736 JLOG(
j_.debug()) <<
"PROPOSAL " << newPeerPos.render();
737 auto const& peerID = newPeerPos.proposal().nodeID();
743 if (props.size() >= 10)
746 props.push_back(newPeerPos);
751template <
class Adaptor>
763 auto const& newPeerProp = newPeerPos.proposal();
767 JLOG(
j_.debug()) <<
"Got proposal for " << newPeerProp.prevLedger() <<
" but we are on "
772 auto const& peerID = newPeerProp.nodeID();
776 JLOG(
j_.info()) <<
"Position from dead node: " << peerID;
786 if (newPeerProp.proposeSeq() <= peerPosIt->second.proposal().proposeSeq())
792 if (newPeerProp.isBowOut())
794 JLOG(
j_.info()) <<
"Peer " << peerID <<
" bows out";
797 for (
auto& it :
result_->disputes)
798 it.second.unVote(peerID);
809 peerPosIt->second = newPeerPos;
817 if (newPeerProp.isInitial())
820 JLOG(
j_.trace()) <<
"Peer reports close time as "
821 << newPeerProp.closeTime().time_since_epoch().count();
825 JLOG(
j_.trace()) <<
"Processing peer proposal " << newPeerProp.proposeSeq() <<
"/"
826 << newPeerProp.position();
829 auto const ait =
acquired_.find(newPeerProp.position());
835 if (
auto set =
adaptor_.acquireTxSet(newPeerProp.position()))
841 JLOG(
j_.debug()) <<
"Don't have tx set for peer";
853template <
class Adaptor>
859 CLOG(clog) <<
"Consensus<Adaptor>::timerEntry. ";
863 CLOG(clog) <<
"Nothing to do during accepted phase. ";
868 CLOG(clog) <<
"Set network adjusted time to " <<
to_string(now) <<
". ";
871 auto const phaseOrig =
phase_;
872 CLOG(clog) <<
"Phase " <<
to_string(phaseOrig) <<
". ";
887 CLOG(clog) <<
"timerEntry finishing in phase " <<
to_string(
phase_) <<
". ";
890template <
class Adaptor>
900 auto id = txSet.id();
904 if (!
acquired_.emplace(
id, txSet).second)
909 JLOG(
j_.debug()) <<
"Not creating disputes: no position yet.";
916 id !=
result_->position.position(),
917 "xrpl::Consensus::gotTxSet : updated transaction set");
921 if (peerPos.proposal().position() ==
id)
930 JLOG(
j_.warn()) <<
"By the time we got " <<
id <<
" no peers were proposing it";
935template <
class Adaptor>
941 using namespace std::chrono_literals;
942 JLOG(
j_.info()) <<
"Simulating consensus";
953 JLOG(
j_.info()) <<
"Simulation complete";
956template <
class Adaptor>
970 ret[
"synched"] =
true;
976 ret[
"synched"] =
false;
982 ret[
"disputes"] =
static_cast<Int
>(
result_->disputes.size());
985 ret[
"our_position"] =
result_->position.getJson();
990 ret[
"current_ms"] =
static_cast<Int
>(
result_->roundTime.read().count());
995 ret[
"previous_mseconds"] =
static_cast<Int
>(
prevRoundTime_.count());
1003 ppj[
to_string(nodeId)] = peerPos.getJson();
1005 ret[
"peer_positions"] = std::move(ppj);
1015 ret[
"acquired"] = std::move(acq);
1021 for (
auto const& [txId, dispute] :
result_->disputes)
1023 dsj[
to_string(txId)] = dispute.getJson();
1025 ret[
"disputes"] = std::move(dsj);
1033 ctj[
std::to_string(ct.first.time_since_epoch().count())] = ct.second;
1035 ret[
"close_times"] = std::move(ctj);
1045 ret[
"dead_nodes"] = std::move(dnj);
1053template <
class Adaptor>
1056 Ledger_t::ID
const& lgrId,
1059 CLOG(clog) <<
"handleWrongLedger. ";
1062 "xrpl::Consensus::handleWrongLedger : have wrong ledger");
1089 CLOG(clog) <<
"previousLedger_.id() == prevLeverID_ " <<
prevLedgerID_ <<
". ";
1097 CLOG(clog) <<
"Have the consensus ledger " <<
prevLedgerID_ <<
". ";
1102 CLOG(clog) <<
"Still on wrong ledger. ";
1107template <
class Adaptor>
1111 CLOG(clog) <<
"checkLedger. ";
1114 CLOG(clog) <<
"network ledgerid " << netLgr <<
", "
1123 JLOG(
j_.warn()) << ss.
str();
1124 CLOG(clog) << ss.
str();
1130 CLOG(clog) <<
"previousLedger_.id() != prevLedgerID_: " <<
previousLedger_.id() <<
','
1136template <
class Adaptor>
1142 for (
auto const& pos : it.second)
1153template <
class Adaptor>
1157 CLOG(clog) <<
"phaseOpen. ";
1161 bool const anyTransactions =
adaptor_.hasOpenTransactions();
1170 auto const mode =
mode_.get();
1173 auto const prevParentCloseTimePlus1 =
previousLedger_.parentCloseTime() + 1s;
1175 (prevCloseTime != prevParentCloseTimePlus1);
1177 auto const lastCloseTime = previousCloseCorrect
1181 if (
now_ >= lastCloseTime)
1189 CLOG(
clog) <<
"calculating how long since last ledger's close time "
1191 <<
to_string(mode) <<
", previous closeAgree: " << closeAgree
1192 <<
", previous close time: " <<
to_string(prevCloseTime)
1193 <<
", previous parent close time + 1s: " <<
to_string(prevParentCloseTimePlus1)
1195 <<
", last close time: " <<
to_string(lastCloseTime)
1196 <<
", since close: " << sinceClose.
count() <<
". ";
1201 CLOG(
clog) <<
"idle interval set to " << idleInterval.
count() <<
"ms based on "
1202 <<
"ledgerIDLE_INTERVAL: " <<
adaptor_.parms().ledgerIdleInterval.count()
1203 <<
", previous ledger close time resolution: "
1220 CLOG(
clog) <<
"closing ledger. ";
1225template <
class Adaptor>
1229 CLOG(
clog) <<
"shouldPause? ";
1230 auto const& parms =
adaptor_.parms();
1233 auto [quorum, trustedKeys] =
adaptor_.getQuorumKeys();
1234 std::size_t const totalValidators = trustedKeys.size();
1239 vars <<
" consensuslog (working seq: " <<
previousLedger_.seq() <<
", "
1240 <<
"validated seq: " <<
adaptor_.getValidLedgerIndex() <<
", "
1241 <<
"am validator: " <<
adaptor_.validator() <<
", "
1242 <<
"have validated: " <<
adaptor_.haveValidated()
1246 <<
"roundTime: " <<
result_->roundTime.read().count()
1249 <<
"max consensus time: " << parms.ledgerMaxConsensus.count() <<
", "
1250 <<
"validators: " << totalValidators <<
", "
1251 <<
"laggards: " << laggards <<
", "
1252 <<
"offline: " << offline <<
", "
1253 <<
"quorum: " << quorum <<
")";
1255 if ((ahead == 0u) || (laggards == 0u) || (totalValidators == 0u) || !
adaptor_.validator() ||
1258 result_->roundTime.read() > parms.ledgerMaxConsensus)
1260 j_.debug() <<
"not pausing (early)" << vars.
str();
1261 CLOG(
clog) <<
"Not pausing (early). ";
1265 bool willPause =
false;
1311 if (laggards + offline > totalValidators - quorum)
1314 case kMaxPausePhase:
1326 float const nonLaggards = totalValidators - (laggards + offline);
1327 float const quorumRatio =
static_cast<float>(quorum) / totalValidators;
1328 float const allowedDissent = 1.0f - quorumRatio;
1329 float const phaseFactor =
static_cast<float>(
phase) / kMaxPausePhase;
1331 if (nonLaggards / totalValidators < quorumRatio + (allowedDissent * phaseFactor))
1339 j_.warn() <<
"pausing" << vars.
str();
1340 CLOG(
clog) <<
"pausing " << vars.
str() <<
". ";
1344 j_.debug() <<
"not pausing" << vars.
str();
1345 CLOG(
clog) <<
"not pausing. ";
1350template <
class Adaptor>
1354 CLOG(
clog) <<
"phaseEstablish. ";
1356 XRPL_ASSERT(
result_,
"xrpl::Consensus::phaseEstablish : result is set");
1371 <<
" is based on round duration so far: " <<
result_->roundTime.read().count()
1373 <<
"previous round duration: " <<
prevRoundTime_.count() <<
"ms, "
1392 JLOG(
j_.info()) <<
"We have TX consensus but not CT consensus";
1393 CLOG(
clog) <<
"We have TX consensus but not CT consensus. ";
1399 <<
" participants). Transitioned to ConsensusPhase::Accepted. ";
1404 JLOG(
j_.debug()) <<
"transitioned to ConsensusPhase::Accepted";
1416template <
class Adaptor>
1421 XRPL_ASSERT(!
result_,
"xrpl::Consensus::closeLedger : result is not set");
1424 JLOG(
j_.debug()) <<
"transitioned to ConsensusPhase::Establish";
1436 auto const mode =
mode_.get();
1437 CLOG(
clog) <<
"closeLedger transitioned to ConsensusPhase::Establish, mode: " <<
to_string(mode)
1445 auto const& pos = pit.second.proposal().position();
1468 int const result = ((participants * percent) + (percent / 2)) / 100;
1470 return (result == 0) ? 1 : result;
1473template <
class Adaptor>
1478 XRPL_ASSERT(
result_,
"xrpl::Consensus::updateOurPositions : result is set");
1485 CLOG(
clog) <<
"updateOurPositions. peerCutoff " <<
to_string(peerCutoff) <<
", ourCutoff "
1494 Proposal_t const& peerProp = it->second.proposal();
1495 if (peerProp.
isStale(peerCutoff))
1499 JLOG(
j_.warn()) <<
"Removing stale proposal from " << peerID;
1500 for (
auto& dt :
result_->disputes)
1501 dt.second.unVote(peerID);
1519 for (
auto& [txId, dispute] :
result_->disputes)
1523 if (dispute.updateVote(
1529 if (dispute.getOurVote())
1532 mutableSet->insert(dispute.tx());
1537 mutableSet->erase(txId);
1543 ourNewSet.
emplace(std::move(*mutableSet));
1558 auto const [neededWeight, newState] =
1562 CLOG(
clog) <<
"neededWeight " << neededWeight <<
". ";
1579 <<
" thrV:" << threshVote <<
" thrC:" << threshConsensus;
1580 JLOG(
j_.info()) << ss.
str();
1589 for (
auto const& [t, v] : std::views::reverse(closeTimeVotes))
1591 JLOG(
j_.debug()) <<
"CCTime: seq "
1593 << t.time_since_epoch().count() <<
" has " << v <<
", " << threshVote
1596 if (v >= threshVote)
1599 consensusCloseTime = t;
1602 if (threshVote >= threshConsensus)
1609 JLOG(
j_.debug()) <<
"No CT consensus:"
1611 <<
" Mode:" <<
to_string(
mode_.get()) <<
" Thresh:" << threshConsensus
1613 CLOG(
clog) <<
"No close time consensus. ";
1619 result_->position.isStale(ourCutoff)))
1627 auto newID = ourNewSet->id();
1629 result_->txns = std::move(*ourNewSet);
1632 ss <<
"Position change: CTime " << consensusCloseTime.
time_since_epoch().count() <<
", tx "
1634 JLOG(
j_.info()) << ss.
str();
1637 result_->position.changePosition(newID, consensusCloseTime,
now_);
1643 if (!
result_->position.isBowOut())
1661template <
class Adaptor>
1666 XRPL_ASSERT(
result_,
"xrpl::Consensus::haveConsensus : has result");
1670 int agree = 0, disagree = 0;
1672 auto ourPosition =
result_->position.position();
1677 Proposal_t const& peerProp = peerPos.proposal();
1678 if (peerProp.
position() == ourPosition)
1684 JLOG(
j_.debug()) <<
"Proposal disagreement: Peer " << nodeId <<
" has "
1691 JLOG(
j_.debug()) <<
"Checking for TX consensus: agree=" << agree <<
", disagree=" << disagree;
1697 bool const stalled =
1700 return dispute.second.stalled(
1701 parms, mode_.get() == ConsensusMode::Proposing, peerUnchangedCounter_, j_, clog);
1706 ss <<
"Consensus detects as stalled with " << (agree + disagree) <<
"/" <<
prevProposers_
1707 <<
" proposers, and " <<
result_->disputes.size() <<
" stalled disputed transactions.";
1708 JLOG(
j_.error()) << ss.
str();
1728 CLOG(
clog) <<
"No consensus. ";
1747 <<
"; continue until round " << kMinimumCounter <<
". "
1749 JLOG(
j_.error()) << ss.
str();
1750 CLOG(
clog) << ss.
str() <<
". ";
1754 JLOG(
j_.error()) << ss.
str();
1755 CLOG(
clog) << ss.
str() <<
". ";
1762 JLOG(
j_.error()) <<
"Unable to reach consensus";
1767 CLOG(
clog) <<
"Consensus has been reached. ";
1772template <
class Adaptor>
1785 JLOG(
j_.info()) <<
"Bowing out of consensus";
1786 CLOG(
clog) <<
"Bowing out of consensus. ";
1790template <
class Adaptor>
1795 XRPL_ASSERT(
result_,
"xrpl::Consensus::createDisputes : result is set");
1799 auto const emplaced =
result_->compares.emplace(o.id()).second;
1800 CLOG(
clog) <<
"createDisputes: new set? " << !emplaced <<
". ";
1805 if (
result_->txns.id() == o.id())
1807 CLOG(
clog) <<
"both sets are identical. ";
1811 CLOG(
clog) <<
"comparing existing with new set: " <<
result_->txns.id() <<
',' << o.id()
1813 JLOG(
j_.debug()) <<
"createDisputes " <<
result_->txns.id() <<
" to " << o.id();
1815 auto differences =
result_->txns.compare(o);
1819 for (
auto const& [txId, inThisSet] : differences)
1824 (inThisSet &&
result_->txns.find(txId) && !o.find(txId)) ||
1825 (!inThisSet && !
result_->txns.find(txId) && o.find(txId)),
1826 "xrpl::Consensus::createDisputes : has disputed transactions");
1828 Tx_t const tx = inThisSet ?
result_->txns.find(txId) : o.find(txId);
1829 auto txID = tx.id();
1834 JLOG(
j_.debug()) <<
"Transaction " << txID <<
" is disputed";
1845 Proposal_t const& peerProp = peerPos.proposal();
1847 if (cit !=
acquired_.end() && dtx.
setVote(nodeId, cit->second.exists(txID)))
1852 result_->disputes.emplace(txID, std::move(dtx));
1854 JLOG(
j_.debug()) << dc <<
" differences found";
1855 CLOG(
clog) <<
"disputes: " << dc <<
". ";
1859template <
class Adaptor>
1864 XRPL_ASSERT(
result_,
"xrpl::Consensus::updateDisputes : result is set");
1869 if (
result_->compares.find(other.id()) ==
result_->compares.end())
1872 for (
auto& it :
result_->disputes)
1874 auto& d = it.second;
1875 if (d.setVote(node, other.exists(d.tx().id())))
1881template <
class Adaptor>
Abstract interface to a clock.
A generic endpoint for log messages.
Decorator for streaming out compact json.
Value & append(Value const &value)
Append value to array at the end.
Represents a proposed position taken during a round of consensus.
Position const & position() const
Get the proposed position.
NodeId const & nodeID() const
Identifying which peer took this position.
NetClock::time_point const & closeTime() const
The current position on the consensus close time.
bool isStale(NetClock::time_point cutoff) const
Get whether this position is stale relative to the provided cutoff.
Measures the duration of phases of consensus.
ConsensusMode get() const
MonitoredMode(ConsensusMode m)
void set(ConsensusMode mode, Adaptor &a)
bool peerProposalInternal(NetClock::time_point const &now, PeerPosition_t const &newProposal)
Handle a replayed or a new peer proposal.
void updateDisputes(NodeID_t const &node, TxSet_t const &other)
bool haveCloseTimeConsensus_
ConsensusProposal< NodeID_t, typename Ledger_t::ID, typename TxSet_t::ID > Proposal_t
hash_map< NodeID_t, std::deque< PeerPosition_t > > recentPeerPositions_
NetClock::duration closeResolution_
void simulate(NetClock::time_point const &now, std::optional< std::chrono::milliseconds > consensusDelay)
Simulate the consensus process without any network traffic.
void gotTxSet(NetClock::time_point const &now, TxSet_t const &txSet)
Process a transaction set acquired from the network.
bool shouldPause(std::unique_ptr< std::stringstream > const &clog) const
Evaluate whether pausing increases likelihood of validation.
void phaseEstablish(std::unique_ptr< std::stringstream > const &clog)
Handle establish phase.
hash_set< NodeID_t > deadNodes_
Adaptor::Ledger_t Ledger_t
std::size_t peerUnchangedCounter_
void leaveConsensus(std::unique_ptr< std::stringstream > const &clog)
beast::AbstractClock< std::chrono::steady_clock > clock_type
Clock type for measuring time within the consensus code.
NetClock::time_point prevCloseTime_
json::Value getJson(bool full) const
Get the Json state of the consensus process.
Ledger_t::ID prevLedgerID() const
ConsensusResult< Adaptor > Result
hash_map< NodeID_t, PeerPosition_t > currPeerPositions_
std::chrono::milliseconds prevRoundTime_
void checkLedger(std::unique_ptr< std::stringstream > const &clog)
Check if our previous ledger matches the network's.
Consensus(Consensus &&) noexcept=default
void startRound(NetClock::time_point const &now, Ledger_t::ID const &prevLedgerID, Ledger_t prevLedger, hash_set< NodeID_t > const &nowUntrusted, bool proposing, std::unique_ptr< std::stringstream > const &clog={})
NetClock::time_point asCloseTime(NetClock::time_point raw) const
ConsensusParms::AvalancheState closeTimeAvalancheState_
ConsensusPhase phase() const
Adaptor::PeerPosition_t PeerPosition_t
void playbackProposals()
If we radically changed our consensus context for some reason, we need to replay recent proposals so ...
void handleWrongLedger(Ledger_t::ID const &lgrId, std::unique_ptr< std::stringstream > const &clog)
Ledger_t::ID prevLedgerID_
hash_map< typename TxSet_t::ID, TxSet_t const > acquired_
void startRoundInternal(NetClock::time_point const &now, Ledger_t::ID const &prevLedgerID, Ledger_t const &prevLedger, ConsensusMode mode, std::unique_ptr< std::stringstream > const &clog)
void phaseOpen(std::unique_ptr< std::stringstream > const &clog)
Handle pre-close phase.
void closeLedger(std::unique_ptr< std::stringstream > const &clog)
std::size_t prevProposers_
std::size_t establishCounter_
NetClock::time_point now_
clock_type const & clock_
void createDisputes(TxSet_t const &o, std::unique_ptr< std::stringstream > const &clog={})
bool peerProposal(NetClock::time_point const &now, PeerPosition_t const &newProposal)
A peer has proposed a new position, adjust our tracking.
std::optional< Result > result_
void timerEntry(NetClock::time_point const &now, std::unique_ptr< std::stringstream > const &clog={})
Call periodically to drive consensus forward.
bool haveConsensus(std::unique_ptr< std::stringstream > const &clog)
void updateOurPositions(std::unique_ptr< std::stringstream > const &clog)
ConsensusCloseTimes rawCloseTimes_
Adaptor::NodeID_t NodeID_t
bool setVote(NodeId const &peer, bool votesYes)
Change a peer's vote.
Tx const & tx() const
The disputed transaction.
std::chrono::time_point< NetClock > time_point
std::chrono::duration< rep, period > duration
T duration_cast(T... args)
@ Array
array value (ordered list)
@ Object
object value (collection of name/value pairs).
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
ConsensusMode
Represents how a node currently participates in Consensus.
@ WrongLedger
We have the wrong ledger and are attempting to acquire it.
@ SwitchedLedger
We switched ledgers since we started this consensus round but are now running on what we believe is t...
@ Proposing
We are normal participant in consensus and propose our position.
@ Observing
We are observing peer positions, but not proposing our position.
std::unordered_set< Value, Hash, Pred, Allocator > hash_set
std::chrono::duration< Rep, Period > getNextLedgerTimeResolution(std::chrono::duration< Rep, Period > previousResolution, bool previousAgree, Seq ledgerSeq)
Calculates the close time resolution for the specified ledger.
std::string to_string(BaseUInt< Bits, Tag > const &a)
ConsensusState
Whether we have or don't have a consensus.
@ Expired
Consensus time limit has hard-expired.
@ MovedOn
The network has consensus without us.
@ No
We do not have consensus.
std::chrono::time_point< Clock, Duration > roundCloseTime(std::chrono::time_point< Clock, Duration > closeTime, std::chrono::duration< Rep, Period > closeResolution)
Calculates the close time for a ledger, given a close time resolution.
ConsensusPhase
Phases of consensus for a single ledger round.
@ Accepted
We have accepted a new last closed ledger and are waiting on a call to startRound to begin the next c...
@ Establish
Establishing consensus by exchanging proposals with our peers.
@ Open
We haven't closed our ledger yet, but others might have.
json::Value getJson(LedgerFill const &fill)
Return a new json::Value representing the ledger with given options.
int participantsNeeded(int participants, int percent)
How many of the participants must agree to reach a given threshold?
std::unordered_map< Key, Value, Hash, Pred, Allocator > hash_map
std::pair< std::size_t, std::optional< ConsensusParms::AvalancheState > > getNeededWeight(ConsensusParms const &p, ConsensusParms::AvalancheState currentState, int percentTime, std::size_t currentRounds, std::size_t minimumRounds)
ConsensusState checkConsensus(std::size_t prevProposers, std::size_t currentProposers, std::size_t currentAgree, std::size_t currentFinished, std::chrono::milliseconds previousAgreeTime, std::chrono::milliseconds currentAgreeTime, bool stalled, ConsensusParms const &parms, bool proposing, beast::Journal j, std::unique_ptr< std::stringstream > const &clog={})
Determine whether the network reached consensus and whether we joined.
bool shouldCloseLedger(bool anyTransactions, std::size_t prevProposers, std::size_t proposersClosed, std::size_t proposersValidated, std::chrono::milliseconds prevRoundTime, std::chrono::milliseconds timeSincePrevClose, std::chrono::milliseconds openTime, std::chrono::milliseconds idleInterval, ConsensusParms const &parms, beast::Journal j, std::unique_ptr< std::stringstream > const &clog={})
Determines whether the current ledger should close at this time.
constexpr auto kLedgerDefaultTimeResolution
Initial resolution of ledger close time.
constexpr bool any(HashRouterFlags flags)
Stores the set of initial close times.
Consensus algorithm parameters.
std::size_t const avCtConsensusPct
Percentage of nodes required to reach agreement on ledger close time.
std::chrono::milliseconds const ledgerMinConsensus
The number of seconds we wait minimum to ensure participation.
std::size_t const avMinRounds
Number of rounds before certain actions can happen.
std::chrono::seconds const proposeFRESHNESS
How long we consider a proposal fresh.
std::chrono::seconds const proposeINTERVAL
How often we force generating a new proposal to keep ours fresh.
std::map< AvalancheState, AvalancheCutoff > const avalancheCutoffs
Map the consensus requirement avalanche state to the amount of time that must pass before moving to t...
std::chrono::milliseconds const avMinConsensusTime
The minimum amount of time to consider the previous round to have taken.
Encapsulates the result of consensus.
DisputedTx< Tx_t, NodeID_t > Dispute_t
T time_since_epoch(T... args)