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