rippled
Loading...
Searching...
No Matches
MPTInvariant.cpp
1#include <xrpl/tx/invariants/MPTInvariant.h>
2//
3#include <xrpl/basics/Log.h>
4#include <xrpl/beast/utility/instrumentation.h>
5#include <xrpl/protocol/Feature.h>
6#include <xrpl/protocol/Indexes.h>
7#include <xrpl/protocol/MPTIssue.h>
8#include <xrpl/protocol/TxFormats.h>
9#include <xrpl/tx/invariants/InvariantCheckPrivilege.h>
10
11namespace xrpl {
12
13void
15 bool isDelete,
16 std::shared_ptr<SLE const> const& before,
18{
19 if (after && after->getType() == ltMPTOKEN_ISSUANCE)
20 {
21 if (isDelete)
22 {
24 }
25 else if (!before)
26 {
28 }
29 }
30
31 if (after && after->getType() == ltMPTOKEN)
32 {
33 if (isDelete)
34 {
36 }
37 else if (!before)
38 {
40 MPTIssue const mptIssue{after->at(sfMPTokenIssuanceID)};
41 if (mptIssue.getIssuer() == after->at(sfAccount))
43 }
44 }
45}
46
47bool
49 STTx const& tx,
50 TER const result,
51 XRPAmount const _fee,
52 ReadView const& view,
53 beast::Journal const& j) const
54{
55 if (isTesSuccess(result))
56 {
57 auto const& rules = view.rules();
58 [[maybe_unused]]
59 bool const enforceCreatedByIssuer =
60 rules.enabled(featureSingleAssetVault) || rules.enabled(featureLendingProtocol);
62 {
63 JLOG(j.fatal()) << "Invariant failed: MPToken created for the MPT issuer";
64 // The comment above starting with "assert(enforce)" explains this
65 // assert.
66 XRPL_ASSERT_PARTS(
67 enforceCreatedByIssuer, "xrpl::ValidMPTIssuance::finalize", "no issuer MPToken");
68 if (enforceCreatedByIssuer)
69 return false;
70 }
71
72 auto const txnType = tx.getTxnType();
74 {
75 if (mptIssuancesCreated_ == 0)
76 {
77 JLOG(j.fatal()) << "Invariant failed: transaction "
78 "succeeded without creating a MPT issuance";
79 }
80 else if (mptIssuancesDeleted_ != 0)
81 {
82 JLOG(j.fatal()) << "Invariant failed: transaction "
83 "succeeded while removing MPT issuances";
84 }
85 else if (mptIssuancesCreated_ > 1)
86 {
87 JLOG(j.fatal()) << "Invariant failed: transaction "
88 "succeeded but created multiple issuances";
89 }
90
92 }
93
95 {
96 if (mptIssuancesDeleted_ == 0)
97 {
98 JLOG(j.fatal()) << "Invariant failed: MPT issuance deletion "
99 "succeeded without removing a MPT issuance";
100 }
101 else if (mptIssuancesCreated_ > 0)
102 {
103 JLOG(j.fatal()) << "Invariant failed: MPT issuance deletion "
104 "succeeded while creating MPT issuances";
105 }
106 else if (mptIssuancesDeleted_ > 1)
107 {
108 JLOG(j.fatal()) << "Invariant failed: MPT issuance deletion "
109 "succeeded but deleted multiple issuances";
110 }
111
112 return mptIssuancesCreated_ == 0 && mptIssuancesDeleted_ == 1;
113 }
114
115 bool const lendingProtocolEnabled = view.rules().enabled(featureLendingProtocol);
116 // ttESCROW_FINISH may authorize an MPT, but it can't have the
117 // mayAuthorizeMPT privilege, because that may cause
118 // non-amendment-gated side effects.
119 bool const enforceEscrowFinish = (txnType == ttESCROW_FINISH) &&
120 (view.rules().enabled(featureSingleAssetVault) || lendingProtocolEnabled);
121 if (hasPrivilege(tx, mustAuthorizeMPT | mayAuthorizeMPT) || enforceEscrowFinish)
122 {
123 bool const submittedByIssuer = tx.isFieldPresent(sfHolder);
124
125 if (mptIssuancesCreated_ > 0)
126 {
127 JLOG(j.fatal()) << "Invariant failed: MPT authorize "
128 "succeeded but created MPT issuances";
129 return false;
130 }
131 if (mptIssuancesDeleted_ > 0)
132 {
133 JLOG(j.fatal()) << "Invariant failed: MPT authorize "
134 "succeeded but deleted issuances";
135 return false;
136 }
137 if (lendingProtocolEnabled && mptokensCreated_ + mptokensDeleted_ > 1)
138 {
139 JLOG(j.fatal()) << "Invariant failed: MPT authorize succeeded "
140 "but created/deleted bad number mptokens";
141 return false;
142 }
143 if (submittedByIssuer && (mptokensCreated_ > 0 || mptokensDeleted_ > 0))
144 {
145 JLOG(j.fatal()) << "Invariant failed: MPT authorize submitted by issuer "
146 "succeeded but created/deleted mptokens";
147 return false;
148 }
149 if (!submittedByIssuer && hasPrivilege(tx, mustAuthorizeMPT) &&
151 {
152 // if the holder submitted this tx, then a mptoken must be
153 // either created or deleted.
154 JLOG(j.fatal()) << "Invariant failed: MPT authorize submitted by holder "
155 "succeeded but created/deleted bad number of mptokens";
156 return false;
157 }
158
159 return true;
160 }
161 if (txnType == ttESCROW_FINISH)
162 {
163 // ttESCROW_FINISH may authorize an MPT, but it can't have the
164 // mayAuthorizeMPT privilege, because that may cause
165 // non-amendment-gated side effects.
166 XRPL_ASSERT_PARTS(
167 !enforceEscrowFinish, "xrpl::ValidMPTIssuance::finalize", "not escrow finish tx");
168 return true;
169 }
170
173 return true;
174 }
175
176 if (mptIssuancesCreated_ != 0)
177 {
178 JLOG(j.fatal()) << "Invariant failed: a MPT issuance was created";
179 }
180 else if (mptIssuancesDeleted_ != 0)
181 {
182 JLOG(j.fatal()) << "Invariant failed: a MPT issuance was deleted";
183 }
184 else if (mptokensCreated_ != 0)
185 {
186 JLOG(j.fatal()) << "Invariant failed: a MPToken was created";
187 }
188 else if (mptokensDeleted_ != 0)
189 {
190 JLOG(j.fatal()) << "Invariant failed: a MPToken was deleted";
191 }
192
193 return mptIssuancesCreated_ == 0 && mptIssuancesDeleted_ == 0 && mptokensCreated_ == 0 &&
194 mptokensDeleted_ == 0;
195}
196
197} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:40
Stream fatal() const
Definition Journal.h:325
A view into a ledger.
Definition ReadView.h:31
virtual Rules const & rules() const =0
Returns the tx processing rules.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:120
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:456
TxType getTxnType() const
Definition STTx.h:188
std::uint32_t mptokensCreated_
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
std::uint32_t mptokensDeleted_
std::uint32_t mptIssuancesCreated_
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
std::uint32_t mptIssuancesDeleted_
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
bool hasPrivilege(STTx const &tx, Privilege priv)
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:523
bool isTesSuccess(TER x) noexcept
Definition TER.h:651