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