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 (
NodeIDT 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 LedgerT::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 ProposalT 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())
1648 ProposalT const& p = peerPos.proposal();
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 ProposalT 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 TxT const tx = inThisSet ?
result_->txns.find(txId) : o.find(txId);
1829 auto txID = tx.id();
1834 JLOG(
j_.debug()) <<
"Transaction " << txID <<
" is disputed";
1845 ProposalT 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 peerProposal(NetClock::time_point const &now, PeerPositionT const &newProposal)
A peer has proposed a new position, adjust our tracking.
bool haveCloseTimeConsensus_
HashMap< typename TxSetT::ID, TxSetT const > acquired_
HashMap< NodeIDT, PeerPositionT > currPeerPositions_
NetClock::duration closeResolution_
void simulate(NetClock::time_point const &now, std::optional< std::chrono::milliseconds > consensusDelay)
Simulate the consensus process without any network traffic.
bool shouldPause(std::unique_ptr< std::stringstream > const &clog) const
Evaluate whether pausing increases likelihood of validation.
Adaptor::PeerPositionT PeerPositionT
void phaseEstablish(std::unique_ptr< std::stringstream > const &clog)
Handle establish phase.
void createDisputes(TxSetT const &o, std::unique_ptr< std::stringstream > const &clog={})
std::size_t peerUnchangedCounter_
void leaveConsensus(std::unique_ptr< std::stringstream > const &clog)
void updateDisputes(NodeIDT const &node, TxSetT const &other)
NetClock::time_point prevCloseTime_
json::Value getJson(bool full) const
Get the Json state of the consensus process.
ConsensusResult< Adaptor > Result
std::chrono::milliseconds prevRoundTime_
void handleWrongLedger(LedgerT::ID const &lgrId, std::unique_ptr< std::stringstream > const &clog)
beast::AbstractClock< std::chrono::steady_clock > ClockType
Clock type for measuring time within the consensus code.
void checkLedger(std::unique_ptr< std::stringstream > const &clog)
Check if our previous ledger matches the network's.
Consensus(Consensus &&) noexcept=default
NetClock::time_point asCloseTime(NetClock::time_point raw) const
bool peerProposalInternal(NetClock::time_point const &now, PeerPositionT const &newProposal)
Handle a replayed or a new peer proposal.
ConsensusParms::AvalancheState closeTimeAvalancheState_
ConsensusPhase phase() const
HashSet< NodeIDT > deadNodes_
HashMap< NodeIDT, std::deque< PeerPositionT > > recentPeerPositions_
void playbackProposals()
If we radically changed our consensus context for some reason, we need to replay recent proposals so ...
void startRound(NetClock::time_point const &now, LedgerT::ID const &prevLedgerID, LedgerT prevLedger, HashSet< NodeIDT > const &nowUntrusted, bool proposing, std::unique_ptr< std::stringstream > const &clog={})
ConsensusProposal< NodeIDT, typename LedgerT::ID, typename TxSetT::ID > ProposalT
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_
LedgerT::ID prevLedgerID_
NetClock::time_point now_
void startRoundInternal(NetClock::time_point const &now, LedgerT::ID const &prevLedgerID, LedgerT const &prevLedger, ConsensusMode mode, std::unique_ptr< std::stringstream > const &clog)
LedgerT::ID prevLedgerID() const
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)
void gotTxSet(NetClock::time_point const &now, TxSetT const &txSet)
Process a transaction set acquired from the network.
ConsensusCloseTimes rawCloseTimes_
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::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.
std::unordered_set< Value, Hash, Pred, Allocator > HashSet
int participantsNeeded(int participants, int percent)
How many of the participants must agree to reach a given threshold?
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.
std::unordered_map< Key, Value, Hash, Pred, Allocator > HashMap
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< TxT, NodeIDT > DisputeT
T time_since_epoch(T... args)