rippled
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 
22 #include <ripple/protocol/TxFlags.h>
23 #include <test/jtx/offer.h>
24 #include <test/jtx/owners.h>
25 
26 namespace ripple {
27 namespace test {
28 namespace jtx {
29 
30 // Functions used in debugging
32 getAccountOffers(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 
40 getAccountLines(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 
47 bool
48 checkArraySize(Json::Value const& val, unsigned int size)
49 {
50  return val.isArray() && val.size() == size;
51 }
52 
53 /* Path finding */
54 /******************************************************************************/
55 void
56 stpath_append_one(STPath& st, Account const& account)
57 {
58  st.push_back(STPathElement({account.id(), std::nullopt, std::nullopt}));
59 }
60 
61 void
63 {
64  st.push_back(pe);
65 }
66 
67 bool
68 equal(STAmount const& sa1, STAmount const& sa2)
69 {
70  return sa1 == sa2 && sa1.issue().account == sa2.issue().account;
71 }
72 
73 // Issue path element
75 IPE(Issue const& iss)
76 {
77  return STPathElement(
79  xrpAccount(),
80  iss.currency,
81  iss.account);
82 }
83 
84 /******************************************************************************/
85 
87 txfee(Env const& env, std::uint16_t n)
88 {
89  return env.current()->fees().base * n;
90 }
91 
93 xrpMinusFee(Env const& env, std::int64_t xrpAmount)
94 {
95  auto feeDrops = env.current()->fees().base;
96  return drops(dropsPerXRP * xrpAmount - feeDrops);
97 };
98 
99 [[nodiscard]] bool
101  Env& env,
102  AccountID const& account,
103  STAmount const& value,
104  bool defaultLimits)
105 {
106  if (auto const sle = env.le(keylet::line(account, value.issue())))
107  {
108  Issue const issue = value.issue();
109  bool const accountLow = account < issue.account;
110 
111  bool expectDefaultTrustLine = true;
112  if (defaultLimits)
113  {
114  STAmount low{issue};
115  STAmount high{issue};
116 
117  low.setIssuer(accountLow ? account : issue.account);
118  high.setIssuer(accountLow ? issue.account : account);
119 
120  expectDefaultTrustLine = sle->getFieldAmount(sfLowLimit) == low &&
121  sle->getFieldAmount(sfHighLimit) == high;
122  }
123 
124  auto amount = sle->getFieldAmount(sfBalance);
125  amount.setIssuer(value.issue().account);
126  if (!accountLow)
127  amount.negate();
128  return amount == value && expectDefaultTrustLine;
129  }
130  return false;
131 }
132 
133 [[nodiscard]] bool
134 expectLine(Env& env, AccountID const& account, None const& value)
135 {
136  return !env.le(keylet::line(account, value.issue));
137 }
138 
139 [[nodiscard]] bool
141  Env& env,
142  AccountID const& account,
143  std::uint16_t size,
144  std::vector<Amounts> const& toMatch)
145 {
146  std::uint16_t cnt = 0;
147  std::uint16_t matched = 0;
148  forEachItem(
149  *env.current(), account, [&](std::shared_ptr<SLE const> const& sle) {
150  if (!sle)
151  return false;
152  if (sle->getType() == ltOFFER)
153  {
154  ++cnt;
155  if (std::find_if(
156  toMatch.begin(), toMatch.end(), [&](auto const& a) {
157  return a.in == sle->getFieldAmount(sfTakerPays) &&
158  a.out == sle->getFieldAmount(sfTakerGets);
159  }) != toMatch.end())
160  ++matched;
161  }
162  return true;
163  });
164  return size == cnt && matched == toMatch.size();
165 }
166 
168 ledgerEntryRoot(Env& env, Account const& acct)
169 {
170  Json::Value jvParams;
171  jvParams[jss::ledger_index] = "current";
172  jvParams[jss::account_root] = acct.human();
173  return env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
174 }
175 
178  Env& env,
179  Account const& acct_a,
180  Account const& acct_b,
181  std::string const& currency)
182 {
183  Json::Value jvParams;
184  jvParams[jss::ledger_index] = "current";
185  jvParams[jss::ripple_state][jss::currency] = currency;
186  jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue;
187  jvParams[jss::ripple_state][jss::accounts].append(acct_a.human());
188  jvParams[jss::ripple_state][jss::accounts].append(acct_b.human());
189  return env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
190 }
191 
193 accountBalance(Env& env, Account const& acct)
194 {
195  auto const jrr = ledgerEntryRoot(env, acct);
196  return jrr[jss::node][sfBalance.fieldName];
197 }
198 
199 [[nodiscard]] bool
201  Env& env,
202  Account const& acct,
203  STAmount const& expectedValue)
204 {
205  return accountBalance(env, acct) == to_string(expectedValue.xrp());
206 }
207 
208 /* Escrow */
209 /******************************************************************************/
210 
212 escrow(AccountID const& account, AccountID const& to, STAmount const& amount)
213 {
214  Json::Value jv;
215  jv[jss::TransactionType] = jss::EscrowCreate;
216  jv[jss::Flags] = tfUniversal;
217  jv[jss::Account] = to_string(account);
218  jv[jss::Destination] = to_string(to);
219  jv[jss::Amount] = amount.getJson(JsonOptions::none);
220  return jv;
221 }
222 
224 finish(AccountID const& account, AccountID const& from, std::uint32_t seq)
225 {
226  Json::Value jv;
227  jv[jss::TransactionType] = jss::EscrowFinish;
228  jv[jss::Flags] = tfUniversal;
229  jv[jss::Account] = to_string(account);
230  jv[sfOwner.jsonName] = to_string(from);
232  return jv;
233 }
234 
236 cancel(AccountID const& account, Account const& from, std::uint32_t seq)
237 {
238  Json::Value jv;
239  jv[jss::TransactionType] = jss::EscrowCancel;
240  jv[jss::Flags] = tfUniversal;
241  jv[jss::Account] = to_string(account);
242  jv[sfOwner.jsonName] = from.human();
244  return jv;
245 }
246 
247 /* Payment Channel */
248 /******************************************************************************/
251  AccountID const& account,
252  AccountID const& to,
253  STAmount const& amount,
254  NetClock::duration const& settleDelay,
255  PublicKey const& pk,
256  std::optional<NetClock::time_point> const& cancelAfter,
257  std::optional<std::uint32_t> const& dstTag)
258 {
259  Json::Value jv;
260  jv[jss::TransactionType] = jss::PaymentChannelCreate;
261  jv[jss::Flags] = tfUniversal;
262  jv[jss::Account] = to_string(account);
263  jv[jss::Destination] = to_string(to);
264  jv[jss::Amount] = amount.getJson(JsonOptions::none);
265  jv[jss::SettleDelay] = settleDelay.count();
266  jv[sfPublicKey.fieldName] = strHex(pk.slice());
267  if (cancelAfter)
268  jv[sfCancelAfter.fieldName] = cancelAfter->time_since_epoch().count();
269  if (dstTag)
270  jv[sfDestinationTag.fieldName] = *dstTag;
271  return jv;
272 }
273 
276  AccountID const& account,
277  uint256 const& channel,
278  STAmount const& amount,
280 {
281  Json::Value jv;
282  jv[jss::TransactionType] = jss::PaymentChannelFund;
283  jv[jss::Flags] = tfUniversal;
284  jv[jss::Account] = to_string(account);
286  jv[jss::Amount] = amount.getJson(JsonOptions::none);
287  if (expiration)
288  jv[sfExpiration.fieldName] = expiration->time_since_epoch().count();
289  return jv;
290 }
291 
294  AccountID const& account,
295  uint256 const& channel,
297  std::optional<STAmount> const& amount,
298  std::optional<Slice> const& signature,
299  std::optional<PublicKey> const& pk)
300 {
301  Json::Value jv;
302  jv[jss::TransactionType] = jss::PaymentChannelClaim;
303  jv[jss::Flags] = tfUniversal;
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 
317 uint256
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 
327 STAmount
328 channelBalance(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 
336 bool
337 channelExists(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 
346 void
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
368 cpe(Currency const& c)
369 {
370  return STPathElement(
372 };
373 
374 // All path element
376 allpe(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
ripple::test::jtx::getAccountOffers
Json::Value getAccountOffers(Env &env, AccountID const &acct, bool current)
Definition: TestHelpers.cpp:32
ripple::sfOfferSequence
const SF_UINT32 sfOfferSequence
ripple::sfOwnerCount
const SF_UINT32 sfOwnerCount
ripple::STPath::push_back
void push_back(STPathElement const &e)
Definition: STPathSet.h:405
ripple::test::jtx::dropsPerXRP
constexpr XRPAmount dropsPerXRP
Definition: amount.h:67
ripple::test::jtx::claim
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)
Definition: TestHelpers.cpp:293
ripple::Issue
A currency issued by an account.
Definition: Issue.h:35
ripple::test::jtx::checkArraySize
bool checkArraySize(Json::Value const &val, unsigned int size)
Definition: TestHelpers.cpp:48
std::string
STL class.
std::shared_ptr
STL class.
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
ripple::test::jtx::finish
Json::Value finish(AccountID const &account, AccountID const &from, std::uint32_t seq)
Definition: TestHelpers.cpp:224
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:350
ripple::test::jtx::stpath_append_one
void stpath_append_one(STPath &st, Account const &account)
Definition: TestHelpers.cpp:56
ripple::test::jtx::owners
Match the number of items in the account's owner directory.
Definition: owners.h:69
ripple::test::jtx::ledgerEntryState
Json::Value ledgerEntryState(Env &env, Account const &acct_a, Account const &acct_b, std::string const &currency)
Definition: TestHelpers.cpp:177
ripple::test::jtx::Env::require
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:479
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::sfOwner
const SF_ACCOUNT sfOwner
ripple::test::jtx::balance
A balance matches.
Definition: balance.h:38
std::vector
STL class.
ripple::SField::fieldName
const std::string fieldName
Definition: SField.h:159
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:653
std::chrono::duration
ripple::Issue::currency
Currency currency
Definition: Issue.h:38
ripple::test::jtx::xrpMinusFee
PrettyAmount xrpMinusFee(Env const &env, std::int64_t xrpAmount)
Definition: TestHelpers.cpp:93
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:113
ripple::test::jtx::channelExists
bool channelExists(ReadView const &view, uint256 const &chan)
Definition: TestHelpers.cpp:337
ripple::PublicKey::slice
Slice slice() const noexcept
Definition: PublicKey.h:125
ripple::QualityDirection::in
@ in
ripple::test::ownerCount
std::uint32_t ownerCount(test::jtx::Env const &env, test::jtx::Account const &acct)
Definition: DID_test.cpp:35
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:163
ripple::test::jtx::n_offers
void n_offers(Env &env, std::size_t n, Account const &account, STAmount const &in, STAmount const &out)
Definition: TestHelpers.cpp:347
ripple::STPathElement::typeCurrency
@ typeCurrency
Definition: STPathSet.h:49
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:345
ripple::test::jtx::equal
bool equal(STAmount const &sa1, STAmount const &sa2)
Definition: TestHelpers.cpp:68
ripple::STPathElement::typeIssuer
@ typeIssuer
Definition: STPathSet.h:50
ripple::sfExpiration
const SF_UINT32 sfExpiration
ripple::test::jtx::expiration
Set Expiration on a JTx.
Definition: Check_test.cpp:29
ripple::base_uint< 160, detail::AccountIDTag >
ripple::sfLowLimit
const SF_AMOUNT sfLowLimit
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
ripple::QualityDirection::out
@ out
ripple::test::jtx::channel
uint256 channel(AccountID const &account, AccountID const &dst, std::uint32_t seqProxyValue)
Definition: TestHelpers.cpp:318
ripple::PublicKey
A public key.
Definition: PublicKey.h:61
ripple::test::jtx::IPE
STPathElement IPE(Issue const &iss)
Definition: TestHelpers.cpp:75
ripple::JsonOptions::none
@ none
ripple::test::jtx::expectOffers
bool expectOffers(Env &env, AccountID const &account, std::uint16_t size, std::vector< Amounts > const &toMatch)
Definition: TestHelpers.cpp:140
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
ripple::STAmount
Definition: STAmount.h:46
ripple::xrpAccount
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:168
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
std::uint16_t
ripple::sfHighLimit
const SF_AMOUNT sfHighLimit
ripple::test::jtx::cpe
STPathElement cpe(Currency const &c)
Definition: TestHelpers.cpp:368
ripple::test::jtx::allpe
STPathElement allpe(AccountID const &a, Issue const &iss)
Definition: TestHelpers.cpp:376
ripple::keylet::line
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:202
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::test::jtx::channelBalance
STAmount channelBalance(ReadView const &view, uint256 const &chan)
Definition: TestHelpers.cpp:328
ripple::test::jtx::None::issue
Issue issue
Definition: amount.h:59
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
ripple::test::jtx::None
Definition: amount.h:57
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:33
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:54
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::keylet::payChan
Keylet payChan(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Definition: Indexes.cpp:333
ripple::STPathElement
Definition: STPathSet.h:34
ripple::test::jtx::Env::le
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:216
ripple::sfDestinationTag
const SF_UINT32 sfDestinationTag
ripple::STPathElement::typeAccount
@ typeAccount
Definition: STPathSet.h:47
ripple::test::jtx::accountBalance
Json::Value accountBalance(Env &env, Account const &acct)
Definition: TestHelpers.cpp:193
ripple::test::jtx::fund
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:35
ripple::sfBalance
const SF_AMOUNT sfBalance
std::chrono::duration::count
T count(T... args)
ripple::sfCancelAfter
const SF_UINT32 sfCancelAfter
std::optional
ripple::forEachItem
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:384
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::sfChannel
const SF_UINT256 sfChannel
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::tfUniversal
constexpr std::uint32_t tfUniversal
Definition: TxFlags.h:59
ripple::STPath
Definition: STPathSet.h:118
ripple::test::jtx::expectLedgerEntryRoot
bool expectLedgerEntryRoot(Env &env, Account const &acct, STAmount const &expectedValue)
Definition: TestHelpers.cpp:200
ripple::sfPublicKey
const SF_VL sfPublicKey
ripple::test::jtx::expectLine
bool expectLine(Env &env, AccountID const &account, STAmount const &value, bool defaultLimits)
Definition: TestHelpers.cpp:100
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:301
ripple::test::jtx::create
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)
Definition: TestHelpers.cpp:250
ripple::test::jtx::txfee
XRPAmount txfee(Env const &env, std::uint16_t n)
Definition: TestHelpers.cpp:87
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:117
ripple::test::jtx::getAccountLines
Json::Value getAccountLines(Env &env, AccountID const &acctId)
Definition: TestHelpers.cpp:40
ripple::Issue::account
AccountID account
Definition: Issue.h:39
ripple::test::jtx::Env::rpc
Json::Value rpc(std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:700
ripple::test::jtx::ledgerEntryRoot
Json::Value ledgerEntryRoot(Env &env, Account const &acct)
Definition: TestHelpers.cpp:168
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::jtx::PrettyAmount
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
Definition: amount.h:73
ripple::ltPAYCHAN
@ ltPAYCHAN
A ledger object describing a single unidirectional XRP payment channel.
Definition: LedgerFormats.h:149
ripple::XRPAmount
Definition: XRPAmount.h:46