Use ephemeral validator public keys in lag ratchet:

A review of the lag ratchet code revealed that we were using
the long-term master public keys of trusted validators, when
we should have been using the ephemeral public keys instead.

As a result, the lag ratchet code would be effectively
inoperable.
This commit is contained in:
Nik Bougalis
2020-02-27 22:55:15 -08:00
committed by Carl Hua
parent 16c659b22c
commit 6529d3e6f7
3 changed files with 43 additions and 28 deletions

View File

@@ -151,7 +151,12 @@ class ValidatorList
hash_map<PublicKey, std::size_t> keyListings_; hash_map<PublicKey, std::size_t> keyListings_;
// The current list of trusted master keys // The current list of trusted master keys
hash_set<PublicKey> trustedKeys_; hash_set<PublicKey> trustedMasterKeys_;
// The current list of trusted signing keys. For those validators using
// a manifest, the signing key is the ephemeral key. For the ones using
// a seed, the signing key is the same as the master key.
hash_set<PublicKey> trustedSigningKeys_;
PublicKey localPubKey_; PublicKey localPubKey_;
@@ -503,7 +508,7 @@ public:
getQuorumKeys() const getQuorumKeys() const
{ {
std::shared_lock<std::shared_timed_mutex> read_lock{mutex_}; std::shared_lock<std::shared_timed_mutex> read_lock{mutex_};
return {quorum_, trustedKeys_}; return {quorum_, trustedSigningKeys_};
} }

View File

@@ -585,7 +585,7 @@ ValidatorList::trusted (PublicKey const& identity) const
std::shared_lock<std::shared_timed_mutex> read_lock{mutex_}; std::shared_lock<std::shared_timed_mutex> read_lock{mutex_};
auto const pubKey = validatorManifests_.getMasterKey (identity); auto const pubKey = validatorManifests_.getMasterKey (identity);
return trustedKeys_.find (pubKey) != trustedKeys_.end(); return trustedMasterKeys_.find (pubKey) != trustedMasterKeys_.end();
} }
boost::optional<PublicKey> boost::optional<PublicKey>
@@ -606,7 +606,7 @@ ValidatorList::getTrustedKey (PublicKey const& identity) const
std::shared_lock<std::shared_timed_mutex> read_lock{mutex_}; std::shared_lock<std::shared_timed_mutex> read_lock{mutex_};
auto const pubKey = validatorManifests_.getMasterKey (identity); auto const pubKey = validatorManifests_.getMasterKey (identity);
if (trustedKeys_.find (pubKey) != trustedKeys_.end()) if (trustedMasterKeys_.find (pubKey) != trustedMasterKeys_.end())
return pubKey; return pubKey;
return boost::none; return boost::none;
} }
@@ -755,7 +755,7 @@ ValidatorList::getJson() const
// Trusted validator keys // Trusted validator keys
Json::Value& jValidatorKeys = Json::Value& jValidatorKeys =
(res[jss::trusted_validator_keys] = Json::arrayValue); (res[jss::trusted_validator_keys] = Json::arrayValue);
for (auto const& k : trustedKeys_) for (auto const& k : trustedMasterKeys_)
{ {
jValidatorKeys.append(toBase58(TokenType::NodePublic, k)); jValidatorKeys.append(toBase58(TokenType::NodePublic, k));
} }
@@ -912,14 +912,14 @@ ValidatorList::updateTrusted(hash_set<NodeID> const& seenValidators)
TrustChanges trustChanges; TrustChanges trustChanges;
auto it = trustedKeys_.cbegin(); auto it = trustedMasterKeys_.cbegin();
while (it != trustedKeys_.cend()) while (it != trustedMasterKeys_.cend())
{ {
if (!keyListings_.count(*it) || if (!keyListings_.count(*it) ||
validatorManifests_.revoked(*it)) validatorManifests_.revoked(*it))
{ {
trustChanges.removed.insert(calcNodeID(*it)); trustChanges.removed.insert(calcNodeID(*it));
it = trustedKeys_.erase(it); it = trustedMasterKeys_.erase(it);
} }
else else
{ {
@@ -930,27 +930,37 @@ ValidatorList::updateTrusted(hash_set<NodeID> const& seenValidators)
for (auto const& val : keyListings_) for (auto const& val : keyListings_)
{ {
if (!validatorManifests_.revoked(val.first) && if (!validatorManifests_.revoked(val.first) &&
trustedKeys_.emplace(val.first).second) trustedMasterKeys_.emplace(val.first).second)
trustChanges.added.insert(calcNodeID(val.first)); trustChanges.added.insert(calcNodeID(val.first));
} }
JLOG (j_.debug()) << // If there were any changes, we need to update the ephemeral signing keys:
trustedKeys_.size() << " of " << keyListings_.size() << if (!trustChanges.added.empty() || !trustChanges.removed.empty())
" listed validators eligible for inclusion in the trusted set"; {
trustedSigningKeys_.clear();
quorum_ = calculateQuorum (trustedKeys_.size(), seenValidators.size()); for (auto const& k : trustedMasterKeys_)
trustedSigningKeys_.insert(validatorManifests_.getSigningKey(k));
}
JLOG(j_.debug()) << "Using quorum of " << quorum_ << " for new set of " JLOG (j_.debug())
<< trustedKeys_.size() << " trusted validators (" << trustedMasterKeys_.size() << " of " << keyListings_.size()
<< " listed validators eligible for inclusion in the trusted set";
quorum_ = calculateQuorum (trustedMasterKeys_.size(), seenValidators.size());
JLOG(j_.debug())
<< "Using quorum of " << quorum_ << " for new set of "
<< trustedMasterKeys_.size() << " trusted validators ("
<< trustChanges.added.size() << " added, " << trustChanges.added.size() << " added, "
<< trustChanges.removed.size() << " removed)"; << trustChanges.removed.size() << " removed)";
if (trustedKeys_.size() < quorum_) if (trustedMasterKeys_.size() < quorum_)
{ {
JLOG (j_.warn()) << JLOG (j_.warn())
"New quorum of " << quorum_ << << "New quorum of " << quorum_
" exceeds the number of trusted validators (" << << " exceeds the number of trusted validators ("
trustedKeys_.size() << ")"; << trustedMasterKeys_.size() << ")";
} }
return trustChanges; return trustChanges;

View File

@@ -1173,7 +1173,7 @@ Consensus<Adaptor>::shouldPause() const
!adaptor_.haveValidated() || !adaptor_.haveValidated() ||
result_->roundTime.read() > parms.ledgerMAX_CONSENSUS) result_->roundTime.read() > parms.ledgerMAX_CONSENSUS)
{ {
j_.debug() << "not pausing" << vars.str(); j_.debug() << "not pausing (early)" << vars.str();
return false; return false;
} }