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/jss.h>
29 #include <ripple/protocol/messages.h>
30 #include <boost/regex.hpp>
32 #include <date/date.h>
48 return "same_sequence";
50 return "unsupported_version";
69 boost::optional<std::size_t> minimumQuorum)
70 : validatorManifests_(validatorManifests)
71 , publisherManifests_(publisherManifests)
72 , timeKeeper_(timeKeeper)
73 , dataPath_(databasePath)
75 , quorum_(minimumQuorum.value_or(1))
76 , minimumQuorum_(minimumQuorum)
86 static boost::regex
const re(
101 <<
"Loading configured trusted validator list publisher keys";
104 for (
auto key : publisherKeys)
106 JLOG(
j_.
trace()) <<
"Processing '" << key <<
"'";
112 JLOG(
j_.
error()) <<
"Invalid validator list publisher key: " << key;
121 <<
"Configured validator list publisher key is revoked: "
129 <<
"Duplicate validator list publisher key: " << key;
145 JLOG(
j_.
debug()) <<
"Loading configured validator keys";
149 for (
auto const& n : configKeys)
151 JLOG(
j_.
trace()) <<
"Processing '" << n <<
"'";
155 if (!boost::regex_match(n, match, re))
157 JLOG(
j_.
error()) <<
"Malformed entry: '" << n <<
"'";
165 JLOG(
j_.
error()) <<
"Invalid node identity: " << match[1];
176 JLOG(
j_.
warn()) <<
"Duplicate node identity: " << match[1];
180 std::piecewise_construct,
185 it.first->second.expiration = TimeKeeper::time_point::max();
186 it.first->second.list.emplace_back(*
id);
187 it.first->second.available =
true;
196 boost::filesystem::path
212 boost::system::error_code ec;
217 value[
"blob"] = publisher.
rawBlob;
226 JLOG(
j_.
error()) <<
"Problem writing " << filename <<
" " << ec.value()
227 <<
": " << ec.message();
244 auto const disposition = result.disposition;
251 assert(result.available && result.publisherKey && result.sequence);
256 protocol::TMValidatorList msg;
259 msg.set_signature(signature);
260 msg.set_version(version);
262 auto const& publisherKey = *result.publisherKey;
263 auto const sequence = *result.sequence;
268 std::make_shared<Message>(msg, protocol::mtVALIDATORLIST);
271 if (toSkip->count(peer->id()) == 0 &&
272 peer->supportsFeature(
274 peer->publisherListSequence(publisherKey) < sequence)
279 <<
"Sent validator list for " <<
strHex(publisherKey)
280 <<
" with sequence " << sequence <<
" to "
281 << peer->getRemoteAddress().to_string() <<
" ("
282 << peer->id() <<
")";
285 peer->setPublisherListSequence(publisherKey, sequence);
301 boost::optional<uint256>
const& hash)
303 using namespace std::string_literals;
312 auto const result =
verify(list, pubKey,
manifest, blob, signature);
322 result, pubKey, publisher.available, publisher.sequence};
330 publisher.available =
true;
331 publisher.sequence = list[
"sequence"].
asUInt();
334 publisher.siteUri = std::move(siteUri);
336 publisher.rawBlob = blob;
337 publisher.rawSignature = signature;
338 publisher.rawVersion = version;
340 publisher.hash = *hash;
344 result, pubKey, publisher.available, publisher.sequence};
347 publisherList.
clear();
350 for (
auto const& val : newList)
352 if (val.isObject() && val.isMember(
"validation_public_key") &&
353 val[
"validation_public_key"].isString())
355 boost::optional<Blob>
const ret =
356 strUnHex(val[
"validation_public_key"].asString());
360 JLOG(
j_.
error()) <<
"Invalid node identity: "
361 << val[
"validation_public_key"].asString();
369 if (val.isMember(
"manifest") && val[
"manifest"].isString())
370 manifests.
push_back(val[
"manifest"].asString());
377 auto iNew = publisherList.
begin();
378 auto iOld = oldList.
begin();
379 while (iNew != publisherList.
end() || iOld != oldList.
end())
381 if (iOld == oldList.
end() ||
382 (iNew != publisherList.
end() && *iNew < *iOld))
389 iNew == publisherList.
end() ||
390 (iOld != oldList.
end() && *iOld < *iNew))
406 if (publisherList.
empty())
408 JLOG(
j_.
warn()) <<
"No validator keys included in valid list";
411 for (
auto const& valManifest : manifests)
418 <<
" contained untrusted validator manifest";
426 <<
" contained invalid validator manifest";
439 using namespace std::string_literals;
440 using namespace boost::filesystem;
441 using namespace boost::system::errc;
449 boost::system::error_code ec;
451 if (publisher.available)
456 auto const fullPath{canonical(filename, ec)};
460 auto size = file_size(fullPath, ec);
465 ec = make_error_code(no_such_file_or_directory);
471 #if _MSC_VER // MSVC: Windows paths need a leading / added
473 return fullPath.root_path() ==
"/"s ?
"file://" :
"file:///";
502 pubKey = m->masterKey;
503 auto const revoked = m->revoked();
516 auto const sig =
strUnHex(signature);
526 if (!r.
parse(data, list))
533 auto const sequence = list[
"sequence"].
asUInt();
568 boost::optional<PublicKey>
579 boost::optional<PublicKey>
611 JLOG(
j_.
debug()) <<
"Removing validator list for publisher "
614 for (
auto const& val : iList->second.list)
620 if (iVal->second <= 1)
626 iList->second.list.clear();
627 iList->second.available =
false;
639 boost::optional<TimeKeeper::time_point>
643 boost::optional<TimeKeeper::time_point> res{boost::none};
651 if (!res || p.second.expiration < *res)
652 res = p.second.expiration;
673 if (*when == TimeKeeper::time_point::max())
675 x[jss::expiration] =
"never";
676 x[jss::status] =
"active";
683 x[jss::status] =
"active";
685 x[jss::status] =
"expired";
690 x[jss::status] =
"unknown";
691 x[jss::expiration] =
"unknown";
701 for (
auto const& key : it->second.list)
710 if (local == p.first)
713 curr[jss::pubkey_publisher] =
strHex(p.first);
714 curr[jss::available] = p.second.available;
715 curr[jss::uri] = p.second.siteUri;
718 curr[jss::seq] =
static_cast<Json::UInt>(p.second.sequence);
719 curr[jss::expiration] =
to_string(p.second.expiration);
723 for (
auto const& key : p.second.list)
759 func(v.first,
trusted(v.first));
770 uint256 const& hash)> func)
const
789 boost::optional<Json::Value>
798 JLOG(
j_.
info()) <<
"Invalid requested validator list publisher key: "
812 value[
"manifest"] = iter->second.rawManifest;
813 value[
"blob"] = iter->second.rawBlob;
814 value[
"signature"] = iter->second.rawSignature;
815 value[
"version"] = iter->second.rawVersion;
827 if (!list.second.available)
870 <<
" as specified in the command line";
884 if (list.second.available &&
913 if (!trustChanges.
added.empty() || !trustChanges.
removed.empty())
923 <<
" listed validators eligible for inclusion in the trusted set";
927 JLOG(
j_.
debug()) <<
"Using quorum of " <<
quorum_ <<
" for new set of "
929 << trustChanges.
added.size() <<
" added, "
930 << trustChanges.
removed.size() <<
" removed)";
935 <<
" exceeds the number of trusted validators ("
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.
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.
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.
std::size_t calculateQuorum(std::size_t trusted, std::size_t seen)
Return quorum for trusted validator set.
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.
@ accepted
Manifest is valid.
Remembers manifests with the highest sequence number.
std::vector< std::string > loadLists()
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.