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