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