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#include <xrpl/basics/Log.h>
25#include <xrpl/basics/base_uint.h>
26#include <xrpl/beast/utility/Journal.h>
27#include <xrpl/json/json_writer.h>
28#include <xrpl/protocol/Serializer.h>
29#include <xrpl/protocol/UintTypes.h>
30#include <boost/container/flat_map.hpp>
31#include <memory>
32
33namespace ripple {
34
49template <class Tx_t, class NodeID_t>
51{
52 using TxID_t = typename Tx_t::ID;
53 using Map_t = boost::container::flat_map<NodeID_t, bool>;
54
55public:
64 Tx_t const& tx,
65 bool ourVote,
66 std::size_t numPeers,
68 : yays_(0), nays_(0), ourVote_(ourVote), tx_(tx), j_(j)
69 {
70 votes_.reserve(numPeers);
71 }
72
74 TxID_t const&
75 ID() const
76 {
77 return tx_.id();
78 }
79
81 bool
82 getOurVote() const
83 {
84 return ourVote_;
85 }
86
88 Tx_t const&
89 tx() const
90 {
91 return tx_;
92 }
93
95 void
96 setOurVote(bool o)
97 {
98 ourVote_ = o;
99 }
100
106 void
107 setVote(NodeID_t const& peer, bool votesYes);
108
113 void
114 unVote(NodeID_t const& peer);
115
127 bool
128 updateVote(int percentTime, bool proposing, ConsensusParms const& p);
129
132 getJson() const;
133
134private:
135 int yays_; //< Number of yes votes
136 int nays_; //< Number of no votes
137 bool ourVote_; //< Our vote (true is yes)
138 Tx_t tx_; //< Transaction under dispute
139 Map_t votes_; //< Map from NodeID to vote
141};
142
143// Track a peer's yes/no vote on a particular disputed tx_
144template <class Tx_t, class NodeID_t>
145void
146DisputedTx<Tx_t, NodeID_t>::setVote(NodeID_t const& peer, bool votesYes)
147{
148 auto const [it, inserted] = votes_.insert(std::make_pair(peer, votesYes));
149
150 // new vote
151 if (inserted)
152 {
153 if (votesYes)
154 {
155 JLOG(j_.debug()) << "Peer " << peer << " votes YES on " << tx_.id();
156 ++yays_;
157 }
158 else
159 {
160 JLOG(j_.debug()) << "Peer " << peer << " votes NO on " << tx_.id();
161 ++nays_;
162 }
163 }
164 // changes vote to yes
165 else if (votesYes && !it->second)
166 {
167 JLOG(j_.debug()) << "Peer " << peer << " now votes YES on " << tx_.id();
168 --nays_;
169 ++yays_;
170 it->second = true;
171 }
172 // changes vote to no
173 else if (!votesYes && it->second)
174 {
175 JLOG(j_.debug()) << "Peer " << peer << " now votes NO on " << tx_.id();
176 ++nays_;
177 --yays_;
178 it->second = false;
179 }
180}
181
182// Remove a peer's vote on this disputed transaction
183template <class Tx_t, class NodeID_t>
184void
186{
187 auto it = votes_.find(peer);
188
189 if (it != votes_.end())
190 {
191 if (it->second)
192 --yays_;
193 else
194 --nays_;
195
196 votes_.erase(it);
197 }
198}
199
200template <class Tx_t, class NodeID_t>
201bool
203 int percentTime,
204 bool proposing,
205 ConsensusParms const& p)
206{
207 if (ourVote_ && (nays_ == 0))
208 return false;
209
210 if (!ourVote_ && (yays_ == 0))
211 return false;
212
213 bool newPosition;
214 int weight;
215
216 if (proposing) // give ourselves full weight
217 {
218 // This is basically the percentage of nodes voting 'yes' (including us)
219 weight = (yays_ * 100 + (ourVote_ ? 100 : 0)) / (nays_ + yays_ + 1);
220
221 // To prevent avalanche stalls, we increase the needed weight slightly
222 // over time.
223 if (percentTime < p.avMID_CONSENSUS_TIME)
224 newPosition = weight > p.avINIT_CONSENSUS_PCT;
225 else if (percentTime < p.avLATE_CONSENSUS_TIME)
226 newPosition = weight > p.avMID_CONSENSUS_PCT;
227 else if (percentTime < p.avSTUCK_CONSENSUS_TIME)
228 newPosition = weight > p.avLATE_CONSENSUS_PCT;
229 else
230 newPosition = weight > p.avSTUCK_CONSENSUS_PCT;
231 }
232 else
233 {
234 // don't let us outweigh a proposing node, just recognize consensus
235 weight = -1;
236 newPosition = yays_ > nays_;
237 }
238
239 if (newPosition == ourVote_)
240 {
241 JLOG(j_.info()) << "No change (" << (ourVote_ ? "YES" : "NO")
242 << ") : weight " << weight << ", percent "
243 << percentTime;
244 JLOG(j_.debug()) << Json::Compact{getJson()};
245 return false;
246 }
247
248 ourVote_ = newPosition;
249 JLOG(j_.debug()) << "We now vote " << (ourVote_ ? "YES" : "NO") << " on "
250 << tx_.id();
251 JLOG(j_.debug()) << Json::Compact{getJson()};
252 return true;
253}
254
255template <class Tx_t, class NodeID_t>
258{
259 using std::to_string;
260
262
263 ret["yays"] = yays_;
264 ret["nays"] = nays_;
265 ret["our_vote"] = ourVote_;
266
267 if (!votes_.empty())
268 {
270 for (auto const& [nodeId, vote] : votes_)
271 votesj[to_string(nodeId)] = vote;
272 ret["votes"] = std::move(votesj);
273 }
274
275 return ret;
276}
277
278} // namespace ripple
279
280#endif
Decorator for streaming out compact json.
Definition: json_writer.h:317
Represents a JSON value.
Definition: json_value.h:147
A generic endpoint for log messages.
Definition: Journal.h:59
Stream debug() const
Definition: Journal.h:317
Stream info() const
Definition: Journal.h:323
A transaction discovered to be in dispute during consensus.
Definition: DisputedTx.h:51
Json::Value getJson() const
JSON representation of dispute, used for debugging.
Definition: DisputedTx.h:257
beast::Journal const j_
Definition: DisputedTx.h:140
bool updateVote(int percentTime, bool proposing, ConsensusParms const &p)
Update our vote given progression of consensus.
Definition: DisputedTx.h:202
boost::container::flat_map< NodeID_t, bool > Map_t
Definition: DisputedTx.h:53
Tx_t const & tx() const
The disputed transaction.
Definition: DisputedTx.h:89
void setVote(NodeID_t const &peer, bool votesYes)
Change a peer's vote.
Definition: DisputedTx.h:146
typename Tx_t::ID TxID_t
Definition: DisputedTx.h:52
DisputedTx(Tx_t const &tx, bool ourVote, std::size_t numPeers, beast::Journal j)
Constructor.
Definition: DisputedTx.h:63
bool getOurVote() const
Our vote on whether the transaction should be included.
Definition: DisputedTx.h:82
void setOurVote(bool o)
Change our vote.
Definition: DisputedTx.h:96
TxID_t const & ID() const
The unique id/hash of the disputed transaction.
Definition: DisputedTx.h:75
void unVote(NodeID_t const &peer)
Remove a peer's vote.
Definition: DisputedTx.h:185
T make_pair(T... args)
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
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:629
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)