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