rippled
Consensus.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/Log.h>
21 #include <ripple/consensus/Consensus.h>
22 
23 namespace ripple {
24 
25 bool
27  bool anyTransactions,
28  std::size_t prevProposers,
29  std::size_t proposersClosed,
30  std::size_t proposersValidated,
31  std::chrono::milliseconds prevRoundTime,
33  timeSincePrevClose, // Time since last ledger's close time
34  std::chrono::milliseconds openTime, // Time waiting to close this ledger
36  std::chrono::milliseconds idleInterval,
37  ConsensusParms const& parms,
39 {
40  using namespace std::chrono_literals;
41 
42  if ((prevRoundTime < -1s) || (prevRoundTime > 10min) ||
43  (timeSincePrevClose > 10min))
44  {
45  // These are unexpected cases, we just close the ledger
46  JLOG(j.warn()) << "Trans=" << (anyTransactions ? "yes" : "no")
47  << " Prop: " << prevProposers << "/" << proposersClosed
48  << " Secs: " << timeSincePrevClose.count()
49  << " (last: " << prevRoundTime.count() << ")";
50  return true;
51  }
52 
53  if ((proposersClosed + proposersValidated) > (prevProposers / 2))
54  {
55  // If more than half of the network has closed, we close
56  JLOG(j.trace()) << "Others have closed";
57  return true;
58  }
59 
60  // The openTime is the time spent so far waiting to close the ledger.
61  // Any time spent retrying ledger validation in the previous round is
62  // also counted.
63  if (validationDelay)
64  openTime += *validationDelay;
65 
66  if (!anyTransactions)
67  {
68  // Only close at the end of the idle interval
69  return timeSincePrevClose >= idleInterval; // normal idle
70  }
71 
72  // Preserve minimum ledger open time
73  if (openTime < parms.ledgerMIN_CLOSE)
74  {
75  JLOG(j.debug()) << "Must wait minimum time before closing";
76  return false;
77  }
78 
79  // Don't let this ledger close more than twice as fast as the previous
80  // ledger reached consensus so that slower validators can slow down
81  // the network
82  if (openTime < (prevRoundTime / 2))
83  {
84  JLOG(j.debug()) << "Ledger has not been open long enough";
85  return false;
86  }
87 
88  // Close the ledger
89  return true;
90 }
91 
92 bool
94  std::size_t agreeing,
95  std::size_t total,
96  bool count_self,
97  std::size_t minConsensusPct)
98 {
99  // If we are alone, we have a consensus
100  if (total == 0)
101  return true;
102 
103  if (count_self)
104  {
105  ++agreeing;
106  ++total;
107  }
108 
109  std::size_t currentPercentage = (agreeing * 100) / total;
110 
111  return currentPercentage >= minConsensusPct;
112 }
113 
116  std::size_t prevProposers,
117  std::size_t currentProposers,
118  std::size_t currentAgree,
119  std::size_t currentFinished,
120  std::chrono::milliseconds previousAgreeTime,
121  std::chrono::milliseconds currentAgreeTime,
122  ConsensusParms const& parms,
123  bool proposing,
124  beast::Journal j)
125 {
126  JLOG(j.trace()) << "checkConsensus: prop=" << currentProposers << "/"
127  << prevProposers << " agree=" << currentAgree
128  << " validated=" << currentFinished
129  << " time=" << currentAgreeTime.count() << "/"
130  << previousAgreeTime.count();
131 
132  if (currentProposers < (prevProposers * 3 / 4))
133  {
134  // Less than 3/4 of the last ledger's proposers are present; don't
135  // rush: we may need more time.
136  if (currentAgreeTime < (previousAgreeTime + parms.ledgerMIN_CONSENSUS))
137  {
138  JLOG(j.trace()) << "too fast, not enough proposers";
139  return ConsensusState::No;
140  }
141  }
142 
143  // Have we, together with the nodes on our UNL list, reached the threshold
144  // to declare consensus?
146  currentAgree, currentProposers, proposing, parms.minCONSENSUS_PCT))
147  {
148  JLOG(j.debug()) << "normal consensus";
149  return ConsensusState::Yes;
150  }
151 
152  // Have sufficient nodes on our UNL list moved on and reached the threshold
153  // to declare consensus?
155  currentFinished, currentProposers, false, parms.minCONSENSUS_PCT))
156  {
157  JLOG(j.warn()) << "We see no consensus, but 80% of nodes have moved on";
159  }
160 
161  // no consensus yet
162  JLOG(j.trace()) << "checkConsensus no consensus";
163  return ConsensusState::No;
164 }
165 
166 } // namespace ripple
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:115
ripple::ConsensusState
ConsensusState
Whether we have or don't have a consensus.
Definition: ConsensusTypes.h:185
ripple::ConsensusMode::proposing
@ proposing
We are normal participant in consensus and propose our position.
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::ConsensusState::Yes
@ Yes
We have consensus along with the network.
ripple::checkConsensusReached
bool checkConsensusReached(std::size_t agreeing, std::size_t total, bool count_self, std::size_t minConsensusPct)
Definition: Consensus.cpp:93
std::chrono::milliseconds
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::ConsensusParms::minCONSENSUS_PCT
std::size_t minCONSENSUS_PCT
The percentage threshold and floating point factor above which we can declare consensus.
Definition: ConsensusParms.h:75
ripple::ConsensusParms::ledgerMIN_CLOSE
std::chrono::milliseconds ledgerMIN_CLOSE
Minimum number of seconds to wait to ensure others have computed the LCL.
Definition: ConsensusParms.h:100
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::ConsensusState::No
@ No
We do not have consensus.
ripple::ConsensusState::MovedOn
@ MovedOn
The network has consensus without us.
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:88
ripple::ConsensusParms
Consensus algorithm parameters.
Definition: ConsensusParms.h:33
std::chrono::milliseconds::count
T count(T... args)
std::optional< std::chrono::milliseconds >
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t
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::optional< std::chrono::milliseconds > validationDelay, std::chrono::milliseconds idleInterval, ConsensusParms const &parms, beast::Journal j)
Determines whether the current ledger should close at this time.
Definition: Consensus.cpp:26