xrpld
Loading...
Searching...
No Matches
apply.cpp
1#include <xrpl/tx/apply.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/base_uint.h>
5#include <xrpl/beast/utility/Journal.h>
6#include <xrpl/beast/utility/instrumentation.h>
7#include <xrpl/core/HashRouter.h>
8#include <xrpl/core/ServiceRegistry.h>
9#include <xrpl/ledger/ApplyView.h>
10#include <xrpl/ledger/OpenView.h>
11#include <xrpl/protocol/Rules.h>
12#include <xrpl/protocol/SField.h>
13#include <xrpl/protocol/STObject.h>
14#include <xrpl/protocol/STTx.h>
15#include <xrpl/protocol/TER.h>
16#include <xrpl/protocol/TxFlags.h>
17#include <xrpl/protocol/TxFormats.h>
18#include <xrpl/tx/applySteps.h>
19
20#include <exception>
21#include <string>
22#include <utility>
23
24namespace xrpl {
25
26// These are the same flags defined as HashRouterFlags::PRIVATE1-4 in
27// HashRouter.h
28constexpr HashRouterFlags kSfSigbad = HashRouterFlags::PRIVATE1; // Signature is bad
29constexpr HashRouterFlags kSfSiggood = HashRouterFlags::PRIVATE2; // Signature is good
30constexpr HashRouterFlags kSfLocalbad = HashRouterFlags::PRIVATE3; // Local checks failed
31constexpr HashRouterFlags kSfLocalgood = HashRouterFlags::PRIVATE4; // Local checks passed
32
33//------------------------------------------------------------------------------
34
36checkValidity(HashRouter& router, STTx const& tx, Rules const& rules)
37{
38 auto const id = tx.getTransactionID();
39 auto const flags = router.getFlags(id);
40
41 // Batch inner transactions are never independently valid: they are applied
42 // within their batch, not through checkValidity. Reaching here means one was
43 // relayed or submitted on its own, so mark it bad regardless of the
44 // amendment (like PeerImp and NetworkOPs).
45 if (tx.isFlag(tfInnerBatchTxn))
46 {
47 router.setFlags(id, kSfSigbad);
48 return {Validity::SigBad, "Batch inner transactions are never considered validly signed."};
49 }
50
51 if (any(flags & kSfSigbad))
52 {
53 // Signature is known bad
54 return {Validity::SigBad, "Transaction has bad signature."};
55 }
56
57 if (!any(flags & kSfSiggood))
58 {
59 auto const sigVerify = tx.checkSign(rules);
60 if (!sigVerify)
61 {
62 router.setFlags(id, kSfSigbad);
63 return {Validity::SigBad, sigVerify.error()};
64 }
65 router.setFlags(id, kSfSiggood);
66 }
67
68 // Signature is now known good
69 if (any(flags & kSfLocalbad))
70 {
71 // ...but the local checks
72 // are known bad.
73 return {Validity::SigGoodOnly, "Local checks failed."};
74 }
75
76 if (any(flags & kSfLocalgood))
77 {
78 // ...and the local checks
79 // are known good.
80 return {Validity::Valid, ""};
81 }
82
83 // Do the local checks
84 std::string reason;
85 if (!passesLocalChecks(tx, reason))
86 {
87 router.setFlags(id, kSfLocalbad);
88 return {Validity::SigGoodOnly, reason};
89 }
90 router.setFlags(id, kSfLocalgood);
91 return {Validity::Valid, ""};
92}
93
94void
95forceValidity(HashRouter& router, uint256 const& txid, Validity validity)
96{
98 switch (validity)
99 {
100 case Validity::Valid:
101 flags |= kSfLocalgood;
102 [[fallthrough]];
104 flags |= kSfSiggood;
105 [[fallthrough]];
106 case Validity::SigBad:
107 // would be silly to call directly
108 break;
109 }
110 if (any(flags))
111 router.setFlags(txid, flags);
112}
113
114template <typename PreflightChecks>
115ApplyResult
116apply(ServiceRegistry& registry, OpenView& view, PreflightChecks&& preflightChecks)
117{
118 return doApply(preclaim(preflightChecks(), registry, view), registry, view);
119}
120
121ApplyResult
122apply(ServiceRegistry& registry, OpenView& view, STTx const& tx, ApplyFlags flags, beast::Journal j)
123{
124 return apply(
125 registry, view, [&]() mutable { return preflight(registry, view.rules(), tx, flags, j); });
126}
127
128ApplyResult
130 ServiceRegistry& registry,
131 OpenView& view,
132 uint256 const& parentBatchId,
133 STTx const& tx,
134 ApplyFlags flags,
136{
137 return apply(registry, view, [&]() mutable {
138 return preflight(registry, view.rules(), parentBatchId, tx, flags, j);
139 });
140}
141
142static bool
144 ServiceRegistry& registry,
145 OpenView& batchView,
146 STTx const& batchTxn,
148{
149 XRPL_ASSERT(
150 batchTxn.getTxnType() == ttBATCH && !batchTxn.getFieldArray(sfRawTransactions).empty(),
151 "Batch transaction missing sfRawTransactions");
152
153 auto const parentBatchId = batchTxn.getTransactionID();
154 auto const mode = batchTxn.getFlags();
155
156 auto applyOneTransaction = [&registry, &j, &parentBatchId, &batchView](STTx const& tx) {
157 OpenView perTxBatchView(kBatchView, batchView);
158
159 auto const ret = apply(registry, perTxBatchView, parentBatchId, tx, TapBatch, j);
160 XRPL_ASSERT(
161 ret.applied == (isTesSuccess(ret.ter) || isTecClaim(ret.ter)),
162 "Inner transaction should not be applied");
163
164 JLOG(j.debug()) << "BatchTrace[" << parentBatchId << "]: " << tx.getTransactionID() << " "
165 << (ret.applied ? "applied" : "failure") << ": " << transToken(ret.ter);
166
167 // If the transaction should be applied push its changes to the
168 // whole-batch view.
169 // NOTE: each inner tx is individually capped at kOversizeMetaDataCap;
170 // there is no aggregate cap here. Bounded by kMaxBatchTxCount * cap,
171 // which standalone txns can already produce in one ledger.
172 if (ret.applied && (isTesSuccess(ret.ter) || isTecClaim(ret.ter)))
173 perTxBatchView.apply(batchView);
174
175 return ret;
176 };
177
178 int applied = 0;
179
180 for (auto const& stx : batchTxn.getBatchTransactions())
181 {
182 auto const result = applyOneTransaction(*stx);
183 XRPL_ASSERT(
184 result.applied == (isTesSuccess(result.ter) || isTecClaim(result.ter)),
185 "Outer Batch failure, inner transaction should not be applied");
186
187 if (result.applied)
188 ++applied;
189
190 if (!isTesSuccess(result.ter))
191 {
192 if ((mode & tfAllOrNothing) != 0u)
193 return false;
194
195 if ((mode & tfUntilFailure) != 0u)
196 break;
197 }
198 else if ((mode & tfOnlyOne) != 0u)
199 {
200 break;
201 }
202 }
203
204 return applied != 0;
205}
206
209 ServiceRegistry& registry,
210 OpenView& view,
211 STTx const& txn,
212 bool retryAssured,
213 ApplyFlags flags,
215{
216 // Returns false if the transaction has need not be retried.
217 if (retryAssured)
218 flags = flags | TapRetry;
219
220 JLOG(j.debug()) << "TXN " << txn.getTransactionID() << (retryAssured ? "/retry" : "/final");
221
222 try
223 {
224 auto const result = apply(registry, view, txn, flags, j);
225
226 if (result.applied)
227 {
228 JLOG(j.debug()) << "Transaction applied: " << transToken(result.ter);
229
230 // The batch transaction was just applied; now we need to apply
231 // its inner transactions as necessary.
232 if (isTesSuccess(result.ter) && txn.getTxnType() == ttBATCH)
233 {
234 OpenView wholeBatchView(kBatchView, view);
235
236 if (applyBatchTransactions(registry, wholeBatchView, txn, j))
237 wholeBatchView.apply(view);
238 }
239
241 }
242
243 if (isTefFailure(result.ter) || isTemMalformed(result.ter) || isTelLocal(result.ter))
244 {
245 // failure
246 JLOG(j.debug()) << "Transaction failure: " << transHuman(result.ter);
248 }
249
250 JLOG(j.debug()) << "Transaction retry: " << transHuman(result.ter);
252 }
253 catch (std::exception const& ex)
254 {
255 JLOG(j.warn()) << "Throws: " << ex.what();
257 }
258}
259
260} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:44
Stream debug() const
Definition Journal.h:344
Stream warn() const
Definition Journal.h:356
Routing table for objects identified by hash.
Definition HashRouter.h:86
HashRouterFlags getFlags(uint256 const &key)
bool setFlags(uint256 const &key, HashRouterFlags flags)
Set the flags on a hash.
Writable ledger view that accumulates state and tx changes.
Definition OpenView.h:59
void apply(TxsRawView &to) const
Apply changes.
Definition OpenView.cpp:126
Rules const & rules() const override
Returns the tx processing rules.
Definition OpenView.cpp:148
Rules controlling protocol behavior.
Definition Rules.h:40
bool empty() const
Definition STArray.h:254
STArray const & getFieldArray(SField const &field) const
Definition STObject.cpp:688
bool isFlag(std::uint32_t) const
Definition STObject.cpp:511
std::uint32_t getFlags() const
Definition STObject.cpp:517
std::expected< void, std::string > checkSign(Rules const &rules) const
Check the signature.
Definition STTx.cpp:257
TxType getTxnType() const
Definition STTx.h:226
uint256 getTransactionID() const
Definition STTx.h:238
std::vector< std::shared_ptr< STTx const > > const & getBatchTransactions() const
The inner transactions of a Batch, built and validated at construction.
Definition STTx.cpp:645
Service registry for dependency injection.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
constexpr HashRouterFlags kSfSigbad
Definition apply.cpp:28
constexpr FlagValue tfInnerBatchTxn
Definition TxFlags.h:44
PreflightResult preflight(ServiceRegistry &registry, Rules const &rules, STTx const &tx, ApplyFlags flags, beast::Journal j)
Gate a transaction based on static information.
PreclaimResult preclaim(PreflightResult const &preflightResult, ServiceRegistry &registry, OpenView const &view)
Gate a transaction based on static ledger information.
Validity
Describes the pre-processing validity of a transaction.
Definition apply.h:24
@ SigBad
Signature is bad.
Definition apply.h:28
@ Valid
Signature and local checks are good / passed.
Definition apply.h:36
@ SigGoodOnly
Signature is good, but local checks fail.
Definition apply.h:32
ApplyResult apply(ServiceRegistry &registry, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
Definition apply.cpp:122
constexpr struct xrpl::BatchViewT kBatchView
ApplyTransactionResult applyTransaction(ServiceRegistry &registry, OpenView &view, STTx const &tx, bool retryAssured, ApplyFlags flags, beast::Journal journal)
Transaction application helper.
Definition apply.cpp:208
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules)
Checks transaction signature and local checks.
Definition apply.cpp:36
constexpr HashRouterFlags kSfSiggood
Definition apply.cpp:29
ApplyTransactionResult
Enum class for return value from applyTransaction.
Definition apply.h:124
@ Success
Applied to this ledger.
Definition apply.h:128
@ Retry
Should be retried in this ledger.
Definition apply.h:136
@ Fail
Should not be retried in this ledger.
Definition apply.h:132
std::string transHuman(TER code)
Definition TER.cpp:260
std::string transToken(TER code)
Definition TER.cpp:251
bool passesLocalChecks(STTx const &tx, std::string &)
Definition STTx.cpp:847
bool isTefFailure(TER x) noexcept
Definition TER.h:664
HashRouterFlags
Definition HashRouter.h:20
static bool applyBatchTransactions(ServiceRegistry &registry, OpenView &batchView, STTx const &batchTxn, beast::Journal j)
Definition apply.cpp:143
ApplyFlags
Definition ApplyView.h:27
@ TapRetry
Definition ApplyView.h:36
@ TapBatch
Definition ApplyView.h:42
bool isTelLocal(TER x) noexcept
Definition TER.h:652
bool isTesSuccess(TER x) noexcept
Definition TER.h:676
bool isTecClaim(TER x) noexcept
Definition TER.h:683
void forceValidity(HashRouter &router, uint256 const &txid, Validity validity)
Sets the validity of a given transaction in the cache.
Definition apply.cpp:95
ApplyResult doApply(PreclaimResult const &preclaimResult, ServiceRegistry &registry, OpenView &view)
Apply a prechecked transaction to an OpenView.
constexpr HashRouterFlags kSfLocalgood
Definition apply.cpp:31
BaseUInt< 256 > uint256
Definition base_uint.h:580
bool isTemMalformed(TER x) noexcept
Definition TER.h:658
constexpr bool any(HashRouterFlags flags)
Definition HashRouter.h:71
constexpr HashRouterFlags kSfLocalbad
Definition apply.cpp:30
T what(T... args)