rippled
Loading...
Searching...
No Matches
ApplyContext.cpp
1#include <xrpl/basics/Log.h>
2#include <xrpl/beast/utility/instrumentation.h>
3#include <xrpl/json/to_string.h>
4#include <xrpl/tx/ApplyContext.h>
5#include <xrpl/tx/InvariantCheck.h>
6
7namespace xrpl {
8
10 ServiceRegistry& registry_,
11 OpenView& base,
12 std::optional<uint256 const> const& parentBatchId,
13 STTx const& tx_,
14 TER preclaimResult_,
15 XRPAmount baseFee_,
16 ApplyFlags flags,
17 beast::Journal journal_)
18 : registry(registry_)
19 , tx(tx_)
20 , preclaimResult(preclaimResult_)
21 , baseFee(baseFee_)
22 , journal(journal_)
23 , base_(base)
24 , flags_(flags)
25 , parentBatchId_(parentBatchId)
26{
27 XRPL_ASSERT(
28 parentBatchId.has_value() == ((flags_ & tapBATCH) == tapBATCH),
29 "Parent Batch ID should be set if batch apply flag is set");
30 view_.emplace(&base_, flags_);
31}
32
33void
35{
36 view_.emplace(&base_, flags_);
37}
38
41{
42 return view_->apply(base_, tx, ter, parentBatchId_, flags_ & tapDRY_RUN, journal);
43}
44
47{
48 return view_->size();
49}
50
51void
53 std::function<void(
54 uint256 const&,
55 bool,
57 std::shared_ptr<SLE const> const&)> const& func)
58{
59 view_->visit(base_, func);
60}
61
62TER
64{
65 // If we already failed invariant checks before and we are now attempting to
66 // only charge a fee, and even that fails the invariant checks something is
67 // very wrong. We switch to tefINVARIANT_FAILED, which does NOT get included
68 // in a ledger.
69
70 return (result == tecINVARIANT_FAILED || result == tefINVARIANT_FAILED)
73}
74
75template <std::size_t... Is>
76TER
78 TER const result,
79 XRPAmount const fee,
81{
82 try
83 {
84 auto checkers = getInvariantChecks();
85
86 // call each check's per-entry method
87 visit([&checkers](
88 uint256 const& index,
89 bool isDelete,
90 std::shared_ptr<SLE const> const& before,
92 (..., std::get<Is>(checkers).visitEntry(isDelete, before, after));
93 });
94
95 // Note: do not replace this logic with a `...&&` fold expression.
96 // The fold expression will only run until the first check fails (it
97 // short-circuits). While the logic is still correct, the log
98 // message won't be. Every failed invariant should write to the log,
99 // not just the first one.
100 std::array<bool, sizeof...(Is)> finalizers{
101 {std::get<Is>(checkers).finalize(tx, result, fee, *view_, journal)...}};
102
103 // call each check's finalizer to see that it passes
104 if (!std::all_of(finalizers.cbegin(), finalizers.cend(), [](auto const& b) { return b; }))
105 {
106 JLOG(journal.fatal()) << "Transaction has failed one or more invariants: "
108
109 return failInvariantCheck(result);
110 }
111 }
112 catch (std::exception const& ex)
113 {
114 JLOG(journal.fatal()) << "Transaction caused an exception in an invariant"
115 << ", ex: " << ex.what()
116 << ", tx: " << to_string(tx.getJson(JsonOptions::none));
117
118 return failInvariantCheck(result);
119 }
120
121 return result;
122}
123
124TER
126{
127 XRPL_ASSERT(
128 isTesSuccess(result) || isTecClaim(result),
129 "xrpl::ApplyContext::checkInvariants : is tesSUCCESS or tecCLAIM");
130
132 result, fee, std::make_index_sequence<std::tuple_size<InvariantChecks>::value>{});
133}
134
135} // 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
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:301
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:600
@ tefINVARIANT_FAILED
Definition TER.h:163
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:3652
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)