diff --git a/src/ripple/app/ledger/impl/LedgerConsensusImp.cpp b/src/ripple/app/ledger/impl/LedgerConsensusImp.cpp index e399fcc31..f263ddf4c 100644 --- a/src/ripple/app/ledger/impl/LedgerConsensusImp.cpp +++ b/src/ripple/app/ledger/impl/LedgerConsensusImp.cpp @@ -600,6 +600,7 @@ void LedgerConsensusImp::checkLCL () for (auto& it : vals) j_.debug << "V: " << it.first << ", " << it.second.first; + j_.debug << getJson (true); } if (mHaveCorrectLCL) @@ -741,31 +742,26 @@ void LedgerConsensusImp::statePreClose () // This ledger is open. This computes how long since last ledger closed int sinceClose; - int idleInterval = 0; - - if (mHaveCorrectLCL && getCloseAgree(mPreviousLedger->info())) { - // we can use consensus timing - sinceClose = 1000 * ( - app_.timeKeeper().closeTime().time_since_epoch().count() - - mPreviousLedger->info().closeTime); - idleInterval = 2 * mPreviousLedger->info().closeTimeResolution; + bool previousCloseCorrect = mHaveCorrectLCL + && getCloseAgree (mPreviousLedger->info()) + && (mPreviousLedger->info().closeTime != + (mPreviousLedger->info().parentCloseTime + 1)); - if (idleInterval < LEDGER_IDLE_INTERVAL) - idleInterval = LEDGER_IDLE_INTERVAL; - } - else - { - // Use the time we saw the last ledger close - sinceClose = 1000 * ( - app_.timeKeeper().closeTime().time_since_epoch().count() - - consensus_.getLastCloseTime ()); - idleInterval = LEDGER_IDLE_INTERVAL; + auto closeTime = previousCloseCorrect + ? mPreviousLedger->info().closeTime // use consensus timing + : consensus_.getLastCloseTime(); // use the time we saw + + auto now = + app_.timeKeeper().closeTime().time_since_epoch().count(); + if (now >= closeTime) + sinceClose = static_cast (1000 * (now - closeTime)); + else + sinceClose = - static_cast (1000 * (closeTime - now)); } - idleInterval = std::max (idleInterval, LEDGER_IDLE_INTERVAL); - idleInterval = std::max ( - idleInterval, 2 * mPreviousLedger->info().closeTimeResolution); + auto const idleInterval = std::max (LEDGER_IDLE_INTERVAL, + 2 * mPreviousLedger->info().closeTimeResolution); // Decide if we should close the ledger if (shouldCloseLedger (anyTransactions @@ -982,35 +978,27 @@ void LedgerConsensusImp::accept (std::shared_ptr set) consensus_.peekStoredProposals ().clear (); } - auto closeTime = mOurPosition->getCloseTime(); + auto closeTime = mOurPosition->getCloseTime (); + bool closeTimeCorrect; auto replay = ledgerMaster_.releaseReplay(); - if (replay) { - // If we're replaying a close, use the time the ledger - // we're replaying closed + // replaying, use the time the ledger we're replaying closed closeTime = replay->closeTime_; - - if ((replay->closeFlags_ & sLCF_NoConsensusTime) != 0) - closeTime = 0; + closeTimeCorrect = ((replay->closeFlags_ & sLCF_NoConsensusTime) == 0); } - - closeTime = roundCloseTime (closeTime, mCloseResolution); - - // If we don't have a close time, then we just agree to disagree - bool const closeTimeCorrect = (closeTime != 0); - - // Switch to new semantics on Oct 27, 2015 at 11:00:00am PDT - if (mPreviousLedger->info().closeTime > 499284000) - { - // Ledger close times should increase strictly monotonically - if (closeTime <= mPreviousLedger->info().closeTime) - closeTime = mPreviousLedger->info().closeTime + 1; - } - else if (!closeTimeCorrect) + else if (closeTime == 0) { + // We agreed to disagree on the close time closeTime = mPreviousLedger->info().closeTime + 1; + closeTimeCorrect = false; + } + else + { + // We agreed on a close time + closeTime = effectiveCloseTime (closeTime); + closeTimeCorrect = true; } JLOG (j_.debug) @@ -1526,6 +1514,16 @@ participantsNeeded (int participants, int percent) return (result == 0) ? 1 : result; } +std::uint32_t LedgerConsensusImp::effectiveCloseTime (std::uint32_t closeTime) +{ + if (closeTime == 0) + return 0; + + return std::max ( + roundCloseTime (closeTime, mCloseResolution), + mPreviousLedger->info().closeTime + 1); +} + void LedgerConsensusImp::updateOurPositions () { // Compute a cutoff time @@ -1558,8 +1556,8 @@ void LedgerConsensusImp::updateOurPositions () else { // proposal is still fresh - ++closeTimes[roundCloseTime ( - it->second->getCloseTime (), mCloseResolution)]; + ++closeTimes[effectiveCloseTime ( + it->second->getCloseTime ())]; ++it; } } @@ -1611,16 +1609,15 @@ void LedgerConsensusImp::updateOurPositions () { // no other times mHaveCloseTimeConsensus = true; - closeTime = roundCloseTime ( - mOurPosition->getCloseTime (), mCloseResolution); + closeTime = effectiveCloseTime (mOurPosition->getCloseTime ()); } else { int participants = mPeerPositions.size (); if (mProposing) { - ++closeTimes[roundCloseTime ( - mOurPosition->getCloseTime (), mCloseResolution)]; + ++closeTimes[ + effectiveCloseTime (mOurPosition->getCloseTime ())]; ++participants; } @@ -1636,42 +1633,36 @@ void LedgerConsensusImp::updateOurPositions () << mPeerPositions.size () << " nw:" << neededWeight << " thrV:" << threshVote << " thrC:" << threshConsensus; - for (auto it = closeTimes.begin () - , end = closeTimes.end (); it != end; ++it) + for (auto const& it : closeTimes) { JLOG (j_.debug) << "CCTime: seq " << mPreviousLedger->info().seq + 1 << ": " - << it->first << " has " << it->second << ", " + << it.first << " has " << it.second << ", " << threshVote << " required"; - if (it->second >= threshVote) + if (it.second >= threshVote) { - JLOG (j_.debug) - << "Close time consensus reached: " << it->first; - closeTime = it->first; - threshVote = it->second; + // A close time has enough votes for us to try to agree + closeTime = it.first; + threshVote = it.second; if (threshVote >= threshConsensus) mHaveCloseTimeConsensus = true; } } - // If we agree to disagree on the close time, don't delay consensus - if (!mHaveCloseTimeConsensus && (closeTimes[0] > threshConsensus)) - { - closeTime = 0; - mHaveCloseTimeConsensus = true; - } - CondLog (!mHaveCloseTimeConsensus, lsDEBUG, LedgerConsensus) << "No CT consensus: Proposers:" << mPeerPositions.size () << " Proposing:" << (mProposing ? "yes" : "no") << " Thresh:" << threshConsensus << " Pos:" << closeTime; } + // Temporarily send a new proposal if there's any change to our + // claimed close time. Once the new close time code is deployed + // to the full network, this can be relaxed to force a change + // only if the rounded close time has changed. if (!changes && - ((closeTime != roundCloseTime ( - mOurPosition->getCloseTime (), mCloseResolution)) + ((closeTime != mOurPosition->getCloseTime ()) || mOurPosition->isStale (ourCutoff))) { // close time changed or our position is stale diff --git a/src/ripple/app/ledger/impl/LedgerConsensusImp.h b/src/ripple/app/ledger/impl/LedgerConsensusImp.h index c6b335bfb..15ea52f35 100644 --- a/src/ripple/app/ledger/impl/LedgerConsensusImp.h +++ b/src/ripple/app/ledger/impl/LedgerConsensusImp.h @@ -293,6 +293,9 @@ private: /** Add our load fee to our validation */ void addLoad(STValidation::ref val); + /** Convert an advertised close time to an effective close time */ + std::uint32_t effectiveCloseTime (std::uint32_t closeTime); + private: Application& app_; ConsensusImp& consensus_; @@ -335,7 +338,7 @@ private: hash_map> mDisputes; hash_set mCompares; - // Close time estimates + // Close time estimates, keep ordered for predictable traverse std::map mCloseTimes; // nodes that have bowed out of this consensus process