rippled
Loading...
Searching...
No Matches
applySteps.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/tx/applySteps.h>
21#pragma push_macro("TRANSACTION")
22#undef TRANSACTION
23
24// Do nothing
25#define TRANSACTION(...)
26#define TRANSACTION_INCLUDE 1
27
28#include <xrpl/protocol/detail/transactions.macro>
29
30#undef TRANSACTION
31#pragma pop_macro("TRANSACTION")
32
33// DO NOT INCLUDE TRANSACTOR HEADER FILES HERE.
34// See the instructions at the top of transactions.macro instead.
35
36#include <xrpl/protocol/TxFormats.h>
37
38#include <stdexcept>
39
40namespace ripple {
41
42namespace {
43
44struct UnknownTxnType : std::exception
45{
46 TxType txnType;
47 UnknownTxnType(TxType t) : txnType{t}
48 {
49 }
50};
51
52// Call a lambda with the concrete transaction type as a template parameter
53// throw an "UnknownTxnType" exception on error
54template <class F>
55auto
56with_txn_type(TxType txnType, F&& f)
57{
58 switch (txnType)
59 {
60#pragma push_macro("TRANSACTION")
61#undef TRANSACTION
62
63#define TRANSACTION(tag, value, name, ...) \
64 case tag: \
65 return f.template operator()<name>();
66
67#include <xrpl/protocol/detail/transactions.macro>
68
69#undef TRANSACTION
70#pragma pop_macro("TRANSACTION")
71 default:
72 throw UnknownTxnType(txnType);
73 }
74}
75} // namespace
76
77// Templates so preflight does the right thing with T::ConsequencesFactory.
78//
79// This could be done more easily using if constexpr, but Visual Studio
80// 2017 doesn't handle if constexpr correctly. So once we're no longer
81// building with Visual Studio 2017 we can consider replacing the four
82// templates with a single template function that uses if constexpr.
83//
84// For Transactor::Normal
85//
86
87// clang-format off
88// Current formatter for rippled is based on clang-10, which does not handle `requires` clauses
89template <class T>
90requires(T::ConsequencesFactory == Transactor::Normal)
91TxConsequences
93{
94 return TxConsequences(ctx.tx);
95};
96
97// For Transactor::Blocker
98template <class T>
99requires(T::ConsequencesFactory == Transactor::Blocker)
100TxConsequences
105
106// For Transactor::Custom
107template <class T>
108requires(T::ConsequencesFactory == Transactor::Custom)
109TxConsequences
111{
112 return T::makeTxConsequences(ctx);
113};
114// clang-format on
115
118{
119 try
120 {
121 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
122 auto const tec = T::preflight(ctx);
123 return std::make_pair(
124 tec,
125 isTesSuccess(tec) ? consequences_helper<T>(ctx)
126 : TxConsequences{tec});
127 });
128 }
129 catch (UnknownTxnType const& e)
130 {
131 // Should never happen
132 JLOG(ctx.j.fatal())
133 << "Unknown transaction type in preflight: " << e.txnType;
134 UNREACHABLE("ripple::invoke_preflight : unknown transaction type");
135 return {temUNKNOWN, TxConsequences{temUNKNOWN}};
136 }
137}
138
139static TER
141{
142 try
143 {
144 // use name hiding to accomplish compile-time polymorphism of static
145 // class functions for Transactor and derived classes.
146 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
147 // If the transactor requires a valid account and the transaction
148 // doesn't list one, preflight will have already a flagged a
149 // failure.
150 auto const id = ctx.tx.getAccountID(sfAccount);
151
152 if (id != beast::zero)
153 {
154 TER result = T::checkSeqProxy(ctx.view, ctx.tx, ctx.j);
155
156 if (result != tesSUCCESS)
157 return result;
158
159 result = T::checkPriorTxAndLastLedger(ctx);
160
161 if (result != tesSUCCESS)
162 return result;
163
164 result = T::checkFee(ctx, calculateBaseFee(ctx.view, ctx.tx));
165
166 if (result != tesSUCCESS)
167 return result;
168
169 result = T::checkPermission(ctx.view, ctx.tx);
170
171 if (result != tesSUCCESS)
172 return result;
173
174 result = T::checkSign(ctx);
175
176 if (result != tesSUCCESS)
177 return result;
178 }
179
180 return T::preclaim(ctx);
181 });
182 }
183 catch (UnknownTxnType const& e)
184 {
185 // Should never happen
186 JLOG(ctx.j.fatal())
187 << "Unknown transaction type in preclaim: " << e.txnType;
188 UNREACHABLE("ripple::invoke_preclaim : unknown transaction type");
189 return temUNKNOWN;
190 }
191}
192
209static XRPAmount
210invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
211{
212 try
213 {
214 return with_txn_type(tx.getTxnType(), [&]<typename T>() {
215 return T::calculateBaseFee(view, tx);
216 });
217 }
218 catch (UnknownTxnType const& e)
219 {
220 UNREACHABLE(
221 "ripple::invoke_calculateBaseFee : unknown transaction type");
222 return XRPAmount{0};
223 }
224}
225
226TxConsequences::TxConsequences(NotTEC pfresult)
227 : isBlocker_(false)
228 , fee_(beast::zero)
229 , potentialSpend_(beast::zero)
230 , seqProx_(SeqProxy::sequence(0))
231 , sequencesConsumed_(0)
232{
233 XRPL_ASSERT(
234 !isTesSuccess(pfresult),
235 "ripple::TxConsequences::TxConsequences : is not tesSUCCESS");
236}
237
239 : isBlocker_(false)
240 , fee_(
241 tx[sfFee].native() && !tx[sfFee].negative() ? tx[sfFee].xrp()
242 : beast::zero)
243 , potentialSpend_(beast::zero)
244 , seqProx_(tx.getSeqProxy())
245 , sequencesConsumed_(tx.getSeqProxy().isSeq() ? 1 : 0)
246{
247}
248
250 : TxConsequences(tx)
251{
252 isBlocker_ = (category == blocker);
253}
254
256 : TxConsequences(tx)
257{
259}
260
266
267static ApplyResult
269{
270 try
271 {
272 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
273 T p(ctx);
274 return p();
275 });
276 }
277 catch (UnknownTxnType const& e)
278 {
279 // Should never happen
280 JLOG(ctx.journal.fatal())
281 << "Unknown transaction type in apply: " << e.txnType;
282 UNREACHABLE("ripple::invoke_apply : unknown transaction type");
283 return {temUNKNOWN, false};
284 }
285}
286
287PreflightResult
289 Application& app,
290 Rules const& rules,
291 STTx const& tx,
292 ApplyFlags flags,
294{
295 PreflightContext const pfctx(app, tx, rules, flags, j);
296 try
297 {
298 return {pfctx, invoke_preflight(pfctx)};
299 }
300 catch (std::exception const& e)
301 {
302 JLOG(j.fatal()) << "apply (preflight): " << e.what();
303 return {pfctx, {tefEXCEPTION, TxConsequences{tx}}};
304 }
305}
306
307PreflightResult
309 Application& app,
310 Rules const& rules,
311 uint256 const& parentBatchId,
312 STTx const& tx,
313 ApplyFlags flags,
315{
316 PreflightContext const pfctx(app, tx, parentBatchId, rules, flags, j);
317 try
318 {
319 return {pfctx, invoke_preflight(pfctx)};
320 }
321 catch (std::exception const& e)
322 {
323 JLOG(j.fatal()) << "apply (preflight): " << e.what();
324 return {pfctx, {tefEXCEPTION, TxConsequences{tx}}};
325 }
326}
327
328PreclaimResult
330 PreflightResult const& preflightResult,
331 Application& app,
332 OpenView const& view)
333{
335 if (preflightResult.rules != view.rules())
336 {
337 auto secondFlight = [&]() {
338 if (preflightResult.parentBatchId)
339 return preflight(
340 app,
341 view.rules(),
342 preflightResult.parentBatchId.value(),
343 preflightResult.tx,
344 preflightResult.flags,
345 preflightResult.j);
346
347 return preflight(
348 app,
349 view.rules(),
350 preflightResult.tx,
351 preflightResult.flags,
352 preflightResult.j);
353 }();
354
355 ctx.emplace(
356 app,
357 view,
358 secondFlight.ter,
359 secondFlight.tx,
360 secondFlight.flags,
361 secondFlight.parentBatchId,
362 secondFlight.j);
363 }
364 else
365 {
366 ctx.emplace(
367 app,
368 view,
369 preflightResult.ter,
370 preflightResult.tx,
371 preflightResult.flags,
372 preflightResult.parentBatchId,
373 preflightResult.j);
374 }
375
376 try
377 {
378 if (ctx->preflightResult != tesSUCCESS)
379 return {*ctx, ctx->preflightResult};
380 return {*ctx, invoke_preclaim(*ctx)};
381 }
382 catch (std::exception const& e)
383 {
384 JLOG(ctx->j.fatal()) << "apply (preclaim): " << e.what();
385 return {*ctx, tefEXCEPTION};
386 }
387}
388
389XRPAmount
390calculateBaseFee(ReadView const& view, STTx const& tx)
391{
392 return invoke_calculateBaseFee(view, tx);
393}
394
395XRPAmount
396calculateDefaultBaseFee(ReadView const& view, STTx const& tx)
397{
398 return Transactor::calculateBaseFee(view, tx);
399}
400
401ApplyResult
402doApply(PreclaimResult const& preclaimResult, Application& app, OpenView& view)
403{
404 if (preclaimResult.view.seq() != view.seq())
405 {
406 // Logic error from the caller. Don't have enough
407 // info to recover.
408 return {tefEXCEPTION, false};
409 }
410 try
411 {
412 if (!preclaimResult.likelyToClaimFee)
413 return {preclaimResult.ter, false};
414 ApplyContext ctx(
415 app,
416 view,
417 preclaimResult.parentBatchId,
418 preclaimResult.tx,
419 preclaimResult.ter,
420 calculateBaseFee(view, preclaimResult.tx),
421 preclaimResult.flags,
422 preclaimResult.j);
423 return invoke_apply(ctx);
424 }
425 catch (std::exception const& e)
426 {
427 JLOG(preclaimResult.j.fatal()) << "apply: " << e.what();
428 return {tefEXCEPTION, false};
429 }
430}
431
432} // namespace ripple
A generic endpoint for log messages.
Definition Journal.h:60
Stream fatal() const
Definition Journal.h:352
State information when applying a tx.
beast::Journal const journal
Writable ledger view that accumulates state and tx changes.
Definition OpenView.h:65
Rules const & rules() const override
Returns the tx processing rules.
Definition OpenView.cpp:150
A view into a ledger.
Definition ReadView.h:51
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition ReadView.h:118
Rules controlling protocol behavior.
Definition Rules.h:38
TxType getTxnType() const
Definition STTx.h:207
A type that represents either a sequence value or a ticket value.
Definition SeqProxy.h:56
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
Class describing the consequences to the account of applying a transaction if the transaction consume...
Definition applySteps.h:58
std::uint32_t sequencesConsumed() const
Sequences consumed.
Definition applySteps.h:134
TxConsequences(NotTEC pfresult)
std::uint32_t sequencesConsumed_
Number of sequences consumed.
Definition applySteps.h:81
XRPAmount const & potentialSpend() const
Potential Spend.
Definition applySteps.h:120
bool isBlocker_
Describes how the transaction affects subsequent transactions.
Definition applySteps.h:73
Category
Describes how the transaction affects subsequent transactions.
Definition applySteps.h:62
@ blocker
Affects the ability of subsequent transactions to claim a fee.
Definition applySteps.h:67
XRPAmount potentialSpend_
Does NOT include the fee.
Definition applySteps.h:77
T emplace(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
PreflightResult preflight(Application &app, Rules const &rules, STTx const &tx, ApplyFlags flags, beast::Journal j)
Gate a transaction based on static information.
ApplyResult doApply(PreclaimResult const &preclaimResult, Application &app, OpenView &view)
Apply a prechecked transaction to an OpenView.
TxType
Transaction type identifiers.
Definition TxFormats.h:57
XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
Compute only the expected base fee for a transaction.
static XRPAmount invoke_calculateBaseFee(ReadView const &view, STTx const &tx)
Calculates the base fee for a given transaction.
PreclaimResult preclaim(PreflightResult const &preflightResult, Application &app, OpenView const &view)
Gate a transaction based on static ledger information.
static std::pair< NotTEC, TxConsequences > invoke_preflight(PreflightContext const &ctx)
static TER invoke_preclaim(PreclaimContext const &ctx)
@ tefEXCEPTION
Definition TER.h:172
@ tesSUCCESS
Definition TER.h:244
bool isTesSuccess(TER x) noexcept
Definition TER.h:674
static ApplyResult invoke_apply(ApplyContext &ctx)
TERSubset< CanCvtToTER > TER
Definition TER.h:645
TxConsequences consequences_helper(PreflightContext const &ctx)
XRPAmount calculateDefaultBaseFee(ReadView const &view, STTx const &tx)
Return the minimum fee that an "ordinary" transaction would pay.
@ temUNKNOWN
Definition TER.h:124
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:80
Describes the results of the preclaim check.
Definition applySteps.h:209
ApplyFlags const flags
From the input - the flags.
Definition applySteps.h:218
TER const ter
Intermediate transaction result.
Definition applySteps.h:223
bool const likelyToClaimFee
Success flag - whether the transaction is likely to claim a fee.
Definition applySteps.h:227
ReadView const & view
From the input - the ledger view.
Definition applySteps.h:212
beast::Journal const j
From the input - the journal.
Definition applySteps.h:220
std::optional< uint256 const > const parentBatchId
From the input - the batch identifier, if part of a batch.
Definition applySteps.h:216
STTx const & tx
From the input - the transaction.
Definition applySteps.h:214
State information when preflighting a tx.
Definition Transactor.h:35
beast::Journal const j
Definition Transactor.h:42
Describes the results of the preflight check.
Definition applySteps.h:163
Rules const rules
From the input - the rules.
Definition applySteps.h:170
ApplyFlags const flags
From the input - the flags.
Definition applySteps.h:174
beast::Journal const j
From the input - the journal.
Definition applySteps.h:176
NotTEC const ter
Intermediate transaction result.
Definition applySteps.h:179
std::optional< uint256 const > const parentBatchId
From the input - the batch identifier, if part of a batch.
Definition applySteps.h:168
STTx const & tx
From the input - the transaction.
Definition applySteps.h:166
T what(T... args)