rippled
PayChan_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 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 <ripple/basics/chrono.h>
21 #include <ripple/ledger/Directory.h>
22 #include <ripple/protocol/Feature.h>
23 #include <ripple/protocol/Indexes.h>
24 #include <ripple/protocol/PayChan.h>
25 #include <ripple/protocol/TxFlags.h>
26 #include <ripple/protocol/jss.h>
27 #include <test/jtx.h>
28 
29 #include <chrono>
30 
31 namespace ripple {
32 namespace test {
33 struct PayChan_test : public beast::unit_test::suite
34 {
35  static uint256
37  jtx::Account const& account,
38  jtx::Account const& dst,
39  std::uint32_t seqProxyValue)
40  {
41  auto const k = keylet::payChan(account, dst, seqProxyValue);
42  return k.key;
43  }
44 
47  ReadView const& view,
48  jtx::Account const& account,
49  jtx::Account const& dst)
50  {
51  auto const sle = view.read(keylet::account(account));
52  if (!sle)
53  return {};
54  auto const k = keylet::payChan(account, dst, (*sle)[sfSequence] - 1);
55  return {k.key, view.read(k)};
56  }
57 
58  static Buffer
60  PublicKey const& pk,
61  SecretKey const& sk,
62  uint256 const& channel,
63  STAmount const& authAmt)
64  {
65  Serializer msg;
66  serializePayChanAuthorization(msg, channel, authAmt.xrp());
67  return sign(pk, sk, msg.slice());
68  }
69 
70  static STAmount
71  channelBalance(ReadView const& view, uint256 const& chan)
72  {
73  auto const slep = view.read({ltPAYCHAN, chan});
74  if (!slep)
75  return XRPAmount{-1};
76  return (*slep)[sfBalance];
77  }
78 
79  static bool
80  channelExists(ReadView const& view, uint256 const& chan)
81  {
82  auto const slep = view.read({ltPAYCHAN, chan});
83  return bool(slep);
84  }
85 
86  static STAmount
87  channelAmount(ReadView const& view, uint256 const& chan)
88  {
89  auto const slep = view.read({ltPAYCHAN, chan});
90  if (!slep)
91  return XRPAmount{-1};
92  return (*slep)[sfAmount];
93  }
94 
96  channelExpiration(ReadView const& view, uint256 const& chan)
97  {
98  auto const slep = view.read({ltPAYCHAN, chan});
99  if (!slep)
100  return std::nullopt;
101  if (auto const r = (*slep)[~sfExpiration])
102  return r.value();
103  return std::nullopt;
104  }
105 
106  static Json::Value
108  jtx::Account const& account,
109  jtx::Account const& to,
110  STAmount const& amount,
111  NetClock::duration const& settleDelay,
112  PublicKey const& pk,
113  std::optional<NetClock::time_point> const& cancelAfter = std::nullopt,
114  std::optional<std::uint32_t> const& dstTag = std::nullopt)
115  {
116  using namespace jtx;
117  Json::Value jv;
118  jv[jss::TransactionType] = jss::PaymentChannelCreate;
119  jv[jss::Flags] = tfUniversal;
120  jv[jss::Account] = account.human();
121  jv[jss::Destination] = to.human();
122  jv[jss::Amount] = amount.getJson(JsonOptions::none);
123  jv["SettleDelay"] = settleDelay.count();
124  jv["PublicKey"] = strHex(pk.slice());
125  if (cancelAfter)
126  jv["CancelAfter"] = cancelAfter->time_since_epoch().count();
127  if (dstTag)
128  jv["DestinationTag"] = *dstTag;
129  return jv;
130  }
131 
132  static Json::Value
134  jtx::Account const& account,
135  uint256 const& channel,
136  STAmount const& amount,
137  std::optional<NetClock::time_point> const& expiration = std::nullopt)
138  {
139  using namespace jtx;
140  Json::Value jv;
141  jv[jss::TransactionType] = jss::PaymentChannelFund;
142  jv[jss::Flags] = tfUniversal;
143  jv[jss::Account] = account.human();
144  jv["Channel"] = to_string(channel);
145  jv[jss::Amount] = amount.getJson(JsonOptions::none);
146  if (expiration)
147  jv["Expiration"] = expiration->time_since_epoch().count();
148  return jv;
149  }
150 
151  static Json::Value
153  jtx::Account const& account,
154  uint256 const& channel,
155  std::optional<STAmount> const& balance = std::nullopt,
156  std::optional<STAmount> const& amount = std::nullopt,
157  std::optional<Slice> const& signature = std::nullopt,
158  std::optional<PublicKey> const& pk = std::nullopt)
159  {
160  using namespace jtx;
161  Json::Value jv;
162  jv[jss::TransactionType] = jss::PaymentChannelClaim;
163  jv[jss::Flags] = tfUniversal;
164  jv[jss::Account] = account.human();
165  jv["Channel"] = to_string(channel);
166  if (amount)
167  jv[jss::Amount] = amount->getJson(JsonOptions::none);
168  if (balance)
169  jv["Balance"] = balance->getJson(JsonOptions::none);
170  if (signature)
171  jv["Signature"] = strHex(*signature);
172  if (pk)
173  jv["PublicKey"] = strHex(pk->slice());
174  return jv;
175  }
176 
177  void
179  {
180  testcase("simple");
181  using namespace jtx;
182  using namespace std::literals::chrono_literals;
183  Env env(*this);
184  auto const alice = Account("alice");
185  auto const bob = Account("bob");
186  auto USDA = alice["USD"];
187  env.fund(XRP(10000), alice, bob);
188  auto const pk = alice.pk();
189  auto const settleDelay = 100s;
190  auto const chan = channel(alice, bob, env.seq(alice));
191  env(create(alice, bob, XRP(1000), settleDelay, pk));
192  BEAST_EXPECT(channelBalance(*env.current(), chan) == XRP(0));
193  BEAST_EXPECT(channelAmount(*env.current(), chan) == XRP(1000));
194 
195  {
196  auto const preAlice = env.balance(alice);
197  env(fund(alice, chan, XRP(1000)));
198  auto const feeDrops = env.current()->fees().base;
199  BEAST_EXPECT(env.balance(alice) == preAlice - XRP(1000) - feeDrops);
200  }
201 
202  auto chanBal = channelBalance(*env.current(), chan);
203  auto chanAmt = channelAmount(*env.current(), chan);
204  BEAST_EXPECT(chanBal == XRP(0));
205  BEAST_EXPECT(chanAmt == XRP(2000));
206 
207  {
208  // bad amounts (non-xrp, negative amounts)
209  env(create(alice, bob, USDA(1000), settleDelay, pk),
210  ter(temBAD_AMOUNT));
211  env(fund(alice, chan, USDA(1000)), ter(temBAD_AMOUNT));
212  env(create(alice, bob, XRP(-1000), settleDelay, pk),
213  ter(temBAD_AMOUNT));
214  env(fund(alice, chan, XRP(-1000)), ter(temBAD_AMOUNT));
215  }
216 
217  // invalid account
218  env(create(alice, "noAccount", XRP(1000), settleDelay, pk),
219  ter(tecNO_DST));
220  // can't create channel to the same account
221  env(create(alice, alice, XRP(1000), settleDelay, pk),
222  ter(temDST_IS_SRC));
223  // invalid channel
224 
225  env(fund(
226  alice,
227  channel(alice, "noAccount", env.seq(alice) - 1),
228  XRP(1000)),
229  ter(tecNO_ENTRY));
230  // not enough funds
231  env(create(alice, bob, XRP(10000), settleDelay, pk), ter(tecUNFUNDED));
232 
233  {
234  // No signature claim with bad amounts (negative and non-xrp)
235  auto const iou = USDA(100).value();
236  auto const negXRP = XRP(-100).value();
237  auto const posXRP = XRP(100).value();
238  env(claim(alice, chan, iou, iou), ter(temBAD_AMOUNT));
239  env(claim(alice, chan, posXRP, iou), ter(temBAD_AMOUNT));
240  env(claim(alice, chan, iou, posXRP), ter(temBAD_AMOUNT));
241  env(claim(alice, chan, negXRP, negXRP), ter(temBAD_AMOUNT));
242  env(claim(alice, chan, posXRP, negXRP), ter(temBAD_AMOUNT));
243  env(claim(alice, chan, negXRP, posXRP), ter(temBAD_AMOUNT));
244  }
245  {
246  // No signature claim more than authorized
247  auto const delta = XRP(500);
248  auto const reqBal = chanBal + delta;
249  auto const authAmt = reqBal + XRP(-100);
250  assert(reqBal <= chanAmt);
251  env(claim(alice, chan, reqBal, authAmt), ter(temBAD_AMOUNT));
252  }
253  {
254  // No signature needed since the owner is claiming
255  auto const preBob = env.balance(bob);
256  auto const delta = XRP(500);
257  auto const reqBal = chanBal + delta;
258  auto const authAmt = reqBal + XRP(100);
259  assert(reqBal <= chanAmt);
260  env(claim(alice, chan, reqBal, authAmt));
261  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
262  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
263  BEAST_EXPECT(env.balance(bob) == preBob + delta);
264  chanBal = reqBal;
265  }
266  {
267  // Claim with signature
268  auto preBob = env.balance(bob);
269  auto const delta = XRP(500);
270  auto const reqBal = chanBal + delta;
271  auto const authAmt = reqBal + XRP(100);
272  assert(reqBal <= chanAmt);
273  auto const sig =
274  signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
275  env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()));
276  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
277  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
278  auto const feeDrops = env.current()->fees().base;
279  BEAST_EXPECT(env.balance(bob) == preBob + delta - feeDrops);
280  chanBal = reqBal;
281 
282  // claim again
283  preBob = env.balance(bob);
284  env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()),
286  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
287  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
288  BEAST_EXPECT(env.balance(bob) == preBob - feeDrops);
289  }
290  {
291  // Try to claim more than authorized
292  auto const preBob = env.balance(bob);
293  STAmount const authAmt = chanBal + XRP(500);
294  STAmount const reqAmt = authAmt + STAmount{1};
295  assert(reqAmt <= chanAmt);
296  auto const sig =
297  signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
298  env(claim(bob, chan, reqAmt, authAmt, Slice(sig), alice.pk()),
299  ter(temBAD_AMOUNT));
300  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
301  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
302  BEAST_EXPECT(env.balance(bob) == preBob);
303  }
304 
305  // Dst tries to fund the channel
306  env(fund(bob, chan, XRP(1000)), ter(tecNO_PERMISSION));
307  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
308  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
309 
310  {
311  // Wrong signing key
312  auto const sig = signClaimAuth(bob.pk(), bob.sk(), chan, XRP(1500));
313  env(claim(
314  bob,
315  chan,
316  XRP(1500).value(),
317  XRP(1500).value(),
318  Slice(sig),
319  bob.pk()),
320  ter(temBAD_SIGNER));
321  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
322  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
323  }
324  {
325  // Bad signature
326  auto const sig = signClaimAuth(bob.pk(), bob.sk(), chan, XRP(1500));
327  env(claim(
328  bob,
329  chan,
330  XRP(1500).value(),
331  XRP(1500).value(),
332  Slice(sig),
333  alice.pk()),
335  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
336  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
337  }
338  {
339  // Dst closes channel
340  auto const preAlice = env.balance(alice);
341  auto const preBob = env.balance(bob);
342  env(claim(bob, chan), txflags(tfClose));
343  BEAST_EXPECT(!channelExists(*env.current(), chan));
344  auto const feeDrops = env.current()->fees().base;
345  auto const delta = chanAmt - chanBal;
346  assert(delta > beast::zero);
347  BEAST_EXPECT(env.balance(alice) == preAlice + delta);
348  BEAST_EXPECT(env.balance(bob) == preBob - feeDrops);
349  }
350  }
351 
352  void
354  {
355  testcase("cancel after");
356  using namespace jtx;
357  using namespace std::literals::chrono_literals;
358  auto const alice = Account("alice");
359  auto const bob = Account("bob");
360  auto const carol = Account("carol");
361  {
362  // If dst claims after cancel after, channel closes
363  Env env(*this);
364  env.fund(XRP(10000), alice, bob);
365  auto const pk = alice.pk();
366  auto const settleDelay = 100s;
367  NetClock::time_point const cancelAfter =
368  env.current()->info().parentCloseTime + 3600s;
369  auto const channelFunds = XRP(1000);
370  auto const chan = channel(alice, bob, env.seq(alice));
371  env(create(alice, bob, channelFunds, settleDelay, pk, cancelAfter));
372  BEAST_EXPECT(channelExists(*env.current(), chan));
373  env.close(cancelAfter);
374  {
375  // dst cannot claim after cancelAfter
376  auto const chanBal = channelBalance(*env.current(), chan);
377  auto const chanAmt = channelAmount(*env.current(), chan);
378  auto preAlice = env.balance(alice);
379  auto preBob = env.balance(bob);
380  auto const delta = XRP(500);
381  auto const reqBal = chanBal + delta;
382  auto const authAmt = reqBal + XRP(100);
383  assert(reqBal <= chanAmt);
384  auto const sig =
385  signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
386  env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()));
387  auto const feeDrops = env.current()->fees().base;
388  BEAST_EXPECT(!channelExists(*env.current(), chan));
389  BEAST_EXPECT(env.balance(bob) == preBob - feeDrops);
390  BEAST_EXPECT(env.balance(alice) == preAlice + channelFunds);
391  }
392  }
393  {
394  // Third party can close after cancel after
395  Env env(*this);
396  env.fund(XRP(10000), alice, bob, carol);
397  auto const pk = alice.pk();
398  auto const settleDelay = 100s;
399  NetClock::time_point const cancelAfter =
400  env.current()->info().parentCloseTime + 3600s;
401  auto const channelFunds = XRP(1000);
402  auto const chan = channel(alice, bob, env.seq(alice));
403  env(create(alice, bob, channelFunds, settleDelay, pk, cancelAfter));
404  BEAST_EXPECT(channelExists(*env.current(), chan));
405  // third party close before cancelAfter
406  env(claim(carol, chan), txflags(tfClose), ter(tecNO_PERMISSION));
407  BEAST_EXPECT(channelExists(*env.current(), chan));
408  env.close(cancelAfter);
409  // third party close after cancelAfter
410  auto const preAlice = env.balance(alice);
411  env(claim(carol, chan), txflags(tfClose));
412  BEAST_EXPECT(!channelExists(*env.current(), chan));
413  BEAST_EXPECT(env.balance(alice) == preAlice + channelFunds);
414  }
415  }
416 
417  void
419  {
420  testcase("expiration");
421  using namespace jtx;
422  using namespace std::literals::chrono_literals;
423  Env env(*this);
424  auto const alice = Account("alice");
425  auto const bob = Account("bob");
426  auto const carol = Account("carol");
427  env.fund(XRP(10000), alice, bob, carol);
428  auto const pk = alice.pk();
429  auto const settleDelay = 3600s;
430  auto const closeTime = env.current()->info().parentCloseTime;
431  auto const minExpiration = closeTime + settleDelay;
432  NetClock::time_point const cancelAfter = closeTime + 7200s;
433  auto const channelFunds = XRP(1000);
434  auto const chan = channel(alice, bob, env.seq(alice));
435  env(create(alice, bob, channelFunds, settleDelay, pk, cancelAfter));
436  BEAST_EXPECT(channelExists(*env.current(), chan));
437  BEAST_EXPECT(!channelExpiration(*env.current(), chan));
438  // Owner closes, will close after settleDelay
439  env(claim(alice, chan), txflags(tfClose));
440  auto counts = [](auto const& t) {
441  return t.time_since_epoch().count();
442  };
443  BEAST_EXPECT(
444  *channelExpiration(*env.current(), chan) == counts(minExpiration));
445  // increase the expiration time
446  env(fund(
447  alice, chan, XRP(1), NetClock::time_point{minExpiration + 100s}));
448  BEAST_EXPECT(
449  *channelExpiration(*env.current(), chan) ==
450  counts(minExpiration) + 100);
451  // decrease the expiration, but still above minExpiration
452  env(fund(
453  alice, chan, XRP(1), NetClock::time_point{minExpiration + 50s}));
454  BEAST_EXPECT(
455  *channelExpiration(*env.current(), chan) ==
456  counts(minExpiration) + 50);
457  // decrease the expiration below minExpiration
458  env(fund(
459  alice, chan, XRP(1), NetClock::time_point{minExpiration - 50s}),
461  BEAST_EXPECT(
462  *channelExpiration(*env.current(), chan) ==
463  counts(minExpiration) + 50);
464  env(claim(bob, chan), txflags(tfRenew), ter(tecNO_PERMISSION));
465  BEAST_EXPECT(
466  *channelExpiration(*env.current(), chan) ==
467  counts(minExpiration) + 50);
468  env(claim(alice, chan), txflags(tfRenew));
469  BEAST_EXPECT(!channelExpiration(*env.current(), chan));
470  // decrease the expiration below minExpiration
471  env(fund(
472  alice, chan, XRP(1), NetClock::time_point{minExpiration - 50s}),
474  BEAST_EXPECT(!channelExpiration(*env.current(), chan));
475  env(fund(alice, chan, XRP(1), NetClock::time_point{minExpiration}));
476  env.close(minExpiration);
477  // Try to extend the expiration after the expiration has already passed
478  env(fund(
479  alice, chan, XRP(1), NetClock::time_point{minExpiration + 1000s}));
480  BEAST_EXPECT(!channelExists(*env.current(), chan));
481  }
482 
483  void
485  {
486  testcase("settle delay");
487  using namespace jtx;
488  using namespace std::literals::chrono_literals;
489  Env env(*this);
490  auto const alice = Account("alice");
491  auto const bob = Account("bob");
492  env.fund(XRP(10000), alice, bob);
493  auto const pk = alice.pk();
494  auto const settleDelay = 3600s;
495  NetClock::time_point const settleTimepoint =
496  env.current()->info().parentCloseTime + settleDelay;
497  auto const channelFunds = XRP(1000);
498  auto const chan = channel(alice, bob, env.seq(alice));
499  env(create(alice, bob, channelFunds, settleDelay, pk));
500  BEAST_EXPECT(channelExists(*env.current(), chan));
501  // Owner closes, will close after settleDelay
502  env(claim(alice, chan), txflags(tfClose));
503  BEAST_EXPECT(channelExists(*env.current(), chan));
504  env.close(settleTimepoint - settleDelay / 2);
505  {
506  // receiver can still claim
507  auto const chanBal = channelBalance(*env.current(), chan);
508  auto const chanAmt = channelAmount(*env.current(), chan);
509  auto preBob = env.balance(bob);
510  auto const delta = XRP(500);
511  auto const reqBal = chanBal + delta;
512  auto const authAmt = reqBal + XRP(100);
513  assert(reqBal <= chanAmt);
514  auto const sig =
515  signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
516  env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()));
517  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
518  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
519  auto const feeDrops = env.current()->fees().base;
520  BEAST_EXPECT(env.balance(bob) == preBob + delta - feeDrops);
521  }
522  env.close(settleTimepoint);
523  {
524  // past settleTime, channel will close
525  auto const chanBal = channelBalance(*env.current(), chan);
526  auto const chanAmt = channelAmount(*env.current(), chan);
527  auto const preAlice = env.balance(alice);
528  auto preBob = env.balance(bob);
529  auto const delta = XRP(500);
530  auto const reqBal = chanBal + delta;
531  auto const authAmt = reqBal + XRP(100);
532  assert(reqBal <= chanAmt);
533  auto const sig =
534  signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
535  env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()));
536  BEAST_EXPECT(!channelExists(*env.current(), chan));
537  auto const feeDrops = env.current()->fees().base;
538  BEAST_EXPECT(env.balance(alice) == preAlice + chanAmt - chanBal);
539  BEAST_EXPECT(env.balance(bob) == preBob - feeDrops);
540  }
541  }
542 
543  void
545  {
546  testcase("close dry");
547  using namespace jtx;
548  using namespace std::literals::chrono_literals;
549  Env env(*this);
550  auto const alice = Account("alice");
551  auto const bob = Account("bob");
552  env.fund(XRP(10000), alice, bob);
553  auto const pk = alice.pk();
554  auto const settleDelay = 3600s;
555  auto const channelFunds = XRP(1000);
556  auto const chan = channel(alice, bob, env.seq(alice));
557  env(create(alice, bob, channelFunds, settleDelay, pk));
558  BEAST_EXPECT(channelExists(*env.current(), chan));
559  // Owner tries to close channel, but it will remain open (settle delay)
560  env(claim(alice, chan), txflags(tfClose));
561  BEAST_EXPECT(channelExists(*env.current(), chan));
562  {
563  // claim the entire amount
564  auto const preBob = env.balance(bob);
565  env(claim(alice, chan, channelFunds.value(), channelFunds.value()));
566  BEAST_EXPECT(channelBalance(*env.current(), chan) == channelFunds);
567  BEAST_EXPECT(env.balance(bob) == preBob + channelFunds);
568  }
569  auto const preAlice = env.balance(alice);
570  // Channel is now dry, can close before expiration date
571  env(claim(alice, chan), txflags(tfClose));
572  BEAST_EXPECT(!channelExists(*env.current(), chan));
573  auto const feeDrops = env.current()->fees().base;
574  BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops);
575  }
576 
577  void
579  {
580  // auth amount defaults to balance if not present
581  testcase("default amount");
582  using namespace jtx;
583  using namespace std::literals::chrono_literals;
584  Env env(*this);
585  auto const alice = Account("alice");
586  auto const bob = Account("bob");
587  env.fund(XRP(10000), alice, bob);
588  auto const pk = alice.pk();
589  auto const settleDelay = 3600s;
590  auto const channelFunds = XRP(1000);
591  auto const chan = channel(alice, bob, env.seq(alice));
592  env(create(alice, bob, channelFunds, settleDelay, pk));
593  BEAST_EXPECT(channelExists(*env.current(), chan));
594  // Owner tries to close channel, but it will remain open (settle delay)
595  env(claim(alice, chan), txflags(tfClose));
596  BEAST_EXPECT(channelExists(*env.current(), chan));
597  {
598  auto chanBal = channelBalance(*env.current(), chan);
599  auto chanAmt = channelAmount(*env.current(), chan);
600  auto const preBob = env.balance(bob);
601 
602  auto const delta = XRP(500);
603  auto const reqBal = chanBal + delta;
604  assert(reqBal <= chanAmt);
605  auto const sig =
606  signClaimAuth(alice.pk(), alice.sk(), chan, reqBal);
607  env(claim(bob, chan, reqBal, std::nullopt, Slice(sig), alice.pk()));
608  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
609  auto const feeDrops = env.current()->fees().base;
610  BEAST_EXPECT(env.balance(bob) == preBob + delta - feeDrops);
611  chanBal = reqBal;
612  }
613  {
614  // Claim again
615  auto chanBal = channelBalance(*env.current(), chan);
616  auto chanAmt = channelAmount(*env.current(), chan);
617  auto const preBob = env.balance(bob);
618 
619  auto const delta = XRP(500);
620  auto const reqBal = chanBal + delta;
621  assert(reqBal <= chanAmt);
622  auto const sig =
623  signClaimAuth(alice.pk(), alice.sk(), chan, reqBal);
624  env(claim(bob, chan, reqBal, std::nullopt, Slice(sig), alice.pk()));
625  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
626  auto const feeDrops = env.current()->fees().base;
627  BEAST_EXPECT(env.balance(bob) == preBob + delta - feeDrops);
628  chanBal = reqBal;
629  }
630  }
631 
632  void
634  {
635  // auth amount defaults to balance if not present
636  testcase("Disallow XRP");
637  using namespace jtx;
638  using namespace std::literals::chrono_literals;
639 
640  auto const alice = Account("alice");
641  auto const bob = Account("bob");
642  {
643  // Create a channel where dst disallows XRP
645  env.fund(XRP(10000), alice, bob);
646  env(fset(bob, asfDisallowXRP));
647  auto const chan = channel(alice, bob, env.seq(alice));
648  env(create(alice, bob, XRP(1000), 3600s, alice.pk()),
649  ter(tecNO_TARGET));
650  BEAST_EXPECT(!channelExists(*env.current(), chan));
651  }
652  {
653  // Create a channel where dst disallows XRP. Ignore that flag,
654  // since it's just advisory.
655  Env env(*this);
656  env.fund(XRP(10000), alice, bob);
657  env(fset(bob, asfDisallowXRP));
658  auto const chan = channel(alice, bob, env.seq(alice));
659  env(create(alice, bob, XRP(1000), 3600s, alice.pk()));
660  BEAST_EXPECT(channelExists(*env.current(), chan));
661  }
662 
663  {
664  // Claim to a channel where dst disallows XRP
665  // (channel is created before disallow xrp is set)
667  env.fund(XRP(10000), alice, bob);
668  auto const chan = channel(alice, bob, env.seq(alice));
669  env(create(alice, bob, XRP(1000), 3600s, alice.pk()));
670  BEAST_EXPECT(channelExists(*env.current(), chan));
671 
672  env(fset(bob, asfDisallowXRP));
673  auto const reqBal = XRP(500).value();
674  env(claim(alice, chan, reqBal, reqBal), ter(tecNO_TARGET));
675  }
676  {
677  // Claim to a channel where dst disallows XRP (channel is
678  // created before disallow xrp is set). Ignore that flag
679  // since it is just advisory.
680  Env env(*this);
681  env.fund(XRP(10000), alice, bob);
682  auto const chan = channel(alice, bob, env.seq(alice));
683  env(create(alice, bob, XRP(1000), 3600s, alice.pk()));
684  BEAST_EXPECT(channelExists(*env.current(), chan));
685 
686  env(fset(bob, asfDisallowXRP));
687  auto const reqBal = XRP(500).value();
688  env(claim(alice, chan, reqBal, reqBal));
689  }
690  }
691 
692  void
694  {
695  // auth amount defaults to balance if not present
696  testcase("Dst Tag");
697  using namespace jtx;
698  using namespace std::literals::chrono_literals;
699  // Create a channel where dst disallows XRP
700  Env env(*this);
701  auto const alice = Account("alice");
702  auto const bob = Account("bob");
703  env.fund(XRP(10000), alice, bob);
704  env(fset(bob, asfRequireDest));
705  auto const pk = alice.pk();
706  auto const settleDelay = 3600s;
707  auto const channelFunds = XRP(1000);
708  {
709  auto const chan = channel(alice, bob, env.seq(alice));
710  env(create(alice, bob, channelFunds, settleDelay, pk),
712  BEAST_EXPECT(!channelExists(*env.current(), chan));
713  }
714  {
715  auto const chan = channel(alice, bob, env.seq(alice));
716  env(create(
717  alice, bob, channelFunds, settleDelay, pk, std::nullopt, 1));
718  BEAST_EXPECT(channelExists(*env.current(), chan));
719  }
720  }
721 
722  void
724  {
725  testcase("Deposit Authorization");
726  using namespace jtx;
727  using namespace std::literals::chrono_literals;
728 
729  auto const alice = Account("alice");
730  auto const bob = Account("bob");
731  auto const carol = Account("carol");
732  auto USDA = alice["USD"];
733  {
734  Env env(*this);
735  env.fund(XRP(10000), alice, bob, carol);
736 
737  env(fset(bob, asfDepositAuth));
738  env.close();
739 
740  auto const pk = alice.pk();
741  auto const settleDelay = 100s;
742  auto const chan = channel(alice, bob, env.seq(alice));
743  env(create(alice, bob, XRP(1000), settleDelay, pk));
744  env.close();
745 
746  BEAST_EXPECT(channelBalance(*env.current(), chan) == XRP(0));
747  BEAST_EXPECT(channelAmount(*env.current(), chan) == XRP(1000));
748 
749  // alice can add more funds to the channel even though bob has
750  // asfDepositAuth set.
751  env(fund(alice, chan, XRP(1000)));
752  env.close();
753 
754  // alice claims. Fails because bob's lsfDepositAuth flag is set.
755  env(claim(alice, chan, XRP(500).value(), XRP(500).value()),
757  env.close();
758 
759  // Claim with signature
760  auto const baseFee = env.current()->fees().base;
761  auto const preBob = env.balance(bob);
762  {
763  auto const delta = XRP(500).value();
764  auto const sig = signClaimAuth(pk, alice.sk(), chan, delta);
765 
766  // alice claims with signature. Fails since bob has
767  // lsfDepositAuth flag set.
768  env(claim(alice, chan, delta, delta, Slice(sig), pk),
770  env.close();
771  BEAST_EXPECT(env.balance(bob) == preBob);
772 
773  // bob claims but omits the signature. Fails because only
774  // alice can claim without a signature.
775  env(claim(bob, chan, delta, delta), ter(temBAD_SIGNATURE));
776  env.close();
777 
778  // bob claims with signature. Succeeds even though bob's
779  // lsfDepositAuth flag is set since bob submitted the
780  // transaction.
781  env(claim(bob, chan, delta, delta, Slice(sig), pk));
782  env.close();
783  BEAST_EXPECT(env.balance(bob) == preBob + delta - baseFee);
784  }
785  {
786  // Explore the limits of deposit preauthorization.
787  auto const delta = XRP(600).value();
788  auto const sig = signClaimAuth(pk, alice.sk(), chan, delta);
789 
790  // carol claims and fails. Only channel participants (bob or
791  // alice) may claim.
792  env(claim(carol, chan, delta, delta, Slice(sig), pk),
794  env.close();
795 
796  // bob preauthorizes carol for deposit. But after that carol
797  // still can't claim since only channel participants may claim.
798  env(deposit::auth(bob, carol));
799  env.close();
800 
801  env(claim(carol, chan, delta, delta, Slice(sig), pk),
803 
804  // Since alice is not preauthorized she also may not claim
805  // for bob.
806  env(claim(alice, chan, delta, delta, Slice(sig), pk),
808  env.close();
809 
810  // However if bob preauthorizes alice for deposit then she can
811  // successfully submit a claim.
812  env(deposit::auth(bob, alice));
813  env.close();
814 
815  env(claim(alice, chan, delta, delta, Slice(sig), pk));
816  env.close();
817 
818  BEAST_EXPECT(
819  env.balance(bob) == preBob + delta - (3 * baseFee));
820  }
821  {
822  // bob removes preauthorization of alice. Once again she
823  // cannot submit a claim.
824  auto const delta = XRP(800).value();
825 
826  env(deposit::unauth(bob, alice));
827  env.close();
828 
829  // alice claims and fails since she is no longer preauthorized.
830  env(claim(alice, chan, delta, delta), ter(tecNO_PERMISSION));
831  env.close();
832 
833  // bob clears lsfDepositAuth. Now alice can claim.
834  env(fclear(bob, asfDepositAuth));
835  env.close();
836 
837  // alice claims successfully.
838  env(claim(alice, chan, delta, delta));
839  env.close();
840  BEAST_EXPECT(
841  env.balance(bob) == preBob + XRP(800) - (5 * baseFee));
842  }
843  }
844  }
845 
846  void
848  {
849  // auth amount defaults to balance if not present
850  testcase("Multiple channels to the same account");
851  using namespace jtx;
852  using namespace std::literals::chrono_literals;
853  Env env(*this);
854  auto const alice = Account("alice");
855  auto const bob = Account("bob");
856  env.fund(XRP(10000), alice, bob);
857  auto const pk = alice.pk();
858  auto const settleDelay = 3600s;
859  auto const channelFunds = XRP(1000);
860  auto const chan1 = channel(alice, bob, env.seq(alice));
861  env(create(alice, bob, channelFunds, settleDelay, pk));
862  BEAST_EXPECT(channelExists(*env.current(), chan1));
863  auto const chan2 = channel(alice, bob, env.seq(alice));
864  env(create(alice, bob, channelFunds, settleDelay, pk));
865  BEAST_EXPECT(channelExists(*env.current(), chan2));
866  BEAST_EXPECT(chan1 != chan2);
867  }
868 
869  void
871  {
872  testcase("AccountChannels RPC");
873 
874  using namespace jtx;
875  using namespace std::literals::chrono_literals;
876  Env env(*this);
877  auto const alice = Account("alice");
878  auto const bob = Account("bob");
879  auto const charlie = Account("charlie", KeyType::ed25519);
880  env.fund(XRP(10000), alice, bob, charlie);
881  auto const pk = alice.pk();
882  auto const settleDelay = 3600s;
883  auto const channelFunds = XRP(1000);
884  auto const chan1Str = to_string(channel(alice, bob, env.seq(alice)));
885  env(create(alice, bob, channelFunds, settleDelay, pk));
886  env.close();
887  {
888  auto const r =
889  env.rpc("account_channels", alice.human(), bob.human());
890  BEAST_EXPECT(r[jss::result][jss::channels].size() == 1);
891  BEAST_EXPECT(
892  r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str);
893  BEAST_EXPECT(r[jss::result][jss::validated]);
894  }
895  {
896  auto const r = env.rpc("account_channels", alice.human());
897  BEAST_EXPECT(r[jss::result][jss::channels].size() == 1);
898  BEAST_EXPECT(
899  r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str);
900  BEAST_EXPECT(r[jss::result][jss::validated]);
901  }
902  {
903  auto const r =
904  env.rpc("account_channels", bob.human(), alice.human());
905  BEAST_EXPECT(r[jss::result][jss::channels].size() == 0);
906  BEAST_EXPECT(r[jss::result][jss::validated]);
907  }
908  auto const chan2Str = to_string(channel(alice, bob, env.seq(alice)));
909  env(create(alice, bob, channelFunds, settleDelay, pk));
910  env.close();
911  {
912  auto const r =
913  env.rpc("account_channels", alice.human(), bob.human());
914  BEAST_EXPECT(r[jss::result][jss::channels].size() == 2);
915  BEAST_EXPECT(r[jss::result][jss::validated]);
916  BEAST_EXPECT(chan1Str != chan2Str);
917  for (auto const& c : {chan1Str, chan2Str})
918  BEAST_EXPECT(
919  r[jss::result][jss::channels][0u][jss::channel_id] == c ||
920  r[jss::result][jss::channels][1u][jss::channel_id] == c);
921  }
922  }
923 
924  void
926  {
927  testcase("Account channels RPC markers");
928 
929  using namespace test::jtx;
930  using namespace std::literals;
931 
932  auto const alice = Account("alice");
933  auto const bobs = []() -> std::vector<Account> {
934  int const n = 10;
936  r.reserve(n);
937  for (int i = 0; i < n; ++i)
938  {
939  r.emplace_back("bob"s + std::to_string(i));
940  }
941  return r;
942  }();
943 
944  Env env(*this);
945  env.fund(XRP(10000), alice);
946  for (auto const& a : bobs)
947  {
948  env.fund(XRP(10000), a);
949  env.close();
950  }
951 
952  {
953  // create a channel from alice to every bob account
954  auto const settleDelay = 3600s;
955  auto const channelFunds = XRP(1);
956  for (auto const& b : bobs)
957  {
958  env(create(alice, b, channelFunds, settleDelay, alice.pk()));
959  }
960  }
961 
962  auto testLimit = [](test::jtx::Env& env,
963  test::jtx::Account const& src,
964  std::optional<int> limit = std::nullopt,
965  Json::Value const& marker = Json::nullValue,
967  std::nullopt) {
968  Json::Value jvc;
969  jvc[jss::account] = src.human();
970  if (dst)
971  jvc[jss::destination_account] = dst->human();
972  if (limit)
973  jvc[jss::limit] = *limit;
974  if (marker)
975  jvc[jss::marker] = marker;
976 
977  return env.rpc(
978  "json", "account_channels", to_string(jvc))[jss::result];
979  };
980 
981  {
982  // No marker
983  auto const r = testLimit(env, alice);
984  BEAST_EXPECT(r.isMember(jss::channels));
985  BEAST_EXPECT(r[jss::channels].size() == bobs.size());
986  }
987 
988  auto const bobsB58 = [&bobs]() -> std::set<std::string> {
990  for (auto const& a : bobs)
991  r.insert(a.human());
992  return r;
993  }();
994 
995  for (int limit = 1; limit < bobs.size() + 1; ++limit)
996  {
997  auto leftToFind = bobsB58;
998  auto const numFull = bobs.size() / limit;
999  auto const numNonFull = bobs.size() % limit ? 1 : 0;
1000 
1001  Json::Value marker = Json::nullValue;
1002 
1003  auto const testIt = [&](bool expectMarker, int expectedBatchSize) {
1004  auto const r = testLimit(env, alice, limit, marker);
1005  BEAST_EXPECT(!expectMarker || r.isMember(jss::marker));
1006  if (r.isMember(jss::marker))
1007  marker = r[jss::marker];
1008  BEAST_EXPECT(r[jss::channels].size() == expectedBatchSize);
1009  auto const c = r[jss::channels];
1010  auto const s = r[jss::channels].size();
1011  for (int j = 0; j < s; ++j)
1012  {
1013  auto const dstAcc =
1014  c[j][jss::destination_account].asString();
1015  BEAST_EXPECT(leftToFind.count(dstAcc));
1016  leftToFind.erase(dstAcc);
1017  }
1018  };
1019 
1020  for (int i = 0; i < numFull; ++i)
1021  {
1022  bool const expectMarker = (numNonFull != 0 || i < numFull - 1);
1023  testIt(expectMarker, limit);
1024  }
1025 
1026  if (numNonFull)
1027  {
1028  testIt(false, bobs.size() % limit);
1029  }
1030  BEAST_EXPECT(leftToFind.empty());
1031  }
1032 
1033  {
1034  // degenerate case
1035  auto const r = testLimit(env, alice, 0);
1036  BEAST_EXPECT(r.isMember(jss::error_message));
1037  }
1038  }
1039 
1040  void
1042  {
1043  // Check that the account_channels command only returns channels owned
1044  // by the account
1045  testcase("Account channels RPC owner only");
1046 
1047  using namespace test::jtx;
1048  using namespace std::literals;
1049 
1050  auto const alice = Account("alice");
1051  auto const bob = Account("bob");
1052  Env env(*this);
1053  env.fund(XRP(10000), alice, bob);
1054 
1055  // Create a channel from alice to bob and from bob to alice
1056  // When retrieving alice's channels, it should only retrieve the
1057  // channels where alice is the source, not the destination
1058  auto const settleDelay = 3600s;
1059  auto const channelFunds = XRP(1000);
1060  env(create(alice, bob, channelFunds, settleDelay, alice.pk()));
1061  env(create(bob, alice, channelFunds, settleDelay, bob.pk()));
1062 
1063  auto const r = [&] {
1064  Json::Value jvc;
1065  jvc[jss::account] = alice.human();
1066 
1067  return env.rpc(
1068  "json", "account_channels", to_string(jvc))[jss::result];
1069  }();
1070  BEAST_EXPECT(r.isMember(jss::channels));
1071  BEAST_EXPECT(r[jss::channels].size() == 1);
1072  BEAST_EXPECT(
1073  r[jss::channels][0u][jss::destination_account].asString() ==
1074  bob.human());
1075  }
1076 
1077  void
1079  {
1080  testcase("PayChan Auth/Verify RPC");
1081  using namespace jtx;
1082  using namespace std::literals::chrono_literals;
1083  Env env(*this);
1084  auto const alice = Account("alice");
1085  auto const bob = Account("bob");
1086  auto const charlie = Account("charlie", KeyType::ed25519);
1087  env.fund(XRP(10000), alice, bob, charlie);
1088  auto const pk = alice.pk();
1089  auto const settleDelay = 3600s;
1090  auto const channelFunds = XRP(1000);
1091  auto const chan1Str = to_string(channel(alice, bob, env.seq(alice)));
1092  env(create(alice, bob, channelFunds, settleDelay, pk));
1093  env.close();
1094  std::string chan1PkStr;
1095  {
1096  auto const r =
1097  env.rpc("account_channels", alice.human(), bob.human());
1098  BEAST_EXPECT(r[jss::result][jss::channels].size() == 1);
1099  BEAST_EXPECT(
1100  r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str);
1101  BEAST_EXPECT(r[jss::result][jss::validated]);
1102  chan1PkStr =
1103  r[jss::result][jss::channels][0u][jss::public_key].asString();
1104  }
1105  {
1106  auto const r = env.rpc("account_channels", alice.human());
1107  BEAST_EXPECT(r[jss::result][jss::channels].size() == 1);
1108  BEAST_EXPECT(
1109  r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str);
1110  BEAST_EXPECT(r[jss::result][jss::validated]);
1111  chan1PkStr =
1112  r[jss::result][jss::channels][0u][jss::public_key].asString();
1113  }
1114  {
1115  auto const r =
1116  env.rpc("account_channels", bob.human(), alice.human());
1117  BEAST_EXPECT(r[jss::result][jss::channels].size() == 0);
1118  BEAST_EXPECT(r[jss::result][jss::validated]);
1119  }
1120  auto const chan2Str = to_string(channel(alice, bob, env.seq(alice)));
1121  env(create(alice, bob, channelFunds, settleDelay, pk));
1122  env.close();
1123  {
1124  auto const r =
1125  env.rpc("account_channels", alice.human(), bob.human());
1126  BEAST_EXPECT(r[jss::result][jss::channels].size() == 2);
1127  BEAST_EXPECT(r[jss::result][jss::validated]);
1128  BEAST_EXPECT(chan1Str != chan2Str);
1129  for (auto const& c : {chan1Str, chan2Str})
1130  BEAST_EXPECT(
1131  r[jss::result][jss::channels][0u][jss::channel_id] == c ||
1132  r[jss::result][jss::channels][1u][jss::channel_id] == c);
1133  }
1134 
1135  auto sliceToHex = [](Slice const& slice) {
1136  std::string s;
1137  s.reserve(2 * slice.size());
1138  for (int i = 0; i < slice.size(); ++i)
1139  {
1140  s += "0123456789ABCDEF"[((slice[i] & 0xf0) >> 4)];
1141  s += "0123456789ABCDEF"[((slice[i] & 0x0f) >> 0)];
1142  }
1143  return s;
1144  };
1145 
1146  {
1147  // Verify chan1 auth
1148  auto const rs =
1149  env.rpc("channel_authorize", "alice", chan1Str, "1000");
1150  auto const sig = rs[jss::result][jss::signature].asString();
1151  BEAST_EXPECT(!sig.empty());
1152  {
1153  auto const rv = env.rpc(
1154  "channel_verify", chan1PkStr, chan1Str, "1000", sig);
1155  BEAST_EXPECT(rv[jss::result][jss::signature_verified].asBool());
1156  }
1157 
1158  {
1159  // use pk hex to verify
1160  auto const pkAsHex = sliceToHex(pk.slice());
1161  auto const rv =
1162  env.rpc("channel_verify", pkAsHex, chan1Str, "1000", sig);
1163  BEAST_EXPECT(rv[jss::result][jss::signature_verified].asBool());
1164  }
1165  {
1166  // malformed amount
1167  auto const pkAsHex = sliceToHex(pk.slice());
1168  auto rv =
1169  env.rpc("channel_verify", pkAsHex, chan1Str, "1000x", sig);
1170  BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
1171  rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1000 ", sig);
1172  BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
1173  rv = env.rpc("channel_verify", pkAsHex, chan1Str, "x1000", sig);
1174  BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
1175  rv = env.rpc("channel_verify", pkAsHex, chan1Str, "x", sig);
1176  BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
1177  rv = env.rpc("channel_verify", pkAsHex, chan1Str, " ", sig);
1178  BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
1179  rv = env.rpc(
1180  "channel_verify", pkAsHex, chan1Str, "1000 1000", sig);
1181  BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
1182  rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1,000", sig);
1183  BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
1184  rv = env.rpc("channel_verify", pkAsHex, chan1Str, " 1000", sig);
1185  BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
1186  rv = env.rpc("channel_verify", pkAsHex, chan1Str, "", sig);
1187  BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
1188  }
1189  {
1190  // malformed channel
1191  auto const pkAsHex = sliceToHex(pk.slice());
1192  auto chan1StrBad = chan1Str;
1193  chan1StrBad.pop_back();
1194  auto rv = env.rpc(
1195  "channel_verify", pkAsHex, chan1StrBad, "1000", sig);
1196  BEAST_EXPECT(rv[jss::error] == "channelMalformed");
1197  rv = env.rpc("channel_authorize", "alice", chan1StrBad, "1000");
1198  BEAST_EXPECT(rv[jss::error] == "channelMalformed");
1199 
1200  chan1StrBad = chan1Str;
1201  chan1StrBad.push_back('0');
1202  rv = env.rpc(
1203  "channel_verify", pkAsHex, chan1StrBad, "1000", sig);
1204  BEAST_EXPECT(rv[jss::error] == "channelMalformed");
1205  rv = env.rpc("channel_authorize", "alice", chan1StrBad, "1000");
1206  BEAST_EXPECT(rv[jss::error] == "channelMalformed");
1207 
1208  chan1StrBad = chan1Str;
1209  chan1StrBad.back() = 'x';
1210  rv = env.rpc(
1211  "channel_verify", pkAsHex, chan1StrBad, "1000", sig);
1212  BEAST_EXPECT(rv[jss::error] == "channelMalformed");
1213  rv = env.rpc("channel_authorize", "alice", chan1StrBad, "1000");
1214  BEAST_EXPECT(rv[jss::error] == "channelMalformed");
1215  }
1216  {
1217  // give an ill formed base 58 public key
1218  auto illFormedPk = chan1PkStr.substr(0, chan1PkStr.size() - 1);
1219  auto const rv = env.rpc(
1220  "channel_verify", illFormedPk, chan1Str, "1000", sig);
1221  BEAST_EXPECT(
1222  !rv[jss::result][jss::signature_verified].asBool());
1223  }
1224  {
1225  // give an ill formed hex public key
1226  auto const pkAsHex = sliceToHex(pk.slice());
1227  auto illFormedPk = pkAsHex.substr(0, chan1PkStr.size() - 1);
1228  auto const rv = env.rpc(
1229  "channel_verify", illFormedPk, chan1Str, "1000", sig);
1230  BEAST_EXPECT(
1231  !rv[jss::result][jss::signature_verified].asBool());
1232  }
1233  }
1234  {
1235  // Try to verify chan2 auth with chan1 key
1236  auto const rs =
1237  env.rpc("channel_authorize", "alice", chan2Str, "1000");
1238  auto const sig = rs[jss::result][jss::signature].asString();
1239  BEAST_EXPECT(!sig.empty());
1240  {
1241  auto const rv = env.rpc(
1242  "channel_verify", chan1PkStr, chan1Str, "1000", sig);
1243  BEAST_EXPECT(
1244  !rv[jss::result][jss::signature_verified].asBool());
1245  }
1246  {
1247  // use pk hex to verify
1248  auto const pkAsHex = sliceToHex(pk.slice());
1249  auto const rv =
1250  env.rpc("channel_verify", pkAsHex, chan1Str, "1000", sig);
1251  BEAST_EXPECT(
1252  !rv[jss::result][jss::signature_verified].asBool());
1253  }
1254  }
1255  {
1256  // Try to explicitly specify secp256k1 and Ed25519 keys:
1257  auto const chan =
1258  to_string(channel(charlie, alice, env.seq(charlie)));
1259  env(create(
1260  charlie, alice, channelFunds, settleDelay, charlie.pk()));
1261  env.close();
1262 
1263  std::string cpk;
1264  {
1265  auto const r =
1266  env.rpc("account_channels", charlie.human(), alice.human());
1267  BEAST_EXPECT(r[jss::result][jss::channels].size() == 1);
1268  BEAST_EXPECT(
1269  r[jss::result][jss::channels][0u][jss::channel_id] == chan);
1270  BEAST_EXPECT(r[jss::result][jss::validated]);
1271  cpk = r[jss::result][jss::channels][0u][jss::public_key]
1272  .asString();
1273  }
1274 
1275  // Try to authorize without specifying a key type, expect an error:
1276  auto const rs =
1277  env.rpc("channel_authorize", "charlie", chan, "1000");
1278  auto const sig = rs[jss::result][jss::signature].asString();
1279  BEAST_EXPECT(!sig.empty());
1280  {
1281  auto const rv =
1282  env.rpc("channel_verify", cpk, chan, "1000", sig);
1283  BEAST_EXPECT(
1284  !rv[jss::result][jss::signature_verified].asBool());
1285  }
1286 
1287  // Try to authorize using an unknown key type, except an error:
1288  auto const rs1 =
1289  env.rpc("channel_authorize", "charlie", "nyx", chan, "1000");
1290  BEAST_EXPECT(rs1[jss::error] == "badKeyType");
1291 
1292  // Try to authorize using secp256k1; the authorization _should_
1293  // succeed but the verification should fail:
1294  auto const rs2 = env.rpc(
1295  "channel_authorize", "charlie", "secp256k1", chan, "1000");
1296  auto const sig2 = rs2[jss::result][jss::signature].asString();
1297  BEAST_EXPECT(!sig2.empty());
1298  {
1299  auto const rv =
1300  env.rpc("channel_verify", cpk, chan, "1000", sig2);
1301  BEAST_EXPECT(
1302  !rv[jss::result][jss::signature_verified].asBool());
1303  }
1304 
1305  // Try to authorize using Ed25519; expect success:
1306  auto const rs3 = env.rpc(
1307  "channel_authorize", "charlie", "ed25519", chan, "1000");
1308  auto const sig3 = rs3[jss::result][jss::signature].asString();
1309  BEAST_EXPECT(!sig3.empty());
1310  {
1311  auto const rv =
1312  env.rpc("channel_verify", cpk, chan, "1000", sig3);
1313  BEAST_EXPECT(rv[jss::result][jss::signature_verified].asBool());
1314  }
1315  }
1316 
1317  {
1318  // send malformed amounts rpc requests
1319  auto rs = env.rpc("channel_authorize", "alice", chan1Str, "1000x");
1320  BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
1321  rs = env.rpc("channel_authorize", "alice", chan1Str, "x1000");
1322  BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
1323  rs = env.rpc("channel_authorize", "alice", chan1Str, "x");
1324  BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
1325  {
1326  // Missing channel_id
1328  args[jss::amount] = "2000";
1329  args[jss::key_type] = "secp256k1";
1330  args[jss::passphrase] = "passphrase_can_be_anything";
1331  rs = env.rpc(
1332  "json",
1333  "channel_authorize",
1334  args.toStyledString())[jss::result];
1335  BEAST_EXPECT(rs[jss::error] == "invalidParams");
1336  }
1337  {
1338  // Missing amount
1340  args[jss::channel_id] = chan1Str;
1341  args[jss::key_type] = "secp256k1";
1342  args[jss::passphrase] = "passphrase_can_be_anything";
1343  rs = env.rpc(
1344  "json",
1345  "channel_authorize",
1346  args.toStyledString())[jss::result];
1347  BEAST_EXPECT(rs[jss::error] == "invalidParams");
1348  }
1349  {
1350  // Missing key_type and no secret.
1352  args[jss::amount] = "2000";
1353  args[jss::channel_id] = chan1Str;
1354  args[jss::passphrase] = "passphrase_can_be_anything";
1355  rs = env.rpc(
1356  "json",
1357  "channel_authorize",
1358  args.toStyledString())[jss::result];
1359  BEAST_EXPECT(rs[jss::error] == "invalidParams");
1360  }
1361  {
1362  // Both passphrase and seed specified.
1364  args[jss::amount] = "2000";
1365  args[jss::channel_id] = chan1Str;
1366  args[jss::key_type] = "secp256k1";
1367  args[jss::passphrase] = "passphrase_can_be_anything";
1368  args[jss::seed] = "seed can be anything";
1369  rs = env.rpc(
1370  "json",
1371  "channel_authorize",
1372  args.toStyledString())[jss::result];
1373  BEAST_EXPECT(rs[jss::error] == "invalidParams");
1374  }
1375  {
1376  // channel_id is not exact hex.
1378  args[jss::amount] = "2000";
1379  args[jss::channel_id] = chan1Str + "1";
1380  args[jss::key_type] = "secp256k1";
1381  args[jss::passphrase] = "passphrase_can_be_anything";
1382  rs = env.rpc(
1383  "json",
1384  "channel_authorize",
1385  args.toStyledString())[jss::result];
1386  BEAST_EXPECT(rs[jss::error] == "channelMalformed");
1387  }
1388  {
1389  // amount is not a string
1391  args[jss::amount] = 2000;
1392  args[jss::channel_id] = chan1Str;
1393  args[jss::key_type] = "secp256k1";
1394  args[jss::passphrase] = "passphrase_can_be_anything";
1395  rs = env.rpc(
1396  "json",
1397  "channel_authorize",
1398  args.toStyledString())[jss::result];
1399  BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
1400  }
1401  {
1402  // Amount is not a decimal string.
1404  args[jss::amount] = "TwoThousand";
1405  args[jss::channel_id] = chan1Str;
1406  args[jss::key_type] = "secp256k1";
1407  args[jss::passphrase] = "passphrase_can_be_anything";
1408  rs = env.rpc(
1409  "json",
1410  "channel_authorize",
1411  args.toStyledString())[jss::result];
1412  BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
1413  }
1414  }
1415  }
1416 
1417  void
1419  {
1420  testcase("Optional Fields");
1421  using namespace jtx;
1422  using namespace std::literals::chrono_literals;
1423  Env env(*this);
1424  auto const alice = Account("alice");
1425  auto const bob = Account("bob");
1426  auto const carol = Account("carol");
1427  auto const dan = Account("dan");
1428  env.fund(XRP(10000), alice, bob, carol, dan);
1429  auto const pk = alice.pk();
1430  auto const settleDelay = 3600s;
1431  auto const channelFunds = XRP(1000);
1432 
1434 
1435  {
1436  auto const chan = to_string(channel(alice, bob, env.seq(alice)));
1437  env(create(alice, bob, channelFunds, settleDelay, pk));
1438  auto const r =
1439  env.rpc("account_channels", alice.human(), bob.human());
1440  BEAST_EXPECT(r[jss::result][jss::channels].size() == 1);
1441  BEAST_EXPECT(
1442  r[jss::result][jss::channels][0u][jss::channel_id] == chan);
1443  BEAST_EXPECT(!r[jss::result][jss::channels][0u].isMember(
1444  jss::destination_tag));
1445  }
1446  {
1447  std::uint32_t dstTag = 42;
1448  auto const chan = to_string(channel(alice, carol, env.seq(alice)));
1449  env(create(
1450  alice,
1451  carol,
1452  channelFunds,
1453  settleDelay,
1454  pk,
1455  cancelAfter,
1456  dstTag));
1457  auto const r =
1458  env.rpc("account_channels", alice.human(), carol.human());
1459  BEAST_EXPECT(r[jss::result][jss::channels].size() == 1);
1460  BEAST_EXPECT(
1461  r[jss::result][jss::channels][0u][jss::channel_id] == chan);
1462  BEAST_EXPECT(
1463  r[jss::result][jss::channels][0u][jss::destination_tag] ==
1464  dstTag);
1465  }
1466  }
1467 
1468  void
1470  {
1471  testcase("malformed pk");
1472  using namespace jtx;
1473  using namespace std::literals::chrono_literals;
1474  Env env(*this);
1475  auto const alice = Account("alice");
1476  auto const bob = Account("bob");
1477  auto USDA = alice["USD"];
1478  env.fund(XRP(10000), alice, bob);
1479  auto const pk = alice.pk();
1480  auto const settleDelay = 100s;
1481 
1482  auto const chan = channel(alice, bob, env.seq(alice));
1483  auto jv = create(alice, bob, XRP(1000), settleDelay, pk);
1484  auto const pkHex = strHex(pk.slice());
1485  jv["PublicKey"] = pkHex.substr(2, pkHex.size() - 2);
1486  env(jv, ter(temMALFORMED));
1487  jv["PublicKey"] = pkHex.substr(0, pkHex.size() - 2);
1488  env(jv, ter(temMALFORMED));
1489  auto badPrefix = pkHex;
1490  badPrefix[0] = 'f';
1491  badPrefix[1] = 'f';
1492  jv["PublicKey"] = badPrefix;
1493  env(jv, ter(temMALFORMED));
1494 
1495  jv["PublicKey"] = pkHex;
1496  env(jv);
1497 
1498  auto const authAmt = XRP(100);
1499  auto const sig = signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
1500  jv = claim(
1501  bob,
1502  chan,
1503  authAmt.value(),
1504  authAmt.value(),
1505  Slice(sig),
1506  alice.pk());
1507  jv["PublicKey"] = pkHex.substr(2, pkHex.size() - 2);
1508  env(jv, ter(temMALFORMED));
1509  jv["PublicKey"] = pkHex.substr(0, pkHex.size() - 2);
1510  env(jv, ter(temMALFORMED));
1511  badPrefix = pkHex;
1512  badPrefix[0] = 'f';
1513  badPrefix[1] = 'f';
1514  jv["PublicKey"] = badPrefix;
1515  env(jv, ter(temMALFORMED));
1516 
1517  // missing public key
1518  jv.removeMember("PublicKey");
1519  env(jv, ter(temMALFORMED));
1520 
1521  {
1522  auto const txn = R"*(
1523  {
1524 
1525  "channel_id":"5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3",
1526  "signature":
1527  "304402204EF0AFB78AC23ED1C472E74F4299C0C21F1B21D07EFC0A3838A420F76D783A400220154FB11B6F54320666E4C36CA7F686C16A3A0456800BBC43746F34AF50290064",
1528  "public_key":
1529  "aKijDDiC2q2gXjMpM7i4BUS6cmixgsEe18e7CjsUxwihKfuoFgS5",
1530  "amount": "1000000"
1531  }
1532  )*";
1533  auto const r = env.rpc("json", "channel_verify", txn);
1534  BEAST_EXPECT(r["result"]["error"] == "publicMalformed");
1535  }
1536  }
1537 
1538  void
1540  {
1541  testcase("Metadata & Ownership");
1542 
1543  using namespace jtx;
1544  using namespace std::literals::chrono_literals;
1545 
1546  auto const alice = Account("alice");
1547  auto const bob = Account("bob");
1548  auto const settleDelay = 100s;
1549  auto const pk = alice.pk();
1550 
1551  auto inOwnerDir = [](ReadView const& view,
1552  Account const& acc,
1553  std::shared_ptr<SLE const> const& chan) -> bool {
1554  ripple::Dir const ownerDir(view, keylet::ownerDir(acc.id()));
1555  return std::find(ownerDir.begin(), ownerDir.end(), chan) !=
1556  ownerDir.end();
1557  };
1558 
1559  auto ownerDirCount = [](ReadView const& view,
1560  Account const& acc) -> std::size_t {
1561  ripple::Dir const ownerDir(view, keylet::ownerDir(acc.id()));
1562  return std::distance(ownerDir.begin(), ownerDir.end());
1563  };
1564 
1565  {
1566  // Test without adding the paychan to the recipient's owner
1567  // directory
1568  Env env(
1570  env.fund(XRP(10000), alice, bob);
1571  env(create(alice, bob, XRP(1000), settleDelay, pk));
1572  env.close();
1573  auto const [chan, chanSle] =
1574  channelKeyAndSle(*env.current(), alice, bob);
1575  BEAST_EXPECT(inOwnerDir(*env.current(), alice, chanSle));
1576  BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
1577  BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle));
1578  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
1579  // close the channel
1580  env(claim(bob, chan), txflags(tfClose));
1581  BEAST_EXPECT(!channelExists(*env.current(), chan));
1582  BEAST_EXPECT(!inOwnerDir(*env.current(), alice, chanSle));
1583  BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
1584  BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle));
1585  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
1586  }
1587 
1588  {
1589  // Test with adding the paychan to the recipient's owner directory
1590  Env env(*this);
1591  env.fund(XRP(10000), alice, bob);
1592  env(create(alice, bob, XRP(1000), settleDelay, pk));
1593  env.close();
1594  auto const [chan, chanSle] =
1595  channelKeyAndSle(*env.current(), alice, bob);
1596  BEAST_EXPECT(inOwnerDir(*env.current(), alice, chanSle));
1597  BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
1598  BEAST_EXPECT(inOwnerDir(*env.current(), bob, chanSle));
1599  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
1600  // close the channel
1601  env(claim(bob, chan), txflags(tfClose));
1602  BEAST_EXPECT(!channelExists(*env.current(), chan));
1603  BEAST_EXPECT(!inOwnerDir(*env.current(), alice, chanSle));
1604  BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
1605  BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle));
1606  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
1607  }
1608 
1609  {
1610  // Test removing paychans created before adding to the recipient's
1611  // owner directory
1612  Env env(
1614  env.fund(XRP(10000), alice, bob);
1615  // create the channel before the amendment activates
1616  env(create(alice, bob, XRP(1000), settleDelay, pk));
1617  env.close();
1618  auto const [chan, chanSle] =
1619  channelKeyAndSle(*env.current(), alice, bob);
1620  BEAST_EXPECT(inOwnerDir(*env.current(), alice, chanSle));
1621  BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
1622  BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle));
1623  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
1625  env.close();
1626  BEAST_EXPECT(
1627  env.current()->rules().enabled(fixPayChanRecipientOwnerDir));
1628  // These checks look redundant, but if you don't `close` after the
1629  // `create` these checks will fail. I believe this is due to the
1630  // create running with one set of amendments initially, then with a
1631  // different set with the ledger closes (tho I haven't dug into it)
1632  BEAST_EXPECT(inOwnerDir(*env.current(), alice, chanSle));
1633  BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle));
1634  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
1635 
1636  // close the channel after the amendment activates
1637  env(claim(bob, chan), txflags(tfClose));
1638  BEAST_EXPECT(!channelExists(*env.current(), chan));
1639  BEAST_EXPECT(!inOwnerDir(*env.current(), alice, chanSle));
1640  BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
1641  BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle));
1642  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
1643  }
1644  }
1645 
1646  void
1648  {
1649  testcase("Account Delete");
1650  using namespace test::jtx;
1651  using namespace std::literals::chrono_literals;
1652  auto rmAccount = [this](
1653  Env& env,
1654  Account const& toRm,
1655  Account const& dst,
1656  TER expectedTer = tesSUCCESS) {
1657  // only allow an account to be deleted if the account's sequence
1658  // number is at least 256 less than the current ledger sequence
1659  for (auto minRmSeq = env.seq(toRm) + 257;
1660  env.current()->seq() < minRmSeq;
1661  env.close())
1662  {
1663  }
1664 
1665  env(acctdelete(toRm, dst),
1666  fee(drops(env.current()->fees().increment)),
1667  ter(expectedTer));
1668  env.close();
1669  this->BEAST_EXPECT(
1670  isTesSuccess(expectedTer) ==
1671  !env.closed()->exists(keylet::account(toRm.id())));
1672  };
1673 
1674  auto const alice = Account("alice");
1675  auto const bob = Account("bob");
1676  auto const carol = Account("carol");
1677 
1678  for (bool const withOwnerDirFix : {false, true})
1679  {
1680  auto const amd = withOwnerDirFix
1683  Env env{*this, amd};
1684  env.fund(XRP(10000), alice, bob, carol);
1685  env.close();
1686  auto const feeDrops = env.current()->fees().base;
1687 
1688  // Create a channel from alice to bob
1689  auto const pk = alice.pk();
1690  auto const settleDelay = 100s;
1691  auto const chan = channel(alice, bob, env.seq(alice));
1692  env(create(alice, bob, XRP(1000), settleDelay, pk));
1693  env.close();
1694  BEAST_EXPECT(channelBalance(*env.current(), chan) == XRP(0));
1695  BEAST_EXPECT(channelAmount(*env.current(), chan) == XRP(1000));
1696 
1697  rmAccount(env, alice, carol, tecHAS_OBLIGATIONS);
1698  // can only remove bob if the channel isn't in their owner direcotry
1699  rmAccount(
1700  env,
1701  bob,
1702  carol,
1703  withOwnerDirFix ? TER(tecHAS_OBLIGATIONS) : TER(tesSUCCESS));
1704 
1705  auto chanBal = channelBalance(*env.current(), chan);
1706  auto chanAmt = channelAmount(*env.current(), chan);
1707  BEAST_EXPECT(chanBal == XRP(0));
1708  BEAST_EXPECT(chanAmt == XRP(1000));
1709 
1710  auto preBob = env.balance(bob);
1711  auto const delta = XRP(50);
1712  auto reqBal = chanBal + delta;
1713  auto authAmt = reqBal + XRP(100);
1714  assert(reqBal <= chanAmt);
1715 
1716  // claim should fail if the dst was removed
1717  if (withOwnerDirFix)
1718  {
1719  env(claim(alice, chan, reqBal, authAmt));
1720  env.close();
1721  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
1722  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1723  BEAST_EXPECT(env.balance(bob) == preBob + delta);
1724  chanBal = reqBal;
1725  }
1726  else
1727  {
1728  auto const preAlice = env.balance(alice);
1729  env(claim(alice, chan, reqBal, authAmt), ter(tecNO_DST));
1730  env.close();
1731  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
1732  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1733  BEAST_EXPECT(env.balance(bob) == preBob);
1734  BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops);
1735  }
1736 
1737  // fund should fail if the dst was removed
1738  if (withOwnerDirFix)
1739  {
1740  auto const preAlice = env.balance(alice);
1741  env(fund(alice, chan, XRP(1000)));
1742  env.close();
1743  BEAST_EXPECT(
1744  env.balance(alice) == preAlice - XRP(1000) - feeDrops);
1745  BEAST_EXPECT(
1746  channelAmount(*env.current(), chan) == chanAmt + XRP(1000));
1747  chanAmt = chanAmt + XRP(1000);
1748  }
1749  else
1750  {
1751  auto const preAlice = env.balance(alice);
1752  env(fund(alice, chan, XRP(1000)), ter(tecNO_DST));
1753  env.close();
1754  BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops);
1755  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1756  }
1757 
1758  {
1759  // Owner closes, will close after settleDelay
1760  env(claim(alice, chan), txflags(tfClose));
1761  env.close();
1762  // settle delay hasn't ellapsed. Channels should exist.
1763  BEAST_EXPECT(channelExists(*env.current(), chan));
1764  auto const closeTime = env.current()->info().parentCloseTime;
1765  auto const minExpiration = closeTime + settleDelay;
1766  env.close(minExpiration);
1767  env(claim(alice, chan), txflags(tfClose));
1768  BEAST_EXPECT(!channelExists(*env.current(), chan));
1769  }
1770  }
1771 
1772  {
1773  // test resurrected account
1774  Env env{
1776  env.fund(XRP(10000), alice, bob, carol);
1777  env.close();
1778  auto const feeDrops = env.current()->fees().base;
1779 
1780  // Create a channel from alice to bob
1781  auto const pk = alice.pk();
1782  auto const settleDelay = 100s;
1783  auto const chan = channel(alice, bob, env.seq(alice));
1784  env(create(alice, bob, XRP(1000), settleDelay, pk));
1785  env.close();
1786  BEAST_EXPECT(channelBalance(*env.current(), chan) == XRP(0));
1787  BEAST_EXPECT(channelAmount(*env.current(), chan) == XRP(1000));
1788 
1789  // Since `fixPayChanRecipientOwnerDir` is not active, can remove bob
1790  rmAccount(env, bob, carol);
1791  BEAST_EXPECT(!env.closed()->exists(keylet::account(bob.id())));
1792 
1793  auto chanBal = channelBalance(*env.current(), chan);
1794  auto chanAmt = channelAmount(*env.current(), chan);
1795  BEAST_EXPECT(chanBal == XRP(0));
1796  BEAST_EXPECT(chanAmt == XRP(1000));
1797  auto preBob = env.balance(bob);
1798  auto const delta = XRP(50);
1799  auto reqBal = chanBal + delta;
1800  auto authAmt = reqBal + XRP(100);
1801  assert(reqBal <= chanAmt);
1802 
1803  {
1804  // claim should fail, since bob doesn't exist
1805  auto const preAlice = env.balance(alice);
1806  env(claim(alice, chan, reqBal, authAmt), ter(tecNO_DST));
1807  env.close();
1808  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
1809  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1810  BEAST_EXPECT(env.balance(bob) == preBob);
1811  BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops);
1812  }
1813 
1814  {
1815  // fund should fail, sincebob doesn't exist
1816  auto const preAlice = env.balance(alice);
1817  env(fund(alice, chan, XRP(1000)), ter(tecNO_DST));
1818  env.close();
1819  BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops);
1820  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1821  }
1822 
1823  // resurrect bob
1824  env(pay(alice, bob, XRP(20)));
1825  env.close();
1826  BEAST_EXPECT(env.closed()->exists(keylet::account(bob.id())));
1827 
1828  {
1829  // alice should be able to claim
1830  preBob = env.balance(bob);
1831  reqBal = chanBal + delta;
1832  authAmt = reqBal + XRP(100);
1833  env(claim(alice, chan, reqBal, authAmt));
1834  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
1835  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1836  BEAST_EXPECT(env.balance(bob) == preBob + delta);
1837  chanBal = reqBal;
1838  }
1839 
1840  {
1841  // bob should be able to claim
1842  preBob = env.balance(bob);
1843  reqBal = chanBal + delta;
1844  authAmt = reqBal + XRP(100);
1845  auto const sig =
1846  signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
1847  env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()));
1848  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
1849  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1850  BEAST_EXPECT(env.balance(bob) == preBob + delta - feeDrops);
1851  chanBal = reqBal;
1852  }
1853 
1854  {
1855  // alice should be able to fund
1856  auto const preAlice = env.balance(alice);
1857  env(fund(alice, chan, XRP(1000)));
1858  BEAST_EXPECT(
1859  env.balance(alice) == preAlice - XRP(1000) - feeDrops);
1860  BEAST_EXPECT(
1861  channelAmount(*env.current(), chan) == chanAmt + XRP(1000));
1862  chanAmt = chanAmt + XRP(1000);
1863  }
1864 
1865  {
1866  // Owner closes, will close after settleDelay
1867  env(claim(alice, chan), txflags(tfClose));
1868  env.close();
1869  // settle delay hasn't ellapsed. Channels should exist.
1870  BEAST_EXPECT(channelExists(*env.current(), chan));
1871  auto const closeTime = env.current()->info().parentCloseTime;
1872  auto const minExpiration = closeTime + settleDelay;
1873  env.close(minExpiration);
1874  env(claim(alice, chan), txflags(tfClose));
1875  BEAST_EXPECT(!channelExists(*env.current(), chan));
1876  }
1877  }
1878  }
1879 
1880  void
1882  {
1883  testcase("using tickets");
1884  using namespace jtx;
1885  using namespace std::literals::chrono_literals;
1886  Env env(*this);
1887  auto const alice = Account("alice");
1888  auto const bob = Account("bob");
1889  auto USDA = alice["USD"];
1890  env.fund(XRP(10000), alice, bob);
1891 
1892  // alice and bob grab enough tickets for all of the following
1893  // transactions. Note that once the tickets are acquired alice's
1894  // and bob's account sequence numbers should not advance.
1895  std::uint32_t aliceTicketSeq{env.seq(alice) + 1};
1896  env(ticket::create(alice, 10));
1897  std::uint32_t const aliceSeq{env.seq(alice)};
1898 
1899  std::uint32_t bobTicketSeq{env.seq(bob) + 1};
1900  env(ticket::create(bob, 10));
1901  std::uint32_t const bobSeq{env.seq(bob)};
1902 
1903  auto const pk = alice.pk();
1904  auto const settleDelay = 100s;
1905  auto const chan = channel(alice, bob, aliceTicketSeq);
1906 
1907  env(create(alice, bob, XRP(1000), settleDelay, pk),
1908  ticket::use(aliceTicketSeq++));
1909 
1910  env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1911  BEAST_EXPECT(env.seq(alice) == aliceSeq);
1912 
1913  BEAST_EXPECT(channelBalance(*env.current(), chan) == XRP(0));
1914  BEAST_EXPECT(channelAmount(*env.current(), chan) == XRP(1000));
1915 
1916  {
1917  auto const preAlice = env.balance(alice);
1918  env(fund(alice, chan, XRP(1000)), ticket::use(aliceTicketSeq++));
1919 
1920  env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1921  BEAST_EXPECT(env.seq(alice) == aliceSeq);
1922 
1923  auto const feeDrops = env.current()->fees().base;
1924  BEAST_EXPECT(env.balance(alice) == preAlice - XRP(1000) - feeDrops);
1925  }
1926 
1927  auto chanBal = channelBalance(*env.current(), chan);
1928  auto chanAmt = channelAmount(*env.current(), chan);
1929  BEAST_EXPECT(chanBal == XRP(0));
1930  BEAST_EXPECT(chanAmt == XRP(2000));
1931 
1932  {
1933  // No signature needed since the owner is claiming
1934  auto const preBob = env.balance(bob);
1935  auto const delta = XRP(500);
1936  auto const reqBal = chanBal + delta;
1937  auto const authAmt = reqBal + XRP(100);
1938  assert(reqBal <= chanAmt);
1939  env(claim(alice, chan, reqBal, authAmt),
1940  ticket::use(aliceTicketSeq++));
1941 
1942  env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1943  BEAST_EXPECT(env.seq(alice) == aliceSeq);
1944 
1945  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
1946  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1947  BEAST_EXPECT(env.balance(bob) == preBob + delta);
1948  chanBal = reqBal;
1949  }
1950  {
1951  // Claim with signature
1952  auto preBob = env.balance(bob);
1953  auto const delta = XRP(500);
1954  auto const reqBal = chanBal + delta;
1955  auto const authAmt = reqBal + XRP(100);
1956  assert(reqBal <= chanAmt);
1957  auto const sig =
1958  signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
1959  env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()),
1960  ticket::use(bobTicketSeq++));
1961 
1962  env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
1963  BEAST_EXPECT(env.seq(bob) == bobSeq);
1964 
1965  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
1966  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1967  auto const feeDrops = env.current()->fees().base;
1968  BEAST_EXPECT(env.balance(bob) == preBob + delta - feeDrops);
1969  chanBal = reqBal;
1970 
1971  // claim again
1972  preBob = env.balance(bob);
1973  // A transaction that generates a tec still consumes its ticket.
1974  env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()),
1975  ticket::use(bobTicketSeq++),
1977 
1978  env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
1979  BEAST_EXPECT(env.seq(bob) == bobSeq);
1980 
1981  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
1982  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1983  BEAST_EXPECT(env.balance(bob) == preBob - feeDrops);
1984  }
1985  {
1986  // Try to claim more than authorized
1987  auto const preBob = env.balance(bob);
1988  STAmount const authAmt = chanBal + XRP(500);
1989  STAmount const reqAmt = authAmt + drops(1);
1990  assert(reqAmt <= chanAmt);
1991  // Note that since claim() returns a tem (neither tec nor tes),
1992  // the ticket is not consumed. So we don't increment bobTicket.
1993  auto const sig =
1994  signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
1995  env(claim(bob, chan, reqAmt, authAmt, Slice(sig), alice.pk()),
1996  ticket::use(bobTicketSeq),
1997  ter(temBAD_AMOUNT));
1998 
1999  env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
2000  BEAST_EXPECT(env.seq(bob) == bobSeq);
2001 
2002  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
2003  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
2004  BEAST_EXPECT(env.balance(bob) == preBob);
2005  }
2006 
2007  // Dst tries to fund the channel
2008  env(fund(bob, chan, XRP(1000)),
2009  ticket::use(bobTicketSeq++),
2011 
2012  env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
2013  BEAST_EXPECT(env.seq(bob) == bobSeq);
2014 
2015  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
2016  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
2017 
2018  {
2019  // Dst closes channel
2020  auto const preAlice = env.balance(alice);
2021  auto const preBob = env.balance(bob);
2022  env(claim(bob, chan),
2023  txflags(tfClose),
2024  ticket::use(bobTicketSeq++));
2025 
2026  env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
2027  BEAST_EXPECT(env.seq(bob) == bobSeq);
2028 
2029  BEAST_EXPECT(!channelExists(*env.current(), chan));
2030  auto const feeDrops = env.current()->fees().base;
2031  auto const delta = chanAmt - chanBal;
2032  assert(delta > beast::zero);
2033  BEAST_EXPECT(env.balance(alice) == preAlice + delta);
2034  BEAST_EXPECT(env.balance(bob) == preBob - feeDrops);
2035  }
2036  env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
2037  BEAST_EXPECT(env.seq(alice) == aliceSeq);
2038  env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
2039  BEAST_EXPECT(env.seq(bob) == bobSeq);
2040  }
2041 
2042  void
2043  run() override
2044  {
2045  testSimple();
2046  testCancelAfter();
2047  testSettleDelay();
2048  testExpiration();
2049  testCloseDry();
2051  testDisallowXRP();
2052  testDstTag();
2053  testDepositAuth();
2054  testMultiple();
2060  testMalformedPK();
2063  testUsingTickets();
2064  }
2065 };
2066 
2067 BEAST_DEFINE_TESTSUITE(PayChan, app, ripple);
2068 } // namespace test
2069 } // namespace ripple
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:300
ripple::test::PayChan_test::testAccountDelete
void testAccountDelete()
Definition: PayChan_test.cpp:1647
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::test::PayChan_test::testAuthVerifyRPC
void testAuthVerifyRPC()
Definition: PayChan_test.cpp:1078
ripple::tecNO_TARGET
@ tecNO_TARGET
Definition: TER.h:266
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::PayChan_test::testCancelAfter
void testCancelAfter()
Definition: PayChan_test.cpp:353
ripple::sliceToHex
static std::string sliceToHex(Slice const &slice)
Definition: PublicKey.cpp:80
ripple::test::jtx::ter
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
ripple::sfAmount
const SF_AMOUNT sfAmount
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:584
ripple::test::jtx::Env::require
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:466
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
ripple::test::jtx::Env::closed
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
Definition: Env.cpp:115
std::pair
std::vector::reserve
T reserve(T... args)
ripple::sfSequence
const SF_UINT32 sfSequence
ripple::test::PayChan_test::create
static Json::Value create(jtx::Account const &account, jtx::Account const &to, STAmount const &amount, NetClock::duration const &settleDelay, PublicKey const &pk, std::optional< NetClock::time_point > const &cancelAfter=std::nullopt, std::optional< std::uint32_t > const &dstTag=std::nullopt)
Definition: PayChan_test.cpp:107
ripple::tfClose
const std::uint32_t tfClose
Definition: TxFlags.h:106
ripple::test::jtx::balance
A balance matches.
Definition: balance.h:38
std::vector
STL class.
std::find
T find(T... args)
ripple::test::jtx::Env::enableFeature
void enableFeature(uint256 const feature)
Definition: Env.cpp:462
std::set::size
T size(T... args)
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:614
std::chrono::duration
ripple::featureDepositAuth
const uint256 featureDepositAuth
ripple::tecDST_TAG_NEEDED
@ tecDST_TAG_NEEDED
Definition: TER.h:271
ripple::test::PayChan_test::channel
static uint256 channel(jtx::Account const &account, jtx::Account const &dst, std::uint32_t seqProxyValue)
Definition: PayChan_test.cpp:36
ripple::test::PayChan_test::testAccountChannelsRPCSenderOnly
void testAccountChannelsRPCSenderOnly()
Definition: PayChan_test.cpp:1041
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:109
std::distance
T distance(T... args)
ripple::test::PayChan_test::channelExists
static bool channelExists(ReadView const &view, uint256 const &chan)
Definition: PayChan_test.cpp:80
ripple::PublicKey::slice
Slice slice() const noexcept
Definition: PublicKey.h:123
ripple::asfDepositAuth
const std::uint32_t asfDepositAuth
Definition: TxFlags.h:73
ripple::Buffer
Like std::vector<char> but better.
Definition: Buffer.h:35
ripple::asfDisallowXRP
const std::uint32_t asfDisallowXRP
Definition: TxFlags.h:67
ripple::test::jtx::Env::balance
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition: Env.cpp:180
ripple::test::PayChan_test::testAccountChannelsRPC
void testAccountChannelsRPC()
Definition: PayChan_test.cpp:870
ripple::serializePayChanAuthorization
void serializePayChanAuthorization(Serializer &msg, uint256 const &key, XRPAmount const &amt)
Definition: protocol/PayChan.h:31
ripple::test::PayChan_test::testUsingTickets
void testUsingTickets()
Definition: PayChan_test.cpp:1881
ripple::temDST_IS_SRC
@ temDST_IS_SRC
Definition: TER.h:103
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:313
ripple::sfExpiration
const SF_UINT32 sfExpiration
ripple::KeyType::ed25519
@ ed25519
ripple::test::jtx::expiration
Set Expiration on a JTx.
Definition: Check_test.cpp:29
ripple::base_uint< 256 >
ripple::test::jtx::ticket::use
Set a ticket sequence on a JTx.
Definition: ticket.h:47
ripple::test::PayChan_test::testMalformedPK
void testMalformedPK()
Definition: PayChan_test.cpp:1469
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:130
chrono
ripple::temBAD_SIGNER
@ temBAD_SIGNER
Definition: TER.h:110
ripple::JsonOptions::none
@ none
ripple::TERSubset< CanCvtToTER >
ripple::test::PayChan_test::run
void run() override
Definition: PayChan_test.cpp:2043
ripple::test::jtx::fset
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:28
ripple::tecUNFUNDED
@ tecUNFUNDED
Definition: TER.h:257
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:555
std::to_string
T to_string(T... args)
ripple::test::jtx::txflags
Set the flags on a JTx.
Definition: txflags.h:30
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:43
ripple::tecUNFUNDED_PAYMENT
@ tecUNFUNDED_PAYMENT
Definition: TER.h:247
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:63
std::chrono::time_point
ripple::fixPayChanRecipientOwnerDir
const uint256 fixPayChanRecipientOwnerDir
ripple::test::PayChan_test::testMultiple
void testMultiple()
Definition: PayChan_test.cpp:847
ripple::temBAD_AMOUNT
@ temBAD_AMOUNT
Definition: TER.h:84
ripple::test::PayChan_test::testMetaAndOwnership
void testMetaAndOwnership()
Definition: PayChan_test.cpp:1539
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
std::uint32_t
ripple::temBAD_SIGNATURE
@ temBAD_SIGNATURE
Definition: TER.h:100
ripple::test::jtx::sig
Set the regular signature on a JTx.
Definition: sig.h:34
ripple::SecretKey
A secret key.
Definition: SecretKey.h:36
ripple::test::jtx::Env::seq
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:204
ripple::test::jtx::fclear
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition: flags.h:40
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::PayChan_test::channelExpiration
static std::optional< std::int64_t > channelExpiration(ReadView const &view, uint256 const &chan)
Definition: PayChan_test.cpp:96
ripple::tfUniversal
const std::uint32_t tfUniversal
Definition: TxFlags.h:49
ripple::asfRequireDest
const std::uint32_t asfRequireDest
Definition: TxFlags.h:65
ripple::test::jtx::fee
Set the fee on a JTx.
Definition: fee.h:35
ripple::Serializer
Definition: Serializer.h:39
std::string::substr
T substr(T... args)
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:192
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::PayChan_test::claim
static Json::Value claim(jtx::Account const &account, uint256 const &channel, std::optional< STAmount > const &balance=std::nullopt, std::optional< STAmount > const &amount=std::nullopt, std::optional< Slice > const &signature=std::nullopt, std::optional< PublicKey > const &pk=std::nullopt)
Definition: PayChan_test.cpp:152
ripple::test::PayChan_test::channelBalance
static STAmount channelBalance(ReadView const &view, uint256 const &chan)
Definition: PayChan_test.cpp:71
ripple::test::PayChan_test::channelKeyAndSle
static std::pair< uint256, std::shared_ptr< SLE const > > channelKeyAndSle(ReadView const &view, jtx::Account const &account, jtx::Account const &dst)
Definition: PayChan_test.cpp:46
ripple::test::jtx::pay
Json::Value pay(Account const &account, Account const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
ripple::keylet::payChan
Keylet payChan(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Definition: Indexes.cpp:321
ripple::sign
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Definition: SecretKey.cpp:238
std::set::insert
T insert(T... args)
ripple::test::PayChan_test::fund
static Json::Value fund(jtx::Account const &account, uint256 const &channel, STAmount const &amount, std::optional< NetClock::time_point > const &expiration=std::nullopt)
Definition: PayChan_test.cpp:133
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:225
ripple::test::PayChan_test::signClaimAuth
static Buffer signClaimAuth(PublicKey const &pk, SecretKey const &sk, uint256 const &channel, STAmount const &authAmt)
Definition: PayChan_test.cpp:59
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::test::PayChan_test::testAccountChannelsRPCMarkers
void testAccountChannelsRPCMarkers()
Definition: PayChan_test.cpp:925
ripple::test::PayChan_test::channelAmount
static STAmount channelAmount(ReadView const &view, uint256 const &chan)
Definition: PayChan_test.cpp:87
ripple::tecHAS_OBLIGATIONS
@ tecHAS_OBLIGATIONS
Definition: TER.h:279
ripple::tecNO_PERMISSION
@ tecNO_PERMISSION
Definition: TER.h:267
ripple::Dir
Definition: Directory.h:28
ripple::tfRenew
const std::uint32_t tfRenew
Definition: TxFlags.h:105
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::test::jtx::acctdelete
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
Definition: acctdelete.cpp:29
std::chrono::duration::count
T count(T... args)
ripple::test::PayChan_test::testDstTag
void testDstTag()
Definition: PayChan_test.cpp:693
std::optional
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:38
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::test::PayChan_test::testDefaultAmount
void testDefaultAmount()
Definition: PayChan_test.cpp:578
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:45
ripple::tecNO_ENTRY
@ tecNO_ENTRY
Definition: TER.h:268
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:82
ripple::test::PayChan_test::testExpiration
void testExpiration()
Definition: PayChan_test.cpp:418
ripple::test::PayChan_test::testCloseDry
void testCloseDry()
Definition: PayChan_test.cpp:544
ripple::temBAD_EXPIRATION
@ temBAD_EXPIRATION
Definition: TER.h:86
ripple::test::PayChan_test::testSimple
void testSimple()
Definition: PayChan_test.cpp:178
ripple::test::PayChan_test::testDisallowXRP
void testDisallowXRP()
Definition: PayChan_test.cpp:633
ripple::test::PayChan_test::testDepositAuth
void testDepositAuth()
Definition: PayChan_test.cpp:723
ripple::test::PayChan_test::testSettleDelay
void testSettleDelay()
Definition: PayChan_test.cpp:484
ripple::test::PayChan_test
Definition: PayChan_test.cpp:33
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:217
ripple::test::PayChan_test::testOptionalFields
void testOptionalFields()
Definition: PayChan_test.cpp:1418
std::set< std::string >
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:300
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::tecNO_DST
@ tecNO_DST
Definition: TER.h:252
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:684
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::ltPAYCHAN
@ ltPAYCHAN
A ledger object describing a single unidirectional XRP payment channel.
Definition: LedgerFormats.h:130
ripple::XRPAmount
Definition: XRPAmount.h:46
ripple::test::jtx::owner_count
Definition: owners.h:49
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)