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::Flags] = tfUniversal;
223 jv[jss::Account] = to_string(account);
224 jv[jss::Destination] = to_string(to);
225 jv[jss::Amount] = amount.getJson(JsonOptions::none);
226 return jv;
227}
228
230finish(AccountID const& account, AccountID const& from, std::uint32_t seq)
231{
232 Json::Value jv;
233 jv[jss::TransactionType] = jss::EscrowFinish;
234 jv[jss::Flags] = tfUniversal;
235 jv[jss::Account] = to_string(account);
236 jv[sfOwner.jsonName] = to_string(from);
237 jv[sfOfferSequence.jsonName] = seq;
238 return jv;
239}
240
242cancel(AccountID const& account, Account const& from, std::uint32_t seq)
243{
244 Json::Value jv;
245 jv[jss::TransactionType] = jss::EscrowCancel;
246 jv[jss::Flags] = tfUniversal;
247 jv[jss::Account] = to_string(account);
248 jv[sfOwner.jsonName] = from.human();
249 jv[sfOfferSequence.jsonName] = seq;
250 return jv;
251}
252
253/* Payment Channel */
254/******************************************************************************/
257 AccountID const& account,
258 AccountID const& to,
259 STAmount const& amount,
260 NetClock::duration const& settleDelay,
261 PublicKey const& pk,
262 std::optional<NetClock::time_point> const& cancelAfter,
263 std::optional<std::uint32_t> const& dstTag)
264{
265 Json::Value jv;
266 jv[jss::TransactionType] = jss::PaymentChannelCreate;
267 jv[jss::Flags] = tfUniversal;
268 jv[jss::Account] = to_string(account);
269 jv[jss::Destination] = to_string(to);
270 jv[jss::Amount] = amount.getJson(JsonOptions::none);
271 jv[jss::SettleDelay] = settleDelay.count();
272 jv[sfPublicKey.fieldName] = strHex(pk.slice());
273 if (cancelAfter)
274 jv[sfCancelAfter.fieldName] = cancelAfter->time_since_epoch().count();
275 if (dstTag)
276 jv[sfDestinationTag.fieldName] = *dstTag;
277 return jv;
278}
279
282 AccountID const& account,
283 uint256 const& channel,
284 STAmount const& amount,
286{
287 Json::Value jv;
288 jv[jss::TransactionType] = jss::PaymentChannelFund;
289 jv[jss::Flags] = tfUniversal;
290 jv[jss::Account] = to_string(account);
291 jv[sfChannel.fieldName] = to_string(channel);
292 jv[jss::Amount] = amount.getJson(JsonOptions::none);
293 if (expiration)
294 jv[sfExpiration.fieldName] = expiration->time_since_epoch().count();
295 return jv;
296}
297
300 AccountID const& account,
301 uint256 const& channel,
303 std::optional<STAmount> const& amount,
304 std::optional<Slice> const& signature,
305 std::optional<PublicKey> const& pk)
306{
307 Json::Value jv;
308 jv[jss::TransactionType] = jss::PaymentChannelClaim;
309 jv[jss::Flags] = tfUniversal;
310 jv[jss::Account] = to_string(account);
311 jv["Channel"] = to_string(channel);
312 if (amount)
313 jv[jss::Amount] = amount->getJson(JsonOptions::none);
314 if (balance)
315 jv["Balance"] = balance->getJson(JsonOptions::none);
316 if (signature)
317 jv["Signature"] = strHex(*signature);
318 if (pk)
319 jv["PublicKey"] = strHex(pk->slice());
320 return jv;
321}
322
325 AccountID const& account,
326 AccountID const& dst,
327 std::uint32_t seqProxyValue)
328{
329 auto const k = keylet::payChan(account, dst, seqProxyValue);
330 return k.key;
331}
332
334channelBalance(ReadView const& view, uint256 const& chan)
335{
336 auto const slep = view.read({ltPAYCHAN, chan});
337 if (!slep)
338 return XRPAmount{-1};
339 return (*slep)[sfBalance];
340}
341
342bool
343channelExists(ReadView const& view, uint256 const& chan)
344{
345 auto const slep = view.read({ltPAYCHAN, chan});
346 return bool(slep);
347}
348
349/* Crossing Limits */
350/******************************************************************************/
351
352void
354 Env& env,
355 std::size_t n,
356 Account const& account,
357 STAmount const& in,
358 STAmount const& out)
359{
360 auto const ownerCount = env.le(account)->getFieldU32(sfOwnerCount);
361 for (std::size_t i = 0; i < n; i++)
362 {
363 env(offer(account, in, out));
364 env.close();
365 }
366 env.require(owners(account, ownerCount + n));
367}
368
369/* Pay Strand */
370/***************************************************************/
371
372// Currency path element
374cpe(Currency const& c)
375{
376 return STPathElement(
378};
379
380// All path element
382allpe(AccountID const& a, Issue const& iss)
383{
384 return STPathElement(
387 a,
388 iss.currency,
389 iss.account);
390};
391
392} // namespace jtx
393} // namespace test
394} // 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
constexpr std::uint32_t tfUniversal
Definition: TxFlags.h:61
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