xrpld
Loading...
Searching...
No Matches
FeeVoteImpl.cpp
1#include <xrpld/app/misc/FeeVote.h>
2#include <xrpld/core/Config.h>
3
4#include <xrpl/basics/Log.h>
5#include <xrpl/basics/base_uint.h>
6#include <xrpl/beast/utility/Journal.h>
7#include <xrpl/beast/utility/instrumentation.h>
8#include <xrpl/ledger/ReadView.h>
9#include <xrpl/protocol/Feature.h>
10#include <xrpl/protocol/Fees.h>
11#include <xrpl/protocol/Protocol.h>
12#include <xrpl/protocol/SField.h>
13#include <xrpl/protocol/STTx.h>
14#include <xrpl/protocol/STValidation.h>
15#include <xrpl/protocol/Serializer.h>
16#include <xrpl/protocol/SystemParameters.h>
17#include <xrpl/protocol/TxFormats.h>
18#include <xrpl/protocol/XRPAmount.h>
19#include <xrpl/shamap/SHAMap.h>
20#include <xrpl/shamap/SHAMapItem.h>
21#include <xrpl/shamap/SHAMapTreeNode.h>
22
23#include <algorithm>
24#include <cstdint>
25#include <limits>
26#include <map>
27#include <memory>
28#include <utility>
29#include <vector>
30
31namespace xrpl {
32
33namespace detail {
34
36{
37private:
39 value_type const current_; // The current setting
40 value_type const target_; // The setting we want
42
43public:
45 {
46 // Add our vote
48 }
49
50 void
52 {
53 ++voteMap_[vote];
54 }
55
56 void
58 {
60 }
61
62 [[nodiscard]] value_type
63 current() const
64 {
65 return current_;
66 }
67
68 [[nodiscard]] std::pair<value_type, bool>
69 getVotes() const;
70};
71
72auto
73VotableValue::getVotes() const -> std::pair<value_type, bool>
74{
75 value_type ourVote = current_;
76 int weight = 0;
77 for (auto const& [key, val] : voteMap_)
78 {
79 // Take most voted value between current and target, inclusive
80 if ((key <= std::max(target_, current_)) && (key >= std::min(target_, current_)) &&
81 (val > weight))
82 {
83 ourVote = key;
84 weight = val;
85 }
86 }
87
88 return {ourVote, ourVote != current_};
89}
90
91} // namespace detail
92
93//------------------------------------------------------------------------------
94
95class FeeVoteImpl : public FeeVote
96{
97private:
100
101public:
102 FeeVoteImpl(FeeSetup const& setup, beast::Journal journal);
103
104 void
105 doValidation(Fees const& lastFees, Rules const& rules, STValidation& val) override;
106
107 void
108 doVoting(
109 std::shared_ptr<ReadView const> const& lastClosedLedger,
110 std::vector<std::shared_ptr<STValidation>> const& parentValidations,
111 std::shared_ptr<SHAMap> const& initialPosition) override;
112};
113
114//--------------------------------------------------------------------------
115
117 : target_(setup), journal_(journal)
118{
119}
120
121void
122FeeVoteImpl::doValidation(Fees const& lastFees, Rules const& rules, 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 =
130 [&v, this](auto const current, XRPAmount target, char const* name, auto const& sfield) {
131 if (current != target)
132 {
133 JLOG(journal_.info()) << "Voting for " << name << " of " << target;
134
135 v[sfield] = target;
136 }
137 };
138 vote(lastFees.base, target_.referenceFee, "base fee", sfBaseFeeDrops);
139 vote(lastFees.reserve, target_.accountReserve, "base reserve", sfReserveBaseDrops);
140 vote(
141 lastFees.increment, target_.ownerReserve, "reserve increment", sfReserveIncrementDrops);
142 }
143 else
144 {
145 auto to32 = [](XRPAmount target) { return target.dropsAs<std::uint32_t>(); };
146 auto to64 = [](XRPAmount target) { return target.dropsAs<std::uint64_t>(); };
147 auto vote = [&v, this](
148 auto const current,
149 XRPAmount target,
150 auto const& convertCallback,
151 char const* name,
152 auto const& sfield) {
153 if (current != target)
154 {
155 JLOG(journal_.info()) << "Voting for " << name << " of " << target;
156
157 if (auto const f = convertCallback(target))
158 v[sfield] = *f;
159 }
160 };
161
162 vote(lastFees.base, target_.referenceFee, to64, "base fee", sfBaseFee);
163 vote(lastFees.reserve, target_.accountReserve, to32, "base reserve", sfReserveBase);
164 vote(
165 lastFees.increment,
166 target_.ownerReserve,
167 to32,
168 "reserve increment",
169 sfReserveIncrement);
170 }
171}
172
173void
175 std::shared_ptr<ReadView const> const& lastClosedLedger,
177 std::shared_ptr<SHAMap> const& initialPosition)
178{
179 // LCL must be flag ledger
180 XRPL_ASSERT(
181 lastClosedLedger && isFlagLedger(lastClosedLedger->seq()),
182 "xrpl::FeeVoteImpl::doVoting : has a flag ledger");
183
184 detail::VotableValue baseFeeVote(lastClosedLedger->fees().base, target_.referenceFee);
185
186 detail::VotableValue baseReserveVote(lastClosedLedger->fees().reserve, target_.accountReserve);
187
188 detail::VotableValue incReserveVote(lastClosedLedger->fees().increment, target_.ownerReserve);
189
190 auto const& rules = lastClosedLedger->rules();
191 if (rules.enabled(featureXRPFees))
192 {
193 auto doVote = [](std::shared_ptr<STValidation> const& val,
195 SF_AMOUNT const& xrpField) {
196 if (auto const field = ~val->at(~xrpField); field && field->native())
197 {
198 auto const vote = field->xrp();
199 if (isLegalAmountSigned(vote))
200 {
201 value.addVote(vote);
202 }
203 else
204 {
205 value.noVote();
206 }
207 }
208 else
209 {
210 value.noVote();
211 }
212 };
213
214 for (auto const& val : set)
215 {
216 if (!val->isTrusted())
217 continue;
218 doVote(val, baseFeeVote, sfBaseFeeDrops);
219 doVote(val, baseReserveVote, sfReserveBaseDrops);
220 doVote(val, incReserveVote, sfReserveIncrementDrops);
221 }
222 }
223 else
224 {
225 auto doVote = [](std::shared_ptr<STValidation> const& val,
227 auto const& valueField) {
228 if (auto const field = val->at(~valueField))
229 {
230 using XRPType = XRPAmount::value_type;
231 auto const vote = *field;
232 if (vote <= std::numeric_limits<XRPType>::max() &&
234 {
235 value.addVote(XRPAmount{unsafeCast<XRPType>(vote)});
236 }
237 else
238 {
239 // Invalid amounts will be treated as if they're
240 // not provided. Don't throw because this value is
241 // provided by an external entity.
242 value.noVote();
243 }
244 }
245 else
246 {
247 value.noVote();
248 }
249 };
250
251 for (auto const& val : set)
252 {
253 if (!val->isTrusted())
254 continue;
255 doVote(val, baseFeeVote, sfBaseFee);
256 doVote(val, baseReserveVote, sfReserveBase);
257 doVote(val, incReserveVote, sfReserveIncrement);
258 }
259 }
260
261 // choose our positions
262 // TODO: Use structured binding once LLVM 16 is the minimum supported
263 // version. See also: https://github.com/llvm/llvm-project/issues/48582
264 // https://github.com/llvm/llvm-project/commit/127bf44385424891eb04cff8e52d3f157fc2cb7c
265 auto const baseFee = baseFeeVote.getVotes();
266 auto const baseReserve = baseReserveVote.getVotes();
267 auto const incReserve = incReserveVote.getVotes();
268
269 auto const seq = lastClosedLedger->header().seq + 1;
270
271 // add transactions to our position
272 if (baseFee.second || baseReserve.second || incReserve.second)
273 {
274 JLOG(journal_.warn()) << "We are voting for a fee change: " << baseFee.first << "/"
275 << baseReserve.first << "/" << incReserve.first;
276
277 STTx const feeTx(ttFEE, [=, &rules](auto& obj) {
278 obj[sfAccount] = AccountID();
279 obj[sfLedgerSequence] = seq;
280 if (rules.enabled(featureXRPFees))
281 {
282 obj[sfBaseFeeDrops] = baseFee.first;
283 obj[sfReserveBaseDrops] = baseReserve.first;
284 obj[sfReserveIncrementDrops] = incReserve.first;
285 }
286 else
287 {
288 // Without the featureXRPFees amendment, these fields are
289 // required.
290 obj[sfBaseFee] = baseFee.first.dropsAs<std::uint64_t>(baseFeeVote.current());
291 obj[sfReserveBase] =
292 baseReserve.first.dropsAs<std::uint32_t>(baseReserveVote.current());
293 obj[sfReserveIncrement] =
294 incReserve.first.dropsAs<std::uint32_t>(incReserveVote.current());
295 obj[sfReferenceFeeUnits] = kFeeUnitsDeprecated;
296 }
297 });
298
299 uint256 const txID = feeTx.getTransactionID();
300
301 JLOG(journal_.warn()) << "Vote: " << txID;
302
303 Serializer s;
304 feeTx.add(s);
305
306 if (!initialPosition->addGiveItem(
308 {
309 JLOG(journal_.warn()) << "Ledger already had fee change";
310 }
311 }
312}
313
314//------------------------------------------------------------------------------
315
317makeFeeVote(FeeSetup const& setup, beast::Journal journal)
318{
319 return std::make_unique<FeeVoteImpl>(setup, journal);
320}
321
322} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
void doValidation(Fees const &lastFees, Rules const &rules, STValidation &val) override
Add local fee preference to validation.
FeeVoteImpl(FeeSetup const &setup, beast::Journal journal)
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.
beast::Journal const journal_
Manager to process fee votes.
Definition FeeVote.h:11
Rules controlling protocol behavior.
Definition Rules.h:33
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:171
Slice slice() const noexcept
Definition Serializer.h:44
std::int64_t value_type
Definition XRPAmount.h:26
value_type const current_
std::map< value_type, int > voteMap_
std::pair< value_type, bool > getVotes() const
value_type current() const
VotableValue(value_type current, value_type target)
void addVote(value_type vote)
T make_unique(T... args)
T max(T... args)
T min(T... args)
STL namespace.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
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 isFlagLedger(LedgerIndex seq)
Returns true if the given ledgerIndex is a flag ledgerIndex.
Definition Protocol.cpp:11
std::unique_ptr< FeeVote > makeFeeVote(FeeSetup const &setup, beast::Journal journal)
Create an instance of the FeeVote logic.
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > unsafeCast(Src s) noexcept
Definition safe_cast.h:52
constexpr std::uint32_t kFeeUnitsDeprecated
TypedField< STAmount > SF_AMOUNT
Definition SField.h:349
boost::intrusive_ptr< SHAMapItem > makeShamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:139
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:28
bool isLegalAmountSigned(XRPAmount const &amount)
Returns true if the absolute value of the amount does not exceed the initial XRP in existence.
BaseUInt< 256 > uint256
Definition base_uint.h:562
Fee schedule for startup / standalone, and to vote for.
Definition Config.h:49
Reflects the fee settings for a particular ledger.
XRPAmount reserve
Minimum XRP an account must hold to exist on the ledger.
XRPAmount increment
Additional XRP reserve required per owned ledger object.
XRPAmount base
Cost of a reference transaction in drops.