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/STValidation.h>
30 #include <ripple/protocol/digest.h>
31 #include <ripple/protocol/jss.h>
32 #include <ripple/protocol/messages.h>
33 #include <boost/regex.hpp>
34 
35 #include <date/date.h>
36 
37 #include <cmath>
38 #include <mutex>
39 #include <numeric>
40 #include <shared_mutex>
41 
42 namespace ripple {
43 
46 {
47  switch (disposition)
48  {
50  return "accepted";
52  return "expired";
54  return "same_sequence";
56  return "pending";
58  return "known_sequence";
60  return "unsupported_version";
62  return "untrusted";
64  return "stale";
66  return "invalid";
67  }
68  return "unknown";
69 }
70 
72 {
73  ++dispositions[d];
74 }
75 
78  PublicKey key,
79  PublisherStatus stat,
80  std::size_t seq)
81  : publisherKey(key), status(stat), sequence(seq)
82 {
83  ++dispositions[d];
84 }
85 
88 {
89  return dispositions.empty() ? ListDisposition::invalid
90  : dispositions.begin()->first;
91 }
92 
95 {
96  return dispositions.empty() ? ListDisposition::invalid
97  : dispositions.rbegin()->first;
98 }
99 
100 void
102  PublisherListStats const& src)
103 {
104  for (auto const [disp, count] : src.dispositions)
105  {
106  dispositions[disp] += count;
107  }
108 }
109 
111  std::shared_ptr<Message> const& message_,
112  uint256 hash_,
113  std::size_t num_)
114  : message(message_), hash(hash_), numVLs(num_)
115 {
116 }
117 
118 const std::string ValidatorList::filePrefix_ = "cache.";
119 
121  ManifestCache& validatorManifests,
122  ManifestCache& publisherManifests,
123  TimeKeeper& timeKeeper,
124  std::string const& databasePath,
125  beast::Journal j,
126  boost::optional<std::size_t> minimumQuorum)
127  : validatorManifests_(validatorManifests)
128  , publisherManifests_(publisherManifests)
129  , timeKeeper_(timeKeeper)
130  , dataPath_(databasePath)
131  , j_(j)
132  , quorum_(minimumQuorum.value_or(1)) // Genesis ledger quorum
133  , minimumQuorum_(minimumQuorum)
134 {
135 }
136 
137 bool
139  PublicKey const& localSigningKey,
140  std::vector<std::string> const& configKeys,
141  std::vector<std::string> const& publisherKeys)
142 {
143  static boost::regex const re(
144  "[[:space:]]*" // skip leading whitespace
145  "([[:alnum:]]+)" // node identity
146  "(?:" // begin optional comment block
147  "[[:space:]]+" // (skip all leading whitespace)
148  "(?:" // begin optional comment
149  "(.*[^[:space:]]+)" // the comment
150  "[[:space:]]*" // (skip all trailing whitespace)
151  ")?" // end optional comment
152  ")?" // end optional comment block
153  );
154 
155  std::lock_guard lock{mutex_};
156 
157  JLOG(j_.debug())
158  << "Loading configured trusted validator list publisher keys";
159 
160  std::size_t count = 0;
161  for (auto key : publisherKeys)
162  {
163  JLOG(j_.trace()) << "Processing '" << key << "'";
164 
165  auto const ret = strUnHex(key);
166 
167  if (!ret || !publicKeyType(makeSlice(*ret)))
168  {
169  JLOG(j_.error()) << "Invalid validator list publisher key: " << key;
170  return false;
171  }
172 
173  auto id = PublicKey(makeSlice(*ret));
174  auto status = PublisherStatus::unavailable;
175 
177  {
178  JLOG(j_.warn())
179  << "Configured validator list publisher key is revoked: "
180  << key;
181  status = PublisherStatus::revoked;
182  }
183 
184  if (publisherLists_.count(id))
185  {
186  JLOG(j_.warn())
187  << "Duplicate validator list publisher key: " << key;
188  continue;
189  }
190 
191  publisherLists_[id].status = status;
192  ++count;
193  }
194 
195  JLOG(j_.debug()) << "Loaded " << count << " keys";
196 
197  localPubKey_ = validatorManifests_.getMasterKey(localSigningKey);
198 
199  // Treat local validator key as though it was listed in the config
200  if (localPubKey_.size())
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  auto [it, inserted] = publisherLists_.emplace();
237  // Config listed keys never expire
238  auto& current = it->second.current;
239  if (inserted)
240  current.validUntil = TimeKeeper::time_point::max();
241  current.list.emplace_back(*id);
242  it->second.status = PublisherStatus::available;
243  ++count;
244  }
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  boost::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  {
511  boost::optional<protocol::TMValidatorListCollection> smallMsg;
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  for (auto const& [pubKey, listCollection] : publisherLists_)
889  {
890  (void)pubKey;
891  if (listCollection.status != PublisherStatus::available)
892  {
893  good = false;
894  break;
895  }
896  }
897  if (good)
898  {
899  networkOPs.clearUNLBlocked();
900  }
901  }
902  bool broadcast = disposition <= ListDisposition::known_sequence;
903 
904  if (broadcast)
905  {
906  auto const& pubCollection = publisherLists_[*result.publisherKey];
907  assert(
908  result.status <= PublisherStatus::expired && result.publisherKey &&
909  pubCollection.maxSequence);
911  *result.publisherKey,
912  pubCollection,
913  *pubCollection.maxSequence,
914  hash,
915  overlay,
916  hashRouter,
917  j_);
918  }
919 
920  return result;
921 }
922 
925  std::string const& manifest,
926  std::uint32_t version,
927  std::vector<ValidatorBlobInfo> const& blobs,
928  std::string siteUri,
929  boost::optional<uint256> const& hash /* = {} */)
930 {
931  if (std::count(
934  version) != 1)
936 
937  std::lock_guard lock{mutex_};
938 
939  PublisherListStats result;
940  for (auto const& blobInfo : blobs)
941  {
942  auto stats = applyList(
943  manifest,
944  blobInfo.manifest,
945  blobInfo.blob,
946  blobInfo.signature,
947  version,
948  siteUri,
949  hash,
950  lock);
951 
952  if (stats.bestDisposition() < result.bestDisposition() ||
953  (stats.bestDisposition() == result.bestDisposition() &&
954  stats.sequence > result.sequence))
955  {
956  stats.mergeDispositions(result);
957  result = std::move(stats);
958  }
959  else
960  result.mergeDispositions(stats);
962  }
963 
964  // Clean up the collection, because some of the processing may have made it
965  // inconsistent
966  if (result.publisherKey && publisherLists_.count(*result.publisherKey))
967  {
968  auto& pubCollection = publisherLists_[*result.publisherKey];
969  auto& remaining = pubCollection.remaining;
970  auto const& current = pubCollection.current;
971  for (auto iter = remaining.begin(); iter != remaining.end();)
972  {
973  auto next = std::next(iter);
974  assert(next == remaining.end() || next->first > iter->first);
975  if (iter->first <= current.sequence ||
976  (next != remaining.end() &&
977  next->second.validFrom <= iter->second.validFrom))
978  {
979  iter = remaining.erase(iter);
980  }
981  else
982  {
983  iter = next;
984  }
985  }
986 
987  cacheValidatorFile(lock, *result.publisherKey);
988 
989  pubCollection.fullHash = sha512Half(pubCollection);
990 
991  result.sequence = *pubCollection.maxSequence;
992  }
993 
994  return result;
995 }
996 
997 void
999  PublicKey const& pubKey,
1000  PublisherList const& current,
1001  std::vector<PublicKey> const& oldList,
1003 {
1004  // Update keyListings_ for added and removed keys
1005  std::vector<PublicKey> const& publisherList = current.list;
1006  std::vector<std::string> const& manifests = current.manifests;
1007  auto iNew = publisherList.begin();
1008  auto iOld = oldList.begin();
1009  while (iNew != publisherList.end() || iOld != oldList.end())
1010  {
1011  if (iOld == oldList.end() ||
1012  (iNew != publisherList.end() && *iNew < *iOld))
1013  {
1014  // Increment list count for added keys
1015  ++keyListings_[*iNew];
1016  ++iNew;
1017  }
1018  else if (
1019  iNew == publisherList.end() ||
1020  (iOld != oldList.end() && *iOld < *iNew))
1021  {
1022  // Decrement list count for removed keys
1023  if (keyListings_[*iOld] <= 1)
1024  keyListings_.erase(*iOld);
1025  else
1026  --keyListings_[*iOld];
1027  ++iOld;
1028  }
1029  else
1030  {
1031  ++iNew;
1032  ++iOld;
1033  }
1034  }
1035 
1036  if (publisherList.empty())
1037  {
1038  JLOG(j_.warn()) << "No validator keys included in valid list";
1039  }
1040 
1041  for (auto const& valManifest : manifests)
1042  {
1043  auto m = deserializeManifest(base64_decode(valManifest));
1044 
1045  if (!m || !keyListings_.count(m->masterKey))
1046  {
1047  JLOG(j_.warn()) << "List for " << strHex(pubKey)
1048  << " contained untrusted validator manifest";
1049  continue;
1050  }
1051 
1052  if (auto const r = validatorManifests_.applyManifest(std::move(*m));
1054  {
1055  JLOG(j_.warn()) << "List for " << strHex(pubKey)
1056  << " contained invalid validator manifest";
1057  }
1058  }
1059 }
1060 
1063  std::string const& globalManifest,
1064  boost::optional<std::string> const& localManifest,
1065  std::string const& blob,
1066  std::string const& signature,
1067  std::uint32_t version,
1068  std::string siteUri,
1069  boost::optional<uint256> const& hash,
1070  ValidatorList::lock_guard const& lock)
1071 {
1072  using namespace std::string_literals;
1073 
1074  Json::Value list;
1075  PublicKey pubKey;
1076  auto const& manifest = localManifest ? *localManifest : globalManifest;
1077  auto const result = verify(lock, list, pubKey, manifest, blob, signature);
1078  if (result > ListDisposition::pending)
1079  {
1080  if (publisherLists_.count(pubKey))
1081  {
1082  auto const& pubCollection = publisherLists_[pubKey];
1083  if (pubCollection.maxSequence &&
1084  (result == ListDisposition::same_sequence ||
1086  {
1087  // We've seen something valid list for this publisher
1088  // already, so return what we know about it.
1089  return PublisherListStats{
1090  result,
1091  pubKey,
1092  pubCollection.status,
1093  *pubCollection.maxSequence};
1094  }
1095  }
1096  return PublisherListStats{result};
1097  }
1098 
1099  // Update publisher's list
1100  auto& pubCollection = publisherLists_[pubKey];
1101  auto const sequence = list[jss::sequence].asUInt();
1102  auto const accepted =
1103  (result == ListDisposition::accepted ||
1104  result == ListDisposition::expired);
1105 
1106  if (accepted)
1107  pubCollection.status = result == ListDisposition::accepted
1110  pubCollection.rawManifest = globalManifest;
1111  if (!pubCollection.maxSequence || sequence > *pubCollection.maxSequence)
1112  pubCollection.maxSequence = sequence;
1113 
1114  Json::Value const& newList = list[jss::validators];
1115  std::vector<PublicKey> oldList;
1116  if (accepted && pubCollection.remaining.count(sequence) != 0)
1117  {
1118  // We've seen this list before and stored it in "remaining". The
1119  // normal expected process is that the processed list would have
1120  // already been moved in to "current" by "updateTrusted()", but race
1121  // conditions are possible, or the node may have lost sync, so do
1122  // some of that work here.
1123  auto& publisher = pubCollection.current;
1124  // Copy the old validator list
1125  oldList = std::move(pubCollection.current.list);
1126  // Move the publisher info from "remaining" to "current"
1127  publisher = std::move(pubCollection.remaining[sequence]);
1128  // Remove the entry in "remaining"
1129  pubCollection.remaining.erase(sequence);
1130  // Done
1131  assert(publisher.sequence == sequence);
1132  }
1133  else
1134  {
1135  auto& publisher = accepted ? pubCollection.current
1136  : pubCollection.remaining[sequence];
1137  publisher.sequence = sequence;
1138  publisher.validFrom = TimeKeeper::time_point{TimeKeeper::duration{
1139  list.isMember(jss::effective) ? list[jss::effective].asUInt() : 0}};
1140  publisher.validUntil = TimeKeeper::time_point{
1141  TimeKeeper::duration{list[jss::expiration].asUInt()}};
1142  publisher.siteUri = std::move(siteUri);
1143  publisher.rawBlob = blob;
1144  publisher.rawSignature = signature;
1145  publisher.rawManifest = localManifest;
1146  if (hash)
1147  publisher.hash = *hash;
1148 
1149  std::vector<PublicKey>& publisherList = publisher.list;
1150  std::vector<std::string>& manifests = publisher.manifests;
1151 
1152  // Copy the old validator list
1153  oldList = std::move(publisherList);
1154  // Build the new validator list from "newList"
1155  publisherList.clear();
1156  publisherList.reserve(newList.size());
1157  for (auto const& val : newList)
1158  {
1159  if (val.isObject() && val.isMember(jss::validation_public_key) &&
1160  val[jss::validation_public_key].isString())
1161  {
1162  boost::optional<Blob> const ret =
1163  strUnHex(val[jss::validation_public_key].asString());
1164 
1165  if (!ret || !publicKeyType(makeSlice(*ret)))
1166  {
1167  JLOG(j_.error())
1168  << "Invalid node identity: "
1169  << val[jss::validation_public_key].asString();
1170  }
1171  else
1172  {
1173  publisherList.push_back(
1174  PublicKey(Slice{ret->data(), ret->size()}));
1175  }
1176 
1177  if (val.isMember(jss::manifest) &&
1178  val[jss::manifest].isString())
1179  manifests.push_back(val[jss::manifest].asString());
1180  }
1181  }
1182 
1183  // Standardize the list order by sorting
1184  std::sort(publisherList.begin(), publisherList.end());
1185  }
1186  // If this publisher has ever sent a more updated version than the one
1187  // in this file, keep it. This scenario is unlikely, but legal.
1188  pubCollection.rawVersion = std::max(pubCollection.rawVersion, version);
1189  if (!pubCollection.remaining.empty())
1190  {
1191  // If there are any pending VLs, then this collection must be at least
1192  // version 2.
1193  pubCollection.rawVersion = std::max(pubCollection.rawVersion, 2u);
1194  }
1195 
1196  PublisherListStats const applyResult{
1197  result, pubKey, pubCollection.status, *pubCollection.maxSequence};
1198 
1199  if (accepted)
1200  {
1201  updatePublisherList(pubKey, pubCollection.current, oldList, lock);
1202  }
1203 
1204  return applyResult;
1205 }
1206 
1209 {
1210  using namespace std::string_literals;
1211  using namespace boost::filesystem;
1212  using namespace boost::system::errc;
1213 
1214  std::lock_guard lock{mutex_};
1215 
1217  sites.reserve(publisherLists_.size());
1218  for (auto const& [pubKey, publisherCollection] : publisherLists_)
1219  {
1220  boost::system::error_code ec;
1221 
1222  if (publisherCollection.status == PublisherStatus::available)
1223  continue;
1224 
1225  boost::filesystem::path const filename = getCacheFileName(lock, pubKey);
1226 
1227  auto const fullPath{canonical(filename, ec)};
1228  if (ec)
1229  continue;
1230 
1231  auto size = file_size(fullPath, ec);
1232  if (!ec && !size)
1233  {
1234  // Treat an empty file as a missing file, because
1235  // nobody else is going to write it.
1236  ec = make_error_code(no_such_file_or_directory);
1237  }
1238  if (ec)
1239  continue;
1240 
1241  std::string const prefix = [&fullPath]() {
1242 #if _MSC_VER // MSVC: Windows paths need a leading / added
1243  {
1244  return fullPath.root_path() == "/"s ? "file://" : "file:///";
1245  }
1246 #else
1247  {
1248  (void)fullPath;
1249  return "file://";
1250  }
1251 #endif
1252  }();
1253  sites.emplace_back(prefix + fullPath.string());
1254  }
1255 
1256  // Then let the ValidatorSites do the rest of the work.
1257  return sites;
1258 }
1259 
1262  ValidatorList::lock_guard const& lock,
1263  Json::Value& list,
1264  PublicKey& pubKey,
1265  std::string const& manifest,
1266  std::string const& blob,
1267  std::string const& signature)
1268 {
1270 
1271  if (!m || !publisherLists_.count(m->masterKey))
1273 
1274  pubKey = m->masterKey;
1275  auto const revoked = m->revoked();
1276 
1277  auto const result = publisherManifests_.applyManifest(std::move(*m));
1278 
1279  if (revoked && result == ManifestDisposition::accepted)
1280  {
1282  // If the manifest is revoked, no future list is valid either
1283  publisherLists_[pubKey].remaining.clear();
1284  }
1285 
1286  if (revoked || result == ManifestDisposition::invalid)
1288 
1289  auto const sig = strUnHex(signature);
1290  auto const data = base64_decode(blob);
1291  if (!sig ||
1292  !ripple::verify(
1294  makeSlice(data),
1295  makeSlice(*sig)))
1296  return ListDisposition::invalid;
1297 
1298  Json::Reader r;
1299  if (!r.parse(data, list))
1300  return ListDisposition::invalid;
1301 
1302  if (list.isMember(jss::sequence) && list[jss::sequence].isInt() &&
1303  list.isMember(jss::expiration) && list[jss::expiration].isInt() &&
1304  (!list.isMember(jss::effective) || list[jss::effective].isInt()) &&
1305  list.isMember(jss::validators) && list[jss::validators].isArray())
1306  {
1307  auto const sequence = list[jss::sequence].asUInt();
1308  auto const validFrom = TimeKeeper::time_point{TimeKeeper::duration{
1309  list.isMember(jss::effective) ? list[jss::effective].asUInt() : 0}};
1310  auto const validUntil = TimeKeeper::time_point{
1311  TimeKeeper::duration{list[jss::expiration].asUInt()}};
1312  auto const now = timeKeeper_.now();
1313  auto const& listCollection = publisherLists_[pubKey];
1314  if (validUntil <= validFrom)
1315  return ListDisposition::invalid;
1316  else if (sequence < listCollection.current.sequence)
1317  return ListDisposition::stale;
1318  else if (sequence == listCollection.current.sequence)
1320  else if (validUntil <= now)
1321  return ListDisposition::expired;
1322  else if (validFrom > now)
1323  // Not yet valid. Return pending if one of the following is true
1324  // * There's no maxSequence, indicating this is the first blob seen
1325  // for this publisher
1326  // * The sequence is larger than the maxSequence, indicating this
1327  // blob is new
1328  // * There's no entry for this sequence AND this blob is valid
1329  // before the last blob, indicating blobs may be processing out of
1330  // order. This may result in some duplicated processing, but
1331  // prevents the risk of missing valid data. Else return
1332  // known_sequence
1333  return !listCollection.maxSequence ||
1334  sequence > *listCollection.maxSequence ||
1335  (listCollection.remaining.count(sequence) == 0 &&
1336  validFrom < listCollection.remaining
1337  .at(*listCollection.maxSequence)
1338  .validFrom)
1341  }
1342  else
1343  {
1344  return ListDisposition::invalid;
1345  }
1346 
1348 }
1349 
1350 bool
1351 ValidatorList::listed(PublicKey const& identity) const
1352 {
1353  std::shared_lock read_lock{mutex_};
1354 
1355  auto const pubKey = validatorManifests_.getMasterKey(identity);
1356  return keyListings_.find(pubKey) != keyListings_.end();
1357 }
1358 
1359 bool
1362  PublicKey const& identity) const
1363 {
1364  auto const pubKey = validatorManifests_.getMasterKey(identity);
1365  return trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end();
1366 }
1367 
1368 bool
1369 ValidatorList::trusted(PublicKey const& identity) const
1370 {
1371  std::shared_lock read_lock{mutex_};
1372  return trusted(read_lock, identity);
1373 }
1374 
1375 boost::optional<PublicKey>
1377 {
1378  std::shared_lock read_lock{mutex_};
1379 
1380  auto const pubKey = validatorManifests_.getMasterKey(identity);
1381  if (keyListings_.find(pubKey) != keyListings_.end())
1382  return pubKey;
1383  return boost::none;
1384 }
1385 
1386 boost::optional<PublicKey>
1389  PublicKey const& identity) const
1390 {
1391  auto const pubKey = validatorManifests_.getMasterKey(identity);
1392  if (trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end())
1393  return pubKey;
1394  return boost::none;
1395 }
1396 
1397 boost::optional<PublicKey>
1399 {
1400  std::shared_lock read_lock{mutex_};
1401 
1402  return getTrustedKey(read_lock, identity);
1403 }
1404 
1405 bool
1407 {
1408  std::shared_lock read_lock{mutex_};
1409  return identity.size() && publisherLists_.count(identity) &&
1410  publisherLists_.at(identity).status < PublisherStatus::revoked;
1411 }
1412 
1413 PublicKey
1415 {
1416  std::shared_lock read_lock{mutex_};
1417  return localPubKey_;
1418 }
1419 
1420 bool
1423  PublicKey const& publisherKey,
1424  PublisherStatus reason)
1425 {
1426  assert(
1427  reason != PublisherStatus::available &&
1428  reason != PublisherStatus::unavailable);
1429  auto const iList = publisherLists_.find(publisherKey);
1430  if (iList == publisherLists_.end())
1431  return false;
1432 
1433  JLOG(j_.debug()) << "Removing validator list for publisher "
1434  << strHex(publisherKey);
1435 
1436  for (auto const& val : iList->second.current.list)
1437  {
1438  auto const& iVal = keyListings_.find(val);
1439  if (iVal == keyListings_.end())
1440  continue;
1441 
1442  if (iVal->second <= 1)
1443  keyListings_.erase(iVal);
1444  else
1445  --iVal->second;
1446  }
1447 
1448  iList->second.current.list.clear();
1449  iList->second.status = reason;
1450 
1451  return true;
1452 }
1453 
1456 {
1457  return publisherLists_.size();
1458 }
1459 
1462 {
1463  std::shared_lock read_lock{mutex_};
1464  return count(read_lock);
1465 }
1466 
1467 boost::optional<TimeKeeper::time_point>
1469 {
1470  boost::optional<TimeKeeper::time_point> res{boost::none};
1471  for (auto const& [pubKey, collection] : publisherLists_)
1472  {
1473  (void)pubKey;
1474  // Unfetched
1475  auto const& current = collection.current;
1476  if (current.validUntil == TimeKeeper::time_point{})
1477  return boost::none;
1478 
1479  // Find the latest validUntil in a chain where the next validFrom
1480  // overlaps with the previous validUntil. applyLists has already cleaned
1481  // up the list so the validFrom dates are guaranteed increasing.
1482  auto chainedExpiration = current.validUntil;
1483  for (auto const& [sequence, check] : collection.remaining)
1484  {
1485  (void)sequence;
1486  if (check.validFrom <= chainedExpiration)
1487  chainedExpiration = check.validUntil;
1488  else
1489  break;
1490  }
1491 
1492  // Earliest
1493  if (!res || chainedExpiration < *res)
1494  {
1495  res = chainedExpiration;
1496  }
1497  }
1498  return res;
1499 }
1500 
1501 boost::optional<TimeKeeper::time_point>
1503 {
1504  std::shared_lock read_lock{mutex_};
1505  return expires(read_lock);
1506 }
1507 
1510 {
1512 
1513  std::shared_lock read_lock{mutex_};
1514 
1515  res[jss::validation_quorum] = static_cast<Json::UInt>(quorum_);
1516 
1517  {
1518  auto& x = (res[jss::validator_list] = Json::objectValue);
1519 
1520  x[jss::count] = static_cast<Json::UInt>(count(read_lock));
1521 
1522  if (auto when = expires(read_lock))
1523  {
1524  if (*when == TimeKeeper::time_point::max())
1525  {
1526  x[jss::expiration] = "never";
1527  x[jss::status] = "active";
1528  }
1529  else
1530  {
1531  x[jss::expiration] = to_string(*when);
1532 
1533  if (*when > timeKeeper_.now())
1534  x[jss::status] = "active";
1535  else
1536  x[jss::status] = "expired";
1537  }
1538  }
1539  else
1540  {
1541  x[jss::status] = "unknown";
1542  x[jss::expiration] = "unknown";
1543  }
1544  }
1545 
1546  // Local static keys
1547  PublicKey local;
1548  Json::Value& jLocalStaticKeys =
1549  (res[jss::local_static_keys] = Json::arrayValue);
1550  if (auto it = publisherLists_.find(local); it != publisherLists_.end())
1551  {
1552  for (auto const& key : it->second.current.list)
1553  jLocalStaticKeys.append(toBase58(TokenType::NodePublic, key));
1554  }
1555 
1556  // Publisher lists
1557  Json::Value& jPublisherLists =
1558  (res[jss::publisher_lists] = Json::arrayValue);
1559  for (auto const& [publicKey, pubCollection] : publisherLists_)
1560  {
1561  if (local == publicKey)
1562  continue;
1563  Json::Value& curr = jPublisherLists.append(Json::objectValue);
1564  curr[jss::pubkey_publisher] = strHex(publicKey);
1565  curr[jss::available] =
1566  pubCollection.status == PublisherStatus::available;
1567 
1568  auto appendList = [](PublisherList const& publisherList,
1569  Json::Value& target) {
1570  target[jss::uri] = publisherList.siteUri;
1571  if (publisherList.validUntil != TimeKeeper::time_point{})
1572  {
1573  target[jss::seq] =
1574  static_cast<Json::UInt>(publisherList.sequence);
1575  target[jss::expiration] = to_string(publisherList.validUntil);
1576  }
1577  if (publisherList.validFrom != TimeKeeper::time_point{})
1578  target[jss::effective] = to_string(publisherList.validFrom);
1579  Json::Value& keys = (target[jss::list] = Json::arrayValue);
1580  for (auto const& key : publisherList.list)
1581  {
1583  }
1584  };
1585  {
1586  auto const& current = pubCollection.current;
1587  appendList(current, curr);
1588  if (current.validUntil != TimeKeeper::time_point{})
1589  {
1590  curr[jss::version] = pubCollection.rawVersion;
1591  }
1592  }
1593 
1594  Json::Value remaining(Json::arrayValue);
1595  for (auto const& [sequence, future] : pubCollection.remaining)
1596  {
1597  using namespace std::chrono_literals;
1598 
1599  (void)sequence;
1600  Json::Value& r = remaining.append(Json::objectValue);
1601  appendList(future, r);
1602  // Race conditions can happen, so make this check "fuzzy"
1603  assert(future.validFrom > timeKeeper_.now() + 600s);
1604  }
1605  if (remaining.size())
1606  curr[jss::remaining] = std::move(remaining);
1607  }
1608 
1609  // Trusted validator keys
1610  Json::Value& jValidatorKeys =
1611  (res[jss::trusted_validator_keys] = Json::arrayValue);
1612  for (auto const& k : trustedMasterKeys_)
1613  {
1614  jValidatorKeys.append(toBase58(TokenType::NodePublic, k));
1615  }
1616 
1617  // signing keys
1618  Json::Value& jSigningKeys = (res[jss::signing_keys] = Json::objectValue);
1619  validatorManifests_.for_each_manifest([&jSigningKeys,
1620  this](Manifest const& manifest) {
1621  auto it = keyListings_.find(manifest.masterKey);
1622  if (it != keyListings_.end())
1623  {
1624  jSigningKeys[toBase58(TokenType::NodePublic, manifest.masterKey)] =
1625  toBase58(TokenType::NodePublic, manifest.signingKey);
1626  }
1627  });
1628 
1629  // Negative UNL
1630  if (!negativeUNL_.empty())
1631  {
1632  Json::Value& jNegativeUNL = (res[jss::NegativeUNL] = Json::arrayValue);
1633  for (auto const& k : negativeUNL_)
1634  {
1635  jNegativeUNL.append(toBase58(TokenType::NodePublic, k));
1636  }
1637  }
1638 
1639  return res;
1640 }
1641 
1642 void
1644  std::function<void(PublicKey const&, bool)> func) const
1645 {
1646  std::shared_lock read_lock{mutex_};
1647 
1648  for (auto const& v : keyListings_)
1649  func(v.first, trusted(read_lock, v.first));
1650 }
1651 
1652 void
1654  std::function<void(
1655  std::string const& manifest,
1656  std::uint32_t version,
1658  PublicKey const& pubKey,
1659  std::size_t maxSequence,
1660  uint256 const& hash)> func) const
1661 {
1662  std::shared_lock read_lock{mutex_};
1663 
1664  for (auto const& [key, plCollection] : publisherLists_)
1665  {
1666  if (plCollection.status != PublisherStatus::available || key.empty())
1667  continue;
1668  assert(plCollection.maxSequence);
1669  func(
1670  plCollection.rawManifest,
1671  plCollection.rawVersion,
1672  buildBlobInfos(plCollection),
1673  key,
1674  plCollection.maxSequence.value_or(0),
1675  plCollection.fullHash);
1676  }
1677 }
1678 
1679 boost::optional<Json::Value>
1681  boost::beast::string_view const& pubKey,
1682  boost::optional<std::uint32_t> forceVersion /* = {} */)
1683 {
1684  std::shared_lock read_lock{mutex_};
1685 
1686  auto const keyBlob = strViewUnHex(pubKey);
1687 
1688  if (!keyBlob || !publicKeyType(makeSlice(*keyBlob)))
1689  {
1690  JLOG(j_.info()) << "Invalid requested validator list publisher key: "
1691  << pubKey;
1692  return {};
1693  }
1694 
1695  auto id = PublicKey(makeSlice(*keyBlob));
1696 
1697  auto const iter = publisherLists_.find(id);
1698 
1699  if (iter == publisherLists_.end() ||
1700  iter->second.status != PublisherStatus::available)
1701  return {};
1702 
1703  Json::Value value =
1704  buildFileData(std::string{pubKey}, iter->second, forceVersion, j_);
1705 
1706  return value;
1707 }
1708 
1711  std::size_t unlSize,
1712  std::size_t effectiveUnlSize,
1713  std::size_t seenSize)
1714 {
1715  // Do not use achievable quorum until lists from all configured
1716  // publishers are available
1717  for (auto const& list : publisherLists_)
1718  {
1719  if (list.second.status != PublisherStatus::available)
1721  }
1722 
1723  // Use an 80% quorum to balance fork safety, liveness, and required UNL
1724  // overlap.
1725  //
1726  // Theorem 8 of the Analysis of the XRP Ledger Consensus Protocol
1727  // (https://arxiv.org/abs/1802.07242) says:
1728  // XRP LCP guarantees fork safety if Oi,j > nj/2 + ni − qi + ti,j
1729  // for every pair of nodes Pi, Pj.
1730  //
1731  // ni: size of Pi's UNL
1732  // nj: size of Pj's UNL
1733  // Oi,j: number of validators in both UNLs
1734  // qi: validation quorum for Pi's UNL
1735  // ti, tj: maximum number of allowed Byzantine faults in Pi and Pj's
1736  // UNLs ti,j: min{ti, tj, Oi,j}
1737  //
1738  // Assume ni < nj, meaning and ti,j = ti
1739  //
1740  // For qi = .8*ni, we make ti <= .2*ni
1741  // (We could make ti lower and tolerate less UNL overlap. However in
1742  // order to prioritize safety over liveness, we need ti >= ni - qi)
1743  //
1744  // An 80% quorum allows two UNLs to safely have < .2*ni unique
1745  // validators between them:
1746  //
1747  // pi = ni - Oi,j
1748  // pj = nj - Oi,j
1749  //
1750  // Oi,j > nj/2 + ni − qi + ti,j
1751  // ni - pi > (ni - pi + pj)/2 + ni − .8*ni + .2*ni
1752  // pi + pj < .2*ni
1753  //
1754  // Note that the negative UNL protocol introduced the
1755  // AbsoluteMinimumQuorum which is 60% of the original UNL size. The
1756  // effective quorum should not be lower than it.
1757  auto quorum = static_cast<std::size_t>(std::max(
1758  std::ceil(effectiveUnlSize * 0.8f), std::ceil(unlSize * 0.6f)));
1759 
1760  // Use lower quorum specified via command line if the normal quorum
1761  // appears unreachable based on the number of recently received
1762  // validations.
1763  if (minimumQuorum_ && *minimumQuorum_ < quorum && seenSize < quorum)
1764  {
1766 
1767  JLOG(j_.warn()) << "Using unsafe quorum of " << quorum
1768  << " as specified in the command line";
1769  }
1770 
1771  return quorum;
1772 }
1773 
1776  hash_set<NodeID> const& seenValidators,
1777  NetClock::time_point closeTime,
1778  NetworkOPs& ops,
1779  Overlay& overlay,
1780  HashRouter& hashRouter)
1781 {
1782  using namespace std::chrono_literals;
1783  if (timeKeeper_.now() > closeTime + 30s)
1784  closeTime = timeKeeper_.now();
1785 
1786  std::lock_guard lock{mutex_};
1787 
1788  // Rotate pending and remove expired published lists
1789  bool good = true;
1790  for (auto& [pubKey, collection] : publisherLists_)
1791  {
1792  {
1793  auto& remaining = collection.remaining;
1794  auto const firstIter = remaining.begin();
1795  auto iter = firstIter;
1796  if (iter != remaining.end() && iter->second.validFrom <= closeTime)
1797  {
1798  // Find the LAST candidate that is ready to go live.
1799  for (auto next = std::next(iter); next != remaining.end() &&
1800  next->second.validFrom <= closeTime;
1801  ++iter, ++next)
1802  {
1803  assert(std::next(iter) == next);
1804  }
1805  assert(iter != remaining.end());
1806 
1807  // Rotate the pending list in to current
1808  auto sequence = iter->first;
1809  auto& candidate = iter->second;
1810  auto& current = collection.current;
1811  assert(candidate.validFrom <= closeTime);
1812 
1813  auto const oldList = current.list;
1814  current = std::move(candidate);
1815  if (collection.status != PublisherStatus::available)
1816  collection.status = PublisherStatus::available;
1817  assert(current.sequence == sequence);
1818  // If the list is expired, remove the validators so they don't
1819  // get processed in. The expiration check below will do the rest
1820  // of the work
1821  if (current.validUntil <= closeTime)
1822  current.list.clear();
1823 
1824  updatePublisherList(pubKey, current, oldList, lock);
1825 
1826  // Only broadcast the current, which will consequently only
1827  // send to peers that don't understand v2, or which are
1828  // unknown (unlikely). Those that do understand v2 should
1829  // already have this list and are in the process of
1830  // switching themselves.
1832  pubKey,
1833  collection,
1834  sequence,
1835  current.hash,
1836  overlay,
1837  hashRouter,
1838  j_);
1839 
1840  // Erase any candidates that we skipped over, plus this one
1841  remaining.erase(firstIter, std::next(iter));
1842  }
1843  }
1844  // Remove if expired
1845  if (collection.status == PublisherStatus::available &&
1846  collection.current.validUntil <= closeTime)
1847  {
1849  ops.setUNLBlocked();
1850  }
1851  if (collection.status != PublisherStatus::available)
1852  good = false;
1853  }
1854  if (good)
1855  ops.clearUNLBlocked();
1856 
1857  TrustChanges trustChanges;
1858 
1859  auto it = trustedMasterKeys_.cbegin();
1860  while (it != trustedMasterKeys_.cend())
1861  {
1862  if (!keyListings_.count(*it) || validatorManifests_.revoked(*it))
1863  {
1864  trustChanges.removed.insert(calcNodeID(*it));
1865  it = trustedMasterKeys_.erase(it);
1866  }
1867  else
1868  {
1869  ++it;
1870  }
1871  }
1872 
1873  for (auto const& val : keyListings_)
1874  {
1875  if (!validatorManifests_.revoked(val.first) &&
1876  trustedMasterKeys_.emplace(val.first).second)
1877  trustChanges.added.insert(calcNodeID(val.first));
1878  }
1879 
1880  // If there were any changes, we need to update the ephemeral signing
1881  // keys:
1882  if (!trustChanges.added.empty() || !trustChanges.removed.empty())
1883  {
1884  trustedSigningKeys_.clear();
1885 
1886  for (auto const& k : trustedMasterKeys_)
1888  }
1889 
1890  JLOG(j_.debug())
1891  << trustedMasterKeys_.size() << " of " << keyListings_.size()
1892  << " listed validators eligible for inclusion in the trusted set";
1893 
1894  auto const unlSize = trustedMasterKeys_.size();
1895  auto effectiveUnlSize = unlSize;
1896  auto seenSize = seenValidators.size();
1897  if (!negativeUNL_.empty())
1898  {
1899  for (auto const& k : trustedMasterKeys_)
1900  {
1901  if (negativeUNL_.count(k))
1902  --effectiveUnlSize;
1903  }
1904  hash_set<NodeID> negUnlNodeIDs;
1905  for (auto const& k : negativeUNL_)
1906  {
1907  negUnlNodeIDs.emplace(calcNodeID(k));
1908  }
1909  for (auto const& nid : seenValidators)
1910  {
1911  if (negUnlNodeIDs.count(nid))
1912  --seenSize;
1913  }
1914  }
1915  quorum_ = calculateQuorum(unlSize, effectiveUnlSize, seenSize);
1916 
1917  JLOG(j_.debug()) << "Using quorum of " << quorum_ << " for new set of "
1918  << unlSize << " trusted validators ("
1919  << trustChanges.added.size() << " added, "
1920  << trustChanges.removed.size() << " removed)";
1921 
1922  if (unlSize < quorum_)
1923  {
1924  JLOG(j_.warn()) << "New quorum of " << quorum_
1925  << " exceeds the number of trusted validators ("
1926  << unlSize << ")";
1927  }
1928 
1929  if (publisherLists_.size() && unlSize == 0)
1930  {
1931  // No validators. Lock down.
1932  ops.setUNLBlocked();
1933  }
1934 
1935  return trustChanges;
1936 }
1937 
1940 {
1941  std::shared_lock read_lock{mutex_};
1942  return trustedMasterKeys_;
1943 }
1944 
1947 {
1948  std::shared_lock read_lock{mutex_};
1949  return negativeUNL_;
1950 }
1951 
1952 void
1954 {
1955  std::lock_guard lock{mutex_};
1956  negativeUNL_ = negUnl;
1957 }
1958 
1961  std::vector<std::shared_ptr<STValidation>>&& validations) const
1962 {
1963  // Remove validations that are from validators on the negative UNL.
1964  auto ret = std::move(validations);
1965 
1966  std::shared_lock read_lock{mutex_};
1967  if (!negativeUNL_.empty())
1968  {
1969  ret.erase(
1971  ret.begin(),
1972  ret.end(),
1973  [&](auto const& v) -> bool {
1974  if (auto const masterKey =
1975  getTrustedKey(read_lock, v->getSignerPublic());
1976  masterKey)
1977  {
1978  return negativeUNL_.count(*masterKey);
1979  }
1980  else
1981  {
1982  return false;
1983  }
1984  }),
1985  ret.end());
1986  }
1987 
1988  return ret;
1989 }
1990 
1991 } // namespace ripple
Json::Value::isInt
bool isInt() const
Definition: json_value.cpp:979
ripple::ValidatorList::getListedKey
boost::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
Definition: ValidatorList.cpp:1376
ripple::NetworkOPs
Provides server functionality for clients.
Definition: NetworkOPs.h:88
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:240
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:1643
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:1414
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:280
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:299
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:309
ripple::publicKeyType
boost::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:203
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:54
std::pair
ripple::ValidatorList::supportedListVersions
static constexpr std::uint32_t supportedListVersions[]
Definition: ValidatorList.h:256
std::vector::reserve
T reserve(T... args)
ripple::ValidatorList::applyList
PublisherListStats applyList(std::string const &globalManifest, boost::optional< std::string > const &localManifest, std::string const &blob, std::string const &signature, std::uint32_t version, std::string siteUri, boost::optional< uint256 > const &hash, lock_guard const &)
Apply published list of public keys.
Definition: ValidatorList.cpp:1062
ripple::HashPrefix::manifest
@ manifest
Manifest.
Json::UInt
unsigned int UInt
Definition: json_forwards.h:27
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:1406
ripple::ValidatorList::setNegativeUNL
void setNegativeUNL(hash_set< PublicKey > const &negUnl)
set the Negative UNL with validators' master public keys
Definition: ValidatorList.cpp:1953
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:29
ripple::ValidatorList::j_
const beast::Journal j_
Definition: ValidatorList.h:228
ripple::Slice::data
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition: Slice.h:96
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:1939
std::unordered_set::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:327
std::lock_guard
STL class.
ripple::Peer::send
virtual void send(std::shared_ptr< Message > const &m)=0
ripple::ValidatorList::maxSupportedBlobs
static constexpr std::size_t maxSupportedBlobs
Definition: ValidatorList.h:259
ripple::ValidatorBlobInfo::blob
std::string blob
Definition: ValidatorList.h:119
ripple::strUnHex
boost::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Definition: StringUtilities.h:49
ripple::ValidatorList::PublisherListStats::bestDisposition
ListDisposition bestDisposition() const
Definition: ValidatorList.cpp:87
std::vector::back
T back(T... args)
std::function
Json::Value::toStyledString
std::string toStyledString() const
Definition: json_value.cpp:1039
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:45
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)
ripple::ValidatorList::PublisherListCollection
Definition: ValidatorList.h:194
ripple::HashRouter
Routing table for objects identified by hash.
Definition: HashRouter.h:52
std::vector::clear
T clear(T... args)
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::ValidatorList::ValidatorList
ValidatorList(ManifestCache &validatorManifests, ManifestCache &publisherManifests, TimeKeeper &timeKeeper, std::string const &databasePath, beast::Journal j, boost::optional< std::size_t > minimumQuorum=boost::none)
Definition: ValidatorList.cpp:120
ripple::ValidatorList::getTrustedKey
boost::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
Definition: ValidatorList.cpp:1398
ripple::verify
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical)
Verify a signature on a message.
Definition: PublicKey.cpp:268
ripple::base_uint< 256 >
ripple::ValidatorList::removePublisherList
bool removePublisherList(lock_guard const &, PublicKey const &publisherKey, PublisherStatus reason)
Stop trusting publisher's list of keys.
Definition: ValidatorList.cpp:1421
ripple::ValidatorList::MessageWithHash
Definition: ValidatorList.h:303
ripple::NetworkOPs::clearUNLBlocked
virtual void clearUNLBlocked()=0
ripple::ValidatorList::getAvailable
boost::optional< Json::Value > getAvailable(boost::beast::string_view const &pubKey, boost::optional< std::uint32_t > forceVersion={})
Returns the current valid list for the given publisher key, if available, as a Json object.
Definition: ValidatorList.cpp:1680
ripple::ValidatorList::PublisherListStats::publisherKey
boost::optional< PublicKey > publisherKey
Definition: ValidatorList.h:298
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::dataPath_
const boost::filesystem::path dataPath_
Definition: ValidatorList.h:227
ripple::ValidatorList::applyLists
PublisherListStats applyLists(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, boost::optional< uint256 > const &hash={})
Apply multiple published lists of public keys.
Definition: ValidatorList.cpp:924
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::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:1261
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::ValidatorList::PublisherListStats::mergeDispositions
void mergeDispositions(PublisherListStats const &src)
Definition: ValidatorList.cpp:101
ripple::PublicKey::size
std::size_t size() const noexcept
Definition: PublicKey.h:87
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::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::minimumQuorum_
boost::optional< std::size_t > minimumQuorum_
Definition: ValidatorList.h:234
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:1775
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:328
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:1351
ripple::writeFileContents
void writeFileContents(boost::system::error_code &ec, boost::filesystem::path const &destPath, std::string const &contents)
Definition: FileUtilities.cpp:66
ripple::base64_decode
std::string base64_decode(std::string const &data)
Definition: base64.cpp:245
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
std::chrono::time_point
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
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:378
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:268
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:261
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:1960
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:1710
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::ManifestCache
Remembers manifests with the highest sequence number.
Definition: Manifest.h:209
ripple::ValidatorBlobInfo::manifest
boost::optional< std::string > manifest
Definition: ValidatorList.h:124
ripple::ValidatorList::loadLists
std::vector< std::string > loadLists()
Definition: ValidatorList.cpp:1208
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::deserializeManifest
boost::optional< Manifest > deserializeManifest(Slice s)
Constructs Manifest from serialized string.
Definition: app/misc/impl/Manifest.cpp:38
ripple::ValidatorList::load
bool load(PublicKey const &localSigningKey, std::vector< std::string > const &configKeys, std::vector< std::string > const &publisherKeys)
Load configured trusted keys.
Definition: ValidatorList.cpp:138
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:52
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::strViewUnHex
boost::optional< Blob > strViewUnHex(boost::string_view const &strSrc)
Definition: StringUtilities.h:95
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:94
std::count
T count(T... args)
ripple::TrustChanges::added
hash_set< NodeID > added
Definition: ValidatorList.h:111
std::vector::empty
T empty(T... args)
ripple::TokenType::NodePublic
@ NodePublic
mutex
ripple::ValidatorList::getJson
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
Definition: ValidatorList.cpp:1509
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t
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:45
std::vector::end
T end(T... args)
ripple::ValidatorList::PublisherListStats::dispositions
std::map< ListDisposition, std::size_t > dispositions
Definition: ValidatorList.h:297
numeric
std::max
T max(T... args)
ripple::ValidatorList::expires
boost::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
Definition: ValidatorList.cpp:1502
ripple::ValidatorList::trusted
bool trusted(PublicKey const &identity) const
Returns true if public key is trusted.
Definition: ValidatorList.cpp:1369
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:1946
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::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:1461
ripple::ManifestCache::applyManifest
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
Definition: app/misc/impl/Manifest.cpp:340
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:1653
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:998
ripple::ValidatorList::MessageWithHash::numVLs
std::size_t numVLs
Definition: ValidatorList.h:312
std::shared_lock
STL class.
ripple::ValidatorList::PublisherList
Definition: ValidatorList.h:174
ripple::ValidatorList::quorum
std::size_t quorum() const
Get quorum value for current trusted key set.
Definition: ValidatorList.h:492
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::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