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