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