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#include <xrpl/beast/utility/Journal.h>
23#include <xrpl/protocol/STValidation.h>
24#include <xrpl/protocol/st.h>
25
26namespace ripple {
27
28namespace detail {
29
31{
32private:
34 value_type const current_; // The current setting
35 value_type const target_; // The setting we want
37
38public:
40 : current_(current), target_(target)
41 {
42 // Add our vote
44 }
45
46 void
48 {
49 ++voteMap_[vote];
50 }
51
52 void
54 {
56 }
57
59 current() const
60 {
61 return current_;
62 }
63
65 getVotes() const;
66};
67
68auto
69VotableValue::getVotes() const -> std::pair<value_type, bool>
70{
71 value_type ourVote = current_;
72 int weight = 0;
73 for (auto const& [key, val] : voteMap_)
74 {
75 // Take most voted value between current and target, inclusive
76 if ((key <= std::max(target_, current_)) &&
77 (key >= std::min(target_, current_)) && (val > weight))
78 {
79 ourVote = key;
80 weight = val;
81 }
82 }
83
84 return {ourVote, ourVote != current_};
85}
86
87} // namespace detail
88
89//------------------------------------------------------------------------------
90
91class FeeVoteImpl : public FeeVote
92{
93private:
96
97public:
98 FeeVoteImpl(FeeSetup const& setup, beast::Journal journal);
99
100 void
101 doValidation(Fees const& lastFees, Rules const& rules, STValidation& val)
102 override;
103
104 void
105 doVoting(
106 std::shared_ptr<ReadView const> const& lastClosedLedger,
107 std::vector<std::shared_ptr<STValidation>> const& parentValidations,
108 std::shared_ptr<SHAMap> const& initialPosition) override;
109};
110
111//--------------------------------------------------------------------------
112
114 : target_(setup), journal_(journal)
115{
116}
117
118void
120 Fees const& lastFees,
121 Rules const& rules,
122 STValidation& v)
123{
124 // Values should always be in a valid range (because the voting process
125 // will ignore out-of-range values) but if we detect such a case, we do
126 // not send a value.
127 if (rules.enabled(featureXRPFees))
128 {
129 auto vote = [&v, this](
130 auto const current,
131 XRPAmount target,
132 const char* name,
133 auto const& sfield) {
134 if (current != target)
135 {
136 JLOG(journal_.info())
137 << "Voting for " << name << " of " << target;
138
139 v[sfield] = target;
140 }
141 };
142 vote(lastFees.base, target_.reference_fee, "base fee", sfBaseFeeDrops);
143 vote(
144 lastFees.accountReserve(0),
146 "base reserve",
147 sfReserveBaseDrops);
148 vote(
149 lastFees.increment,
151 "reserve increment",
152 sfReserveIncrementDrops);
153 }
154 else
155 {
156 auto to32 = [](XRPAmount target) {
157 return target.dropsAs<std::uint32_t>();
158 };
159 auto to64 = [](XRPAmount target) {
160 return target.dropsAs<std::uint64_t>();
161 };
162 auto vote = [&v, this](
163 auto const current,
164 XRPAmount target,
165 auto const& convertCallback,
166 const char* name,
167 auto const& sfield) {
168 if (current != target)
169 {
170 JLOG(journal_.info())
171 << "Voting for " << name << " of " << target;
172
173 if (auto const f = convertCallback(target))
174 v[sfield] = *f;
175 }
176 };
177
178 vote(lastFees.base, target_.reference_fee, to64, "base fee", sfBaseFee);
179 vote(
180 lastFees.accountReserve(0),
182 to32,
183 "base reserve",
184 sfReserveBase);
185 vote(
186 lastFees.increment,
188 to32,
189 "reserve increment",
190 sfReserveIncrement);
191 }
192}
193
194void
196 std::shared_ptr<ReadView const> const& lastClosedLedger,
198 std::shared_ptr<SHAMap> const& initialPosition)
199{
200 // LCL must be flag ledger
201 XRPL_ASSERT(
202 lastClosedLedger && isFlagLedger(lastClosedLedger->seq()),
203 "ripple::FeeVoteImpl::doVoting : has a flag ledger");
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,
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,
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 16 is the minimum supported
281 // version. See also: https://github.com/llvm/llvm-project/issues/48582
282 // https://github.com/llvm/llvm-project/commit/127bf44385424891eb04cff8e52d3f157fc2cb7c
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());
316 obj[sfReferenceFeeUnits] = Config::FEE_UNITS_DEPRECATED;
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
340{
341 return std::make_unique<FeeVoteImpl>(setup, journal);
342}
343
344} // 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_
Definition: FeeVoteImpl.cpp:95
Manager to process fee votes.
Definition: FeeVote.h:31
Rules controlling protocol behavior.
Definition: Rules.h:35
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:130
Slice slice() const noexcept
Definition: Serializer.h:67
std::int64_t value_type
Definition: XRPAmount.h:46
VotableValue(value_type current, value_type target)
Definition: FeeVoteImpl.cpp:39
std::pair< value_type, bool > getVotes() const
Definition: FeeVoteImpl.cpp:69
std::map< value_type, int > voteMap_
Definition: FeeVoteImpl.cpp:36
void addVote(value_type vote)
Definition: FeeVoteImpl.cpp:47
value_type current() const
Definition: FeeVoteImpl.cpp:59
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:26
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition: AccountID.h:49
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:315
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:956
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.
Definition: protocol/Fees.h:33
XRPAmount base
Definition: protocol/Fees.h:34
XRPAmount increment
Definition: protocol/Fees.h:36
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
Definition: protocol/Fees.h:49
A field with a type known at compile time.
Definition: SField.h:315