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/CancelCheck.h>
30#include <xrpld/app/tx/detail/CancelOffer.h>
31#include <xrpld/app/tx/detail/CashCheck.h>
32#include <xrpld/app/tx/detail/Change.h>
33#include <xrpld/app/tx/detail/Clawback.h>
34#include <xrpld/app/tx/detail/CreateCheck.h>
35#include <xrpld/app/tx/detail/CreateOffer.h>
36#include <xrpld/app/tx/detail/CreateTicket.h>
37#include <xrpld/app/tx/detail/Credentials.h>
38#include <xrpld/app/tx/detail/DID.h>
39#include <xrpld/app/tx/detail/DeleteAccount.h>
40#include <xrpld/app/tx/detail/DeleteOracle.h>
41#include <xrpld/app/tx/detail/DepositPreauth.h>
42#include <xrpld/app/tx/detail/Escrow.h>
43#include <xrpld/app/tx/detail/LedgerStateFix.h>
44#include <xrpld/app/tx/detail/MPTokenAuthorize.h>
45#include <xrpld/app/tx/detail/MPTokenIssuanceCreate.h>
46#include <xrpld/app/tx/detail/MPTokenIssuanceDestroy.h>
47#include <xrpld/app/tx/detail/MPTokenIssuanceSet.h>
48#include <xrpld/app/tx/detail/NFTokenAcceptOffer.h>
49#include <xrpld/app/tx/detail/NFTokenBurn.h>
50#include <xrpld/app/tx/detail/NFTokenCancelOffer.h>
51#include <xrpld/app/tx/detail/NFTokenCreateOffer.h>
52#include <xrpld/app/tx/detail/NFTokenMint.h>
53#include <xrpld/app/tx/detail/NFTokenModify.h>
54#include <xrpld/app/tx/detail/PayChan.h>
55#include <xrpld/app/tx/detail/Payment.h>
56#include <xrpld/app/tx/detail/PermissionedDomainDelete.h>
57#include <xrpld/app/tx/detail/PermissionedDomainSet.h>
58#include <xrpld/app/tx/detail/SetAccount.h>
59#include <xrpld/app/tx/detail/SetOracle.h>
60#include <xrpld/app/tx/detail/SetRegularKey.h>
61#include <xrpld/app/tx/detail/SetSignerList.h>
62#include <xrpld/app/tx/detail/SetTrust.h>
63#include <xrpld/app/tx/detail/XChainBridge.h>
64#include <xrpl/protocol/TxFormats.h>
65
66#include <stdexcept>
67
68namespace ripple {
69
70namespace {
71
72struct UnknownTxnType : std::exception
73{
74 TxType txnType;
75 UnknownTxnType(TxType t) : txnType{t}
76 {
77 }
78};
79
80// Call a lambda with the concrete transaction type as a template parameter
81// throw an "UnknownTxnType" exception on error
82template <class F>
83auto
84with_txn_type(TxType txnType, F&& f)
85{
86 switch (txnType)
87 {
88#pragma push_macro("TRANSACTION")
89#undef TRANSACTION
90
91#define TRANSACTION(tag, value, name, fields) \
92 case tag: \
93 return f.template operator()<name>();
94
95#include <xrpl/protocol/detail/transactions.macro>
96
97#undef TRANSACTION
98#pragma pop_macro("TRANSACTION")
99
100 default:
101 throw UnknownTxnType(txnType);
102 }
103}
104} // namespace
105
106// Templates so preflight does the right thing with T::ConsequencesFactory.
107//
108// This could be done more easily using if constexpr, but Visual Studio
109// 2017 doesn't handle if constexpr correctly. So once we're no longer
110// building with Visual Studio 2017 we can consider replacing the four
111// templates with a single template function that uses if constexpr.
112//
113// For Transactor::Normal
114//
115
116// clang-format off
117// Current formatter for rippled is based on clang-10, which does not handle `requires` clauses
118template <class T>
119requires(T::ConsequencesFactory == Transactor::Normal)
120TxConsequences
122{
123 return TxConsequences(ctx.tx);
124};
125
126// For Transactor::Blocker
127template <class T>
128requires(T::ConsequencesFactory == Transactor::Blocker)
129TxConsequences
131{
133};
134
135// For Transactor::Custom
136template <class T>
137requires(T::ConsequencesFactory == Transactor::Custom)
138TxConsequences
140{
141 return T::makeTxConsequences(ctx);
142};
143// clang-format on
144
147{
148 try
149 {
150 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
151 auto const tec = T::preflight(ctx);
152 return std::make_pair(
153 tec,
154 isTesSuccess(tec) ? consequences_helper<T>(ctx)
155 : TxConsequences{tec});
156 });
157 }
158 catch (UnknownTxnType const& e)
159 {
160 // Should never happen
161 JLOG(ctx.j.fatal())
162 << "Unknown transaction type in preflight: " << e.txnType;
163 UNREACHABLE("ripple::invoke_preflight : unknown transaction type");
164 return {temUNKNOWN, TxConsequences{temUNKNOWN}};
165 }
166}
167
168static TER
170{
171 try
172 {
173 // use name hiding to accomplish compile-time polymorphism of static
174 // class functions for Transactor and derived classes.
175 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
176 // If the transactor requires a valid account and the transaction
177 // doesn't list one, preflight will have already a flagged a
178 // failure.
179 auto const id = ctx.tx.getAccountID(sfAccount);
180
181 if (id != beast::zero)
182 {
183 TER result = T::checkSeqProxy(ctx.view, ctx.tx, ctx.j);
184
185 if (result != tesSUCCESS)
186 return result;
187
188 result = T::checkPriorTxAndLastLedger(ctx);
189
190 if (result != tesSUCCESS)
191 return result;
192
193 result = T::checkFee(ctx, calculateBaseFee(ctx.view, ctx.tx));
194
195 if (result != tesSUCCESS)
196 return result;
197
198 result = T::checkSign(ctx);
199
200 if (result != tesSUCCESS)
201 return result;
202 }
203
204 return T::preclaim(ctx);
205 });
206 }
207 catch (UnknownTxnType const& e)
208 {
209 // Should never happen
210 JLOG(ctx.j.fatal())
211 << "Unknown transaction type in preclaim: " << e.txnType;
212 UNREACHABLE("ripple::invoke_preclaim : unknown transaction type");
213 return temUNKNOWN;
214 }
215}
216
217static XRPAmount
218invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
219{
220 try
221 {
222 return with_txn_type(tx.getTxnType(), [&]<typename T>() {
223 return T::calculateBaseFee(view, tx);
224 });
225 }
226 catch (UnknownTxnType const& e)
227 {
228 UNREACHABLE(
229 "ripple::invoke_calculateBaseFee : unknown transaction type");
230 return XRPAmount{0};
231 }
232}
233
234TxConsequences::TxConsequences(NotTEC pfresult)
235 : isBlocker_(false)
236 , fee_(beast::zero)
237 , potentialSpend_(beast::zero)
238 , seqProx_(SeqProxy::sequence(0))
239 , sequencesConsumed_(0)
240{
241 XRPL_ASSERT(
242 !isTesSuccess(pfresult),
243 "ripple::TxConsequences::TxConsequences : is not tesSUCCESS");
244}
245
247 : isBlocker_(false)
248 , fee_(
249 tx[sfFee].native() && !tx[sfFee].negative() ? tx[sfFee].xrp()
250 : beast::zero)
251 , potentialSpend_(beast::zero)
252 , seqProx_(tx.getSeqProxy())
253 , sequencesConsumed_(tx.getSeqProxy().isSeq() ? 1 : 0)
254{
255}
256
258 : TxConsequences(tx)
259{
260 isBlocker_ = (category == blocker);
261}
262
264 : TxConsequences(tx)
265{
267}
268
270 : TxConsequences(tx)
271{
273}
274
275static ApplyResult
277{
278 try
279 {
280 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
281 T p(ctx);
282 return p();
283 });
284 }
285 catch (UnknownTxnType const& e)
286 {
287 // Should never happen
288 JLOG(ctx.journal.fatal())
289 << "Unknown transaction type in apply: " << e.txnType;
290 UNREACHABLE("ripple::invoke_apply : unknown transaction type");
291 return {temUNKNOWN, false};
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: " << e.what();
311 return {pfctx, {tefEXCEPTION, TxConsequences{tx}}};
312 }
313}
314
315PreclaimResult
317 PreflightResult const& preflightResult,
318 Application& app,
319 OpenView const& view)
320{
322 if (preflightResult.rules != view.rules())
323 {
324 auto secondFlight = preflight(
325 app,
326 view.rules(),
327 preflightResult.tx,
328 preflightResult.flags,
329 preflightResult.j);
330 ctx.emplace(
331 app,
332 view,
333 secondFlight.ter,
334 secondFlight.tx,
335 secondFlight.flags,
336 secondFlight.j);
337 }
338 else
339 {
340 ctx.emplace(
341 app,
342 view,
343 preflightResult.ter,
344 preflightResult.tx,
345 preflightResult.flags,
346 preflightResult.j);
347 }
348 try
349 {
350 if (ctx->preflightResult != tesSUCCESS)
351 return {*ctx, ctx->preflightResult};
352 return {*ctx, invoke_preclaim(*ctx)};
353 }
354 catch (std::exception const& e)
355 {
356 JLOG(ctx->j.fatal()) << "apply: " << e.what();
357 return {*ctx, tefEXCEPTION};
358 }
359}
360
361XRPAmount
362calculateBaseFee(ReadView const& view, STTx const& tx)
363{
364 return invoke_calculateBaseFee(view, tx);
365}
366
367XRPAmount
368calculateDefaultBaseFee(ReadView const& view, STTx const& tx)
369{
370 return Transactor::calculateBaseFee(view, tx);
371}
372
373ApplyResult
374doApply(PreclaimResult const& preclaimResult, Application& app, OpenView& view)
375{
376 if (preclaimResult.view.seq() != view.seq())
377 {
378 // Logic error from the caller. Don't have enough
379 // info to recover.
380 return {tefEXCEPTION, false};
381 }
382 try
383 {
384 if (!preclaimResult.likelyToClaimFee)
385 return {preclaimResult.ter, false};
386 ApplyContext ctx(
387 app,
388 view,
389 preclaimResult.tx,
390 preclaimResult.ter,
391 calculateBaseFee(view, preclaimResult.tx),
392 preclaimResult.flags,
393 preclaimResult.j);
394 return invoke_apply(ctx);
395 }
396 catch (std::exception const& e)
397 {
398 JLOG(preclaimResult.j.fatal()) << "apply: " << e.what();
399 return {tefEXCEPTION, false};
400 }
401}
402
403} // namespace ripple
A generic endpoint for log messages.
Definition: Journal.h:59
Stream fatal() const
Definition: Journal.h:351
State information when applying a tx.
Definition: ApplyContext.h:36
beast::Journal const journal
Definition: ApplyContext.h:51
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:56
Rules const & rules() const override
Returns the tx processing rules.
Definition: OpenView.cpp:152
A view into a ledger.
Definition: ReadView.h:55
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition: ReadView.h:122
Rules controlling protocol behavior.
Definition: Rules.h:35
TxType getTxnType() const
Definition: STTx.h:181
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:194
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)
Definition: applySteps.cpp:234
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: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:296
ApplyResult doApply(PreclaimResult const &preclaimResult, Application &app, OpenView &view)
Apply a prechecked transaction to an OpenView.
Definition: applySteps.cpp:374
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:362
static XRPAmount invoke_calculateBaseFee(ReadView const &view, STTx const &tx)
Definition: applySteps.cpp:218
PreclaimResult preclaim(PreflightResult const &preflightResult, Application &app, OpenView const &view)
Gate a transaction based on static ledger information.
Definition: applySteps.cpp:316
static std::pair< NotTEC, TxConsequences > invoke_preflight(PreflightContext const &ctx)
Definition: applySteps.cpp:146
bool isTesSuccess(TER x)
Definition: TER.h:656
static TER invoke_preclaim(PreclaimContext const &ctx)
Definition: applySteps.cpp:169
@ tefEXCEPTION
Definition: TER.h:172
@ tesSUCCESS
Definition: TER.h:242
ApplyFlags
Definition: ApplyView.h:30
static ApplyResult invoke_apply(ApplyContext &ctx)
Definition: applySteps.cpp:276
TERSubset< CanCvtToTER > TER
Definition: TER.h:627
TxConsequences consequences_helper(PreflightContext const &ctx)
Definition: applySteps.cpp:121
XRPAmount calculateDefaultBaseFee(ReadView const &view, STTx const &tx)
Return the minimum fee that an "ordinary" transaction would pay.
Definition: applySteps.cpp:368
@ temUNKNOWN
Definition: TER.h:124
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:53
Describes the results of the preclaim check.
Definition: applySteps.h:206
ApplyFlags const flags
From the input - the flags.
Definition: applySteps.h:213
TER const ter
Intermediate transaction result.
Definition: applySteps.h:218
bool const likelyToClaimFee
Success flag - whether the transaction is likely to claim a fee.
Definition: applySteps.h:221
ReadView const & view
From the input - the ledger view.
Definition: applySteps.h:209
beast::Journal const j
From the input - the journal.
Definition: applySteps.h:215
STTx const & tx
From the input - the transaction.
Definition: applySteps.h:211
State information when preflighting a tx.
Definition: Transactor.h:32
beast::Journal const j
Definition: Transactor.h:38
Describes the results of the preflight check.
Definition: applySteps.h:163
Rules const rules
From the input - the rules.
Definition: applySteps.h:168
ApplyFlags const flags
From the input - the flags.
Definition: applySteps.h:172
beast::Journal const j
From the input - the journal.
Definition: applySteps.h:174
NotTEC const ter
Intermediate transaction result.
Definition: applySteps.h:177
STTx const & tx
From the input - the transaction.
Definition: applySteps.h:166
T what(T... args)