xrpld
Loading...
Searching...
No Matches
InvariantRunner.cpp
1#include <xrpl/tx/invariants/InvariantRunner.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> // IWYU pragma: keep
9#include <xrpl/protocol/TER.h>
10#include <xrpl/protocol/XRPAmount.h>
11#include <xrpl/tx/ApplyContext.h>
12#include <xrpl/tx/invariants/InvariantCheck.h>
13
14#include <algorithm>
15#include <array>
16#include <cstddef>
17#include <exception>
18#include <functional>
19#include <optional>
20#include <tuple>
21#include <utility>
22
23namespace xrpl {
24
25namespace {
26
27TER
28failInvariantCheck(TER const result)
29{
30 return (result == tecINVARIANT_FAILED || result == tefINVARIANT_FAILED)
33}
34
35template <std::size_t... Is>
36TER
37checkInvariantsHelper(
38 ApplyContext& ctx,
39 TER const result,
40 XRPAmount const fee,
41 std::optional<std::reference_wrapper<TxInvariantCheck>> txCheck,
42 std::index_sequence<Is...>)
43{
44 bool allOk = true;
45
46 try
47 {
48 auto checkers = getInvariantChecks();
49
50 ctx.visit([&](UInt256 const&, bool isDelete, SLE::ConstRef before, SLE::ConstRef after) {
51 if (txCheck)
52 txCheck->get().visitEntry(isDelete, before, after);
53 (..., std::get<Is>(checkers).visitEntry(isDelete, before, after));
54 });
55
56 if (txCheck)
57 {
58 if (!txCheck->get().finalize(ctx.tx, result, fee, ctx.view(), ctx.journal))
59 {
60 JLOG(ctx.journal.fatal())
61 << "Transaction has failed one or more transaction invariants: "
62 << to_string(ctx.tx.getJson(JsonOptions::Values::None));
63 allOk = false;
64 }
65 }
66
67 // Note: do not replace this logic with a `...&&` fold expression.
68 // The fold expression will only run until the first check fails (it
69 // short-circuits). While the logic is still correct, the log
70 // message won't be. Every failed invariant should write to the log,
71 // not just the first one.
72 std::array<bool, sizeof...(Is)> const finalizers{
73 {std::get<Is>(checkers).finalize(ctx.tx, result, fee, ctx.view(), ctx.journal)...}};
74
75 if (!std::all_of(finalizers.cbegin(), finalizers.cend(), [](auto const& b) { return b; }))
76 {
77 JLOG(ctx.journal.fatal()) << "Transaction has failed one or more global invariants: "
78 << to_string(ctx.tx.getJson(JsonOptions::Values::None));
79 allOk = false;
80 }
81 }
82 catch (std::exception const& ex)
83 {
84 JLOG(ctx.journal.fatal()) << "Transaction caused an exception during invariant checks"
85 << ", ex: " << ex.what() << ", tx: "
86 << to_string(ctx.tx.getJson(JsonOptions::Values::None));
87 return failInvariantCheck(result);
88 }
89
90 return allOk ? result : failInvariantCheck(result);
91}
92
93} // namespace
94
95TER
97 ApplyContext& ctx,
98 TER const result,
99 XRPAmount const fee,
101{
102 XRPL_ASSERT(
103 isTesSuccess(result) || isTecClaim(result),
104 "xrpl::checkInvariants : is tesSUCCESS or tecCLAIM");
105
106 return checkInvariantsHelper(
108}
109
110} // namespace xrpl
T all_of(T... args)
State information when applying a tx.
std::shared_ptr< STLedgerEntry const > const & ConstRef
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:178
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:657
TER checkInvariants(ApplyContext &ctx, TER result, XRPAmount fee, std::optional< std::reference_wrapper< TxInvariantCheck > > txCheck)
Run all protocol invariant checks plus the transaction-specific check in a single pass over the modif...
BaseUInt< 256 > UInt256
Definition base_uint.h:580
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:644
bool isTesSuccess(TER x) noexcept
Definition TER.h:683
TERSubset< CanCvtToTER > TER
Definition TER.h:654
@ tecINVARIANT_FAILED
Definition TER.h:321
bool isTecClaim(TER x) noexcept
Definition TER.h:690
T tuple_size_v
T what(T... args)