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