Consensus ledger switch improvements

* Expire validations faster based on when we first saw them.
* Never jump to a ledger prior to the latest fully-valid ledger
* Drop validations with signing times too far in the future immediately
This commit is contained in:
JoelKatz
2015-11-18 14:15:04 -08:00
committed by Nik Bougalis
parent 469d5494ea
commit 45b07ff9ec
12 changed files with 77 additions and 51 deletions

View File

@@ -72,11 +72,16 @@ const int LEDGER_IDLE_INTERVAL = 15;
// The number of seconds a validation remains current after its ledger's close
// time. This is a safety to protect against very old validations and the time
// it takes to adjust the close time accuracy window
const int LEDGER_VAL_INTERVAL = 300;
const int VALIDATION_VALID_WALL = 300;
// The number of seconds a validation remains current after the time we first
// saw it. This provides faster recovery in very rare cases where the number
// of validations produced by the network is lower than normal
const int VALIDATION_VALID_LOCAL = 180;
// The number of seconds before a close time that we consider a validation
// acceptable. This protects against extreme clock errors
const int LEDGER_EARLY_INTERVAL = 180;
const int VALIDATION_VALID_EARLY = 180;
// The number of milliseconds we wait minimum to ensure participation
const int LEDGER_MIN_CONSENSUS = 2000;

View File

