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/main/Application.h>
22#include <xrpld/app/misc/FeeVote.h>
23#include <xrpl/basics/BasicConfig.h>
24#include <xrpl/beast/utility/Journal.h>
25#include <xrpl/protocol/STValidation.h>
26#include <xrpl/protocol/st.h>
27
28namespace ripple {
29
30namespace detail {
31
33{
34private:
36 value_type const current_; // The current setting
37 value_type const target_; // The setting we want
39
40public:
42 : current_(current), target_(target)
43 {
44 // Add our vote
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
70auto
71VotableValue::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
93class FeeVoteImpl : public FeeVote
94{
95private:
98
99public:
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
120void
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",
149 sfReserveBaseDrops);
150 vote(
151 lastFees.increment,
153 "reserve increment",
154 sfReserveIncrementDrops);
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",
192 sfReserveIncrement);
193 }
194}
195
196void
198 std::shared_ptr<ReadView const> const& lastClosedLedger,
200 std::shared_ptr<SHAMap> const& initialPosition)
201{
202 // LCL must be flag ledger
203 XRPL_ASSERT(
204 lastClosedLedger && isFlagLedger(lastClosedLedger->seq()),
205 "ripple::FeeVoteImpl::doVoting : has a flag ledger");
206
207 detail::VotableValue baseFeeVote(
208 lastClosedLedger->fees().base, target_.reference_fee);
209
210 detail::VotableValue baseReserveVote(
211 lastClosedLedger->fees().accountReserve(0), target_.account_reserve);
212
213 detail::VotableValue incReserveVote(
214 lastClosedLedger->fees().increment, target_.owner_reserve);
215
216 auto const& rules = lastClosedLedger->rules();
217 if (rules.enabled(featureXRPFees))
218 {
219 auto doVote = [](std::shared_ptr<STValidation> const& val,
221 SF_AMOUNT const& xrpField) {
222 if (auto const field = ~val->at(~xrpField);
223 field && field->native())
224 {
225 auto const vote = field->xrp();
226 if (isLegalAmountSigned(vote))
227 value.addVote(vote);
228 else
229 value.noVote();
230 }
231 else
232 {
233 value.noVote();
234 }
235 };
236
237 for (auto const& val : set)
238 {
239 if (!val->isTrusted())
240 continue;
241 doVote(val, baseFeeVote, sfBaseFeeDrops);
242 doVote(val, baseReserveVote, sfReserveBaseDrops);
243 doVote(val, incReserveVote, sfReserveIncrementDrops);
244 }
245 }
246 else
247 {
248 auto doVote = [](std::shared_ptr<STValidation> const& val,
250 auto const& valueField) {
251 if (auto const field = val->at(~valueField))
252 {
253 using xrptype = XRPAmount::value_type;
254 auto const vote = *field;
255 if (vote <= std::numeric_limits<xrptype>::max() &&
256 isLegalAmountSigned(XRPAmount{unsafe_cast<xrptype>(vote)}))
257 value.addVote(
258 XRPAmount{unsafe_cast<XRPAmount::value_type>(vote)});
259 else
260 // Invalid amounts will be treated as if they're
261 // not provided. Don't throw because this value is
262 // provided by an external entity.
263 value.noVote();
264 }
265 else
266 {
267 value.noVote();
268 }
269 };
270
271 for (auto const& val : set)
272 {
273 if (!val->isTrusted())
274 continue;
275 doVote(val, baseFeeVote, sfBaseFee);
276 doVote(val, baseReserveVote, sfReserveBase);
277 doVote(val, incReserveVote, sfReserveIncrement);
278 }
279 }
280
281 // choose our positions
282 // TODO: Use structured binding once LLVM 16 is the minimum supported
283 // version. See also: https://github.com/llvm/llvm-project/issues/48582
284 // https://github.com/llvm/llvm-project/commit/127bf44385424891eb04cff8e52d3f157fc2cb7c
285 auto const baseFee = baseFeeVote.getVotes();
286 auto const baseReserve = baseReserveVote.getVotes();
287 auto const incReserve = incReserveVote.getVotes();
288
289 auto const seq = lastClosedLedger->info().seq + 1;
290
291 // add transactions to our position
292 if (baseFee.second || baseReserve.second || incReserve.second)
293 {
294 JLOG(journal_.warn())
295 << "We are voting for a fee change: " << baseFee.first << "/"
296 << baseReserve.first << "/" << incReserve.first;
297
298 STTx feeTx(ttFEE, [=, &rules](auto& obj) {
299 obj[sfAccount] = AccountID();
300 obj[sfLedgerSequence] = seq;
301 if (rules.enabled(featureXRPFees))
302 {
303 obj[sfBaseFeeDrops] = baseFee.first;
304 obj[sfReserveBaseDrops] = baseReserve.first;
305 obj[sfReserveIncrementDrops] = incReserve.first;
306 }
307 else
308 {
309 // Without the featureXRPFees amendment, these fields are
310 // required.
311 obj[sfBaseFee] =
312 baseFee.first.dropsAs<std::uint64_t>(baseFeeVote.current());
313 obj[sfReserveBase] = baseReserve.first.dropsAs<std::uint32_t>(
314 baseReserveVote.current());
315 obj[sfReserveIncrement] =
316 incReserve.first.dropsAs<std::uint32_t>(
317 incReserveVote.current());
318 obj[sfReferenceFeeUnits] = Config::FEE_UNITS_DEPRECATED;
319 }
320 });
321
322 uint256 txID = feeTx.getTransactionID();
323
324 JLOG(journal_.warn()) << "Vote: " << txID;
325
326 Serializer s;
327 feeTx.add(s);
328
329 if (!initialPosition->addGiveItem(
331 make_shamapitem(txID, s.slice())))
332 {
333 JLOG(journal_.warn()) << "Ledger already had fee change";
334 }
335 }
336}
337
338//------------------------------------------------------------------------------
339
342{
343 return std::make_unique<FeeVoteImpl>(setup, journal);
344}
345
346} // namespace ripple
A generic endpoint for log messages.
Definition: Journal.h:59
Stream info() const
Definition: Journal.h:323
Stream warn() const
Definition: Journal.h:329
static constexpr std::uint32_t FEE_UNITS_DEPRECATED
Definition: Config.h:167
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:97
Manager to process fee votes.
Definition: FeeVote.h:33
Rules controlling protocol behavior.
Definition: Rules.h:35
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:122
Slice slice() const noexcept
Definition: Serializer.h:66
std::int64_t value_type
Definition: XRPAmount.h:46
VotableValue(value_type current, value_type target)
Definition: FeeVoteImpl.cpp:41
std::pair< value_type, bool > getVotes() const
Definition: FeeVoteImpl.cpp:71
std::map< value_type, int > voteMap_
Definition: FeeVoteImpl.cpp:38
void addVote(value_type vote)
Definition: FeeVoteImpl.cpp:49
value_type current() const
Definition: FeeVoteImpl.cpp:61
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:316
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:966
boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition: SHAMapItem.h:160
STL namespace.
Fee schedule for startup / standalone, and to vote for.
Definition: Config.h:73
XRPAmount reference_fee
The cost of a reference transaction in drops.
Definition: Config.h:75
XRPAmount owner_reserve
The per-owned item reserve requirement in drops.
Definition: Config.h:81
XRPAmount account_reserve
The account reserve requirement in drops.
Definition: Config.h:78
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