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 xrpl {
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(base_, tx, ter, parentBatchId_, flags_ & tapDRY_RUN, journal);
44}
45
48{
49 return view_->size();
50}
51
52void
55 void(uint256 const&, bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&)> const& func)
56{
57 view_->visit(base_, func);
58}
59
60TER
62{
63 // If we already failed invariant checks before and we are now attempting to
64 // only charge a fee, and even that fails the invariant checks something is
65 // very wrong. We switch to tefINVARIANT_FAILED, which does NOT get included
66 // in a ledger.
67
68 return (result == tecINVARIANT_FAILED || result == tefINVARIANT_FAILED) ? TER{tefINVARIANT_FAILED}
70}
71
72template <std::size_t... Is>
73TER
75{
76 try
77 {
78 auto checkers = getInvariantChecks();
79
80 // call each check's per-entry method
81 visit([&checkers](
82 uint256 const& index,
83 bool isDelete,
84 std::shared_ptr<SLE const> const& before,
86 (..., std::get<Is>(checkers).visitEntry(isDelete, before, after));
87 });
88
89 // Note: do not replace this logic with a `...&&` fold expression.
90 // The fold expression will only run until the first check fails (it
91 // short-circuits). While the logic is still correct, the log
92 // message won't be. Every failed invariant should write to the log,
93 // not just the first one.
94 std::array<bool, sizeof...(Is)> finalizers{
95 {std::get<Is>(checkers).finalize(tx, result, fee, *view_, journal)...}};
96
97 // call each check's finalizer to see that it passes
98 if (!std::all_of(finalizers.cbegin(), finalizers.cend(), [](auto const& b) { return b; }))
99 {
100 JLOG(journal.fatal()) << "Transaction has failed one or more invariants: "
102
103 return failInvariantCheck(result);
104 }
105 }
106 catch (std::exception const& ex)
107 {
108 JLOG(journal.fatal()) << "Transaction caused an exception in an invariant"
109 << ", ex: " << ex.what() << ", tx: " << to_string(tx.getJson(JsonOptions::none));
110
111 return failInvariantCheck(result);
112 }
113
114 return result;
115}
116
117TER
119{
120 XRPL_ASSERT(
121 isTesSuccess(result) || isTecClaim(result), "xrpl::ApplyContext::checkInvariants : is tesSUCCESS or tecCLAIM");
122
123 return checkInvariantsHelper(result, fee, std::make_index_sequence<std::tuple_size<InvariantChecks>::value>{});
124}
125
126} // namespace xrpl
T all_of(T... args)
A generic endpoint for log messages.
Definition Journal.h:41
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.
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()})
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_
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:46
Json::Value getJson(JsonOptions options) const override
Definition STTx.cpp:299
T is_same_v
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
InvariantChecks getInvariantChecks()
get a tuple of all invariant checks
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:598
@ tefINVARIANT_FAILED
Definition TER.h:164
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:3436
ApplyFlags
Definition ApplyView.h:11
@ tapDRY_RUN
Definition ApplyView.h:30
@ tapBATCH
Definition ApplyView.h:26
bool isTesSuccess(TER x) noexcept
Definition TER.h:650
@ tecINVARIANT_FAILED
Definition TER.h:295
bool isTecClaim(TER x) noexcept
Definition TER.h:657
T has_value(T... args)
T what(T... args)