rippled
FeeVoteImpl.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/app/ledger/Ledger.h>
21 #include <ripple/app/main/Application.h>
22 #include <ripple/app/misc/FeeVote.h>
23 #include <ripple/basics/BasicConfig.h>
24 #include <ripple/beast/utility/Journal.h>
25 #include <ripple/protocol/STValidation.h>
26 #include <ripple/protocol/st.h>
27 
28 namespace ripple {
29 
30 namespace detail {
31 
33 {
34 private:
36  value_type const current_; // The current setting
37  value_type const target_; // The setting we want
39 
40 public:
42  : current_(current), target_(target)
43  {
44  // Add our vote
45  ++voteMap_[target_];
46  }
47 
48  void
50  {
51  ++voteMap_[vote];
52  }
53 
54  void
56  {
58  }
59 
61  current() const
62  {
63  return current_;
64  }
65 
67  getVotes() const;
68 };
69 
70 auto
71 VotableValue::getVotes() const -> std::pair<value_type, bool>
72 {
73  value_type ourVote = current_;
74  int weight = 0;
75  for (auto const& [key, val] : voteMap_)
76  {
77  // Take most voted value between current and target, inclusive
78  if ((key <= std::max(target_, current_)) &&
79  (key >= std::min(target_, current_)) && (val > weight))
80  {
81  ourVote = key;
82  weight = val;
83  }
84  }
85 
86  return {ourVote, ourVote != current_};
87 }
88 
89 } // namespace detail
90 
91 //------------------------------------------------------------------------------
92 
93 class FeeVoteImpl : public FeeVote
94 {
95 private:
98 
99 public:
100  FeeVoteImpl(FeeSetup const& setup, beast::Journal journal);
101 
102  void
103  doValidation(Fees const& lastFees, Rules const& rules, STValidation& val)
104  override;
105 
106  void
107  doVoting(
108  std::shared_ptr<ReadView const> const& lastClosedLedger,
109  std::vector<std::shared_ptr<STValidation>> const& parentValidations,
110  std::shared_ptr<SHAMap> const& initialPosition) override;
111 };
112 
113 //--------------------------------------------------------------------------
114 
116  : target_(setup), journal_(journal)
117 {
118 }
119 
120 void
122  Fees const& lastFees,
123  Rules const& rules,
124  STValidation& v)
125 {
126  // Values should always be in a valid range (because the voting process
127  // will ignore out-of-range values) but if we detect such a case, we do
128  // not send a value.
129  if (rules.enabled(featureXRPFees))
130  {
131  auto vote = [&v, this](
132  auto const current,
133  XRPAmount target,
134  const char* name,
135  auto const& sfield) {
136  if (current != target)
137  {
138  JLOG(journal_.info())
139  << "Voting for " << name << " of " << target;
140 
141  v[sfield] = target;
142  }
143  };
144  vote(lastFees.base, target_.reference_fee, "base fee", sfBaseFeeDrops);
145  vote(
146  lastFees.accountReserve(0),
148  "base reserve",
150  vote(
151  lastFees.increment,
153  "reserve increment",
155  }
156  else
157  {
158  auto to32 = [](XRPAmount target) {
159  return target.dropsAs<std::uint32_t>();
160  };
161  auto to64 = [](XRPAmount target) {
162  return target.dropsAs<std::uint64_t>();
163  };
164  auto vote = [&v, this](
165  auto const current,
166  XRPAmount target,
167  auto const& convertCallback,
168  const char* name,
169  auto const& sfield) {
170  if (current != target)
171  {
172  JLOG(journal_.info())
173  << "Voting for " << name << " of " << target;
174 
175  if (auto const f = convertCallback(target))
176  v[sfield] = *f;
177  }
178  };
179 
180  vote(lastFees.base, target_.reference_fee, to64, "base fee", sfBaseFee);
181  vote(
182  lastFees.accountReserve(0),
184  to32,
185  "base reserve",
186  sfReserveBase);
187  vote(
188  lastFees.increment,
190  to32,
191  "reserve increment",
193  }
194 }
195 
196 void
198  std::shared_ptr<ReadView const> const& lastClosedLedger,
200  std::shared_ptr<SHAMap> const& initialPosition)
201 {
202  // LCL must be flag ledger
203  assert(lastClosedLedger && isFlagLedger(lastClosedLedger->seq()));
204 
205  detail::VotableValue baseFeeVote(
206  lastClosedLedger->fees().base, target_.reference_fee);
207 
208  detail::VotableValue baseReserveVote(
209  lastClosedLedger->fees().accountReserve(0), target_.account_reserve);
210 
211  detail::VotableValue incReserveVote(
212  lastClosedLedger->fees().increment, target_.owner_reserve);
213 
214  auto const& rules = lastClosedLedger->rules();
215  if (rules.enabled(featureXRPFees))
216  {
217  auto doVote = [](std::shared_ptr<STValidation> const& val,
218  detail::VotableValue& value,
219  SF_AMOUNT const& xrpField) {
220  if (auto const field = ~val->at(~xrpField);
221  field && field->native())
222  {
223  auto const vote = field->xrp();
224  if (isLegalAmountSigned(vote))
225  value.addVote(vote);
226  else
227  value.noVote();
228  }
229  else
230  {
231  value.noVote();
232  }
233  };
234 
235  for (auto const& val : set)
236  {
237  if (!val->isTrusted())
238  continue;
239  doVote(val, baseFeeVote, sfBaseFeeDrops);
240  doVote(val, baseReserveVote, sfReserveBaseDrops);
241  doVote(val, incReserveVote, sfReserveIncrementDrops);
242  }
243  }
244  else
245  {
246  auto doVote = [](std::shared_ptr<STValidation> const& val,
247  detail::VotableValue& value,
248  auto const& valueField) {
249  if (auto const field = val->at(~valueField))
250  {
251  using xrptype = XRPAmount::value_type;
252  auto const vote = *field;
253  if (vote <= std::numeric_limits<xrptype>::max() &&
254  isLegalAmountSigned(XRPAmount{unsafe_cast<xrptype>(vote)}))
255  value.addVote(
256  XRPAmount{unsafe_cast<XRPAmount::value_type>(vote)});
257  else
258  // Invalid amounts will be treated as if they're
259  // not provided. Don't throw because this value is
260  // provided by an external entity.
261  value.noVote();
262  }
263  else
264  {
265  value.noVote();
266  }
267  };
268 
269  for (auto const& val : set)
270  {
271  if (!val->isTrusted())
272  continue;
273  doVote(val, baseFeeVote, sfBaseFee);
274  doVote(val, baseReserveVote, sfReserveBase);
275  doVote(val, incReserveVote, sfReserveIncrement);
276  }
277  }
278 
279  // choose our positions
280  // TODO: Use structured binding once LLVM issue
281  // https://github.com/llvm/llvm-project/issues/48582
282  // is fixed.
283  auto const baseFee = baseFeeVote.getVotes();
284  auto const baseReserve = baseReserveVote.getVotes();
285  auto const incReserve = incReserveVote.getVotes();
286 
287  auto const seq = lastClosedLedger->info().seq + 1;
288 
289  // add transactions to our position
290  if (baseFee.second || baseReserve.second || incReserve.second)
291  {
292  JLOG(journal_.warn())
293  << "We are voting for a fee change: " << baseFee.first << "/"
294  << baseReserve.first << "/" << incReserve.first;
295 
296  STTx feeTx(ttFEE, [=, &rules](auto& obj) {
297  obj[sfAccount] = AccountID();
298  obj[sfLedgerSequence] = seq;
299  if (rules.enabled(featureXRPFees))
300  {
301  obj[sfBaseFeeDrops] = baseFee.first;
302  obj[sfReserveBaseDrops] = baseReserve.first;
303  obj[sfReserveIncrementDrops] = incReserve.first;
304  }
305  else
306  {
307  // Without the featureXRPFees amendment, these fields are
308  // required.
309  obj[sfBaseFee] =
310  baseFee.first.dropsAs<std::uint64_t>(baseFeeVote.current());
311  obj[sfReserveBase] = baseReserve.first.dropsAs<std::uint32_t>(
312  baseReserveVote.current());
313  obj[sfReserveIncrement] =
314  incReserve.first.dropsAs<std::uint32_t>(
315  incReserveVote.current());
317  }
318  });
319 
320  uint256 txID = feeTx.getTransactionID();
321 
322  JLOG(journal_.warn()) << "Vote: " << txID;
323 
324  Serializer s;
325  feeTx.add(s);
326 
327  if (!initialPosition->addGiveItem(
329  make_shamapitem(txID, s.slice())))
330  {
331  JLOG(journal_.warn()) << "Ledger already had fee change";
332  }
333  }
334 }
335 
336 //------------------------------------------------------------------------------
337 
339 make_FeeVote(FeeSetup const& setup, beast::Journal journal)
340 {
341  return std::make_unique<FeeVoteImpl>(setup, journal);
342 }
343 
344 } // namespace ripple
ripple::FeeSetup::reference_fee
XRPAmount reference_fee
The cost of a reference transaction in drops.
Definition: Config.h:72
ripple::detail::VotableValue::voteMap_
std::map< value_type, int > voteMap_
Definition: FeeVoteImpl.cpp:38
ripple::isFlagLedger
bool isFlagLedger(LedgerIndex seq)
Returns true if the given ledgerIndex is a flag ledgerIndex.
Definition: Ledger.cpp:969
ripple::sfBaseFeeDrops
const SF_AMOUNT sfBaseFeeDrops
ripple::sfReserveBase
const SF_UINT32 sfReserveBase
ripple::featureXRPFees
const uint256 featureXRPFees
ripple::Rules::enabled
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:94
std::shared_ptr
STL class.
ripple::TypedField
A field with a type known at compile time.
Definition: SField.h:271
ripple::FeeVoteImpl::FeeVoteImpl
FeeVoteImpl(FeeSetup const &setup, beast::Journal journal)
Definition: FeeVoteImpl.cpp:115
ripple::sfLedgerSequence
const SF_UINT32 sfLedgerSequence
ripple::FeeVoteImpl::target_
FeeSetup target_
Definition: FeeVoteImpl.cpp:96
std::pair
ripple::make_shamapitem
boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition: SHAMapItem.h:160
ripple::FeeVote
Manager to process fee votes.
Definition: FeeVote.h:32
std::vector
STL class.
ripple::detail::VotableValue::noVote
void noVote()
Definition: FeeVoteImpl.cpp:55
ripple::isLegalAmountSigned
bool isLegalAmountSigned(XRPAmount const &amount)
Returns true if the absolute value of the amount does not exceed the initial XRP in existence.
Definition: SystemParameters.h:55
ripple::ttFEE
@ ttFEE
This system-generated transaction type is used to update the network's fee settings.
Definition: TxFormats.h:152
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::detail::VotableValue::target_
const value_type target_
Definition: FeeVoteImpl.cpp:37
ripple::detail::VotableValue::VotableValue
VotableValue(value_type current, value_type target)
Definition: FeeVoteImpl.cpp:41
ripple::FeeVoteImpl
Definition: FeeVoteImpl.cpp:93
ripple::SHAMapNodeType::tnTRANSACTION_NM
@ tnTRANSACTION_NM
ripple::STValidation
Definition: STValidation.h:44
ripple::Fees::increment
XRPAmount increment
Definition: ReadView.h:53
ripple::base_uint< 256 >
ripple::Fees
Reflects the fee settings for a particular ledger.
Definition: ReadView.h:49
ripple::detail::VotableValue::value_type
XRPAmount value_type
Definition: FeeVoteImpl.cpp:35
ripple::FeeVoteImpl::journal_
const beast::Journal journal_
Definition: FeeVoteImpl.cpp:97
ripple::detail::VotableValue::current
value_type current() const
Definition: FeeVoteImpl.cpp:61
ripple::sfReserveIncrement
const SF_UINT32 sfReserveIncrement
ripple::XRPAmount::value_type
std::int64_t value_type
Definition: XRPAmount.h:53
ripple::detail::VotableValue::current_
const value_type current_
Definition: FeeVoteImpl.cpp:36
ripple::detail::VotableValue
Definition: FeeVoteImpl.cpp:32
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:313
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:63
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::STTx
Definition: STTx.h:45
ripple::ValStatus::current
@ current
This was a new validation and was added.
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::FeeSetup::account_reserve
XRPAmount account_reserve
The account reserve requirement in drops.
Definition: Config.h:75
std::uint32_t
std::map
STL class.
ripple::sfReserveIncrementDrops
const SF_AMOUNT sfReserveIncrementDrops
ripple::sfReserveBaseDrops
const SF_AMOUNT sfReserveBaseDrops
ripple::Config::FEE_UNITS_DEPRECATED
static constexpr std::uint32_t FEE_UNITS_DEPRECATED
Definition: Config.h:165
std::min
T min(T... args)
ripple::Serializer
Definition: Serializer.h:39
ripple::sfBaseFee
const SF_UINT64 sfBaseFee
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::detail::VotableValue::getVotes
std::pair< value_type, bool > getVotes() const
Definition: FeeVoteImpl.cpp:71
ripple::Fees::accountReserve
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
Definition: ReadView.h:66
std
STL namespace.
ripple::FeeSetup::owner_reserve
XRPAmount owner_reserve
The per-owned item reserve requirement in drops.
Definition: Config.h:78
ripple::sfReferenceFeeUnits
const SF_UINT32 sfReferenceFeeUnits
ripple::Rules
Rules controlling protocol behavior.
Definition: Rules.h:33
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::FeeSetup
Fee schedule for startup / standalone, and to vote for.
Definition: Config.h:69
ripple::FeeVoteImpl::doValidation
void doValidation(Fees const &lastFees, Rules const &rules, STValidation &val) override
Add local fee preference to validation.
Definition: FeeVoteImpl.cpp:121
std::max
T max(T... args)
std::unique_ptr
STL class.
ripple::detail::VotableValue::addVote
void addVote(value_type vote)
Definition: FeeVoteImpl.cpp:49
std::numeric_limits
ripple::make_FeeVote
std::unique_ptr< FeeVote > make_FeeVote(FeeSetup const &setup, beast::Journal journal)
Create an instance of the FeeVote logic.
Definition: FeeVoteImpl.cpp:339
ripple::AccountID
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition: AccountID.h:47
ripple::Fees::base
XRPAmount base
Definition: ReadView.h:51
ripple::FeeVoteImpl::doVoting
void doVoting(std::shared_ptr< ReadView const > const &lastClosedLedger, std::vector< std::shared_ptr< STValidation >> const &parentValidations, std::shared_ptr< SHAMap > const &initialPosition) override
Cast our local vote on the fee.
Definition: FeeVoteImpl.cpp:197
ripple::XRPAmount
Definition: XRPAmount.h:46