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  ReadView const& view,
38  jtx::Account const& account,
39  jtx::Account const& dst)
40  {
41  auto const sle = view.read(keylet::account(account));
42  if (!sle)
43  return beast::zero;
44  auto const k = keylet::payChan(account, dst, (*sle)[sfSequence] - 1);
45  return k.key;
46  }
47 
50  ReadView const& view,
51  jtx::Account const& account,
52  jtx::Account const& dst)
53  {
54  auto const sle = view.read(keylet::account(account));
55  if (!sle)
56  return {};
57  auto const k = keylet::payChan(account, dst, (*sle)[sfSequence] - 1);
58  return {k.key, view.read(k)};
59  }
60 
61  static Buffer
63  PublicKey const& pk,
64  SecretKey const& sk,
65  uint256 const& channel,
66  STAmount const& authAmt)
67  {
68  Serializer msg;
69  serializePayChanAuthorization(msg, channel, authAmt.xrp());
70  return sign(pk, sk, msg.slice());
71  }
72 
73  static STAmount
74  channelBalance(ReadView const& view, uint256 const& chan)
75  {
76  auto const slep = view.read({ltPAYCHAN, chan});
77  if (!slep)
78  return XRPAmount{-1};
79  return (*slep)[sfBalance];
80  }
81 
82  static bool
83  channelExists(ReadView const& view, uint256 const& chan)
84  {
85  auto const slep = view.read({ltPAYCHAN, chan});
86  return bool(slep);
87  }
88 
89  static STAmount
90  channelAmount(ReadView const& view, uint256 const& chan)
91  {
92  auto const slep = view.read({ltPAYCHAN, chan});
93  if (!slep)
94  return XRPAmount{-1};
95  return (*slep)[sfAmount];
96  }
97 
98  static boost::optional<std::int64_t>
99  channelExpiration(ReadView const& view, uint256 const& chan)
100  {
101  auto const slep = view.read({ltPAYCHAN, chan});
102  if (!slep)
103  return boost::none;
104  if (auto const r = (*slep)[~sfExpiration])
105  return r.value();
106  return boost::none;
107  }
108 
109  static Json::Value
111  jtx::Account const& account,
112  jtx::Account const& to,
113  STAmount const& amount,
114  NetClock::duration const& settleDelay,
115  PublicKey const& pk,
116  boost::optional<NetClock::time_point> const& cancelAfter = boost::none,
117  boost::optional<std::uint32_t> const& dstTag = boost::none)
118  {
119  using namespace jtx;
120  Json::Value jv;
121  jv[jss::TransactionType] = jss::PaymentChannelCreate;
122  jv[jss::Flags] = tfUniversal;
123  jv[jss::Account] = account.human();
124  jv[jss::Destination] = to.human();
125  jv[jss::Amount] = amount.getJson(JsonOptions::none);
126  jv["SettleDelay"] = settleDelay.count();
127  jv["PublicKey"] = strHex(pk.slice());
128  if (cancelAfter)
129  jv["CancelAfter"] = cancelAfter->time_since_epoch().count();
130  if (dstTag)
131  jv["DestinationTag"] = *dstTag;
132  return jv;
133  }
134 
135  static Json::Value
137  jtx::Account const& account,
138  uint256 const& channel,
139  STAmount const& amount,
140  boost::optional<NetClock::time_point> const& expiration = boost::none)
141  {
142  using namespace jtx;
143  Json::Value jv;
144  jv[jss::TransactionType] = jss::PaymentChannelFund;
145  jv[jss::Flags] = tfUniversal;
146  jv[jss::Account] = account.human();
147  jv["Channel"] = to_string(channel);
148  jv[jss::Amount] = amount.getJson(JsonOptions::none);
149  if (expiration)
150  jv["Expiration"] = expiration->time_since_epoch().count();
151  return jv;
152  }
153 
154  static Json::Value
156  jtx::Account const& account,
157  uint256 const& channel,
158  boost::optional<STAmount> const& balance = boost::none,
159  boost::optional<STAmount> const& amount = boost::none,
160  boost::optional<Slice> const& signature = boost::none,
161  boost::optional<PublicKey> const& pk = boost::none)
162  {
163  using namespace jtx;
164  Json::Value jv;
165  jv[jss::TransactionType] = jss::PaymentChannelClaim;
166  jv[jss::Flags] = tfUniversal;
167  jv[jss::Account] = account.human();
168  jv["Channel"] = to_string(channel);
169  if (amount)
170  jv[jss::Amount] = amount->getJson(JsonOptions::none);
171  if (balance)
172  jv["Balance"] = balance->getJson(JsonOptions::none);
173  if (signature)
174  jv["Signature"] = strHex(*signature);
175  if (pk)
176  jv["PublicKey"] = strHex(pk->slice());
177  return jv;
178  }
179 
180  void
182  {
183  testcase("simple");
184  using namespace jtx;
185  using namespace std::literals::chrono_literals;
186  Env env(*this);
187  auto const alice = Account("alice");
188  auto const bob = Account("bob");
189  auto USDA = alice["USD"];
190  env.fund(XRP(10000), alice, bob);
191  auto const pk = alice.pk();
192  auto const settleDelay = 100s;
193  env(create(alice, bob, XRP(1000), settleDelay, pk));
194  auto const chan = channel(*env.current(), alice, bob);
195  BEAST_EXPECT(channelBalance(*env.current(), chan) == XRP(0));
196  BEAST_EXPECT(channelAmount(*env.current(), chan) == XRP(1000));
197 
198  {
199  auto const preAlice = env.balance(alice);
200  env(fund(alice, chan, XRP(1000)));
201  auto const feeDrops = env.current()->fees().base;
202  BEAST_EXPECT(env.balance(alice) == preAlice - XRP(1000) - feeDrops);
203  }
204 
205  auto chanBal = channelBalance(*env.current(), chan);
206  auto chanAmt = channelAmount(*env.current(), chan);
207  BEAST_EXPECT(chanBal == XRP(0));
208  BEAST_EXPECT(chanAmt == XRP(2000));
209 
210  {
211  // bad amounts (non-xrp, negative amounts)
212  env(create(alice, bob, USDA(1000), settleDelay, pk),
213  ter(temBAD_AMOUNT));
214  env(fund(alice, chan, USDA(1000)), ter(temBAD_AMOUNT));
215  env(create(alice, bob, XRP(-1000), settleDelay, pk),
216  ter(temBAD_AMOUNT));
217  env(fund(alice, chan, XRP(-1000)), ter(temBAD_AMOUNT));
218  }
219 
220  // invalid account
221  env(create(alice, "noAccount", XRP(1000), settleDelay, pk),
222  ter(tecNO_DST));
223  // can't create channel to the same account
224  env(create(alice, alice, XRP(1000), settleDelay, pk),
225  ter(temDST_IS_SRC));
226  // invalid channel
227  env(fund(alice, channel(*env.current(), alice, "noAccount"), XRP(1000)),
228  ter(tecNO_ENTRY));
229  // not enough funds
230  env(create(alice, bob, XRP(10000), settleDelay, pk), ter(tecUNFUNDED));
231 
232  {
233  // No signature claim with bad amounts (negative and non-xrp)
234  auto const iou = USDA(100).value();
235  auto const negXRP = XRP(-100).value();
236  auto const posXRP = XRP(100).value();
237  env(claim(alice, chan, iou, iou), ter(temBAD_AMOUNT));
238  env(claim(alice, chan, posXRP, iou), ter(temBAD_AMOUNT));
239  env(claim(alice, chan, iou, posXRP), ter(temBAD_AMOUNT));
240  env(claim(alice, chan, negXRP, negXRP), ter(temBAD_AMOUNT));
241  env(claim(alice, chan, posXRP, negXRP), ter(temBAD_AMOUNT));
242  env(claim(alice, chan, negXRP, posXRP), ter(temBAD_AMOUNT));
243  }
244  {
245  // No signature claim more than authorized
246  auto const delta = XRP(500);
247  auto const reqBal = chanBal + delta;
248  auto const authAmt = reqBal + XRP(-100);
249  assert(reqBal <= chanAmt);
250  env(claim(alice, chan, reqBal, authAmt), ter(temBAD_AMOUNT));
251  }
252  {
253  // No signature needed since the owner is claiming
254  auto const preBob = env.balance(bob);
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));
260  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
261  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
262  BEAST_EXPECT(env.balance(bob) == preBob + delta);
263  chanBal = reqBal;
264  }
265  {
266  // Claim with signature
267  auto preBob = env.balance(bob);
268  auto const delta = XRP(500);
269  auto const reqBal = chanBal + delta;
270  auto const authAmt = reqBal + XRP(100);
271  assert(reqBal <= chanAmt);
272  auto const sig =
273  signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
274  env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()));
275  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
276  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
277  auto const feeDrops = env.current()->fees().base;
278  BEAST_EXPECT(env.balance(bob) == preBob + delta - feeDrops);
279  chanBal = reqBal;
280 
281  // claim again
282  preBob = env.balance(bob);
283  env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()),
285  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
286  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
287  BEAST_EXPECT(env.balance(bob) == preBob - feeDrops);
288  }
289  {
290  // Try to claim more than authorized
291  auto const preBob = env.balance(bob);
292  STAmount const authAmt = chanBal + XRP(500);
293  STAmount const reqAmt = authAmt + STAmount{1};
294  assert(reqAmt <= chanAmt);
295  auto const sig =
296  signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
297  env(claim(bob, chan, reqAmt, authAmt, Slice(sig), alice.pk()),
298  ter(temBAD_AMOUNT));
299  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
300  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
301  BEAST_EXPECT(env.balance(bob) == preBob);
302  }
303 
304  // Dst tries to fund the channel
305  env(fund(bob, chan, XRP(1000)), ter(tecNO_PERMISSION));
306  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
307  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
308 
309  {
310  // Wrong signing key
311  auto const sig = signClaimAuth(bob.pk(), bob.sk(), chan, XRP(1500));
312  env(claim(
313  bob,
314  chan,
315  XRP(1500).value(),
316  XRP(1500).value(),
317  Slice(sig),
318  bob.pk()),
319  ter(temBAD_SIGNER));
320  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
321  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
322  }
323  {
324  // Bad signature
325  auto const sig = signClaimAuth(bob.pk(), bob.sk(), chan, XRP(1500));
326  env(claim(
327  bob,
328  chan,
329  XRP(1500).value(),
330  XRP(1500).value(),
331  Slice(sig),
332  alice.pk()),
334  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
335  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
336  }
337  {
338  // Dst closes channel
339  auto const preAlice = env.balance(alice);
340  auto const preBob = env.balance(bob);
341  env(claim(bob, chan), txflags(tfClose));
342  BEAST_EXPECT(!channelExists(*env.current(), chan));
343  auto const feeDrops = env.current()->fees().base;
344  auto const delta = chanAmt - chanBal;
345  assert(delta > beast::zero);
346  BEAST_EXPECT(env.balance(alice) == preAlice + delta);
347  BEAST_EXPECT(env.balance(bob) == preBob - feeDrops);
348  }
349  }
350 
351  void
353  {
354  testcase("cancel after");
355  using namespace jtx;
356  using namespace std::literals::chrono_literals;
357  auto const alice = Account("alice");
358  auto const bob = Account("bob");
359  auto const carol = Account("carol");
360  {
361  // If dst claims after cancel after, channel closes
362  Env env(*this);
363  env.fund(XRP(10000), alice, bob);
364  auto const pk = alice.pk();
365  auto const settleDelay = 100s;
366  NetClock::time_point const cancelAfter =
367  env.current()->info().parentCloseTime + 3600s;
368  auto const channelFunds = XRP(1000);
369  env(create(alice, bob, channelFunds, settleDelay, pk, cancelAfter));
370  auto const chan = channel(*env.current(), alice, bob);
371  if (!chan)
372  {
373  fail();
374  return;
375  }
376  BEAST_EXPECT(channelExists(*env.current(), chan));
377  env.close(cancelAfter);
378  {
379  // dst cannot claim after cancelAfter
380  auto const chanBal = channelBalance(*env.current(), chan);
381  auto const chanAmt = channelAmount(*env.current(), chan);
382  auto preAlice = env.balance(alice);
383  auto preBob = env.balance(bob);
384  auto const delta = XRP(500);
385  auto const reqBal = chanBal + delta;
386  auto const authAmt = reqBal + XRP(100);
387  assert(reqBal <= chanAmt);
388  auto const sig =
389  signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
390  env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()));
391  auto const feeDrops = env.current()->fees().base;
392  BEAST_EXPECT(!channelExists(*env.current(), chan));
393  BEAST_EXPECT(env.balance(bob) == preBob - feeDrops);
394  BEAST_EXPECT(env.balance(alice) == preAlice + channelFunds);
395  }
396  }
397  {
398  // Third party can close after cancel after
399  Env env(*this);
400  env.fund(XRP(10000), alice, bob, carol);
401  auto const pk = alice.pk();
402  auto const settleDelay = 100s;
403  NetClock::time_point const cancelAfter =
404  env.current()->info().parentCloseTime + 3600s;
405  auto const channelFunds = XRP(1000);
406  env(create(alice, bob, channelFunds, settleDelay, pk, cancelAfter));
407  auto const chan = channel(*env.current(), alice, bob);
408  BEAST_EXPECT(channelExists(*env.current(), chan));
409  // third party close before cancelAfter
410  env(claim(carol, chan), txflags(tfClose), ter(tecNO_PERMISSION));
411  BEAST_EXPECT(channelExists(*env.current(), chan));
412  env.close(cancelAfter);
413  // third party close after cancelAfter
414  auto const preAlice = env.balance(alice);
415  env(claim(carol, chan), txflags(tfClose));
416  BEAST_EXPECT(!channelExists(*env.current(), chan));
417  BEAST_EXPECT(env.balance(alice) == preAlice + channelFunds);
418  }
419  }
420 
421  void
423  {
424  testcase("expiration");
425  using namespace jtx;
426  using namespace std::literals::chrono_literals;
427  Env env(*this);
428  auto const alice = Account("alice");
429  auto const bob = Account("bob");
430  auto const carol = Account("carol");
431  env.fund(XRP(10000), alice, bob, carol);
432  auto const pk = alice.pk();
433  auto const settleDelay = 3600s;
434  auto const closeTime = env.current()->info().parentCloseTime;
435  auto const minExpiration = closeTime + settleDelay;
436  NetClock::time_point const cancelAfter = closeTime + 7200s;
437  auto const channelFunds = XRP(1000);
438  env(create(alice, bob, channelFunds, settleDelay, pk, cancelAfter));
439  auto const chan = channel(*env.current(), alice, bob);
440  BEAST_EXPECT(channelExists(*env.current(), chan));
441  BEAST_EXPECT(!channelExpiration(*env.current(), chan));
442  // Owner closes, will close after settleDelay
443  env(claim(alice, chan), txflags(tfClose));
444  auto counts = [](auto const& t) {
445  return t.time_since_epoch().count();
446  };
447  BEAST_EXPECT(
448  *channelExpiration(*env.current(), chan) == counts(minExpiration));
449  // increase the expiration time
450  env(fund(
451  alice, chan, XRP(1), NetClock::time_point{minExpiration + 100s}));
452  BEAST_EXPECT(
453  *channelExpiration(*env.current(), chan) ==
454  counts(minExpiration) + 100);
455  // decrease the expiration, but still above minExpiration
456  env(fund(
457  alice, chan, XRP(1), NetClock::time_point{minExpiration + 50s}));
458  BEAST_EXPECT(
459  *channelExpiration(*env.current(), chan) ==
460  counts(minExpiration) + 50);
461  // decrease the expiration below minExpiration
462  env(fund(
463  alice, chan, XRP(1), NetClock::time_point{minExpiration - 50s}),
465  BEAST_EXPECT(
466  *channelExpiration(*env.current(), chan) ==
467  counts(minExpiration) + 50);
468  env(claim(bob, chan), txflags(tfRenew), ter(tecNO_PERMISSION));
469  BEAST_EXPECT(
470  *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(
476  alice, chan, XRP(1), 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(alice, chan, channelFunds.value(), channelFunds.value()));
570  BEAST_EXPECT(channelBalance(*env.current(), chan) == channelFunds);
571  BEAST_EXPECT(env.balance(bob) == preBob + channelFunds);
572  }
573  auto const preAlice = env.balance(alice);
574  // Channel is now dry, can close before expiration date
575  env(claim(alice, chan), txflags(tfClose));
576  BEAST_EXPECT(!channelExists(*env.current(), chan));
577  auto const feeDrops = env.current()->fees().base;
578  BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops);
579  }
580 
581  void
583  {
584  // auth amount defaults to balance if not present
585  testcase("default amount");
586  using namespace jtx;
587  using namespace std::literals::chrono_literals;
588  Env env(*this);
589  auto const alice = Account("alice");
590  auto const bob = Account("bob");
591  env.fund(XRP(10000), alice, bob);
592  auto const pk = alice.pk();
593  auto const settleDelay = 3600s;
594  auto const channelFunds = XRP(1000);
595  env(create(alice, bob, channelFunds, settleDelay, pk));
596  auto const chan = channel(*env.current(), alice, bob);
597  BEAST_EXPECT(channelExists(*env.current(), chan));
598  // Owner tries to close channel, but it will remain open (settle delay)
599  env(claim(alice, chan), txflags(tfClose));
600  BEAST_EXPECT(channelExists(*env.current(), chan));
601  {
602  auto chanBal = channelBalance(*env.current(), chan);
603  auto chanAmt = channelAmount(*env.current(), chan);
604  auto const preBob = env.balance(bob);
605 
606  auto const delta = XRP(500);
607  auto const reqBal = chanBal + delta;
608  assert(reqBal <= chanAmt);
609  auto const sig =
610  signClaimAuth(alice.pk(), alice.sk(), chan, reqBal);
611  env(claim(bob, chan, reqBal, boost::none, Slice(sig), alice.pk()));
612  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
613  auto const feeDrops = env.current()->fees().base;
614  BEAST_EXPECT(env.balance(bob) == preBob + delta - feeDrops);
615  chanBal = reqBal;
616  }
617  {
618  // Claim again
619  auto chanBal = channelBalance(*env.current(), chan);
620  auto chanAmt = channelAmount(*env.current(), chan);
621  auto const preBob = env.balance(bob);
622 
623  auto const delta = XRP(500);
624  auto const reqBal = chanBal + delta;
625  assert(reqBal <= chanAmt);
626  auto const sig =
627  signClaimAuth(alice.pk(), alice.sk(), chan, reqBal);
628  env(claim(bob, chan, reqBal, boost::none, Slice(sig), alice.pk()));
629  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
630  auto const feeDrops = env.current()->fees().base;
631  BEAST_EXPECT(env.balance(bob) == preBob + delta - feeDrops);
632  chanBal = reqBal;
633  }
634  }
635 
636  void
638  {
639  // auth amount defaults to balance if not present
640  testcase("Disallow XRP");
641  using namespace jtx;
642  using namespace std::literals::chrono_literals;
643 
644  auto const alice = Account("alice");
645  auto const bob = Account("bob");
646  {
647  // Create a channel where dst disallows XRP
649  env.fund(XRP(10000), alice, bob);
650  env(fset(bob, asfDisallowXRP));
651  env(create(alice, bob, XRP(1000), 3600s, alice.pk()),
652  ter(tecNO_TARGET));
653  auto const chan = channel(*env.current(), alice, bob);
654  BEAST_EXPECT(!channelExists(*env.current(), chan));
655  }
656  {
657  // Create a channel where dst disallows XRP. Ignore that flag,
658  // since it's just advisory.
659  Env env(*this, supported_amendments());
660  env.fund(XRP(10000), alice, bob);
661  env(fset(bob, asfDisallowXRP));
662  env(create(alice, bob, XRP(1000), 3600s, alice.pk()));
663  auto const chan = channel(*env.current(), alice, bob);
664  BEAST_EXPECT(channelExists(*env.current(), chan));
665  }
666 
667  {
668  // Claim to a channel where dst disallows XRP
669  // (channel is created before disallow xrp is set)
671  env.fund(XRP(10000), alice, bob);
672  env(create(alice, bob, XRP(1000), 3600s, alice.pk()));
673  auto const chan = channel(*env.current(), alice, bob);
674  BEAST_EXPECT(channelExists(*env.current(), chan));
675 
676  env(fset(bob, asfDisallowXRP));
677  auto const reqBal = XRP(500).value();
678  env(claim(alice, chan, reqBal, reqBal), ter(tecNO_TARGET));
679  }
680  {
681  // Claim to a channel where dst disallows XRP (channel is
682  // created before disallow xrp is set). Ignore that flag
683  // since it is just advisory.
684  Env env(*this, supported_amendments());
685  env.fund(XRP(10000), alice, bob);
686  env(create(alice, bob, XRP(1000), 3600s, alice.pk()));
687  auto const chan = channel(*env.current(), alice, bob);
688  BEAST_EXPECT(channelExists(*env.current(), chan));
689 
690  env(fset(bob, asfDisallowXRP));
691  auto const reqBal = XRP(500).value();
692  env(claim(alice, chan, reqBal, reqBal));
693  }
694  }
695 
696  void
698  {
699  // auth amount defaults to balance if not present
700  testcase("Dst Tag");
701  using namespace jtx;
702  using namespace std::literals::chrono_literals;
703  // Create a channel where dst disallows XRP
704  Env env(*this);
705  auto const alice = Account("alice");
706  auto const bob = Account("bob");
707  env.fund(XRP(10000), alice, bob);
708  env(fset(bob, asfRequireDest));
709  auto const pk = alice.pk();
710  auto const settleDelay = 3600s;
711  auto const channelFunds = XRP(1000);
712  env(create(alice, bob, channelFunds, settleDelay, pk),
714  BEAST_EXPECT(!channelExists(
715  *env.current(), channel(*env.current(), alice, bob)));
716  env(create(alice, bob, channelFunds, settleDelay, pk, boost::none, 1));
717  BEAST_EXPECT(
718  channelExists(*env.current(), channel(*env.current(), alice, bob)));
719  }
720 
721  void
723  {
724  testcase("Deposit Authorization");
725  using namespace jtx;
726  using namespace std::literals::chrono_literals;
727 
728  auto const alice = Account("alice");
729  auto const bob = Account("bob");
730  auto const carol = Account("carol");
731  auto USDA = alice["USD"];
732  {
733  Env env(*this);
734  env.fund(XRP(10000), alice, bob, carol);
735 
736  env(fset(bob, asfDepositAuth));
737  env.close();
738 
739  auto const pk = alice.pk();
740  auto const settleDelay = 100s;
741  env(create(alice, bob, XRP(1000), settleDelay, pk));
742  env.close();
743 
744  auto const chan = channel(*env.current(), alice, bob);
745  BEAST_EXPECT(channelBalance(*env.current(), chan) == XRP(0));
746  BEAST_EXPECT(channelAmount(*env.current(), chan) == XRP(1000));
747 
748  // alice can add more funds to the channel even though bob has
749  // asfDepositAuth set.
750  env(fund(alice, chan, XRP(1000)));
751  env.close();
752 
753  // alice claims. Fails because bob's lsfDepositAuth flag is set.
754  env(claim(alice, chan, XRP(500).value(), XRP(500).value()),
756  env.close();
757 
758  // Claim with signature
759  auto const baseFee = env.current()->fees().base;
760  auto const preBob = env.balance(bob);
761  {
762  auto const delta = XRP(500).value();
763  auto const sig = signClaimAuth(pk, alice.sk(), chan, delta);
764 
765  // alice claims with signature. Fails since bob has
766  // lsfDepositAuth flag set.
767  env(claim(alice, chan, delta, delta, Slice(sig), pk),
769  env.close();
770  BEAST_EXPECT(env.balance(bob) == preBob);
771 
772  // bob claims but omits the signature. Fails because only
773  // alice can claim without a signature.
774  env(claim(bob, chan, delta, delta), ter(temBAD_SIGNATURE));
775  env.close();
776 
777  // bob claims with signature. Succeeds even though bob's
778  // lsfDepositAuth flag is set since bob submitted the
779  // transaction.
780  env(claim(bob, chan, delta, delta, Slice(sig), pk));
781  env.close();
782  BEAST_EXPECT(env.balance(bob) == preBob + delta - baseFee);
783  }
784  {
785  // Explore the limits of deposit preauthorization.
786  auto const delta = XRP(600).value();
787  auto const sig = signClaimAuth(pk, alice.sk(), chan, delta);
788 
789  // carol claims and fails. Only channel participants (bob or
790  // alice) may claim.
791  env(claim(carol, chan, delta, delta, Slice(sig), pk),
793  env.close();
794 
795  // bob preauthorizes carol for deposit. But after that carol
796  // still can't claim since only channel participants may claim.
797  env(deposit::auth(bob, carol));
798  env.close();
799 
800  env(claim(carol, chan, delta, delta, Slice(sig), pk),
802 
803  // Since alice is not preauthorized she also may not claim
804  // for bob.
805  env(claim(alice, chan, delta, delta, Slice(sig), pk),
807  env.close();
808 
809  // However if bob preauthorizes alice for deposit then she can
810  // successfully submit a claim.
811  env(deposit::auth(bob, alice));
812  env.close();
813 
814  env(claim(alice, chan, delta, delta, Slice(sig), pk));
815  env.close();
816 
817  BEAST_EXPECT(
818  env.balance(bob) == preBob + delta - (3 * baseFee));
819  }
820  {
821  // bob removes preauthorization of alice. Once again she
822  // cannot submit a claim.
823  auto const delta = XRP(800).value();
824 
825  env(deposit::unauth(bob, alice));
826  env.close();
827 
828  // alice claims and fails since she is no longer preauthorized.
829  env(claim(alice, chan, delta, delta), ter(tecNO_PERMISSION));
830  env.close();
831 
832  // bob clears lsfDepositAuth. Now alice can claim.
833  env(fclear(bob, asfDepositAuth));
834  env.close();
835 
836  // alice claims successfully.
837  env(claim(alice, chan, delta, delta));
838  env.close();
839  BEAST_EXPECT(
840  env.balance(bob) == preBob + XRP(800) - (5 * baseFee));
841  }
842  }
843  }
844 
845  void
847  {
848  // auth amount defaults to balance if not present
849  testcase("Multiple channels to the same account");
850  using namespace jtx;
851  using namespace std::literals::chrono_literals;
852  Env env(*this);
853  auto const alice = Account("alice");
854  auto const bob = Account("bob");
855  env.fund(XRP(10000), alice, bob);
856  auto const pk = alice.pk();
857  auto const settleDelay = 3600s;
858  auto const channelFunds = XRP(1000);
859  env(create(alice, bob, channelFunds, settleDelay, pk));
860  auto const chan1 = channel(*env.current(), alice, bob);
861  BEAST_EXPECT(channelExists(*env.current(), chan1));
862  env(create(alice, bob, channelFunds, settleDelay, pk));
863  auto const chan2 = channel(*env.current(), alice, bob);
864  BEAST_EXPECT(channelExists(*env.current(), chan2));
865  BEAST_EXPECT(chan1 != chan2);
866  }
867 
868  void
870  {
871  testcase("AccountChannels RPC");
872 
873  using namespace jtx;
874  using namespace std::literals::chrono_literals;
875  Env env(*this);
876  auto const alice = Account("alice");
877  auto const bob = Account("bob");
878  auto const charlie = Account("charlie", KeyType::ed25519);
879  env.fund(XRP(10000), alice, bob, charlie);
880  auto const pk = alice.pk();
881  auto const settleDelay = 3600s;
882  auto const channelFunds = XRP(1000);
883  env(create(alice, bob, channelFunds, settleDelay, pk));
884  env.close();
885  auto const chan1Str = to_string(channel(*env.current(), alice, bob));
886  {
887  auto const r =
888  env.rpc("account_channels", alice.human(), bob.human());
889  BEAST_EXPECT(r[jss::result][jss::channels].size() == 1);
890  BEAST_EXPECT(
891  r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str);
892  BEAST_EXPECT(r[jss::result][jss::validated]);
893  }
894  {
895  auto const r = env.rpc("account_channels", alice.human());
896  BEAST_EXPECT(r[jss::result][jss::channels].size() == 1);
897  BEAST_EXPECT(
898  r[jss::result][jss::channels][0u][jss::channel_id] == chan1Str);
899  BEAST_EXPECT(r[jss::result][jss::validated]);
900  }
901  {
902  auto const r =
903  env.rpc("account_channels", bob.human(), alice.human());
904  BEAST_EXPECT(r[jss::result][jss::channels].size() == 0);
905  BEAST_EXPECT(r[jss::result][jss::validated]);
906  }
907  env(create(alice, bob, channelFunds, settleDelay, pk));
908  env.close();
909  auto const chan2Str = to_string(channel(*env.current(), alice, bob));
910  {
911  auto const r =
912  env.rpc("account_channels", alice.human(), bob.human());
913  BEAST_EXPECT(r[jss::result][jss::channels].size() == 2);
914  BEAST_EXPECT(r[jss::result][jss::validated]);
915  BEAST_EXPECT(chan1Str != chan2Str);
916  for (auto const& c : {chan1Str, chan2Str})
917  BEAST_EXPECT(
918  r[jss::result][jss::channels][0u][jss::channel_id] == c ||
919  r[jss::result][jss::channels][1u][jss::channel_id] == c);
920  }
921  }
922 
923  void
925  {
926  testcase("Account channels RPC markers");
927 
928  using namespace test::jtx;
929  using namespace std::literals;
930 
931  auto const alice = Account("alice");
932  auto const bobs = []() -> std::vector<Account> {
933  int const n = 10;
935  r.reserve(n);
936  for (int i = 0; i < n; ++i)
937  {
938  r.emplace_back("bob"s + std::to_string(i));
939  }
940  return r;
941  }();
942 
943  Env env(*this);
944  env.fund(XRP(10000), alice);
945  for (auto const& a : bobs)
946  {
947  env.fund(XRP(10000), a);
948  env.close();
949  }
950 
951  {
952  // create a channel from alice to every bob account
953  auto const settleDelay = 3600s;
954  auto const channelFunds = XRP(1);
955  for (auto const& b : bobs)
956  {
957  env(create(alice, b, channelFunds, settleDelay, alice.pk()));
958  }
959  }
960 
961  auto testLimit = [](test::jtx::Env& env,
962  test::jtx::Account const& src,
963  boost::optional<int> limit = boost::none,
964  Json::Value const& marker = Json::nullValue,
965  boost::optional<test::jtx::Account> const& dst =
966  boost::none) {
967  Json::Value jvc;
968  jvc[jss::account] = src.human();
969  if (dst)
970  jvc[jss::destination_account] = dst->human();
971  if (limit)
972  jvc[jss::limit] = *limit;
973  if (marker)
974  jvc[jss::marker] = marker;
975 
976  return env.rpc(
977  "json", "account_channels", to_string(jvc))[jss::result];
978  };
979 
980  {
981  // No marker
982  auto const r = testLimit(env, alice);
983  BEAST_EXPECT(r.isMember(jss::channels));
984  BEAST_EXPECT(r[jss::channels].size() == bobs.size());
985  }
986 
987  auto const bobsB58 = [&bobs]() -> std::set<std::string> {
989  for (auto const& a : bobs)
990  r.insert(a.human());
991  return r;
992  }();
993 
994  for (int limit = 1; limit < bobs.size() + 1; ++limit)
995  {
996  auto leftToFind = bobsB58;
997  auto const numFull = bobs.size() / limit;
998  auto const numNonFull = bobs.size() % limit ? 1 : 0;
999 
1000  Json::Value marker = Json::nullValue;
1001 
1002  auto const testIt = [&](bool expectMarker, int expectedBatchSize) {
1003  auto const r = testLimit(env, alice, limit, marker);
1004  BEAST_EXPECT(!expectMarker || r.isMember(jss::marker));
1005  if (r.isMember(jss::marker))
1006  marker = r[jss::marker];
1007  BEAST_EXPECT(r[jss::channels].size() == expectedBatchSize);
1008  auto const c = r[jss::channels];
1009  auto const s = r[jss::channels].size();
1010  for (int j = 0; j < s; ++j)
1011  {
1012  auto const dstAcc =
1013  c[j][jss::destination_account].asString();
1014  BEAST_EXPECT(leftToFind.count(dstAcc));
1015  leftToFind.erase(dstAcc);
1016  }
1017  };
1018 
1019  for (int i = 0; i < numFull; ++i)
1020  {
1021  bool const expectMarker = (numNonFull != 0 || i < numFull - 1);
1022  testIt(expectMarker, limit);
1023  }
1024 
1025  if (numNonFull)
1026  {
1027  testIt(false, bobs.size() % limit);
1028  }
1029  BEAST_EXPECT(leftToFind.empty());
1030  }
1031 
1032  {
1033  // degenerate case
1034  auto const r = testLimit(env, alice, 0);
1035  BEAST_EXPECT(r.isMember(jss::marker));
1036  BEAST_EXPECT(r[jss::channels].size() == 0);
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  env(create(alice, bob, channelFunds, settleDelay, pk));
1092  env.close();
1093  auto const chan1Str = to_string(channel(*env.current(), alice, bob));
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  env(create(alice, bob, channelFunds, settleDelay, pk));
1121  env.close();
1122  auto const chan2Str = to_string(channel(*env.current(), alice, bob));
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  env(create(
1258  charlie, alice, channelFunds, settleDelay, charlie.pk()));
1259  env.close();
1260 
1261  auto const chan =
1262  to_string(channel(*env.current(), charlie, alice));
1263 
1264  std::string cpk;
1265  {
1266  auto const r =
1267  env.rpc("account_channels", charlie.human(), alice.human());
1268  BEAST_EXPECT(r[jss::result][jss::channels].size() == 1);
1269  BEAST_EXPECT(
1270  r[jss::result][jss::channels][0u][jss::channel_id] == chan);
1271  BEAST_EXPECT(r[jss::result][jss::validated]);
1272  cpk = r[jss::result][jss::channels][0u][jss::public_key]
1273  .asString();
1274  }
1275 
1276  // Try to authorize without specifying a key type, expect an error:
1277  auto const rs =
1278  env.rpc("channel_authorize", "charlie", chan, "1000");
1279  auto const sig = rs[jss::result][jss::signature].asString();
1280  BEAST_EXPECT(!sig.empty());
1281  {
1282  auto const rv =
1283  env.rpc("channel_verify", cpk, chan, "1000", sig);
1284  BEAST_EXPECT(
1285  !rv[jss::result][jss::signature_verified].asBool());
1286  }
1287 
1288  // Try to authorize using an unknown key type, except an error:
1289  auto const rs1 =
1290  env.rpc("channel_authorize", "charlie", "nyx", chan, "1000");
1291  BEAST_EXPECT(rs1[jss::error] == "badKeyType");
1292 
1293  // Try to authorize using secp256k1; the authorization _should_
1294  // succeed but the verification should fail:
1295  auto const rs2 = env.rpc(
1296  "channel_authorize", "charlie", "secp256k1", chan, "1000");
1297  auto const sig2 = rs2[jss::result][jss::signature].asString();
1298  BEAST_EXPECT(!sig2.empty());
1299  {
1300  auto const rv =
1301  env.rpc("channel_verify", cpk, chan, "1000", sig2);
1302  BEAST_EXPECT(
1303  !rv[jss::result][jss::signature_verified].asBool());
1304  }
1305 
1306  // Try to authorize using Ed25519; expect success:
1307  auto const rs3 = env.rpc(
1308  "channel_authorize", "charlie", "ed25519", chan, "1000");
1309  auto const sig3 = rs3[jss::result][jss::signature].asString();
1310  BEAST_EXPECT(!sig3.empty());
1311  {
1312  auto const rv =
1313  env.rpc("channel_verify", cpk, chan, "1000", sig3);
1314  BEAST_EXPECT(rv[jss::result][jss::signature_verified].asBool());
1315  }
1316  }
1317 
1318  {
1319  // send malformed amounts rpc requests
1320  auto rs = env.rpc("channel_authorize", "alice", chan1Str, "1000x");
1321  BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
1322  rs = env.rpc("channel_authorize", "alice", chan1Str, "x1000");
1323  BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
1324  rs = env.rpc("channel_authorize", "alice", chan1Str, "x");
1325  BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
1326  {
1327  // Missing channel_id
1329  args[jss::amount] = "2000";
1330  args[jss::key_type] = "secp256k1";
1331  args[jss::passphrase] = "passphrase_can_be_anything";
1332  rs = env.rpc(
1333  "json",
1334  "channel_authorize",
1335  args.toStyledString())[jss::result];
1336  BEAST_EXPECT(rs[jss::error] == "invalidParams");
1337  }
1338  {
1339  // Missing amount
1341  args[jss::channel_id] = chan1Str;
1342  args[jss::key_type] = "secp256k1";
1343  args[jss::passphrase] = "passphrase_can_be_anything";
1344  rs = env.rpc(
1345  "json",
1346  "channel_authorize",
1347  args.toStyledString())[jss::result];
1348  BEAST_EXPECT(rs[jss::error] == "invalidParams");
1349  }
1350  {
1351  // Missing key_type and no secret.
1353  args[jss::amount] = "2000";
1354  args[jss::channel_id] = chan1Str;
1355  args[jss::passphrase] = "passphrase_can_be_anything";
1356  rs = env.rpc(
1357  "json",
1358  "channel_authorize",
1359  args.toStyledString())[jss::result];
1360  BEAST_EXPECT(rs[jss::error] == "invalidParams");
1361  }
1362  {
1363  // Both passphrase and seed specified.
1365  args[jss::amount] = "2000";
1366  args[jss::channel_id] = chan1Str;
1367  args[jss::key_type] = "secp256k1";
1368  args[jss::passphrase] = "passphrase_can_be_anything";
1369  args[jss::seed] = "seed can be anything";
1370  rs = env.rpc(
1371  "json",
1372  "channel_authorize",
1373  args.toStyledString())[jss::result];
1374  BEAST_EXPECT(rs[jss::error] == "invalidParams");
1375  }
1376  {
1377  // channel_id is not exact hex.
1379  args[jss::amount] = "2000";
1380  args[jss::channel_id] = chan1Str + "1";
1381  args[jss::key_type] = "secp256k1";
1382  args[jss::passphrase] = "passphrase_can_be_anything";
1383  rs = env.rpc(
1384  "json",
1385  "channel_authorize",
1386  args.toStyledString())[jss::result];
1387  BEAST_EXPECT(rs[jss::error] == "channelMalformed");
1388  }
1389  {
1390  // amount is not a string
1392  args[jss::amount] = 2000;
1393  args[jss::channel_id] = chan1Str;
1394  args[jss::key_type] = "secp256k1";
1395  args[jss::passphrase] = "passphrase_can_be_anything";
1396  rs = env.rpc(
1397  "json",
1398  "channel_authorize",
1399  args.toStyledString())[jss::result];
1400  BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
1401  }
1402  {
1403  // Amount is not a decimal string.
1405  args[jss::amount] = "TwoThousand";
1406  args[jss::channel_id] = chan1Str;
1407  args[jss::key_type] = "secp256k1";
1408  args[jss::passphrase] = "passphrase_can_be_anything";
1409  rs = env.rpc(
1410  "json",
1411  "channel_authorize",
1412  args.toStyledString())[jss::result];
1413  BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
1414  }
1415  }
1416  }
1417 
1418  void
1420  {
1421  testcase("Optional Fields");
1422  using namespace jtx;
1423  using namespace std::literals::chrono_literals;
1424  Env env(*this);
1425  auto const alice = Account("alice");
1426  auto const bob = Account("bob");
1427  auto const carol = Account("carol");
1428  auto const dan = Account("dan");
1429  env.fund(XRP(10000), alice, bob, carol, dan);
1430  auto const pk = alice.pk();
1431  auto const settleDelay = 3600s;
1432  auto const channelFunds = XRP(1000);
1433 
1434  boost::optional<NetClock::time_point> cancelAfter;
1435 
1436  {
1437  env(create(alice, bob, channelFunds, settleDelay, pk));
1438  auto const chan = to_string(channel(*env.current(), alice, bob));
1439  auto const r =
1440  env.rpc("account_channels", alice.human(), bob.human());
1441  BEAST_EXPECT(r[jss::result][jss::channels].size() == 1);
1442  BEAST_EXPECT(
1443  r[jss::result][jss::channels][0u][jss::channel_id] == chan);
1444  BEAST_EXPECT(!r[jss::result][jss::channels][0u].isMember(
1445  jss::destination_tag));
1446  }
1447  {
1448  std::uint32_t dstTag = 42;
1449  env(create(
1450  alice,
1451  carol,
1452  channelFunds,
1453  settleDelay,
1454  pk,
1455  cancelAfter,
1456  dstTag));
1457  auto const chan = to_string(channel(*env.current(), alice, carol));
1458  auto const r =
1459  env.rpc("account_channels", alice.human(), carol.human());
1460  BEAST_EXPECT(r[jss::result][jss::channels].size() == 1);
1461  BEAST_EXPECT(
1462  r[jss::result][jss::channels][0u][jss::channel_id] == chan);
1463  BEAST_EXPECT(
1464  r[jss::result][jss::channels][0u][jss::destination_tag] ==
1465  dstTag);
1466  }
1467  }
1468 
1469  void
1471  {
1472  testcase("malformed pk");
1473  using namespace jtx;
1474  using namespace std::literals::chrono_literals;
1475  Env env(*this);
1476  auto const alice = Account("alice");
1477  auto const bob = Account("bob");
1478  auto USDA = alice["USD"];
1479  env.fund(XRP(10000), alice, bob);
1480  auto const pk = alice.pk();
1481  auto const settleDelay = 100s;
1482 
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  auto const chan = channel(*env.current(), alice, bob);
1498 
1499  auto const authAmt = XRP(100);
1500  auto const sig = signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
1501  jv = claim(
1502  bob,
1503  chan,
1504  authAmt.value(),
1505  authAmt.value(),
1506  Slice(sig),
1507  alice.pk());
1508  jv["PublicKey"] = pkHex.substr(2, pkHex.size() - 2);
1509  env(jv, ter(temMALFORMED));
1510  jv["PublicKey"] = pkHex.substr(0, pkHex.size() - 2);
1511  env(jv, ter(temMALFORMED));
1512  badPrefix = pkHex;
1513  badPrefix[0] = 'f';
1514  badPrefix[1] = 'f';
1515  jv["PublicKey"] = badPrefix;
1516  env(jv, ter(temMALFORMED));
1517 
1518  // missing public key
1519  jv.removeMember("PublicKey");
1520  env(jv, ter(temMALFORMED));
1521 
1522  {
1523  auto const txn = R"*(
1524  {
1525 
1526  "channel_id":"5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3",
1527  "signature":
1528  "304402204EF0AFB78AC23ED1C472E74F4299C0C21F1B21D07EFC0A3838A420F76D783A400220154FB11B6F54320666E4C36CA7F686C16A3A0456800BBC43746F34AF50290064",
1529  "public_key":
1530  "aKijDDiC2q2gXjMpM7i4BUS6cmixgsEe18e7CjsUxwihKfuoFgS5",
1531  "amount": "1000000"
1532  }
1533  )*";
1534  auto const r = env.rpc("json", "channel_verify", txn);
1535  BEAST_EXPECT(r["result"]["error"] == "publicMalformed");
1536  }
1537  }
1538 
1539  void
1541  {
1542  testcase("Metadata & Ownership");
1543 
1544  using namespace jtx;
1545  using namespace std::literals::chrono_literals;
1546 
1547  auto const alice = Account("alice");
1548  auto const bob = Account("bob");
1549  auto const settleDelay = 100s;
1550  auto const pk = alice.pk();
1551 
1552  auto inOwnerDir = [](ReadView const& view,
1553  Account const& acc,
1554  std::shared_ptr<SLE const> const& chan) -> bool {
1555  ripple::Dir const ownerDir(view, keylet::ownerDir(acc.id()));
1556  return std::find(ownerDir.begin(), ownerDir.end(), chan) !=
1557  ownerDir.end();
1558  };
1559 
1560  auto ownerDirCount = [](ReadView const& view,
1561  Account const& acc) -> std::size_t {
1562  ripple::Dir const ownerDir(view, keylet::ownerDir(acc.id()));
1563  return std::distance(ownerDir.begin(), ownerDir.end());
1564  };
1565 
1566  {
1567  // Test without adding the paychan to the recipient's owner
1568  // directory
1569  Env env(
1571  env.fund(XRP(10000), alice, bob);
1572  env(create(alice, bob, XRP(1000), settleDelay, pk));
1573  env.close();
1574  auto const [chan, chanSle] =
1575  channelKeyAndSle(*env.current(), alice, bob);
1576  BEAST_EXPECT(inOwnerDir(*env.current(), alice, chanSle));
1577  BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
1578  BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle));
1579  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
1580  // close the channel
1581  env(claim(bob, chan), txflags(tfClose));
1582  BEAST_EXPECT(!channelExists(*env.current(), chan));
1583  BEAST_EXPECT(!inOwnerDir(*env.current(), alice, chanSle));
1584  BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
1585  BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle));
1586  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
1587  }
1588 
1589  {
1590  // Test with adding the paychan to the recipient's owner directory
1591  Env env(*this, supported_amendments());
1592  env.fund(XRP(10000), alice, bob);
1593  env(create(alice, bob, XRP(1000), settleDelay, pk));
1594  env.close();
1595  auto const [chan, chanSle] =
1596  channelKeyAndSle(*env.current(), alice, bob);
1597  BEAST_EXPECT(inOwnerDir(*env.current(), alice, chanSle));
1598  BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
1599  BEAST_EXPECT(inOwnerDir(*env.current(), bob, chanSle));
1600  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
1601  // close the channel
1602  env(claim(bob, chan), txflags(tfClose));
1603  BEAST_EXPECT(!channelExists(*env.current(), chan));
1604  BEAST_EXPECT(!inOwnerDir(*env.current(), alice, chanSle));
1605  BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
1606  BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle));
1607  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
1608  }
1609 
1610  {
1611  // Test removing paychans created before adding to the recipient's
1612  // owner directory
1613  Env env(
1615  env.fund(XRP(10000), alice, bob);
1616  // create the channel before the amendment activates
1617  env(create(alice, bob, XRP(1000), settleDelay, pk));
1618  env.close();
1619  auto const [chan, chanSle] =
1620  channelKeyAndSle(*env.current(), alice, bob);
1621  BEAST_EXPECT(inOwnerDir(*env.current(), alice, chanSle));
1622  BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
1623  BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle));
1624  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
1626  env.close();
1627  BEAST_EXPECT(
1628  env.current()->rules().enabled(fixPayChanRecipientOwnerDir));
1629  // These checks look redundant, but if you don't `close` after the
1630  // `create` these checks will fail. I believe this is due to the
1631  // create running with one set of amendments initially, then with a
1632  // different set with the ledger closes (tho I haven't dug into it)
1633  BEAST_EXPECT(inOwnerDir(*env.current(), alice, chanSle));
1634  BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle));
1635  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
1636 
1637  // close the channel after the amendment activates
1638  env(claim(bob, chan), txflags(tfClose));
1639  BEAST_EXPECT(!channelExists(*env.current(), chan));
1640  BEAST_EXPECT(!inOwnerDir(*env.current(), alice, chanSle));
1641  BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
1642  BEAST_EXPECT(!inOwnerDir(*env.current(), bob, chanSle));
1643  BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
1644  }
1645  }
1646 
1647  void
1649  {
1650  testcase("Account Delete");
1651  using namespace test::jtx;
1652  using namespace std::literals::chrono_literals;
1653  auto rmAccount = [this](
1654  Env& env,
1655  Account const& toRm,
1656  Account const& dst,
1657  TER expectedTer = tesSUCCESS) {
1658  // only allow an account to be deleted if the account's sequence
1659  // number is at least 256 less than the current ledger sequence
1660  for (auto minRmSeq = env.seq(toRm) + 257;
1661  env.current()->seq() < minRmSeq;
1662  env.close())
1663  {
1664  }
1665 
1666  env(acctdelete(toRm, dst),
1667  fee(drops(env.current()->fees().increment)),
1668  ter(expectedTer));
1669  env.close();
1670  this->BEAST_EXPECT(
1671  isTesSuccess(expectedTer) ==
1672  !env.closed()->exists(keylet::account(toRm.id())));
1673  };
1674 
1675  auto const alice = Account("alice");
1676  auto const bob = Account("bob");
1677  auto const carol = Account("carol");
1678 
1679  for (bool const withOwnerDirFix : {false, true})
1680  {
1681  auto const amd = withOwnerDirFix
1684  Env env{*this, amd};
1685  env.fund(XRP(10000), alice, bob, carol);
1686  env.close();
1687  auto const feeDrops = env.current()->fees().base;
1688 
1689  // Create a channel from alice to bob
1690  auto const pk = alice.pk();
1691  auto const settleDelay = 100s;
1692  env(create(alice, bob, XRP(1000), settleDelay, pk));
1693  env.close();
1694  auto const chan = channel(*env.current(), alice, bob);
1695  BEAST_EXPECT(channelBalance(*env.current(), chan) == XRP(0));
1696  BEAST_EXPECT(channelAmount(*env.current(), chan) == XRP(1000));
1697 
1698  rmAccount(env, alice, carol, tecHAS_OBLIGATIONS);
1699  // can only remove bob if the channel isn't in their owner direcotry
1700  rmAccount(
1701  env,
1702  bob,
1703  carol,
1704  withOwnerDirFix ? TER(tecHAS_OBLIGATIONS) : TER(tesSUCCESS));
1705 
1706  auto chanBal = channelBalance(*env.current(), chan);
1707  auto chanAmt = channelAmount(*env.current(), chan);
1708  BEAST_EXPECT(chanBal == XRP(0));
1709  BEAST_EXPECT(chanAmt == XRP(1000));
1710 
1711  auto preBob = env.balance(bob);
1712  auto const delta = XRP(50);
1713  auto reqBal = chanBal + delta;
1714  auto authAmt = reqBal + XRP(100);
1715  assert(reqBal <= chanAmt);
1716 
1717  // claim should fail if the dst was removed
1718  if (withOwnerDirFix)
1719  {
1720  env(claim(alice, chan, reqBal, authAmt));
1721  env.close();
1722  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
1723  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1724  BEAST_EXPECT(env.balance(bob) == preBob + delta);
1725  chanBal = reqBal;
1726  }
1727  else
1728  {
1729  auto const preAlice = env.balance(alice);
1730  env(claim(alice, chan, reqBal, authAmt), ter(tecNO_DST));
1731  env.close();
1732  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
1733  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1734  BEAST_EXPECT(env.balance(bob) == preBob);
1735  BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops);
1736  }
1737 
1738  // fund should fail if the dst was removed
1739  if (withOwnerDirFix)
1740  {
1741  auto const preAlice = env.balance(alice);
1742  env(fund(alice, chan, XRP(1000)));
1743  env.close();
1744  BEAST_EXPECT(
1745  env.balance(alice) == preAlice - XRP(1000) - feeDrops);
1746  BEAST_EXPECT(
1747  channelAmount(*env.current(), chan) == chanAmt + XRP(1000));
1748  chanAmt = chanAmt + XRP(1000);
1749  }
1750  else
1751  {
1752  auto const preAlice = env.balance(alice);
1753  env(fund(alice, chan, XRP(1000)), ter(tecNO_DST));
1754  env.close();
1755  BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops);
1756  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1757  }
1758 
1759  {
1760  // Owner closes, will close after settleDelay
1761  env(claim(alice, chan), txflags(tfClose));
1762  env.close();
1763  // settle delay hasn't ellapsed. Channels should exist.
1764  BEAST_EXPECT(channelExists(*env.current(), chan));
1765  auto const closeTime = env.current()->info().parentCloseTime;
1766  auto const minExpiration = closeTime + settleDelay;
1767  env.close(minExpiration);
1768  env(claim(alice, chan), txflags(tfClose));
1769  BEAST_EXPECT(!channelExists(*env.current(), chan));
1770  }
1771  }
1772 
1773  {
1774  // test resurrected account
1775  Env env{
1777  env.fund(XRP(10000), alice, bob, carol);
1778  env.close();
1779  auto const feeDrops = env.current()->fees().base;
1780 
1781  // Create a channel from alice to bob
1782  auto const pk = alice.pk();
1783  auto const settleDelay = 100s;
1784  env(create(alice, bob, XRP(1000), settleDelay, pk));
1785  env.close();
1786  auto const chan = channel(*env.current(), alice, bob);
1787  BEAST_EXPECT(channelBalance(*env.current(), chan) == XRP(0));
1788  BEAST_EXPECT(channelAmount(*env.current(), chan) == XRP(1000));
1789 
1790  // Since `fixPayChanRecipientOwnerDir` is not active, can remove bob
1791  rmAccount(env, bob, carol);
1792  BEAST_EXPECT(!env.closed()->exists(keylet::account(bob.id())));
1793 
1794  auto chanBal = channelBalance(*env.current(), chan);
1795  auto chanAmt = channelAmount(*env.current(), chan);
1796  BEAST_EXPECT(chanBal == XRP(0));
1797  BEAST_EXPECT(chanAmt == XRP(1000));
1798  auto preBob = env.balance(bob);
1799  auto const delta = XRP(50);
1800  auto reqBal = chanBal + delta;
1801  auto authAmt = reqBal + XRP(100);
1802  assert(reqBal <= chanAmt);
1803 
1804  {
1805  // claim should fail, since bob doesn't exist
1806  auto const preAlice = env.balance(alice);
1807  env(claim(alice, chan, reqBal, authAmt), ter(tecNO_DST));
1808  env.close();
1809  BEAST_EXPECT(channelBalance(*env.current(), chan) == chanBal);
1810  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1811  BEAST_EXPECT(env.balance(bob) == preBob);
1812  BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops);
1813  }
1814 
1815  {
1816  // fund should fail, sincebob doesn't exist
1817  auto const preAlice = env.balance(alice);
1818  env(fund(alice, chan, XRP(1000)), ter(tecNO_DST));
1819  env.close();
1820  BEAST_EXPECT(env.balance(alice) == preAlice - feeDrops);
1821  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1822  }
1823 
1824  // resurrect bob
1825  env(pay(alice, bob, XRP(20)));
1826  env.close();
1827  BEAST_EXPECT(env.closed()->exists(keylet::account(bob.id())));
1828 
1829  {
1830  // alice should be able to claim
1831  preBob = env.balance(bob);
1832  reqBal = chanBal + delta;
1833  authAmt = reqBal + XRP(100);
1834  env(claim(alice, chan, reqBal, authAmt));
1835  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
1836  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1837  BEAST_EXPECT(env.balance(bob) == preBob + delta);
1838  chanBal = reqBal;
1839  }
1840 
1841  {
1842  // bob should be able to claim
1843  preBob = env.balance(bob);
1844  reqBal = chanBal + delta;
1845  authAmt = reqBal + XRP(100);
1846  auto const sig =
1847  signClaimAuth(alice.pk(), alice.sk(), chan, authAmt);
1848  env(claim(bob, chan, reqBal, authAmt, Slice(sig), alice.pk()));
1849  BEAST_EXPECT(channelBalance(*env.current(), chan) == reqBal);
1850  BEAST_EXPECT(channelAmount(*env.current(), chan) == chanAmt);
1851  BEAST_EXPECT(env.balance(bob) == preBob + delta - feeDrops);
1852  chanBal = reqBal;
1853  }
1854 
1855  {
1856  // alice should be able to fund
1857  auto const preAlice = env.balance(alice);
1858  env(fund(alice, chan, XRP(1000)));
1859  BEAST_EXPECT(
1860  env.balance(alice) == preAlice - XRP(1000) - feeDrops);
1861  BEAST_EXPECT(
1862  channelAmount(*env.current(), chan) == chanAmt + XRP(1000));
1863  chanAmt = chanAmt + XRP(1000);
1864  }
1865 
1866  {
1867  // Owner closes, will close after settleDelay
1868  env(claim(alice, chan), txflags(tfClose));
1869  env.close();
1870  // settle delay hasn't ellapsed. Channels should exist.
1871  BEAST_EXPECT(channelExists(*env.current(), chan));
1872  auto const closeTime = env.current()->info().parentCloseTime;
1873  auto const minExpiration = closeTime + settleDelay;
1874  env.close(minExpiration);
1875  env(claim(alice, chan), txflags(tfClose));
1876  BEAST_EXPECT(!channelExists(*env.current(), chan));
1877  }
1878  }
1879  }
1880 
1881  void
1882  run() override
1883  {
1884  testSimple();
1885  testCancelAfter();
1886  testSettleDelay();
1887  testExpiration();
1888  testCloseDry();
1890  testDisallowXRP();
1891  testDstTag();
1892  testDepositAuth();
1893  testMultiple();
1899  testMalformedPK();
1902  }
1903 };
1904 
1905 BEAST_DEFINE_TESTSUITE(PayChan, app, ripple);
1906 } // namespace test
1907 } // namespace ripple
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:276
ripple::test::PayChan_test::testAccountDelete
void testAccountDelete()
Definition: PayChan_test.cpp:1648
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:262
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:241
ripple::test::PayChan_test::testCancelAfter
void testCancelAfter()
Definition: PayChan_test.cpp:352
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::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:576
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:105
std::pair
std::vector::reserve
T reserve(T... args)
ripple::tfClose
const std::uint32_t tfClose
Definition: TxFlags.h:106
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:110
std::vector
STL class.
std::find
T find(T... args)
ripple::test::jtx::Env::enableFeature
void enableFeature(uint256 const feature)
Definition: Env.cpp:443
std::set::size
T size(T... args)
ripple::sfSequence
const SF_U32 sfSequence(access, STI_UINT32, 4, "Sequence")
Definition: SField.h:355
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:594
std::chrono::duration
ripple::featureDepositAuth
const uint256 featureDepositAuth
Definition: Feature.cpp:167
ripple::tecDST_TAG_NEEDED
@ tecDST_TAG_NEEDED
Definition: TER.h:267
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
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:155
std::distance
T distance(T... args)
ripple::test::PayChan_test::channelExists
static bool channelExists(ReadView const &view, uint256 const &chan)
Definition: PayChan_test.cpp:83
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:164
ripple::test::PayChan_test::testAccountChannelsRPC
void testAccountChannelsRPC()
Definition: PayChan_test.cpp:869
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:31
ripple::sfAmount
const SF_Amount sfAmount(access, STI_AMOUNT, 1, "Amount")
Definition: SField.h:439
ripple::temDST_IS_SRC
@ temDST_IS_SRC
Definition: TER.h:103
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:299
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:1470
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:120
ripple::test::PayChan_test::channel
static uint256 channel(ReadView const &view, jtx::Account const &account, jtx::Account const &dst)
Definition: PayChan_test.cpp:36
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:1882
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:253
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:547
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:243
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:63
std::chrono::time_point
ripple::fixPayChanRecipientOwnerDir
const uint256 fixPayChanRecipientOwnerDir
Definition: Feature.cpp:179
ripple::test::PayChan_test::testMultiple
void testMultiple()
Definition: PayChan_test.cpp:846
ripple::temBAD_AMOUNT
@ temBAD_AMOUNT
Definition: TER.h:84
ripple::test::PayChan_test::testMetaAndOwnership
void testMetaAndOwnership()
Definition: PayChan_test.cpp:1540
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:69
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: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:188
ripple::test::jtx::fclear
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition: flags.h:40
ripple::sfExpiration
const SF_U32 sfExpiration(access, STI_UINT32, 10, "Expiration")
Definition: SField.h:361
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:99
ripple::Serializer
Definition: Serializer.h:39
std::string::substr
T substr(T... args)
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:188
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:74
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:49
ripple::sfBalance
const SF_Amount sfBalance(access, STI_AMOUNT, 2, "Balance")
Definition: SField.h:440
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:297
ripple::sign
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Definition: SecretKey.cpp:124
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:136
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, boost::optional< std::chrono::milliseconds > consensusDelay=boost::none)
Close and advance the ledger.
Definition: Env.cpp:111
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:209
ripple::test::PayChan_test::signClaimAuth
static Buffer signClaimAuth(PublicKey const &pk, SecretKey const &sk, uint256 const &channel, STAmount const &authAmt)
Definition: PayChan_test.cpp:62
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::test::PayChan_test::testAccountChannelsRPCMarkers
void testAccountChannelsRPCMarkers()
Definition: PayChan_test.cpp:924
ripple::test::PayChan_test::channelAmount
static STAmount channelAmount(ReadView const &view, uint256 const &chan)
Definition: PayChan_test.cpp:90
ripple::tecHAS_OBLIGATIONS
@ tecHAS_OBLIGATIONS
Definition: TER.h:275
ripple::tecNO_PERMISSION
@ tecNO_PERMISSION
Definition: TER.h:263
ripple::Dir
Definition: Directory.h:28
ripple::tfRenew
const std::uint32_t tfRenew
Definition: TxFlags.h:105
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:697
ripple::ltPAYCHAN
@ ltPAYCHAN
Definition: LedgerFormats.h:83
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:582
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:67
ripple::tecNO_ENTRY
@ tecNO_ENTRY
Definition: TER.h:264
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:82
ripple::test::PayChan_test::testExpiration
void testExpiration()
Definition: PayChan_test.cpp:422
ripple::test::PayChan_test::testCloseDry
void testCloseDry()
Definition: PayChan_test.cpp:548
ripple::temBAD_EXPIRATION
@ temBAD_EXPIRATION
Definition: TER.h:86
ripple::test::PayChan_test::testSimple
void testSimple()
Definition: PayChan_test.cpp:181
ripple::test::PayChan_test::testDisallowXRP
void testDisallowXRP()
Definition: PayChan_test.cpp:637
ripple::test::PayChan_test::testDepositAuth
void testDepositAuth()
Definition: PayChan_test.cpp:722
ripple::test::PayChan_test::testSettleDelay
void testSettleDelay()
Definition: PayChan_test.cpp:488
ripple::test::PayChan_test
Definition: PayChan_test.cpp:33
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:213
ripple::test::PayChan_test::testOptionalFields
void testOptionalFields()
Definition: PayChan_test.cpp:1419
std::set< std::string >
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:297
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:114
ripple::tecNO_DST
@ tecNO_DST
Definition: TER.h:248
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:682
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::XRPAmount
Definition: XRPAmount.h:46
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469