rippled
Consensus.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2017 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 #ifndef RIPPLE_CONSENSUS_CONSENSUS_H_INCLUDED
21 #define RIPPLE_CONSENSUS_CONSENSUS_H_INCLUDED
22 
23 #include <ripple/basics/Log.h>
24 #include <ripple/basics/chrono.h>
25 #include <ripple/beast/utility/Journal.h>
26 #include <ripple/consensus/ConsensusParms.h>
27 #include <ripple/consensus/ConsensusProposal.h>
28 #include <ripple/consensus/ConsensusTypes.h>
29 #include <ripple/consensus/DisputedTx.h>
30 #include <ripple/consensus/LedgerTiming.h>
31 #include <ripple/json/json_writer.h>
32 #include <boost/logic/tribool.hpp>
33 #include <sstream>
34 
35 namespace ripple {
36 
55 bool
57  bool anyTransactions,
58  std::size_t prevProposers,
59  std::size_t proposersClosed,
60  std::size_t proposersValidated,
61  std::chrono::milliseconds prevRoundTime,
62  std::chrono::milliseconds timeSincePrevClose,
64  std::chrono::milliseconds idleInterval,
65  ConsensusParms const& parms,
66  beast::Journal j);
67 
84  std::size_t prevProposers,
85  std::size_t currentProposers,
86  std::size_t currentAgree,
87  std::size_t currentFinished,
88  std::chrono::milliseconds previousAgreeTime,
89  std::chrono::milliseconds currentAgreeTime,
90  ConsensusParms const& parms,
91  bool proposing,
92  beast::Journal j);
93 
282 template <class Adaptor>
284 {
285  using Ledger_t = typename Adaptor::Ledger_t;
286  using TxSet_t = typename Adaptor::TxSet_t;
287  using NodeID_t = typename Adaptor::NodeID_t;
288  using Tx_t = typename TxSet_t::Tx;
289  using PeerPosition_t = typename Adaptor::PeerPosition_t;
291  NodeID_t,
292  typename Ledger_t::ID,
293  typename TxSet_t::ID>;
294 
296 
297  // Helper class to ensure adaptor is notified whenver the ConsensusMode
298  // changes
300  {
302 
303  public:
305  {
306  }
308  get() const
309  {
310  return mode_;
311  }
312 
313  void
314  set(ConsensusMode mode, Adaptor& a)
315  {
316  a.onModeChange(mode_, mode);
317  mode_ = mode;
318  }
319  };
320 
321 public:
324 
325  Consensus(Consensus&&) noexcept = default;
326 
333  Consensus(clock_type const& clock, Adaptor& adaptor, beast::Journal j);
334 
348  void
349  startRound(
350  NetClock::time_point const& now,
351  typename Ledger_t::ID const& prevLedgerID,
352  Ledger_t prevLedger,
353  hash_set<NodeID_t> const& nowUntrusted,
354  bool proposing);
355 
362  bool
363  peerProposal(
364  NetClock::time_point const& now,
365  PeerPosition_t const& newProposal);
366 
371  void
372  timerEntry(NetClock::time_point const& now);
373 
379  void
380  gotTxSet(NetClock::time_point const& now, TxSet_t const& txSet);
381 
398  void
399  simulate(
400  NetClock::time_point const& now,
401  boost::optional<std::chrono::milliseconds> consensusDelay);
402 
410  typename Ledger_t::ID
411  prevLedgerID() const
412  {
413  return prevLedgerID_;
414  }
415 
417  phase() const
418  {
419  return phase_;
420  }
421 
430  getJson(bool full) const;
431 
432 private:
433  void
435  NetClock::time_point const& now,
436  typename Ledger_t::ID const& prevLedgerID,
437  Ledger_t const& prevLedger,
438  ConsensusMode mode);
439 
440  // Change our view of the previous ledger
441  void
442  handleWrongLedger(typename Ledger_t::ID const& lgrId);
443 
449  void
450  checkLedger();
451 
455  void
457 
460  bool
462  NetClock::time_point const& now,
463  PeerPosition_t const& newProposal);
464 
471  void
472  phaseOpen();
473 
482  void
483  phaseEstablish();
484 
507  bool
508  shouldPause() const;
509 
510  // Close the open ledger and establish initial position.
511  void
512  closeLedger();
513 
514  // Adjust our positions to try to agree with other validators.
515  void
517 
518  bool
519  haveConsensus();
520 
521  // Create disputes between our position and the provided one.
522  void
523  createDisputes(TxSet_t const& o);
524 
525  // Update our disputes given that this node has adopted a new position.
526  // Will call createDisputes as needed.
527  void
528  updateDisputes(NodeID_t const& node, TxSet_t const& other);
529 
530  // Revoke our outstanding proposal, if any, and cease proposing
531  // until this round ends.
532  void
533  leaveConsensus();
534 
535  // The rounded or effective close time estimate from a proposer
538 
539 private:
540  Adaptor& adaptor_;
541 
544  bool firstRound_ = true;
546 
548 
549  // How long the consensus convergence has taken, expressed as
550  // a percentage of the time that we expected it to take.
552 
553  // How long has this round been open
555 
557 
558  // Time it took for the last consensus round to converge
560 
561  //-------------------------------------------------------------------------
562  // Network time measurements of consensus progress
563 
564  // The current network adjusted time. This is the network time the
565  // ledger would close if it closed now
568 
569  //-------------------------------------------------------------------------
570  // Non-peer (self) consensus data
571 
572  // Last validated ledger ID provided to consensus
573  typename Ledger_t::ID prevLedgerID_;
574  // Last validated ledger seen by consensus
576 
577  // Transaction Sets, indexed by hash of transaction tree
579 
580  boost::optional<Result> result_;
582 
583  //-------------------------------------------------------------------------
584  // Peer related consensus data
585 
586  // Peer proposed positions for the current round
588 
589  // Recently received peer positions, available when transitioning between
590  // ledgers or rounds
592 
593  // The number of proposers who participated in the last consensus round
595 
596  // nodes that have bowed out of this consensus process
598 
599  // Journal for debugging
601 };
602 
603 template <class Adaptor>
605  clock_type const& clock,
606  Adaptor& adaptor,
607  beast::Journal journal)
608  : adaptor_(adaptor), clock_(clock), j_{journal}
609 {
610  JLOG(j_.debug()) << "Creating consensus object";
611 }
612 
613 template <class Adaptor>
614 void
616  NetClock::time_point const& now,
617  typename Ledger_t::ID const& prevLedgerID,
618  Ledger_t prevLedger,
619  hash_set<NodeID_t> const& nowUntrusted,
620  bool proposing)
621 {
622  if (firstRound_)
623  {
624  // take our initial view of closeTime_ from the seed ledger
625  prevRoundTime_ = adaptor_.parms().ledgerIDLE_INTERVAL;
626  prevCloseTime_ = prevLedger.closeTime();
627  firstRound_ = false;
628  }
629  else
630  {
631  prevCloseTime_ = rawCloseTimes_.self;
632  }
633 
634  for (NodeID_t const& n : nowUntrusted)
635  recentPeerPositions_.erase(n);
636 
637  ConsensusMode startMode =
638  proposing ? ConsensusMode::proposing : ConsensusMode::observing;
639 
640  // We were handed the wrong ledger
641  if (prevLedger.id() != prevLedgerID)
642  {
643  // try to acquire the correct one
644  if (auto newLedger = adaptor_.acquireLedger(prevLedgerID))
645  {
646  prevLedger = *newLedger;
647  }
648  else // Unable to acquire the correct ledger
649  {
650  startMode = ConsensusMode::wrongLedger;
651  JLOG(j_.info())
652  << "Entering consensus with: " << previousLedger_.id();
653  JLOG(j_.info()) << "Correct LCL is: " << prevLedgerID;
654  }
655  }
656 
657  startRoundInternal(now, prevLedgerID, prevLedger, startMode);
658 }
659 template <class Adaptor>
660 void
662  NetClock::time_point const& now,
663  typename Ledger_t::ID const& prevLedgerID,
664  Ledger_t const& prevLedger,
665  ConsensusMode mode)
666 {
667  phase_ = ConsensusPhase::open;
668  mode_.set(mode, adaptor_);
669  now_ = now;
670  prevLedgerID_ = prevLedgerID;
671  previousLedger_ = prevLedger;
672  result_.reset();
673  convergePercent_ = 0;
674  haveCloseTimeConsensus_ = false;
675  openTime_.reset(clock_.now());
676  currPeerPositions_.clear();
677  acquired_.clear();
678  rawCloseTimes_.peers.clear();
679  rawCloseTimes_.self = {};
680  deadNodes_.clear();
681 
682  closeResolution_ = getNextLedgerTimeResolution(
683  previousLedger_.closeTimeResolution(),
684  previousLedger_.closeAgree(),
685  previousLedger_.seq() + typename Ledger_t::Seq{1});
686 
687  playbackProposals();
688  if (currPeerPositions_.size() > (prevProposers_ / 2))
689  {
690  // We may be falling behind, don't wait for the timer
691  // consider closing the ledger immediately
692  timerEntry(now_);
693  }
694 }
695 
696 template <class Adaptor>
697 bool
699  NetClock::time_point const& now,
700  PeerPosition_t const& newPeerPos)
701 {
702  NodeID_t const& peerID = newPeerPos.proposal().nodeID();
703 
704  // Always need to store recent positions
705  {
706  auto& props = recentPeerPositions_[peerID];
707 
708  if (props.size() >= 10)
709  props.pop_front();
710 
711  props.push_back(newPeerPos);
712  }
713  return peerProposalInternal(now, newPeerPos);
714 }
715 
716 template <class Adaptor>
717 bool
719  NetClock::time_point const& now,
720  PeerPosition_t const& newPeerPos)
721 {
722  // Nothing to do for now if we are currently working on a ledger
723  if (phase_ == ConsensusPhase::accepted)
724  return false;
725 
726  now_ = now;
727 
728  Proposal_t const& newPeerProp = newPeerPos.proposal();
729 
730  NodeID_t const& peerID = newPeerProp.nodeID();
731 
732  if (newPeerProp.prevLedger() != prevLedgerID_)
733  {
734  JLOG(j_.debug()) << "Got proposal for " << newPeerProp.prevLedger()
735  << " but we are on " << prevLedgerID_;
736  return false;
737  }
738 
739  if (deadNodes_.find(peerID) != deadNodes_.end())
740  {
741  using std::to_string;
742  JLOG(j_.info()) << "Position from dead node: " << to_string(peerID);
743  return false;
744  }
745 
746  {
747  // update current position
748  auto peerPosIt = currPeerPositions_.find(peerID);
749 
750  if (peerPosIt != currPeerPositions_.end())
751  {
752  if (newPeerProp.proposeSeq() <=
753  peerPosIt->second.proposal().proposeSeq())
754  {
755  return false;
756  }
757  }
758 
759  if (newPeerProp.isBowOut())
760  {
761  using std::to_string;
762 
763  JLOG(j_.info()) << "Peer bows out: " << to_string(peerID);
764  if (result_)
765  {
766  for (auto& it : result_->disputes)
767  it.second.unVote(peerID);
768  }
769  if (peerPosIt != currPeerPositions_.end())
770  currPeerPositions_.erase(peerID);
771  deadNodes_.insert(peerID);
772 
773  return true;
774  }
775 
776  if (peerPosIt != currPeerPositions_.end())
777  peerPosIt->second = newPeerPos;
778  else
779  currPeerPositions_.emplace(peerID, newPeerPos);
780  }
781 
782  if (newPeerProp.isInitial())
783  {
784  // Record the close time estimate
785  JLOG(j_.trace()) << "Peer reports close time as "
786  << newPeerProp.closeTime().time_since_epoch().count();
787  ++rawCloseTimes_.peers[newPeerProp.closeTime()];
788  }
789 
790  JLOG(j_.trace()) << "Processing peer proposal " << newPeerProp.proposeSeq()
791  << "/" << newPeerProp.position();
792 
793  {
794  auto const ait = acquired_.find(newPeerProp.position());
795  if (ait == acquired_.end())
796  {
797  // acquireTxSet will return the set if it is available, or
798  // spawn a request for it and return none/nullptr. It will call
799  // gotTxSet once it arrives
800  if (auto set = adaptor_.acquireTxSet(newPeerProp.position()))
801  gotTxSet(now_, *set);
802  else
803  JLOG(j_.debug()) << "Don't have tx set for peer";
804  }
805  else if (result_)
806  {
807  updateDisputes(newPeerProp.nodeID(), ait->second);
808  }
809  }
810 
811  return true;
812 }
813 
814 template <class Adaptor>
815 void
817 {
818  // Nothing to do if we are currently working on a ledger
819  if (phase_ == ConsensusPhase::accepted)
820  return;
821 
822  now_ = now;
823 
824  // Check we are on the proper ledger (this may change phase_)
825  checkLedger();
826 
827  if (phase_ == ConsensusPhase::open)
828  {
829  phaseOpen();
830  }
831  else if (phase_ == ConsensusPhase::establish)
832  {
833  phaseEstablish();
834  }
835 }
836 
837 template <class Adaptor>
838 void
840  NetClock::time_point const& now,
841  TxSet_t const& txSet)
842 {
843  // Nothing to do if we've finished work on a ledger
844  if (phase_ == ConsensusPhase::accepted)
845  return;
846 
847  now_ = now;
848 
849  auto id = txSet.id();
850 
851  // If we've already processed this transaction set since requesting
852  // it from the network, there is nothing to do now
853  if (!acquired_.emplace(id, txSet).second)
854  return;
855 
856  if (!result_)
857  {
858  JLOG(j_.debug()) << "Not creating disputes: no position yet.";
859  }
860  else
861  {
862  // Our position is added to acquired_ as soon as we create it,
863  // so this txSet must differ
864  assert(id != result_->position.position());
865  bool any = false;
866  for (auto const& [nodeId, peerPos] : currPeerPositions_)
867  {
868  if (peerPos.proposal().position() == id)
869  {
870  updateDisputes(nodeId, txSet);
871  any = true;
872  }
873  }
874 
875  if (!any)
876  {
877  JLOG(j_.warn())
878  << "By the time we got " << id << " no peers were proposing it";
879  }
880  }
881 }
882 
883 template <class Adaptor>
884 void
886  NetClock::time_point const& now,
887  boost::optional<std::chrono::milliseconds> consensusDelay)
888 {
889  using namespace std::chrono_literals;
890  JLOG(j_.info()) << "Simulating consensus";
891  now_ = now;
892  closeLedger();
893  result_->roundTime.tick(consensusDelay.value_or(100ms));
894  result_->proposers = prevProposers_ = currPeerPositions_.size();
895  prevRoundTime_ = result_->roundTime.read();
896  phase_ = ConsensusPhase::accepted;
897  adaptor_.onForceAccept(
898  *result_,
899  previousLedger_,
900  closeResolution_,
901  rawCloseTimes_,
902  mode_.get(),
903  getJson(true));
904  JLOG(j_.info()) << "Simulation complete";
905 }
906 
907 template <class Adaptor>
910 {
911  using std::to_string;
912  using Int = Json::Value::Int;
913 
915 
916  ret["proposing"] = (mode_.get() == ConsensusMode::proposing);
917  ret["proposers"] = static_cast<int>(currPeerPositions_.size());
918 
919  if (mode_.get() != ConsensusMode::wrongLedger)
920  {
921  ret["synched"] = true;
922  ret["ledger_seq"] =
923  static_cast<std::uint32_t>(previousLedger_.seq()) + 1;
924  ret["close_granularity"] = static_cast<Int>(closeResolution_.count());
925  }
926  else
927  ret["synched"] = false;
928 
929  ret["phase"] = to_string(phase_);
930 
931  if (result_ && !result_->disputes.empty() && !full)
932  ret["disputes"] = static_cast<Int>(result_->disputes.size());
933 
934  if (result_)
935  ret["our_position"] = result_->position.getJson();
936 
937  if (full)
938  {
939  if (result_)
940  ret["current_ms"] =
941  static_cast<Int>(result_->roundTime.read().count());
942  ret["converge_percent"] = convergePercent_;
943  ret["close_resolution"] = static_cast<Int>(closeResolution_.count());
944  ret["have_time_consensus"] = haveCloseTimeConsensus_;
945  ret["previous_proposers"] = static_cast<Int>(prevProposers_);
946  ret["previous_mseconds"] = static_cast<Int>(prevRoundTime_.count());
947 
948  if (!currPeerPositions_.empty())
949  {
951 
952  for (auto const& [nodeId, peerPos] : currPeerPositions_)
953  {
954  ppj[to_string(nodeId)] = peerPos.getJson();
955  }
956  ret["peer_positions"] = std::move(ppj);
957  }
958 
959  if (!acquired_.empty())
960  {
962  for (auto const& at : acquired_)
963  {
964  acq.append(to_string(at.first));
965  }
966  ret["acquired"] = std::move(acq);
967  }
968 
969  if (result_ && !result_->disputes.empty())
970  {
972  for (auto const& [txId, dispute] : result_->disputes)
973  {
974  dsj[to_string(txId)] = dispute.getJson();
975  }
976  ret["disputes"] = std::move(dsj);
977  }
978 
979  if (!rawCloseTimes_.peers.empty())
980  {
982  for (auto const& ct : rawCloseTimes_.peers)
983  {
984  ctj[std::to_string(ct.first.time_since_epoch().count())] =
985  ct.second;
986  }
987  ret["close_times"] = std::move(ctj);
988  }
989 
990  if (!deadNodes_.empty())
991  {
993  for (auto const& dn : deadNodes_)
994  {
995  dnj.append(to_string(dn));
996  }
997  ret["dead_nodes"] = std::move(dnj);
998  }
999  }
1000 
1001  return ret;
1002 }
1003 
1004 // Handle a change in the prior ledger during a consensus round
1005 template <class Adaptor>
1006 void
1007 Consensus<Adaptor>::handleWrongLedger(typename Ledger_t::ID const& lgrId)
1008 {
1009  assert(lgrId != prevLedgerID_ || previousLedger_.id() != lgrId);
1010 
1011  // Stop proposing because we are out of sync
1012  leaveConsensus();
1013 
1014  // First time switching to this ledger
1015  if (prevLedgerID_ != lgrId)
1016  {
1017  prevLedgerID_ = lgrId;
1018 
1019  // Clear out state
1020  if (result_)
1021  {
1022  result_->disputes.clear();
1023  result_->compares.clear();
1024  }
1025 
1026  currPeerPositions_.clear();
1027  rawCloseTimes_.peers.clear();
1028  deadNodes_.clear();
1029 
1030  // Get back in sync, this will also recreate disputes
1031  playbackProposals();
1032  }
1033 
1034  if (previousLedger_.id() == prevLedgerID_)
1035  return;
1036 
1037  // we need to switch the ledger we're working from
1038  if (auto newLedger = adaptor_.acquireLedger(prevLedgerID_))
1039  {
1040  JLOG(j_.info()) << "Have the consensus ledger " << prevLedgerID_;
1041  startRoundInternal(
1042  now_, lgrId, *newLedger, ConsensusMode::switchedLedger);
1043  }
1044  else
1045  {
1046  mode_.set(ConsensusMode::wrongLedger, adaptor_);
1047  }
1048 }
1049 
1050 template <class Adaptor>
1051 void
1053 {
1054  auto netLgr =
1055  adaptor_.getPrevLedger(prevLedgerID_, previousLedger_, mode_.get());
1056 
1057  if (netLgr != prevLedgerID_)
1058  {
1059  JLOG(j_.warn()) << "View of consensus changed during "
1060  << to_string(phase_) << " status=" << to_string(phase_)
1061  << ", "
1062  << " mode=" << to_string(mode_.get());
1063  JLOG(j_.warn()) << prevLedgerID_ << " to " << netLgr;
1064  JLOG(j_.warn()) << Json::Compact{previousLedger_.getJson()};
1065  JLOG(j_.debug()) << "State on consensus change "
1066  << Json::Compact{getJson(true)};
1067  handleWrongLedger(netLgr);
1068  }
1069  else if (previousLedger_.id() != prevLedgerID_)
1070  handleWrongLedger(netLgr);
1071 }
1072 
1073 template <class Adaptor>
1074 void
1076 {
1077  for (auto const& it : recentPeerPositions_)
1078  {
1079  for (auto const& pos : it.second)
1080  {
1081  if (pos.proposal().prevLedger() == prevLedgerID_)
1082  {
1083  if (peerProposalInternal(now_, pos))
1084  adaptor_.share(pos);
1085  }
1086  }
1087  }
1088 }
1089 
1090 template <class Adaptor>
1091 void
1093 {
1094  using namespace std::chrono;
1095 
1096  // it is shortly before ledger close time
1097  bool anyTransactions = adaptor_.hasOpenTransactions();
1098  auto proposersClosed = currPeerPositions_.size();
1099  auto proposersValidated = adaptor_.proposersValidated(prevLedgerID_);
1100 
1101  openTime_.tick(clock_.now());
1102 
1103  // This computes how long since last ledger's close time
1104  milliseconds sinceClose;
1105  {
1106  bool previousCloseCorrect =
1107  (mode_.get() != ConsensusMode::wrongLedger) &&
1108  previousLedger_.closeAgree() &&
1109  (previousLedger_.closeTime() !=
1110  (previousLedger_.parentCloseTime() + 1s));
1111 
1112  auto lastCloseTime = previousCloseCorrect
1113  ? previousLedger_.closeTime() // use consensus timing
1114  : prevCloseTime_; // use the time we saw internally
1115 
1116  if (now_ >= lastCloseTime)
1117  sinceClose = duration_cast<milliseconds>(now_ - lastCloseTime);
1118  else
1119  sinceClose = -duration_cast<milliseconds>(lastCloseTime - now_);
1120  }
1121 
1122  auto const idleInterval = std::max<milliseconds>(
1123  adaptor_.parms().ledgerIDLE_INTERVAL,
1124  2 * previousLedger_.closeTimeResolution());
1125 
1126  // Decide if we should close the ledger
1127  if (shouldCloseLedger(
1128  anyTransactions,
1129  prevProposers_,
1130  proposersClosed,
1131  proposersValidated,
1132  prevRoundTime_,
1133  sinceClose,
1134  openTime_.read(),
1135  idleInterval,
1136  adaptor_.parms(),
1137  j_))
1138  {
1139  closeLedger();
1140  }
1141 }
1142 
1143 template <class Adaptor>
1144 bool
1146 {
1147  auto const& parms = adaptor_.parms();
1148  std::uint32_t const ahead(
1149  previousLedger_.seq() -
1150  std::min(adaptor_.getValidLedgerIndex(), previousLedger_.seq()));
1151  auto [quorum, trustedKeys] = adaptor_.getQuorumKeys();
1152  std::size_t const totalValidators = trustedKeys.size();
1153  std::size_t laggards =
1154  adaptor_.laggards(previousLedger_.seq(), trustedKeys);
1155  std::size_t const offline = trustedKeys.size();
1156 
1157  std::stringstream vars;
1158  vars << " (working seq: " << previousLedger_.seq() << ", "
1159  << "validated seq: " << adaptor_.getValidLedgerIndex() << ", "
1160  << "am validator: " << adaptor_.validator() << ", "
1161  << "have validated: " << adaptor_.haveValidated() << ", "
1162  << "roundTime: " << result_->roundTime.read().count() << ", "
1163  << "max consensus time: " << parms.ledgerMAX_CONSENSUS.count() << ", "
1164  << "validators: " << totalValidators << ", "
1165  << "laggards: " << laggards << ", "
1166  << "offline: " << offline << ", "
1167  << "quorum: " << quorum << ")";
1168 
1169  if (!ahead || !laggards || !totalValidators || !adaptor_.validator() ||
1170  !adaptor_.haveValidated() ||
1171  result_->roundTime.read() > parms.ledgerMAX_CONSENSUS)
1172  {
1173  j_.debug() << "not pausing (early)" << vars.str();
1174  return false;
1175  }
1176 
1177  bool willPause = false;
1178 
1192  constexpr static std::size_t maxPausePhase = 4;
1193 
1213  std::size_t const phase = (ahead - 1) % (maxPausePhase + 1);
1214 
1215  // validators that remain after the laggards() function are considered
1216  // offline, and should be considered as laggards for purposes of
1217  // evaluating whether the threshold for non-laggards has been reached.
1218  switch (phase)
1219  {
1220  case 0:
1221  // Laggards and offline shouldn't preclude consensus.
1222  if (laggards + offline > totalValidators - quorum)
1223  willPause = true;
1224  break;
1225  case maxPausePhase:
1226  // No tolerance.
1227  willPause = true;
1228  break;
1229  default:
1230  // Ensure that sufficient validators are known to be not lagging.
1231  // Their sufficiently most recent validation sequence was equal to
1232  // or greater than our own.
1233  //
1234  // The threshold is the amount required for quorum plus
1235  // the proportion of the remainder based on number of intermediate
1236  // phases between 0 and max.
1237  float const nonLaggards = totalValidators - (laggards + offline);
1238  float const quorumRatio =
1239  static_cast<float>(quorum) / totalValidators;
1240  float const allowedDissent = 1.0f - quorumRatio;
1241  float const phaseFactor = static_cast<float>(phase) / maxPausePhase;
1242 
1243  if (nonLaggards / totalValidators <
1244  quorumRatio + (allowedDissent * phaseFactor))
1245  {
1246  willPause = true;
1247  }
1248  }
1249 
1250  if (willPause)
1251  j_.warn() << "pausing" << vars.str();
1252  else
1253  j_.debug() << "not pausing" << vars.str();
1254  return willPause;
1255 }
1256 
1257 template <class Adaptor>
1258 void
1260 {
1261  // can only establish consensus if we already took a stance
1262  assert(result_);
1263 
1264  using namespace std::chrono;
1265  ConsensusParms const& parms = adaptor_.parms();
1266 
1267  result_->roundTime.tick(clock_.now());
1268  result_->proposers = currPeerPositions_.size();
1269 
1270  convergePercent_ = result_->roundTime.read() * 100 /
1271  std::max<milliseconds>(prevRoundTime_, parms.avMIN_CONSENSUS_TIME);
1272 
1273  // Give everyone a chance to take an initial position
1274  if (result_->roundTime.read() < parms.ledgerMIN_CONSENSUS)
1275  return;
1276 
1277  updateOurPositions();
1278 
1279  // Nothing to do if too many laggards or we don't have consensus.
1280  if (shouldPause() || !haveConsensus())
1281  return;
1282 
1283  if (!haveCloseTimeConsensus_)
1284  {
1285  JLOG(j_.info()) << "We have TX consensus but not CT consensus";
1286  return;
1287  }
1288 
1289  JLOG(j_.info()) << "Converge cutoff (" << currPeerPositions_.size()
1290  << " participants)";
1291  adaptor_.updateOperatingMode(currPeerPositions_.size());
1292  prevProposers_ = currPeerPositions_.size();
1293  prevRoundTime_ = result_->roundTime.read();
1294  phase_ = ConsensusPhase::accepted;
1295  adaptor_.onAccept(
1296  *result_,
1297  previousLedger_,
1298  closeResolution_,
1299  rawCloseTimes_,
1300  mode_.get(),
1301  getJson(true));
1302 }
1303 
1304 template <class Adaptor>
1305 void
1307 {
1308  // We should not be closing if we already have a position
1309  assert(!result_);
1310 
1311  phase_ = ConsensusPhase::establish;
1312  rawCloseTimes_.self = now_;
1313 
1314  result_.emplace(adaptor_.onClose(previousLedger_, now_, mode_.get()));
1315  result_->roundTime.reset(clock_.now());
1316  // Share the newly created transaction set if we haven't already
1317  // received it from a peer
1318  if (acquired_.emplace(result_->txns.id(), result_->txns).second)
1319  adaptor_.share(result_->txns);
1320 
1321  if (mode_.get() == ConsensusMode::proposing)
1322  adaptor_.propose(result_->position);
1323 
1324  // Create disputes with any peer positions we have transactions for
1325  for (auto const& pit : currPeerPositions_)
1326  {
1327  auto const& pos = pit.second.proposal().position();
1328  auto const it = acquired_.find(pos);
1329  if (it != acquired_.end())
1330  {
1331  createDisputes(it->second);
1332  }
1333  }
1334 }
1335 
1348 inline int
1349 participantsNeeded(int participants, int percent)
1350 {
1351  int result = ((participants * percent) + (percent / 2)) / 100;
1352 
1353  return (result == 0) ? 1 : result;
1354 }
1355 
1356 template <class Adaptor>
1357 void
1359 {
1360  // We must have a position if we are updating it
1361  assert(result_);
1362  ConsensusParms const& parms = adaptor_.parms();
1363 
1364  // Compute a cutoff time
1365  auto const peerCutoff = now_ - parms.proposeFRESHNESS;
1366  auto const ourCutoff = now_ - parms.proposeINTERVAL;
1367 
1368  // Verify freshness of peer positions and compute close times
1369  std::map<NetClock::time_point, int> closeTimeVotes;
1370  {
1371  auto it = currPeerPositions_.begin();
1372  while (it != currPeerPositions_.end())
1373  {
1374  Proposal_t const& peerProp = it->second.proposal();
1375  if (peerProp.isStale(peerCutoff))
1376  {
1377  // peer's proposal is stale, so remove it
1378  NodeID_t const& peerID = peerProp.nodeID();
1379  JLOG(j_.warn()) << "Removing stale proposal from " << peerID;
1380  for (auto& dt : result_->disputes)
1381  dt.second.unVote(peerID);
1382  it = currPeerPositions_.erase(it);
1383  }
1384  else
1385  {
1386  // proposal is still fresh
1387  ++closeTimeVotes[asCloseTime(peerProp.closeTime())];
1388  ++it;
1389  }
1390  }
1391  }
1392 
1393  // This will stay unseated unless there are any changes
1394  boost::optional<TxSet_t> ourNewSet;
1395 
1396  // Update votes on disputed transactions
1397  {
1398  boost::optional<typename TxSet_t::MutableTxSet> mutableSet;
1399  for (auto& [txId, dispute] : result_->disputes)
1400  {
1401  // Because the threshold for inclusion increases,
1402  // time can change our position on a dispute
1403  if (dispute.updateVote(
1404  convergePercent_,
1405  mode_.get() == ConsensusMode::proposing,
1406  parms))
1407  {
1408  if (!mutableSet)
1409  mutableSet.emplace(result_->txns);
1410 
1411  if (dispute.getOurVote())
1412  {
1413  // now a yes
1414  mutableSet->insert(dispute.tx());
1415  }
1416  else
1417  {
1418  // now a no
1419  mutableSet->erase(txId);
1420  }
1421  }
1422  }
1423 
1424  if (mutableSet)
1425  ourNewSet.emplace(std::move(*mutableSet));
1426  }
1427 
1428  NetClock::time_point consensusCloseTime = {};
1429  haveCloseTimeConsensus_ = false;
1430 
1431  if (currPeerPositions_.empty())
1432  {
1433  // no other times
1434  haveCloseTimeConsensus_ = true;
1435  consensusCloseTime = asCloseTime(result_->position.closeTime());
1436  }
1437  else
1438  {
1439  int neededWeight;
1440 
1441  if (convergePercent_ < parms.avMID_CONSENSUS_TIME)
1442  neededWeight = parms.avINIT_CONSENSUS_PCT;
1443  else if (convergePercent_ < parms.avLATE_CONSENSUS_TIME)
1444  neededWeight = parms.avMID_CONSENSUS_PCT;
1445  else if (convergePercent_ < parms.avSTUCK_CONSENSUS_TIME)
1446  neededWeight = parms.avLATE_CONSENSUS_PCT;
1447  else
1448  neededWeight = parms.avSTUCK_CONSENSUS_PCT;
1449 
1450  int participants = currPeerPositions_.size();
1451  if (mode_.get() == ConsensusMode::proposing)
1452  {
1453  ++closeTimeVotes[asCloseTime(result_->position.closeTime())];
1454  ++participants;
1455  }
1456 
1457  // Threshold for non-zero vote
1458  int threshVote = participantsNeeded(participants, neededWeight);
1459 
1460  // Threshold to declare consensus
1461  int const threshConsensus =
1462  participantsNeeded(participants, parms.avCT_CONSENSUS_PCT);
1463 
1464  JLOG(j_.info()) << "Proposers:" << currPeerPositions_.size()
1465  << " nw:" << neededWeight << " thrV:" << threshVote
1466  << " thrC:" << threshConsensus;
1467 
1468  for (auto const& [t, v] : closeTimeVotes)
1469  {
1470  JLOG(j_.debug())
1471  << "CCTime: seq "
1472  << static_cast<std::uint32_t>(previousLedger_.seq()) + 1 << ": "
1473  << t.time_since_epoch().count() << " has " << v << ", "
1474  << threshVote << " required";
1475 
1476  if (v >= threshVote)
1477  {
1478  // A close time has enough votes for us to try to agree
1479  consensusCloseTime = t;
1480  threshVote = v;
1481 
1482  if (threshVote >= threshConsensus)
1483  haveCloseTimeConsensus_ = true;
1484  }
1485  }
1486 
1487  if (!haveCloseTimeConsensus_)
1488  {
1489  JLOG(j_.debug())
1490  << "No CT consensus:"
1491  << " Proposers:" << currPeerPositions_.size()
1492  << " Mode:" << to_string(mode_.get())
1493  << " Thresh:" << threshConsensus
1494  << " Pos:" << consensusCloseTime.time_since_epoch().count();
1495  }
1496  }
1497 
1498  if (!ourNewSet &&
1499  ((consensusCloseTime != asCloseTime(result_->position.closeTime())) ||
1500  result_->position.isStale(ourCutoff)))
1501  {
1502  // close time changed or our position is stale
1503  ourNewSet.emplace(result_->txns);
1504  }
1505 
1506  if (ourNewSet)
1507  {
1508  auto newID = ourNewSet->id();
1509 
1510  result_->txns = std::move(*ourNewSet);
1511 
1512  JLOG(j_.info()) << "Position change: CTime "
1513  << consensusCloseTime.time_since_epoch().count()
1514  << ", tx " << newID;
1515 
1516  result_->position.changePosition(newID, consensusCloseTime, now_);
1517 
1518  // Share our new transaction set and update disputes
1519  // if we haven't already received it
1520  if (acquired_.emplace(newID, result_->txns).second)
1521  {
1522  if (!result_->position.isBowOut())
1523  adaptor_.share(result_->txns);
1524 
1525  for (auto const& [nodeId, peerPos] : currPeerPositions_)
1526  {
1527  Proposal_t const& p = peerPos.proposal();
1528  if (p.position() == newID)
1529  updateDisputes(nodeId, result_->txns);
1530  }
1531  }
1532 
1533  // Share our new position if we are still participating this round
1534  if (!result_->position.isBowOut() &&
1535  (mode_.get() == ConsensusMode::proposing))
1536  adaptor_.propose(result_->position);
1537  }
1538 }
1539 
1540 template <class Adaptor>
1541 bool
1543 {
1544  // Must have a stance if we are checking for consensus
1545  assert(result_);
1546 
1547  // CHECKME: should possibly count unacquired TX sets as disagreeing
1548  int agree = 0, disagree = 0;
1549 
1550  auto ourPosition = result_->position.position();
1551 
1552  // Count number of agreements/disagreements with our position
1553  for (auto const& [nodeId, peerPos] : currPeerPositions_)
1554  {
1555  Proposal_t const& peerProp = peerPos.proposal();
1556  if (peerProp.position() == ourPosition)
1557  {
1558  ++agree;
1559  }
1560  else
1561  {
1562  using std::to_string;
1563 
1564  JLOG(j_.debug()) << to_string(nodeId) << " has "
1565  << to_string(peerProp.position());
1566  ++disagree;
1567  }
1568  }
1569  auto currentFinished =
1570  adaptor_.proposersFinished(previousLedger_, prevLedgerID_);
1571 
1572  JLOG(j_.debug()) << "Checking for TX consensus: agree=" << agree
1573  << ", disagree=" << disagree;
1574 
1575  // Determine if we actually have consensus or not
1576  result_->state = checkConsensus(
1577  prevProposers_,
1578  agree + disagree,
1579  agree,
1580  currentFinished,
1581  prevRoundTime_,
1582  result_->roundTime.read(),
1583  adaptor_.parms(),
1584  mode_.get() == ConsensusMode::proposing,
1585  j_);
1586 
1587  if (result_->state == ConsensusState::No)
1588  return false;
1589 
1590  // There is consensus, but we need to track if the network moved on
1591  // without us.
1592  if (result_->state == ConsensusState::MovedOn)
1593  {
1594  JLOG(j_.error()) << "Unable to reach consensus";
1595  JLOG(j_.error()) << Json::Compact{getJson(true)};
1596  }
1597 
1598  return true;
1599 }
1600 
1601 template <class Adaptor>
1602 void
1604 {
1605  if (mode_.get() == ConsensusMode::proposing)
1606  {
1607  if (result_ && !result_->position.isBowOut())
1608  {
1609  result_->position.bowOut(now_);
1610  adaptor_.propose(result_->position);
1611  }
1612 
1613  mode_.set(ConsensusMode::observing, adaptor_);
1614  JLOG(j_.info()) << "Bowing out of consensus";
1615  }
1616 }
1617 
1618 template <class Adaptor>
1619 void
1621 {
1622  // Cannot create disputes without our stance
1623  assert(result_);
1624 
1625  // Only create disputes if this is a new set
1626  if (!result_->compares.emplace(o.id()).second)
1627  return;
1628 
1629  // Nothing to dispute if we agree
1630  if (result_->txns.id() == o.id())
1631  return;
1632 
1633  JLOG(j_.debug()) << "createDisputes " << result_->txns.id() << " to "
1634  << o.id();
1635 
1636  auto differences = result_->txns.compare(o);
1637 
1638  int dc = 0;
1639 
1640  for (auto const& [txId, inThisSet] : differences)
1641  {
1642  ++dc;
1643  // create disputed transactions (from the ledger that has them)
1644  assert(
1645  (inThisSet && result_->txns.find(txId) && !o.find(txId)) ||
1646  (!inThisSet && !result_->txns.find(txId) && o.find(txId)));
1647 
1648  Tx_t tx = inThisSet ? *result_->txns.find(txId) : *o.find(txId);
1649  auto txID = tx.id();
1650 
1651  if (result_->disputes.find(txID) != result_->disputes.end())
1652  continue;
1653 
1654  JLOG(j_.debug()) << "Transaction " << txID << " is disputed";
1655 
1656  typename Result::Dispute_t dtx{
1657  tx,
1658  result_->txns.exists(txID),
1659  std::max(prevProposers_, currPeerPositions_.size()),
1660  j_};
1661 
1662  // Update all of the available peer's votes on the disputed transaction
1663  for (auto const& [nodeId, peerPos] : currPeerPositions_)
1664  {
1665  Proposal_t const& peerProp = peerPos.proposal();
1666  auto const cit = acquired_.find(peerProp.position());
1667  if (cit != acquired_.end())
1668  dtx.setVote(nodeId, cit->second.exists(txID));
1669  }
1670  adaptor_.share(dtx.tx());
1671 
1672  result_->disputes.emplace(txID, std::move(dtx));
1673  }
1674  JLOG(j_.debug()) << dc << " differences found";
1675 }
1676 
1677 template <class Adaptor>
1678 void
1680 {
1681  // Cannot updateDisputes without our stance
1682  assert(result_);
1683 
1684  // Ensure we have created disputes against this set if we haven't seen
1685  // it before
1686  if (result_->compares.find(other.id()) == result_->compares.end())
1687  createDisputes(other);
1688 
1689  for (auto& it : result_->disputes)
1690  {
1691  auto& d = it.second;
1692  d.setVote(node, other.exists(d.tx().id()));
1693  }
1694 }
1695 
1696 template <class Adaptor>
1699 {
1700  return roundCloseTime(raw, closeResolution_);
1701 }
1702 
1703 } // namespace ripple
1704 
1705 #endif
ripple::ConsensusParms::avCT_CONSENSUS_PCT
std::size_t avCT_CONSENSUS_PCT
Percentage of nodes required to reach agreement on ledger close time.
Definition: ConsensusParms.h:137
Json::Value::Int
Json::Int Int
Definition: json_value.h:154
ripple::Consensus::deadNodes_
hash_set< NodeID_t > deadNodes_
Definition: Consensus.h:597
ripple::ConsensusProposal::proposeSeq
std::uint32_t proposeSeq() const
Get the sequence number of this proposal.
Definition: ConsensusProposal.h:117
ripple::checkConsensus
ConsensusState checkConsensus(std::size_t prevProposers, std::size_t currentProposers, std::size_t currentAgree, std::size_t currentFinished, std::chrono::milliseconds previousAgreeTime, std::chrono::milliseconds currentAgreeTime, ConsensusParms const &parms, bool proposing, beast::Journal j)
Determine whether the network reached consensus and whether we joined.
Definition: Consensus.cpp:108
sstream
ripple::Consensus::checkLedger
void checkLedger()
Check if our previous ledger matches the network's.
Definition: Consensus.h:1052
ripple::ConsensusState
ConsensusState
Whether we have or don't have a consensus.
Definition: ConsensusTypes.h:186
ripple::Consensus::playbackProposals
void playbackProposals()
If we radically changed our consensus context for some reason, we need to replay recent proposals so ...
Definition: Consensus.h:1075
ripple::Consensus::shouldPause
bool shouldPause() const
Evaluate whether pausing increases likelihood of validation.
Definition: Consensus.h:1145
ripple::ConsensusProposal::isStale
bool isStale(NetClock::time_point cutoff) const
Get whether this position is stale relative to the provided cutoff.
Definition: ConsensusProposal.h:154
ripple::Consensus::result_
boost::optional< Result > result_
Definition: Consensus.h:580
ripple::ConsensusMode::proposing
@ proposing
We are normal participant in consensus and propose our position.
ripple::ConsensusTimer
Measures the duration of phases of consensus.
Definition: ConsensusTypes.h:134
ripple::Consensus::asCloseTime
NetClock::time_point asCloseTime(NetClock::time_point raw) const
Definition: Consensus.h:1698
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::shouldCloseLedger
bool shouldCloseLedger(bool anyTransactions, std::size_t prevProposers, std::size_t proposersClosed, std::size_t proposersValidated, std::chrono::milliseconds prevRoundTime, std::chrono::milliseconds timeSincePrevClose, std::chrono::milliseconds openTime, std::chrono::milliseconds idleInterval, ConsensusParms const &parms, beast::Journal j)
Determines whether the current ledger should close at this time.
Definition: Consensus.cpp:26
ripple::Consensus::createDisputes
void createDisputes(TxSet_t const &o)
Definition: Consensus.h:1620
ripple::Consensus::handleWrongLedger
void handleWrongLedger(typename Ledger_t::ID const &lgrId)
Definition: Consensus.h:1007
ripple::ConsensusParms::avMID_CONSENSUS_TIME
std::size_t avMID_CONSENSUS_TIME
Percentage of previous round duration before we advance.
Definition: ConsensusParms.h:119
ripple::Consensus::closeResolution_
NetClock::duration closeResolution_
Definition: Consensus.h:556
std::unordered_set
STL class.
ripple::Consensus< ripple::test::csf::Peer >::Tx_t
typename TxSet_t::Tx Tx_t
Definition: Consensus.h:288
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::ConsensusParms::avLATE_CONSENSUS_PCT
std::size_t avLATE_CONSENSUS_PCT
Percentage of nodes that most vote yes after advancing.
Definition: ConsensusParms.h:128
ripple::Consensus::MonitoredMode::set
void set(ConsensusMode mode, Adaptor &a)
Definition: Consensus.h:314
ripple::Consensus::MonitoredMode::MonitoredMode
MonitoredMode(ConsensusMode m)
Definition: Consensus.h:304
Json::Compact
Decorator for streaming out compact json.
Definition: json_writer.h:316
ripple::Consensus::getJson
Json::Value getJson(bool full) const
Get the Json state of the consensus process.
Definition: Consensus.h:909
ripple::ConsensusParms::avSTUCK_CONSENSUS_PCT
std::size_t avSTUCK_CONSENSUS_PCT
Percentage of nodes that must vote yes after we are stuck.
Definition: ConsensusParms.h:134
ripple::Consensus
Generic implementation of consensus algorithm.
Definition: Consensus.h:283
ripple::Consensus::recentPeerPositions_
hash_map< NodeID_t, std::deque< PeerPosition_t > > recentPeerPositions_
Definition: Consensus.h:591
std::chrono::milliseconds
std::map::emplace
T emplace(T... args)
std::stringstream
STL class.
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::Consensus::leaveConsensus
void leaveConsensus()
Definition: Consensus.h:1603
ripple::Consensus::phase
ConsensusPhase phase() const
Definition: Consensus.h:417
ripple::Consensus::j_
const beast::Journal j_
Definition: Consensus.h:600
ripple::roundCloseTime
std::chrono::time_point< Clock, Duration > roundCloseTime(std::chrono::time_point< Clock, Duration > closeTime, std::chrono::duration< Rep, Period > closeResolution)
Calculates the close time for a ledger, given a close time resolution.
Definition: LedgerTiming.h:126
ripple::Consensus::currPeerPositions_
hash_map< NodeID_t, PeerPosition_t > currPeerPositions_
Definition: Consensus.h:587
boost
Definition: IPAddress.h:117
ripple::ConsensusParms::proposeINTERVAL
std::chrono::seconds proposeINTERVAL
How often we force generating a new proposal to keep ours fresh.
Definition: ConsensusParms.h:67
ripple::Consensus::prevProposers_
std::size_t prevProposers_
Definition: Consensus.h:594
ripple::Consensus::now_
NetClock::time_point now_
Definition: Consensus.h:566
std::stringstream::read
T read(T... args)
ripple::ConsensusPhase::accepted
@ accepted
We have accepted a new last closed ledger and are waiting on a call to startRound to begin the next c...
ripple::Consensus::gotTxSet
void gotTxSet(NetClock::time_point const &now, TxSet_t const &txSet)
Process a transaction set acquired from the network.
Definition: Consensus.h:839
ripple::ConsensusResult
Encapsulates the result of consensus.
Definition: ConsensusTypes.h:201
ripple::Consensus::acquired_
hash_map< typename TxSet_t::ID, const TxSet_t > acquired_
Definition: Consensus.h:578
ripple::Consensus::prevRoundTime_
std::chrono::milliseconds prevRoundTime_
Definition: Consensus.h:559
ripple::Consensus::clock_
clock_type const & clock_
Definition: Consensus.h:547
ripple::ConsensusMode::observing
@ observing
We are observing peer positions, but not proposing our position.
ripple::Consensus::adaptor_
Adaptor & adaptor_
Definition: Consensus.h:540
ripple::Consensus::phaseOpen
void phaseOpen()
Handle pre-close phase.
Definition: Consensus.h:1092
std::chrono::time_point::time_since_epoch
T time_since_epoch(T... args)
ripple::ConsensusProposal::prevLedger
LedgerID_t const & prevLedger() const
Get the prior accepted ledger this position is based on.
Definition: ConsensusProposal.h:104
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::Consensus::timerEntry
void timerEntry(NetClock::time_point const &now)
Call periodically to drive consensus forward.
Definition: Consensus.h:816
ripple::Consensus::convergePercent_
int convergePercent_
Definition: Consensus.h:551
ripple::Consensus::phase_
ConsensusPhase phase_
Definition: Consensus.h:542
ripple::Consensus::startRoundInternal
void startRoundInternal(NetClock::time_point const &now, typename Ledger_t::ID const &prevLedgerID, Ledger_t const &prevLedger, ConsensusMode mode)
Definition: Consensus.h:661
ripple::Consensus::Consensus
Consensus(Consensus &&) noexcept=default
std::to_string
T to_string(T... args)
ripple::ConsensusParms::proposeFRESHNESS
std::chrono::seconds proposeFRESHNESS
How long we consider a proposal fresh.
Definition: ConsensusParms.h:64
ripple::Consensus::prevLedgerID
Ledger_t::ID prevLedgerID() const
Get the previous ledger ID.
Definition: Consensus.h:411
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:276
ripple::ConsensusPhase
ConsensusPhase
Phases of consensus for a single ledger round.
Definition: ConsensusTypes.h:103
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
std::chrono::time_point
ripple::Consensus::updateDisputes
void updateDisputes(NodeID_t const &node, TxSet_t const &other)
Definition: Consensus.h:1679
ripple::Consensus< ripple::test::csf::Peer >::NodeID_t
typename ripple::test::csf::Peer ::NodeID_t NodeID_t
Definition: Consensus.h:287
ripple::Consensus::haveCloseTimeConsensus_
bool haveCloseTimeConsensus_
Definition: Consensus.h:545
ripple::ConsensusParms::avINIT_CONSENSUS_PCT
std::size_t avINIT_CONSENSUS_PCT
Percentage of nodes on our UNL that must vote yes.
Definition: ConsensusParms.h:116
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::uint32_t
ripple::Consensus::firstRound_
bool firstRound_
Definition: Consensus.h:544
std::map
STL class.
ripple::Consensus::mode_
MonitoredMode mode_
Definition: Consensus.h:543
ripple::Consensus< ripple::test::csf::Peer >::Ledger_t
typename ripple::test::csf::Peer ::Ledger_t Ledger_t
Definition: Consensus.h:285
ripple::ConsensusParms::avMID_CONSENSUS_PCT
std::size_t avMID_CONSENSUS_PCT
Percentage of nodes that most vote yes after advancing.
Definition: ConsensusParms.h:122
ripple::Consensus< ripple::test::csf::Peer >::PeerPosition_t
typename ripple::test::csf::Peer ::PeerPosition_t PeerPosition_t
Definition: Consensus.h:289
beast::abstract_clock< std::chrono::steady_clock >
ripple::Consensus::phaseEstablish
void phaseEstablish()
Handle establish phase.
Definition: Consensus.h:1259
std::min
T min(T... args)
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:280
ripple::Consensus::MonitoredMode::get
ConsensusMode get() const
Definition: Consensus.h:308
ripple::ConsensusProposal::nodeID
NodeID_t const & nodeID() const
Identifying which peer took this position.
Definition: ConsensusProposal.h:90
ripple::Consensus::prevCloseTime_
NetClock::time_point prevCloseTime_
Definition: Consensus.h:567
ripple::ConsensusProposal::closeTime
NetClock::time_point const & closeTime() const
The current position on the consensus close time.
Definition: ConsensusProposal.h:124
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::ConsensusParms::ledgerMIN_CONSENSUS
std::chrono::milliseconds ledgerMIN_CONSENSUS
The number of seconds we wait minimum to ensure participation.
Definition: ConsensusParms.h:80
ripple::ConsensusMode
ConsensusMode
Represents how a node currently participates in Consensus.
Definition: ConsensusTypes.h:55
ripple::Consensus::peerProposalInternal
bool peerProposalInternal(NetClock::time_point const &now, PeerPosition_t const &newProposal)
Handle a replayed or a new peer proposal.
Definition: Consensus.h:718
ripple::ConsensusParms
Consensus algorithm parameters.
Definition: ConsensusParms.h:33
std::map::begin
T begin(T... args)
ripple::Consensus::MonitoredMode
Definition: Consensus.h:299
std
STL namespace.
ripple::ConsensusProposal::isBowOut
bool isBowOut() const
Get whether this node left the consensus process.
Definition: ConsensusProposal.h:147
ripple::ConsensusParms::avSTUCK_CONSENSUS_TIME
std::size_t avSTUCK_CONSENSUS_TIME
Percentage of previous round duration before we are stuck.
Definition: ConsensusParms.h:131
ripple::Consensus::prevLedgerID_
Ledger_t::ID prevLedgerID_
Definition: Consensus.h:573
ripple::Consensus::openTime_
ConsensusTimer openTime_
Definition: Consensus.h:554
ripple::Consensus::peerProposal
bool peerProposal(NetClock::time_point const &now, PeerPosition_t const &newProposal)
A peer has proposed a new position, adjust our tracking.
Definition: Consensus.h:698
std::stringstream::str
T str(T... args)
ripple::DisputedTx
A transaction discovered to be in dispute during consensus.
Definition: DisputedTx.h:50
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t
ripple::ConsensusParms::avLATE_CONSENSUS_TIME
std::size_t avLATE_CONSENSUS_TIME
Percentage of previous round duration before we advance.
Definition: ConsensusParms.h:125
ripple::Consensus< ripple::test::csf::Peer >::TxSet_t
typename ripple::test::csf::Peer ::TxSet_t TxSet_t
Definition: Consensus.h:286
ripple::Consensus::simulate
void simulate(NetClock::time_point const &now, boost::optional< std::chrono::milliseconds > consensusDelay)
Simulate the consensus process without any network traffic.
Definition: Consensus.h:885
ripple::Consensus::haveConsensus
bool haveConsensus()
Definition: Consensus.h:1542
std::max
T max(T... args)
ripple::getNextLedgerTimeResolution
std::chrono::duration< Rep, Period > getNextLedgerTimeResolution(std::chrono::duration< Rep, Period > previousResolution, bool previousAgree, Seq ledgerSeq)
Calculates the close time resolution for the specified ledger.
Definition: LedgerTiming.h:77
ripple::Consensus::closeLedger
void closeLedger()
Definition: Consensus.h:1306
ripple::ledgerDefaultTimeResolution
constexpr auto ledgerDefaultTimeResolution
Initial resolution of ledger close time.
Definition: LedgerTiming.h:44
ripple::NetClock
Clock for measuring Ripple Network Time.
Definition: chrono.h:46
ripple::Consensus::updateOurPositions
void updateOurPositions()
Definition: Consensus.h:1358
ripple::Consensus::MonitoredMode::mode_
ConsensusMode mode_
Definition: Consensus.h:301
ripple::ConsensusParms::avMIN_CONSENSUS_TIME
std::chrono::milliseconds avMIN_CONSENSUS_TIME
The minimum amount of time to consider the previous round to have taken.
Definition: ConsensusParms.h:107
std::unordered_map
STL class.
ripple::ConsensusProposal::position
Position_t const & position() const
Get the proposed position.
Definition: ConsensusProposal.h:97
ripple::participantsNeeded
int participantsNeeded(int participants, int percent)
How many of the participants must agree to reach a given threshold?
Definition: Consensus.h:1349
ripple::Consensus::startRound
void startRound(NetClock::time_point const &now, typename Ledger_t::ID const &prevLedgerID, Ledger_t prevLedger, hash_set< NodeID_t > const &nowUntrusted, bool proposing)
Kick-off the next round of consensus.
Definition: Consensus.h:615
ripple::ConsensusCloseTimes
Stores the set of initial close times.
Definition: ConsensusTypes.h:174
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::ConsensusProposal::isInitial
bool isInitial() const
Whether this is the first position taken during the current consensus round.
Definition: ConsensusProposal.h:140
ripple::Consensus::rawCloseTimes_
ConsensusCloseTimes rawCloseTimes_
Definition: Consensus.h:581
ripple::Consensus::previousLedger_
Ledger_t previousLedger_
Definition: Consensus.h:575
ripple::ConsensusProposal< NodeID_t, typename Ledger_t::ID, typename TxSet_t::ID >
beast
Definition: base_uint.h:646
std::chrono