20 #include <ripple/app/misc/HashRouter.h>
21 #include <ripple/app/misc/ValidatorList.h>
22 #include <ripple/basics/FileUtilities.h>
23 #include <ripple/basics/Slice.h>
24 #include <ripple/basics/StringUtilities.h>
25 #include <ripple/basics/base64.h>
26 #include <ripple/json/json_reader.h>
27 #include <ripple/overlay/Overlay.h>
28 #include <ripple/protocol/STValidation.h>
29 #include <ripple/protocol/jss.h>
30 #include <ripple/protocol/messages.h>
31 #include <boost/regex.hpp>
33 #include <date/date.h>
49 return "same_sequence";
51 return "unsupported_version";
70 boost::optional<std::size_t> minimumQuorum)
71 : validatorManifests_(validatorManifests)
72 , publisherManifests_(publisherManifests)
73 , timeKeeper_(timeKeeper)
74 , dataPath_(databasePath)
76 , quorum_(minimumQuorum.value_or(1))
77 , minimumQuorum_(minimumQuorum)
87 static boost::regex
const re(
102 <<
"Loading configured trusted validator list publisher keys";
105 for (
auto key : publisherKeys)
107 JLOG(
j_.
trace()) <<
"Processing '" << key <<
"'";
113 JLOG(
j_.
error()) <<
"Invalid validator list publisher key: " << key;
122 <<
"Configured validator list publisher key is revoked: "
130 <<
"Duplicate validator list publisher key: " << key;
146 JLOG(
j_.
debug()) <<
"Loading configured validator keys";
150 for (
auto const& n : configKeys)
152 JLOG(
j_.
trace()) <<
"Processing '" << n <<
"'";
156 if (!boost::regex_match(n, match, re))
158 JLOG(
j_.
error()) <<
"Malformed entry: '" << n <<
"'";
166 JLOG(
j_.
error()) <<
"Invalid node identity: " << match[1];
177 JLOG(
j_.
warn()) <<
"Duplicate node identity: " << match[1];
181 std::piecewise_construct,
186 it.first->second.expiration = TimeKeeper::time_point::max();
187 it.first->second.list.emplace_back(*
id);
188 it.first->second.available =
true;
197 boost::filesystem::path
213 boost::system::error_code ec;
218 value[
"blob"] = publisher.
rawBlob;
227 JLOG(
j_.
error()) <<
"Problem writing " << filename <<
" " << ec.value()
228 <<
": " << ec.message();
245 auto const disposition = result.disposition;
252 assert(result.available && result.publisherKey && result.sequence);
257 protocol::TMValidatorList msg;
260 msg.set_signature(signature);
261 msg.set_version(version);
263 auto const& publisherKey = *result.publisherKey;
264 auto const sequence = *result.sequence;
269 std::make_shared<Message>(msg, protocol::mtVALIDATORLIST);
272 if (toSkip->count(peer->id()) == 0 &&
273 peer->supportsFeature(
275 peer->publisherListSequence(publisherKey) < sequence)
280 <<
"Sent validator list for " <<
strHex(publisherKey)
281 <<
" with sequence " << sequence <<
" to "
282 << peer->getRemoteAddress().to_string() <<
" ("
283 << peer->id() <<
")";
286 peer->setPublisherListSequence(publisherKey, sequence);
302 boost::optional<uint256>
const& hash)
304 using namespace std::string_literals;
313 auto const result =
verify(list, pubKey,
manifest, blob, signature);
323 result, pubKey, publisher.available, publisher.sequence};
331 publisher.available =
true;
332 publisher.sequence = list[
"sequence"].
asUInt();
335 publisher.siteUri = std::move(siteUri);
337 publisher.rawBlob = blob;
338 publisher.rawSignature = signature;
339 publisher.rawVersion = version;
341 publisher.hash = *hash;
345 result, pubKey, publisher.available, publisher.sequence};
348 publisherList.
clear();
351 for (
auto const& val : newList)
353 if (val.isObject() && val.isMember(
"validation_public_key") &&
354 val[
"validation_public_key"].isString())
356 boost::optional<Blob>
const ret =
357 strUnHex(val[
"validation_public_key"].asString());
361 JLOG(
j_.
error()) <<
"Invalid node identity: "
362 << val[
"validation_public_key"].asString();
370 if (val.isMember(
"manifest") && val[
"manifest"].isString())
371 manifests.
push_back(val[
"manifest"].asString());
378 auto iNew = publisherList.
begin();
379 auto iOld = oldList.
begin();
380 while (iNew != publisherList.
end() || iOld != oldList.
end())
382 if (iOld == oldList.
end() ||
383 (iNew != publisherList.
end() && *iNew < *iOld))
390 iNew == publisherList.
end() ||
391 (iOld != oldList.
end() && *iOld < *iNew))
407 if (publisherList.
empty())
409 JLOG(
j_.
warn()) <<
"No validator keys included in valid list";
412 for (
auto const& valManifest : manifests)
419 <<
" contained untrusted validator manifest";
427 <<
" contained invalid validator manifest";
440 using namespace std::string_literals;
441 using namespace boost::filesystem;
442 using namespace boost::system::errc;
450 boost::system::error_code ec;
452 if (publisher.available)
457 auto const fullPath{canonical(filename, ec)};
461 auto size = file_size(fullPath, ec);
466 ec = make_error_code(no_such_file_or_directory);
472 #if _MSC_VER // MSVC: Windows paths need a leading / added
474 return fullPath.root_path() ==
"/"s ?
"file://" :
"file:///";
503 pubKey = m->masterKey;
504 auto const revoked = m->revoked();
517 auto const sig =
strUnHex(signature);
527 if (!r.
parse(data, list))
534 auto const sequence = list[
"sequence"].
asUInt();
569 boost::optional<PublicKey>
580 boost::optional<PublicKey>
612 JLOG(
j_.
debug()) <<
"Removing validator list for publisher "
615 for (
auto const& val : iList->second.list)
621 if (iVal->second <= 1)
627 iList->second.list.clear();
628 iList->second.available =
false;
640 boost::optional<TimeKeeper::time_point>
644 boost::optional<TimeKeeper::time_point> res{boost::none};
652 if (!res || p.second.expiration < *res)
653 res = p.second.expiration;
674 if (*when == TimeKeeper::time_point::max())
676 x[jss::expiration] =
"never";
677 x[jss::status] =
"active";
684 x[jss::status] =
"active";
686 x[jss::status] =
"expired";
691 x[jss::status] =
"unknown";
692 x[jss::expiration] =
"unknown";
702 for (
auto const& key : it->second.list)
711 if (local == p.first)
714 curr[jss::pubkey_publisher] =
strHex(p.first);
715 curr[jss::available] = p.second.available;
716 curr[jss::uri] = p.second.siteUri;
719 curr[jss::seq] =
static_cast<Json::UInt>(p.second.sequence);
720 curr[jss::expiration] =
to_string(p.second.expiration);
724 for (
auto const& key : p.second.list)
770 func(v.first,
trusted(v.first));
781 uint256 const& hash)> func)
const
800 boost::optional<Json::Value>
809 JLOG(
j_.
info()) <<
"Invalid requested validator list publisher key: "
823 value[
"manifest"] = iter->second.rawManifest;
824 value[
"blob"] = iter->second.rawBlob;
825 value[
"signature"] = iter->second.rawSignature;
826 value[
"version"] = iter->second.rawVersion;
841 if (!list.second.available)
889 <<
" as specified in the command line";
903 if (list.second.available &&
932 if (!trustChanges.
added.empty() || !trustChanges.
removed.empty())
942 <<
" listed validators eligible for inclusion in the trusted set";
945 auto effectiveUnlSize = unlSize;
946 auto seenSize = seenValidators.
size();
959 for (
auto const& nid : seenValidators)
961 if (negUnlNodeIDs.
count(nid))
967 JLOG(
j_.
debug()) <<
"Using quorum of " <<
quorum_ <<
" for new set of "
969 << trustChanges.
added.size() <<
" added, "
970 << trustChanges.
removed.size() <<
" removed)";
975 <<
" exceeds the number of trusted validators ("
1008 auto ret = std::move(validations);
1017 [&](
auto const& v) ->
bool {
1018 if (auto const masterKey =
1019 getTrustedKey(v->getSignerPublic());
1022 return negativeUnl_.count(*masterKey);
boost::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
ManifestCache & validatorManifests_
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
void for_each_listed(std::function< void(PublicKey const &, bool)> func) const
Invokes the callback once for every listed validation public key.
bool addSuppressionPeer(uint256 const &key, PeerShortID peer)
PublicKey localPublicKey() const
Returns local validator public key.
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
NodeID calcNodeID(PublicKey const &pk)
Calculate the 160-bit node ID from a node public key.
Stream trace() const
Severity stream access functions.
boost::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
hash_set< PublicKey > negativeUnl_
Changes in trusted nodes after updating validator list.
@ stale
Trusted publisher key, but seq is too old.
An immutable linear range of bytes.
hash_map< PublicKey, PublisherList > publisherLists_
@ arrayValue
array value (ordered list)
boost::optional< Json::Value > getAvailable(boost::beast::string_view const &pubKey)
Returns the current valid list for the given publisher key, if available, as a Json object.
boost::filesystem::path GetCacheFileName(PublicKey const &pubKey)
Get the filename used for caching UNLs.
bool trustedPublisher(PublicKey const &identity) const
Returns true if public key is a trusted publisher.
Describes the result of processing a Validator List (UNL), including some of the information from the...
static const std::string filePrefix_
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
TrustChanges updateTrusted(hash_set< NodeID > const &seenValidators)
Update trusted nodes.
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
hash_set< PublicKey > getTrustedMasterKeys() const
get the trusted master public keys
ListDisposition verify(Json::Value &list, PublicKey &pubKey, std::string const &manifest, std::string const &blob, std::string const &signature)
Check response for trusted valid published list.
boost::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
std::string toStyledString() const
std::string to_string(ListDisposition disposition)
Unserialize a JSON document into a Value.
Routing table for objects identified by hash.
std::shared_timed_mutex mutex_
ValidatorList(ManifestCache &validatorManifests, ManifestCache &publisherManifests, TimeKeeper &timeKeeper, std::string const &databasePath, beast::Journal j, boost::optional< std::size_t > minimumQuorum=boost::none)
boost::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical)
Verify a signature on a message.
void CacheValidatorFile(PublicKey const &pubKey, PublisherList const &publisher)
Write a JSON UNL to a cache file.
Value & append(const Value &value)
Append value to array at the end.
const boost::filesystem::path dataPath_
@ objectValue
object value (collection of name/value pairs).
PublisherListStats applyList(std::string const &manifest, std::string const &blob, std::string const &signature, std::uint32_t version, std::string siteUri, boost::optional< uint256 > const &hash={})
Apply published list of public keys.
std::size_t size() const noexcept
hash_set< NodeID > removed
boost::optional< std::size_t > minimumQuorum_
ManifestCache & publisherManifests_
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
void writeFileContents(boost::system::error_code &ec, boost::filesystem::path const &destPath, std::string const &contents)
std::string base64_decode(std::string const &data)
UInt size() const
Number of values in array or object.
void for_each_manifest(Function &&f) const
Invokes the callback once for every populated manifest.
virtual PeerSequence getActivePeers() const =0
Returns a sequence representing the current list of peers.
@ untrusted
List signed by untrusted publisher key.
PublicKey getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
bool isMember(const char *key) const
Return true if the object has a member named key.
A generic endpoint for log messages.
static constexpr std::uint32_t requiredListVersion
PublisherListStats applyListAndBroadcast(std::string const &manifest, std::string const &blob, std::string const &signature, std::uint32_t version, std::string siteUri, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter)
Apply published list of public keys, then broadcast it to all peers that have not seen it or sent it.
boost::optional< std::set< PeerShortID > > shouldRelay(uint256 const &key)
Determines whether the hashed item should be relayed.
T forward_as_tuple(T... args)
Manages various times used by the server.
@ unsupported_version
List version is not supported.
@ invalid
Timely, but invalid signature.
std::vector< std::shared_ptr< STValidation > > negativeUNLFilter(std::vector< std::shared_ptr< STValidation >> &&validations) const
Remove validations that are from validators on the negative UNL.
void setNegativeUnl(hash_set< PublicKey > const &negUnl)
set the Negative UNL with validators' master public keys
std::size_t calculateQuorum(std::size_t unlSize, std::size_t effectiveUnlSize, std::size_t seenSize)
Return quorum for trusted validator set.
@ accepted
Manifest is valid.
Remembers manifests with the highest sequence number.
std::vector< std::string > loadLists()
hash_set< PublicKey > getNegativeUnl() const
get the master public keys of Negative UNL validators
T emplace_back(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
hash_set< PublicKey > trustedSigningKeys_
boost::optional< Manifest > deserializeManifest(Slice s)
Constructs Manifest from serialized string.
bool load(PublicKey const &localSigningKey, std::vector< std::string > const &configKeys, std::vector< std::string > const &publisherKeys)
Load configured trusted keys.
void for_each_available(std::function< void(std::string const &manifest, std::string const &blob, std::string const &signature, std::uint32_t version, PublicKey const &pubKey, std::size_t sequence, uint256 const &hash)> func) const
Invokes the callback once for every available publisher list's raw data members.
Manages the set of connected peers.
@ same_sequence
Same sequence as current list.
boost::optional< Blob > strViewUnHex(boost::string_view const &strSrc)
@ invalid
Invalid format or signature.
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
virtual time_point now() const override=0
Returns the estimate of wall time, in network time.
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
@ ValidatorListPropagation
std::string strHex(FwdIt begin, FwdIt end)
boost::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
bool trusted(PublicKey const &identity) const
Returns true if public key is trusted.
hash_set< PublicKey > trustedMasterKeys_
std::size_t count() const
Return the number of configured validator list sites.
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
typename NetClock ::time_point time_point
hash_map< PublicKey, std::size_t > keyListings_
std::atomic< std::size_t > quorum_
typename NetClock ::duration duration
std::size_t quorum() const
Get quorum value for current trusted key set.
bool removePublisherList(PublicKey const &publisherKey)
Stop trusting publisher's list of keys.