xrpld
Loading...
Searching...
No Matches
InvariantsBase.cpp
1#include <test/app/invariants/InvariantsBase.h>
2
3#include <test/jtx/Account.h>
4#include <test/jtx/Env.h>
5#include <test/jtx/TestHelpers.h>
6#include <test/jtx/amount.h>
7#include <test/jtx/envconfig.h>
8#include <test/jtx/fee.h>
9#include <test/jtx/tags.h>
10#include <test/jtx/vault.h>
11#include <test/unit_test/SuiteJournal.h>
12
13#include <xrpl/basics/Number.h>
14#include <xrpl/basics/base_uint.h>
15#include <xrpl/beast/unit_test/suite.h>
16#include <xrpl/beast/utility/Journal.h>
17#include <xrpl/ledger/ApplyView.h>
18#include <xrpl/ledger/OpenView.h>
19#include <xrpl/protocol/AccountID.h>
20#include <xrpl/protocol/Feature.h>
21#include <xrpl/protocol/Indexes.h>
22#include <xrpl/protocol/Keylet.h>
23#include <xrpl/protocol/Protocol.h>
24#include <xrpl/protocol/Rules.h>
25#include <xrpl/protocol/SField.h>
26#include <xrpl/protocol/STLedgerEntry.h>
27#include <xrpl/protocol/STTx.h>
28#include <xrpl/protocol/SeqProxy.h>
29#include <xrpl/protocol/TER.h>
30#include <xrpl/protocol/XRPAmount.h>
31#include <xrpl/tx/ApplyContext.h>
32#include <xrpl/tx/Transactor.h>
33#include <xrpl/tx/applySteps.h>
34
35#include <chrono>
36#include <cstdint>
37#include <initializer_list>
38#include <memory>
39#include <source_location>
40#include <string>
41#include <utility>
42#include <vector>
43
44namespace xrpl::test {
45
46test::jtx::Env
48{
49 return {*this, test::jtx::envconfig(), features, nullptr, beast::Severity::Disabled};
50}
51
52void
54 std::vector<std::string> const& expectLogs,
55 Precheck const& precheck,
56 XRPAmount fee,
57 STTx tx,
59 Preclose const& preclose,
60 TxAccount setTxAccount,
61 std::source_location const& loc,
62 TER initialResult)
63{
66 expectLogs,
67 precheck,
68 fee,
69 tx,
70 ters,
71 preclose,
72 setTxAccount,
73 loc,
74 initialResult);
75}
76
77void
79 test::jtx::Env&& env,
80 std::vector<std::string> const& expectLogs,
81 Precheck const& precheck,
82 XRPAmount fee,
83 STTx tx,
85 Preclose const& preclose,
86 TxAccount setTxAccount,
87 std::source_location const& loc,
88 TER initialResult)
89{
90 using namespace test::jtx;
91
92 Account const a1{"A1"};
93 Account const a2{"A2"};
94 env.fund(XRP(1000), a1, a2);
95 if (preclose)
96 BEAST_EXPECT(preclose(a1, a2, env));
97 env.close();
98
99 if (setTxAccount != TxAccount::None)
100 tx.setAccountID(sfAccount, setTxAccount == TxAccount::A1 ? a1.id() : a2.id());
101
103 std::move(env), a1, a2, expectLogs, precheck, fee, tx, ters, loc, initialResult);
104}
105
106void
108 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
109 test::jtx::Env&& env,
110 test::jtx::Account const& a1,
111 test::jtx::Account const& a2,
112 std::vector<std::string> const& expectLogs,
113 Precheck const& precheck,
114 XRPAmount fee,
115 STTx tx,
117 std::source_location const& loc,
118 TER initialResult)
119{
120 using namespace test::jtx;
121
122 OpenView ov{*env.current()};
124 beast::Journal const jlog{sink};
125 ApplyContext ac{env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
126
127 // Invariants normally run in the Transaction's "apply" (operator()) context, and can always
128 // access global Rules.
129 CurrentTransactionRulesGuard const rulesGuard(ov.rules());
130
131 BEAST_EXPECT(precheck(a1, a2, ac));
132
133 auto transactor = makeTransactor(ac);
134 if (!BEAST_EXPECT(transactor))
135 return;
136
137 // Invoke the check twice to cover the tec and tef cases. Both passes run
138 // against the same view -- production would discard it in between -- so
139 // the second sees the same violation and escalates tec -> tef. A
140 // {tec, tef} pair therefore means "enforced whatever the incoming
141 // result", not that the transaction ends in tef on ledger.
142 if (!BEAST_EXPECT(ters.size() == 2))
143 return;
144
145 TER terActual = initialResult;
146 for (TER const& terExpect : ters)
147 {
148 TER const terInput = terActual;
149 terActual = transactor->checkInvariants(terActual, fee, Transactor::InvariantScope::Full);
150 expect(
151 terExpect == terActual,
152 "expected: " + transToken(terExpect) + " got: " + transToken(terActual),
153 loc.file_name(),
154 loc.line());
155 auto const messages = sink.messages().str();
156
157 // checkInvariants returns its input unchanged unless something
158 // fires, so a changed result means an invariant fired, and a firing
159 // invariant must log.
160 if (terActual != terInput)
161 {
162 expect(
163 messages.starts_with("Invariant failed:") ||
164 messages.starts_with("Transaction caused an exception"),
165 messages,
166 loc.file_name(),
167 loc.line());
168 }
169
170 // std::cerr << messages << '\n';
171 for (auto const& m : expectLogs)
172 {
173 expect(messages.contains(m), m, loc.file_name(), loc.line());
174 }
175 }
176}
177
178Keylet
180 jtx::Account const& a,
181 jtx::Env& env,
182 jtx::PrettyAsset const& asset)
183{
184 using namespace jtx;
185
186 // Under featureLendingProtocolV1_1 LoanBrokerSet::preclaim only
187 // accepts closed-ended vaults. Build one with a comfortable
188 // subscription window; LoanBrokerSet itself is not phase-gated,
189 // so leaving the vault in the Subscription phase is fine here.
190 UInt256 vaultID;
191 Vault const vault{env};
192 auto [tx, vKeylet, _] = vault.createClosedEnded(
193 {.owner = a,
194 .asset = asset,
195 .subscriptionOffset = std::chrono::seconds{60},
196 .investmentWindow = std::chrono::seconds{kMinInvestmentPeriod + 1'000'000u}});
197 env(tx);
198 BEAST_EXPECT(env.le(vKeylet));
199
200 vaultID = vKeylet.key;
201
202 // Create Loan Broker
203 using namespace loan_broker;
204
205 auto const loanBrokerKeylet = keylet::loanBroker(a.id(), SeqProxy::rawSequence(env.seq(a)));
206 // Create a Loan Broker with all default values.
207 env(set(a, vaultID), Fee(kIncrement));
208
209 return loanBrokerKeylet;
210}
211
214 UInt256 const& loanBrokerID,
215 std::uint32_t loanSeq,
216 AccountID const& borrower)
217{
218 auto sleLoan =
220 // SoeRequired fields.
221 sleLoan->at(sfLoanBrokerID) = loanBrokerID;
222 sleLoan->at(sfLoanSequence) = loanSeq;
223 sleLoan->at(sfBorrower) = borrower;
224 sleLoan->at(sfStartDate) = 0u;
225 sleLoan->at(sfPaymentInterval) = 1u;
226 sleLoan->at(sfPeriodicPayment) = Number(1);
227 // SoeDefault fields, materialized so that an invariant reading them through
228 // at() does not throw on this hand-built entry.
229 sleLoan->at(sfLoanServiceFee) = Number(0);
230 sleLoan->at(sfLatePaymentFee) = Number(0);
231 sleLoan->at(sfClosePaymentFee) = Number(0);
232 sleLoan->at(sfPrincipalOutstanding) = Number(0);
233 sleLoan->at(sfTotalValueOutstanding) = Number(0);
234 sleLoan->at(sfManagementFeeOutstanding) = Number(0);
235 sleLoan->setFieldU32(sfPaymentRemaining, 0);
236 sleLoan->makeFieldPresent(sfOwnerNode);
237 sleLoan->makeFieldPresent(sfLoanBrokerNode);
238 return sleLoan;
239}
240
241} // namespace xrpl::test
A generic endpoint for log messages.
Definition Journal.h:44
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:235
State information when applying a tx.
RAII class to set and restore the current transaction rules.
Definition Rules.h:113
Number is a floating point type that can represent a wide range of values.
Definition Number.h:351
Writable ledger view that accumulates state and tx changes.
Definition OpenView.h:59
Rules const & rules() const override
Returns the tx processing rules.
Definition OpenView.cpp:149
std::shared_ptr< STLedgerEntry > pointer
void setAccountID(SField const &field, AccountID const &)
Definition STObject.cpp:785
static constexpr SeqProxy rawSequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition SeqProxy.h:62
Keylet createLoanBroker(jtx::Account const &a, jtx::Env &env, jtx::PrettyAsset const &asset)
std::function< bool(test::jtx::Account const &a, test::jtx::Account const &b, ApplyContext &ac)> Precheck
test::jtx::Env makeEnv(FeatureBitset features)
void doInvariantCheck(std::vector< std::string > const &expectLogs, Precheck const &precheck, XRPAmount fee=XRPAmount{}, STTx tx=STTx{ttACCOUNT_SET, [](STObject &) {}}, std::initializer_list< TER > ters={tecINVARIANT_FAILED, tefINVARIANT_FAILED}, Preclose const &preclose={}, TxAccount setTxAccount=TxAccount::None, std::source_location const &loc=std::source_location::current(), TER initialResult=tesSUCCESS)
Run a specific test case to put the ledger into a state that will be detected by an invariant.
static SLE::pointer makeLoanSle(UInt256 const &loanBrokerID, std::uint32_t loanSeq, AccountID const &borrower)
std::function< bool(test::jtx::Account const &a, test::jtx::Account const &b, test::jtx::Env &env)> Preclose
std::stringstream const & messages() const
Immutable cryptographic account descriptor.
Definition jtx/Account.h:21
AccountID id() const
Returns the Account ID.
A transaction testing environment.
Definition Env.h:161
SLE::const_pointer le(Account const &account) const
Return an account root.
Definition Env.cpp:311
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition Env.cpp:302
Set the fee on a JTx.
Definition fee.h:20
T file_name(T... args)
T make_shared(T... args)
Keylet loanBroker(AccountID const &owner, SeqProxy const &seq) noexcept
Definition Indexes.cpp:597
Keylet loan(UInt256 const &loanBrokerID, SeqProxy const &loanSeq) noexcept
Definition Indexes.cpp:603
XrpT const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:92
FeatureBitset testableAmendments()
Definition Env.h:92
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:38
static IncrementT const kIncrement
Definition tags.h:31
constexpr XRPAmount
Convert XRP to drops (integral types).
Definition TxTest.h:54
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
std::string transToken(TER code)
Definition TER.cpp:257
BaseUInt< 256 > UInt256
Definition base_uint.h:580
std::unique_ptr< Transactor > makeTransactor(ApplyContext &ctx)
@ TapNone
Definition ApplyView.h:28
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:34
TERSubset< CanCvtToTER > TER
Definition TER.h:654
constexpr std::uint32_t kMinInvestmentPeriod
Bounds on the length of a closed-ended vault's Investment phase (RedemptionDate - SubscriptionDate).
Definition Protocol.h:369
@ tesSUCCESS
Definition TER.h:250
T str(T... args)
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:20