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 = Transactor::invokePreflight<T>(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 // LCOV_EXCL_START
133 JLOG(ctx.j.fatal())
134 << "Unknown transaction type in preflight: " << e.txnType;
135 UNREACHABLE("ripple::invoke_preflight : unknown transaction type");
136 return {temUNKNOWN, TxConsequences{temUNKNOWN}};
137 // LCOV_EXCL_STOP
138 }
139}
140
141static TER
143{
144 try
145 {
146 // use name hiding to accomplish compile-time polymorphism of static
147 // class functions for Transactor and derived classes.
148 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
149 // If the transactor requires a valid account and the transaction
150 // doesn't list one, preflight will have already a flagged a
151 // failure.
152 auto const id = ctx.tx.getAccountID(sfAccount);
153
154 if (id != beast::zero)
155 {
156 TER result = T::checkSeqProxy(ctx.view, ctx.tx, ctx.j);
157
158 if (result != tesSUCCESS)
159 return result;
160
161 result = T::checkPriorTxAndLastLedger(ctx);
162
163 if (result != tesSUCCESS)
164 return result;
165
166 result = T::checkFee(ctx, calculateBaseFee(ctx.view, ctx.tx));
167
168 if (result != tesSUCCESS)
169 return result;
170
171 result = T::checkPermission(ctx.view, ctx.tx);
172
173 if (result != tesSUCCESS)
174 return result;
175
176 result = T::checkSign(ctx);
177
178 if (result != tesSUCCESS)
179 return result;
180 }
181
182 return T::preclaim(ctx);
183 });
184 }
185 catch (UnknownTxnType const& e)
186 {
187 // Should never happen
188 // LCOV_EXCL_START
189 JLOG(ctx.j.fatal())
190 << "Unknown transaction type in preclaim: " << e.txnType;
191 UNREACHABLE("ripple::invoke_preclaim : unknown transaction type");
192 return temUNKNOWN;
193 // LCOV_EXCL_STOP
194 }
195}
196
213static XRPAmount
214invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
215{
216 try
217 {
218 return with_txn_type(tx.getTxnType(), [&]<typename T>() {
219 return T::calculateBaseFee(view, tx);
220 });
221 }
222 catch (UnknownTxnType const& e)
223 {
224 // LCOV_EXCL_START
225 UNREACHABLE(
226 "ripple::invoke_calculateBaseFee : unknown transaction type");
227 return XRPAmount{0};
228 // LCOV_EXCL_STOP
229 }
230}
231
232TxConsequences::TxConsequences(NotTEC pfresult)
233 : isBlocker_(false)
234 , fee_(beast::zero)
235 , potentialSpend_(beast::zero)
236 , seqProx_(SeqProxy::sequence(0))
237 , sequencesConsumed_(0)
238{
239 XRPL_ASSERT(
240 !isTesSuccess(pfresult),
241 "ripple::TxConsequences::TxConsequences : is not tesSUCCESS");
242}
243
245 : isBlocker_(false)
246 , fee_(
247 tx[sfFee].native() && !tx[sfFee].negative() ? tx[sfFee].xrp()
248 : beast::zero)
249 , potentialSpend_(beast::zero)
250 , seqProx_(tx.getSeqProxy())
251 , sequencesConsumed_(tx.getSeqProxy().isSeq() ? 1 : 0)
252{
253}
254
256 : TxConsequences(tx)
257{
258 isBlocker_ = (category == blocker);
259}
260
262 : TxConsequences(tx)
263{
265}
266
272
273static ApplyResult
275{
276 try
277 {
278 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
279 T p(ctx);
280 return p();
281 });
282 }
283 catch (UnknownTxnType const& e)
284 {
285 // Should never happen
286 // LCOV_EXCL_START
287 JLOG(ctx.journal.fatal())
288 << "Unknown transaction type in apply: " << e.txnType;
289 UNREACHABLE("ripple::invoke_apply : unknown transaction type");
290 return {temUNKNOWN, false};
291 // LCOV_EXCL_STOP
292 }
293}
294
295PreflightResult
297 Application& app,
298 Rules const& rules,
299 STTx const& tx,
300 ApplyFlags flags,
302{
303 PreflightContext const pfctx(app, tx, rules, flags, j);
304 try
305 {
306 return {pfctx, invoke_preflight(pfctx)};
307 }
308 catch (std::exception const& e)
309 {
310 JLOG(j.fatal()) << "apply (preflight): " << e.what();
311 return {pfctx, {tefEXCEPTION, TxConsequences{tx}}};
312 }
313}
314
315PreflightResult
317 Application& app,
318 Rules const& rules,
319 uint256 const& parentBatchId,
320 STTx const& tx,
321 ApplyFlags flags,
323{
324 PreflightContext const pfctx(app, tx, parentBatchId, rules, flags, j);
325 try
326 {
327 return {pfctx, invoke_preflight(pfctx)};
328 }
329 catch (std::exception const& e)
330 {
331 JLOG(j.fatal()) << "apply (preflight): " << e.what();
332 return {pfctx, {tefEXCEPTION, TxConsequences{tx}}};
333 }
334}
335
336PreclaimResult
338 PreflightResult const& preflightResult,
339 Application& app,
340 OpenView const& view)
341{
343 if (preflightResult.rules != view.rules())
344 {
345 auto secondFlight = [&]() {
346 if (preflightResult.parentBatchId)
347 return preflight(
348 app,
349 view.rules(),
350 preflightResult.parentBatchId.value(),
351 preflightResult.tx,
352 preflightResult.flags,
353 preflightResult.j);
354
355 return preflight(
356 app,
357 view.rules(),
358 preflightResult.tx,
359 preflightResult.flags,
360 preflightResult.j);
361 }();
362
363 ctx.emplace(
364 app,
365 view,
366 secondFlight.ter,
367 secondFlight.tx,
368 secondFlight.flags,
369 secondFlight.parentBatchId,
370 secondFlight.j);
371 }
372 else
373 {
374 ctx.emplace(
375 app,
376 view,
377 preflightResult.ter,
378 preflightResult.tx,
379 preflightResult.flags,
380 preflightResult.parentBatchId,
381 preflightResult.j);
382 }
383
384 try
385 {
386 if (ctx->preflightResult != tesSUCCESS)
387 return {*ctx, ctx->preflightResult};
388 return {*ctx, invoke_preclaim(*ctx)};
389 }
390 catch (std::exception const& e)
391 {
392 JLOG(ctx->j.fatal()) << "apply (preclaim): " << e.what();
393 return {*ctx, tefEXCEPTION};
394 }
395}
396
397XRPAmount
398calculateBaseFee(ReadView const& view, STTx const& tx)
399{
400 return invoke_calculateBaseFee(view, tx);
401}
402
403XRPAmount
404calculateDefaultBaseFee(ReadView const& view, STTx const& tx)
405{
406 return Transactor::calculateBaseFee(view, tx);
407}
408
409ApplyResult
410doApply(PreclaimResult const& preclaimResult, Application& app, OpenView& view)
411{
412 if (preclaimResult.view.seq() != view.seq())
413 {
414 // Logic error from the caller. Don't have enough
415 // info to recover.
416 return {tefEXCEPTION, false};
417 }
418 try
419 {
420 if (!preclaimResult.likelyToClaimFee)
421 return {preclaimResult.ter, false};
422 ApplyContext ctx(
423 app,
424 view,
425 preclaimResult.parentBatchId,
426 preclaimResult.tx,
427 preclaimResult.ter,
428 calculateBaseFee(view, preclaimResult.tx),
429 preclaimResult.flags,
430 preclaimResult.j);
431 return invoke_apply(ctx);
432 }
433 catch (std::exception const& e)
434 {
435 JLOG(preclaimResult.j.fatal()) << "apply: " << e.what();
436 return {tefEXCEPTION, false};
437 }
438}
439
440} // 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:237
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)