Skip to content

Commit

Permalink
Update validations on UNL change (RIPD-1566):
Browse files Browse the repository at this point in the history
Change the trust status of existing validations based when nodes are
added or removed from the UNL.
  • Loading branch information
bachase committed Feb 27, 2018
1 parent 6230204 commit 941935f
Show file tree
Hide file tree
Showing 24 changed files with 765 additions and 390 deletions.
8 changes: 5 additions & 3 deletions src/ripple/app/consensus/RCLConsensus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ RCLConsensus::Adaptor::Adaptor(
, localTxs_(localTxs)
, inboundTransactions_{inboundTransactions}
, j_(journal)
, nodeID_{calcNodeID(app.nodeIdentity().first)}
, nodeID_{validatorKeys.nodeID}
, valPublic_{validatorKeys.publicKey}
, valSecret_{validatorKeys.secretKey}
{
Expand Down Expand Up @@ -837,6 +837,7 @@ RCLConsensus::Adaptor::validate(RCLCxLedger const& ledger, bool proposing)
ledger.id(),
validationTime,
valPublic_,
nodeID_,
proposing /* full if proposed */);
v->setFieldU32(sfLedgerSequence, ledger.seq());

Expand Down Expand Up @@ -980,10 +981,11 @@ void
RCLConsensus::startRound(
NetClock::time_point const& now,
RCLCxLedger::ID const& prevLgrId,
RCLCxLedger const& prevLgr)
RCLCxLedger const& prevLgr,
hash_set<NodeID> const& nowUntrusted)
{
ScopedLockType _{mutex_};
consensus_.startRound(
now, prevLgrId, prevLgr, adaptor_.preStartRound(prevLgr));
now, prevLgrId, prevLgr, nowUntrusted, adaptor_.preStartRound(prevLgr));
}
}
3 changes: 2 additions & 1 deletion src/ripple/app/consensus/RCLConsensus.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,8 @@ class RCLConsensus
startRound(
NetClock::time_point const& now,
RCLCxLedger::ID const& prevLgrId,
RCLCxLedger const& prevLgr);
RCLCxLedger const& prevLgr,
hash_set<NodeID> const& nowUntrusted);

//! @see Consensus::timerEntry
void
Expand Down
11 changes: 2 additions & 9 deletions src/ripple/app/consensus/RCLValidations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ RCLValidationsAdaptor::onStale(RCLValidation&& v)
}

