xrpld
Loading...
Searching...
No Matches
ApplyContext.cpp
1#include <xrpl/tx/ApplyContext.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/ServiceRegistry.h>
8#include <xrpl/json/to_string.h>
9#include <xrpl/ledger/ApplyView.h>
10#include <xrpl/ledger/OpenView.h>
11#include <xrpl/protocol/STTx.h>
12#include <xrpl/protocol/TER.h>
13#include <xrpl/protocol/TxMeta.h>
14#include <xrpl/protocol/XRPAmount.h>
15#include <xrpl/tx/invariants/InvariantCheck.h>
16
17#include <algorithm>
18#include <array>
19#include <cstddef>
20#include <exception>
21#include <functional>
22#include <optional>
23#include <tuple>
24#include <utility>
25
26namespace xrpl {
27
30 OpenView& base,
31 std::optional<uint256 const> const& parentBatchId,
32 STTx const& tx,
38 , tx(tx)
42 , base_(base)
43 , flags_(flags)
44 , parentBatchId_(parentBatchId)
45{
46 XRPL_ASSERT(
47 parentBatchId.has_value() == ((flags_ & TapBatch) == TapBatch),
48 "Parent Batch ID should be set if batch apply flag is set");
49 view_.emplace(&base_, flags_);
50}
51
52void
54{
55 view_.emplace(&base_, flags_);
56}
57
60{
61 // NOLINTNEXTLINE(bugprone-unchecked-optional-access) view_ emplaced in constructor
62 return view_->apply(base_, tx, ter, parentBatchId_, (flags_ & TapDryRun) != 0u, journal);
63}
64
67{
68 return view_->size(); // NOLINT(bugprone-unchecked-optional-access)
69}
70
71void
73 std::function<void(uint256 const&, bool, SLE::const_ref, SLE::const_ref)> const& func)
74{
75 view_->visit(base_, func); // NOLINT(bugprone-unchecked-optional-access)
76}
77
78TER
80{
81 // If we already failed invariant checks before and we are now attempting to
82 // only charge a fee, and even that fails the invariant checks something is
83 // very wrong. We switch to tefINVARIANT_FAILED, which does NOT get included
84 // in a ledger.
85
86 return (result == tecINVARIANT_FAILED || result == tefINVARIANT_FAILED)
89}
90
91template <std::size_t... Is>
92TER
94 TER const result,
95 XRPAmount const fee,
97{
98 try
99 {
100 auto checkers = getInvariantChecks();
101
102 // call each check's per-entry method
103 visit(
104 [&checkers](
105 uint256 const& index, bool isDelete, SLE::const_ref before, SLE::const_ref after) {
106 (..., std::get<Is>(checkers).visitEntry(isDelete, before, after));
107 });
108
109 // Note: do not replace this logic with a `...&&` fold expression.
110 // The fold expression will only run until the first check fails (it
111 // short-circuits). While the logic is still correct, the log
112 // message won't be. Every failed invariant should write to the log,
113 // not just the first one.
114 std::array<bool, sizeof...(Is)> const finalizers{{std::get<Is>(checkers).finalize(
115 tx, result, fee, *view_, journal)...}}; // NOLINT(bugprone-unchecked-optional-access)
116
117 // call each check's finalizer to see that it passes
118 if (!std::ranges::all_of(finalizers, [](auto const& b) { return b; }))
119 {
120 JLOG(journal.fatal()) << "Transaction has failed one or more global invariants: "
122
123 return failInvariantCheck(result);
124 }
125 }
126 catch (std::exception const& ex)
127 {
128 JLOG(journal.fatal()) << "Transaction caused an exception in a global invariant"
129 << ", ex: " << ex.what()
130 << ", tx: " << to_string(tx.getJson(JsonOptions::Values::None));
131
132 return failInvariantCheck(result);
133 }
134
135 return result;
136}
137
138TER
140{
141 XRPL_ASSERT(
142 isTesSuccess(result) || isTecClaim(result),
143 "xrpl::ApplyContext::checkInvariants : is tesSUCCESS or tecCLAIM");
144
147}
148
149} // namespace xrpl
T all_of(T... args)
A generic endpoint for log messages.
Definition Journal.h:38
std::size_t size()
Get the number of unapplied changes.
STTx const & tx
static TER failInvariantCheck(TER const result)
XRPAmount const baseFee
ApplyFlags const & flags() const
void discard()
Discard changes and start fresh.
std::reference_wrapper< ServiceRegistry > registry
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... >)
void visit(std::function< void(uint256 const &key, bool isDelete, SLE::const_ref before, SLE::const_ref after)> const &func)
Visit unapplied changes.
TER checkInvariants(TER const result, XRPAmount const fee)
Applies all invariant checkers one by one.
std::optional< uint256 const > parentBatchId_
TER const preclaimResult
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()})
Writable ledger view that accumulates state and tx changes.
Definition OpenView.h:45
std::shared_ptr< STLedgerEntry const > const & const_ref
Service registry for dependency injection.
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
@ tefINVARIANT_FAILED
Definition TER.h:173
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:554
ApplyFlags
Definition ApplyView.h:12
@ TapDryRun
Definition ApplyView.h:31
@ TapBatch
Definition ApplyView.h:27
bool isTesSuccess(TER x) noexcept
Definition TER.h:663
TERSubset< CanCvtToTER > TER
Definition TER.h:634
@ tecINVARIANT_FAILED
Definition TER.h:311
bool isTecClaim(TER x) noexcept
Definition TER.h:670
BaseUInt< 256 > uint256
Definition base_uint.h:562
T has_value(T... args)
T tuple_size_v
T what(T... args)