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/ConsensusProposal.h>
27 #include <ripple/consensus/ConsensusParms.h>
28 #include <ripple/consensus/ConsensusTypes.h>
29 #include <ripple/consensus/LedgerTiming.h>
30 #include <ripple/consensus/DisputedTx.h>
31 #include <ripple/json/json_writer.h>
32 #include <boost/logic/tribool.hpp>
33 #include <sstream>
34 
35 namespace ripple {
36 
37 
56 bool
58  bool anyTransactions,
59  std::size_t prevProposers,
60  std::size_t proposersClosed,
61  std::size_t proposersValidated,
62  std::chrono::milliseconds prevRoundTime,
63  std::chrono::milliseconds timeSincePrevClose,
65  std::chrono::milliseconds idleInterval,
66  ConsensusParms const & parms,
67  beast::Journal j);
68 
85  std::size_t prevProposers,
86  std::size_t currentProposers,
87  std::size_t currentAgree,
88  std::size_t currentFinished,
89  std::chrono::milliseconds previousAgreeTime,
90  std::chrono::milliseconds currentAgreeTime,
91  ConsensusParms const & parms,
92  bool proposing,
93  beast::Journal j);
94 
283 template <class Adaptor>
285 {
286  using Ledger_t = typename Adaptor::Ledger_t;
287  using TxSet_t = typename Adaptor::TxSet_t;
288  using NodeID_t = typename Adaptor::NodeID_t;
289  using Tx_t = typename TxSet_t::Tx;
290  using PeerPosition_t = typename Adaptor::PeerPosition_t;
292  NodeID_t,
293  typename Ledger_t::ID,
294  typename TxSet_t::ID>;
295 
297 
298  // Helper class to ensure adaptor is notified whenver the ConsensusMode
299  // changes
301  {
303 
304  public:
306  {
307  }
309  get() const
310  {
311  return mode_;
312  }
313 
314  void
315  set(ConsensusMode mode, Adaptor& a)
316  {
317  a.onModeChange(mode_, mode);
318  mode_ = mode;
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)
609  , clock_(clock)
610  , j_{journal}
611 {
612  JLOG(j_.debug()) << "Creating consensus object";
613 }
614 
615 template <class Adaptor>
616 void
618  NetClock::time_point const& now,
619  typename Ledger_t::ID const& prevLedgerID,
620  Ledger_t prevLedger,
621  hash_set<NodeID_t> const& nowUntrusted,
622  bool proposing)
623 {
624  if (firstRound_)
625  {
626  // take our initial view of closeTime_ from the seed ledger
627  prevRoundTime_ = adaptor_.parms().ledgerIDLE_INTERVAL;
628  prevCloseTime_ = prevLedger.closeTime();
629  firstRound_ = false;
630  }
631  else
632  {
633  prevCloseTime_ = rawCloseTimes_.self;
634  }
635 
636  for(NodeID_t const& n : nowUntrusted)
637  recentPeerPositions_.erase(n);
638 
639  ConsensusMode startMode =
640  proposing ? ConsensusMode::proposing : ConsensusMode::observing;
641 
642  // We were handed the wrong ledger
643  if (prevLedger.id() != prevLedgerID)
644  {
645  // try to acquire the correct one
646  if (auto newLedger = adaptor_.acquireLedger(prevLedgerID))
647  {
648  prevLedger = *newLedger;
649  }
650  else // Unable to acquire the correct ledger
651  {
652  startMode = ConsensusMode::wrongLedger;
653  JLOG(j_.info())
654  << "Entering consensus with: " << previousLedger_.id();
655  JLOG(j_.info()) << "Correct LCL is: " << prevLedgerID;
656  }
657  }
658 
659  startRoundInternal(now, prevLedgerID, prevLedger, startMode);
660 }
661 template <class Adaptor>
662 void
664  NetClock::time_point const& now,
665  typename Ledger_t::ID const& prevLedgerID,
666  Ledger_t const& prevLedger,
667  ConsensusMode mode)
668 {
669  phase_ = ConsensusPhase::open;
670  mode_.set(mode, adaptor_);
671  now_ = now;
672  prevLedgerID_ = prevLedgerID;
673  previousLedger_ = prevLedger;
674  result_.reset();
675  convergePercent_ = 0;
676  haveCloseTimeConsensus_ = false;
677  openTime_.reset(clock_.now());
678  currPeerPositions_.clear();
679  acquired_.clear();
680  rawCloseTimes_.peers.clear();
681  rawCloseTimes_.self = {};
682  deadNodes_.clear();
683 
684  closeResolution_ = getNextLedgerTimeResolution(
685  previousLedger_.closeTimeResolution(),
686  previousLedger_.closeAgree(),
687  previousLedger_.seq() + typename Ledger_t::Seq{1});
688 
689  playbackProposals();
690  if (currPeerPositions_.size() > (prevProposers_ / 2))
691  {
692  // We may be falling behind, don't wait for the timer
693  // consider closing the ledger immediately
694  timerEntry(now_);
695  }
696 }
697 
698 template <class Adaptor>
699 bool
701  NetClock::time_point const& now,
702  PeerPosition_t const& newPeerPos)
703 {
704  NodeID_t const& peerID = newPeerPos.proposal().nodeID();
705 
706  // Always need to store recent positions
707  {
708  auto& props = recentPeerPositions_[peerID];
709 
710  if (props.size() >= 10)
711  props.pop_front();
712 
713  props.push_back(newPeerPos);
714  }
715  return peerProposalInternal(now, newPeerPos);
716 }
717 
718 template <class Adaptor>
719 bool
721  NetClock::time_point const& now,
722  PeerPosition_t const& newPeerPos)
723 {
724  // Nothing to do for now if we are currently working on a ledger
725  if (phase_ == ConsensusPhase::accepted)
726  return false;
727 
728  now_ = now;
729 
730  Proposal_t const& newPeerProp = newPeerPos.proposal();
731 
732  NodeID_t const& peerID = newPeerProp.nodeID();
733 
734  if (newPeerProp.prevLedger() != prevLedgerID_)
735  {
736  JLOG(j_.debug()) << "Got proposal for " << newPeerProp.prevLedger()
737  << " but we are on " << prevLedgerID_;
738  return false;
739  }
740 
741  if (deadNodes_.find(peerID) != deadNodes_.end())
742  {
743  using std::to_string;
744  JLOG(j_.info()) << "Position from dead node: " << to_string(peerID);
745  return false;
746  }
747 
748  {
749  // update current position
750  auto peerPosIt = currPeerPositions_.find(peerID);
751 
752  if (peerPosIt != currPeerPositions_.end())
753  {
754  if (newPeerProp.proposeSeq() <=
755  peerPosIt->second.proposal().proposeSeq())
756  {
757  return false;
758  }
759  }
760 
761  if (newPeerProp.isBowOut())
762  {
763  using std::to_string;
764 
765  JLOG(j_.info()) << "Peer bows out: " << to_string(peerID);
766  if (result_)
767  {
768  for (auto& it : result_->disputes)
769  it.second.unVote(peerID);
770  }
771  if (peerPosIt != currPeerPositions_.end())
772  currPeerPositions_.erase(peerID);
773  deadNodes_.insert(peerID);
774 
775  return true;
776  }
777 
778  if (peerPosIt != currPeerPositions_.end())
779  peerPosIt->second = newPeerPos;
780  else
781  currPeerPositions_.emplace(peerID, newPeerPos);
782  }
783 
784  if (newPeerProp.isInitial())
785  {
786  // Record the close time estimate
787  JLOG(j_.trace()) << "Peer reports close time as "
788  << newPeerProp.closeTime().time_since_epoch().count();
789  ++rawCloseTimes_.peers[newPeerProp.closeTime()];
790  }
791 
792  JLOG(j_.trace()) << "Processing peer proposal " << newPeerProp.proposeSeq()
793  << "/" << newPeerProp.position();
794 
795  {
796  auto const ait = acquired_.find(newPeerProp.position());
797  if (ait == acquired_.end())
798  {
799  // acquireTxSet will return the set if it is available, or
800  // spawn a request for it and return none/nullptr. It will call
801  // gotTxSet once it arrives
802  if (auto set = adaptor_.acquireTxSet(newPeerProp.position()))
803  gotTxSet(now_, *set);
804  else
805  JLOG(j_.debug()) << "Don't have tx set for peer";
806  }
807  else if (result_)
808  {
809  updateDisputes(newPeerProp.nodeID(), ait->second);
810  }
811  }
812 
813  return true;
814 }
815 
816 template <class Adaptor>
817 void
819 {
820  // Nothing to do if we are currently working on a ledger
821  if (phase_ == ConsensusPhase::accepted)
822  return;
823 
824  now_ = now;
825 
826  // Check we are on the proper ledger (this may change phase_)
827  checkLedger();
828 
829  if (phase_ == ConsensusPhase::open)
830  {
831  phaseOpen();
832  }
833  else if (phase_ == ConsensusPhase::establish)
834  {
835  phaseEstablish();
836  }
837 }
838 
839 template <class Adaptor>
840 void
842  NetClock::time_point const& now,
843  TxSet_t const& txSet)
844 {
845  // Nothing to do if we've finished work on a ledger
846  if (phase_ == ConsensusPhase::accepted)
847  return;
848 
849  now_ = now;
850 
851  auto id = txSet.id();
852 
853  // If we've already processed this transaction set since requesting
854  // it from the network, there is nothing to do now
855  if (!acquired_.emplace(id, txSet).second)
856  return;
857 
858  if (!result_)
859  {
860  JLOG(j_.debug()) << "Not creating disputes: no position yet.";
861  }
862  else
863  {
864  // Our position is added to acquired_ as soon as we create it,
865  // so this txSet must differ
866  assert(id != result_->position.position());
867  bool any = false;
868  for (auto const& [nodeId, peerPos] : currPeerPositions_)
869  {
870  if (peerPos.proposal().position() == id)
871  {
872  updateDisputes(nodeId, txSet);
873  any = true;
874  }
875  }
876 
877  if (!any)
878  {
879  JLOG(j_.warn())
880  << "By the time we got " << id << " no peers were proposing it";
881  }
882  }
883 }
884 
885 template <class Adaptor>
886 void
888  NetClock::time_point const& now,
889  boost::optional<std::chrono::milliseconds> consensusDelay)
890 {
891  using namespace std::chrono_literals;
892  JLOG(j_.info()) << "Simulating consensus";
893  now_ = now;
894  closeLedger();
895  result_->roundTime.tick(consensusDelay.value_or(100ms));
896  result_->proposers = prevProposers_ = currPeerPositions_.size();
897  prevRoundTime_ = result_->roundTime.read();
898  phase_ = ConsensusPhase::accepted;
899  adaptor_.onForceAccept(
900  *result_,
901  previousLedger_,
902  closeResolution_,
903  rawCloseTimes_,
904  mode_.get(),
905  getJson(true));
906  JLOG(j_.info()) << "Simulation complete";
907 }
908 
909 template <class Adaptor>
912 {
913  using std::to_string;
914  using Int = Json::Value::Int;
915 
917 
918  ret["proposing"] = (mode_.get() == ConsensusMode::proposing);
919  ret["proposers"] = static_cast<int>(currPeerPositions_.size());
920 
921  if (mode_.get() != ConsensusMode::wrongLedger)
922  {
923  ret["synched"] = true;
924  ret["ledger_seq"] = static_cast<std::uint32_t>(previousLedger_.seq())+ 1;
925  ret["close_granularity"] = static_cast<Int>(closeResolution_.count());
926  }
927  else
928  ret["synched"] = false;
929 
930  ret["phase"] = to_string(phase_);
931 
932  if (result_ && !result_->disputes.empty() && !full)
933  ret["disputes"] = static_cast<Int>(result_->disputes.size());
934 
935  if (result_)
936  ret["our_position"] = result_->position.getJson();
937 
938  if (full)
939  {
940  if (result_)
941  ret["current_ms"] =
942  static_cast<Int>(result_->roundTime.read().count());
943  ret["converge_percent"] = convergePercent_;
944  ret["close_resolution"] = static_cast<Int>(closeResolution_.count());
945  ret["have_time_consensus"] = haveCloseTimeConsensus_;
946  ret["previous_proposers"] = static_cast<Int>(prevProposers_);
947  ret["previous_mseconds"] = static_cast<Int>(prevRoundTime_.count());
948 
949  if (!currPeerPositions_.empty())
950  {
952 
953  for (auto const& [nodeId, peerPos] : currPeerPositions_)
954  {
955  ppj[to_string(nodeId)] = peerPos.getJson();
956  }
957  ret["peer_positions"] = std::move(ppj);
958  }
959 
960  if (!acquired_.empty())
961  {
963  for (auto const& at : acquired_)
964  {
965  acq.append(to_string(at.first));
966  }
967  ret["acquired"] = std::move(acq);
968  }
969 
970  if (result_ && !result_->disputes.empty())
971  {
973  for (auto const& [txId, dispute] : result_->disputes)
974  {
975  dsj[to_string(txId)] = dispute.getJson();
976  }
977  ret["disputes"] = std::move(dsj);
978  }
979 
980  if (!rawCloseTimes_.peers.empty())
981  {
983  for (auto const& ct : rawCloseTimes_.peers)
984  {
985  ctj[std::to_string(ct.first.time_since_epoch().count())] =
986  ct.second;
987  }
988  ret["close_times"] = std::move(ctj);
989  }
990 
991  if (!deadNodes_.empty())
992  {
994  for (auto const& dn : deadNodes_)
995  {
996  dnj.append(to_string(dn));
997  }
998  ret["dead_nodes"] = std::move(dnj);
999  }
1000  }
1001 
1002  return ret;
1003 }
1004 
1005 // Handle a change in the prior ledger during a consensus round
1006 template <class Adaptor>
1007 void
1008 Consensus<Adaptor>::handleWrongLedger(typename Ledger_t::ID const& lgrId)
1009 {
1010  assert(lgrId != prevLedgerID_ || previousLedger_.id() != lgrId);
1011 
1012  // Stop proposing because we are out of sync
1013  leaveConsensus();
1014 
1015  // First time switching to this ledger
1016  if (prevLedgerID_ != lgrId)
1017  {
1018  prevLedgerID_ = lgrId;
1019 
1020  // Clear out state
1021  if (result_)
1022  {
1023  result_->disputes.clear();
1024  result_->compares.clear();
1025  }
1026 
1027  currPeerPositions_.clear();
1028  rawCloseTimes_.peers.clear();
1029  deadNodes_.clear();
1030 
1031  // Get back in sync, this will also recreate disputes
1032  playbackProposals();
1033  }
1034 
1035  if (previousLedger_.id() == prevLedgerID_)
1036  return;
1037 
1038  // we need to switch the ledger we're working from
1039  if (auto newLedger = adaptor_.acquireLedger(prevLedgerID_))
1040  {
1041  JLOG(j_.info()) << "Have the consensus ledger " << prevLedgerID_;
1042  startRoundInternal(
1043  now_, lgrId, *newLedger, ConsensusMode::switchedLedger);
1044  }
1045  else
1046  {
1047  mode_.set(ConsensusMode::wrongLedger, adaptor_);
1048  }
1049 }
1050 
1051 template <class Adaptor>
1052 void
1054 {
1055  auto netLgr =
1056  adaptor_.getPrevLedger(prevLedgerID_, previousLedger_, mode_.get());
1057 
1058  if (netLgr != prevLedgerID_)
1059  {
1060  JLOG(j_.warn()) << "View of consensus changed during "
1061  << to_string(phase_) << " status=" << to_string(phase_)
1062  << ", "
1063  << " mode=" << to_string(mode_.get());
1064  JLOG(j_.warn()) << prevLedgerID_ << " to " << netLgr;
1065  JLOG(j_.warn()) << Json::Compact{previousLedger_.getJson()};
1066  JLOG(j_.debug()) << "State on consensus change "
1067  << Json::Compact{getJson(true)};
1068  handleWrongLedger(netLgr);
1069  }
1070  else if (previousLedger_.id() != prevLedgerID_)
1071  handleWrongLedger(netLgr);
1072 }
1073 
1074 template <class Adaptor>
1075 void
1077 {
1078  for (auto const& it : recentPeerPositions_)
1079  {
1080  for (auto const& pos : it.second)
1081  {
1082  if (pos.proposal().prevLedger() == prevLedgerID_)
1083  {
1084  if (peerProposalInternal(now_, pos))
1085  adaptor_.share(pos);
1086  }
1087  }
1088  }
1089 }
1090 
1091 template <class Adaptor>
1092 void
1094 {
1095  using namespace std::chrono;
1096 
1097  // it is shortly before ledger close time
1098  bool anyTransactions = adaptor_.hasOpenTransactions();
1099  auto proposersClosed = currPeerPositions_.size();
1100  auto proposersValidated = adaptor_.proposersValidated(prevLedgerID_);
1101 
1102  openTime_.tick(clock_.now());
1103 
1104  // This computes how long since last ledger's close time
1105  milliseconds sinceClose;
1106  {
1107  bool previousCloseCorrect =
1108  (mode_.get() != ConsensusMode::wrongLedger) &&
1109  previousLedger_.closeAgree() &&
1110  (previousLedger_.closeTime() !=
1111  (previousLedger_.parentCloseTime() + 1s));
1112 
1113  auto lastCloseTime = previousCloseCorrect
1114  ? previousLedger_.closeTime() // use consensus timing
1115  : prevCloseTime_; // use the time we saw internally
1116 
1117  if (now_ >= lastCloseTime)
1118  sinceClose = duration_cast<milliseconds>(now_ - lastCloseTime);
1119  else
1120  sinceClose = -duration_cast<milliseconds>(lastCloseTime - now_);
1121  }
1122 
1123  auto const idleInterval = std::max<milliseconds>(
1124  adaptor_.parms().ledgerIDLE_INTERVAL,
1125  2 * previousLedger_.closeTimeResolution());
1126 
1127  // Decide if we should close the ledger
1128  if (shouldCloseLedger(
1129  anyTransactions,
1130  prevProposers_,
1131  proposersClosed,
1132  proposersValidated,
1133  prevRoundTime_,
1134  sinceClose,
1135  openTime_.read(),
1136  idleInterval,
1137  adaptor_.parms(),
1138  j_))
1139  {
1140  closeLedger();
1141  }
1142 }
1143 
1144 template <class Adaptor>
1145 bool
1147 {
1148  auto const& parms = adaptor_.parms();
1149  std::uint32_t const ahead (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 = adaptor_.laggards(previousLedger_.seq(),
1154  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 ||
1170  !laggards ||
1171  !totalValidators ||
1172  !adaptor_.validator() ||
1173  !adaptor_.haveValidated() ||
1174  result_->roundTime.read() > parms.ledgerMAX_CONSENSUS)
1175  {
1176  j_.debug() << "not pausing (early)" << vars.str();
1177  return false;
1178  }
1179 
1180  bool willPause = false;
1181 
1195  constexpr static std::size_t maxPausePhase = 4;
1196 
1216  std::size_t const phase = (ahead - 1) % (maxPausePhase + 1);
1217 
1218  // validators that remain after the laggards() function are considered
1219  // offline, and should be considered as laggards for purposes of
1220  // evaluating whether the threshold for non-laggards has been reached.
1221  switch (phase)
1222  {
1223  case 0:
1224  // Laggards and offline shouldn't preclude consensus.
1225  if (laggards + offline > totalValidators - quorum)
1226  willPause = true;
1227  break;
1228  case maxPausePhase:
1229  // No tolerance.
1230  willPause = true;
1231  break;
1232  default:
1233  // Ensure that sufficient validators are known to be not lagging.
1234  // Their sufficiently most recent validation sequence was equal to
1235  // or greater than our own.
1236  //
1237  // The threshold is the amount required for quorum plus
1238  // the proportion of the remainder based on number of intermediate
1239  // phases between 0 and max.
1240  float const nonLaggards = totalValidators - (laggards + offline);
1241  float const quorumRatio =
1242  static_cast<float>(quorum) / totalValidators;
1243  float const allowedDissent = 1.0f - quorumRatio;
1244  float const phaseFactor = static_cast<float>(phase) / maxPausePhase;
1245 
1246  if (nonLaggards / totalValidators <
1247  quorumRatio + (allowedDissent * phaseFactor))
1248  {
1249  willPause = true;
1250  }
1251  }
1252 
1253  if (willPause)
1254  j_.warn() << "pausing" << vars.str();
1255  else
1256  j_.debug() << "not pausing" << vars.str();
1257  return willPause;
1258 }
1259 
1260 template <class Adaptor>
1261 void
1263 {
1264  // can only establish consensus if we already took a stance
1265  assert(result_);
1266 
1267  using namespace std::chrono;
1268  ConsensusParms const & parms = adaptor_.parms();
1269 
1270  result_->roundTime.tick(clock_.now());
1271  result_->proposers = currPeerPositions_.size();
1272 
1273  convergePercent_ = result_->roundTime.read() * 100 /
1274  std::max<milliseconds>(prevRoundTime_, parms.avMIN_CONSENSUS_TIME);
1275 
1276  // Give everyone a chance to take an initial position
1277  if (result_->roundTime.read() < parms.ledgerMIN_CONSENSUS)
1278  return;
1279 
1280  updateOurPositions();
1281 
1282  // Nothing to do if too many laggards or we don't have consensus.
1283  if (shouldPause() || !haveConsensus())
1284  return;
1285 
1286  if (!haveCloseTimeConsensus_)
1287  {
1288  JLOG(j_.info()) << "We have TX consensus but not CT consensus";
1289  return;
1290  }
1291 
1292  JLOG(j_.info()) << "Converge cutoff (" << currPeerPositions_.size()
1293  << " participants)";
1294  adaptor_.updateOperatingMode(currPeerPositions_.size());
1295  prevProposers_ = currPeerPositions_.size();
1296  prevRoundTime_ = result_->roundTime.read();
1297  phase_ = ConsensusPhase::accepted;
1298  adaptor_.onAccept(
1299  *result_,
1300  previousLedger_,
1301  closeResolution_,
1302  rawCloseTimes_,
1303  mode_.get(),
1304  getJson(true));
1305 }
1306 
1307 template <class Adaptor>
1308 void
1310 {
1311  // We should not be closing if we already have a position
1312  assert(!result_);
1313 
1314  phase_ = ConsensusPhase::establish;
1315  rawCloseTimes_.self = now_;
1316 
1317  result_.emplace(adaptor_.onClose(previousLedger_, now_, mode_.get()));
1318  result_->roundTime.reset(clock_.now());
1319  // Share the newly created transaction set if we haven't already
1320  // received it from a peer
1321  if (acquired_.emplace(result_->txns.id(), result_->txns).second)
1322  adaptor_.share(result_->txns);
1323 
1324  if (mode_.get() == ConsensusMode::proposing)
1325  adaptor_.propose(result_->position);
1326 
1327  // Create disputes with any peer positions we have transactions for
1328  for (auto const& pit : currPeerPositions_)
1329  {
1330  auto const& pos = pit.second.proposal().position();
1331  auto const it = acquired_.find(pos);
1332  if (it != acquired_.end())
1333  {
1334  createDisputes(it->second);
1335  }
1336  }
1337 }
1338 
1351 inline int
1352 participantsNeeded(int participants, int percent)
1353 {
1354  int result = ((participants * percent) + (percent / 2)) / 100;
1355 
1356  return (result == 0) ? 1 : result;
1357 }
1358 
1359 template <class Adaptor>
1360 void
1362 {
1363  // We must have a position if we are updating it
1364  assert(result_);
1365  ConsensusParms const & parms = adaptor_.parms();
1366 
1367  // Compute a cutoff time
1368  auto const peerCutoff = now_ - parms.proposeFRESHNESS;
1369  auto const ourCutoff = now_ - parms.proposeINTERVAL;
1370 
1371  // Verify freshness of peer positions and compute close times
1372  std::map<NetClock::time_point, int> closeTimeVotes;
1373  {
1374  auto it = currPeerPositions_.begin();
1375  while (it != currPeerPositions_.end())
1376  {
1377  Proposal_t const& peerProp = it->second.proposal();
1378  if (peerProp.isStale(peerCutoff))
1379  {
1380  // peer's proposal is stale, so remove it
1381  NodeID_t const& peerID = peerProp.nodeID();
1382  JLOG(j_.warn()) << "Removing stale proposal from " << peerID;
1383  for (auto& dt : result_->disputes)
1384  dt.second.unVote(peerID);
1385  it = currPeerPositions_.erase(it);
1386  }
1387  else
1388  {
1389  // proposal is still fresh
1390  ++closeTimeVotes[asCloseTime(peerProp.closeTime())];
1391  ++it;
1392  }
1393  }
1394  }
1395 
1396  // This will stay unseated unless there are any changes
1397  boost::optional<TxSet_t> ourNewSet;
1398 
1399  // Update votes on disputed transactions
1400  {
1401  boost::optional<typename TxSet_t::MutableTxSet> mutableSet;
1402  for (auto& [txId, dispute] : result_->disputes)
1403  {
1404  // Because the threshold for inclusion increases,
1405  // time can change our position on a dispute
1406  if (dispute.updateVote(
1407  convergePercent_,
1408  mode_.get()== ConsensusMode::proposing,
1409  parms))
1410  {
1411  if (!mutableSet)
1412  mutableSet.emplace(result_->txns);
1413 
1414  if (dispute.getOurVote())
1415  {
1416  // now a yes
1417  mutableSet->insert(dispute.tx());
1418  }
1419  else
1420  {
1421  // now a no
1422  mutableSet->erase(txId);
1423  }
1424  }
1425  }
1426 
1427  if (mutableSet)
1428  ourNewSet.emplace(std::move(*mutableSet));
1429  }
1430 
1431  NetClock::time_point consensusCloseTime = {};
1432  haveCloseTimeConsensus_ = false;
1433 
1434  if (currPeerPositions_.empty())
1435  {
1436  // no other times
1437  haveCloseTimeConsensus_ = true;
1438  consensusCloseTime = asCloseTime(result_->position.closeTime());
1439  }
1440  else
1441  {
1442  int neededWeight;
1443 
1444  if (convergePercent_ < parms.avMID_CONSENSUS_TIME)
1445  neededWeight = parms.avINIT_CONSENSUS_PCT;
1446  else if (convergePercent_ < parms.avLATE_CONSENSUS_TIME)
1447  neededWeight = parms.avMID_CONSENSUS_PCT;
1448  else if (convergePercent_ < parms.avSTUCK_CONSENSUS_TIME)
1449  neededWeight = parms.avLATE_CONSENSUS_PCT;
1450  else
1451  neededWeight = parms.avSTUCK_CONSENSUS_PCT;
1452 
1453  int participants = currPeerPositions_.size();
1454  if (mode_.get() == ConsensusMode::proposing)
1455  {
1456  ++closeTimeVotes[asCloseTime(result_->position.closeTime())];
1457  ++participants;
1458  }
1459 
1460  // Threshold for non-zero vote
1461  int threshVote = participantsNeeded(participants, neededWeight);
1462 
1463  // Threshold to declare consensus
1464  int const threshConsensus =
1465  participantsNeeded(participants, parms.avCT_CONSENSUS_PCT);
1466 
1467  JLOG(j_.info()) << "Proposers:" << currPeerPositions_.size()
1468  << " nw:" << neededWeight << " thrV:" << threshVote
1469  << " thrC:" << threshConsensus;
1470 
1471  for (auto const& [t, v] : closeTimeVotes)
1472  {
1473  JLOG(j_.debug())
1474  << "CCTime: seq "
1475  << static_cast<std::uint32_t>(previousLedger_.seq()) + 1 << ": "
1476  << t.time_since_epoch().count() << " has " << v
1477  << ", " << threshVote << " required";
1478 
1479  if (v >= threshVote)
1480  {
1481  // A close time has enough votes for us to try to agree
1482  consensusCloseTime = t;
1483  threshVote = v;
1484 
1485  if (threshVote >= threshConsensus)
1486  haveCloseTimeConsensus_ = true;
1487  }
1488  }
1489 
1490  if (!haveCloseTimeConsensus_)
1491  {
1492  JLOG(j_.debug())
1493  << "No CT consensus:"
1494  << " Proposers:" << currPeerPositions_.size()
1495  << " Mode:" << to_string(mode_.get())
1496  << " Thresh:" << threshConsensus
1497  << " Pos:" << consensusCloseTime.time_since_epoch().count();
1498  }
1499  }
1500 
1501  if (!ourNewSet &&
1502  ((consensusCloseTime != asCloseTime(result_->position.closeTime())) ||
1503  result_->position.isStale(ourCutoff)))
1504  {
1505  // close time changed or our position is stale
1506  ourNewSet.emplace(result_->txns);
1507  }
1508 
1509  if (ourNewSet)
1510  {
1511  auto newID = ourNewSet->id();
1512 
1513  result_->txns = std::move(*ourNewSet);
1514 
1515  JLOG(j_.info()) << "Position change: CTime "
1516  << consensusCloseTime.time_since_epoch().count()
1517  << ", tx " << newID;
1518 
1519  result_->position.changePosition(newID, consensusCloseTime, now_);
1520 
1521  // Share our new transaction set and update disputes
1522  // if we haven't already received it
1523  if (acquired_.emplace(newID, result_->txns).second)
1524  {
1525  if (!result_->position.isBowOut())
1526  adaptor_.share(result_->txns);
1527 
1528  for (auto const& [nodeId, peerPos] : currPeerPositions_)
1529  {
1530  Proposal_t const& p = peerPos.proposal();
1531  if (p.position() == newID)
1532  updateDisputes(nodeId, result_->txns);
1533  }
1534  }
1535 
1536  // Share our new position if we are still participating this round
1537  if (!result_->position.isBowOut() &&
1538  (mode_.get() == ConsensusMode::proposing))
1539  adaptor_.propose(result_->position);
1540  }
1541 }
1542 
1543 template <class Adaptor>
1544 bool
1546 {
1547  // Must have a stance if we are checking for consensus
1548  assert(result_);
1549 
1550  // CHECKME: should possibly count unacquired TX sets as disagreeing
1551  int agree = 0, disagree = 0;
1552 
1553  auto ourPosition = result_->position.position();
1554 
1555  // Count number of agreements/disagreements with our position
1556  for (auto const& [nodeId, peerPos] : currPeerPositions_)
1557  {
1558  Proposal_t const& peerProp = peerPos.proposal();
1559  if (peerProp.position() == ourPosition)
1560  {
1561  ++agree;
1562  }
1563  else
1564  {
1565  using std::to_string;
1566 
1567  JLOG(j_.debug()) << to_string(nodeId) << " has "
1568  << to_string(peerProp.position());
1569  ++disagree;
1570  }
1571  }
1572  auto currentFinished =
1573  adaptor_.proposersFinished(previousLedger_, prevLedgerID_);
1574 
1575  JLOG(j_.debug()) << "Checking for TX consensus: agree=" << agree
1576  << ", disagree=" << disagree;
1577 
1578  // Determine if we actually have consensus or not
1579  result_->state = checkConsensus(
1580  prevProposers_,
1581  agree + disagree,
1582  agree,
1583  currentFinished,
1584  prevRoundTime_,
1585  result_->roundTime.read(),
1586  adaptor_.parms(),
1587  mode_.get() == ConsensusMode::proposing,
1588  j_);
1589 
1590  if (result_->state == ConsensusState::No)
1591  return false;
1592 
1593  // There is consensus, but we need to track if the network moved on
1594  // without us.
1595  if (result_->state == ConsensusState::MovedOn)
1596  {
1597  JLOG(j_.error()) << "Unable to reach consensus";
1598  JLOG(j_.error()) << Json::Compact{getJson(true)};
1599  }
1600 
1601  return true;
1602 }
1603 
1604 template <class Adaptor>
1605 void
1607 {
1608  if (mode_.get() == ConsensusMode::proposing)
1609  {
1610  if (result_ && !result_->position.isBowOut())
1611  {
1612  result_->position.bowOut(now_);
1613  adaptor_.propose(result_->position);
1614  }
1615 
1616  mode_.set(ConsensusMode::observing, adaptor_);
1617  JLOG(j_.info()) << "Bowing out of consensus";
1618  }
1619 }
1620 
1621 template <class Adaptor>
1622 void
1624 {
1625  // Cannot create disputes without our stance
1626  assert(result_);
1627 
1628  // Only create disputes if this is a new set
1629  if (!result_->compares.emplace(o.id()).second)
1630  return;
1631 
1632  // Nothing to dispute if we agree
1633  if (result_->txns.id() == o.id())
1634  return;
1635 
1636  JLOG(j_.debug()) << "createDisputes " << result_->txns.id() << " to "
1637  << o.id();
1638 
1639  auto differences = result_->txns.compare(o);
1640 
1641  int dc = 0;
1642 
1643  for (auto const& [txId, inThisSet] : differences)
1644  {
1645  ++dc;
1646  // create disputed transactions (from the ledger that has them)
1647  assert(
1648  (inThisSet && result_->txns.find(txId) && !o.find(txId)) ||
1649  (!inThisSet && !result_->txns.find(txId) && o.find(txId)));
1650 
1651  Tx_t tx = inThisSet ? *result_->txns.find(txId) : *o.find(txId);
1652  auto txID = tx.id();
1653 
1654  if (result_->disputes.find(txID) != result_->disputes.end())
1655  continue;
1656 
1657  JLOG(j_.debug()) << "Transaction " << txID << " is disputed";
1658 
1659  typename Result::Dispute_t dtx{tx, result_->txns.exists(txID),
1660  std::max(prevProposers_, currPeerPositions_.size()), 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:140
Json::Value::Int
Json::Int Int
Definition: json_value.h:150
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
sstream
ripple::Consensus::checkLedger
void checkLedger()
Check if our previous ledger matches the network's.
Definition: Consensus.h:1053
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:1076
ripple::Consensus::shouldPause
bool shouldPause() const
Evaluate whether pausing increases likelihood of validation.
Definition: Consensus.h:1146
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:287
ripple::Consensus::createDisputes
void createDisputes(TxSet_t const &o)
Definition: Consensus.h:1623
ripple::Consensus::handleWrongLedger
void handleWrongLedger(typename Ledger_t::ID const &lgrId)
Definition: Consensus.h:1008
ripple::ConsensusParms::avMID_CONSENSUS_TIME
std::size_t avMID_CONSENSUS_TIME
Percentage of previous round duration before we advance.
Definition: ConsensusParms.h:122
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:289
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:44
ripple::ConsensusParms::avLATE_CONSENSUS_PCT
std::size_t avLATE_CONSENSUS_PCT
Percentage of nodes that most vote yes after advancing.
Definition: ConsensusParms.h:131
ripple::Consensus::MonitoredMode::set
void set(ConsensusMode mode, Adaptor &a)
Definition: Consensus.h:315
ripple::Consensus::MonitoredMode::MonitoredMode
MonitoredMode(ConsensusMode m)
Definition: Consensus.h:305
Json::Compact
Decorator for streaming out compact json.
Definition: json_writer.h:277
ripple::Consensus::getJson
Json::Value getJson(bool full) const
Get the Json state of the consensus process.
Definition: Consensus.h:911
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:137
ripple::Consensus
Generic implementation of consensus algorithm.
Definition: Consensus.h:284
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:302
ripple::Consensus::leaveConsensus
void leaveConsensus()
Definition: Consensus.h:1606
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:128
ripple::Consensus::currPeerPositions_
hash_map< NodeID_t, PeerPosition_t > currPeerPositions_
Definition: Consensus.h:587
boost
Definition: IPAddress.h:127
ripple::ConsensusParms::proposeINTERVAL
std::chrono::seconds proposeINTERVAL
How often we force generating a new proposal to keep ours fresh.
Definition: ConsensusParms.h:68
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:841
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:1093
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:907
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:45
ripple::Consensus::timerEntry
void timerEntry(NetClock::time_point const &now)
Call periodically to drive consensus forward.
Definition: Consensus.h:818
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:663
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:65
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:271
ripple::ConsensusPhase
ConsensusPhase
Phases of consensus for a single ledger round.
Definition: ConsensusTypes.h:103
beast::Journal::error
Stream error() const
Definition: Journal.h:307
beast::Journal::info
Stream info() const
Definition: Journal.h:297
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:288
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:119
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:60
std::uint32_t
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
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:286
ripple::ConsensusParms::avMID_CONSENSUS_PCT
std::size_t avMID_CONSENSUS_PCT
Percentage of nodes that most vote yes after advancing.
Definition: ConsensusParms.h:125
ripple::Consensus< ripple::test::csf::Peer >::PeerPosition_t
typename ripple::test::csf::Peer ::PeerPosition_t PeerPosition_t
Definition: Consensus.h:290
beast::abstract_clock< std::chrono::steady_clock >
ripple::Consensus::phaseEstablish
void phaseEstablish()
Handle establish phase.
Definition: Consensus.h:1262
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:272
ripple::Consensus::MonitoredMode::get
ConsensusMode get() const
Definition: Consensus.h:309
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:82
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:720
ripple::ConsensusParms
Consensus algorithm parameters.
Definition: ConsensusParms.h:33
std::map::begin
T begin(T... args)
ripple::Consensus::MonitoredMode
Definition: Consensus.h:300
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:134
ripple::Consensus::prevLedgerID_
Ledger_t::ID prevLedgerID_
Definition: Consensus.h:573
ripple::Consensus::openTime_
ConsensusTimer openTime_
Definition: Consensus.h:554
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::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:700
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:292
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:128
ripple::Consensus< ripple::test::csf::Peer >::TxSet_t
typename ripple::test::csf::Peer ::TxSet_t TxSet_t
Definition: Consensus.h:287
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:887
ripple::Consensus::haveConsensus
bool haveConsensus()
Definition: Consensus.h:1545
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:79
ripple::Consensus::closeLedger
void closeLedger()
Definition: Consensus.h:1309
ripple::ledgerDefaultTimeResolution
constexpr auto ledgerDefaultTimeResolution
Initial resolution of ledger close time.
Definition: LedgerTiming.h:46
ripple::NetClock
Clock for measuring Ripple Network Time.
Definition: chrono.h:45
ripple::Consensus::updateOurPositions
void updateOurPositions()
Definition: Consensus.h:1361
ripple::Consensus::MonitoredMode::mode_
ConsensusMode mode_
Definition: Consensus.h:302
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:110
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:1352
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:617
ripple::ConsensusCloseTimes
Stores the set of initial close times.
Definition: ConsensusTypes.h:174
Json::Value
Represents a JSON value.
Definition: json_value.h:141
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:582
std::chrono