rippled
ValidatorList.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2015 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
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>
31 
32 #include <date/date.h>
33 
34 #include <cmath>
35 #include <mutex>
36 #include <shared_mutex>
37 
38 namespace ripple {
39 
42 {
43  switch (disposition)
44  {
46  return "accepted";
48  return "same_sequence";
50  return "unsupported_version";
52  return "untrusted";
54  return "stale";
56  return "invalid";
57  }
58  return "unknown";
59 }
60 
62 
64  ManifestCache& validatorManifests,
65  ManifestCache& publisherManifests,
66  TimeKeeper& timeKeeper,
67  std::string const& databasePath,
69  boost::optional<std::size_t> minimumQuorum)
70  : validatorManifests_(validatorManifests)
71  , publisherManifests_(publisherManifests)
72  , timeKeeper_(timeKeeper)
73  , dataPath_(databasePath)
74  , j_(j)
75  , quorum_(minimumQuorum.value_or(1)) // Genesis ledger quorum
76  , minimumQuorum_(minimumQuorum)
77 {
78 }
79 
80 bool
82  PublicKey const& localSigningKey,
83  std::vector<std::string> const& configKeys,
84  std::vector<std::string> const& publisherKeys)
85 {
86  static boost::regex const re(
87  "[[:space:]]*" // skip leading whitespace
88  "([[:alnum:]]+)" // node identity
89  "(?:" // begin optional comment block
90  "[[:space:]]+" // (skip all leading whitespace)
91  "(?:" // begin optional comment
92  "(.*[^[:space:]]+)" // the comment
93  "[[:space:]]*" // (skip all trailing whitespace)
94  ")?" // end optional comment
95  ")?" // end optional comment block
96  );
97 
99 
100  JLOG(j_.debug())
101  << "Loading configured trusted validator list publisher keys";
102 
103  std::size_t count = 0;
104  for (auto key : publisherKeys)
105  {
106  JLOG(j_.trace()) << "Processing '" << key << "'";
107 
108  auto const ret = strUnHex(key);
109 
110  if (!ret || !publicKeyType(makeSlice(*ret)))
111  {
112  JLOG(j_.error()) << "Invalid validator list publisher key: " << key;
113  return false;
114  }
115 
116  auto id = PublicKey(makeSlice(*ret));
117 
119  {
120  JLOG(j_.warn())
121  << "Configured validator list publisher key is revoked: "
122  << key;
123  continue;
124  }
125 
126  if (publisherLists_.count(id))
127  {
128  JLOG(j_.warn())
129  << "Duplicate validator list publisher key: " << key;
130  continue;
131  }
132 
133  publisherLists_[id].available = false;
134  ++count;
135  }
136 
137  JLOG(j_.debug()) << "Loaded " << count << " keys";
138 
139  localPubKey_ = validatorManifests_.getMasterKey(localSigningKey);
140 
141  // Treat local validator key as though it was listed in the config
142  if (localPubKey_.size())
143  keyListings_.insert({localPubKey_, 1});
144 
145  JLOG(j_.debug()) << "Loading configured validator keys";
146 
147  count = 0;
148  PublicKey local;
149  for (auto const& n : configKeys)
150  {
151  JLOG(j_.trace()) << "Processing '" << n << "'";
152 
153  boost::smatch match;
154 
155  if (!boost::regex_match(n, match, re))
156  {
157  JLOG(j_.error()) << "Malformed entry: '" << n << "'";
158  return false;
159  }
160 
161  auto const id = parseBase58<PublicKey>(TokenType::NodePublic, match[1]);
162 
163  if (!id)
164  {
165  JLOG(j_.error()) << "Invalid node identity: " << match[1];
166  return false;
167  }
168 
169  // Skip local key which was already added
170  if (*id == localPubKey_ || *id == localSigningKey)
171  continue;
172 
173  auto ret = keyListings_.insert({*id, 1});
174  if (!ret.second)
175  {
176  JLOG(j_.warn()) << "Duplicate node identity: " << match[1];
177  continue;
178  }
179  auto it = publisherLists_.emplace(
180  std::piecewise_construct,
181  std::forward_as_tuple(local),
183  // Config listed keys never expire
184  if (it.second)
185  it.first->second.expiration = TimeKeeper::time_point::max();
186  it.first->second.list.emplace_back(*id);
187  it.first->second.available = true;
188  ++count;
189  }
190 
191  JLOG(j_.debug()) << "Loaded " << count << " entries";
192 
193  return true;
194 }
195 
196 boost::filesystem::path
198 {
199  return dataPath_ / (filePrefix_ + strHex(pubKey));
200 }
201 
202 void
204  PublicKey const& pubKey,
205  PublisherList const& publisher)
206 {
207  if (dataPath_.empty())
208  return;
209 
210  boost::filesystem::path const filename = GetCacheFileName(pubKey);
211 
212  boost::system::error_code ec;
213 
215 
216  value["manifest"] = publisher.rawManifest;
217  value["blob"] = publisher.rawBlob;
218  value["signature"] = publisher.rawSignature;
219  value["version"] = publisher.rawVersion;
220 
221  writeFileContents(ec, filename, value.toStyledString());
222 
223  if (ec)
224  {
225  // Log and ignore any file I/O exceptions
226  JLOG(j_.error()) << "Problem writing " << filename << " " << ec.value()
227  << ": " << ec.message();
228  }
229 }
230 
233  std::string const& manifest,
234  std::string const& blob,
235  std::string const& signature,
236  std::uint32_t version,
237  std::string siteUri,
238  uint256 const& hash,
239  Overlay& overlay,
240  HashRouter& hashRouter)
241 {
242  auto const result =
243  applyList(manifest, blob, signature, version, std::move(siteUri), hash);
244  auto const disposition = result.disposition;
245 
246  bool broadcast = disposition == ListDisposition::accepted ||
247  disposition == ListDisposition::same_sequence;
248 
249  if (broadcast)
250  {
251  assert(result.available && result.publisherKey && result.sequence);
252  auto const toSkip = hashRouter.shouldRelay(hash);
253 
254  if (toSkip)
255  {
256  protocol::TMValidatorList msg;
257  msg.set_manifest(manifest);
258  msg.set_blob(blob);
259  msg.set_signature(signature);
260  msg.set_version(version);
261 
262  auto const& publisherKey = *result.publisherKey;
263  auto const sequence = *result.sequence;
264 
265  // Can't use overlay.foreach here because we need to modify
266  // the peer, and foreach provides a const&
267  auto message =
268  std::make_shared<Message>(msg, protocol::mtVALIDATORLIST);
269  for (auto& peer : overlay.getActivePeers())
270  {
271  if (toSkip->count(peer->id()) == 0 &&
272  peer->supportsFeature(
274  peer->publisherListSequence(publisherKey) < sequence)
275  {
276  peer->send(message);
277 
278  JLOG(j_.debug())
279  << "Sent validator list for " << strHex(publisherKey)
280  << " with sequence " << sequence << " to "
281  << peer->getRemoteAddress().to_string() << " ("
282  << peer->id() << ")";
283  // Don't send it next time.
284  hashRouter.addSuppressionPeer(hash, peer->id());
285  peer->setPublisherListSequence(publisherKey, sequence);
286  }
287  }
288  }
289  }
290 
291  return result;
292 }
293 
296  std::string const& manifest,
297  std::string const& blob,
298  std::string const& signature,
299  std::uint32_t version,
300  std::string siteUri,
301  boost::optional<uint256> const& hash)
302 {
303  using namespace std::string_literals;
304 
305  if (version != requiredListVersion)
307 
309 
310  Json::Value list;
311  PublicKey pubKey;
312  auto const result = verify(list, pubKey, manifest, blob, signature);
313  if (result != ListDisposition::accepted)
314  {
315  if (result == ListDisposition::same_sequence &&
316  publisherLists_.count(pubKey))
317  {
318  // We've seen this valid list already, so return
319  // what we know about it.
320  auto const& publisher = publisherLists_[pubKey];
321  return PublisherListStats{
322  result, pubKey, publisher.available, publisher.sequence};
323  }
324  return PublisherListStats{result};
325  }
326 
327  // Update publisher's list
328  Json::Value const& newList = list["validators"];
329  auto& publisher = publisherLists_[pubKey];
330  publisher.available = true;
331  publisher.sequence = list["sequence"].asUInt();
332  publisher.expiration = TimeKeeper::time_point{
333  TimeKeeper::duration{list["expiration"].asUInt()}};
334  publisher.siteUri = std::move(siteUri);
335  publisher.rawManifest = manifest;
336  publisher.rawBlob = blob;
337  publisher.rawSignature = signature;
338  publisher.rawVersion = version;
339  if (hash)
340  publisher.hash = *hash;
341  std::vector<PublicKey>& publisherList = publisher.list;
342 
343  PublisherListStats const applyResult{
344  result, pubKey, publisher.available, publisher.sequence};
345 
346  std::vector<PublicKey> oldList = publisherList;
347  publisherList.clear();
348  publisherList.reserve(newList.size());
349  std::vector<std::string> manifests;
350  for (auto const& val : newList)
351  {
352  if (val.isObject() && val.isMember("validation_public_key") &&
353  val["validation_public_key"].isString())
354  {
355  boost::optional<Blob> const ret =
356  strUnHex(val["validation_public_key"].asString());
357 
358  if (!ret || !publicKeyType(makeSlice(*ret)))
359  {
360  JLOG(j_.error()) << "Invalid node identity: "
361  << val["validation_public_key"].asString();
362  }
363  else
364  {
365  publisherList.push_back(
366  PublicKey(Slice{ret->data(), ret->size()}));
367  }
368 
369  if (val.isMember("manifest") && val["manifest"].isString())
370  manifests.push_back(val["manifest"].asString());
371  }
372  }
373 
374  // Update keyListings_ for added and removed keys
375  std::sort(publisherList.begin(), publisherList.end());
376 
377  auto iNew = publisherList.begin();
378  auto iOld = oldList.begin();
379  while (iNew != publisherList.end() || iOld != oldList.end())
380  {
381  if (iOld == oldList.end() ||
382  (iNew != publisherList.end() && *iNew < *iOld))
383  {
384  // Increment list count for added keys
385  ++keyListings_[*iNew];
386  ++iNew;
387  }
388  else if (
389  iNew == publisherList.end() ||
390  (iOld != oldList.end() && *iOld < *iNew))
391  {
392  // Decrement list count for removed keys
393  if (keyListings_[*iOld] <= 1)
394  keyListings_.erase(*iOld);
395  else
396  --keyListings_[*iOld];
397  ++iOld;
398  }
399  else
400  {
401  ++iNew;
402  ++iOld;
403  }
404  }
405 
406  if (publisherList.empty())
407  {
408  JLOG(j_.warn()) << "No validator keys included in valid list";
409  }
410 
411  for (auto const& valManifest : manifests)
412  {
413  auto m = deserializeManifest(base64_decode(valManifest));
414 
415  if (!m || !keyListings_.count(m->masterKey))
416  {
417  JLOG(j_.warn()) << "List for " << strHex(pubKey)
418  << " contained untrusted validator manifest";
419  continue;
420  }
421 
422  if (auto const r = validatorManifests_.applyManifest(std::move(*m));
424  {
425  JLOG(j_.warn()) << "List for " << strHex(pubKey)
426  << " contained invalid validator manifest";
427  }
428  }
429 
430  // Cache the validator list in a file
431  CacheValidatorFile(pubKey, publisher);
432 
433  return applyResult;
434 }
435 
438 {
439  using namespace std::string_literals;
440  using namespace boost::filesystem;
441  using namespace boost::system::errc;
442 
444 
446  sites.reserve(publisherLists_.size());
447  for (auto const& [pubKey, publisher] : publisherLists_)
448  {
449  boost::system::error_code ec;
450 
451  if (publisher.available)
452  continue;
453 
454  boost::filesystem::path const filename = GetCacheFileName(pubKey);
455 
456  auto const fullPath{canonical(filename, ec)};
457  if (ec)
458  continue;
459 
460  auto size = file_size(fullPath, ec);
461  if (!ec && !size)
462  {
463  // Treat an empty file as a missing file, because
464  // nobody else is going to write it.
465  ec = make_error_code(no_such_file_or_directory);
466  }
467  if (ec)
468  continue;
469 
470  std::string const prefix = [&fullPath]() {
471 #if _MSC_VER // MSVC: Windows paths need a leading / added
472  {
473  return fullPath.root_path() == "/"s ? "file://" : "file:///";
474  }
475 #else
476  {
477  (void)fullPath;
478  return "file://";
479  }
480 #endif
481  }();
482  sites.emplace_back(prefix + fullPath.string());
483  }
484 
485  // Then let the ValidatorSites do the rest of the work.
486  return sites;
487 }
488 
491  Json::Value& list,
492  PublicKey& pubKey,
493  std::string const& manifest,
494  std::string const& blob,
495  std::string const& signature)
496 {
498 
499  if (!m || !publisherLists_.count(m->masterKey))
501 
502  pubKey = m->masterKey;
503  auto const revoked = m->revoked();
504 
505  auto const result = publisherManifests_.applyManifest(std::move(*m));
506 
507  if (revoked && result == ManifestDisposition::accepted)
508  {
509  removePublisherList(pubKey);
510  publisherLists_.erase(pubKey);
511  }
512 
513  if (revoked || result == ManifestDisposition::invalid)
515 
516  auto const sig = strUnHex(signature);
517  auto const data = base64_decode(blob);
518  if (!sig ||
521  makeSlice(data),
522  makeSlice(*sig)))
524 
525  Json::Reader r;
526  if (!r.parse(data, list))
528 
529  if (list.isMember("sequence") && list["sequence"].isInt() &&
530  list.isMember("expiration") && list["expiration"].isInt() &&
531  list.isMember("validators") && list["validators"].isArray())
532  {
533  auto const sequence = list["sequence"].asUInt();
534  auto const expiration = TimeKeeper::time_point{
535  TimeKeeper::duration{list["expiration"].asUInt()}};
536  if (sequence < publisherLists_[pubKey].sequence ||
537  expiration <= timeKeeper_.now())
538  return ListDisposition::stale;
539  else if (sequence == publisherLists_[pubKey].sequence)
541  }
542  else
543  {
545  }
546 
548 }
549 
550 bool
551 ValidatorList::listed(PublicKey const& identity) const
552 {
554 
555  auto const pubKey = validatorManifests_.getMasterKey(identity);
556  return keyListings_.find(pubKey) != keyListings_.end();
557 }
558 
559 bool
560 ValidatorList::trusted(PublicKey const& identity) const
561 {
563 
564  auto const pubKey = validatorManifests_.getMasterKey(identity);
565  return trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end();
566 }
567 
568 boost::optional<PublicKey>
570 {
572 
573  auto const pubKey = validatorManifests_.getMasterKey(identity);
574  if (keyListings_.find(pubKey) != keyListings_.end())
575  return pubKey;
576  return boost::none;
577 }
578 
579 boost::optional<PublicKey>
581 {
583 
584  auto const pubKey = validatorManifests_.getMasterKey(identity);
585  if (trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end())
586  return pubKey;
587  return boost::none;
588 }
589 
590 bool
592 {
594  return identity.size() && publisherLists_.count(identity);
595 }
596 
597 PublicKey
599 {
601  return localPubKey_;
602 }
603 
604 bool
606 {
607  auto const iList = publisherLists_.find(publisherKey);
608  if (iList == publisherLists_.end())
609  return false;
610 
611  JLOG(j_.debug()) << "Removing validator list for publisher "
612  << strHex(publisherKey);
613 
614  for (auto const& val : iList->second.list)
615  {
616  auto const& iVal = keyListings_.find(val);
617  if (iVal == keyListings_.end())
618  continue;
619 
620  if (iVal->second <= 1)
621  keyListings_.erase(iVal);
622  else
623  --iVal->second;
624  }
625 
626  iList->second.list.clear();
627  iList->second.available = false;
628 
629  return true;
630 }
631 
634 {
636  return publisherLists_.size();
637 }
638 
639 boost::optional<TimeKeeper::time_point>
641 {
643  boost::optional<TimeKeeper::time_point> res{boost::none};
644  for (auto const& p : publisherLists_)
645  {
646  // Unfetched
647  if (p.second.expiration == TimeKeeper::time_point{})
648  return boost::none;
649 
650  // Earliest
651  if (!res || p.second.expiration < *res)
652  res = p.second.expiration;
653  }
654  return res;
655 }
656 
659 {
661 
663 
664  res[jss::validation_quorum] = static_cast<Json::UInt>(quorum());
665 
666  {
667  auto& x = (res[jss::validator_list] = Json::objectValue);
668 
669  x[jss::count] = static_cast<Json::UInt>(count());
670 
671  if (auto when = expires())
672  {
673  if (*when == TimeKeeper::time_point::max())
674  {
675  x[jss::expiration] = "never";
676  x[jss::status] = "active";
677  }
678  else
679  {
680  x[jss::expiration] = to_string(*when);
681 
682  if (*when > timeKeeper_.now())
683  x[jss::status] = "active";
684  else
685  x[jss::status] = "expired";
686  }
687  }
688  else
689  {
690  x[jss::status] = "unknown";
691  x[jss::expiration] = "unknown";
692  }
693  }
694 
695  // Local static keys
696  PublicKey local;
697  Json::Value& jLocalStaticKeys =
698  (res[jss::local_static_keys] = Json::arrayValue);
699  if (auto it = publisherLists_.find(local); it != publisherLists_.end())
700  {
701  for (auto const& key : it->second.list)
702  jLocalStaticKeys.append(toBase58(TokenType::NodePublic, key));
703  }
704 
705  // Publisher lists
706  Json::Value& jPublisherLists =
707  (res[jss::publisher_lists] = Json::arrayValue);
708  for (auto const& p : publisherLists_)
709  {
710  if (local == p.first)
711  continue;
712  Json::Value& curr = jPublisherLists.append(Json::objectValue);
713  curr[jss::pubkey_publisher] = strHex(p.first);
714  curr[jss::available] = p.second.available;
715  curr[jss::uri] = p.second.siteUri;
716  if (p.second.expiration != TimeKeeper::time_point{})
717  {
718  curr[jss::seq] = static_cast<Json::UInt>(p.second.sequence);
719  curr[jss::expiration] = to_string(p.second.expiration);
720  curr[jss::version] = requiredListVersion;
721  }
722  Json::Value& keys = (curr[jss::list] = Json::arrayValue);
723  for (auto const& key : p.second.list)
724  {
726  }
727  }
728 
729  // Trusted validator keys
730  Json::Value& jValidatorKeys =
731  (res[jss::trusted_validator_keys] = Json::arrayValue);
732  for (auto const& k : trustedMasterKeys_)
733  {
734  jValidatorKeys.append(toBase58(TokenType::NodePublic, k));
735  }
736 
737  // signing keys
738  Json::Value& jSigningKeys = (res[jss::signing_keys] = Json::objectValue);
739  validatorManifests_.for_each_manifest([&jSigningKeys,
740  this](Manifest const& manifest) {
741  auto it = keyListings_.find(manifest.masterKey);
742  if (it != keyListings_.end())
743  {
744  jSigningKeys[toBase58(TokenType::NodePublic, manifest.masterKey)] =
746  }
747  });
748 
749  return res;
750 }
751 
752 void
754  std::function<void(PublicKey const&, bool)> func) const
755 {
757 
758  for (auto const& v : keyListings_)
759  func(v.first, trusted(v.first));
760 }
761 
762 void
764  std::string const& manifest,
765  std::string const& blob,
766  std::string const& signature,
767  std::uint32_t version,
768  PublicKey const& pubKey,
769  std::size_t sequence,
770  uint256 const& hash)> func) const
771 {
773 
774  for (auto const& [key, pl] : publisherLists_)
775  {
776  if (!pl.available)
777  continue;
778  func(
779  pl.rawManifest,
780  pl.rawBlob,
781  pl.rawSignature,
782  pl.rawVersion,
783  key,
784  pl.sequence,
785  pl.hash);
786  }
787 }
788 
789 boost::optional<Json::Value>
790 ValidatorList::getAvailable(boost::beast::string_view const& pubKey)
791 {
793 
794  auto const keyBlob = strViewUnHex(pubKey);
795 
796  if (!keyBlob || !publicKeyType(makeSlice(*keyBlob)))
797  {
798  JLOG(j_.info()) << "Invalid requested validator list publisher key: "
799  << pubKey;
800  return {};
801  }
802 
803  auto id = PublicKey(makeSlice(*keyBlob));
804 
805  auto iter = publisherLists_.find(id);
806 
807  if (iter == publisherLists_.end() || !iter->second.available)
808  return {};
809 
811 
812  value["manifest"] = iter->second.rawManifest;
813  value["blob"] = iter->second.rawBlob;
814  value["signature"] = iter->second.rawSignature;
815  value["version"] = iter->second.rawVersion;
816 
817  return value;
818 }
819 
822 {
823  // Do not use achievable quorum until lists from all configured
824  // publishers are available
825  for (auto const& list : publisherLists_)
826  {
827  if (!list.second.available)
829  }
830 
831  // Use an 80% quorum to balance fork safety, liveness, and required UNL
832  // overlap.
833  //
834  // Theorem 8 of the Analysis of the XRP Ledger Consensus Protocol
835  // (https://arxiv.org/abs/1802.07242) says:
836  // XRP LCP guarantees fork safety if Oi,j > nj/2 + ni − qi + ti,j for
837  // every pair of nodes Pi, Pj.
838  //
839  // ni: size of Pi's UNL
840  // nj: size of Pj's UNL
841  // Oi,j: number of validators in both UNLs
842  // qi: validation quorum for Pi's UNL
843  // ti, tj: maximum number of allowed Byzantine faults in Pi and Pj's UNLs
844  // ti,j: min{ti, tj, Oi,j}
845  //
846  // Assume ni < nj, meaning and ti,j = ti
847  //
848  // For qi = .8*ni, we make ti <= .2*ni
849  // (We could make ti lower and tolerate less UNL overlap. However in order
850  // to prioritize safety over liveness, we need ti >= ni - qi)
851  //
852  // An 80% quorum allows two UNLs to safely have < .2*ni unique validators
853  // between them:
854  //
855  // pi = ni - Oi,j
856  // pj = nj - Oi,j
857  //
858  // Oi,j > nj/2 + ni − qi + ti,j
859  // ni - pi > (ni - pi + pj)/2 + ni − .8*ni + .2*ni
860  // pi + pj < .2*ni
861  auto quorum = static_cast<std::size_t>(std::ceil(trusted * 0.8f));
862 
863  // Use lower quorum specified via command line if the normal quorum appears
864  // unreachable based on the number of recently received validations.
865  if (minimumQuorum_ && *minimumQuorum_ < quorum && seen < quorum)
866  {
868 
869  JLOG(j_.warn()) << "Using unsafe quorum of " << quorum
870  << " as specified in the command line";
871  }
872 
873  return quorum;
874 }
875 
878 {
880 
881  // Remove any expired published lists
882  for (auto const& list : publisherLists_)
883  {
884  if (list.second.available &&
885  list.second.expiration <= timeKeeper_.now())
886  removePublisherList(list.first);
887  }
888 
889  TrustChanges trustChanges;
890 
891  auto it = trustedMasterKeys_.cbegin();
892  while (it != trustedMasterKeys_.cend())
893  {
894  if (!keyListings_.count(*it) || validatorManifests_.revoked(*it))
895  {
896  trustChanges.removed.insert(calcNodeID(*it));
897  it = trustedMasterKeys_.erase(it);
898  }
899  else
900  {
901  ++it;
902  }
903  }
904 
905  for (auto const& val : keyListings_)
906  {
907  if (!validatorManifests_.revoked(val.first) &&
908  trustedMasterKeys_.emplace(val.first).second)
909  trustChanges.added.insert(calcNodeID(val.first));
910  }
911 
912  // If there were any changes, we need to update the ephemeral signing keys:
913  if (!trustChanges.added.empty() || !trustChanges.removed.empty())
914  {
915  trustedSigningKeys_.clear();
916 
917  for (auto const& k : trustedMasterKeys_)
919  }
920 
921  JLOG(j_.debug())
922  << trustedMasterKeys_.size() << " of " << keyListings_.size()
923  << " listed validators eligible for inclusion in the trusted set";
924 
925  quorum_ = calculateQuorum(trustedMasterKeys_.size(), seenValidators.size());
926 
927  JLOG(j_.debug()) << "Using quorum of " << quorum_ << " for new set of "
928  << trustedMasterKeys_.size() << " trusted validators ("
929  << trustChanges.added.size() << " added, "
930  << trustChanges.removed.size() << " removed)";
931 
932  if (trustedMasterKeys_.size() < quorum_)
933  {
934  JLOG(j_.warn()) << "New quorum of " << quorum_
935  << " exceeds the number of trusted validators ("
936  << trustedMasterKeys_.size() << ")";
937  }
938 
939  return trustChanges;
940 }
941 
942 } // namespace ripple
Json::Value::isInt
bool isInt() const
Definition: json_value.cpp:979
ripple::ValidatorList::getListedKey
boost::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
Definition: ValidatorList.cpp:569
ripple::ValidatorList::validatorManifests_
ManifestCache & validatorManifests_
Definition: ValidatorList.h:136
ripple::makeSlice
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)
Definition: Slice.h:194
ripple::ValidatorList::for_each_listed
void for_each_listed(std::function< void(PublicKey const &, bool)> func) const
Invokes the callback once for every listed validation public key.
Definition: ValidatorList.cpp:753
ripple::HashRouter::addSuppressionPeer
bool addSuppressionPeer(uint256 const &key, PeerShortID peer)
Definition: HashRouter.cpp:51
ripple::ValidatorList::localPublicKey
PublicKey localPublicKey() const
Returns local validator public key.
Definition: ValidatorList.cpp:598
std::string
STL class.
ripple::ListDisposition
ListDisposition
Definition: ValidatorList.h:42
ripple::ManifestCache::getMasterKey
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
Definition: app/misc/impl/Manifest.cpp:301
ripple::calcNodeID
NodeID calcNodeID(PublicKey const &pk)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:299
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::publicKeyType
boost::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:203
ripple::ValidatorList::PublisherList::rawSignature
std::string rawSignature
Definition: ValidatorList.h:131
ripple::TrustChanges
Changes in trusted nodes after updating validator list.
Definition: ValidatorList.h:67
ripple::Manifest
Definition: Manifest.h:78
ripple::ListDisposition::stale
@ stale
Trusted publisher key, but seq is too old.
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:43
ripple::ValidatorList::publisherLists_
hash_map< PublicKey, PublisherList > publisherLists_
Definition: ValidatorList.h:147
std::unordered_set
STL class.
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
std::vector::reserve
T reserve(T... args)
ripple::ValidatorList::getAvailable
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.
Definition: ValidatorList.cpp:790
ripple::HashPrefix::manifest
@ manifest
Manifest.
ripple::ValidatorList::GetCacheFileName
boost::filesystem::path GetCacheFileName(PublicKey const &pubKey)
Get the filename used for caching UNLs.
Definition: ValidatorList.cpp:197
Json::UInt
unsigned int UInt
Definition: json_forwards.h:27
std::vector< std::string >
std::unordered_set::size
T size(T... args)
ripple::ValidatorList::PublisherList::rawManifest
std::string rawManifest
Definition: ValidatorList.h:129
ripple::ValidatorList::trustedPublisher
bool trustedPublisher(PublicKey const &identity) const
Returns true if public key is a trusted publisher.
Definition: ValidatorList.cpp:591
ripple::ValidatorList::PublisherListStats
Describes the result of processing a Validator List (UNL), including some of the information from the...
Definition: ValidatorList.h:181
ripple::ValidatorList::filePrefix_
static const std::string filePrefix_
Definition: ValidatorList.h:164
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:29
ripple::ValidatorList::updateTrusted
TrustChanges updateTrusted(hash_set< NodeID > const &seenValidators)
Update trusted nodes.
Definition: ValidatorList.cpp:877
ripple::ValidatorList::j_
const beast::Journal j_
Definition: ValidatorList.h:140
ripple::Slice::data
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition: Slice.h:87
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::ValidatorList::verify
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.
Definition: ValidatorList.cpp:490
ripple::strUnHex
boost::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Definition: StringUtilities.h:72
std::function
Json::Value::toStyledString
std::string toStyledString() const
Definition: json_value.cpp:1039
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
Json::Reader
Unserialize a JSON document into a Value.
Definition: json_reader.h:36
cmath
std::sort
T sort(T... args)
ripple::HashRouter
Routing table for objects identified by hash.
Definition: HashRouter.h:52
ripple::ValidatorList::mutex_
std::shared_timed_mutex mutex_
Definition: ValidatorList.h:141
std::vector::clear
T clear(T... args)
std::vector::push_back
T push_back(T... args)
ripple::ValidatorList::ValidatorList
ValidatorList(ManifestCache &validatorManifests, ManifestCache &publisherManifests, TimeKeeper &timeKeeper, std::string const &databasePath, beast::Journal j, boost::optional< std::size_t > minimumQuorum=boost::none)
Definition: ValidatorList.cpp:63
ripple::ValidatorList::getTrustedKey
boost::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
Definition: ValidatorList.cpp:580
ripple::verify
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical)
Verify a signature on a message.
Definition: PublicKey.cpp:268
ripple::base_uint< 256 >
ripple::ValidatorList::CacheValidatorFile
void CacheValidatorFile(PublicKey const &pubKey, PublisherList const &publisher)
Write a JSON UNL to a cache file.
Definition: ValidatorList.cpp:203
ripple::ValidatorList::calculateQuorum
std::size_t calculateQuorum(std::size_t trusted, std::size_t seen)
Return quorum for trusted validator set.
Definition: ValidatorList.cpp:821
ripple::ValidatorList::PublisherList::rawVersion
std::uint32_t rawVersion
Definition: ValidatorList.h:132
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
ripple::ValidatorList::dataPath_
const boost::filesystem::path dataPath_
Definition: ValidatorList.h:139
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::ValidatorList::applyList
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.
Definition: ValidatorList.cpp:295
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::PublicKey::size
std::size_t size() const noexcept
Definition: PublicKey.h:87
ripple::TrustChanges::removed
hash_set< NodeID > removed
Definition: ValidatorList.h:72
ripple::ValidatorList::minimumQuorum_
boost::optional< std::size_t > minimumQuorum_
Definition: ValidatorList.h:144
std::unique_lock
STL class.
ripple::ValidatorList::publisherManifests_
ManifestCache & publisherManifests_
Definition: ValidatorList.h:137
ripple::ManifestCache::revoked
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
Definition: app/misc/impl/Manifest.cpp:349
ripple::ValidatorList::timeKeeper_
TimeKeeper & timeKeeper_
Definition: ValidatorList.h:138
ripple::ValidatorList::listed
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
Definition: ValidatorList.cpp:551
ripple::writeFileContents
void writeFileContents(boost::system::error_code &ec, boost::filesystem::path const &destPath, std::string const &contents)
Definition: FileUtilities.cpp:66
ripple::base64_decode
std::string base64_decode(std::string const &data)
Definition: base64.cpp:245
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
ripple::ManifestCache::for_each_manifest
void for_each_manifest(Function &&f) const
Invokes the callback once for every populated manifest.
Definition: Manifest.h:369
ripple::Overlay::getActivePeers
virtual PeerSequence getActivePeers() const =0
Returns a sequence representing the current list of peers.
ripple::ListDisposition::untrusted
@ untrusted
List signed by untrusted publisher key.
ripple::ManifestCache::getSigningKey
PublicKey getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
Definition: app/misc/impl/Manifest.cpp:289
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::ValidatorList::requiredListVersion
static constexpr std::uint32_t requiredListVersion
Definition: ValidatorList.h:163
ripple::ValidatorList::applyListAndBroadcast
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.
Definition: ValidatorList.cpp:232
std::uint32_t
ripple::HashRouter::shouldRelay
boost::optional< std::set< PeerShortID > > shouldRelay(uint256 const &key)
Determines whether the hashed item should be relayed.
Definition: HashRouter.cpp:112
std::forward_as_tuple
T forward_as_tuple(T... args)
ripple::TimeKeeper
Manages various times used by the server.
Definition: TimeKeeper.h:32
ripple::ListDisposition::unsupported_version
@ unsupported_version
List version is not supported.
std::ceil
T ceil(T... args)
ripple::ManifestDisposition::invalid
@ invalid
Timely, but invalid signature.
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
ripple::ValidatorList::PublisherList::rawBlob
std::string rawBlob
Definition: ValidatorList.h:130
ripple::ManifestDisposition::accepted
@ accepted
Manifest is valid.
ripple::ValidatorList::localPubKey_
PublicKey localPubKey_
Definition: ValidatorList.h:160
ripple::ManifestCache
Remembers manifests with the highest sequence number.
Definition: Manifest.h:209
ripple::ValidatorList::loadLists
std::vector< std::string > loadLists()
Definition: ValidatorList.cpp:437
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::ValidatorList::trustedSigningKeys_
hash_set< PublicKey > trustedSigningKeys_
Definition: ValidatorList.h:158
ripple::deserializeManifest
boost::optional< Manifest > deserializeManifest(Slice s)
Constructs Manifest from serialized string.
Definition: app/misc/impl/Manifest.cpp:38
ripple::ValidatorList::load
bool load(PublicKey const &localSigningKey, std::vector< std::string > const &configKeys, std::vector< std::string > const &publisherKeys)
Load configured trusted keys.
Definition: ValidatorList.cpp:81
ripple::ValidatorList::for_each_available
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.
Definition: ValidatorList.cpp:763
ripple::Overlay
Manages the set of connected peers.
Definition: Overlay.h:52
ripple::ListDisposition::same_sequence
@ same_sequence
Same sequence as current list.
std::vector::begin
T begin(T... args)
ripple::strViewUnHex
boost::optional< Blob > strViewUnHex(boost::string_view const &strSrc)
Definition: StringUtilities.h:118
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
ripple::ListDisposition::invalid
@ invalid
Invalid format or signature.
Json::Reader::parse
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:73
ripple::TimeKeeper::now
virtual time_point now() const override=0
Returns the estimate of wall time, in network time.
ripple::TrustChanges::added
hash_set< NodeID > added
Definition: ValidatorList.h:71
std::vector::empty
T empty(T... args)
ripple::TokenType::NodePublic
@ NodePublic
mutex
ripple::ValidatorList::getJson
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
Definition: ValidatorList.cpp:658
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t
ripple::ProtocolFeature::ValidatorListPropagation
@ ValidatorListPropagation
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:67
std::vector::end
T end(T... args)
std::numeric_limits::max
T max(T... args)
ripple::ValidatorList::expires
boost::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
Definition: ValidatorList.cpp:640
ripple::ValidatorList::trusted
bool trusted(PublicKey const &identity) const
Returns true if public key is trusted.
Definition: ValidatorList.cpp:560
ripple::ValidatorList::trustedMasterKeys_
hash_set< PublicKey > trustedMasterKeys_
Definition: ValidatorList.h:153
ripple::ValidatorList::count
std::size_t count() const
Return the number of configured validator list sites.
Definition: ValidatorList.cpp:633
ripple::ManifestCache::applyManifest
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
Definition: app/misc/impl/Manifest.cpp:361
shared_mutex
beast::abstract_clock< NetClock >::time_point
typename NetClock ::time_point time_point
Definition: abstract_clock.h:63
ripple::ValidatorList::keyListings_
hash_map< PublicKey, std::size_t > keyListings_
Definition: ValidatorList.h:150
ripple::ListDisposition::accepted
@ accepted
List is valid.
ripple::ValidatorList::quorum_
std::atomic< std::size_t > quorum_
Definition: ValidatorList.h:143
beast::abstract_clock< NetClock >::duration
typename NetClock ::duration duration
Definition: abstract_clock.h:62
std::shared_lock
STL class.
ripple::ValidatorList::PublisherList
Definition: ValidatorList.h:120
ripple::ValidatorList::quorum
std::size_t quorum() const
Get quorum value for current trusted key set.
Definition: ValidatorList.h:338
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::ValidatorList::removePublisherList
bool removePublisherList(PublicKey const &publisherKey)
Stop trusting publisher's list of keys.
Definition: ValidatorList.cpp:605