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  JLOG(j_.info()) << "Position from dead node: " << peerID;
742  return false;
743  }
744 
745  {
746  // update current position
747  auto peerPosIt = currPeerPositions_.find(peerID);
748 
749  if (peerPosIt != currPeerPositions_.end())
750  {
751  if (newPeerProp.proposeSeq() <=
752  peerPosIt->second.proposal().proposeSeq())
753  {
754  return false;
755  }
756  }
757 
758  if (newPeerProp.isBowOut())
759  {
760  JLOG(j_.info()) << "Peer " << peerID << " bows out";
761  if (result_)
762  {
763  for (auto& it : result_->disputes)
764  it.second.unVote(peerID);
765  }
766  if (peerPosIt != currPeerPositions_.end())
767  currPeerPositions_.erase(peerID);
768  deadNodes_.insert(peerID);
769 
770  return true;
771  }
772 
773  if (peerPosIt != currPeerPositions_.end())
774  peerPosIt->second = newPeerPos;
775  else
776  currPeerPositions_.emplace(peerID, newPeerPos);
777  }
778 
779  if (newPeerProp.isInitial())
780  {
781  // Record the close time estimate
782  JLOG(j_.trace()) << "Peer reports close time as "
783  << newPeerProp.closeTime().time_since_epoch().count();
784  ++rawCloseTimes_.peers[newPeerProp.closeTime()];
785  }
786 
787  JLOG(j_.trace()) << "Processing peer proposal " << newPeerProp.proposeSeq()
788  << "/" << newPeerProp.position();
789 
790  {
791  auto const ait = acquired_.find(newPeerProp.position());
792  if (ait == acquired_.end())
793  {
794  // acquireTxSet will return the set if it is available, or
795  // spawn a request for it and return none/nullptr. It will call
796  // gotTxSet once it arrives
797  if (auto set = adaptor_.acquireTxSet(newPeerProp.position()))
798  gotTxSet(now_, *set);
799  else
800  JLOG(j_.debug()) << "Don't have tx set for peer";
801  }
802  else if (result_)
803  {
804  updateDisputes(newPeerProp.nodeID(), ait->second);
805  }
806  }
807 
808  return true;
809 }
810 
811 template <class Adaptor>
812 void
814 {
815  // Nothing to do if we are currently working on a ledger
816  if (phase_ == ConsensusPhase::accepted)
817  return;
818 
819  now_ = now;
820 
821  // Check we are on the proper ledger (this may change phase_)
822  checkLedger();
823 
824  if (phase_ == ConsensusPhase::open)
825  {
826  phaseOpen();
827  }
828  else if (phase_ == ConsensusPhase::establish)
829  {
830  phaseEstablish();
831  }
832 }
833 
834 template <class Adaptor>
835 void
837  NetClock::time_point const& now,
838  TxSet_t const& txSet)
839 {
840  // Nothing to do if we've finished work on a ledger
841  if (phase_ == ConsensusPhase::accepted)
842  return;
843 
844  now_ = now;
845 
846  auto id = txSet.id();
847 
848  // If we've already processed this transaction set since requesting
849  // it from the network, there is nothing to do now
850  if (!acquired_.emplace(id, txSet).second)
851  return;
852 
853  if (!result_)
854  {
855  JLOG(j_.debug()) << "Not creating disputes: no position yet.";
856  }
857  else
858  {
859  // Our position is added to acquired_ as soon as we create it,
860  // so this txSet must differ
861  assert(id != result_->position.position());
862  bool any = false;
863  for (auto const& [nodeId, peerPos] : currPeerPositions_)
864  {
865  if (peerPos.proposal().position() == id)
866  {
867  updateDisputes(nodeId, txSet);
868  any = true;
869  }
870  }
871 
872  if (!any)
873  {
874  JLOG(j_.warn())
875  << "By the time we got " << id << " no peers were proposing it";
876  }
877  }
878 }
879 
880 template <class Adaptor>
881 void
883  NetClock::time_point const& now,
884  boost::optional<std::chrono::milliseconds> consensusDelay)
885 {
886  using namespace std::chrono_literals;
887  JLOG(j_.info()) << "Simulating consensus";
888  now_ = now;
889  closeLedger();
890  result_->roundTime.tick(consensusDelay.value_or(100ms));
891  result_->proposers = prevProposers_ = currPeerPositions_.size();
892  prevRoundTime_ = result_->roundTime.read();
893  phase_ = ConsensusPhase::accepted;
894  adaptor_.onForceAccept(
895  *result_,
896  previousLedger_,
897  closeResolution_,
898  rawCloseTimes_,
899  mode_.get(),
900  getJson(true));
901  JLOG(j_.info()) << "Simulation complete";
902 }
903 
904 template <class Adaptor>
907 {
908  using std::to_string;
909  using Int = Json::Value::Int;
910 
912 
913  ret["proposing"] = (mode_.get() == ConsensusMode::proposing);
914  ret["proposers"] = static_cast<int>(currPeerPositions_.size());
915 
916  if (mode_.get() != ConsensusMode::wrongLedger)
917  {
918  ret["synched"] = true;
919  ret["ledger_seq"] =
920  static_cast<std::uint32_t>(previousLedger_.seq()) + 1;
921  ret["close_granularity"] = static_cast<Int>(closeResolution_.count());
922  }
923  else
924  ret["synched"] = false;
925 
926  ret["phase"] = to_string(phase_);
927 
928  if (result_ && !result_->disputes.empty() && !full)
929  ret["disputes"] = static_cast<Int>(result_->disputes.size());
930 
931  if (result_)
932  ret["our_position"] = result_->position.getJson();
933 
934  if (full)
935  {
936  if (result_)
937  ret["current_ms"] =
938  static_cast<Int>(result_->roundTime.read().count());
939  ret["converge_percent"] = convergePercent_;
940  ret["close_resolution"] = static_cast<Int>(closeResolution_.count());
941  ret["have_time_consensus"] = haveCloseTimeConsensus_;
942  ret["previous_proposers"] = static_cast<Int>(prevProposers_);
943  ret["previous_mseconds"] = static_cast<Int>(prevRoundTime_.count());
944 
945  if (!currPeerPositions_.empty())
946  {
948 
949  for (auto const& [nodeId, peerPos] : currPeerPositions_)
950  {
951  ppj[to_string(nodeId)] = peerPos.getJson();
952  }
953  ret["peer_positions"] = std::move(ppj);
954  }
955 
956  if (!acquired_.empty())
957  {
959  for (auto const& at : acquired_)
960  {
961  acq.append(to_string(at.first));
962  }
963  ret["acquired"] = std::move(acq);
964  }
965 
966  if (result_ && !result_->disputes.empty())
967  {
969  for (auto const& [txId, dispute] : result_->disputes)
970  {
971  dsj[to_string(txId)] = dispute.getJson();
972  }
973  ret["disputes"] = std::move(dsj);
974  }
975 
976  if (!rawCloseTimes_.peers.empty())
977  {
979  for (auto const& ct : rawCloseTimes_.peers)
980  {
981  ctj[std::to_string(ct.first.time_since_epoch().count())] =
982  ct.second;
983  }
984  ret["close_times"] = std::move(ctj);
985  }
986 
987  if (!deadNodes_.empty())
988  {
990  for (auto const& dn : deadNodes_)
991  {
992  dnj.append(to_string(dn));
993  }
994  ret["dead_nodes"] = std::move(dnj);
995  }
996  }
997 
998  return ret;
999 }
1000 
1001 // Handle a change in the prior ledger during a consensus round
1002 template <class Adaptor>
1003 void
1004 Consensus<Adaptor>::handleWrongLedger(typename Ledger_t::ID const& lgrId)
1005 {
1006  assert(lgrId != prevLedgerID_ || previousLedger_.id() != lgrId);
1007 
1008  // Stop proposing because we are out of sync
1009  leaveConsensus();
1010 
1011  // First time switching to this ledger
1012  if (prevLedgerID_ != lgrId)
1013  {
1014  prevLedgerID_ = lgrId;
1015 
1016  // Clear out state
1017  if (result_)
1018  {
1019  result_->disputes.clear();
1020  result_->compares.clear();
1021  }
1022 
1023  currPeerPositions_.clear();
1024  rawCloseTimes_.peers.clear();
1025  deadNodes_.clear();
1026 
1027  // Get back in sync, this will also recreate disputes
1028  playbackProposals();
1029  }
1030 
1031  if (previousLedger_.id() == prevLedgerID_)
1032  return;
1033 
1034  // we need to switch the ledger we're working from
1035  if (auto newLedger = adaptor_.acquireLedger(prevLedgerID_))
1036  {
1037  JLOG(j_.info()) << "Have the consensus ledger " << prevLedgerID_;
1038  startRoundInternal(
1039  now_, lgrId, *newLedger, ConsensusMode::switchedLedger);
1040  }
1041  else
1042  {
1043  mode_.set(ConsensusMode::wrongLedger, adaptor_);
1044  }
1045 }
1046 
1047 template <class Adaptor>
1048 void
1050 {
1051  auto netLgr =
1052  adaptor_.getPrevLedger(prevLedgerID_, previousLedger_, mode_.get());
1053 
1054  if (netLgr != prevLedgerID_)
1055  {
1056  JLOG(j_.warn()) << "View of consensus changed during "
1057  << to_string(phase_) << " status=" << to_string(phase_)
1058  << ", "
1059  << " mode=" << to_string(mode_.get());
1060  JLOG(j_.warn()) << prevLedgerID_ << " to " << netLgr;
1061  JLOG(j_.warn()) << Json::Compact{previousLedger_.getJson()};
1062  JLOG(j_.debug()) << "State on consensus change "
1063  << Json::Compact{getJson(true)};
1064  handleWrongLedger(netLgr);
1065  }
1066  else if (previousLedger_.id() != prevLedgerID_)
1067  handleWrongLedger(netLgr);
1068 }
1069 
1070 template <class Adaptor>
1071 void
1073 {
1074  for (auto const& it : recentPeerPositions_)
1075  {
1076  for (auto const& pos : it.second)
1077  {
1078  if (pos.proposal().prevLedger() == prevLedgerID_)
1079  {
1080  if (peerProposalInternal(now_, pos))
1081  adaptor_.share(pos);
1082  }
1083  }
1084  }
1085 }
1086 
1087 template <class Adaptor>
1088 void
1090 {
1091  using namespace std::chrono;
1092 
1093  // it is shortly before ledger close time
1094  bool anyTransactions = adaptor_.hasOpenTransactions();
1095  auto proposersClosed = currPeerPositions_.size();
1096  auto proposersValidated = adaptor_.proposersValidated(prevLedgerID_);
1097 
1098  openTime_.tick(clock_.now());
1099 
1100  // This computes how long since last ledger's close time
1101  milliseconds sinceClose;
1102  {
1103  bool previousCloseCorrect =
1104  (mode_.get() != ConsensusMode::wrongLedger) &&
1105  previousLedger_.closeAgree() &&
1106  (previousLedger_.closeTime() !=
1107  (previousLedger_.parentCloseTime() + 1s));
1108 
1109  auto lastCloseTime = previousCloseCorrect
1110  ? previousLedger_.closeTime() // use consensus timing
1111  : prevCloseTime_; // use the time we saw internally
1112 
1113  if (now_ >= lastCloseTime)
1114  sinceClose = duration_cast<milliseconds>(now_ - lastCloseTime);
1115  else
1116  sinceClose = -duration_cast<milliseconds>(lastCloseTime - now_);
1117  }
1118 
1119  auto const idleInterval = std::max<milliseconds>(
1120  adaptor_.parms().ledgerIDLE_INTERVAL,
1121  2 * previousLedger_.closeTimeResolution());
1122 
1123  // Decide if we should close the ledger
1124  if (shouldCloseLedger(
1125  anyTransactions,
1126  prevProposers_,
1127  proposersClosed,
1128  proposersValidated,
1129  prevRoundTime_,
1130  sinceClose,
1131  openTime_.read(),
1132  idleInterval,
1133  adaptor_.parms(),
1134  j_))
1135  {
1136  closeLedger();
1137  }
1138 }
1139 
1140 template <class Adaptor>
1141 bool
1143 {
1144  auto const& parms = adaptor_.parms();
1145  std::uint32_t const ahead(
1146  previousLedger_.seq() -
1147  std::min(adaptor_.getValidLedgerIndex(), previousLedger_.seq()));
1148  auto [quorum, trustedKeys] = adaptor_.getQuorumKeys();
1149  std::size_t const totalValidators = trustedKeys.size();
1150  std::size_t laggards =
1151  adaptor_.laggards(previousLedger_.seq(), trustedKeys);
1152  std::size_t const offline = trustedKeys.size();
1153 
1154  std::stringstream vars;
1155  vars << " (working seq: " << previousLedger_.seq() << ", "
1156  << "validated seq: " << adaptor_.getValidLedgerIndex() << ", "
1157  << "am validator: " << adaptor_.validator() << ", "
1158  << "have validated: " << adaptor_.haveValidated() << ", "
1159  << "roundTime: " << result_->roundTime.read().count() << ", "
1160  << "max consensus time: " << parms.ledgerMAX_CONSENSUS.count() << ", "
1161  << "validators: " << totalValidators << ", "
1162  << "laggards: " << laggards << ", "
1163  << "offline: " << offline << ", "
1164  << "quorum: " << quorum << ")";
1165 
1166  if (!ahead || !laggards || !totalValidators || !adaptor_.validator() ||
1167  !adaptor_.haveValidated() ||
1168  result_->roundTime.read() > parms.ledgerMAX_CONSENSUS)
1169  {
1170  j_.debug() << "not pausing (early)" << vars.str();
1171  return false;
1172  }
1173 
1174  bool willPause = false;
1175 
1189  constexpr static std::size_t maxPausePhase = 4;
1190 
1210  std::size_t const phase = (ahead - 1) % (maxPausePhase + 1);
1211 
1212  // validators that remain after the laggards() function are considered
1213  // offline, and should be considered as laggards for purposes of
1214  // evaluating whether the threshold for non-laggards has been reached.
1215  switch (phase)
1216  {
1217  case 0:
1218  // Laggards and offline shouldn't preclude consensus.
1219  if (laggards + offline > totalValidators - quorum)
1220  willPause = true;
1221  break;
1222  case maxPausePhase:
1223  // No tolerance.
1224  willPause = true;
1225  break;
1226  default:
1227  // Ensure that sufficient validators are known to be not lagging.
1228  // Their sufficiently most recent validation sequence was equal to
1229  // or greater than our own.
1230  //
1231  // The threshold is the amount required for quorum plus
1232  // the proportion of the remainder based on number of intermediate
1233  // phases between 0 and max.
1234  float const nonLaggards = totalValidators - (laggards + offline);
1235  float const quorumRatio =
1236  static_cast<float>(quorum) / totalValidators;
1237  float const allowedDissent = 1.0f - quorumRatio;
1238  float const phaseFactor = static_cast<float>(phase) / maxPausePhase;
1239 
1240  if (nonLaggards / totalValidators <
1241  quorumRatio + (allowedDissent * phaseFactor))
1242  {
1243  willPause = true;
1244  }
1245  }
1246 
1247  if (willPause)
1248  j_.warn() << "pausing" << vars.str();
1249  else
1250  j_.debug() << "not pausing" << vars.str();
1251  return willPause;
1252 }
1253 
1254 template <class Adaptor>
1255 void
1257 {
1258  // can only establish consensus if we already took a stance
1259  assert(result_);
1260 
1261  using namespace std::chrono;
1262  ConsensusParms const& parms = adaptor_.parms();
1263 
1264  result_->roundTime.tick(clock_.now());
1265  result_->proposers = currPeerPositions_.size();
1266 
1267  convergePercent_ = result_->roundTime.read() * 100 /
1268  std::max<milliseconds>(prevRoundTime_, parms.avMIN_CONSENSUS_TIME);
1269 
1270  // Give everyone a chance to take an initial position
1271  if (result_->roundTime.read() < parms.ledgerMIN_CONSENSUS)
1272  return;
1273 
1274  updateOurPositions();
1275 
1276  // Nothing to do if too many laggards or we don't have consensus.
1277  if (shouldPause() || !haveConsensus())
1278  return;
1279 
1280  if (!haveCloseTimeConsensus_)
1281  {
1282  JLOG(j_.info()) << "We have TX consensus but not CT consensus";
1283  return;
1284  }
1285 
1286  JLOG(j_.info()) << "Converge cutoff (" << currPeerPositions_.size()
1287  << " participants)";
1288  adaptor_.updateOperatingMode(currPeerPositions_.size());
1289  prevProposers_ = currPeerPositions_.size();
1290  prevRoundTime_ = result_->roundTime.read();
1291  phase_ = ConsensusPhase::accepted;
1292  adaptor_.onAccept(
1293  *result_,
1294  previousLedger_,
1295  closeResolution_,
1296  rawCloseTimes_,
1297  mode_.get(),
1298  getJson(true));
1299 }
1300 
1301 template <class Adaptor>
1302 void
1304 {
1305  // We should not be closing if we already have a position
1306  assert(!result_);
1307 
1308  phase_ = ConsensusPhase::establish;
1309  rawCloseTimes_.self = now_;
1310 
1311  result_.emplace(adaptor_.onClose(previousLedger_, now_, mode_.get()));
1312  result_->roundTime.reset(clock_.now());
1313  // Share the newly created transaction set if we haven't already
1314  // received it from a peer
1315  if (acquired_.emplace(result_->txns.id(), result_->txns).second)
1316  adaptor_.share(result_->txns);
1317 
1318  if (mode_.get() == ConsensusMode::proposing)
1319  adaptor_.propose(result_->position);
1320 
1321  // Create disputes with any peer positions we have transactions for
1322  for (auto const& pit : currPeerPositions_)
1323  {
1324  auto const& pos = pit.second.proposal().position();
1325  auto const it = acquired_.find(pos);
1326  if (it != acquired_.end())
1327  {
1328  createDisputes(it->second);
1329  }
1330  }
1331 }
1332 
1345 inline int
1346 participantsNeeded(int participants, int percent)
1347 {
1348  int result = ((participants * percent) + (percent / 2)) / 100;
1349 
1350  return (result == 0) ? 1 : result;
1351 }
1352 
1353 template <class Adaptor>
1354 void
1356 {
1357  // We must have a position if we are updating it
1358  assert(result_);
1359  ConsensusParms const& parms = adaptor_.parms();
1360 
1361  // Compute a cutoff time
1362  auto const peerCutoff = now_ - parms.proposeFRESHNESS;
1363  auto const ourCutoff = now_ - parms.proposeINTERVAL;
1364 
1365  // Verify freshness of peer positions and compute close times
1366  std::map<NetClock::time_point, int> closeTimeVotes;
1367  {
1368  auto it = currPeerPositions_.begin();
1369  while (it != currPeerPositions_.end())
1370  {
1371  Proposal_t const& peerProp = it->second.proposal();
1372  if (peerProp.isStale(peerCutoff))
1373  {
1374  // peer's proposal is stale, so remove it
1375  NodeID_t const& peerID = peerProp.nodeID();
1376  JLOG(j_.warn()) << "Removing stale proposal from " << peerID;
1377  for (auto& dt : result_->disputes)
1378  dt.second.unVote(peerID);
1379  it = currPeerPositions_.erase(it);
1380  }
1381  else
1382  {
1383  // proposal is still fresh
1384  ++closeTimeVotes[asCloseTime(peerProp.closeTime())];
1385  ++it;
1386  }
1387  }
1388  }
1389 
1390  // This will stay unseated unless there are any changes
1391  boost::optional<TxSet_t> ourNewSet;
1392 
1393  // Update votes on disputed transactions
1394  {
1395  boost::optional<typename TxSet_t::MutableTxSet> mutableSet;
1396  for (auto& [txId, dispute] : result_->disputes)
1397  {
1398  // Because the threshold for inclusion increases,
1399  // time can change our position on a dispute
1400  if (dispute.updateVote(
1401  convergePercent_,
1402  mode_.get() == ConsensusMode::proposing,
1403  parms))
1404  {
1405  if (!mutableSet)
1406  mutableSet.emplace(result_->txns);
1407 
1408  if (dispute.getOurVote())
1409  {
1410  // now a yes
1411  mutableSet->insert(dispute.tx());
1412  }
1413  else
1414  {
1415  // now a no
1416  mutableSet->erase(txId);
1417  }
1418  }
1419  }
1420 
1421  if (mutableSet)
1422  ourNewSet.emplace(std::move(*mutableSet));
1423  }
1424 
1425  NetClock::time_point consensusCloseTime = {};
1426  haveCloseTimeConsensus_ = false;
1427 
1428  if (currPeerPositions_.empty())
1429  {
1430  // no other times
1431  haveCloseTimeConsensus_ = true;
1432  consensusCloseTime = asCloseTime(result_->position.closeTime());
1433  }
1434  else
1435  {
1436  int neededWeight;
1437 
1438  if (convergePercent_ < parms.avMID_CONSENSUS_TIME)
1439  neededWeight = parms.avINIT_CONSENSUS_PCT;
1440  else if (convergePercent_ < parms.avLATE_CONSENSUS_TIME)
1441  neededWeight = parms.avMID_CONSENSUS_PCT;
1442  else if (convergePercent_ < parms.avSTUCK_CONSENSUS_TIME)
1443  neededWeight = parms.avLATE_CONSENSUS_PCT;
1444  else
1445  neededWeight = parms.avSTUCK_CONSENSUS_PCT;
1446 
1447  int participants = currPeerPositions_.size();
1448  if (mode_.get() == ConsensusMode::proposing)
1449  {
1450  ++closeTimeVotes[asCloseTime(result_->position.closeTime())];
1451  ++participants;
1452  }
1453 
1454  // Threshold for non-zero vote
1455  int threshVote = participantsNeeded(participants, neededWeight);
1456 
1457  // Threshold to declare consensus
1458  int const threshConsensus =
1459  participantsNeeded(participants, parms.avCT_CONSENSUS_PCT);
1460 
1461  JLOG(j_.info()) << "Proposers:" << currPeerPositions_.size()
1462  << " nw:" << neededWeight << " thrV:" << threshVote
1463  << " thrC:" << threshConsensus;
1464 
1465  for (auto const& [t, v] : closeTimeVotes)
1466  {
1467  JLOG(j_.debug())
1468  << "CCTime: seq "
1469  << static_cast<std::uint32_t>(previousLedger_.seq()) + 1 << ": "
1470  << t.time_since_epoch().count() << " has " << v << ", "
1471  << threshVote << " required";
1472 
1473  if (v >= threshVote)
1474  {
1475  // A close time has enough votes for us to try to agree
1476  consensusCloseTime = t;
1477  threshVote = v;
1478 
1479  if (threshVote >= threshConsensus)
1480  haveCloseTimeConsensus_ = true;
1481  }
1482  }
1483 
1484  if (!haveCloseTimeConsensus_)
1485  {
1486  JLOG(j_.debug())
1487  << "No CT consensus:"
1488  << " Proposers:" << currPeerPositions_.size()
1489  << " Mode:" << to_string(mode_.get())
1490  << " Thresh:" << threshConsensus
1491  << " Pos:" << consensusCloseTime.time_since_epoch().count();
1492  }
1493  }
1494 
1495  if (!ourNewSet &&
1496  ((consensusCloseTime != asCloseTime(result_->position.closeTime())) ||
1497  result_->position.isStale(ourCutoff)))
1498  {
1499  // close time changed or our position is stale
1500  ourNewSet.emplace(result_->txns);
1501  }
1502 
1503  if (ourNewSet)
1504  {
1505  auto newID = ourNewSet->id();
1506 
1507  result_->txns = std::move(*ourNewSet);
1508 
1509  JLOG(j_.info()) << "Position change: CTime "
1510  << consensusCloseTime.time_since_epoch().count()
1511  << ", tx " << newID;
1512 
1513  result_->position.changePosition(newID, consensusCloseTime, now_);
1514 
1515  // Share our new transaction set and update disputes
1516  // if we haven't already received it
1517  if (acquired_.emplace(newID, result_->txns).second)
1518  {
1519  if (!result_->position.isBowOut())
1520  adaptor_.share(result_->txns);
1521 
1522  for (auto const& [nodeId, peerPos] : currPeerPositions_)
1523  {
1524  Proposal_t const& p = peerPos.proposal();
1525  if (p.position() == newID)
1526  updateDisputes(nodeId, result_->txns);
1527  }
1528  }
1529 
1530  // Share our new position if we are still participating this round
1531  if (!result_->position.isBowOut() &&
1532  (mode_.get() == ConsensusMode::proposing))
1533  adaptor_.propose(result_->position);
1534  }
1535 }
1536 
1537 template <class Adaptor>
1538 bool
1540 {
1541  // Must have a stance if we are checking for consensus
1542  assert(result_);
1543 
1544  // CHECKME: should possibly count unacquired TX sets as disagreeing
1545  int agree = 0, disagree = 0;
1546 
1547  auto ourPosition = result_->position.position();
1548 
1549  // Count number of agreements/disagreements with our position
1550  for (auto const& [nodeId, peerPos] : currPeerPositions_)
1551  {
1552  Proposal_t const& peerProp = peerPos.proposal();
1553  if (peerProp.position() == ourPosition)
1554  {
1555  ++agree;
1556  }
1557  else
1558  {
1559  JLOG(j_.debug()) << nodeId << " has " << peerProp.position();
1560  ++disagree;
1561  }
1562  }
1563  auto currentFinished =
1564  adaptor_.proposersFinished(previousLedger_, prevLedgerID_);
1565 
1566  JLOG(j_.debug()) << "Checking for TX consensus: agree=" << agree
1567  << ", disagree=" << disagree;
1568 
1569  // Determine if we actually have consensus or not
1570  result_->state = checkConsensus(
1571  prevProposers_,
1572  agree + disagree,
1573  agree,
1574  currentFinished,
1575  prevRoundTime_,
1576  result_->roundTime.read(),
1577  adaptor_.parms(),
1578  mode_.get() == ConsensusMode::proposing,
1579  j_);
1580 
1581  if (result_->state == ConsensusState::No)
1582  return false;
1583 
1584  // There is consensus, but we need to track if the network moved on
1585  // without us.
1586  if (result_->state == ConsensusState::MovedOn)
1587  {
1588  JLOG(j_.error()) << "Unable to reach consensus";
1589  JLOG(j_.error()) << Json::Compact{getJson(true)};
1590  }
1591 
1592  return true;
1593 }
1594 
1595 template <class Adaptor>
1596 void
1598 {
1599  if (mode_.get() == ConsensusMode::proposing)
1600  {
1601  if (result_ && !result_->position.isBowOut())
1602  {
1603  result_->position.bowOut(now_);
1604  adaptor_.propose(result_->position);
1605  }
1606 
1607  mode_.set(ConsensusMode::observing, adaptor_);
1608  JLOG(j_.info()) << "Bowing out of consensus";
1609  }
1610 }
1611 
1612 template <class Adaptor>
1613 void
1615 {
1616  // Cannot create disputes without our stance
1617  assert(result_);
1618 
1619  // Only create disputes if this is a new set
1620  if (!result_->compares.emplace(o.id()).second)
1621  return;
1622 
1623  // Nothing to dispute if we agree
1624  if (result_->txns.id() == o.id())
1625  return;
1626 
1627  JLOG(j_.debug()) << "createDisputes " << result_->txns.id() << " to "
1628  << o.id();
1629 
1630  auto differences = result_->txns.compare(o);
1631 
1632  int dc = 0;
1633 
1634  for (auto const& [txId, inThisSet] : differences)
1635  {
1636  ++dc;
1637  // create disputed transactions (from the ledger that has them)
1638  assert(
1639  (inThisSet && result_->txns.find(txId) && !o.find(txId)) ||
1640  (!inThisSet && !result_->txns.find(txId) && o.find(txId)));
1641 
1642  Tx_t tx = inThisSet ? *result_->txns.find(txId) : *o.find(txId);
1643  auto txID = tx.id();
1644 
1645  if (result_->disputes.find(txID) != result_->disputes.end())
1646  continue;
1647 
1648  JLOG(j_.debug()) << "Transaction " << txID << " is disputed";
1649 
1650  typename Result::Dispute_t dtx{
1651  tx,
1652  result_->txns.exists(txID),
1653  std::max(prevProposers_, currPeerPositions_.size()),
1654  j_};
1655 
1656  // Update all of the available peer's votes on the disputed transaction
1657  for (auto const& [nodeId, peerPos] : currPeerPositions_)
1658  {
1659  Proposal_t const& peerProp = peerPos.proposal();
1660  auto const cit = acquired_.find(peerProp.position());
1661  if (cit != acquired_.end())
1662  dtx.setVote(nodeId, cit->second.exists(txID));
1663  }
1664  adaptor_.share(dtx.tx());
1665 
1666  result_->disputes.emplace(txID, std::move(dtx));
1667  }
1668  JLOG(j_.debug()) << dc << " differences found";
1669 }
1670 
1671 template <class Adaptor>
1672 void
1674 {
1675  // Cannot updateDisputes without our stance
1676  assert(result_);
1677 
1678  // Ensure we have created disputes against this set if we haven't seen
1679  // it before
1680  if (result_->compares.find(other.id()) == result_->compares.end())
1681  createDisputes(other);
1682 
1683  for (auto& it : result_->disputes)
1684  {
1685  auto& d = it.second;
1686  d.setVote(node, other.exists(d.tx().id()));
1687  }
1688 }
1689 
1690 template <class Adaptor>
1693 {
1694  return roundCloseTime(raw, closeResolution_);
1695 }
1696 
1697 } // namespace ripple
1698 
1699 #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:1049
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:1072
ripple::Consensus::shouldPause
bool shouldPause() const
Evaluate whether pausing increases likelihood of validation.
Definition: Consensus.h:1142
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:1692
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:1614
ripple::Consensus::handleWrongLedger
void handleWrongLedger(typename Ledger_t::ID const &lgrId)
Definition: Consensus.h:1004
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:906
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:1597
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:836
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:1089
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:813
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:1673
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:1256
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:882
ripple::Consensus::haveConsensus
bool haveConsensus()
Definition: Consensus.h:1539
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:1303
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:1355
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:1346
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:585
std::chrono