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/Feature.h>
12#include <xrpl/protocol/Rules.h>
13#include <xrpl/protocol/SField.h>
14#include <xrpl/protocol/STObject.h>
15#include <xrpl/protocol/STTx.h>
16#include <xrpl/protocol/TER.h>
17#include <xrpl/protocol/TxFlags.h>
18#include <xrpl/protocol/TxFormats.h>
19#include <xrpl/tx/applySteps.h>
20
21#include <exception>
22#include <string>
23#include <utility>
24
25namespace xrpl {
26
27// These are the same flags defined as HashRouterFlags::PRIVATE1-4 in
28// HashRouter.h
29constexpr HashRouterFlags kSfSigbad = HashRouterFlags::PRIVATE1; // Signature is bad
30constexpr HashRouterFlags kSfSiggood = HashRouterFlags::PRIVATE2; // Signature is good
31constexpr HashRouterFlags kSfLocalbad = HashRouterFlags::PRIVATE3; // Local checks failed
32constexpr HashRouterFlags kSfLocalgood = HashRouterFlags::PRIVATE4; // Local checks passed
33
34//------------------------------------------------------------------------------
35
37checkValidity(HashRouter& router, STTx const& tx, Rules const& rules)
38{
39 auto const id = tx.getTransactionID();
40 auto const flags = router.getFlags(id);
41
42 // Ignore signature check on batch inner transactions
43 if (tx.isFlag(tfInnerBatchTxn) && rules.enabled(featureBatch))
44 {
45 // Defensive Check: These values are also checked in Batch::preflight
46 if (tx.isFieldPresent(sfTxnSignature) || !tx.getSigningPubKey().empty() ||
47 tx.isFieldPresent(sfSigners))
48 return {Validity::SigBad, "Malformed: Invalid inner batch transaction."};
49
50 // This block should probably have never been included in the
51 // original `Batch` implementation. An inner transaction never
52 // has a valid signature.
53 bool const neverValid = rules.enabled(fixBatchInnerSigs);
54 if (!neverValid)
55 {
56 std::string reason;
57 if (!passesLocalChecks(tx, reason))
58 {
59 router.setFlags(id, kSfLocalbad);
60 return {Validity::SigGoodOnly, reason};
61 }
62
63 router.setFlags(id, kSfSiggood);
64 return {Validity::Valid, ""};
65 }
66 }
67
68 if (any(flags & kSfSigbad))
69 {
70 // Signature is known bad
71 return {Validity::SigBad, "Transaction has bad signature."};
72 }
73
74 if (!any(flags & kSfSiggood))
75 {
76 auto const sigVerify = tx.checkSign(rules);
77 if (!sigVerify)
78 {
79 router.setFlags(id, kSfSigbad);
80 return {Validity::SigBad, sigVerify.error()};
81 }
82 router.setFlags(id, kSfSiggood);
83 }
84
85 // Signature is now known good
86 if (any(flags & kSfLocalbad))
87 {
88 // ...but the local checks
89 // are known bad.
90 return {Validity::SigGoodOnly, "Local checks failed."};
91 }
92
93 if (any(flags & kSfLocalgood))
94 {
95 // ...and the local checks
96 // are known good.
97 return {Validity::Valid, ""};
98 }
99
100 // Do the local checks
101 std::string reason;
102 if (!passesLocalChecks(tx, reason))
103 {
104 router.setFlags(id, kSfLocalbad);
105 return {Validity::SigGoodOnly, reason};
106 }
107 router.setFlags(id, kSfLocalgood);
108 return {Validity::Valid, ""};
109}
110
111void
112forceValidity(HashRouter& router, uint256 const& txid, Validity validity)
113{
115 switch (validity)
116 {
117 case Validity::Valid:
118 flags |= kSfLocalgood;
119 [[fallthrough]];
121 flags |= kSfSiggood;
122 [[fallthrough]];
123 case Validity::SigBad:
124 // would be silly to call directly
125 break;
126 }
127 if (any(flags))
128 router.setFlags(txid, flags);
129}
130
131template <typename PreflightChecks>
132ApplyResult
133apply(ServiceRegistry& registry, OpenView& view, PreflightChecks&& preflightChecks)
134{
135 return doApply(preclaim(preflightChecks(), registry, view), registry, view);
136}
137
138ApplyResult
139apply(ServiceRegistry& registry, OpenView& view, STTx const& tx, ApplyFlags flags, beast::Journal j)
140{
141 return apply(
142 registry, view, [&]() mutable { return preflight(registry, view.rules(), tx, flags, j); });
143}
144
145ApplyResult
147 ServiceRegistry& registry,
148 OpenView& view,
149 uint256 const& parentBatchId,
150 STTx const& tx,
151 ApplyFlags flags,
153{
154 return apply(registry, view, [&]() mutable {
155 return preflight(registry, view.rules(), parentBatchId, tx, flags, j);
156 });
157}
158
159static bool
161 ServiceRegistry& registry,
162 OpenView& batchView,
163 STTx const& batchTxn,
165{
166 XRPL_ASSERT(
167 batchTxn.getTxnType() == ttBATCH && !batchTxn.getFieldArray(sfRawTransactions).empty(),
168 "Batch transaction missing sfRawTransactions");
169
170 auto const parentBatchId = batchTxn.getTransactionID();
171 auto const mode = batchTxn.getFlags();
172
173 auto applyOneTransaction = [&registry, &j, &parentBatchId, &batchView](STTx const& tx) {
174 OpenView perTxBatchView(kBatchView, batchView);
175
176 auto const ret = apply(registry, perTxBatchView, parentBatchId, tx, TapBatch, j);
177 XRPL_ASSERT(
178 ret.applied == (isTesSuccess(ret.ter) || isTecClaim(ret.ter)),
179 "Inner transaction should not be applied");
180
181 JLOG(j.debug()) << "BatchTrace[" << parentBatchId << "]: " << tx.getTransactionID() << " "
182 << (ret.applied ? "applied" : "failure") << ": " << transToken(ret.ter);
183
184 // If the transaction should be applied push its changes to the
185 // whole-batch view.
186 if (ret.applied && (isTesSuccess(ret.ter) || isTecClaim(ret.ter)))
187 perTxBatchView.apply(batchView);
188
189 return ret;
190 };
191
192 int applied = 0;
193
194 for (STObject rb : batchTxn.getFieldArray(sfRawTransactions))
195 {
196 auto const result = applyOneTransaction(STTx{std::move(rb)});
197 XRPL_ASSERT(
198 result.applied == (isTesSuccess(result.ter) || isTecClaim(result.ter)),
199 "Outer Batch failure, inner transaction should not be applied");
200
201 if (result.applied)
202 ++applied;
203
204 if (!isTesSuccess(result.ter))
205 {
206 if ((mode & tfAllOrNothing) != 0u)
207 return false;
208
209 if ((mode & tfUntilFailure) != 0u)
210 break;
211 }
212 else if ((mode & tfOnlyOne) != 0u)
213 {
214 break;
215 }
216 }
217
218 return applied != 0;
219}
220
223 ServiceRegistry& registry,
224 OpenView& view,
225 STTx const& txn,
226 bool retryAssured,
227 ApplyFlags flags,
229{
230 // Returns false if the transaction has need not be retried.
231 if (retryAssured)
232 flags = flags | TapRetry;
233
234 JLOG(j.debug()) << "TXN " << txn.getTransactionID() << (retryAssured ? "/retry" : "/final");
235
236 try
237 {
238 auto const result = apply(registry, view, txn, flags, j);
239
240 if (result.applied)
241 {
242 JLOG(j.debug()) << "Transaction applied: " << transToken(result.ter);
243
244 // The batch transaction was just applied; now we need to apply
245 // its inner transactions as necessary.
246 if (isTesSuccess(result.ter) && txn.getTxnType() == ttBATCH)
247 {
248 OpenView wholeBatchView(kBatchView, view);
249
250 if (applyBatchTransactions(registry, wholeBatchView, txn, j))
251 wholeBatchView.apply(view);
252 }
253
255 }
256
257 if (isTefFailure(result.ter) || isTemMalformed(result.ter) || isTelLocal(result.ter))
258 {
259 // failure
260 JLOG(j.debug()) << "Transaction failure: " << transHuman(result.ter);
262 }
263
264 JLOG(j.debug()) << "Transaction retry: " << transHuman(result.ter);
266 }
267 catch (std::exception const& ex)
268 {
269 JLOG(j.warn()) << "Throws: " << ex.what();
271 }
272}
273
274} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
Stream debug() const
Definition Journal.h:297
Stream warn() const
Definition Journal.h:309
Routing table for objects identified by hash.
Definition HashRouter.h:77
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:45
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:33
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:171
bool empty() const
Definition STArray.h:246
STArray const & getFieldArray(SField const &field) const
Definition STObject.cpp:678
bool isFlag(std::uint32_t) const
Definition STObject.cpp:501
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:454
std::uint32_t getFlags() const
Definition STObject.cpp:507
std::expected< void, std::string > checkSign(Rules const &rules) const
Check the signature.
Definition STTx.cpp:271
TxType getTxnType() const
Definition STTx.h:188
Blob getSigningPubKey() const
Definition STTx.h:194
uint256 getTransactionID() const
Definition STTx.h:200
Service registry for dependency injection.
T empty(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
constexpr HashRouterFlags kSfSigbad
Definition apply.cpp:29
constexpr FlagValue tfInnerBatchTxn
Definition TxFlags.h:43
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:19
@ SigBad
Signature is bad. Didn't do local checks.
Definition apply.h:21
@ Valid
Signature and local checks are good / passed.
Definition apply.h:25
@ SigGoodOnly
Signature is good, but local checks fail.
Definition apply.h:23
ApplyResult apply(ServiceRegistry &registry, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
Definition apply.cpp:139
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:222
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules)
Checks transaction signature and local checks.
Definition apply.cpp:37
constexpr HashRouterFlags kSfSiggood
Definition apply.cpp:30
ApplyTransactionResult
Enum class for return value from applyTransaction.
Definition apply.h:109
@ Success
Applied to this ledger.
Definition apply.h:111
@ Retry
Should be retried in this ledger.
Definition apply.h:115
@ Fail
Should not be retried in this ledger.
Definition apply.h:113
std::string transHuman(TER code)
Definition TER.cpp:256
std::string transToken(TER code)
Definition TER.cpp:247
bool isTefFailure(TER x) noexcept
Definition TER.h:651
bool passesLocalChecks(STObject const &st, std::string &)
Definition STTx.cpp:771
HashRouterFlags
Definition HashRouter.h:14
static bool applyBatchTransactions(ServiceRegistry &registry, OpenView &batchView, STTx const &batchTxn, beast::Journal j)
Definition apply.cpp:160
ApplyFlags
Definition ApplyView.h:12
@ TapRetry
Definition ApplyView.h:21
@ TapBatch
Definition ApplyView.h:27
bool isTelLocal(TER x) noexcept
Definition TER.h:639
bool isTesSuccess(TER x) noexcept
Definition TER.h:663
bool isTecClaim(TER x) noexcept
Definition TER.h:670
void forceValidity(HashRouter &router, uint256 const &txid, Validity validity)
Sets the validity of a given transaction in the cache.
Definition apply.cpp:112
ApplyResult doApply(PreclaimResult const &preclaimResult, ServiceRegistry &registry, OpenView &view)
Apply a prechecked transaction to an OpenView.
constexpr HashRouterFlags kSfLocalgood
Definition apply.cpp:32
BaseUInt< 256 > uint256
Definition base_uint.h:562
bool isTemMalformed(TER x) noexcept
Definition TER.h:645
constexpr bool any(HashRouterFlags flags)
Definition HashRouter.h:63
constexpr HashRouterFlags kSfLocalbad
Definition apply.cpp:31
T what(T... args)