void
RCLValidationsAdaptor::flush(hash_map<PublicKey, RCLValidation>&& remaining)
RCLValidationsAdaptor::flush(hash_map<NodeID, RCLValidation>&& remaining)
{
bool anyNew = false;
{
Expand Down Expand Up @@ -317,7 +317,7 @@ handleNewValidation(Application& app,
// masterKey is seated only if validator is trusted or listed
if (masterKey)
{
ValStatus const outcome = validations.add(*masterKey, val);
ValStatus const outcome = validations.add(calcNodeID(*masterKey), val);
if(j.debug())
dmp(j.debug(), to_string(outcome));

Expand All @@ -327,13 +327,6 @@ handleNewValidation(Application& app,
dmp(j.warn(),
"already validated sequence at or past " + to_string(seq));
}
else if(outcome == ValStatus::repeatID && j.warn())
{
auto const seq = val->getFieldU32(sfLedgerSequence);
dmp(j.warn(),
"already validated ledger with same id but different seq "
"than" + to_string(seq));
}

if (val->isTrusted() && outcome == ValStatus::current)
{
Expand Down
16 changes: 14 additions & 2 deletions src/ripple/app/consensus/RCLValidations.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,19 @@ class RCLValidation
return val_->isTrusted();
}

/// Whether the validatioon is full (not-partial)
void
setTrusted()
{
val_->setTrusted();
}

void
setUntrusted()
{
val_->setUntrusted();
}

/// Whether the validation is full (not-partial)
bool
full() const
{
Expand Down Expand Up @@ -214,7 +226,7 @@ class RCLValidationsAdaptor
@param remaining The remaining validations to flush
*/
void
flush(hash_map<PublicKey, RCLValidation>&& remaining);
flush(hash_map<NodeID, RCLValidation>&& remaining);

/** Attempt to acquire the ledger with given id from the network */
boost::optional<RCLValidatedLedger>
Expand Down
18 changes: 10 additions & 8 deletions src/ripple/app/misc/NetworkOPs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,7 @@ class NetworkOPsImp final
// Ledger proposal/close functions.
void processTrustedProposal (
RCLCxPeerPos proposal,
std::shared_ptr<protocol::TMProposeSet> set,
NodeID const &node) override;
std::shared_ptr<protocol::TMProposeSet> set) override;

bool recvValidation (
STValidation::ref val, std::string const& source) override;
Expand Down Expand Up @@ -1434,13 +1433,17 @@ bool NetworkOPsImp::beginConsensus (uint256 const& networkClosed)
assert (closingInfo.parentHash ==
m_ledgerMaster.getClosedLedger()->info().hash);

app_.validators().onConsensusStart (
app_.getValidations().getCurrentPublicKeys ());
TrustChanges const changes = app_.validators().updateTrusted(
app_.getValidations().getCurrentNodeIDs());

mConsensus.startRound (
if (!changes.added.empty() || !changes.removed.empty())
app_.getValidations().trustChanged(changes.added, changes.removed);

mConsensus.startRound(
app_.timeKeeper().closeTime(),
networkClosed,
prevLedger);
prevLedger,
changes.removed);

JLOG(m_journal.debug()) << "Initiating consensus engine";
return true;
Expand All @@ -1453,8 +1456,7 @@ uint256 NetworkOPsImp::getConsensusLCL ()

void NetworkOPsImp::processTrustedProposal (
RCLCxPeerPos peerPos,
std::shared_ptr<protocol::TMProposeSet> set,
NodeID const& node)
std::shared_ptr<protocol::TMProposeSet> set)
{
if (mConsensus.peerProposal(
app_.timeKeeper().closeTime(), peerPos))
Expand Down
3 changes: 1 addition & 2 deletions src/ripple/app/misc/NetworkOPs.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,7 @@ class NetworkOPs

// ledger proposal/close functions
virtual void processTrustedProposal (RCLCxPeerPos peerPos,
std::shared_ptr<protocol::TMProposeSet> set,
NodeID const& node) = 0;
std::shared_ptr<protocol::TMProposeSet> set) = 0;

virtual bool recvValidation (STValidation::ref val,
std::string const& source) = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/ripple/app/misc/ValidatorKeys.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <ripple/beast/utility/Journal.h>
#include <ripple/protocol/PublicKey.h>
#include <ripple/protocol/SecretKey.h>
#include <ripple/protocol/UintTypes.h>
#include <string>

namespace ripple {
Expand All @@ -37,6 +38,7 @@ class ValidatorKeys
public:
PublicKey publicKey;
SecretKey secretKey;
NodeID nodeID;
std::string manifest;
ValidatorKeys(Config const& config, beast::Journal j);

Expand Down
152 changes: 17 additions & 135 deletions src/ripple/app/misc/ValidatorList.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ enum class ListDisposition
std::string
to_string(ListDisposition disposition);

/** Changes in trusted nodes after updating validator list
*/
struct TrustChanges
{
hash_set<NodeID> added;
hash_set<NodeID> removed;
};

/**
Trusted Validators List
-----------------------
Expand Down Expand Up @@ -202,22 +210,23 @@ class ValidatorList
std::string const& signature,
std::uint32_t version);

/** Update trusted keys
/** Update trusted nodes
Reset the trusted keys based on latest manifests, received validations,
Reset the trusted nodes based on latest manifests, received validations,
and lists.
@param seenValidators Set of public keys used to sign recently
received validations
@param seenValidators Set of NodeIDs of validators that have signed
recently received validations
@return TrustedKeyChanges instance with newly trusted or untrusted
node identities.
@par Thread Safety
May be called concurrently
*/
template<class KeySet>
void
onConsensusStart (
KeySet const& seenValidators);
TrustChanges
updateTrusted (hash_set<NodeID> const& seenValidators);

/** Get quorum value for current trusted key set
Expand Down Expand Up @@ -390,133 +399,6 @@ class ValidatorList
calculateMinimumQuorum (
std::size_t nListedKeys, bool unlistedLocal=false);
};

//------------------------------------------------------------------------------

template<class KeySet>
void
ValidatorList::onConsensusStart (
KeySet const& seenValidators)
{
boost::unique_lock<boost::shared_mutex> lock{mutex_};

// Check that lists from all configured publishers are available
bool allListsAvailable = true;

for (auto const& list : publisherLists_)
{
// Remove any expired published lists
if (TimeKeeper::time_point{} < list.second.expiration &&
list.second.expiration <= timeKeeper_.now())
removePublisherList(list.first);

if (! list.second.available)
allListsAvailable = false;
}

std::multimap<std::size_t, PublicKey> rankedKeys;
bool localKeyListed = false;

// "Iterate" the listed keys in random order so that the rank of multiple
// keys with the same number of listings is not deterministic
std::vector<std::size_t> indexes (keyListings_.size());
std::iota (indexes.begin(), indexes.end(), 0);
std::shuffle (indexes.begin(), indexes.end(), crypto_prng());

for (auto const& index : indexes)
{
auto const& val = std::next (keyListings_.begin(), index);

if (validatorManifests_.revoked (val->first))
continue;

if (val->first == localPubKey_)
{
localKeyListed = val->second > 1;
rankedKeys.insert (
std::pair<std::size_t,PublicKey>(
std::numeric_limits<std::size_t>::max(), localPubKey_));
}
// If the total number of validators is too small, or
// no validations are being received, use all validators.
// Otherwise, do not use validators whose validations aren't
// being received.
else if (keyListings_.size() < MINIMUM_RESIZEABLE_UNL ||
seenValidators.empty() ||
seenValidators.find (val->first) != seenValidators.end ())
{
rankedKeys.insert (
std::pair<std::size_t,PublicKey>(val->second, val->first));
}
}

// This minimum quorum guarantees safe overlap with the trusted sets of
// other nodes using the same set of published lists.
std::size_t quorum = calculateMinimumQuorum (keyListings_.size(),
localPubKey_.size() && !localKeyListed);

JLOG (j_.debug()) <<
rankedKeys.size() << " of " << keyListings_.size() <<
" listed validators eligible for inclusion in the trusted set";

auto size = rankedKeys.size();

// Require 80% quorum if there are lots of validators.
if (rankedKeys.size() > BYZANTINE_THRESHOLD)
{
// Use all eligible keys if there is only one trusted list
if (publisherLists_.size() == 1 ||
keyListings_.size() < MINIMUM_RESIZEABLE_UNL)
{
// Try to raise the quorum to at least 80% of the trusted set
quorum = std::max(quorum, size - size / 5);
}
else
{
// Reduce the trusted set size so that the quorum represents
// at least 80%
size = quorum * 1.25;
}
}

if (minimumQuorum_ && seenValidators.size() < quorum)
{
quorum = *minimumQuorum_;
JLOG (j_.warn())
<< "Using unsafe quorum of "
<< quorum_
<< " as specified in the command line";
}

// Do not use achievable quorum until lists from all configured
// publishers are available
else if (! allListsAvailable)
quorum = std::numeric_limits<std::size_t>::max();

trustedKeys_.clear();
quorum_ = quorum;

for (auto const& val : boost::adaptors::reverse (rankedKeys))
{
if (size <= trustedKeys_.size())
break;

trustedKeys_.insert (val.second);
}

JLOG (j_.debug()) <<
"Using quorum of " << quorum_ << " for new set of " <<
trustedKeys_.size() << " trusted validators";

if (trustedKeys_.size() < quorum_)
{
JLOG (j_.warn()) <<
"New quorum of " << quorum_ <<
" exceeds the number of trusted validators (" <<
trustedKeys_.size() << ")";
}
}

} // ripple

#endif
3 changes: 2 additions & 1 deletion src/ripple/app/misc/impl/ValidatorKeys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ ValidatorKeys::ValidatorKeys(Config const& config, beast::Journal j)
KeyType::secp256k1, token->validationSecret);
auto const m = Manifest::make_Manifest(
beast::detail::base64_decode(token->manifest));

if (! m || pk != m->signingKey)
{
configInvalid_ = true;
Expand All @@ -58,6 +57,7 @@ ValidatorKeys::ValidatorKeys(Config const& config, beast::Journal j)
{
secretKey = token->validationSecret;
publicKey = pk;
nodeID = calcNodeID(m->masterKey);
manifest = std::move(token->manifest);
}
}
Expand All @@ -82,6 +82,7 @@ ValidatorKeys::ValidatorKeys(Config const& config, beast::Journal j)
{
secretKey = generateSecretKey(KeyType::secp256k1, *seed);
publicKey = derivePublicKey(KeyType::secp256k1, secretKey);
nodeID = calcNodeID(publicKey);
}
}
}
Expand Down
Loading

0 comments on commit 941935f

Please sign in to comment.