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#include <xrpld/app/tx/detail/AMMBid.h>
22#include <xrpld/app/tx/detail/AMMClawback.h>
23#include <xrpld/app/tx/detail/AMMCreate.h>
24#include <xrpld/app/tx/detail/AMMDelete.h>
25#include <xrpld/app/tx/detail/AMMDeposit.h>
26#include <xrpld/app/tx/detail/AMMVote.h>
27#include <xrpld/app/tx/detail/AMMWithdraw.h>
28#include <xrpld/app/tx/detail/ApplyContext.h>
29#include <xrpld/app/tx/detail/Batch.h>
30#include <xrpld/app/tx/detail/CancelCheck.h>
31#include <xrpld/app/tx/detail/CancelOffer.h>
32#include <xrpld/app/tx/detail/CashCheck.h>
33#include <xrpld/app/tx/detail/Change.h>
34#include <xrpld/app/tx/detail/Clawback.h>
35#include <xrpld/app/tx/detail/CreateCheck.h>
36#include <xrpld/app/tx/detail/CreateOffer.h>
37#include <xrpld/app/tx/detail/CreateTicket.h>
38#include <xrpld/app/tx/detail/Credentials.h>
39#include <xrpld/app/tx/detail/DID.h>
40#include <xrpld/app/tx/detail/DelegateSet.h>
41#include <xrpld/app/tx/detail/DeleteAccount.h>
42#include <xrpld/app/tx/detail/DeleteOracle.h>
43#include <xrpld/app/tx/detail/DepositPreauth.h>
44#include <xrpld/app/tx/detail/Escrow.h>
45#include <xrpld/app/tx/detail/LedgerStateFix.h>
46#include <xrpld/app/tx/detail/MPTokenAuthorize.h>
47#include <xrpld/app/tx/detail/MPTokenIssuanceCreate.h>
48#include <xrpld/app/tx/detail/MPTokenIssuanceDestroy.h>
49#include <xrpld/app/tx/detail/MPTokenIssuanceSet.h>
50#include <xrpld/app/tx/detail/NFTokenAcceptOffer.h>
51#include <xrpld/app/tx/detail/NFTokenBurn.h>
52#include <xrpld/app/tx/detail/NFTokenCancelOffer.h>
53#include <xrpld/app/tx/detail/NFTokenCreateOffer.h>
54#include <xrpld/app/tx/detail/NFTokenMint.h>
55#include <xrpld/app/tx/detail/NFTokenModify.h>
56#include <xrpld/app/tx/detail/PayChan.h>
57#include <xrpld/app/tx/detail/Payment.h>
58#include <xrpld/app/tx/detail/PermissionedDomainDelete.h>
59#include <xrpld/app/tx/detail/PermissionedDomainSet.h>
60#include <xrpld/app/tx/detail/SetAccount.h>
61#include <xrpld/app/tx/detail/SetOracle.h>
62#include <xrpld/app/tx/detail/SetRegularKey.h>
63#include <xrpld/app/tx/detail/SetSignerList.h>
64#include <xrpld/app/tx/detail/SetTrust.h>
65#include <xrpld/app/tx/detail/VaultClawback.h>
66#include <xrpld/app/tx/detail/VaultCreate.h>
67#include <xrpld/app/tx/detail/VaultDelete.h>
68#include <xrpld/app/tx/detail/VaultDeposit.h>
69#include <xrpld/app/tx/detail/VaultSet.h>
70#include <xrpld/app/tx/detail/VaultWithdraw.h>
71#include <xrpld/app/tx/detail/XChainBridge.h>
72
73#include <xrpl/protocol/TxFormats.h>
74
75#include <stdexcept>
76
77namespace ripple {
78
79namespace {
80
81struct UnknownTxnType : std::exception
82{
83 TxType txnType;
84 UnknownTxnType(TxType t) : txnType{t}
85 {
86 }
87};
88
89// Call a lambda with the concrete transaction type as a template parameter
90// throw an "UnknownTxnType" exception on error
91template <class F>
92auto
93with_txn_type(TxType txnType, F&& f)
94{
95 switch (txnType)
96 {
97#pragma push_macro("TRANSACTION")
98#undef TRANSACTION
99
100#define TRANSACTION(tag, value, name, delegatable, fields) \
101 case tag: \
102 return f.template operator()<name>();
103
104#include <xrpl/protocol/detail/transactions.macro>
105
106#undef TRANSACTION
107#pragma pop_macro("TRANSACTION")
108 default:
109 throw UnknownTxnType(txnType);
110 }
111}
112} // namespace
113
114// Templates so preflight does the right thing with T::ConsequencesFactory.
115//
116// This could be done more easily using if constexpr, but Visual Studio
117// 2017 doesn't handle if constexpr correctly. So once we're no longer
118// building with Visual Studio 2017 we can consider replacing the four
119// templates with a single template function that uses if constexpr.
120//
121// For Transactor::Normal
122//
123
124// clang-format off
125// Current formatter for rippled is based on clang-10, which does not handle `requires` clauses
126template <class T>
127requires(T::ConsequencesFactory == Transactor::Normal)
128TxConsequences
130{
131 return TxConsequences(ctx.tx);
132};
133
134// For Transactor::Blocker
135template <class T>
136requires(T::ConsequencesFactory == Transactor::Blocker)
137TxConsequences
139{
141};
142
143// For Transactor::Custom
144template <class T>
145requires(T::ConsequencesFactory == Transactor::Custom)
146TxConsequences
148{
149 return T::makeTxConsequences(ctx);
150};
151// clang-format on
152
155{
156 try
157 {
158 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
159 auto const tec = T::preflight(ctx);
160 return std::make_pair(
161 tec,
162 isTesSuccess(tec) ? consequences_helper<T>(ctx)
163 : TxConsequences{tec});
164 });
165 }
166 catch (UnknownTxnType const& e)
167 {
168 // Should never happen
169 JLOG(ctx.j.fatal())
170 << "Unknown transaction type in preflight: " << e.txnType;
171 UNREACHABLE("ripple::invoke_preflight : unknown transaction type");
172 return {temUNKNOWN, TxConsequences{temUNKNOWN}};
173 }
174}
175
176static TER
178{
179 try
180 {
181 // use name hiding to accomplish compile-time polymorphism of static
182 // class functions for Transactor and derived classes.
183 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
184 // If the transactor requires a valid account and the transaction
185 // doesn't list one, preflight will have already a flagged a
186 // failure.
187 auto const id = ctx.tx.getAccountID(sfAccount);
188
189 if (id != beast::zero)
190 {
191 TER result = T::checkSeqProxy(ctx.view, ctx.tx, ctx.j);
192
193 if (result != tesSUCCESS)
194 return result;
195
196 result = T::checkPriorTxAndLastLedger(ctx);
197
198 if (result != tesSUCCESS)
199 return result;
200
201 result = T::checkFee(ctx, calculateBaseFee(ctx.view, ctx.tx));
202
203 if (result != tesSUCCESS)
204 return result;
205
206 result = T::checkPermission(ctx.view, ctx.tx);
207
208 if (result != tesSUCCESS)
209 return result;
210
211 result = T::checkSign(ctx);
212
213 if (result != tesSUCCESS)
214 return result;
215 }
216
217 return T::preclaim(ctx);
218 });
219 }
220 catch (UnknownTxnType const& e)
221 {
222 // Should never happen
223 JLOG(ctx.j.fatal())
224 << "Unknown transaction type in preclaim: " << e.txnType;
225 UNREACHABLE("ripple::invoke_preclaim : unknown transaction type");
226 return temUNKNOWN;
227 }
228}
229
246static XRPAmount
247invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
248{
249 try
250 {
251 return with_txn_type(tx.getTxnType(), [&]<typename T>() {
252 return T::calculateBaseFee(view, tx);
253 });
254 }
255 catch (UnknownTxnType const& e)
256 {
257 UNREACHABLE(
258 "ripple::invoke_calculateBaseFee : unknown transaction type");
259 return XRPAmount{0};
260 }
261}
262
263TxConsequences::TxConsequences(NotTEC pfresult)
264 : isBlocker_(false)
265 , fee_(beast::zero)
266 , potentialSpend_(beast::zero)
267 , seqProx_(SeqProxy::sequence(0))
268 , sequencesConsumed_(0)
269{
270 XRPL_ASSERT(
271 !isTesSuccess(pfresult),
272 "ripple::TxConsequences::TxConsequences : is not tesSUCCESS");
273}
274
276 : isBlocker_(false)
277 , fee_(
278 tx[sfFee].native() && !tx[sfFee].negative() ? tx[sfFee].xrp()
279 : beast::zero)
280 , potentialSpend_(beast::zero)
281 , seqProx_(tx.getSeqProxy())
282 , sequencesConsumed_(tx.getSeqProxy().isSeq() ? 1 : 0)
283{
284}
285
287 : TxConsequences(tx)
288{
289 isBlocker_ = (category == blocker);
290}
291
293 : TxConsequences(tx)
294{
296}
297
299 : TxConsequences(tx)
300{
302}
303
304static ApplyResult
306{
307 try
308 {
309 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
310 T p(ctx);
311 return p();
312 });
313 }
314 catch (UnknownTxnType const& e)
315 {
316 // Should never happen
317 JLOG(ctx.journal.fatal())
318 << "Unknown transaction type in apply: " << e.txnType;
319 UNREACHABLE("ripple::invoke_apply : unknown transaction type");
320 return {temUNKNOWN, false};
321 }
322}
323
324PreflightResult
326 Application& app,
327 Rules const& rules,
328 STTx const& tx,
329 ApplyFlags flags,
331{
332 PreflightContext const pfctx(app, tx, 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
344PreflightResult
346 Application& app,
347 Rules const& rules,
348 uint256 const& parentBatchId,
349 STTx const& tx,
350 ApplyFlags flags,
352{
353 PreflightContext const pfctx(app, tx, parentBatchId, rules, flags, j);
354 try
355 {
356 return {pfctx, invoke_preflight(pfctx)};
357 }
358 catch (std::exception const& e)
359 {
360 JLOG(j.fatal()) << "apply (preflight): " << e.what();
361 return {pfctx, {tefEXCEPTION, TxConsequences{tx}}};
362 }
363}
364
365PreclaimResult
367 PreflightResult const& preflightResult,
368 Application& app,
369 OpenView const& view)
370{
372 if (preflightResult.rules != view.rules())
373 {
374 auto secondFlight = [&]() {
375 if (preflightResult.parentBatchId)
376 return preflight(
377 app,
378 view.rules(),
379 preflightResult.parentBatchId.value(),
380 preflightResult.tx,
381 preflightResult.flags,
382 preflightResult.j);
383
384 return preflight(
385 app,
386 view.rules(),
387 preflightResult.tx,
388 preflightResult.flags,
389 preflightResult.j);
390 }();
391
392 ctx.emplace(
393 app,
394 view,
395 secondFlight.ter,
396 secondFlight.tx,
397 secondFlight.flags,
398 secondFlight.parentBatchId,
399 secondFlight.j);
400 }
401 else
402 {
403 ctx.emplace(
404 app,
405 view,
406 preflightResult.ter,
407 preflightResult.tx,
408 preflightResult.flags,
409 preflightResult.parentBatchId,
410 preflightResult.j);
411 }
412
413 try
414 {
415 if (ctx->preflightResult != tesSUCCESS)
416 return {*ctx, ctx->preflightResult};
417 return {*ctx, invoke_preclaim(*ctx)};
418 }
419 catch (std::exception const& e)
420 {
421 JLOG(ctx->j.fatal()) << "apply (preclaim): " << e.what();
422 return {*ctx, tefEXCEPTION};
423 }
424}
425
426XRPAmount
427calculateBaseFee(ReadView const& view, STTx const& tx)
428{
429 return invoke_calculateBaseFee(view, tx);
430}
431
432XRPAmount
433calculateDefaultBaseFee(ReadView const& view, STTx const& tx)
434{
435 return Transactor::calculateBaseFee(view, tx);
436}
437
438ApplyResult
439doApply(PreclaimResult const& preclaimResult, Application& app, OpenView& view)
440{
441 if (preclaimResult.view.seq() != view.seq())
442 {
443 // Logic error from the caller. Don't have enough
444 // info to recover.
445 return {tefEXCEPTION, false};
446 }
447 try
448 {
449 if (!preclaimResult.likelyToClaimFee)
450 return {preclaimResult.ter, false};
451 ApplyContext ctx(
452 app,
453 view,
454 preclaimResult.parentBatchId,
455 preclaimResult.tx,
456 preclaimResult.ter,
457 calculateBaseFee(view, preclaimResult.tx),
458 preclaimResult.flags,
459 preclaimResult.j);
460 return invoke_apply(ctx);
461 }
462 catch (std::exception const& e)
463 {
464 JLOG(preclaimResult.j.fatal()) << "apply: " << e.what();
465 return {tefEXCEPTION, false};
466 }
467}
468
469} // 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.
Definition: ApplyContext.h:37
beast::Journal const journal
Definition: ApplyContext.h:75
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:66
Rules const & rules() const override
Returns the tx processing rules.
Definition: OpenView.cpp:151
A view into a ledger.
Definition: ReadView.h:52
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition: ReadView.h:119
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)
Definition: Transactor.cpp:224
Class describing the consequences to the account of applying a transaction if the transaction consume...
Definition: applySteps.h:59
std::uint32_t sequencesConsumed() const
Sequences consumed.
Definition: applySteps.h:135
TxConsequences(NotTEC pfresult)
Definition: applySteps.cpp:263
std::uint32_t sequencesConsumed_
Number of sequences consumed.
Definition: applySteps.h:82
XRPAmount const & potentialSpend() const
Potential Spend.
Definition: applySteps.h:121
bool isBlocker_
Describes how the transaction affects subsequent transactions.
Definition: applySteps.h:74
Category
Describes how the transaction affects subsequent transactions.
Definition: applySteps.h:63
@ blocker
Affects the ability of subsequent transactions to claim a fee.
Definition: applySteps.h:68
XRPAmount potentialSpend_
Does NOT include the fee.
Definition: applySteps.h:78
T emplace(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
PreflightResult preflight(Application &app, Rules const &rules, STTx const &tx, ApplyFlags flags, beast::Journal j)
Gate a transaction based on static information.
Definition: applySteps.cpp:325
ApplyResult doApply(PreclaimResult const &preclaimResult, Application &app, OpenView &view)
Apply a prechecked transaction to an OpenView.
Definition: applySteps.cpp:439
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.
Definition: applySteps.cpp:427
static XRPAmount invoke_calculateBaseFee(ReadView const &view, STTx const &tx)
Calculates the base fee for a given transaction.
Definition: applySteps.cpp:247
PreclaimResult preclaim(PreflightResult const &preflightResult, Application &app, OpenView const &view)
Gate a transaction based on static ledger information.
Definition: applySteps.cpp:366
static std::pair< NotTEC, TxConsequences > invoke_preflight(PreflightContext const &ctx)
Definition: applySteps.cpp:154
static TER invoke_preclaim(PreclaimContext const &ctx)
Definition: applySteps.cpp:177
@ tefEXCEPTION
Definition: TER.h:172
@ tesSUCCESS
Definition: TER.h:244
bool isTesSuccess(TER x) noexcept
Definition: TER.h:672
ApplyFlags
Definition: ApplyView.h:31
static ApplyResult invoke_apply(ApplyContext &ctx)
Definition: applySteps.cpp:305
TERSubset< CanCvtToTER > TER
Definition: TER.h:643
TxConsequences consequences_helper(PreflightContext const &ctx)
Definition: applySteps.cpp:129
XRPAmount calculateDefaultBaseFee(ReadView const &view, STTx const &tx)
Return the minimum fee that an "ordinary" transaction would pay.
Definition: applySteps.cpp:433
@ temUNKNOWN
Definition: TER.h:124
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:79
Describes the results of the preclaim check.
Definition: applySteps.h:210
ApplyFlags const flags
From the input - the flags.
Definition: applySteps.h:219
TER const ter
Intermediate transaction result.
Definition: applySteps.h:224
bool const likelyToClaimFee
Success flag - whether the transaction is likely to claim a fee.
Definition: applySteps.h:228
ReadView const & view
From the input - the ledger view.
Definition: applySteps.h:213
beast::Journal const j
From the input - the journal.
Definition: applySteps.h:221
std::optional< uint256 const > const parentBatchId
From the input - the batch identifier, if part of a batch.
Definition: applySteps.h:217
STTx const & tx
From the input - the transaction.
Definition: applySteps.h:215
State information when preflighting a tx.
Definition: Transactor.h:34
beast::Journal const j
Definition: Transactor.h:41
Describes the results of the preflight check.
Definition: applySteps.h:164
Rules const rules
From the input - the rules.
Definition: applySteps.h:171
ApplyFlags const flags
From the input - the flags.
Definition: applySteps.h:175
beast::Journal const j
From the input - the journal.
Definition: applySteps.h:177
NotTEC const ter
Intermediate transaction result.
Definition: applySteps.h:180
std::optional< uint256 const > const parentBatchId
From the input - the batch identifier, if part of a batch.
Definition: applySteps.h:169
STTx const & tx
From the input - the transaction.
Definition: applySteps.h:167
T what(T... args)