@@ -550,8 +550,9 @@ void LedgerConsensusImp::checkLCL ()
// Get validators that are on our ledger, or "close" to being on
// our ledger.
hash_map<uint256, ValidationCounter> vals =
app_.getValidations ().getCurrentValidations
(favoredLedger, priorLedger);
app_.getValidations ().getCurrentValidations(
favoredLedger, priorLedger,
ledgerMaster_.getValidLedgerIndex ());
for (auto& it : vals)
{

View File

@@ -198,7 +198,7 @@ public:
if (mStrictValCount)
{
// If we're only using validation count, then we can't
// reject a ledger even if it's ioncompatible
// reject a ledger even if it's incompatible
return true;
}

View File

@@ -1007,7 +1007,6 @@ void ApplicationImp::setup()
if (!config_->RUN_STANDALONE)
getUNL ().nodeBootstrap ();
mValidations->tune (config_->getSize (siValidationsSize), config_->getSize (siValidationsAge));
m_nodeStore->tune (config_->getSize (siNodeCacheSize), config_->getSize (siNodeCacheAge));
m_ledgerMaster->tune (config_->getSize (siLedgerSize), config_->getSize (siLedgerAge));
family().treecache().setTargetSize (config_->getSize (siTreeCacheSize));

View File

@@ -1218,7 +1218,8 @@ bool NetworkOPsImp::checkLastClosedLedger (
hash_map<uint256, ValidationCount> ledgers;
{
auto current = app_.getValidations ().getCurrentValidations (
closedLedger, prevClosedLedger);
closedLedger, prevClosedLedger,
m_ledgerMaster.getValidLedgerIndex());
for (auto& it: current)
{

View File

@@ -75,7 +75,7 @@ private:
public:
ValidationsImp (Application& app)
: app_ (app)
, mValidations ("Validations", 128, 600, stopwatch(),
, mValidations ("Validations", 4096, 600, stopwatch(),
app.journal("TaggedCache"))
, mWriting (false)
, j_ (app.journal ("Validations"))
@@ -87,19 +87,11 @@ private:
bool addValidation (STValidation::ref val, std::string const& source) override
{
RippleAddress signer = val->getSignerPublic ();
bool isCurrent = false;
bool isCurrent = current (val);
if (! val->isTrusted() && app_.getUNL().nodeInUNL (signer))
val->setTrusted();
auto const now = app_.timeKeeper().closeTime().time_since_epoch().count();
std::uint32_t valClose = val->getSignTime();
if ((now > (valClose - LEDGER_EARLY_INTERVAL)) && (now < (valClose + LEDGER_VAL_INTERVAL)))
isCurrent = true;
else
JLOG (j_.warning) << "Received stale validation now=" << now << ", close=" << valClose;
if (!val->isTrusted ())
{
JLOG (j_.debug) << "Node " << signer.humanNodePublic () << " not in UNL st=" << val->getSignTime () <<
@@ -144,7 +136,8 @@ private:
}
JLOG (j_.debug) << "Val for " << hash << " from " << signer.humanNodePublic ()
<< " added " << (val->isTrusted () ? "trusted/" : "UNtrusted/") << (isCurrent ? "current" : "stale");
<< " added " << (val->isTrusted () ? "trusted/" : "UNtrusted/")
<< (isCurrent ? "current" : "stale");
if (val->isTrusted () && isCurrent)
{
@@ -174,6 +167,25 @@ private:
return ValidationSet ();
}
bool current (STValidation::ref val) override
{
// Because this can be called on untrusted, possibly
// malicious validations, we do our math in a way
// that avoids any chance of overflowing or underflowing
// the signing time.
auto const now =
app_.timeKeeper().now().time_since_epoch().count();
auto const signTime = val->getSignTime();
return
(signTime > (now - VALIDATION_VALID_EARLY)) &&
(signTime < (now + VALIDATION_VALID_WALL)) &&
((val->getSeenTime() == 0) ||
(val->getSeenTime() < (now + VALIDATION_VALID_LOCAL)));
}
void getValidationCount (uint256 const& ledger, bool currentOnly,
int& trusted, int& untrusted) override
{
@@ -183,22 +195,14 @@ private:
if (set)
{
auto const now =
app_.timeKeeper().now().time_since_epoch().count();
for (auto& it: *set)
{
bool isTrusted = it.second->isTrusted ();
if (isTrusted && currentOnly)
{
std::uint32_t closeTime = it.second->getSignTime ();
if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_VAL_INTERVAL)))
isTrusted = false;
else
if (isTrusted && currentOnly && ! current (it.second))
{
JLOG (j_.trace) << "VC: Untrusted due to time " << ledger;
}
isTrusted = false;
}
if (isTrusted)
@@ -312,9 +316,6 @@ private:
std::list<STValidation::pointer> getCurrentTrustedValidations () override
{
// VFALCO LEDGER_VAL_INTERVAL should be a NetClock::duration
auto const cutoff = app_.timeKeeper().now().time_since_epoch().count() - LEDGER_VAL_INTERVAL;
std::list<STValidation::pointer> ret;
ScopedLockType sl (mLock);
@@ -324,7 +325,7 @@ private:
{
if (!it->second) // contains no record
it = mCurrentValidations.erase (it);
else if (it->second->getSignTime () < cutoff)
else if (! current (it->second))
{
// contains a stale record
mStaleValidations.push_back (it->second);
@@ -346,9 +347,10 @@ private:
}
LedgerToValidationCounter getCurrentValidations (
uint256 currentLedger, uint256 priorLedger) override
uint256 currentLedger,
uint256 priorLedger,
LedgerIndex cutoffBefore) override
{
auto const cutoff = app_.timeKeeper().now().time_since_epoch().count() - LEDGER_VAL_INTERVAL;
bool valCurrentLedger = currentLedger.isNonZero ();
bool valPriorLedger = priorLedger.isNonZero ();
@@ -361,7 +363,7 @@ private:
{
if (!it->second) // contains no record
it = mCurrentValidations.erase (it);
else if (it->second->getSignTime () < cutoff)
else if (! current (it->second))
{
// contains a stale record
mStaleValidations.push_back (it->second);
@@ -369,7 +371,8 @@ private:
condWrite ();
it = mCurrentValidations.erase (it);
}
else
else if (! it->second->isFieldPresent (sfLedgerSequence) ||
(it->second->getFieldU32 (sfLedgerSequence) >= cutoffBefore))
{
// contains a live record
bool countPreferred = valCurrentLedger && (it->second->getLedgerHash () == currentLedger);
@@ -391,6 +394,10 @@ private:
++it;
}
else
{
++it;
}
}
return ret;

View File

@@ -21,6 +21,7 @@
#define RIPPLE_APP_MISC_VALIDATIONS_H_INCLUDED
#include <ripple/app/main/Application.h>
#include <ripple/protocol/Protocol.h>
#include <ripple/protocol/STValidation.h>
#include <memory>
#include <vector>
@@ -43,6 +44,8 @@ public:
virtual bool addValidation (STValidation::ref, std::string const& source) = 0;
virtual bool current (STValidation::ref) = 0;
virtual ValidationSet getValidations (uint256 const& ledger) = 0;
virtual void getValidationCount (
@@ -63,7 +66,8 @@ public:
// VFALCO TODO make a type alias for this ugly return value!
virtual LedgerToValidationCounter getCurrentValidations (
uint256 currentLedger, uint256 previousLedger) = 0;
uint256 currentLedger, uint256 previousLedger,
LedgerIndex cutoffBefore) = 0;
/** Return the times of all validations for a particular ledger hash. */
virtual std::vector<std::uint32_t> getValidationTimes (

View File

@@ -63,8 +63,6 @@ class Rules;
enum SizedItemName
{
siSweepInterval,
siValidationsSize,
siValidationsAge,
siNodeCacheSize,
siNodeCacheAge,
siTreeCacheSize,

View File

@@ -513,9 +513,6 @@ int Config::getSize (SizedItemName item) const
{ siLedgerFetch, { 2, 2, 3, 3, 3 } },
{ siValidationsSize, { 256, 256, 512, 1024, 1024 } },
{ siValidationsAge, { 500, 500, 500, 500, 500 } },
{ siNodeCacheSize, { 16384, 32768, 131072, 262144, 524288 } },
{ siNodeCacheAge, { 60, 90, 120, 900, 1800 } },

View File

@@ -23,11 +23,13 @@
#include <ripple/overlay/impl/Tuning.h>
#include <ripple/app/ledger/InboundLedgers.h>
#include <ripple/app/ledger/LedgerMaster.h>
#include <ripple/app/ledger/LedgerTiming.h>
#include <ripple/app/ledger/InboundTransactions.h>
#include <ripple/app/misc/HashRouter.h>
#include <ripple/app/misc/NetworkOPs.h>
#include <ripple/app/misc/Transaction.h>
#include <ripple/app/misc/UniqueNodeList.h>
#include <ripple/app/misc/Validations.h>
#include <ripple/app/tx/apply.h>
#include <ripple/protocol/digest.h>
#include <ripple/basics/StringUtilities.h>
@@ -1550,7 +1552,8 @@ void
PeerImp::onMessage (std::shared_ptr <protocol::TMValidation> const& m)
{
error_code ec;
auto const closeTime = app_.timeKeeper().closeTime().time_since_epoch().count();
auto const closeTime =
app_.timeKeeper().closeTime().time_since_epoch().count();
if (m->has_hops() && ! slot_->cluster())
m->set_hops(m->hops() + 1);
@@ -1569,11 +1572,12 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMValidation> const& m)
SerialIter sit (makeSlice(m->validation()));
val = std::make_shared <
STValidation> (std::ref (sit), false);
val->setSeen (closeTime);
}
if (closeTime > (120 + val->getFieldU32(sfSigningTime)))
if (! app_.getValidations().current (val))
{
p_journal_.trace << "Validation: Too old";
p_journal_.trace << "Validation: Not current";
fee_ = Resource::feeUnwantedData;
return;
}

View File

@@ -66,6 +66,7 @@ public:
uint256 getLedgerHash () const;
std::uint32_t getSignTime () const;
std::uint32_t getSeenTime () const;
std::uint32_t getFlags () const;
RippleAddress getSignerPublic () const;
NodeID getNodeID () const
@@ -85,6 +86,10 @@ public:
{
mTrusted = true;
}
void setSeen (std::uint32_t s)
{
mSeen = s;
}
Blob getSigned () const;
Blob getSignature () const;
@@ -112,7 +117,8 @@ private:
uint256 mPreviousHash;
NodeID mNodeID;
bool mTrusted;
bool mTrusted = false;
std::uint32_t mSeen = 0;
};
} // ripple

View File

@@ -28,7 +28,6 @@ namespace ripple {
STValidation::STValidation (SerialIter& sit, bool checkSignature)
: STObject (getFormat (), sit, sfValidation)
, mTrusted (false)
{
mNodeID = RippleAddress::createNodePublic (getFieldVL (sfSigningPubKey)).getNodeID ();
assert (mNodeID.isNonZero ());
@@ -44,7 +43,7 @@ STValidation::STValidation (
uint256 const& ledgerHash, std::uint32_t signTime,
RippleAddress const& raPub, bool isFull)
: STObject (getFormat (), sfValidation)
, mTrusted (false)
, mSeen (signTime)
{
// Does not sign
setFieldH256 (sfLedgerHash, ledgerHash);
@@ -85,6 +84,11 @@ std::uint32_t STValidation::getSignTime () const
return getFieldU32 (sfSigningTime);
}
std::uint32_t STValidation::getSeenTime () const
{
return mSeen;
}
std::uint32_t STValidation::getFlags () const
{
return getFieldU32 (sfFlags);