Use LedgerTrie for preferred ledger (RIPD-1551):

These changes augment the Validations class with a LedgerTrie to better
track the history of support for validated ledgers. This improves the
selection of the preferred working ledger for consensus. The Validations
class now tracks both full and partial validations. Partial validations
are only used to determine the working ledger; full validations are
required for any quorum related function. Validators are also now
explicitly restricted to sending validations with increasing ledger
sequence number.
This commit is contained in:
Brad Chase
2017-12-07 11:00:42 -05:00
parent 1c44c4a43e
commit 94c6a2a850
26 changed files with 3648 additions and 1043 deletions

View File

@@ -1273,84 +1273,39 @@ bool NetworkOPsImp::checkLastClosedLedger (
JLOG(m_journal.trace()) << "OurClosed: " << closedLedger;
JLOG(m_journal.trace()) << "PrevClosed: " << prevClosedLedger;
struct ValidationCount
{
std::uint32_t trustedValidations = 0;
std::uint32_t nodesUsing = 0;
};
//-------------------------------------------------------------------------
// Determine preferred last closed ledger
hash_map<uint256, ValidationCount> ledgers;
{
hash_map<uint256, std::uint32_t> current =
app_.getValidations().currentTrustedDistribution(
closedLedger,
prevClosedLedger,
m_ledgerMaster.getValidLedgerIndex());
for (auto& it: current)
ledgers[it.first].trustedValidations += it.second;
}
auto& ourVC = ledgers[closedLedger];
auto & validations = app_.getValidations();
JLOG(m_journal.debug())
<< "ValidationTrie " << Json::Compact(validations.getJsonTrie());
// Will rely on peer LCL if no trusted validations exist
hash_map<uint256, std::uint32_t> peerCounts;
peerCounts[closedLedger] = 0;
if (mMode >= omTRACKING)
peerCounts[closedLedger]++;
for (auto& peer : peerList)
{
++ourVC.nodesUsing;
uint256 peerLedger = peer->getClosedLedgerHash();
if (peerLedger.isNonZero())
++peerCounts[peerLedger];
}
for (auto& peer: peerList)
{
uint256 peerLedger = peer->getClosedLedgerHash ();
for(auto const & it: peerCounts)
JLOG(m_journal.debug()) << "L: " << it.first << " n=" << it.second;
if (peerLedger.isNonZero ())
++ledgers[peerLedger].nodesUsing;
}
// 3) Is there a network ledger we'd like to switch to? If so, do we have
// it?
bool switchLedgers = false;
ValidationCount bestCounts = ledgers[closedLedger];
for (auto const& it: ledgers)
{
uint256 const & currLedger = it.first;
ValidationCount const & currCounts = it.second;
JLOG(m_journal.debug()) << "L: " << currLedger
<< " t=" << currCounts.trustedValidations
<< ", n=" << currCounts.nodesUsing;
bool const preferCurr = [&]()
{
// Prefer ledger with more trustedValidations
if (currCounts.trustedValidations > bestCounts.trustedValidations)
return true;
if (currCounts.trustedValidations < bestCounts.trustedValidations)
return false;
// If neither are trusted, prefer more nodesUsing
if (currCounts.trustedValidations == 0)
{
if (currCounts.nodesUsing > bestCounts.nodesUsing)
return true;
if (currCounts.nodesUsing < bestCounts.nodesUsing)
return false;
}
// If tied trustedValidations (non-zero) or tied nodesUsing,
// prefer higher ledger hash
return currLedger > closedLedger;
}();
// Switch to current ledger if it is preferred over best so far
if (preferCurr)
{
bestCounts = currCounts;
closedLedger = currLedger;
switchLedgers = true;
}
}
uint256 preferredLCL = validations.getPreferredLCL(
RCLValidatedLedger{ourClosed, validations.adaptor().journal()},
m_ledgerMaster.getValidLedgerIndex(),
peerCounts);
bool switchLedgers = preferredLCL != closedLedger;
if(switchLedgers)
closedLedger = preferredLCL;
//-------------------------------------------------------------------------
if (switchLedgers && (closedLedger == prevClosedLedger))
{
// don't switch to our own previous ledger
@@ -1364,15 +1319,15 @@ bool NetworkOPsImp::checkLastClosedLedger (
if (!switchLedgers)
return false;
auto consensus = m_ledgerMaster.getLedgerByHash (closedLedger);
auto consensus = m_ledgerMaster.getLedgerByHash(closedLedger);
if (!consensus)
consensus = app_.getInboundLedgers().acquire (
consensus = app_.getInboundLedgers().acquire(
closedLedger, 0, InboundLedger::Reason::CONSENSUS);
if (consensus &&
! m_ledgerMaster.isCompatible (*consensus, m_journal.debug(),
"Not switching"))
!m_ledgerMaster.isCompatible(
*consensus, m_journal.debug(), "Not switching"))
{
// Don't switch to a ledger not on the validated chain
networkClosed = ourClosed->info().hash;
@@ -1380,18 +1335,18 @@ bool NetworkOPsImp::checkLastClosedLedger (
}
JLOG(m_journal.warn()) << "We are not running on the consensus ledger";
JLOG(m_journal.info()) << "Our LCL: " << getJson (*ourClosed);
JLOG(m_journal.info()) << "Our LCL: " << getJson(*ourClosed);
JLOG(m_journal.info()) << "Net LCL " << closedLedger;
if ((mMode == omTRACKING) || (mMode == omFULL))
setMode (omCONNECTED);
setMode(omCONNECTED);
if (consensus)
{
// FIXME: If this rewinds the ledger sequence, or has the same sequence, we
// should update the status on any stored transactions in the invalidated
// ledgers.
switchLastClosedLedger (consensus);
// FIXME: If this rewinds the ledger sequence, or has the same
// sequence, we should update the status on any stored transactions
// in the invalidated ledgers.
switchLastClosedLedger(consensus);
}
return true;