rippled
Loading...
Searching...
No Matches
TestHelpers.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2023 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/jtx/TestHelpers.h>
21#include <test/jtx/offer.h>
22#include <test/jtx/owners.h>
23
24#include <xrpl/protocol/TxFlags.h>
25
26namespace ripple {
27namespace test {
28namespace jtx {
29
30// Functions used in debugging
32getAccountOffers(Env& env, AccountID const& acct, bool current)
33{
34 Json::Value jv;
35 jv[jss::account] = to_string(acct);
36 return env.rpc("json", "account_offers", to_string(jv))[jss::result];
37}
38
40getAccountLines(Env& env, AccountID const& acctId)
41{
42 Json::Value jv;
43 jv[jss::account] = to_string(acctId);
44 return env.rpc("json", "account_lines", to_string(jv))[jss::result];
45}
46
47bool
48checkArraySize(Json::Value const& val, unsigned int size)
49{
50 return val.isArray() && val.size() == size;
51}
52
54ownerCount(Env const& env, Account const& account)
55{
56 return env.ownerCount(account);
57}
58
59/* Path finding */
60/******************************************************************************/
61void
62stpath_append_one(STPath& st, Account const& account)
63{
64 st.push_back(STPathElement({account.id(), std::nullopt, std::nullopt}));
65}
66
67void
69{
70 st.push_back(pe);
71}
72
73bool
74equal(STAmount const& sa1, STAmount const& sa2)
75{
76 return sa1 == sa2 && sa1.issue().account == sa2.issue().account;
77}
78
79// Issue path element
81IPE(Issue const& iss)
82{
83 return STPathElement(
85 xrpAccount(),
86 iss.currency,
87 iss.account);
88}
89
90/******************************************************************************/
91
93txfee(Env const& env, std::uint16_t n)
94{
95 return env.current()->fees().base * n;
96}
97
99xrpMinusFee(Env const& env, std::int64_t xrpAmount)
100{
101 auto feeDrops = env.current()->fees().base;
102 return drops(dropsPerXRP * xrpAmount - feeDrops);
103};
104
105[[nodiscard]] bool
107 Env& env,
108 AccountID const& account,
109 STAmount const& value,
110 bool defaultLimits)
111{
112 if (auto const sle = env.le(keylet::line(account, value.issue())))
113 {
114 Issue const issue = value.issue();
115 bool const accountLow = account < issue.account;
116
117 bool expectDefaultTrustLine = true;
118 if (defaultLimits)
119 {
120 STAmount low{issue};
121 STAmount high{issue};
122
123 low.setIssuer(accountLow ? account : issue.account);
124 high.setIssuer(accountLow ? issue.account : account);
125
126 expectDefaultTrustLine = sle->getFieldAmount(sfLowLimit) == low &&
127 sle->getFieldAmount(sfHighLimit) == high;
128 }
129
130 auto amount = sle->getFieldAmount(sfBalance);
131 amount.setIssuer(value.issue().account);
132 if (!accountLow)
133 amount.negate();
134 return amount == value && expectDefaultTrustLine;
135 }
136 return false;
137}
138
139[[nodiscard]] bool
140expectLine(Env& env, AccountID const& account, None const& value)
141{
142 return !env.le(keylet::line(account, value.issue));
143}
144
145[[nodiscard]] bool
147 Env& env,
148 AccountID const& account,
149 std::uint16_t size,
150 std::vector<Amounts> const& toMatch)
151{
152 std::uint16_t cnt = 0;
153 std::uint16_t matched = 0;
155 *env.current(), account, [&](std::shared_ptr<SLE const> const& sle) {
156 if (!sle)
157 return false;
158 if (sle->getType() == ltOFFER)
159 {
160 ++cnt;
161 if (std::find_if(
162 toMatch.begin(), toMatch.end(), [&](auto const& a) {
163 return a.in == sle->getFieldAmount(sfTakerPays) &&
164 a.out == sle->getFieldAmount(sfTakerGets);
165 }) != toMatch.end())
166 ++matched;
167 }
168 return true;
169 });
170 return size == cnt && matched == toMatch.size();
171}
172
174ledgerEntryRoot(Env& env, Account const& acct)
175{
176 Json::Value jvParams;
177 jvParams[jss::ledger_index] = "current";
178 jvParams[jss::account_root] = acct.human();
179 return env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
180}
181
184 Env& env,
185 Account const& acct_a,
186 Account const& acct_b,
187 std::string const& currency)
188{
189 Json::Value jvParams;
190 jvParams[jss::ledger_index] = "current";
191 jvParams[jss::ripple_state][jss::currency] = currency;
192 jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
193 jvParams[jss::ripple_state][jss::accounts].append(acct_a.human());
194 jvParams[jss::ripple_state][jss::accounts].append(acct_b.human());
195 return env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
196}
197
199accountBalance(Env& env, Account const& acct)
200{
201 auto const jrr = ledgerEntryRoot(env, acct);
202 return jrr[jss::node][sfBalance.fieldName];
203}
204
205[[nodiscard]] bool
207 Env& env,
208 Account const& acct,
209 STAmount const& expectedValue)
210{
211 return accountBalance(env, acct) == to_string(expectedValue.xrp());
212}
213
214/* Escrow */
215/******************************************************************************/
216
218escrow(AccountID const& account, AccountID const& to, STAmount const& amount)
219{
220 Json::Value jv;
221 jv[jss::TransactionType] = jss::EscrowCreate;
222 jv[jss::Account] = to_string(account);
223 jv[jss::Destination] = to_string(to);
224 jv[jss::Amount] = amount.getJson(JsonOptions::none);
225 return jv;
226}
227
229finish(AccountID const& account, AccountID const& from, std::uint32_t seq)
230{
231 Json::Value jv;
232 jv[jss::TransactionType] = jss::EscrowFinish;
233 jv[jss::Account] = to_string(account);
234 jv[sfOwner.jsonName] = to_string(from);
235 jv[sfOfferSequence.jsonName] = seq;
236 return jv;
237}
238
240cancel(AccountID const& account, Account const& from, std::uint32_t seq)
241{
242 Json::Value jv;
243 jv[jss::TransactionType] = jss::EscrowCancel;
244 jv[jss::Account] = to_string(account);
245 jv[sfOwner.jsonName] = from.human();
246 jv[sfOfferSequence.jsonName] = seq;
247 return jv;
248}
249
250/* Payment Channel */
251/******************************************************************************/
254 AccountID const& account,
255 AccountID const& to,
256 STAmount const& amount,
257 NetClock::duration const& settleDelay,
258 PublicKey const& pk,
259 std::optional<NetClock::time_point> const& cancelAfter,
260 std::optional<std::uint32_t> const& dstTag)
261{
262 Json::Value jv;
263 jv[jss::TransactionType] = jss::PaymentChannelCreate;
264 jv[jss::Account] = to_string(account);
265 jv[jss::Destination] = to_string(to);
266 jv[jss::Amount] = amount.getJson(JsonOptions::none);
267 jv[jss::SettleDelay] = settleDelay.count();
268 jv[sfPublicKey.fieldName] = strHex(pk.slice());
269 if (cancelAfter)
270 jv[sfCancelAfter.fieldName] = cancelAfter->time_since_epoch().count();
271 if (dstTag)
272 jv[sfDestinationTag.fieldName] = *dstTag;
273 return jv;
274}
275
278 AccountID const& account,
279 uint256 const& channel,
280 STAmount const& amount,
282{
283 Json::Value jv;
284 jv[jss::TransactionType] = jss::PaymentChannelFund;
285 jv[jss::Account] = to_string(account);
286 jv[sfChannel.fieldName] = to_string(channel);
287 jv[jss::Amount] = amount.getJson(JsonOptions::none);
288 if (expiration)
289 jv[sfExpiration.fieldName] = expiration->time_since_epoch().count();
290 return jv;
291}
292
295 AccountID const& account,
296 uint256 const& channel,
298 std::optional<STAmount> const& amount,
299 std::optional<Slice> const& signature,
300 std::optional<PublicKey> const& pk)
301{
302 Json::Value jv;
303 jv[jss::TransactionType] = jss::PaymentChannelClaim;
304 jv[jss::Account] = to_string(account);
305 jv["Channel"] = to_string(channel);
306 if (amount)
307 jv[jss::Amount] = amount->getJson(JsonOptions::none);
308 if (balance)
309 jv["Balance"] = balance->getJson(JsonOptions::none);
310 if (signature)
311 jv["Signature"] = strHex(*signature);
312 if (pk)
313 jv["PublicKey"] = strHex(pk->slice());
314 return jv;
315}
316
319 AccountID const& account,
320 AccountID const& dst,
321 std::uint32_t seqProxyValue)
322{
323 auto const k = keylet::payChan(account, dst, seqProxyValue);
324 return k.key;
325}
326
328channelBalance(ReadView const& view, uint256 const& chan)
329{
330 auto const slep = view.read({ltPAYCHAN, chan});
331 if (!slep)
332 return XRPAmount{-1};
333 return (*slep)[sfBalance];
334}
335
336bool
337channelExists(ReadView const& view, uint256 const& chan)
338{
339 auto const slep = view.read({ltPAYCHAN, chan});
340 return bool(slep);
341}
342
343/* Crossing Limits */
344/******************************************************************************/
345
346void
348 Env& env,
349 std::size_t n,
350 Account const& account,
351 STAmount const& in,
352 STAmount const& out)
353{
354 auto const ownerCount = env.le(account)->getFieldU32(sfOwnerCount);
355 for (std::size_t i = 0; i < n; i++)
356 {
357 env(offer(account, in, out));
358 env.close();
359 }
360 env.require(owners(account, ownerCount + n));
361}
362
363/* Pay Strand */
364/***************************************************************/
365
366// Currency path element
368cpe(Currency const& c)
369{
370 return STPathElement(
372};
373
374// All path element
376allpe(AccountID const& a, Issue const& iss)
377{
378 return STPathElement(
381 a,
382 iss.currency,
383 iss.account);
384};
385
386} // namespace jtx
387} // namespace test
388} // namespace ripple
Represents a JSON value.
Definition: json_value.h:150
bool isArray() const
Value & append(Value const &value)
Append value to array at the end.
Definition: json_value.cpp:910
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:719
A currency issued by an account.
Definition: Issue.h:36
AccountID account
Definition: Issue.h:39
Currency currency
Definition: Issue.h:38
A public key.
Definition: PublicKey.h:62
Slice slice() const noexcept
Definition: PublicKey.h:123
A view into a ledger.
Definition: ReadView.h:52
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
Json::Value getJson(JsonOptions=JsonOptions::none) const override
Definition: STAmount.cpp:639
XRPAmount xrp() const
Definition: STAmount.cpp:306
Issue const & issue() const
Definition: STAmount.h:496
void push_back(STPathElement const &e)
Definition: STPathSet.h:410
Immutable cryptographic account descriptor.
Definition: Account.h:39
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:114
A transaction testing environment.
Definition: Env.h:121
std::uint32_t ownerCount(Account const &account) const
Return the number of objects owned by an account.
Definition: Env.cpp:203
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:535
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:331
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:117
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:770
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:221
A balance matches.
Definition: balance.h:39
Set Expiration on a JTx.
Definition: Check_test.cpp:31
Match the number of items in the account's owner directory.
Definition: owners.h:73
@ arrayValue
array value (ordered list)
Definition: json_value.h:45
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:237
Keylet payChan(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Definition: Indexes.cpp:388
bool checkArraySize(Json::Value const &val, unsigned int size)
Definition: TestHelpers.cpp:48
std::uint32_t ownerCount(Env const &env, Account const &account)
Definition: TestHelpers.cpp:54
Json::Value ledgerEntryRoot(Env &env, Account const &acct)
Json::Value escrow(AccountID const &account, AccountID const &to, STAmount const &amount)
bool expectOffers(Env &env, AccountID const &account, std::uint16_t size, std::vector< Amounts > const &toMatch)
STAmount channelBalance(ReadView const &view, uint256 const &chan)
uint256 channel(AccountID const &account, AccountID const &dst, std::uint32_t seqProxyValue)
PrettyAmount xrpMinusFee(Env const &env, std::int64_t xrpAmount)
Definition: TestHelpers.cpp:99
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
bool expectLine(Env &env, AccountID const &account, STAmount const &value, bool defaultLimits)
bool equal(STAmount const &sa1, STAmount const &sa2)
Definition: TestHelpers.cpp:74
constexpr XRPAmount dropsPerXRP
Json::Value getAccountLines(Env &env, AccountID const &acctId)
Definition: TestHelpers.cpp:40
Json::Value ledgerEntryState(Env &env, Account const &acct_a, Account const &acct_b, std::string const &currency)
void stpath_append_one(STPath &st, Account const &account)
Definition: TestHelpers.cpp:62
void fund(jtx::Env &env, jtx::Account const &gw, std::vector< jtx::Account > const &accounts, std::vector< STAmount > const &amts, Fund how)
Definition: AMMTest.cpp:36
void n_offers(Env &env, std::size_t n, Account const &account, STAmount const &in, STAmount const &out)
Json::Value accountBalance(Env &env, Account const &acct)
Json::Value cancel(AccountID const &account, Account const &from, std::uint32_t seq)
STPathElement IPE(Issue const &iss)
Definition: TestHelpers.cpp:81
Json::Value claim(AccountID const &account, uint256 const &channel, std::optional< STAmount > const &balance, std::optional< STAmount > const &amount, std::optional< Slice > const &signature, std::optional< PublicKey > const &pk)
Json::Value finish(AccountID const &account, AccountID const &from, std::uint32_t seq)
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Definition: offer.cpp:29
Json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount, NetClock::duration const &settleDelay, PublicKey const &pk, std::optional< NetClock::time_point > const &cancelAfter, std::optional< std::uint32_t > const &dstTag)
STPathElement cpe(Currency const &c)
bool expectLedgerEntryRoot(Env &env, Account const &acct, STAmount const &expectedValue)
STPathElement allpe(AccountID const &a, Issue const &iss)
bool channelExists(ReadView const &view, uint256 const &chan)
XRPAmount txfee(Env const &env, std::uint16_t n)
Definition: TestHelpers.cpp:93
Json::Value getAccountOffers(Env &env, AccountID const &acct, bool current)
Definition: TestHelpers.cpp:32
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:178
@ current
This was a new validation and was added.
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
void forEachItem(ReadView const &view, Keylet const &root, std::function< void(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items in the given directory.
Definition: View.cpp:656
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
Set the sequence number on a JTx.
Definition: seq.h:34