rippled
Loading...
Searching...
No Matches
ApplyContext.cpp
1#include <xrpld/app/tx/detail/ApplyContext.h>
2#include <xrpld/app/tx/detail/InvariantCheck.h>
3
4#include <xrpl/basics/Log.h>
5#include <xrpl/beast/utility/instrumentation.h>
6#include <xrpl/json/to_string.h>
7
8namespace ripple {
9
11 Application& app_,
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 : app(app_)
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(
45}
46
49{
50 return view_->size();
51}
52
53void
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)> finalizers{
102 {std::get<Is>(checkers).finalize(
103 tx, result, fee, *view_, journal)...}};
104
105 // call each check's finalizer to see that it passes
106 if (!std::all_of(
107 finalizers.cbegin(), finalizers.cend(), [](auto const& b) {
108 return b;
109 }))
110 {
111 JLOG(journal.fatal())
112 << "Transaction has failed one or more invariants: "
114
115 return failInvariantCheck(result);
116 }
117 }
118 catch (std::exception const& ex)
119 {
120 JLOG(journal.fatal())
121 << "Transaction caused an exception in an invariant"
122 << ", ex: " << ex.what()
123 << ", tx: " << to_string(tx.getJson(JsonOptions::none));
124
125 return failInvariantCheck(result);
126 }
127
128 return result;
129}
130
131TER
133{
134 XRPL_ASSERT(
135 isTesSuccess(result) || isTecClaim(result),
136 "ripple::ApplyContext::checkInvariants : is tesSUCCESS or tecCLAIM");
137
139 result,
140 fee,
141 std::make_index_sequence<std::tuple_size<InvariantChecks>::value>{});
142}
143
144} // namespace ripple
T all_of(T... args)
A generic endpoint for log messages.
Definition Journal.h:41
Stream fatal() const
Definition Journal.h:333
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.
std::optional< TxMeta > apply(TER)
Apply the transaction result to the base.
ApplyContext(Application &app, 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 discard()
Discard changes and start fresh.
TER failInvariantCheck(TER const result)
beast::Journal const journal
std::size_t size()
Get the number of unapplied changes.
std::optional< ApplyViewImpl > view_
TER checkInvariants(TER const result, XRPAmount const fee)
Applies all invariant checkers one by one.
std::optional< uint256 const > parentBatchId_
TER checkInvariantsHelper(TER const result, XRPAmount const fee, std::index_sequence< Is... >)
Writable ledger view that accumulates state and tx changes.
Definition OpenView.h:46
Json::Value getJson(JsonOptions options) const override
Definition STTx.cpp:319
T is_same_v
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
@ tefINVARIANT_FAILED
Definition TER.h:164
@ tecINVARIANT_FAILED
Definition TER.h:295
bool isTesSuccess(TER x) noexcept
Definition TER.h:659
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:3247
InvariantChecks getInvariantChecks()
get a tuple of all invariant checks
@ tapDRY_RUN
Definition ApplyView.h:30
@ tapBATCH
Definition ApplyView.h:26
bool isTecClaim(TER x) noexcept
Definition TER.h:666
T has_value(T... args)
T what(T... args)