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
35  std::chrono::milliseconds idleInterval,
36  ConsensusParms const& parms,
38 {
39  using namespace std::chrono_literals;
40  if ((prevRoundTime < -1s) || (prevRoundTime > 10min) ||
41  (timeSincePrevClose > 10min))
42  {
43  // These are unexpected cases, we just close the ledger
44  JLOG(j.warn()) << "shouldCloseLedger Trans="
45  << (anyTransactions ? "yes" : "no")
46  << " Prop: " << prevProposers << "/" << proposersClosed
47  << " Secs: " << timeSincePrevClose.count()
48  << " (last: " << prevRoundTime.count() << ")";
49  return true;
50  }
51 
52  if ((proposersClosed + proposersValidated) > (prevProposers / 2))
53  {
54  // If more than half of the network has closed, we close
55  JLOG(j.trace()) << "Others have closed";
56  return true;
57  }
58 
59  if (!anyTransactions)
60  {
61  // Only close at the end of the idle interval
62  return timeSincePrevClose >= idleInterval; // normal idle
63  }
64 
65  // Preserve minimum ledger open time
66  if (openTime < parms.ledgerMIN_CLOSE)
67  {
68  JLOG(j.debug()) << "Must wait minimum time before closing";
69  return false;
70  }
71 
72  // Don't let this ledger close more than twice as fast as the previous
73  // ledger reached consensus so that slower validators can slow down
74  // the network
75  if (openTime < (prevRoundTime / 2))
76  {
77  JLOG(j.debug()) << "Ledger has not been open long enough";
78  return false;
79  }
80 
81  // Close the ledger
82  return true;
83 }
84 
85 bool
87  std::size_t agreeing,
88  std::size_t total,
89  bool count_self,
90  std::size_t minConsensusPct)
91 {
92  // If we are alone, we have a consensus
93  if (total == 0)
94  return true;
95 
96  if (count_self)
97  {
98  ++agreeing;
99  ++total;
100  }
101 
102  std::size_t currentPercentage = (agreeing * 100) / total;
103 
104  return currentPercentage >= minConsensusPct;
105 }
106 
109  std::size_t prevProposers,
110  std::size_t currentProposers,
111  std::size_t currentAgree,
112  std::size_t currentFinished,
113  std::chrono::milliseconds previousAgreeTime,
114  std::chrono::milliseconds currentAgreeTime,
115  ConsensusParms const& parms,
116  bool proposing,
117  beast::Journal j)
118 {
119  JLOG(j.trace()) << "checkConsensus: prop=" << currentProposers << "/"
120  << prevProposers << " agree=" << currentAgree
121  << " validated=" << currentFinished
122  << " time=" << currentAgreeTime.count() << "/"
123  << previousAgreeTime.count();
124 
125  if (currentAgreeTime <= parms.ledgerMIN_CONSENSUS)
126  return ConsensusState::No;
127 
128  if (currentProposers < (prevProposers * 3 / 4))
129  {
130  // Less than 3/4 of the last ledger's proposers are present; don't
131  // rush: we may need more time.
132  if (currentAgreeTime < (previousAgreeTime + parms.ledgerMIN_CONSENSUS))
133  {
134  JLOG(j.trace()) << "too fast, not enough proposers";
135  return ConsensusState::No;
136  }
137  }
138 
139  // Have we, together with the nodes on our UNL list, reached the threshold
140  // to declare consensus?
142  currentAgree, currentProposers, proposing, parms.minCONSENSUS_PCT))
143  {
144  JLOG(j.debug()) << "normal consensus";
145  return ConsensusState::Yes;
146  }
147 
148  // Have sufficient nodes on our UNL list moved on and reached the threshold
149  // to declare consensus?
151  currentFinished, currentProposers, false, parms.minCONSENSUS_PCT))
152  {
153  JLOG(j.warn()) << "We see no consensus, but 80% of nodes have moved on";
155  }
156 
157  // no consensus yet
158  JLOG(j.trace()) << "no consensus";
159  return ConsensusState::No;
160 }
161 
162 } // 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:108
ripple::ConsensusState
ConsensusState
Whether we have or don't have a consensus.
Definition: ConsensusTypes.h:186
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::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::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:86
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 above which we can declare consensus.
Definition: ConsensusParms.h:74
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:92
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:80
ripple::ConsensusParms
Consensus algorithm parameters.
Definition: ConsensusParms.h:33
std::chrono::milliseconds::count
T count(T... args)
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t