mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Redesign CSF framework (RIPD-1361):
- Separate `Scheduler` from `BasicNetwork`. - Add an event/collector framework for monitoring invariants and calculating statistics. - Allow distinct network and trust connections between Peers. - Add a simple routing strategy to support broadcasting arbitrary messages. - Add a common directed graph (`Digraph`) class for representing network and trust topologies. - Add a `PeerGroup` class for simpler specification of the trust and network topologies. - Add a `LedgerOracle` class to ensure distinct ledger histories and simplify branch checking. - Add a `Submitter` to send transactions in at fixed or random intervals to fixed or random peers. Co-authored-by: Joseph McGee
This commit is contained in:
@@ -126,7 +126,7 @@ RCLConsensus::Adaptor::acquireLedger(LedgerHash const& ledger)
|
||||
|
||||
|
||||
void
|
||||
RCLConsensus::Adaptor::relay(RCLCxPeerPos const& peerPos)
|
||||
RCLConsensus::Adaptor::share(RCLCxPeerPos const& peerPos)
|
||||
{
|
||||
protocol::TMProposeSet prop;
|
||||
|
||||
@@ -150,7 +150,7 @@ RCLConsensus::Adaptor::relay(RCLCxPeerPos const& peerPos)
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::Adaptor::relay(RCLCxTx const& tx)
|
||||
RCLConsensus::Adaptor::share(RCLCxTx const& tx)
|
||||
{
|
||||
// If we didn't relay this transaction recently, relay it to all peers
|
||||
if (app_.getHashRouter().shouldRelay(tx.id()))
|
||||
@@ -204,7 +204,7 @@ RCLConsensus::Adaptor::propose(RCLCxPeerPos::Proposal const& proposal)
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::Adaptor::relay(RCLTxSet const& set)
|
||||
RCLConsensus::Adaptor::share(RCLTxSet const& set)
|
||||
{
|
||||
inboundTransactions_.giveSet(set.id(), set.map_, false);
|
||||
}
|
||||
@@ -254,19 +254,7 @@ RCLConsensus::Adaptor::getPrevLedger(
|
||||
app_.getValidations().currentTrustedDistribution(
|
||||
ledgerID, parentID, ledgerMaster_.getValidLedgerIndex());
|
||||
|
||||
uint256 netLgr = ledgerID;
|
||||
int netLgrCount = 0;
|
||||
for (auto const & it : ledgerCounts)
|
||||
{
|
||||
// Switch to ledger supported by more peers
|
||||
// Or stick with ours on a tie
|
||||
if ((it.second > netLgrCount) ||
|
||||
((it.second == netLgrCount) && (it.first == ledgerID)))
|
||||
{
|
||||
netLgr = it.first;
|
||||
netLgrCount = it.second;
|
||||
}
|
||||
}
|
||||
uint256 netLgr = getPreferredLedger(ledgerID, ledgerCounts);
|
||||
|
||||
if (netLgr != ledgerID)
|
||||
{
|
||||
|
||||
@@ -158,21 +158,21 @@ class RCLConsensus
|
||||
boost::optional<RCLCxLedger>
|
||||
acquireLedger(LedgerHash const& ledger);
|
||||
|
||||
/** Relay the given proposal to all peers
|
||||
/** Share the given proposal with all peers
|
||||
|
||||
@param peerPos The peer position to relay.
|
||||
@param peerPos The peer position to share.
|
||||
*/
|
||||
void
|
||||
relay(RCLCxPeerPos const& peerPos);
|
||||
share(RCLCxPeerPos const& peerPos);
|
||||
|
||||
/** Relay disputed transacction to peers.
|
||||
/** Share disputed transaction to peers.
|
||||
|
||||
Only relay if the provided transaction hasn't been shared recently.
|
||||
Only share if the provided transaction hasn't been shared recently.
|
||||
|
||||
@param tx The disputed transaction to relay.
|
||||
@param tx The disputed transaction to share.
|
||||
*/
|
||||
void
|
||||
relay(RCLCxTx const& tx);
|
||||
share(RCLCxTx const& tx);
|
||||
|
||||
/** Acquire the transaction set associated with a proposal.
|
||||
|
||||
@@ -215,12 +215,12 @@ class RCLConsensus
|
||||
void
|
||||
propose(RCLCxPeerPos::Proposal const& proposal);
|
||||
|
||||
/** Relay the given tx set to peers.
|
||||
/** Share the given tx set to peers.
|
||||
|
||||
@param set The TxSet to share.
|
||||
*/
|
||||
void
|
||||
relay(RCLTxSet const& set);
|
||||
share(RCLTxSet const& set);
|
||||
|
||||
/** Get the ID of the previous ledger/last closed ledger(LCL) on the
|
||||
network
|
||||
|
||||
@@ -37,6 +37,8 @@ class RCLCxLedger
|
||||
public:
|
||||
//! Unique identifier of a ledger
|
||||
using ID = LedgerHash;
|
||||
//! Sequence number of a ledger
|
||||
using Seq = LedgerIndex;
|
||||
|
||||
/** Default constructor
|
||||
|
||||
@@ -55,28 +57,28 @@ public:
|
||||
}
|
||||
|
||||
//! Sequence number of the ledger.
|
||||
auto const&
|
||||
Seq const&
|
||||
seq() const
|
||||
{
|
||||
return ledger_->info().seq;
|
||||
}
|
||||
|
||||
//! Unique identifier (hash) of this ledger.
|
||||
auto const&
|
||||
ID const&
|
||||
id() const
|
||||
{
|
||||
return ledger_->info().hash;
|
||||
}
|
||||
|
||||
//! Unique identifier (hash) of this ledger's parent.
|
||||
auto const&
|
||||
ID const&
|
||||
parentID() const
|
||||
{
|
||||
return ledger_->info().parentHash;
|
||||
}
|
||||
|
||||
//! Resolution used when calculating this ledger's close time.
|
||||
auto
|
||||
NetClock::duration
|
||||
closeTimeResolution() const
|
||||
{
|
||||
return ledger_->info().closeTimeResolution;
|
||||
@@ -90,14 +92,14 @@ public:
|
||||
}
|
||||
|
||||
//! The close time of this ledger
|
||||
auto
|
||||
NetClock::time_point
|
||||
closeTime() const
|
||||
{
|
||||
return ledger_->info().closeTime;
|
||||
}
|
||||
|
||||
//! The close time of this ledger's parent.
|
||||
auto
|
||||
NetClock::time_point
|
||||
parentCloseTime() const
|
||||
{
|
||||
return ledger_->info().parentCloseTime;
|
||||
|
||||
@@ -41,9 +41,18 @@ namespace ripple {
|
||||
allowed arithmetic operations.
|
||||
*/
|
||||
template <class Int, class Tag>
|
||||
class tagged_integer : boost::operators<tagged_integer<Int, Tag>>
|
||||
, boost::shiftable<tagged_integer<Int, Tag>>
|
||||
class tagged_integer
|
||||
: boost::totally_ordered<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::integer_arithmetic<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::bitwise<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::unit_steppable<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::shiftable<tagged_integer<Int, Tag>>>>>>
|
||||
{
|
||||
|
||||
private:
|
||||
Int m_value;
|
||||
|
||||
@@ -63,6 +72,9 @@ public:
|
||||
tagged_integer(OtherInt value) noexcept
|
||||
: m_value(value)
|
||||
{
|
||||
static_assert(
|
||||
sizeof(tagged_integer) == sizeof(Int),
|
||||
"tagged_integer is adding padding");
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -176,10 +176,11 @@ checkConsensus(
|
||||
struct Ledger
|
||||
{
|
||||
using ID = ...;
|
||||
using Seq = ...;
|
||||
|
||||
// Unique identifier of ledgerr
|
||||
ID const id() const;
|
||||
auto seq() const;
|
||||
Seq seq() const;
|
||||
auto closeTimeResolution() const;
|
||||
auto closeAgree() const;
|
||||
auto closeTime() const;
|
||||
@@ -257,14 +258,14 @@ checkConsensus(
|
||||
// Propose the position to peers.
|
||||
void propose(ConsensusProposal<...> const & pos);
|
||||
|
||||
// Relay a received peer proposal on to other peer's.
|
||||
void relay(PeerPosition_t const & prop);
|
||||
// Share a received peer proposal with other peer's.
|
||||
void share(PeerPosition_t const & prop);
|
||||
|
||||
// Relay a disputed transaction to peers
|
||||
void relay(Txn const & tx);
|
||||
// Share a disputed transaction with peers
|
||||
void share(Txn const & tx);
|
||||
|
||||
// Share given transaction set with peers
|
||||
void relay(TxSet const &s);
|
||||
void share(TxSet const &s);
|
||||
|
||||
// Consensus timing parameters and constants
|
||||
ConsensusParms const &
|
||||
@@ -642,7 +643,7 @@ Consensus<Adaptor>::startRoundInternal(
|
||||
closeResolution_ = getNextLedgerTimeResolution(
|
||||
previousLedger_.closeTimeResolution(),
|
||||
previousLedger_.closeAgree(),
|
||||
previousLedger_.seq() + 1);
|
||||
previousLedger_.seq() + typename Ledger_t::Seq{1});
|
||||
|
||||
playbackProposals();
|
||||
if (currPeerPositions_.size() > (prevProposers_ / 2))
|
||||
@@ -878,7 +879,7 @@ Consensus<Adaptor>::getJson(bool full) const
|
||||
if (mode_.get() != ConsensusMode::wrongLedger)
|
||||
{
|
||||
ret["synched"] = true;
|
||||
ret["ledger_seq"] = previousLedger_.seq() + 1;
|
||||
ret["ledger_seq"] = static_cast<std::uint32_t>(previousLedger_.seq())+ 1;
|
||||
ret["close_granularity"] = static_cast<Int>(closeResolution_.count());
|
||||
}
|
||||
else
|
||||
@@ -1038,7 +1039,7 @@ Consensus<Adaptor>::playbackProposals()
|
||||
if (pos.proposal().prevLedger() == prevLedgerID_)
|
||||
{
|
||||
if (peerProposalInternal(now_, pos))
|
||||
adaptor_.relay(pos);
|
||||
adaptor_.share(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1158,7 +1159,7 @@ Consensus<Adaptor>::closeLedger()
|
||||
// Share the newly created transaction set if we haven't already
|
||||
// received it from a peer
|
||||
if (acquired_.emplace(result_->set.id(), result_->set).second)
|
||||
adaptor_.relay(result_->set);
|
||||
adaptor_.share(result_->set);
|
||||
|
||||
if (mode_.get() == ConsensusMode::proposing)
|
||||
adaptor_.propose(result_->position);
|
||||
@@ -1264,7 +1265,7 @@ Consensus<Adaptor>::updateOurPositions()
|
||||
}
|
||||
|
||||
if (mutableSet)
|
||||
ourNewSet.emplace(*mutableSet);
|
||||
ourNewSet.emplace(std::move(*mutableSet));
|
||||
}
|
||||
|
||||
NetClock::time_point consensusCloseTime = {};
|
||||
@@ -1310,7 +1311,8 @@ Consensus<Adaptor>::updateOurPositions()
|
||||
for (auto const& it : closeTimeVotes)
|
||||
{
|
||||
JLOG(j_.debug())
|
||||
<< "CCTime: seq " << previousLedger_.seq() + 1 << ": "
|
||||
<< "CCTime: seq "
|
||||
<< static_cast<std::uint32_t>(previousLedger_.seq()) + 1 << ": "
|
||||
<< it.first.time_since_epoch().count() << " has " << it.second
|
||||
<< ", " << threshVote << " required";
|
||||
|
||||
@@ -1361,7 +1363,7 @@ Consensus<Adaptor>::updateOurPositions()
|
||||
if (acquired_.emplace(newID, result_->set).second)
|
||||
{
|
||||
if (!result_->position.isBowOut())
|
||||
adaptor_.relay(result_->set);
|
||||
adaptor_.share(result_->set);
|
||||
|
||||
for (auto const& it : currPeerPositions_)
|
||||
{
|
||||
@@ -1493,7 +1495,8 @@ Consensus<Adaptor>::createDisputes(TxSet_t const& o)
|
||||
|
||||
JLOG(j_.debug()) << "Transaction " << txID << " is disputed";
|
||||
|
||||
typename Result::Dispute_t dtx{tx, result_->set.exists(txID), j_};
|
||||
typename Result::Dispute_t dtx{tx, result_->set.exists(txID),
|
||||
std::max(prevProposers_, currPeerPositions_.size()), j_};
|
||||
|
||||
// Update all of the available peer's votes on the disputed transaction
|
||||
for (auto const& pit : currPeerPositions_)
|
||||
@@ -1503,7 +1506,7 @@ Consensus<Adaptor>::createDisputes(TxSet_t const& o)
|
||||
if (cit != acquired_.end())
|
||||
dtx.setVote(pit.first, cit->second.exists(txID));
|
||||
}
|
||||
adaptor_.relay(dtx.tx());
|
||||
adaptor_.share(dtx.tx());
|
||||
|
||||
result_->disputes.emplace(txID, std::move(dtx));
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#ifndef RIPPLE_APP_CONSENSUS_IMPL_DISPUTEDTX_H_INCLUDED
|
||||
#define RIPPLE_APP_CONSENSUS_IMPL_DISPUTEDTX_H_INCLUDED
|
||||
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/base_uint.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
@@ -48,17 +49,19 @@ template <class Tx_t, class NodeID_t>
|
||||
class DisputedTx
|
||||
{
|
||||
using TxID_t = typename Tx_t::ID;
|
||||
|
||||
using Map_t = boost::container::flat_map<NodeID_t, bool>;
|
||||
public:
|
||||
/** Constructor
|
||||
|
||||
@param tx The transaction under dispute
|
||||
@param ourVote Our vote on whether tx should be included
|
||||
@param numPeers Anticipated number of peer votes
|
||||
@param j Journal for debugging
|
||||
*/
|
||||
DisputedTx(Tx_t const& tx, bool ourVote, beast::Journal j)
|
||||
DisputedTx(Tx_t const& tx, bool ourVote, std::size_t numPeers, beast::Journal j)
|
||||
: yays_(0), nays_(0), ourVote_(ourVote), tx_(tx), j_(j)
|
||||
{
|
||||
votes_.reserve(numPeers);
|
||||
}
|
||||
|
||||
//! The unique id/hash of the disputed transaction.
|
||||
@@ -127,9 +130,8 @@ private:
|
||||
int nays_; //< Number of no votes
|
||||
bool ourVote_; //< Our vote (true is yes)
|
||||
Tx_t tx_; //< Transaction under dispute
|
||||
|
||||
hash_map<NodeID_t, bool> votes_; //< Votes of our peers
|
||||
beast::Journal j_; //< Debug journal
|
||||
Map_t votes_; //< Map from NodeID to vote
|
||||
beast::Journal j_;
|
||||
};
|
||||
|
||||
// Track a peer's yes/no vote on a particular disputed tx_
|
||||
|
||||
@@ -46,7 +46,6 @@ auto constexpr increaseLedgerTimeResolutionEvery = 8;
|
||||
//! How often we decrease the close time resolution (in numbers of ledgers)
|
||||
auto constexpr decreaseLedgerTimeResolutionEvery = 1;
|
||||
|
||||
|
||||
/** Calculates the close time resolution for the specified ledger.
|
||||
|
||||
The Ripple protocol uses binning to represent time intervals using only one
|
||||
@@ -62,15 +61,22 @@ auto constexpr decreaseLedgerTimeResolutionEvery = 1;
|
||||
|
||||
@pre previousResolution must be a valid bin
|
||||
from @ref ledgerPossibleTimeResolutions
|
||||
|
||||
@tparam Rep Type representing number of ticks in std::chrono::duration
|
||||
@tparam Period An std::ratio representing tick period in
|
||||
std::chrono::duration
|
||||
@tparam Seq Unsigned integer-like type corresponding to the ledger sequence
|
||||
number. It should be comparable to 0 and support modular
|
||||
division. Built-in and tagged_integers are supported.
|
||||
*/
|
||||
template <class duration>
|
||||
duration
|
||||
template <class Rep, class Period, class Seq>
|
||||
std::chrono::duration<Rep, Period>
|
||||
getNextLedgerTimeResolution(
|
||||
duration previousResolution,
|
||||
std::chrono::duration<Rep, Period> previousResolution,
|
||||
bool previousAgree,
|
||||
std::uint32_t ledgerSeq)
|
||||
Seq ledgerSeq)
|
||||
{
|
||||
assert(ledgerSeq);
|
||||
assert(ledgerSeq != Seq{0});
|
||||
|
||||
using namespace std::chrono;
|
||||
// Find the current resolution:
|
||||
@@ -86,7 +92,8 @@ getNextLedgerTimeResolution(
|
||||
|
||||
// If we did not previously agree, we try to decrease the resolution to
|
||||
// improve the chance that we will agree now.
|
||||
if (!previousAgree && ledgerSeq % decreaseLedgerTimeResolutionEvery == 0)
|
||||
if (!previousAgree &&
|
||||
(ledgerSeq % Seq{decreaseLedgerTimeResolutionEvery} == Seq{0}))
|
||||
{
|
||||
if (++iter != std::end(ledgerPossibleTimeResolutions))
|
||||
return *iter;
|
||||
@@ -94,7 +101,8 @@ getNextLedgerTimeResolution(
|
||||
|
||||
// If we previously agreed, we try to increase the resolution to determine
|
||||
// if we can continue to agree.
|
||||
if (previousAgree && ledgerSeq % increaseLedgerTimeResolutionEvery == 0)
|
||||
if (previousAgree &&
|
||||
(ledgerSeq % Seq{increaseLedgerTimeResolutionEvery} == Seq{0}))
|
||||
{
|
||||
if (iter-- != std::begin(ledgerPossibleTimeResolutions))
|
||||
return *iter;
|
||||
@@ -110,12 +118,13 @@ getNextLedgerTimeResolution(
|
||||
@return @b closeTime rounded to the nearest multiple of @b closeResolution.
|
||||
Rounds up if @b closeTime is midway between multiples of @b closeResolution.
|
||||
*/
|
||||
template <class time_point>
|
||||
time_point
|
||||
template <class Clock, class Duration, class Rep, class Period>
|
||||
std::chrono::time_point<Clock, Duration>
|
||||
roundCloseTime(
|
||||
time_point closeTime,
|
||||
typename time_point::duration closeResolution)
|
||||
std::chrono::time_point<Clock, Duration> closeTime,
|
||||
std::chrono::duration<Rep, Period> closeResolution)
|
||||
{
|
||||
using time_point = decltype(closeTime);
|
||||
if (closeTime == time_point{})
|
||||
return closeTime;
|
||||
|
||||
@@ -132,14 +141,15 @@ roundCloseTime(
|
||||
@param resolution The current close time resolution
|
||||
@param priorCloseTime The close time of the prior ledger
|
||||
*/
|
||||
template <class time_point>
|
||||
time_point
|
||||
template <class Clock, class Duration, class Rep, class Period>
|
||||
std::chrono::time_point<Clock, Duration>
|
||||
effCloseTime(
|
||||
time_point closeTime,
|
||||
typename time_point::duration const resolution,
|
||||
time_point priorCloseTime)
|
||||
std::chrono::time_point<Clock, Duration> closeTime,
|
||||
std::chrono::duration<Rep, Period> resolution,
|
||||
std::chrono::time_point<Clock, Duration> priorCloseTime)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
using time_point = decltype(closeTime);
|
||||
|
||||
if (closeTime == time_point{})
|
||||
return closeTime;
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <ripple/beast/container/aged_container_utility.h>
|
||||
#include <ripple/beast/container/aged_unordered_map.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/beast/utility/Zero.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
@@ -74,6 +73,7 @@ struct ValidationParms
|
||||
std::chrono::seconds validationSET_EXPIRES = std::chrono::minutes{10};
|
||||
};
|
||||
|
||||
|
||||
/** Whether a validation is still current
|
||||
|
||||
Determines whether a validation can still be considered the current
|
||||
@@ -103,6 +103,37 @@ isCurrent(
|
||||
(seenTime < (now + p.validationCURRENT_LOCAL)));
|
||||
}
|
||||
|
||||
/** Determine the preferred ledger based on its support
|
||||
|
||||
@param current The current ledger the node follows
|
||||
@param dist Ledger IDs and corresponding counts of support
|
||||
@return The ID of the ledger with most support, preferring to stick with
|
||||
current ledger in the case of equal support
|
||||
*/
|
||||
template <class LedgerID>
|
||||
inline LedgerID
|
||||
getPreferredLedger(
|
||||
LedgerID const& current,
|
||||
hash_map<LedgerID, std::uint32_t> const& dist)
|
||||
{
|
||||
LedgerID netLgr = current;
|
||||
int netLgrCount = 0;
|
||||
for (auto const& it : dist)
|
||||
{
|
||||
// Switch to ledger supported by more peers
|
||||
// On a tie, prefer the current ledger, or the one with higher ID
|
||||
if ((it.second > netLgrCount) ||
|
||||
((it.second == netLgrCount) &&
|
||||
((it.first == current) ||
|
||||
(it.first > netLgr && netLgr != current))))
|
||||
{
|
||||
netLgr = it.first;
|
||||
netLgrCount = it.second;
|
||||
}
|
||||
}
|
||||
return netLgr;
|
||||
}
|
||||
|
||||
/** Maintains current and recent ledger validations.
|
||||
|
||||
Manages storage and queries related to validations received on the network.
|
||||
@@ -192,6 +223,7 @@ class Validations
|
||||
decay_result_t<decltype (&Validation::ledgerID)(Validation)>;
|
||||
using NodeKey = decay_result_t<decltype (&Validation::key)(Validation)>;
|
||||
using NodeID = decay_result_t<decltype (&Validation::nodeID)(Validation)>;
|
||||
using SeqType = decay_result_t<decltype (&Validation::seq)(Validation)>;
|
||||
|
||||
|
||||
using ScopedLock = std::lock_guard<MutexType>;
|
||||
@@ -397,11 +429,12 @@ public:
|
||||
Validation& oldVal = ins.first->second.val;
|
||||
LedgerID const previousLedgerID = ins.first->second.prevLedgerID;
|
||||
|
||||
std::uint32_t const oldSeq{oldVal.seq()};
|
||||
std::uint32_t const newSeq{val.seq()};
|
||||
SeqType const oldSeq{oldVal.seq()};
|
||||
SeqType const newSeq{val.seq()};
|
||||
|
||||
// Sequence of 0 indicates a missing sequence number
|
||||
if (oldSeq && newSeq && oldSeq == newSeq)
|
||||
if ((oldSeq != SeqType{0}) && (newSeq != SeqType{0}) &&
|
||||
oldSeq == newSeq)
|
||||
{
|
||||
result = AddOutcome::sameSeq;
|
||||
|
||||
@@ -491,7 +524,9 @@ public:
|
||||
ledgers one away from the current ledger to count as the current.
|
||||
|
||||
@param currentLedger The identifier of the ledger we believe is current
|
||||
(0 if unknown)
|
||||
@param priorLedger The identifier of our previous current ledger
|
||||
(0 if unknown)
|
||||
@param cutoffBefore Ignore ledgers with sequence number before this
|
||||
|
||||
@return Map representing the distribution of ledgerID by count
|
||||
@@ -500,10 +535,10 @@ public:
|
||||
currentTrustedDistribution(
|
||||
LedgerID const& currentLedger,
|
||||
LedgerID const& priorLedger,
|
||||
std::uint32_t cutoffBefore)
|
||||
SeqType cutoffBefore)
|
||||
{
|
||||
bool const valCurrentLedger = currentLedger != beast::zero;
|
||||
bool const valPriorLedger = priorLedger != beast::zero;
|
||||
bool const valCurrentLedger = currentLedger != LedgerID{0};
|
||||
bool const valPriorLedger = priorLedger != LedgerID{0};
|
||||
|
||||
hash_map<LedgerID, std::uint32_t> ret;
|
||||
|
||||
@@ -524,8 +559,8 @@ public:
|
||||
if (!v.trusted())
|
||||
return;
|
||||
|
||||
std::uint32_t const seq = v.seq();
|
||||
if ((seq == 0) || (seq >= cutoffBefore))
|
||||
SeqType const seq = v.seq();
|
||||
if ((seq == SeqType{0}) || (seq >= cutoffBefore))
|
||||
{
|
||||
// contains a live record
|
||||
bool countPreferred =
|
||||
|
||||
Reference in New Issue
Block a user