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