rippled
Loading...
Searching...
No Matches
ApplyContext.cpp
1#include <xrpl/tx/ApplyContext.h>
2//
3#include <xrpl/basics/Log.h>
4#include <xrpl/beast/utility/instrumentation.h>
5#include <xrpl/json/to_string.h>
6#include <xrpl/tx/invariants/InvariantCheck.h>
7
8namespace xrpl {
9
11 ServiceRegistry& registry_,
12 OpenView& base,
13 std::optional<uint256 const> const& parentBatchId,
14 STTx const& tx_,
15 TER preclaimResult_,
16 XRPAmount baseFee_,
17 ApplyFlags flags,
18 beast::Journal journal_)
19 : registry(registry_)
20 , tx(tx_)
21 , preclaimResult(preclaimResult_)
22 , baseFee(baseFee_)
23 , journal(journal_)
24 , base_(base)
25 , flags_(flags)
26 , parentBatchId_(parentBatchId)
27{
28 XRPL_ASSERT(
29 parentBatchId.has_value() == ((flags_ & tapBATCH) == tapBATCH),
30 "Parent Batch ID should be set if batch apply flag is set");
31 view_.emplace(&base_, flags_);
32}
33
34void
36{
37 view_.emplace(&base_, flags_);
38}
39
42{
43 return view_->apply(base_, tx, ter, parentBatchId_, (flags_ & tapDRY_RUN) != 0u, journal);
44}
45
48{
49 return view_->size();
50}
51
52void
54 std::function<void(
55 uint256 const&,
56 bool,
58 std::shared_ptr<SLE const> const&)> const& func)
59{
60 view_->visit(base_, func);
61}
62
63TER
65{
66 // If we already failed invariant checks before and we are now attempting to
67 // only charge a fee, and even that fails the invariant checks something is
68 // very wrong. We switch to tefINVARIANT_FAILED, which does NOT get included
69 // in a ledger.
70
71 return (result == tecINVARIANT_FAILED || result == tefINVARIANT_FAILED)
74}
75
76template <std::size_t... Is>
77TER
79 TER const result,
80 XRPAmount const fee,
82{
83 try
84 {
85 auto checkers = getInvariantChecks();
86
87 // call each check's per-entry method
88 visit([&checkers](
89 uint256 const& index,
90 bool isDelete,
91 std::shared_ptr<SLE const> const& before,
93 (..., std::get<Is>(checkers).visitEntry(isDelete, before, after));
94 });
95
96 // Note: do not replace this logic with a `...&&` fold expression.
97 // The fold expression will only run until the first check fails (it
98 // short-circuits). While the logic is still correct, the log
99 // message won't be. Every failed invariant should write to the log,
100 // not just the first one.
101 std::array<bool, sizeof...(Is)> const finalizers{
102 {std::get<Is>(checkers).finalize(tx, result, fee, *view_, journal)...}};
103
104 // call each check's finalizer to see that it passes
105 if (!std::all_of(finalizers.cbegin(), finalizers.cend(), [](auto const& b) { return b; }))
106 {
107 JLOG(journal.fatal()) << "Transaction has failed one or more invariants: "
109
110 return failInvariantCheck(result);
111 }
112 }
113 catch (std::exception const& ex)
114 {
115 JLOG(journal.fatal()) << "Transaction caused an exception in an invariant"
116 << ", ex: " << ex.what()
117 << ", tx: " << to_string(tx.getJson(JsonOptions::none));
118
119 return failInvariantCheck(result);
120 }
121
122 return result;
123}
124
125TER
127{
128 XRPL_ASSERT(
129 isTesSuccess(result) || isTecClaim(result),
130 "xrpl::ApplyContext::checkInvariants : is tesSUCCESS or tecCLAIM");
131
133 result, fee, std::make_index_sequence<std::tuple_size<InvariantChecks>::value>{});
134}
135
136} // namespace xrpl
T all_of(T... args)
A generic endpoint for log messages.
Definition Journal.h:40
Stream fatal() const
Definition Journal.h:325
std::size_t size()
Get the number of unapplied changes.
STTx const & tx
static TER failInvariantCheck(TER const result)
void discard()
Discard changes and start fresh.
std::optional< TxMeta > apply(TER)
Apply the transaction result to the base.
std::optional< ApplyViewImpl > view_
beast::Journal const journal
TER checkInvariantsHelper(TER const result, XRPAmount const fee, std::index_sequence< Is... >)
TER checkInvariants(TER const result, XRPAmount const fee)
Applies all invariant checkers one by one.
std::optional< uint256 const > parentBatchId_
ApplyContext(ServiceRegistry &registry, OpenView &base, std::optional< uint256 const > const &parentBatchId, STTx const &tx, TER preclaimResult, XRPAmount baseFee, ApplyFlags flags, beast::Journal journal=beast::Journal{beast::Journal::getNullSink()})
void visit(std::function< void(uint256 const &key, bool isDelete, std::shared_ptr< SLE const > const &before, std::shared_ptr< SLE const > const &after)> const &func)
Visit unapplied changes.
Writable ledger view that accumulates state and tx changes.
Definition OpenView.h:45
Json::Value getJson(JsonOptions options) const override
Definition STTx.cpp:317
Service registry for dependency injection.
T is_same_v
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
InvariantChecks getInvariantChecks()
get a tuple of all invariant checks
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
@ tefINVARIANT_FAILED
Definition TER.h:163
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:523
ApplyFlags
Definition ApplyView.h:10
@ tapDRY_RUN
Definition ApplyView.h:29
@ tapBATCH
Definition ApplyView.h:25
bool isTesSuccess(TER x) noexcept
Definition TER.h:651
@ tecINVARIANT_FAILED
Definition TER.h:294
bool isTecClaim(TER x) noexcept
Definition TER.h:658
T has_value(T... args)
T what(T... args)