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