rippled
Loading...
Searching...
No Matches
DisputedTx.h
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#ifndef RIPPLE_APP_CONSENSUS_IMPL_DISPUTEDTX_H_INCLUDED
21#define RIPPLE_APP_CONSENSUS_IMPL_DISPUTEDTX_H_INCLUDED
22
23#include <xrpld/consensus/ConsensusParms.h>
24
25#include <xrpl/basics/Log.h>
26#include <xrpl/beast/utility/Journal.h>
27#include <xrpl/json/json_writer.h>
28
29#include <boost/container/flat_map.hpp>
30
31namespace ripple {
32
47template <class Tx_t, class NodeID_t>
49{
50 using TxID_t = typename Tx_t::ID;
51 using Map_t = boost::container::flat_map<NodeID_t, bool>;
52
53public:
62 Tx_t const& tx,
63 bool ourVote,
64 std::size_t numPeers,
66 : yays_(0), nays_(0), ourVote_(ourVote), tx_(tx), j_(j)
67 {
68 votes_.reserve(numPeers);
69 }
70
72 TxID_t const&
73 ID() const
74 {
75 return tx_.id();
76 }
77
79 bool
80 getOurVote() const
81 {
82 return ourVote_;
83 }
84
86 Tx_t const&
87 tx() const
88 {
89 return tx_;
90 }
91
93 void
94 setOurVote(bool o)
95 {
96 ourVote_ = o;
97 }
98
104 void
105 setVote(NodeID_t const& peer, bool votesYes);
106
111 void
112 unVote(NodeID_t const& peer);
113
125 bool
126 updateVote(int percentTime, bool proposing, ConsensusParms const& p);
127
130 getJson() const;
131
132private:
133 int yays_; //< Number of yes votes
134 int nays_; //< Number of no votes
135 bool ourVote_; //< Our vote (true is yes)
136 Tx_t tx_; //< Transaction under dispute
137 Map_t votes_; //< Map from NodeID to vote
139};
140
141// Track a peer's yes/no vote on a particular disputed tx_
142template <class Tx_t, class NodeID_t>
143void
144DisputedTx<Tx_t, NodeID_t>::setVote(NodeID_t const& peer, bool votesYes)
145{
146 auto const [it, inserted] = votes_.insert(std::make_pair(peer, votesYes));
147
148 // new vote
149 if (inserted)
150 {
151 if (votesYes)
152 {
153 JLOG(j_.debug()) << "Peer " << peer << " votes YES on " << tx_.id();
154 ++yays_;
155 }
156 else
157 {
158 JLOG(j_.debug()) << "Peer " << peer << " votes NO on " << tx_.id();
159 ++nays_;
160 }
161 }
162 // changes vote to yes
163 else if (votesYes && !it->second)
164 {
165 JLOG(j_.debug()) << "Peer " << peer << " now votes YES on " << tx_.id();
166 --nays_;
167 ++yays_;
168 it->second = true;
169 }
170 // changes vote to no
171 else if (!votesYes && it->second)
172 {
173 JLOG(j_.debug()) << "Peer " << peer << " now votes NO on " << tx_.id();
174 ++nays_;
175 --yays_;
176 it->second = false;
177 }
178}
179
180// Remove a peer's vote on this disputed transaction
181template <class Tx_t, class NodeID_t>
182void
184{
185 auto it = votes_.find(peer);
186
187 if (it != votes_.end())
188 {
189 if (it->second)
190 --yays_;
191 else
192 --nays_;
193
194 votes_.erase(it);
195 }
196}
197
198template <class Tx_t, class NodeID_t>
199bool
201 int percentTime,
202 bool proposing,
203 ConsensusParms const& p)
204{
205 if (ourVote_ && (nays_ == 0))
206 return false;
207
208 if (!ourVote_ && (yays_ == 0))
209 return false;
210
211 bool newPosition;
212 int weight;
213
214 if (proposing) // give ourselves full weight
215 {
216 // This is basically the percentage of nodes voting 'yes' (including us)
217 weight = (yays_ * 100 + (ourVote_ ? 100 : 0)) / (nays_ + yays_ + 1);
218
219 // To prevent avalanche stalls, we increase the needed weight slightly
220 // over time.
221 if (percentTime < p.avMID_CONSENSUS_TIME)
222 newPosition = weight > p.avINIT_CONSENSUS_PCT;
223 else if (percentTime < p.avLATE_CONSENSUS_TIME)
224 newPosition = weight > p.avMID_CONSENSUS_PCT;
225 else if (percentTime < p.avSTUCK_CONSENSUS_TIME)
226 newPosition = weight > p.avLATE_CONSENSUS_PCT;
227 else
228 newPosition = weight > p.avSTUCK_CONSENSUS_PCT;
229 }
230 else
231 {
232 // don't let us outweigh a proposing node, just recognize consensus
233 weight = -1;
234 newPosition = yays_ > nays_;
235 }
236
237 if (newPosition == ourVote_)
238 {
239 JLOG(j_.info()) << "No change (" << (ourVote_ ? "YES" : "NO")
240 << ") : weight " << weight << ", percent "
241 << percentTime;
242 JLOG(j_.debug()) << Json::Compact{getJson()};
243 return false;
244 }
245
246 ourVote_ = newPosition;
247 JLOG(j_.debug()) << "We now vote " << (ourVote_ ? "YES" : "NO") << " on "
248 << tx_.id();
249 JLOG(j_.debug()) << Json::Compact{getJson()};
250 return true;
251}
252
253template <class Tx_t, class NodeID_t>
256{
257 using std::to_string;
258
260
261 ret["yays"] = yays_;
262 ret["nays"] = nays_;
263 ret["our_vote"] = ourVote_;
264
265 if (!votes_.empty())
266 {
268 for (auto const& [nodeId, vote] : votes_)
269 votesj[to_string(nodeId)] = vote;
270 ret["votes"] = std::move(votesj);
271 }
272
273 return ret;
274}
275
276} // namespace ripple
277
278#endif
Decorator for streaming out compact json.
Definition: json_writer.h:318
Represents a JSON value.
Definition: json_value.h:148
A generic endpoint for log messages.
Definition: Journal.h:60
Stream debug() const
Definition: Journal.h:328
Stream info() const
Definition: Journal.h:334
A transaction discovered to be in dispute during consensus.
Definition: DisputedTx.h:49
Json::Value getJson() const
JSON representation of dispute, used for debugging.
Definition: DisputedTx.h:255
beast::Journal const j_
Definition: DisputedTx.h:138
bool updateVote(int percentTime, bool proposing, ConsensusParms const &p)
Update our vote given progression of consensus.
Definition: DisputedTx.h:200
boost::container::flat_map< NodeID_t, bool > Map_t
Definition: DisputedTx.h:51
Tx_t const & tx() const
The disputed transaction.
Definition: DisputedTx.h:87
void setVote(NodeID_t const &peer, bool votesYes)
Change a peer's vote.
Definition: DisputedTx.h:144
typename Tx_t::ID TxID_t
Definition: DisputedTx.h:50
DisputedTx(Tx_t const &tx, bool ourVote, std::size_t numPeers, beast::Journal j)
Constructor.
Definition: DisputedTx.h:61
bool getOurVote() const
Our vote on whether the transaction should be included.
Definition: DisputedTx.h:80
void setOurVote(bool o)
Change our vote.
Definition: DisputedTx.h:94
TxID_t const & ID() const
The unique id/hash of the disputed transaction.
Definition: DisputedTx.h:73
void unVote(NodeID_t const &peer)
Remove a peer's vote.
Definition: DisputedTx.h:183
T make_pair(T... args)
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:44
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
@ proposing
We are normal participant in consensus and propose our position.
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Consensus algorithm parameters.
std::size_t avINIT_CONSENSUS_PCT
Percentage of nodes on our UNL that must vote yes.
std::size_t avLATE_CONSENSUS_PCT
Percentage of nodes that most vote yes after advancing.
std::size_t avSTUCK_CONSENSUS_PCT
Percentage of nodes that must vote yes after we are stuck.
std::size_t avLATE_CONSENSUS_TIME
Percentage of previous round duration before we advance.
std::size_t avMID_CONSENSUS_PCT
Percentage of nodes that most vote yes after advancing.
std::size_t avSTUCK_CONSENSUS_TIME
Percentage of previous round duration before we are stuck.
std::size_t avMID_CONSENSUS_TIME
Percentage of previous round duration before we advance.
T to_string(T... args)