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>() -> TER {
149 // preclaim functionality is divided into two sections:
150 // 1. Up to and including the signature check: returns NotTEC.
151 // All transaction checks before and including checkSign
152 // MUST return NotTEC, or something more restrictive.
153 // Allowing tec results in these steps risks theft or
154 // destruction of funds, as a fee will be charged before the
155 // signature is checked.
156 // 2. After the signature check: returns TER.
157
158 // If the transactor requires a valid account and the
159 // transaction doesn't list one, preflight will have already
160 // a flagged a failure.
161 auto const id = ctx.tx.getAccountID(sfAccount);
162
163 if (id != beast::zero)
164 {
165 if (NotTEC const preSigResult = [&]() -> NotTEC {
166 if (NotTEC const result =
167 T::checkSeqProxy(ctx.view, ctx.tx, ctx.j))
168 return result;
169
170 if (NotTEC const result =
171 T::checkPriorTxAndLastLedger(ctx))
172 return result;
173
174 if (NotTEC const result =
175 T::checkPermission(ctx.view, ctx.tx))
176 return result;
177
178 if (NotTEC const result = T::checkSign(ctx))
179 return result;
180
181 return tesSUCCESS;
182 }())
183 return preSigResult;
184
185 if (TER const result =
186 T::checkFee(ctx, calculateBaseFee(ctx.view, ctx.tx)))
187 return result;
188 }
189
190 return T::preclaim(ctx);
191 });
192 }
193 catch (UnknownTxnType const& e)
194 {
195 // Should never happen
196 // LCOV_EXCL_START
197 JLOG(ctx.j.fatal())
198 << "Unknown transaction type in preclaim: " << e.txnType;
199 UNREACHABLE("ripple::invoke_preclaim : unknown transaction type");
200 return temUNKNOWN;
201 // LCOV_EXCL_STOP
202 }
203}
204
221static XRPAmount
222invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
223{
224 try
225 {
226 return with_txn_type(tx.getTxnType(), [&]<typename T>() {
227 return T::calculateBaseFee(view, tx);
228 });
229 }
230 catch (UnknownTxnType const& e)
231 {
232 // LCOV_EXCL_START
233 UNREACHABLE(
234 "ripple::invoke_calculateBaseFee : unknown transaction type");
235 return XRPAmount{0};
236 // LCOV_EXCL_STOP
237 }
238}
239
240TxConsequences::TxConsequences(NotTEC pfresult)
241 : isBlocker_(false)
242 , fee_(beast::zero)
243 , potentialSpend_(beast::zero)
244 , seqProx_(SeqProxy::sequence(0))
245 , sequencesConsumed_(0)
246{
247 XRPL_ASSERT(
248 !isTesSuccess(pfresult),
249 "ripple::TxConsequences::TxConsequences : is not tesSUCCESS");
250}
251
253 : isBlocker_(false)
254 , fee_(
255 tx[sfFee].native() && !tx[sfFee].negative() ? tx[sfFee].xrp()
256 : beast::zero)
257 , potentialSpend_(beast::zero)
258 , seqProx_(tx.getSeqProxy())
259 , sequencesConsumed_(tx.getSeqProxy().isSeq() ? 1 : 0)
260{
261}
262
264 : TxConsequences(tx)
265{
266 isBlocker_ = (category == blocker);
267}
268
270 : TxConsequences(tx)
271{
273}
274
280
281static ApplyResult
283{
284 try
285 {
286 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
287 T p(ctx);
288 return p();
289 });
290 }
291 catch (UnknownTxnType const& e)
292 {
293 // Should never happen
294 // LCOV_EXCL_START
295 JLOG(ctx.journal.fatal())
296 << "Unknown transaction type in apply: " << e.txnType;
297 UNREACHABLE("ripple::invoke_apply : unknown transaction type");
298 return {temUNKNOWN, false};
299 // LCOV_EXCL_STOP
300 }
301}
302
303PreflightResult
305 Application& app,
306 Rules const& rules,
307 STTx const& tx,
308 ApplyFlags flags,
310{
311 PreflightContext const pfctx(app, tx, rules, flags, j);
312 try
313 {
314 return {pfctx, invoke_preflight(pfctx)};
315 }
316 catch (std::exception const& e)
317 {
318 JLOG(j.fatal()) << "apply (preflight): " << e.what();
319 return {pfctx, {tefEXCEPTION, TxConsequences{tx}}};
320 }
321}
322
323PreflightResult
325 Application& app,
326 Rules const& rules,
327 uint256 const& parentBatchId,
328 STTx const& tx,
329 ApplyFlags flags,
331{
332 PreflightContext const pfctx(app, tx, parentBatchId, rules, flags, j);
333 try
334 {
335 return {pfctx, invoke_preflight(pfctx)};
336 }
337 catch (std::exception const& e)
338 {
339 JLOG(j.fatal()) << "apply (preflight): " << e.what();
340 return {pfctx, {tefEXCEPTION, TxConsequences{tx}}};
341 }
342}
343
344PreclaimResult
346 PreflightResult const& preflightResult,
347 Application& app,
348 OpenView const& view)
349{
351 if (preflightResult.rules != view.rules())
352 {
353 auto secondFlight = [&]() {
354 if (preflightResult.parentBatchId)
355 return preflight(
356 app,
357 view.rules(),
358 preflightResult.parentBatchId.value(),
359 preflightResult.tx,
360 preflightResult.flags,
361 preflightResult.j);
362
363 return preflight(
364 app,
365 view.rules(),
366 preflightResult.tx,
367 preflightResult.flags,
368 preflightResult.j);
369 }();
370
371 ctx.emplace(
372 app,
373 view,
374 secondFlight.ter,
375 secondFlight.tx,
376 secondFlight.flags,
377 secondFlight.parentBatchId,
378 secondFlight.j);
379 }
380 else
381 {
382 ctx.emplace(
383 app,
384 view,
385 preflightResult.ter,
386 preflightResult.tx,
387 preflightResult.flags,
388 preflightResult.parentBatchId,
389 preflightResult.j);
390 }
391
392 try
393 {
394 if (ctx->preflightResult != tesSUCCESS)
395 return {*ctx, ctx->preflightResult};
396 return {*ctx, invoke_preclaim(*ctx)};
397 }
398 catch (std::exception const& e)
399 {
400 JLOG(ctx->j.fatal()) << "apply (preclaim): " << e.what();
401 return {*ctx, tefEXCEPTION};
402 }
403}
404
405XRPAmount
406calculateBaseFee(ReadView const& view, STTx const& tx)
407{
408 return invoke_calculateBaseFee(view, tx);
409}
410
411XRPAmount
412calculateDefaultBaseFee(ReadView const& view, STTx const& tx)
413{
414 return Transactor::calculateBaseFee(view, tx);
415}
416
417ApplyResult
418doApply(PreclaimResult const& preclaimResult, Application& app, OpenView& view)
419{
420 if (preclaimResult.view.seq() != view.seq())
421 {
422 // Logic error from the caller. Don't have enough
423 // info to recover.
424 return {tefEXCEPTION, false};
425 }
426 try
427 {
428 if (!preclaimResult.likelyToClaimFee)
429 return {preclaimResult.ter, false};
430 ApplyContext ctx(
431 app,
432 view,
433 preclaimResult.parentBatchId,
434 preclaimResult.tx,
435 preclaimResult.ter,
436 calculateBaseFee(view, preclaimResult.tx),
437 preclaimResult.flags,
438 preclaimResult.j);
439 return invoke_apply(ctx);
440 }
441 catch (std::exception const& e)
442 {
443 JLOG(preclaimResult.j.fatal()) << "apply: " << e.what();
444 return {tefEXCEPTION, false};
445 }
446}
447
448} // 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:245
bool isTesSuccess(TER x) noexcept
Definition TER.h:678
static ApplyResult invoke_apply(ApplyContext &ctx)
TERSubset< CanCvtToTER > TER
Definition TER.h:649
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)