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/VaultClawback.h>
65#include <xrpld/app/tx/detail/VaultCreate.h>
66#include <xrpld/app/tx/detail/VaultDelete.h>
67#include <xrpld/app/tx/detail/VaultDeposit.h>
68#include <xrpld/app/tx/detail/VaultSet.h>
69#include <xrpld/app/tx/detail/VaultWithdraw.h>
70#include <xrpld/app/tx/detail/XChainBridge.h>
71
72#include <xrpl/protocol/TxFormats.h>
73
74#include <stdexcept>
75
76namespace ripple {
77
78namespace {
79
80struct UnknownTxnType : std::exception
81{
82 TxType txnType;
83 UnknownTxnType(TxType t) : txnType{t}
84 {
85 }
86};
87
88// Call a lambda with the concrete transaction type as a template parameter
89// throw an "UnknownTxnType" exception on error
90template <class F>
91auto
92with_txn_type(TxType txnType, F&& f)
93{
94 switch (txnType)
95 {
96#pragma push_macro("TRANSACTION")
97#undef TRANSACTION
98
99#define TRANSACTION(tag, value, name, delegatable, fields) \
100 case tag: \
101 return f.template operator()<name>();
102
103#include <xrpl/protocol/detail/transactions.macro>
104
105#undef TRANSACTION
106#pragma pop_macro("TRANSACTION")
107
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
230static XRPAmount
231invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
232{
233 try
234 {
235 return with_txn_type(tx.getTxnType(), [&]<typename T>() {
236 return T::calculateBaseFee(view, tx);
237 });
238 }
239 catch (UnknownTxnType const& e)
240 {
241 UNREACHABLE(
242 "ripple::invoke_calculateBaseFee : unknown transaction type");
243 return XRPAmount{0};
244 }
245}
246
247TxConsequences::TxConsequences(NotTEC pfresult)
248 : isBlocker_(false)
249 , fee_(beast::zero)
250 , potentialSpend_(beast::zero)
251 , seqProx_(SeqProxy::sequence(0))
252 , sequencesConsumed_(0)
253{
254 XRPL_ASSERT(
255 !isTesSuccess(pfresult),
256 "ripple::TxConsequences::TxConsequences : is not tesSUCCESS");
257}
258
260 : isBlocker_(false)
261 , fee_(
262 tx[sfFee].native() && !tx[sfFee].negative() ? tx[sfFee].xrp()
263 : beast::zero)
264 , potentialSpend_(beast::zero)
265 , seqProx_(tx.getSeqProxy())
266 , sequencesConsumed_(tx.getSeqProxy().isSeq() ? 1 : 0)
267{
268}
269
271 : TxConsequences(tx)
272{
273 isBlocker_ = (category == blocker);
274}
275
277 : TxConsequences(tx)
278{
280}
281
283 : TxConsequences(tx)
284{
286}
287
288static ApplyResult
290{
291 try
292 {
293 return with_txn_type(ctx.tx.getTxnType(), [&]<typename T>() {
294 T p(ctx);
295 return p();
296 });
297 }
298 catch (UnknownTxnType const& e)
299 {
300 // Should never happen
301 JLOG(ctx.journal.fatal())
302 << "Unknown transaction type in apply: " << e.txnType;
303 UNREACHABLE("ripple::invoke_apply : unknown transaction type");
304 return {temUNKNOWN, false};
305 }
306}
307
308PreflightResult
310 Application& app,
311 Rules const& rules,
312 STTx const& tx,
315{
316 PreflightContext const pfctx(app, tx, rules, flags, j);
317 try
318 {
319 return {pfctx, invoke_preflight(pfctx)};
320 }
321 catch (std::exception const& e)
322 {
323 JLOG(j.fatal()) << "apply: " << e.what();
324 return {pfctx, {tefEXCEPTION, TxConsequences{tx}}};
325 }
326}
327
328PreclaimResult
330 PreflightResult const& preflightResult,
331 Application& app,
332 OpenView const& view)
333{
335 if (preflightResult.rules != view.rules())
336 {
337 auto secondFlight = preflight(
338 app,
339 view.rules(),
340 preflightResult.tx,
341 preflightResult.flags,
342 preflightResult.j);
343 ctx.emplace(
344 app,
345 view,
346 secondFlight.ter,
347 secondFlight.tx,
348 secondFlight.flags,
349 secondFlight.j);
350 }
351 else
352 {
353 ctx.emplace(
354 app,
355 view,
356 preflightResult.ter,
357 preflightResult.tx,
358 preflightResult.flags,
359 preflightResult.j);
360 }
361 try
362 {
363 if (ctx->preflightResult != tesSUCCESS)
364 return {*ctx, ctx->preflightResult};
365 return {*ctx, invoke_preclaim(*ctx)};
366 }
367 catch (std::exception const& e)
368 {
369 JLOG(ctx->j.fatal()) << "apply: " << e.what();
370 return {*ctx, tefEXCEPTION};
371 }
372}
373
374XRPAmount
375calculateBaseFee(ReadView const& view, STTx const& tx)
376{
377 return invoke_calculateBaseFee(view, tx);
378}
379
380XRPAmount
381calculateDefaultBaseFee(ReadView const& view, STTx const& tx)
382{
383 return Transactor::calculateBaseFee(view, tx);
384}
385
386ApplyResult
387doApply(PreclaimResult const& preclaimResult, Application& app, OpenView& view)
388{
389 if (preclaimResult.view.seq() != view.seq())
390 {
391 // Logic error from the caller. Don't have enough
392 // info to recover.
393 return {tefEXCEPTION, false};
394 }
395 try
396 {
397 if (!preclaimResult.likelyToClaimFee)
398 return {preclaimResult.ter, false};
399 ApplyContext ctx(
400 app,
401 view,
402 preclaimResult.tx,
403 preclaimResult.ter,
404 calculateBaseFee(view, preclaimResult.tx),
405 preclaimResult.flags,
406 preclaimResult.j);
407 return invoke_apply(ctx);
408 }
409 catch (std::exception const& e)
410 {
411 JLOG(preclaimResult.j.fatal()) << "apply: " << e.what();
412 return {tefEXCEPTION, false};
413 }
414}
415
416} // 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:186
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:247
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
Match set account flags.
Definition: flags.h:125
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:309
ApplyResult doApply(PreclaimResult const &preclaimResult, Application &app, OpenView &view)
Apply a prechecked transaction to an OpenView.
Definition: applySteps.cpp:387
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:375
static XRPAmount invoke_calculateBaseFee(ReadView const &view, STTx const &tx)
Definition: applySteps.cpp:231
PreclaimResult preclaim(PreflightResult const &preflightResult, Application &app, OpenView const &view)
Gate a transaction based on static ledger information.
Definition: applySteps.cpp:329
static std::pair< NotTEC, TxConsequences > invoke_preflight(PreflightContext const &ctx)
Definition: applySteps.cpp:154
bool isTesSuccess(TER x)
Definition: TER.h:672
static TER invoke_preclaim(PreclaimContext const &ctx)
Definition: applySteps.cpp:177
@ tefEXCEPTION
Definition: TER.h:172
@ tesSUCCESS
Definition: TER.h:244
ApplyFlags
Definition: ApplyView.h:31
static ApplyResult invoke_apply(ApplyContext &ctx)
Definition: applySteps.cpp:289
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:381
@ 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)