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/NetworkOPs.h>
22 #include <ripple/app/misc/ValidatorList.h>
23 #include <ripple/basics/FileUtilities.h>
24 #include <ripple/basics/Slice.h>
25 #include <ripple/basics/StringUtilities.h>
26 #include <ripple/basics/base64.h>
27 #include <ripple/consensus/ConsensusParms.h>
28 #include <ripple/json/json_reader.h>
29 #include <ripple/overlay/Overlay.h>
30 #include <ripple/protocol/STValidation.h>
31 #include <ripple/protocol/digest.h>
32 #include <ripple/protocol/jss.h>
33 #include <ripple/protocol/messages.h>
34 #include <boost/regex.hpp>
35 
36 #include <cmath>
37 #include <mutex>
38 #include <numeric>
39 #include <shared_mutex>
40 
41 namespace ripple {
42 
45 {
46  switch (disposition)
47  {
49  return "accepted";
51  return "expired";
53  return "same_sequence";
55  return "pending";
57  return "known_sequence";
59  return "unsupported_version";
61  return "untrusted";
63  return "stale";
65  return "invalid";
66  }
67  return "unknown";
68 }
69 
71 {
72  ++dispositions[d];
73 }
74 
77  PublicKey key,
78  PublisherStatus stat,
79  std::size_t seq)
80  : publisherKey(key), status(stat), sequence(seq)
81 {
82  ++dispositions[d];
83 }
84 
87 {
88  return dispositions.empty() ? ListDisposition::invalid
89  : dispositions.begin()->first;
90 }
91 
94 {
95  return dispositions.empty() ? ListDisposition::invalid
96  : dispositions.rbegin()->first;
97 }
98 
99 void
101  PublisherListStats const& src)
102 {
103  for (auto const& [disp, count] : src.dispositions)
104  {
105  dispositions[disp] += count;
106  }
107 }
108 
110  std::shared_ptr<Message> const& message_,
111  uint256 hash_,
112  std::size_t num_)
113  : message(message_), hash(hash_), numVLs(num_)
114 {
115 }
116 
117 const std::string ValidatorList::filePrefix_ = "cache.";
118 
120  ManifestCache& validatorManifests,
121  ManifestCache& publisherManifests,
122  TimeKeeper& timeKeeper,
123  std::string const& databasePath,
124  beast::Journal j,
125  std::optional<std::size_t> minimumQuorum)
126  : validatorManifests_(validatorManifests)
127  , publisherManifests_(publisherManifests)
128  , timeKeeper_(timeKeeper)
129  , dataPath_(databasePath)
130  , j_(j)
131  , quorum_(minimumQuorum.value_or(1)) // Genesis ledger quorum
132  , minimumQuorum_(minimumQuorum)
133 {
134 }
135 
136 bool
138  PublicKey const& localSigningKey,
139  std::vector<std::string> const& configKeys,
140  std::vector<std::string> const& publisherKeys)
141 {
142  static boost::regex const re(
143  "[[:space:]]*" // skip leading whitespace
144  "([[:alnum:]]+)" // node identity
145  "(?:" // begin optional comment block
146  "[[:space:]]+" // (skip all leading whitespace)
147  "(?:" // begin optional comment
148  "(.*[^[:space:]]+)" // the comment
149  "[[:space:]]*" // (skip all trailing whitespace)
150  ")?" // end optional comment
151  ")?" // end optional comment block
152  );
153 
154  std::lock_guard lock{mutex_};
155 
156  JLOG(j_.debug())
157  << "Loading configured trusted validator list publisher keys";
158 
159  std::size_t count = 0;
160  for (auto key : publisherKeys)
161  {
162  JLOG(j_.trace()) << "Processing '" << key << "'";
163 
164  auto const ret = strUnHex(key);
165 
166  if (!ret || !publicKeyType(makeSlice(*ret)))
167  {
168  JLOG(j_.error()) << "Invalid validator list publisher key: " << key;
169  return false;
170  }
171 
172  auto id = PublicKey(makeSlice(*ret));
173  auto status = PublisherStatus::unavailable;
174 
176  {
177  JLOG(j_.warn())
178  << "Configured validator list publisher key is revoked: "
179  << key;
180  status = PublisherStatus::revoked;
181  }
182 
183  if (publisherLists_.count(id))
184  {
185  JLOG(j_.warn())
186  << "Duplicate validator list publisher key: " << key;
187  continue;
188  }
189 
190  publisherLists_[id].status = status;
191  ++count;
192  }
193 
194  JLOG(j_.debug()) << "Loaded " << count << " keys";
195 
196  localPubKey_ = validatorManifests_.getMasterKey(localSigningKey);
197 
198  // Treat local validator key as though it was listed in the config
199  if (localPubKey_.size())
200  keyListings_.insert({localPubKey_, 1});
201 
202  JLOG(j_.debug()) << "Loading configured validator keys";
203 
204  count = 0;
205  for (auto const& n : configKeys)
206  {
207  JLOG(j_.trace()) << "Processing '" << n << "'";
208 
209  boost::smatch match;
210 
211  if (!boost::regex_match(n, match, re))
212  {
213  JLOG(j_.error()) << "Malformed entry: '" << n << "'";
214  return false;
215  }
216 
217  auto const id = parseBase58<PublicKey>(TokenType::NodePublic, match[1]);
218 
219  if (!id)
220  {
221  JLOG(j_.error()) << "Invalid node identity: " << match[1];
222  return false;
223  }
224 
225  // Skip local key which was already added
226  if (*id == localPubKey_ || *id == localSigningKey)
227  continue;
228 
229  auto ret = keyListings_.insert({*id, 1});
230  if (!ret.second)
231  {
232  JLOG(j_.warn()) << "Duplicate node identity: " << match[1];
233  continue;
234  }
235  auto [it, inserted] = publisherLists_.emplace();
236  // Config listed keys never expire
237  auto& current = it->second.current;
238  if (inserted)
239  current.validUntil = TimeKeeper::time_point::max();
240  current.list.emplace_back(*id);
241  it->second.status = PublisherStatus::available;
242  ++count;
243  }
244 
245  JLOG(j_.debug()) << "Loaded " << count << " entries";
246 
247  return true;
248 }
249 
250 boost::filesystem::path
253  PublicKey const& pubKey) const
254 {
255  return dataPath_ / (filePrefix_ + strHex(pubKey));
256 }
257 
258 // static
261  std::string const& pubKey,
262  ValidatorList::PublisherListCollection const& pubCollection,
263  beast::Journal j)
264 {
265  return buildFileData(pubKey, pubCollection, {}, j);
266 }
267 
268 // static
271  std::string const& pubKey,
272  ValidatorList::PublisherListCollection const& pubCollection,
273  std::optional<std::uint32_t> forceVersion,
274  beast::Journal j)
275 {
277 
278  assert(pubCollection.rawVersion == 2 || pubCollection.remaining.empty());
279  auto const effectiveVersion =
280  forceVersion ? *forceVersion : pubCollection.rawVersion;
281 
282  value[jss::manifest] = pubCollection.rawManifest;
283  value[jss::version] = effectiveVersion;
284  value[jss::public_key] = pubKey;
285 
286  switch (effectiveVersion)
287  {
288  case 1: {
289  auto const& current = pubCollection.current;
290  value[jss::blob] = current.rawBlob;
291  value[jss::signature] = current.rawSignature;
292  // This is only possible if "downgrading" a v2 UNL to v1, for
293  // example for the /vl/ endpoint.
294  if (current.rawManifest &&
295  *current.rawManifest != pubCollection.rawManifest)
296  value[jss::manifest] = *current.rawManifest;
297  break;
298  }
299  case 2: {
301 
302  auto add = [&blobs, &outerManifest = pubCollection.rawManifest](
303  PublisherList const& pubList) {
304  auto& blob = blobs.append(Json::objectValue);
305  blob[jss::blob] = pubList.rawBlob;
306  blob[jss::signature] = pubList.rawSignature;
307  if (pubList.rawManifest &&
308  *pubList.rawManifest != outerManifest)
309  blob[jss::manifest] = *pubList.rawManifest;
310  };
311 
312  add(pubCollection.current);
313  for (auto const& [_, pending] : pubCollection.remaining)
314  {
315  (void)_;
316  add(pending);
317  }
318 
319  value[jss::blobs_v2] = std::move(blobs);
320  break;
321  }
322  default:
323  JLOG(j.trace())
324  << "Invalid VL version provided: " << effectiveVersion;
325  value = Json::nullValue;
326  }
327 
328  return value;
329 }
330 
331 void
333  ValidatorList::lock_guard const& lock,
334  PublicKey const& pubKey) const
335 {
336  if (dataPath_.empty())
337  return;
338 
339  boost::filesystem::path const filename = getCacheFileName(lock, pubKey);
340 
341  boost::system::error_code ec;
342 
343  Json::Value value =
344  buildFileData(strHex(pubKey), publisherLists_.at(pubKey), j_);
345  // rippled should be the only process writing to this file, so
346  // if it ever needs to be read, it is not expected to change externally, so
347  // delay the refresh as long as possible: 24 hours. (See also
348  // `ValidatorSite::missingSite()`)
349  value[jss::refresh_interval] = 24 * 60;
350 
351  writeFileContents(ec, filename, value.toStyledString());
352 
353  if (ec)
354  {
355  // Log and ignore any file I/O exceptions
356  JLOG(j_.error()) << "Problem writing " << filename << " " << ec.value()
357  << ": " << ec.message();
358  }
359 }
360 
361 // static
364 {
366  switch (version)
367  {
368  case 1: {
369  if (!body.isMember(jss::blob) || !body[jss::blob].isString() ||
370  !body.isMember(jss::signature) ||
371  !body[jss::signature].isString() ||
372  // If the v2 field is present, the VL is malformed
373  body.isMember(jss::blobs_v2))
374  return {};
375  ValidatorBlobInfo& info = result.emplace_back();
376  info.blob = body[jss::blob].asString();
377  info.signature = body[jss::signature].asString();
378  assert(result.size() == 1);
379  return result;
380  }
381  // Treat unknown versions as if they're the latest version. This
382  // will likely break a bunch of unit tests each time we introduce a
383  // new version, so don't do it casually. Note that the version is
384  // validated elsewhere.
385  case 2:
386  default: {
387  if (!body.isMember(jss::blobs_v2) ||
388  !body[jss::blobs_v2].isArray() ||
389  body[jss::blobs_v2].size() > maxSupportedBlobs ||
390  // If any of the v1 fields are present, the VL is malformed
391  body.isMember(jss::blob) || body.isMember(jss::signature))
392  return {};
393  auto const& blobs = body[jss::blobs_v2];
394  result.reserve(blobs.size());
395  for (auto const& blobInfo : blobs)
396  {
397  if (!blobInfo.isObject() ||
398  !blobInfo.isMember(jss::signature) ||
399  !blobInfo[jss::signature].isString() ||
400  !blobInfo.isMember(jss::blob) ||
401  !blobInfo[jss::blob].isString())
402  return {};
403  ValidatorBlobInfo& info = result.emplace_back();
404  info.blob = blobInfo[jss::blob].asString();
405  info.signature = blobInfo[jss::signature].asString();
406  if (blobInfo.isMember(jss::manifest))
407  {
408  if (!blobInfo[jss::manifest].isString())
409  return {};
410  info.manifest = blobInfo[jss::manifest].asString();
411  }
412  }
413  assert(result.size() == blobs.size());
414  return result;
415  }
416  }
417 }
418 
419 // static
421 ValidatorList::parseBlobs(protocol::TMValidatorList const& body)
422 {
423  return {{body.blob(), body.signature(), {}}};
424 }
425 
426 // static
428 ValidatorList::parseBlobs(protocol::TMValidatorListCollection const& body)
429 {
430  if (body.blobs_size() > maxSupportedBlobs)
431  return {};
433  result.reserve(body.blobs_size());
434  for (auto const& blob : body.blobs())
435  {
436  ValidatorBlobInfo& info = result.emplace_back();
437  info.blob = blob.blob();
438  info.signature = blob.signature();
439  if (blob.has_manifest())
440  {
441  info.manifest = blob.manifest();
442  }
443  }
444  assert(result.size() == body.blobs_size());
445  return result;
446 }
447 
451  protocol::TMValidatorListCollection const& largeMsg,
452  std::size_t maxSize,
453  std::size_t begin,
454  std::size_t end);
455 
459  protocol::TMValidatorListCollection const& largeMsg,
460  std::size_t maxSize,
461  std::size_t begin = 0,
462  std::size_t end = 0)
463 {
464  if (begin == 0 && end == 0)
465  end = largeMsg.blobs_size();
466  assert(begin < end);
467  if (end <= begin)
468  return 0;
469 
470  auto mid = (begin + end) / 2;
471  // The parts function will do range checking
472  // Use two separate calls to ensure deterministic order
473  auto result = splitMessageParts(messages, largeMsg, maxSize, begin, mid);
474  return result + splitMessageParts(messages, largeMsg, maxSize, mid, end);
475 }
476 
480  protocol::TMValidatorListCollection const& largeMsg,
481  std::size_t maxSize,
482  std::size_t begin,
483  std::size_t end)
484 {
485  if (end <= begin)
486  return 0;
487  if (end - begin == 1)
488  {
489  protocol::TMValidatorList smallMsg;
490  smallMsg.set_version(1);
491  smallMsg.set_manifest(largeMsg.manifest());
492 
493  auto const& blob = largeMsg.blobs(begin);
494  smallMsg.set_blob(blob.blob());
495  smallMsg.set_signature(blob.signature());
496  // This is only possible if "downgrading" a v2 UNL to v1.
497  if (blob.has_manifest())
498  smallMsg.set_manifest(blob.manifest());
499 
500  assert(Message::totalSize(smallMsg) <= maximiumMessageSize);
501 
502  messages.emplace_back(
503  std::make_shared<Message>(smallMsg, protocol::mtVALIDATORLIST),
504  sha512Half(smallMsg),
505  1);
506  return messages.back().numVLs;
507  }
508  else
509  {
511  smallMsg.emplace();
512  smallMsg->set_version(largeMsg.version());
513  smallMsg->set_manifest(largeMsg.manifest());
514 
515  for (std::size_t i = begin; i < end; ++i)
516  {
517  *smallMsg->add_blobs() = largeMsg.blobs(i);
518  }
519 
520  if (Message::totalSize(*smallMsg) > maxSize)
521  {
522  // free up the message space
523  smallMsg.reset();
524  return splitMessage(messages, largeMsg, maxSize, begin, end);
525  }
526  else
527  {
528  messages.emplace_back(
529  std::make_shared<Message>(
530  *smallMsg, protocol::mtVALIDATORLISTCOLLECTION),
531  sha512Half(*smallMsg),
532  smallMsg->blobs_size());
533  return messages.back().numVLs;
534  }
535  }
536  return 0;
537 }
538 
539 // Build a v1 protocol message using only the current VL
543  std::uint32_t rawVersion,
544  std::string const& rawManifest,
545  ValidatorBlobInfo const& currentBlob,
546  std::size_t maxSize)
547 {
548  assert(messages.empty());
549  protocol::TMValidatorList msg;
550  auto const manifest =
551  currentBlob.manifest ? *currentBlob.manifest : rawManifest;
552  auto const version = 1;
553  msg.set_manifest(manifest);
554  msg.set_blob(currentBlob.blob);
555  msg.set_signature(currentBlob.signature);
556  // Override the version
557  msg.set_version(version);
558 
559  assert(Message::totalSize(msg) <= maximiumMessageSize);
560  messages.emplace_back(
561  std::make_shared<Message>(msg, protocol::mtVALIDATORLIST),
562  sha512Half(msg),
563  1);
564  return 1;
565 }
566 
567 // Build a v2 protocol message using all the VLs with sequence larger than the
568 // peer's
572  std::uint64_t peerSequence,
573  std::uint32_t rawVersion,
574  std::string const& rawManifest,
576  std::size_t maxSize)
577 {
578  assert(messages.empty());
579  protocol::TMValidatorListCollection msg;
580  auto const version = rawVersion < 2 ? 2 : rawVersion;
581  msg.set_version(version);
582  msg.set_manifest(rawManifest);
583 
584  for (auto const& [sequence, blobInfo] : blobInfos)
585  {
586  if (sequence <= peerSequence)
587  continue;
588  protocol::ValidatorBlobInfo& blob = *msg.add_blobs();
589  blob.set_blob(blobInfo.blob);
590  blob.set_signature(blobInfo.signature);
591  if (blobInfo.manifest)
592  blob.set_manifest(*blobInfo.manifest);
593  }
594  assert(msg.blobs_size() > 0);
595  if (Message::totalSize(msg) > maxSize)
596  {
597  // split into smaller messages
598  return splitMessage(messages, msg, maxSize);
599  }
600  else
601  {
602  messages.emplace_back(
603  std::make_shared<Message>(msg, protocol::mtVALIDATORLISTCOLLECTION),
604  sha512Half(msg),
605  msg.blobs_size());
606  return messages.back().numVLs;
607  }
608 }
609 
610 [[nodiscard]]
611 // static
614  std::size_t messageVersion,
615  std::uint64_t peerSequence,
616  std::size_t maxSequence,
617  std::uint32_t rawVersion,
618  std::string const& rawManifest,
621  std::size_t maxSize /*= maximiumMessageSize*/)
622 {
623  assert(!blobInfos.empty());
624  auto const& [currentSeq, currentBlob] = *blobInfos.begin();
625  auto numVLs = std::accumulate(
626  messages.begin(),
627  messages.end(),
628  0,
629  [](std::size_t total, MessageWithHash const& m) {
630  return total + m.numVLs;
631  });
632  if (messageVersion == 2 && peerSequence < maxSequence)
633  {
634  // Version 2
635  if (messages.empty())
636  {
637  numVLs = buildValidatorListMessage(
638  messages,
639  peerSequence,
640  rawVersion,
641  rawManifest,
642  blobInfos,
643  maxSize);
644  if (messages.empty())
645  // No message was generated. Create an empty placeholder so we
646  // dont' repeat the work later.
647  messages.emplace_back();
648  }
649 
650  // Don't send it next time.
651  return {maxSequence, numVLs};
652  }
653  else if (messageVersion == 1 && peerSequence < currentSeq)
654  {
655  // Version 1
656  if (messages.empty())
657  {
658  numVLs = buildValidatorListMessage(
659  messages,
660  rawVersion,
661  currentBlob.manifest ? *currentBlob.manifest : rawManifest,
662  currentBlob,
663  maxSize);
664  if (messages.empty())
665  // No message was generated. Create an empty placeholder so we
666  // dont' repeat the work later.
667  messages.emplace_back();
668  }
669 
670  // Don't send it next time.
671  return {currentSeq, numVLs};
672  }
673  return {0, 0};
674 }
675 
676 // static
677 void
679  Peer& peer,
680  std::uint64_t peerSequence,
681  PublicKey const& publisherKey,
682  std::size_t maxSequence,
683  std::uint32_t rawVersion,
684  std::string const& rawManifest,
687  HashRouter& hashRouter,
688  beast::Journal j)
689 {
690  std::size_t const messageVersion =
692  ? 2
694  : 0;
695  if (!messageVersion)
696  return;
697  auto const [newPeerSequence, numVLs] = buildValidatorListMessages(
698  messageVersion,
699  peerSequence,
700  maxSequence,
701  rawVersion,
702  rawManifest,
703  blobInfos,
704  messages);
705  if (newPeerSequence)
706  {
707  assert(!messages.empty());
708  // Don't send it next time.
709  peer.setPublisherListSequence(publisherKey, newPeerSequence);
710 
711  bool sent = false;
712  for (auto const& message : messages)
713  {
714  if (message.message)
715  {
716  peer.send(message.message);
717  hashRouter.addSuppressionPeer(message.hash, peer.id());
718  sent = true;
719  }
720  }
721  // The only way sent wil be false is if the messages was too big, and
722  // thus there will only be one entry without a message
723  assert(sent || messages.size() == 1);
724  if (sent)
725  {
726  if (messageVersion > 1)
727  JLOG(j.debug())
728  << "Sent " << messages.size()
729  << " validator list collection(s) containing " << numVLs
730  << " validator list(s) for " << strHex(publisherKey)
731  << " with sequence range " << peerSequence << ", "
732  << newPeerSequence << " to "
733  << peer.getRemoteAddress().to_string() << " [" << peer.id()
734  << "]";
735  else
736  {
737  assert(numVLs == 1);
738  JLOG(j.debug())
739  << "Sent validator list for " << strHex(publisherKey)
740  << " with sequence " << newPeerSequence << " to "
741  << peer.getRemoteAddress().to_string() << " [" << peer.id()
742  << "]";
743  }
744  }
745  }
746 }
747 
748 // static
749 void
751  Peer& peer,
752  std::uint64_t peerSequence,
753  PublicKey const& publisherKey,
754  std::size_t maxSequence,
755  std::uint32_t rawVersion,
756  std::string const& rawManifest,
758  HashRouter& hashRouter,
759  beast::Journal j)
760 {
763  peer,
764  peerSequence,
765  publisherKey,
766  maxSequence,
767  rawVersion,
768  rawManifest,
769  blobInfos,
770  messages,
771  hashRouter,
772  j);
773 }
774 
775 // static
776 void
780 {
781  auto const& current = lists.current;
782  auto const& remaining = lists.remaining;
783  blobInfos[current.sequence] = {
784  current.rawBlob, current.rawSignature, current.rawManifest};
785  for (auto const& [sequence, vl] : remaining)
786  {
787  blobInfos[sequence] = {vl.rawBlob, vl.rawSignature, vl.rawManifest};
788  }
789 }
790 
791 // static
795 {
797  buildBlobInfos(result, lists);
798  return result;
799 }
800 
801 // static
802 void
804  PublicKey const& publisherKey,
806  std::size_t maxSequence,
807  uint256 const& hash,
808  Overlay& overlay,
809  HashRouter& hashRouter,
810  beast::Journal j)
811 {
812  auto const toSkip = hashRouter.shouldRelay(hash);
813 
814  if (toSkip)
815  {
816  // We don't know what messages or message versions we're sending
817  // until we examine our peer's properties. Build the message(s) on
818  // demand, but reuse them when possible.
819 
820  // This will hold a v1 message with only the current VL if we have
821  // any peers that don't support v2
823  // This will hold v2 messages indexed by the peer's
824  // `publisherListSequence`. For each `publisherListSequence`, we'll
825  // only send the VLs with higher sequences.
827  messages2;
828  // If any peers are found that are worth considering, this list will
829  // be built to hold info for all of the valid VLs.
831 
832  assert(
833  lists.current.sequence == maxSequence ||
834  lists.remaining.count(maxSequence) == 1);
835  // Can't use overlay.foreach here because we need to modify
836  // the peer, and foreach provides a const&
837  for (auto& peer : overlay.getActivePeers())
838  {
839  if (toSkip->count(peer->id()) == 0)
840  {
841  auto const peerSequence =
842  peer->publisherListSequence(publisherKey).value_or(0);
843  if (peerSequence < maxSequence)
844  {
845  if (blobInfos.empty())
846  buildBlobInfos(blobInfos, lists);
847  auto const v2 = peer->supportsFeature(
850  *peer,
851  peerSequence,
852  publisherKey,
853  maxSequence,
854  lists.rawVersion,
855  lists.rawManifest,
856  blobInfos,
857  v2 ? messages2[peerSequence] : messages1,
858  hashRouter,
859  j);
860  // Even if the peer doesn't support the messages,
861  // suppress it so it'll be ignored next time.
862  hashRouter.addSuppressionPeer(hash, peer->id());
863  }
864  }
865  }
866  }
867 }
868 
871  std::string const& manifest,
872  std::uint32_t version,
873  std::vector<ValidatorBlobInfo> const& blobs,
874  std::string siteUri,
875  uint256 const& hash,
876  Overlay& overlay,
877  HashRouter& hashRouter,
878  NetworkOPs& networkOPs)
879 {
880  auto const result =
881  applyLists(manifest, version, blobs, std::move(siteUri), hash);
882  auto const disposition = result.bestDisposition();
883 
884  if (disposition == ListDisposition::accepted)
885  {
886  bool good = true;
887  for (auto const& [pubKey, listCollection] : publisherLists_)
888  {
889  (void)pubKey;
890  if (listCollection.status != PublisherStatus::available)
891  {
892  good = false;
893  break;
894  }
895  }
896  if (good)
897  {
898  networkOPs.clearUNLBlocked();
899  }
900  }
901  bool broadcast = disposition <= ListDisposition::known_sequence;
902 
903  if (broadcast)
904  {
905  auto const& pubCollection = publisherLists_[*result.publisherKey];
906  assert(
907  result.status <= PublisherStatus::expired && result.publisherKey &&
908  pubCollection.maxSequence);
910  *result.publisherKey,
911  pubCollection,
912  *pubCollection.maxSequence,
913  hash,
914  overlay,
915  hashRouter,
916  j_);
917  }
918 
919  return result;
920 }
921 
924  std::string const& manifest,
925  std::uint32_t version,
926  std::vector<ValidatorBlobInfo> const& blobs,
927  std::string siteUri,
928  std::optional<uint256> const& hash /* = {} */)
929 {
930  if (std::count(
933  version) != 1)
935 
936  std::lock_guard lock{mutex_};
937 
938  PublisherListStats result;
939  for (auto const& blobInfo : blobs)
940  {
941  auto stats = applyList(
942  manifest,
943  blobInfo.manifest,
944  blobInfo.blob,
945  blobInfo.signature,
946  version,
947  siteUri,
948  hash,
949  lock);
950 
951  if (stats.bestDisposition() < result.bestDisposition() ||
952  (stats.bestDisposition() == result.bestDisposition() &&
953  stats.sequence > result.sequence))
954  {
955  stats.mergeDispositions(result);
956  result = std::move(stats);
957  }
958  else
959  result.mergeDispositions(stats);
961  }
962 
963  // Clean up the collection, because some of the processing may have made it
964  // inconsistent
965  if (result.publisherKey && publisherLists_.count(*result.publisherKey))
966  {
967  auto& pubCollection = publisherLists_[*result.publisherKey];
968  auto& remaining = pubCollection.remaining;
969  auto const& current = pubCollection.current;
970  for (auto iter = remaining.begin(); iter != remaining.end();)
971  {
972  auto next = std::next(iter);
973  assert(next == remaining.end() || next->first > iter->first);
974  if (iter->first <= current.sequence ||
975  (next != remaining.end() &&
976  next->second.validFrom <= iter->second.validFrom))
977  {
978  iter = remaining.erase(iter);
979  }
980  else
981  {
982  iter = next;
983  }
984  }
985 
986  cacheValidatorFile(lock, *result.publisherKey);
987 
988  pubCollection.fullHash = sha512Half(pubCollection);
989 
990  result.sequence = *pubCollection.maxSequence;
991  }
992 
993  return result;
994 }
995 
996 void
998  PublicKey const& pubKey,
999  PublisherList const& current,
1000  std::vector<PublicKey> const& oldList,
1002 {
1003  // Update keyListings_ for added and removed keys
1004  std::vector<PublicKey> const& publisherList = current.list;
1005  std::vector<std::string> const& manifests = current.manifests;
1006  auto iNew = publisherList.begin();
1007  auto iOld = oldList.begin();
1008  while (iNew != publisherList.end() || iOld != oldList.end())
1009  {
1010  if (iOld == oldList.end() ||
1011  (iNew != publisherList.end() && *iNew < *iOld))
1012  {
1013  // Increment list count for added keys
1014  ++keyListings_[*iNew];
1015  ++iNew;
1016  }
1017  else if (
1018  iNew == publisherList.end() ||
1019  (iOld != oldList.end() && *iOld < *iNew))
1020  {
1021  // Decrement list count for removed keys
1022  if (keyListings_[*iOld] <= 1)
1023  keyListings_.erase(*iOld);
1024  else
1025  --keyListings_[*iOld];
1026  ++iOld;
1027  }
1028  else
1029  {
1030  ++iNew;
1031  ++iOld;
1032  }
1033  }
1034 
1035  if (publisherList.empty())
1036  {
1037  JLOG(j_.warn()) << "No validator keys included in valid list";
1038  }
1039 
1040  for (auto const& valManifest : manifests)
1041  {
1042  auto m = deserializeManifest(base64_decode(valManifest));
1043 
1044  if (!m || !keyListings_.count(m->masterKey))
1045  {
1046  JLOG(j_.warn()) << "List for " << strHex(pubKey)
1047  << " contained untrusted validator manifest";
1048  continue;
1049  }
1050 
1051  if (auto const r = validatorManifests_.applyManifest(std::move(*m));
1053  {
1054  JLOG(j_.warn()) << "List for " << strHex(pubKey)
1055  << " contained invalid validator manifest";
1056  }
1057  }
1058 }
1059 
1062  std::string const& globalManifest,
1063  std::optional<std::string> const& localManifest,
1064  std::string const& blob,
1065  std::string const& signature,
1066  std::uint32_t version,
1067  std::string siteUri,
1068  std::optional<uint256> const& hash,
1069  ValidatorList::lock_guard const& lock)
1070 {
1071  using namespace std::string_literals;
1072 
1073  Json::Value list;
1074  PublicKey pubKey;
1075  auto const& manifest = localManifest ? *localManifest : globalManifest;
1076  auto const result = verify(lock, list, pubKey, manifest, blob, signature);
1077  if (result > ListDisposition::pending)
1078  {
1079  if (publisherLists_.count(pubKey))
1080  {
1081  auto const& pubCollection = publisherLists_[pubKey];
1082  if (pubCollection.maxSequence &&
1083  (result == ListDisposition::same_sequence ||
1085  {
1086  // We've seen something valid list for this publisher
1087  // already, so return what we know about it.
1088  return PublisherListStats{
1089  result,
1090  pubKey,
1091  pubCollection.status,
1092  *pubCollection.maxSequence};
1093  }
1094  }
1095  return PublisherListStats{result};
1096  }
1097 
1098  // Update publisher's list
1099  auto& pubCollection = publisherLists_[pubKey];
1100  auto const sequence = list[jss::sequence].asUInt();
1101  auto const accepted =
1102  (result == ListDisposition::accepted ||
1103  result == ListDisposition::expired);
1104 
1105  if (accepted)
1106  pubCollection.status = result == ListDisposition::accepted
1109  pubCollection.rawManifest = globalManifest;
1110  if (!pubCollection.maxSequence || sequence > *pubCollection.maxSequence)
1111  pubCollection.maxSequence = sequence;
1112 
1113  Json::Value const& newList = list[jss::validators];
1114  std::vector<PublicKey> oldList;
1115  if (accepted && pubCollection.remaining.count(sequence) != 0)
1116  {
1117  // We've seen this list before and stored it in "remaining". The
1118  // normal expected process is that the processed list would have
1119  // already been moved in to "current" by "updateTrusted()", but race
1120  // conditions are possible, or the node may have lost sync, so do
1121  // some of that work here.
1122  auto& publisher = pubCollection.current;
1123  // Copy the old validator list
1124  oldList = std::move(pubCollection.current.list);
1125  // Move the publisher info from "remaining" to "current"
1126  publisher = std::move(pubCollection.remaining[sequence]);
1127  // Remove the entry in "remaining"
1128  pubCollection.remaining.erase(sequence);
1129  // Done
1130  assert(publisher.sequence == sequence);
1131  }
1132  else
1133  {
1134  auto& publisher = accepted ? pubCollection.current
1135  : pubCollection.remaining[sequence];
1136  publisher.sequence = sequence;
1137  publisher.validFrom = TimeKeeper::time_point{TimeKeeper::duration{
1138  list.isMember(jss::effective) ? list[jss::effective].asUInt() : 0}};
1139  publisher.validUntil = TimeKeeper::time_point{
1140  TimeKeeper::duration{list[jss::expiration].asUInt()}};
1141  publisher.siteUri = std::move(siteUri);
1142  publisher.rawBlob = blob;
1143  publisher.rawSignature = signature;
1144  publisher.rawManifest = localManifest;
1145  if (hash)
1146  publisher.hash = *hash;
1147 
1148  std::vector<PublicKey>& publisherList = publisher.list;
1149  std::vector<std::string>& manifests = publisher.manifests;
1150 
1151  // Copy the old validator list
1152  oldList = std::move(publisherList);
1153  // Build the new validator list from "newList"
1154  publisherList.clear();
1155  publisherList.reserve(newList.size());
1156  for (auto const& val : newList)
1157  {
1158  if (val.isObject() && val.isMember(jss::validation_public_key) &&
1159  val[jss::validation_public_key].isString())
1160  {
1161  std::optional<Blob> const ret =
1162  strUnHex(val[jss::validation_public_key].asString());
1163 
1164  if (!ret || !publicKeyType(makeSlice(*ret)))
1165  {
1166  JLOG(j_.error())
1167  << "Invalid node identity: "
1168  << val[jss::validation_public_key].asString();
1169  }
1170  else
1171  {
1172  publisherList.push_back(
1173  PublicKey(Slice{ret->data(), ret->size()}));
1174  }
1175 
1176  if (val.isMember(jss::manifest) &&
1177  val[jss::manifest].isString())
1178  manifests.push_back(val[jss::manifest].asString());
1179  }
1180  }
1181 
1182  // Standardize the list order by sorting
1183  std::sort(publisherList.begin(), publisherList.end());
1184  }
1185  // If this publisher has ever sent a more updated version than the one
1186  // in this file, keep it. This scenario is unlikely, but legal.
1187  pubCollection.rawVersion = std::max(pubCollection.rawVersion, version);
1188  if (!pubCollection.remaining.empty())
1189  {
1190  // If there are any pending VLs, then this collection must be at least
1191  // version 2.
1192  pubCollection.rawVersion = std::max(pubCollection.rawVersion, 2u);
1193  }
1194 
1195  PublisherListStats const applyResult{
1196  result, pubKey, pubCollection.status, *pubCollection.maxSequence};
1197 
1198  if (accepted)
1199  {
1200  updatePublisherList(pubKey, pubCollection.current, oldList, lock);
1201  }
1202 
1203  return applyResult;
1204 }
1205 
1208 {
1209  using namespace std::string_literals;
1210  using namespace boost::filesystem;
1211  using namespace boost::system::errc;
1212 
1213  std::lock_guard lock{mutex_};
1214 
1216  sites.reserve(publisherLists_.size());
1217  for (auto const& [pubKey, publisherCollection] : publisherLists_)
1218  {
1219  boost::system::error_code ec;
1220 
1221  if (publisherCollection.status == PublisherStatus::available)
1222  continue;
1223 
1224  boost::filesystem::path const filename = getCacheFileName(lock, pubKey);
1225 
1226  auto const fullPath{canonical(filename, ec)};
1227  if (ec)
1228  continue;
1229 
1230  auto size = file_size(fullPath, ec);
1231  if (!ec && !size)
1232  {
1233  // Treat an empty file as a missing file, because
1234  // nobody else is going to write it.
1235  ec = make_error_code(no_such_file_or_directory);
1236  }
1237  if (ec)
1238  continue;
1239 
1240  std::string const prefix = [&fullPath]() {
1241 #if _MSC_VER // MSVC: Windows paths need a leading / added
1242  {
1243  return fullPath.root_path() == "/"s ? "file://" : "file:///";
1244  }
1245 #else
1246  {
1247  (void)fullPath;
1248  return "file://";
1249  }
1250 #endif
1251  }();
1252  sites.emplace_back(prefix + fullPath.string());
1253  }
1254 
1255  // Then let the ValidatorSites do the rest of the work.
1256  return sites;
1257 }
1258 
1261  ValidatorList::lock_guard const& lock,
1262  Json::Value& list,
1263  PublicKey& pubKey,
1264  std::string const& manifest,
1265  std::string const& blob,
1266  std::string const& signature)
1267 {
1269 
1270  if (!m || !publisherLists_.count(m->masterKey))
1272 
1273  pubKey = m->masterKey;
1274  auto const revoked = m->revoked();
1275 
1276  auto const result = publisherManifests_.applyManifest(std::move(*m));
1277 
1278  if (revoked && result == ManifestDisposition::accepted)
1279  {
1281  // If the manifest is revoked, no future list is valid either
1282  publisherLists_[pubKey].remaining.clear();
1283  }
1284 
1285  if (revoked || result == ManifestDisposition::invalid)
1287 
1288  auto const sig = strUnHex(signature);
1289  auto const data = base64_decode(blob);
1290  if (!sig ||
1291  !ripple::verify(
1293  makeSlice(data),
1294  makeSlice(*sig)))
1295  return ListDisposition::invalid;
1296 
1297  Json::Reader r;
1298  if (!r.parse(data, list))
1299  return ListDisposition::invalid;
1300 
1301  if (list.isMember(jss::sequence) && list[jss::sequence].isInt() &&
1302  list.isMember(jss::expiration) && list[jss::expiration].isInt() &&
1303  (!list.isMember(jss::effective) || list[jss::effective].isInt()) &&
1304  list.isMember(jss::validators) && list[jss::validators].isArray())
1305  {
1306  auto const sequence = list[jss::sequence].asUInt();
1307  auto const validFrom = TimeKeeper::time_point{TimeKeeper::duration{
1308  list.isMember(jss::effective) ? list[jss::effective].asUInt() : 0}};
1309  auto const validUntil = TimeKeeper::time_point{
1310  TimeKeeper::duration{list[jss::expiration].asUInt()}};
1311  auto const now = timeKeeper_.now();
1312  auto const& listCollection = publisherLists_[pubKey];
1313  if (validUntil <= validFrom)
1314  return ListDisposition::invalid;
1315  else if (sequence < listCollection.current.sequence)
1316  return ListDisposition::stale;
1317  else if (sequence == listCollection.current.sequence)
1319  else if (validUntil <= now)
1320  return ListDisposition::expired;
1321  else if (validFrom > now)
1322  // Not yet valid. Return pending if one of the following is true
1323  // * There's no maxSequence, indicating this is the first blob seen
1324  // for this publisher
1325  // * The sequence is larger than the maxSequence, indicating this
1326  // blob is new
1327  // * There's no entry for this sequence AND this blob is valid
1328  // before the last blob, indicating blobs may be processing out of
1329  // order. This may result in some duplicated processing, but
1330  // prevents the risk of missing valid data. Else return
1331  // known_sequence
1332  return !listCollection.maxSequence ||
1333  sequence > *listCollection.maxSequence ||
1334  (listCollection.remaining.count(sequence) == 0 &&
1335  validFrom < listCollection.remaining
1336  .at(*listCollection.maxSequence)
1337  .validFrom)
1340  }
1341  else
1342  {
1343  return ListDisposition::invalid;
1344  }
1345 
1347 }
1348 
1349 bool
1350 ValidatorList::listed(PublicKey const& identity) const
1351 {
1352  std::shared_lock read_lock{mutex_};
1353 
1354  auto const pubKey = validatorManifests_.getMasterKey(identity);
1355  return keyListings_.find(pubKey) != keyListings_.end();
1356 }
1357 
1358 bool
1361  PublicKey const& identity) const
1362 {
1363  auto const pubKey = validatorManifests_.getMasterKey(identity);
1364  return trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end();
1365 }
1366 
1367 bool
1368 ValidatorList::trusted(PublicKey const& identity) const
1369 {
1370  std::shared_lock read_lock{mutex_};
1371  return trusted(read_lock, identity);
1372 }
1373 
1376 {
1377  std::shared_lock read_lock{mutex_};
1378 
1379  auto const pubKey = validatorManifests_.getMasterKey(identity);
1380  if (keyListings_.find(pubKey) != keyListings_.end())
1381  return pubKey;
1382  return std::nullopt;
1383 }
1384 
1388  PublicKey const& identity) const
1389 {
1390  auto const pubKey = validatorManifests_.getMasterKey(identity);
1391  if (trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end())
1392  return pubKey;
1393  return std::nullopt;
1394 }
1395 
1398 {
1399  std::shared_lock read_lock{mutex_};
1400 
1401  return getTrustedKey(read_lock, identity);
1402 }
1403 
1404 bool
1406 {
1407  std::shared_lock read_lock{mutex_};
1408  return identity.size() && publisherLists_.count(identity) &&
1409  publisherLists_.at(identity).status < PublisherStatus::revoked;
1410 }
1411 
1412 PublicKey
1414 {
1415  std::shared_lock read_lock{mutex_};
1416  return localPubKey_;
1417 }
1418 
1419 bool
1422  PublicKey const& publisherKey,
1423  PublisherStatus reason)
1424 {
1425  assert(
1426  reason != PublisherStatus::available &&
1427  reason != PublisherStatus::unavailable);
1428  auto const iList = publisherLists_.find(publisherKey);
1429  if (iList == publisherLists_.end())
1430  return false;
1431 
1432  JLOG(j_.debug()) << "Removing validator list for publisher "
1433  << strHex(publisherKey);
1434 
1435  for (auto const& val : iList->second.current.list)
1436  {
1437  auto const& iVal = keyListings_.find(val);
1438  if (iVal == keyListings_.end())
1439  continue;
1440 
1441  if (iVal->second <= 1)
1442  keyListings_.erase(iVal);
1443  else
1444  --iVal->second;
1445  }
1446 
1447  iList->second.current.list.clear();
1448  iList->second.status = reason;
1449 
1450  return true;
1451 }
1452 
1455 {
1456  return publisherLists_.size();
1457 }
1458 
1461 {
1462  std::shared_lock read_lock{mutex_};
1463  return count(read_lock);
1464 }
1465 
1468 {
1470  for (auto const& [pubKey, collection] : publisherLists_)
1471  {
1472  (void)pubKey;
1473  // Unfetched
1474  auto const& current = collection.current;
1475  if (current.validUntil == TimeKeeper::time_point{})
1476  return std::nullopt;
1477 
1478  // Find the latest validUntil in a chain where the next validFrom
1479  // overlaps with the previous validUntil. applyLists has already cleaned
1480  // up the list so the validFrom dates are guaranteed increasing.
1481  auto chainedExpiration = current.validUntil;
1482  for (auto const& [sequence, check] : collection.remaining)
1483  {
1484  (void)sequence;
1485  if (check.validFrom <= chainedExpiration)
1486  chainedExpiration = check.validUntil;
1487  else
1488  break;
1489  }
1490 
1491  // Earliest
1492  if (!res || chainedExpiration < *res)
1493  {
1494  res = chainedExpiration;
1495  }
1496  }
1497  return res;
1498 }
1499 
1502 {
1503  std::shared_lock read_lock{mutex_};
1504  return expires(read_lock);
1505 }
1506 
1509 {
1511 
1512  std::shared_lock read_lock{mutex_};
1513 
1514  res[jss::validation_quorum] = static_cast<Json::UInt>(quorum_);
1515 
1516  {
1517  auto& x = (res[jss::validator_list] = Json::objectValue);
1518 
1519  x[jss::count] = static_cast<Json::UInt>(count(read_lock));
1520 
1521  if (auto when = expires(read_lock))
1522  {
1523  if (*when == TimeKeeper::time_point::max())
1524  {
1525  x[jss::expiration] = "never";
1526  x[jss::status] = "active";
1527  }
1528  else
1529  {
1530  x[jss::expiration] = to_string(*when);
1531 
1532  if (*when > timeKeeper_.now())
1533  x[jss::status] = "active";
1534  else
1535  x[jss::status] = "expired";
1536  }
1537  }
1538  else
1539  {
1540  x[jss::status] = "unknown";
1541  x[jss::expiration] = "unknown";
1542  }
1543  }
1544 
1545  // Local static keys
1546  PublicKey local;
1547  Json::Value& jLocalStaticKeys =
1548  (res[jss::local_static_keys] = Json::arrayValue);
1549  if (auto it = publisherLists_.find(local); it != publisherLists_.end())
1550  {
1551  for (auto const& key : it->second.current.list)
1552  jLocalStaticKeys.append(toBase58(TokenType::NodePublic, key));
1553  }
1554 
1555  // Publisher lists
1556  Json::Value& jPublisherLists =
1557  (res[jss::publisher_lists] = Json::arrayValue);
1558  for (auto const& [publicKey, pubCollection] : publisherLists_)
1559  {
1560  if (local == publicKey)
1561  continue;
1562  Json::Value& curr = jPublisherLists.append(Json::objectValue);
1563  curr[jss::pubkey_publisher] = strHex(publicKey);
1564  curr[jss::available] =
1565  pubCollection.status == PublisherStatus::available;
1566 
1567  auto appendList = [](PublisherList const& publisherList,
1568  Json::Value& target) {
1569  target[jss::uri] = publisherList.siteUri;
1570  if (publisherList.validUntil != TimeKeeper::time_point{})
1571  {
1572  target[jss::seq] =
1573  static_cast<Json::UInt>(publisherList.sequence);
1574  target[jss::expiration] = to_string(publisherList.validUntil);
1575  }
1576  if (publisherList.validFrom != TimeKeeper::time_point{})
1577  target[jss::effective] = to_string(publisherList.validFrom);
1578  Json::Value& keys = (target[jss::list] = Json::arrayValue);
1579  for (auto const& key : publisherList.list)
1580  {
1582  }
1583  };
1584  {
1585  auto const& current = pubCollection.current;
1586  appendList(current, curr);
1587  if (current.validUntil != TimeKeeper::time_point{})
1588  {
1589  curr[jss::version] = pubCollection.rawVersion;
1590  }
1591  }
1592 
1593  Json::Value remaining(Json::arrayValue);
1594  for (auto const& [sequence, future] : pubCollection.remaining)
1595  {
1596  using namespace std::chrono_literals;
1597 
1598  (void)sequence;
1599  Json::Value& r = remaining.append(Json::objectValue);
1600  appendList(future, r);
1601  // Race conditions can happen, so make this check "fuzzy"
1602  assert(future.validFrom > timeKeeper_.now() + 600s);
1603  }
1604  if (remaining.size())
1605  curr[jss::remaining] = std::move(remaining);
1606  }
1607 
1608  // Trusted validator keys
1609  Json::Value& jValidatorKeys =
1610  (res[jss::trusted_validator_keys] = Json::arrayValue);
1611  for (auto const& k : trustedMasterKeys_)
1612  {
1613  jValidatorKeys.append(toBase58(TokenType::NodePublic, k));
1614  }
1615 
1616  // signing keys
1617  Json::Value& jSigningKeys = (res[jss::signing_keys] = Json::objectValue);
1618  validatorManifests_.for_each_manifest([&jSigningKeys,
1619  this](Manifest const& manifest) {
1620  auto it = keyListings_.find(manifest.masterKey);
1621  if (it != keyListings_.end())
1622  {
1623  jSigningKeys[toBase58(TokenType::NodePublic, manifest.masterKey)] =
1624  toBase58(TokenType::NodePublic, manifest.signingKey);
1625  }
1626  });
1627 
1628  // Negative UNL
1629  if (!negativeUNL_.empty())
1630  {
1631  Json::Value& jNegativeUNL = (res[jss::NegativeUNL] = Json::arrayValue);
1632  for (auto const& k : negativeUNL_)
1633  {
1634  jNegativeUNL.append(toBase58(TokenType::NodePublic, k));
1635  }
1636  }
1637 
1638  return res;
1639 }
1640 
1641 void
1643  std::function<void(PublicKey const&, bool)> func) const
1644 {
1645  std::shared_lock read_lock{mutex_};
1646 
1647  for (auto const& v : keyListings_)
1648  func(v.first, trusted(read_lock, v.first));
1649 }
1650 
1651 void
1653  std::function<void(
1654  std::string const& manifest,
1655  std::uint32_t version,
1657  PublicKey const& pubKey,
1658  std::size_t maxSequence,
1659  uint256 const& hash)> func) const
1660 {
1661  std::shared_lock read_lock{mutex_};
1662 
1663  for (auto const& [key, plCollection] : publisherLists_)
1664  {
1665  if (plCollection.status != PublisherStatus::available || key.empty())
1666  continue;
1667  assert(plCollection.maxSequence);
1668  func(
1669  plCollection.rawManifest,
1670  plCollection.rawVersion,
1671  buildBlobInfos(plCollection),
1672  key,
1673  plCollection.maxSequence.value_or(0),
1674  plCollection.fullHash);
1675  }
1676 }
1677 
1680  boost::beast::string_view const& pubKey,
1681  std::optional<std::uint32_t> forceVersion /* = {} */)
1682 {
1683  std::shared_lock read_lock{mutex_};
1684 
1685  auto const keyBlob = strViewUnHex(pubKey);
1686 
1687  if (!keyBlob || !publicKeyType(makeSlice(*keyBlob)))
1688  {
1689  JLOG(j_.info()) << "Invalid requested validator list publisher key: "
1690  << pubKey;
1691  return {};
1692  }
1693 
1694  auto id = PublicKey(makeSlice(*keyBlob));
1695 
1696  auto const iter = publisherLists_.find(id);
1697 
1698  if (iter == publisherLists_.end() ||
1699  iter->second.status != PublisherStatus::available)
1700  return {};
1701 
1702  Json::Value value =
1703  buildFileData(std::string{pubKey}, iter->second, forceVersion, j_);
1704 
1705  return value;
1706 }
1707 
1710  std::size_t unlSize,
1711  std::size_t effectiveUnlSize,
1712  std::size_t seenSize)
1713 {
1714  // Use quorum if specified via command line.
1715  if (minimumQuorum_ > 0)
1716  {
1717  JLOG(j_.warn()) << "Using potentially unsafe quorum of "
1718  << *minimumQuorum_
1719  << " as specified on the command line";
1720  return *minimumQuorum_;
1721  }
1722 
1723  // Do not use achievable quorum until lists from all configured
1724  // publishers are available
1725  for (auto const& list : publisherLists_)
1726  {
1727  if (list.second.status != PublisherStatus::available)
1729  }
1730 
1731  // Use an 80% quorum to balance fork safety, liveness, and required UNL
1732  // overlap.
1733  //
1734  // Theorem 8 of the Analysis of the XRP Ledger Consensus Protocol
1735  // (https://arxiv.org/abs/1802.07242) says:
1736  // XRP LCP guarantees fork safety if Oi,j > nj/2 + ni − qi + ti,j
1737  // for every pair of nodes Pi, Pj.
1738  //
1739  // ni: size of Pi's UNL
1740  // nj: size of Pj's UNL
1741  // Oi,j: number of validators in both UNLs
1742  // qi: validation quorum for Pi's UNL
1743  // ti, tj: maximum number of allowed Byzantine faults in Pi and Pj's
1744  // UNLs ti,j: min{ti, tj, Oi,j}
1745  //
1746  // Assume ni < nj, meaning and ti,j = ti
1747  //
1748  // For qi = .8*ni, we make ti <= .2*ni
1749  // (We could make ti lower and tolerate less UNL overlap. However in
1750  // order to prioritize safety over liveness, we need ti >= ni - qi)
1751  //
1752  // An 80% quorum allows two UNLs to safely have < .2*ni unique
1753  // validators between them:
1754  //
1755  // pi = ni - Oi,j
1756  // pj = nj - Oi,j
1757  //
1758  // Oi,j > nj/2 + ni − qi + ti,j
1759  // ni - pi > (ni - pi + pj)/2 + ni − .8*ni + .2*ni
1760  // pi + pj < .2*ni
1761  //
1762  // Note that the negative UNL protocol introduced the
1763  // AbsoluteMinimumQuorum which is 60% of the original UNL size. The
1764  // effective quorum should not be lower than it.
1765  static ConsensusParms const parms;
1766  return static_cast<std::size_t>(std::max(
1767  std::ceil(effectiveUnlSize * parms.minCONSENSUS_FACTOR),
1768  std::ceil(unlSize * parms.negUNL_MIN_CONSENSUS_FACTOR)));
1769 }
1770 
1773  hash_set<NodeID> const& seenValidators,
1774  NetClock::time_point closeTime,
1775  NetworkOPs& ops,
1776  Overlay& overlay,
1777  HashRouter& hashRouter)
1778 {
1779  using namespace std::chrono_literals;
1780  if (timeKeeper_.now() > closeTime + 30s)
1781  closeTime = timeKeeper_.now();
1782 
1783  std::lock_guard lock{mutex_};
1784 
1785  // Rotate pending and remove expired published lists
1786  bool good = true;
1787  for (auto& [pubKey, collection] : publisherLists_)
1788  {
1789  {
1790  auto& remaining = collection.remaining;
1791  auto const firstIter = remaining.begin();
1792  auto iter = firstIter;
1793  if (iter != remaining.end() && iter->second.validFrom <= closeTime)
1794  {
1795  // Find the LAST candidate that is ready to go live.
1796  for (auto next = std::next(iter); next != remaining.end() &&
1797  next->second.validFrom <= closeTime;
1798  ++iter, ++next)
1799  {
1800  assert(std::next(iter) == next);
1801  }
1802  assert(iter != remaining.end());
1803 
1804  // Rotate the pending list in to current
1805  auto sequence = iter->first;
1806  auto& candidate = iter->second;
1807  auto& current = collection.current;
1808  assert(candidate.validFrom <= closeTime);
1809 
1810  auto const oldList = current.list;
1811  current = std::move(candidate);
1812  if (collection.status != PublisherStatus::available)
1813  collection.status = PublisherStatus::available;
1814  assert(current.sequence == sequence);
1815  // If the list is expired, remove the validators so they don't
1816  // get processed in. The expiration check below will do the rest
1817  // of the work
1818  if (current.validUntil <= closeTime)
1819  current.list.clear();
1820 
1821  updatePublisherList(pubKey, current, oldList, lock);
1822 
1823  // Only broadcast the current, which will consequently only
1824  // send to peers that don't understand v2, or which are
1825  // unknown (unlikely). Those that do understand v2 should
1826  // already have this list and are in the process of
1827  // switching themselves.
1829  pubKey,
1830  collection,
1831  sequence,
1832  current.hash,
1833  overlay,
1834  hashRouter,
1835  j_);
1836 
1837  // Erase any candidates that we skipped over, plus this one
1838  remaining.erase(firstIter, std::next(iter));
1839  }
1840  }
1841  // Remove if expired
1842  if (collection.status == PublisherStatus::available &&
1843  collection.current.validUntil <= closeTime)
1844  {
1846  ops.setUNLBlocked();
1847  }
1848  if (collection.status != PublisherStatus::available)
1849  good = false;
1850  }
1851  if (good)
1852  ops.clearUNLBlocked();
1853 
1854  TrustChanges trustChanges;
1855 
1856  auto it = trustedMasterKeys_.cbegin();
1857  while (it != trustedMasterKeys_.cend())
1858  {
1859  if (!keyListings_.count(*it) || validatorManifests_.revoked(*it))
1860  {
1861  trustChanges.removed.insert(calcNodeID(*it));
1862  it = trustedMasterKeys_.erase(it);
1863  }
1864  else
1865  {
1866  ++it;
1867  }
1868  }
1869 
1870  for (auto const& val : keyListings_)
1871  {
1872  if (!validatorManifests_.revoked(val.first) &&
1873  trustedMasterKeys_.emplace(val.first).second)
1874  trustChanges.added.insert(calcNodeID(val.first));
1875  }
1876 
1877  // If there were any changes, we need to update the ephemeral signing
1878  // keys:
1879  if (!trustChanges.added.empty() || !trustChanges.removed.empty())
1880  {
1881  trustedSigningKeys_.clear();
1882 
1883  for (auto const& k : trustedMasterKeys_)
1885  }
1886 
1887  JLOG(j_.debug())
1888  << trustedMasterKeys_.size() << " of " << keyListings_.size()
1889  << " listed validators eligible for inclusion in the trusted set";
1890 
1891  auto const unlSize = trustedMasterKeys_.size();
1892  auto effectiveUnlSize = unlSize;
1893  auto seenSize = seenValidators.size();
1894  if (!negativeUNL_.empty())
1895  {
1896  for (auto const& k : trustedMasterKeys_)
1897  {
1898  if (negativeUNL_.count(k))
1899  --effectiveUnlSize;
1900  }
1901  hash_set<NodeID> negUnlNodeIDs;
1902  for (auto const& k : negativeUNL_)
1903  {
1904  negUnlNodeIDs.emplace(calcNodeID(k));
1905  }
1906  for (auto const& nid : seenValidators)
1907  {
1908  if (negUnlNodeIDs.count(nid))
1909  --seenSize;
1910  }
1911  }
1912  quorum_ = calculateQuorum(unlSize, effectiveUnlSize, seenSize);
1913 
1914  JLOG(j_.debug()) << "Using quorum of " << quorum_ << " for new set of "
1915  << unlSize << " trusted validators ("
1916  << trustChanges.added.size() << " added, "
1917  << trustChanges.removed.size() << " removed)";
1918 
1919  if (unlSize < quorum_)
1920  {
1921  JLOG(j_.warn()) << "New quorum of " << quorum_
1922  << " exceeds the number of trusted validators ("
1923  << unlSize << ")";
1924  }
1925 
1926  if (publisherLists_.size() && unlSize == 0)
1927  {
1928  // No validators. Lock down.
1929  ops.setUNLBlocked();
1930  }
1931 
1932  return trustChanges;
1933 }
1934 
1937 {
1938  std::shared_lock read_lock{mutex_};
1939  return trustedMasterKeys_;
1940 }
1941 
1944 {
1945  std::shared_lock read_lock{mutex_};
1946  return negativeUNL_;
1947 }
1948 
1949 void
1951 {
1952  std::lock_guard lock{mutex_};
1953  negativeUNL_ = negUnl;
1954 }
1955 
1958  std::vector<std::shared_ptr<STValidation>>&& validations) const
1959 {
1960  // Remove validations that are from validators on the negative UNL.
1961  auto ret = std::move(validations);
1962 
1963  std::shared_lock read_lock{mutex_};
1964  if (!negativeUNL_.empty())
1965  {
1966  ret.erase(
1968  ret.begin(),
1969  ret.end(),
1970  [&](auto const& v) -> bool {
1971  if (auto const masterKey =
1972  getTrustedKey(read_lock, v->getSignerPublic());
1973  masterKey)
1974  {
1975  return negativeUNL_.count(*masterKey);
1976  }
1977  else
1978  {
1979  return false;
1980  }
1981  }),
1982  ret.end());
1983  }
1984 
1985  return ret;
1986 }
1987 
1988 } // namespace ripple
Json::Value::isInt
bool isInt() const
Definition: json_value.cpp:979
ripple::NetworkOPs
Provides server functionality for clients.
Definition: NetworkOPs.h:90
ripple::ValidatorList::MessageWithHash::MessageWithHash
MessageWithHash()=default
ripple::ValidatorList::PublisherList::sequence
std::size_t sequence
Definition: ValidatorList.h:180
ripple::ValidatorList::validatorManifests_
ManifestCache & validatorManifests_
Definition: ValidatorList.h:224
ripple::ListDisposition::pending
@ pending
List will be valid in the future.
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:241
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:1642
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:1413
ripple::ValidatorBlobInfo::signature
std::string signature
Definition: ValidatorList.h:121
ripple::ValidatorList::PublisherListStats::PublisherListStats
PublisherListStats()=default
std::string
STL class.
std::shared_ptr< Message >
ripple::ListDisposition
ListDisposition
Definition: ValidatorList.h:55
ripple::ManifestCache::getMasterKey
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
Definition: app/misc/impl/Manifest.cpp:303
ripple::maximiumMessageSize
constexpr std::size_t maximiumMessageSize
Definition: overlay/Message.h:38
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
ripple::calcNodeID
NodeID calcNodeID(PublicKey const &pk)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:303
ripple::Message::totalSize
static std::size_t totalSize(::google::protobuf::Message const &message)
Definition: Message.cpp:62
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:308
ripple::TrustChanges
Changes in trusted nodes after updating validator list.
Definition: ValidatorList.h:107
ripple::ListDisposition::stale
@ stale
Trusted publisher key, but seq is too old.
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
std::unordered_set
STL class.
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
beast::IP::Endpoint::to_string
std::string to_string() const
Returns a string representing the endpoint.
Definition: IPEndpoint.cpp:57
std::pair
ripple::ValidatorList::supportedListVersions
static constexpr std::uint32_t supportedListVersions[]
Definition: ValidatorList.h:256
std::vector::reserve
T reserve(T... args)
ripple::HashPrefix::manifest
@ manifest
Manifest.
Json::UInt
unsigned int UInt
Definition: json_forwards.h:27
ripple::verify
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical) noexcept
Verify a signature on a message.
Definition: PublicKey.cpp:272
ripple::ValidatorList::buildBlobInfos
static void buildBlobInfos(std::map< std::size_t, ValidatorBlobInfo > &blobInfos, PublisherListCollection const &lists)
Definition: ValidatorList.cpp:777
std::vector< std::string >
ripple::ValidatorList::applyListsAndBroadcast
PublisherListStats applyListsAndBroadcast(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, NetworkOPs &networkOPs)
Apply multiple published lists of public keys, then broadcast it to all peers that have not seen it o...
Definition: ValidatorList.cpp:870
std::vector::size
T size(T... args)
ripple::ValidatorList::trustedPublisher
bool trustedPublisher(PublicKey const &identity) const
Returns true if public key is a trusted publisher.
Definition: ValidatorList.cpp:1405
ripple::ValidatorList::setNegativeUNL
void setNegativeUNL(hash_set< PublicKey > const &negUnl)
set the Negative UNL with validators' master public keys
Definition: ValidatorList.cpp:1950
ripple::ValidatorList::PublisherListStats
Describes the result of processing a Validator List (UNL), including some of the information from the...
Definition: ValidatorList.h:278
ripple::ValidatorList::negativeUNL_
hash_set< PublicKey > negativeUNL_
Definition: ValidatorList.h:253
ripple::ValidatorList::filePrefix_
static const std::string filePrefix_
Definition: ValidatorList.h:261
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
ripple::ValidatorList::j_
const beast::Journal j_
Definition: ValidatorList.h:228
ripple::ValidatorList::PublisherList::validUntil
TimeKeeper::time_point validUntil
Definition: ValidatorList.h:182
ripple::ValidatorList::getTrustedMasterKeys
hash_set< PublicKey > getTrustedMasterKeys() const
get the trusted master public keys
Definition: ValidatorList.cpp:1936
std::optional::emplace
T emplace(T... args)
ripple::ValidatorList::buildValidatorListMessages
static std::pair< std::size_t, std::size_t > buildValidatorListMessages(std::size_t messageVersion, std::uint64_t peerSequence, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, std::vector< MessageWithHash > &messages, std::size_t maxSize=maximiumMessageSize)
Definition: ValidatorList.cpp:613
beast::Journal::warn
Stream warn() const
Definition: Journal.h:326
std::lock_guard
STL class.
ripple::Peer::send
virtual void send(std::shared_ptr< Message > const &m)=0
ripple::strViewUnHex
std::optional< Blob > strViewUnHex(boost::string_view const &strSrc)
Definition: StringUtilities.h:113
ripple::ValidatorList::maxSupportedBlobs
static constexpr std::size_t maxSupportedBlobs
Definition: ValidatorList.h:259
ripple::ValidatorBlobInfo::blob
std::string blob
Definition: ValidatorList.h:119
ripple::ValidatorList::PublisherListStats::bestDisposition
ListDisposition bestDisposition() const
Definition: ValidatorList.cpp:86
std::vector::back
T back(T... args)
std::function
Json::Value::toStyledString
std::string toStyledString() const
Definition: json_value.cpp:1039
ripple::ValidatorList::parseBlobs
static std::vector< ValidatorBlobInfo > parseBlobs(std::uint32_t version, Json::Value const &body)
Pull the blob/signature/manifest information out of the appropriate Json body fields depending on the...
Definition: ValidatorList.cpp:363
Json::Reader
Unserialize a JSON document into a Value.
Definition: json_reader.h:36
cmath
ripple::ListDisposition::expired
@ expired
List is expired, but has the largest non-pending sequence seen so far.
std::sort
T sort(T... args)
std::optional::reset
T reset(T... args)
ripple::ValidatorList::PublisherListCollection
Definition: ValidatorList.h:194
ripple::HashRouter
Routing table for objects identified by hash.
Definition: HashRouter.h:53
std::vector::clear
T clear(T... args)
ripple::ValidatorList::getTrustedKey
std::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
Definition: ValidatorList.cpp:1397
ripple::ValidatorList::sendValidatorList
static void sendValidatorList(Peer &peer, std::uint64_t peerSequence, PublicKey const &publisherKey, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, HashRouter &hashRouter, beast::Journal j)
Definition: ValidatorList.cpp:750
std::vector::push_back
T push_back(T... args)
ripple::publicKeyType
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:207
ripple::base_uint< 256 >
ripple::ValidatorList::removePublisherList
bool removePublisherList(lock_guard const &, PublicKey const &publisherKey, PublisherStatus reason)
Stop trusting publisher's list of keys.
Definition: ValidatorList.cpp:1420
ripple::ValidatorList::MessageWithHash
Definition: ValidatorList.h:303
ripple::NetworkOPs::clearUNLBlocked
virtual void clearUNLBlocked()=0
ripple::ValidatorList::cacheValidatorFile
void cacheValidatorFile(lock_guard const &lock, PublicKey const &pubKey) const
Write a JSON UNL to a cache file.
Definition: ValidatorList.cpp:332
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
ripple::ValidatorList::ValidatorList
ValidatorList(ManifestCache &validatorManifests, ManifestCache &publisherManifests, TimeKeeper &timeKeeper, std::string const &databasePath, beast::Journal j, std::optional< std::size_t > minimumQuorum=std::nullopt)
Definition: ValidatorList.cpp:119
ripple::ValidatorList::dataPath_
const boost::filesystem::path dataPath_
Definition: ValidatorList.h:227
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::ValidatorList::getCacheFileName
boost::filesystem::path getCacheFileName(lock_guard const &, PublicKey const &pubKey) const
Get the filename used for caching UNLs.
Definition: ValidatorList.cpp:251
ripple::ValidatorList::verify
ListDisposition verify(lock_guard const &, 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:1260
ripple::PublicKey
A public key.
Definition: PublicKey.h:61
ripple::ValidatorList::PublisherListStats::mergeDispositions
void mergeDispositions(PublisherListStats const &src)
Definition: ValidatorList.cpp:100
ripple::PublicKey::size
std::size_t size() const noexcept
Definition: PublicKey.h:89
ripple::ValidatorList::PublisherList::list
std::vector< PublicKey > list
Definition: ValidatorList.h:178
ripple::Peer::setPublisherListSequence
virtual void setPublisherListSequence(PublicKey const &, std::size_t const)=0
ripple::ValidatorList::getListedKey
std::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
Definition: ValidatorList.cpp:1375
ripple::ValidatorBlobInfo
Used to represent the information stored in the blobs_v2 Json array.
Definition: ValidatorList.h:116
ripple::TrustChanges::removed
hash_set< NodeID > removed
Definition: ValidatorList.h:112
ripple::ConsensusParms::minCONSENSUS_FACTOR
float minCONSENSUS_FACTOR
Definition: ConsensusParms.h:76
ripple::ValidatorList::updateTrusted
TrustChanges updateTrusted(hash_set< NodeID > const &seenValidators, NetClock::time_point closeTime, NetworkOPs &ops, Overlay &overlay, HashRouter &hashRouter)
Update trusted nodes.
Definition: ValidatorList.cpp:1772
ripple::ValidatorList::PublisherListCollection::remaining
std::map< std::size_t, PublisherList > remaining
Definition: ValidatorList.h:216
ripple::ValidatorList::publisherManifests_
ManifestCache & publisherManifests_
Definition: ValidatorList.h:225
ripple::ValidatorList::broadcastBlobs
static void broadcastBlobs(PublicKey const &publisherKey, PublisherListCollection const &lists, std::size_t maxSequence, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, beast::Journal j)
Definition: ValidatorList.cpp:803
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:351
ripple::ValidatorList::timeKeeper_
TimeKeeper & timeKeeper_
Definition: ValidatorList.h:226
ripple::ValidatorList::listed
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
Definition: ValidatorList.cpp:1350
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:332
beast::Journal::info
Stream info() const
Definition: Journal.h:320
std::chrono::time_point
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
ripple::ValidatorList::getAvailable
std::optional< Json::Value > getAvailable(boost::beast::string_view const &pubKey, std::optional< std::uint32_t > forceVersion={})
Returns the current valid list for the given publisher key, if available, as a Json object.
Definition: ValidatorList.cpp:1679
ripple::ValidatorList::PublisherList::siteUri
std::string siteUri
Definition: ValidatorList.h:183
ripple::ManifestCache::for_each_manifest
void for_each_manifest(Function &&f) const
Invokes the callback once for every populated manifest.
Definition: Manifest.h:401
ripple::Overlay::getActivePeers
virtual PeerSequence getActivePeers() const =0
Returns a sequence representing the current list of peers.
ripple::ValStatus::current
@ current
This was a new validation and was added.
ripple::ListDisposition::untrusted
@ untrusted
List signed by untrusted publisher key.
std::accumulate
T accumulate(T... args)
ripple::ManifestCache::getSigningKey
PublicKey getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
Definition: app/misc/impl/Manifest.cpp:291
ripple::Peer::supportsFeature
virtual bool supportsFeature(ProtocolFeature f) const =0
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
std::uint32_t
ripple::ValidatorList::PublisherListStats::sequence
std::size_t sequence
Definition: ValidatorList.h:300
ripple::NetworkOPs::setUNLBlocked
virtual void setUNLBlocked()=0
ripple::HashRouter::shouldRelay
std::optional< std::set< PeerShortID > > shouldRelay(uint256 const &key)
Determines whether the hashed item should be relayed.
Definition: HashRouter.cpp:118
std::remove_if
T remove_if(T... args)
ripple::TimeKeeper
Manages various times used by the server.
Definition: TimeKeeper.h:32
std::map
STL class.
ripple::ListDisposition::unsupported_version
@ unsupported_version
List version is not supported.
ripple::ValidatorList::buildFileData
static Json::Value buildFileData(std::string const &pubKey, PublisherListCollection const &pubCollection, beast::Journal j)
Build a Json representation of the collection, suitable for writing to a cache file,...
Definition: ValidatorList.cpp:260
std::ceil
T ceil(T... args)
ripple::ManifestDisposition::invalid
@ invalid
Timely, but invalid signature.
ripple::Peer::getRemoteAddress
virtual beast::IP::Endpoint getRemoteAddress() const =0
ripple::ValidatorList::negativeUNLFilter
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.
Definition: ValidatorList.cpp:1957
ripple::ValidatorList::expires
std::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
Definition: ValidatorList.cpp:1501
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
ripple::ValidatorList::calculateQuorum
std::size_t calculateQuorum(std::size_t unlSize, std::size_t effectiveUnlSize, std::size_t seenSize)
Return quorum for trusted validator set.
Definition: ValidatorList.cpp:1709
ripple::ManifestDisposition::accepted
@ accepted
Manifest is valid.
ripple::ListDisposition::known_sequence
@ known_sequence
Future sequence already seen.
ripple::ValidatorList::localPubKey_
PublicKey localPubKey_
Definition: ValidatorList.h:250
ripple::ValidatorList::applyList
PublisherListStats applyList(std::string const &globalManifest, std::optional< std::string > const &localManifest, std::string const &blob, std::string const &signature, std::uint32_t version, std::string siteUri, std::optional< uint256 > const &hash, lock_guard const &)
Apply published list of public keys.
Definition: ValidatorList.cpp:1061
ripple::ManifestCache
Remembers manifests with the highest sequence number.
Definition: Manifest.h:231
ripple::ValidatorList::loadLists
std::vector< std::string > loadLists()
Definition: ValidatorList.cpp:1207
ripple::ValidatorList::PublisherListCollection::rawVersion
std::uint32_t rawVersion
Definition: ValidatorList.h:221
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:248
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:137
ripple::splitMessageParts
std::size_t splitMessageParts(std::vector< ValidatorList::MessageWithHash > &messages, protocol::TMValidatorListCollection const &largeMsg, std::size_t maxSize, std::size_t begin, std::size_t end)
Definition: ValidatorList.cpp:478
ripple::ConsensusParms
Consensus algorithm parameters.
Definition: ConsensusParms.h:33
ripple::ProtocolFeature::ValidatorList2Propagation
@ ValidatorList2Propagation
ripple::Overlay
Manages the set of connected peers.
Definition: Overlay.h:51
ripple::ValidatorList::PublisherListCollection::current
PublisherList current
Definition: ValidatorList.h:207
ripple::PublisherStatus::unavailable
@ unavailable
ripple::ListDisposition::same_sequence
@ same_sequence
Same sequence as current list.
std::map::begin
T begin(T... args)
ripple::sha512Half
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:216
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
ripple::ListDisposition::invalid
@ invalid
Invalid format or signature.
ripple::ValidatorList::PublisherList::validFrom
TimeKeeper::time_point validFrom
Definition: ValidatorList.h:181
Json::Reader::parse
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:74
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::ValidatorList::mutex_
boost::shared_mutex mutex_
Definition: ValidatorList.h:229
ripple::TimeKeeper::now
virtual time_point now() const override=0
Returns the estimate of wall time, in network time.
ripple::ValidatorList::PublisherListStats::worstDisposition
ListDisposition worstDisposition() const
Definition: ValidatorList.cpp:93
std::count
T count(T... args)
ripple::ValidatorList::PublisherListStats::publisherKey
std::optional< PublicKey > publisherKey
Definition: ValidatorList.h:298
ripple::TrustChanges::added
hash_set< NodeID > added
Definition: ValidatorList.h:111
std::vector::empty
T empty(T... args)
ripple::TokenType::NodePublic
@ NodePublic
std::optional< std::size_t >
mutex
ripple::ValidatorList::getJson
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
Definition: ValidatorList.cpp:1508
beast::Journal::debug
Stream debug() const
Definition: Journal.h:314
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::Peer::id
virtual id_t id() const =0
ripple::ProtocolFeature::ValidatorListPropagation
@ ValidatorListPropagation
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
std::vector::end
T end(T... args)
ripple::deserializeManifest
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
Definition: app/misc/impl/Manifest.cpp:53
ripple::ValidatorBlobInfo::manifest
std::optional< std::string > manifest
Definition: ValidatorList.h:124
ripple::ValidatorList::PublisherListStats::dispositions
std::map< ListDisposition, std::size_t > dispositions
Definition: ValidatorList.h:297
numeric
std::max
T max(T... args)
ripple::ValidatorList::trusted
bool trusted(PublicKey const &identity) const
Returns true if public key is trusted.
Definition: ValidatorList.cpp:1368
ripple::ValidatorList::trustedMasterKeys_
hash_set< PublicKey > trustedMasterKeys_
Definition: ValidatorList.h:243
ripple::ValidatorList::getNegativeUNL
hash_set< PublicKey > getNegativeUNL() const
get the master public keys of Negative UNL validators
Definition: ValidatorList.cpp:1943
ripple::PublisherStatus
PublisherStatus
Definition: ValidatorList.h:87
ripple::ConsensusParms::negUNL_MIN_CONSENSUS_FACTOR
float negUNL_MIN_CONSENSUS_FACTOR
Definition: ConsensusParms.h:81
ripple::splitMessage
std::size_t splitMessage(std::vector< ValidatorList::MessageWithHash > &messages, protocol::TMValidatorListCollection const &largeMsg, std::size_t maxSize, std::size_t begin=0, std::size_t end=0)
Definition: ValidatorList.cpp:457
ripple::ValidatorList::applyLists
PublisherListStats applyLists(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, std::optional< uint256 > const &hash={})
Apply multiple published lists of public keys.
Definition: ValidatorList.cpp:923
ripple::ValidatorList::PublisherListCollection::rawManifest
std::string rawManifest
Definition: ValidatorList.h:220
ripple::PublisherStatus::revoked
@ revoked
ripple::ValidatorList::count
std::size_t count() const
Return the number of configured validator list sites.
Definition: ValidatorList.cpp:1460
ripple::ManifestCache::applyManifest
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
Definition: app/misc/impl/Manifest.cpp:363
ripple::strUnHex
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Definition: StringUtilities.h:52
shared_mutex
beast::abstract_clock< NetClock >::time_point
typename NetClock ::time_point time_point
Definition: abstract_clock.h:63
ripple::ValidatorList::publisherLists_
hash_map< PublicKey, PublisherListCollection > publisherLists_
Definition: ValidatorList.h:237
ripple::ValidatorList::for_each_available
void for_each_available(std::function< void(std::string const &manifest, std::uint32_t version, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, PublicKey const &pubKey, std::size_t maxSequence, uint256 const &hash)> func) const
Invokes the callback once for every available publisher list's raw data members.
Definition: ValidatorList.cpp:1652
ripple::ValidatorList::keyListings_
hash_map< PublicKey, std::size_t > keyListings_
Definition: ValidatorList.h:240
ripple::ListDisposition::accepted
@ accepted
List is valid.
ripple::ValidatorList::quorum_
std::atomic< std::size_t > quorum_
Definition: ValidatorList.h:233
beast::abstract_clock< NetClock >::duration
typename NetClock ::duration duration
Definition: abstract_clock.h:62
ripple::PublisherStatus::available
@ available
ripple::PublisherStatus::expired
@ expired
ripple::ValidatorList::updatePublisherList
void updatePublisherList(PublicKey const &pubKey, PublisherList const &current, std::vector< PublicKey > const &oldList, lock_guard const &)
Definition: ValidatorList.cpp:997
ripple::ValidatorList::MessageWithHash::numVLs
std::size_t numVLs
Definition: ValidatorList.h:312
std::shared_lock
STL class.
ripple::ValidatorList::PublisherList
Definition: ValidatorList.h:174
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::buildValidatorListMessage
std::size_t buildValidatorListMessage(std::vector< ValidatorList::MessageWithHash > &messages, std::uint32_t rawVersion, std::string const &rawManifest, ValidatorBlobInfo const &currentBlob, std::size_t maxSize)
Definition: ValidatorList.cpp:541
ripple::ValidatorList::minimumQuorum_
std::optional< std::size_t > minimumQuorum_
Definition: ValidatorList.h:234
ripple::Peer
Represents a peer connection in the overlay.
Definition: ripple/overlay/Peer.h:46
std::next
T next(T... args)
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469