rippled
Loading...
Searching...
No Matches
Escrow_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/jtx.h>
21
22#include <xrpld/app/tx/applySteps.h>
23#include <xrpld/ledger/Dir.h>
24
25#include <xrpl/protocol/Feature.h>
26#include <xrpl/protocol/Indexes.h>
27#include <xrpl/protocol/TxFlags.h>
28#include <xrpl/protocol/jss.h>
29
30#include <algorithm>
31#include <iterator>
32
33namespace ripple {
34namespace test {
35
37{
38 void
40 {
41 testcase("Enablement");
42
43 using namespace jtx;
44 using namespace std::chrono;
45
46 Env env(*this, features);
47 auto const baseFee = env.current()->fees().base;
48 env.fund(XRP(5000), "alice", "bob");
49 env(escrow::create("alice", "bob", XRP(1000)),
50 escrow::finish_time(env.now() + 1s));
51 env.close();
52
53 auto const seq1 = env.seq("alice");
54
55 env(escrow::create("alice", "bob", XRP(1000)),
57 escrow::finish_time(env.now() + 1s),
58 fee(baseFee * 150));
59 env.close();
60 env(escrow::finish("bob", "alice", seq1),
63 fee(baseFee * 150));
64
65 auto const seq2 = env.seq("alice");
66
67 env(escrow::create("alice", "bob", XRP(1000)),
69 escrow::finish_time(env.now() + 1s),
70 escrow::cancel_time(env.now() + 2s),
71 fee(baseFee * 150));
72 env.close();
73 env(escrow::cancel("bob", "alice", seq2), fee(baseFee * 150));
74 }
75
76 void
78 {
79 using namespace jtx;
80 using namespace std::chrono;
81
82 {
83 testcase("Timing: Finish Only");
84 Env env(*this, features);
85 auto const baseFee = env.current()->fees().base;
86 env.fund(XRP(5000), "alice", "bob");
87 env.close();
88
89 // We create an escrow that can be finished in the future
90 auto const ts = env.now() + 97s;
91
92 auto const seq = env.seq("alice");
93 env(escrow::create("alice", "bob", XRP(1000)),
95
96 // Advance the ledger, verifying that the finish won't complete
97 // prematurely.
98 for (; env.now() < ts; env.close())
99 env(escrow::finish("bob", "alice", seq),
100 fee(baseFee * 150),
102
103 env(escrow::finish("bob", "alice", seq), fee(baseFee * 150));
104 }
105
106 {
107 testcase("Timing: Cancel Only");
108 Env env(*this, features);
109 auto const baseFee = env.current()->fees().base;
110 env.fund(XRP(5000), "alice", "bob");
111 env.close();
112
113 // We create an escrow that can be cancelled in the future
114 auto const ts = env.now() + 117s;
115
116 auto const seq = env.seq("alice");
117 env(escrow::create("alice", "bob", XRP(1000)),
120
121 // Advance the ledger, verifying that the cancel won't complete
122 // prematurely.
123 for (; env.now() < ts; env.close())
124 env(escrow::cancel("bob", "alice", seq),
125 fee(baseFee * 150),
127
128 // Verify that a finish won't work anymore.
129 env(escrow::finish("bob", "alice", seq),
132 fee(baseFee * 150),
134
135 // Verify that the cancel will succeed
136 env(escrow::cancel("bob", "alice", seq), fee(baseFee * 150));
137 }
138
139 {
140 testcase("Timing: Finish and Cancel -> Finish");
141 Env env(*this, features);
142 auto const baseFee = env.current()->fees().base;
143 env.fund(XRP(5000), "alice", "bob");
144 env.close();
145
146 // We create an escrow that can be cancelled in the future
147 auto const fts = env.now() + 117s;
148 auto const cts = env.now() + 192s;
149
150 auto const seq = env.seq("alice");
151 env(escrow::create("alice", "bob", XRP(1000)),
154
155 // Advance the ledger, verifying that the finish and cancel won't
156 // complete prematurely.
157 for (; env.now() < fts; env.close())
158 {
159 env(escrow::finish("bob", "alice", seq),
160 fee(baseFee * 150),
162 env(escrow::cancel("bob", "alice", seq),
163 fee(baseFee * 150),
165 }
166
167 // Verify that a cancel still won't work
168 env(escrow::cancel("bob", "alice", seq),
169 fee(baseFee * 150),
171
172 // And verify that a finish will
173 env(escrow::finish("bob", "alice", seq), fee(baseFee * 150));
174 }
175
176 {
177 testcase("Timing: Finish and Cancel -> Cancel");
178 Env env(*this, features);
179 auto const baseFee = env.current()->fees().base;
180 env.fund(XRP(5000), "alice", "bob");
181 env.close();
182
183 // We create an escrow that can be cancelled in the future
184 auto const fts = env.now() + 109s;
185 auto const cts = env.now() + 184s;
186
187 auto const seq = env.seq("alice");
188 env(escrow::create("alice", "bob", XRP(1000)),
191
192 // Advance the ledger, verifying that the finish and cancel won't
193 // complete prematurely.
194 for (; env.now() < fts; env.close())
195 {
196 env(escrow::finish("bob", "alice", seq),
197 fee(baseFee * 150),
199 env(escrow::cancel("bob", "alice", seq),
200 fee(baseFee * 150),
202 }
203
204 // Continue advancing, verifying that the cancel won't complete
205 // prematurely. At this point a finish would succeed.
206 for (; env.now() < cts; env.close())
207 env(escrow::cancel("bob", "alice", seq),
208 fee(baseFee * 150),
210
211 // Verify that finish will no longer work, since we are past the
212 // cancel activation time.
213 env(escrow::finish("bob", "alice", seq),
214 fee(baseFee * 150),
216
217 // And verify that a cancel will succeed.
218 env(escrow::cancel("bob", "alice", seq), fee(baseFee * 150));
219 }
220 }
221
222 void
224 {
225 testcase("Tags");
226
227 using namespace jtx;
228 using namespace std::chrono;
229
230 Env env(*this, features);
231
232 auto const alice = Account("alice");
233 auto const bob = Account("bob");
234
235 env.fund(XRP(5000), alice, bob);
236
237 // Check to make sure that we correctly detect if tags are really
238 // required:
239 env(fset(bob, asfRequireDest));
240 env(escrow::create(alice, bob, XRP(1000)),
241 escrow::finish_time(env.now() + 1s),
243
244 // set source and dest tags
245 auto const seq = env.seq(alice);
246
247 env(escrow::create(alice, bob, XRP(1000)),
248 escrow::finish_time(env.now() + 1s),
249 stag(1),
250 dtag(2));
251
252 auto const sle = env.le(keylet::escrow(alice.id(), seq));
253 BEAST_EXPECT(sle);
254 BEAST_EXPECT((*sle)[sfSourceTag] == 1);
255 BEAST_EXPECT((*sle)[sfDestinationTag] == 2);
256 }
257
258 void
260 {
261 testcase("Disallow XRP");
262
263 using namespace jtx;
264 using namespace std::chrono;
265
266 {
267 // Respect the "asfDisallowXRP" account flag:
268 Env env(*this, features - featureDepositAuth);
269
270 env.fund(XRP(5000), "bob", "george");
271 env(fset("george", asfDisallowXRP));
272 env(escrow::create("bob", "george", XRP(10)),
273 escrow::finish_time(env.now() + 1s),
275 }
276 {
277 // Ignore the "asfDisallowXRP" account flag, which we should
278 // have been doing before.
279 Env env(*this, features);
280
281 env.fund(XRP(5000), "bob", "george");
282 env(fset("george", asfDisallowXRP));
283 env(escrow::create("bob", "george", XRP(10)),
284 escrow::finish_time(env.now() + 1s));
285 }
286 }
287
288 void
290 {
291 using namespace jtx;
292 using namespace std::chrono;
293
294 {
295 testcase("Implied Finish Time (without fix1571)");
296
297 Env env(*this, supported_amendments() - fix1571);
298 auto const baseFee = env.current()->fees().base;
299 env.fund(XRP(5000), "alice", "bob", "carol");
300 env.close();
301
302 // Creating an escrow without a finish time and finishing it
303 // is allowed without fix1571:
304 auto const seq1 = env.seq("alice");
305 env(escrow::create("alice", "bob", XRP(100)),
306 escrow::cancel_time(env.now() + 1s),
307 fee(baseFee * 150));
308 env.close();
309 env(escrow::finish("carol", "alice", seq1), fee(baseFee * 150));
310 BEAST_EXPECT(env.balance("bob") == XRP(5100));
311
312 env.close();
313
314 // Creating an escrow without a finish time and a condition is
315 // also allowed without fix1571:
316 auto const seq2 = env.seq("alice");
317 env(escrow::create("alice", "bob", XRP(100)),
318 escrow::cancel_time(env.now() + 1s),
320 fee(baseFee * 150));
321 env.close();
322 env(escrow::finish("carol", "alice", seq2),
325 fee(baseFee * 150));
326 BEAST_EXPECT(env.balance("bob") == XRP(5200));
327 }
328
329 {
330 testcase("Implied Finish Time (with fix1571)");
331
332 Env env(*this, features);
333 auto const baseFee = env.current()->fees().base;
334 env.fund(XRP(5000), "alice", "bob", "carol");
335 env.close();
336
337 // Creating an escrow with only a cancel time is not allowed:
338 env(escrow::create("alice", "bob", XRP(100)),
339 escrow::cancel_time(env.now() + 90s),
340 fee(baseFee * 150),
342
343 // Creating an escrow with only a cancel time and a condition is
344 // allowed:
345 auto const seq = env.seq("alice");
346 env(escrow::create("alice", "bob", XRP(100)),
347 escrow::cancel_time(env.now() + 90s),
349 fee(baseFee * 150));
350 env.close();
351 env(escrow::finish("carol", "alice", seq),
354 fee(baseFee * 150));
355 BEAST_EXPECT(env.balance("bob") == XRP(5100));
356 }
357 }
358
359 void
361 {
362 testcase("Failure Cases");
363
364 using namespace jtx;
365 using namespace std::chrono;
366
367 Env env(*this, features);
368 auto const baseFee = env.current()->fees().base;
369 env.fund(XRP(5000), "alice", "bob", "gw");
370 env.close();
371
372 // temINVALID_FLAG
373 env(escrow::create("alice", "bob", XRP(1000)),
374 escrow::finish_time(env.now() + 5s),
377
378 // Finish time is in the past
379 env(escrow::create("alice", "bob", XRP(1000)),
380 escrow::finish_time(env.now() - 5s),
382
383 // Cancel time is in the past
384 env(escrow::create("alice", "bob", XRP(1000)),
386 escrow::cancel_time(env.now() - 5s),
388
389 // no destination account
390 env(escrow::create("alice", "carol", XRP(1000)),
391 escrow::finish_time(env.now() + 1s),
392 ter(tecNO_DST));
393
394 env.fund(XRP(5000), "carol");
395
396 // Using non-XRP:
397 bool const withTokenEscrow =
398 env.current()->rules().enabled(featureTokenEscrow);
399 {
400 // tecNO_PERMISSION: token escrow is enabled but the issuer did not
401 // set the asfAllowTrustLineLocking flag
402 auto const txResult =
403 withTokenEscrow ? ter(tecNO_PERMISSION) : ter(temBAD_AMOUNT);
404 env(escrow::create("alice", "carol", Account("alice")["USD"](500)),
405 escrow::finish_time(env.now() + 5s),
406 txResult);
407 }
408
409 // Sending zero or no XRP:
410 env(escrow::create("alice", "carol", XRP(0)),
411 escrow::finish_time(env.now() + 1s),
413 env(escrow::create("alice", "carol", XRP(-1000)),
414 escrow::finish_time(env.now() + 1s),
416
417 // Fail if neither CancelAfter nor FinishAfter are specified:
418 env(escrow::create("alice", "carol", XRP(1)), ter(temBAD_EXPIRATION));
419
420 // Fail if neither a FinishTime nor a condition are attached:
421 env(escrow::create("alice", "carol", XRP(1)),
422 escrow::cancel_time(env.now() + 1s),
424
425 // Fail if FinishAfter has already passed:
426 env(escrow::create("alice", "carol", XRP(1)),
427 escrow::finish_time(env.now() - 1s),
429
430 // If both CancelAfter and FinishAfter are set, then CancelAfter must
431 // be strictly later than FinishAfter.
432 env(escrow::create("alice", "carol", XRP(1)),
434 escrow::finish_time(env.now() + 10s),
435 escrow::cancel_time(env.now() + 10s),
437
438 env(escrow::create("alice", "carol", XRP(1)),
440 escrow::finish_time(env.now() + 10s),
441 escrow::cancel_time(env.now() + 5s),
443
444 // Carol now requires the use of a destination tag
445 env(fset("carol", asfRequireDest));
446
447 // missing destination tag
448 env(escrow::create("alice", "carol", XRP(1)),
450 escrow::cancel_time(env.now() + 1s),
452
453 // Success!
454 env(escrow::create("alice", "carol", XRP(1)),
456 escrow::cancel_time(env.now() + 1s),
457 dtag(1));
458
459 { // Fail if the sender wants to send more than he has:
460 auto const accountReserve = drops(env.current()->fees().reserve);
461 auto const accountIncrement =
462 drops(env.current()->fees().increment);
463
464 env.fund(accountReserve + accountIncrement + XRP(50), "daniel");
465 env(escrow::create("daniel", "bob", XRP(51)),
466 escrow::finish_time(env.now() + 1s),
468
469 env.fund(accountReserve + accountIncrement + XRP(50), "evan");
470 env(escrow::create("evan", "bob", XRP(50)),
471 escrow::finish_time(env.now() + 1s),
473
474 env.fund(accountReserve, "frank");
475 env(escrow::create("frank", "bob", XRP(1)),
476 escrow::finish_time(env.now() + 1s),
478 }
479
480 { // Specify incorrect sequence number
481 env.fund(XRP(5000), "hannah");
482 auto const seq = env.seq("hannah");
483 env(escrow::create("hannah", "hannah", XRP(10)),
484 escrow::finish_time(env.now() + 1s),
485 fee(150 * baseFee));
486 env.close();
487 env(escrow::finish("hannah", "hannah", seq + 7),
488 fee(150 * baseFee),
490 }
491
492 { // Try to specify a condition for a non-conditional payment
493 env.fund(XRP(5000), "ivan");
494 auto const seq = env.seq("ivan");
495
496 env(escrow::create("ivan", "ivan", XRP(10)),
497 escrow::finish_time(env.now() + 1s));
498 env.close();
499 env(escrow::finish("ivan", "ivan", seq),
502 fee(150 * baseFee),
504 }
505 }
506
507 void
509 {
510 testcase("Lockup");
511
512 using namespace jtx;
513 using namespace std::chrono;
514
515 {
516 // Unconditional
517 Env env(*this, features);
518 auto const baseFee = env.current()->fees().base;
519 env.fund(XRP(5000), "alice", "bob");
520 auto const seq = env.seq("alice");
521 env(escrow::create("alice", "alice", XRP(1000)),
522 escrow::finish_time(env.now() + 5s));
523 env.require(balance("alice", XRP(4000) - drops(baseFee)));
524
525 // Not enough time has elapsed for a finish and canceling isn't
526 // possible.
527 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
528 env(escrow::finish("bob", "alice", seq), ter(tecNO_PERMISSION));
529 env.close();
530
531 // Cancel continues to not be possible
532 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
533
534 // Finish should succeed. Verify funds.
535 env(escrow::finish("bob", "alice", seq));
536 env.require(balance("alice", XRP(5000) - drops(baseFee)));
537 }
538 {
539 // Unconditionally pay from Alice to Bob. Zelda (neither source nor
540 // destination) signs all cancels and finishes. This shows that
541 // Escrow will make a payment to Bob with no intervention from Bob.
542 Env env(*this, features);
543 auto const baseFee = env.current()->fees().base;
544 env.fund(XRP(5000), "alice", "bob", "zelda");
545 auto const seq = env.seq("alice");
546 env(escrow::create("alice", "bob", XRP(1000)),
547 escrow::finish_time(env.now() + 5s));
548 env.require(balance("alice", XRP(4000) - drops(baseFee)));
549
550 // Not enough time has elapsed for a finish and canceling isn't
551 // possible.
552 env(escrow::cancel("zelda", "alice", seq), ter(tecNO_PERMISSION));
553 env(escrow::finish("zelda", "alice", seq), ter(tecNO_PERMISSION));
554 env.close();
555
556 // Cancel continues to not be possible
557 env(escrow::cancel("zelda", "alice", seq), ter(tecNO_PERMISSION));
558
559 // Finish should succeed. Verify funds.
560 env(escrow::finish("zelda", "alice", seq));
561 env.close();
562
563 env.require(balance("alice", XRP(4000) - drops(baseFee)));
564 env.require(balance("bob", XRP(6000)));
565 env.require(balance("zelda", XRP(5000) - drops(4 * baseFee)));
566 }
567 {
568 // Bob sets DepositAuth so only Bob can finish the escrow.
569 Env env(*this, features);
570 auto const baseFee = env.current()->fees().base;
571
572 env.fund(XRP(5000), "alice", "bob", "zelda");
573 env(fset("bob", asfDepositAuth));
574 env.close();
575
576 auto const seq = env.seq("alice");
577 env(escrow::create("alice", "bob", XRP(1000)),
578 escrow::finish_time(env.now() + 5s));
579 env.require(balance("alice", XRP(4000) - drops(baseFee)));
580
581 // Not enough time has elapsed for a finish and canceling isn't
582 // possible.
583 env(escrow::cancel("zelda", "alice", seq), ter(tecNO_PERMISSION));
584 env(escrow::cancel("alice", "alice", seq), ter(tecNO_PERMISSION));
585 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
586 env(escrow::finish("zelda", "alice", seq), ter(tecNO_PERMISSION));
587 env(escrow::finish("alice", "alice", seq), ter(tecNO_PERMISSION));
588 env(escrow::finish("bob", "alice", seq), ter(tecNO_PERMISSION));
589 env.close();
590
591 // Cancel continues to not be possible. Finish will only succeed for
592 // Bob, because of DepositAuth.
593 env(escrow::cancel("zelda", "alice", seq), ter(tecNO_PERMISSION));
594 env(escrow::cancel("alice", "alice", seq), ter(tecNO_PERMISSION));
595 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
596 env(escrow::finish("zelda", "alice", seq), ter(tecNO_PERMISSION));
597 env(escrow::finish("alice", "alice", seq), ter(tecNO_PERMISSION));
598 env(escrow::finish("bob", "alice", seq));
599 env.close();
600
601 env.require(balance("alice", XRP(4000) - (baseFee * 5)));
602 env.require(balance("bob", XRP(6000) - (baseFee * 5)));
603 env.require(balance("zelda", XRP(5000) - (baseFee * 4)));
604 }
605 {
606 // Bob sets DepositAuth but preauthorizes Zelda, so Zelda can
607 // finish the escrow.
608 Env env(*this, features);
609 auto const baseFee = env.current()->fees().base;
610
611 env.fund(XRP(5000), "alice", "bob", "zelda");
612 env(fset("bob", asfDepositAuth));
613 env.close();
614 env(deposit::auth("bob", "zelda"));
615 env.close();
616
617 auto const seq = env.seq("alice");
618 env(escrow::create("alice", "bob", XRP(1000)),
619 escrow::finish_time(env.now() + 5s));
620 env.require(balance("alice", XRP(4000) - drops(baseFee)));
621 env.close();
622
623 // DepositPreauth allows Finish to succeed for either Zelda or
624 // Bob. But Finish won't succeed for Alice since she is not
625 // preauthorized.
626 env(escrow::finish("alice", "alice", seq), ter(tecNO_PERMISSION));
627 env(escrow::finish("zelda", "alice", seq));
628 env.close();
629
630 env.require(balance("alice", XRP(4000) - (baseFee * 2)));
631 env.require(balance("bob", XRP(6000) - (baseFee * 2)));
632 env.require(balance("zelda", XRP(5000) - (baseFee * 1)));
633 }
634 {
635 // Conditional
636 Env env(*this, features);
637 auto const baseFee = env.current()->fees().base;
638 env.fund(XRP(5000), "alice", "bob");
639 auto const seq = env.seq("alice");
640 env(escrow::create("alice", "alice", XRP(1000)),
642 escrow::finish_time(env.now() + 5s));
643 env.require(balance("alice", XRP(4000) - drops(baseFee)));
644
645 // Not enough time has elapsed for a finish and canceling isn't
646 // possible.
647 env(escrow::cancel("alice", "alice", seq), ter(tecNO_PERMISSION));
648 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
649 env(escrow::finish("alice", "alice", seq), ter(tecNO_PERMISSION));
650 env(escrow::finish("alice", "alice", seq),
653 fee(150 * baseFee),
655 env(escrow::finish("bob", "alice", seq), ter(tecNO_PERMISSION));
656 env(escrow::finish("bob", "alice", seq),
659 fee(150 * baseFee),
661 env.close();
662
663 // Cancel continues to not be possible. Finish is possible but
664 // requires the fulfillment associated with the escrow.
665 env(escrow::cancel("alice", "alice", seq), ter(tecNO_PERMISSION));
666 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
667 env(escrow::finish("bob", "alice", seq),
669 env(escrow::finish("alice", "alice", seq),
671 env.close();
672
673 env(escrow::finish("bob", "alice", seq),
676 fee(150 * baseFee));
677 }
678 {
679 // Self-escrowed conditional with DepositAuth.
680 Env env(*this, features);
681 auto const baseFee = env.current()->fees().base;
682
683 env.fund(XRP(5000), "alice", "bob");
684 auto const seq = env.seq("alice");
685 env(escrow::create("alice", "alice", XRP(1000)),
687 escrow::finish_time(env.now() + 5s));
688 env.require(balance("alice", XRP(4000) - drops(baseFee)));
689 env.close();
690
691 // Finish is now possible but requires the cryptocondition.
692 env(escrow::finish("bob", "alice", seq),
694 env(escrow::finish("alice", "alice", seq),
696
697 // Enable deposit authorization. After this only Alice can finish
698 // the escrow.
699 env(fset("alice", asfDepositAuth));
700 env.close();
701
702 env(escrow::finish("alice", "alice", seq),
705 fee(150 * baseFee),
707 env(escrow::finish("bob", "alice", seq),
710 fee(150 * baseFee),
712 env(escrow::finish("alice", "alice", seq),
715 fee(150 * baseFee));
716 }
717 {
718 // Self-escrowed conditional with DepositAuth and DepositPreauth.
719 Env env(*this, features);
720 auto const baseFee = env.current()->fees().base;
721
722 env.fund(XRP(5000), "alice", "bob", "zelda");
723 auto const seq = env.seq("alice");
724 env(escrow::create("alice", "alice", XRP(1000)),
726 escrow::finish_time(env.now() + 5s));
727 env.require(balance("alice", XRP(4000) - drops(baseFee)));
728 env.close();
729
730 // Alice preauthorizes Zelda for deposit, even though Alice has not
731 // set the lsfDepositAuth flag (yet).
732 env(deposit::auth("alice", "zelda"));
733 env.close();
734
735 // Finish is now possible but requires the cryptocondition.
736 env(escrow::finish("alice", "alice", seq),
738 env(escrow::finish("bob", "alice", seq),
740 env(escrow::finish("zelda", "alice", seq),
742
743 // Alice enables deposit authorization. After this only Alice or
744 // Zelda (because Zelda is preauthorized) can finish the escrow.
745 env(fset("alice", asfDepositAuth));
746 env.close();
747
748 env(escrow::finish("alice", "alice", seq),
751 fee(150 * baseFee),
753 env(escrow::finish("bob", "alice", seq),
756 fee(150 * baseFee),
758 env(escrow::finish("zelda", "alice", seq),
761 fee(150 * baseFee));
762 }
763 }
764
765 void
767 {
768 testcase("Escrow with CryptoConditions");
769
770 using namespace jtx;
771 using namespace std::chrono;
772
773 { // Test cryptoconditions
774 Env env(*this, features);
775 auto const baseFee = env.current()->fees().base;
776 env.fund(XRP(5000), "alice", "bob", "carol");
777 auto const seq = env.seq("alice");
778 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
779 env(escrow::create("alice", "carol", XRP(1000)),
781 escrow::cancel_time(env.now() + 1s));
782 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
783 env.require(balance("alice", XRP(4000) - drops(baseFee)));
784 env.require(balance("carol", XRP(5000)));
785 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
786 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
787
788 // Attempt to finish without a fulfillment
789 env(escrow::finish("bob", "alice", seq),
791 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
792
793 // Attempt to finish with a condition instead of a fulfillment
794 env(escrow::finish("bob", "alice", seq),
797 fee(150 * baseFee),
799 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
800 env(escrow::finish("bob", "alice", seq),
803 fee(150 * baseFee),
805 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
806 env(escrow::finish("bob", "alice", seq),
809 fee(150 * baseFee),
811 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
812
813 // Attempt to finish with an incorrect condition and various
814 // combinations of correct and incorrect fulfillments.
815 env(escrow::finish("bob", "alice", seq),
818 fee(150 * baseFee),
820 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
821 env(escrow::finish("bob", "alice", seq),
824 fee(150 * baseFee),
826 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
827 env(escrow::finish("bob", "alice", seq),
830 fee(150 * baseFee),
832 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
833
834 // Attempt to finish with the correct condition & fulfillment
835 env(escrow::finish("bob", "alice", seq),
838 fee(150 * baseFee));
839
840 // SLE removed on finish
841 BEAST_EXPECT(!env.le(keylet::escrow(Account("alice").id(), seq)));
842 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
843 env.require(balance("carol", XRP(6000)));
844 env(escrow::cancel("bob", "alice", seq), ter(tecNO_TARGET));
845 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
846 env(escrow::cancel("bob", "carol", 1), ter(tecNO_TARGET));
847 }
848 { // Test cancel when condition is present
849 Env env(*this, features);
850 auto const baseFee = env.current()->fees().base;
851 env.fund(XRP(5000), "alice", "bob", "carol");
852 auto const seq = env.seq("alice");
853 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
854 env(escrow::create("alice", "carol", XRP(1000)),
856 escrow::cancel_time(env.now() + 1s));
857 env.close();
858 env.require(balance("alice", XRP(4000) - drops(baseFee)));
859 // balance restored on cancel
860 env(escrow::cancel("bob", "alice", seq));
861 env.require(balance("alice", XRP(5000) - drops(baseFee)));
862 // SLE removed on cancel
863 BEAST_EXPECT(!env.le(keylet::escrow(Account("alice").id(), seq)));
864 }
865 {
866 Env env(*this, features);
867 auto const baseFee = env.current()->fees().base;
868 env.fund(XRP(5000), "alice", "bob", "carol");
869 env.close();
870 auto const seq = env.seq("alice");
871 env(escrow::create("alice", "carol", XRP(1000)),
873 escrow::cancel_time(env.now() + 1s));
874 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
875 // cancel fails before expiration
876 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
877 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
878 env.close();
879 // finish fails after expiration
880 env(escrow::finish("bob", "alice", seq),
883 fee(150 * baseFee),
885 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
886 env.require(balance("carol", XRP(5000)));
887 }
888 { // Test long & short conditions during creation
889 Env env(*this, features);
890 env.fund(XRP(5000), "alice", "bob", "carol");
891
893 v.resize(escrow::cb1.size() + 2, 0x78);
894 std::memcpy(v.data() + 1, escrow::cb1.data(), escrow::cb1.size());
895
896 auto const p = v.data();
897 auto const s = v.size();
898
899 auto const ts = env.now() + 1s;
900
901 // All these are expected to fail, because the
902 // condition we pass in is malformed in some way
903 env(escrow::create("alice", "carol", XRP(1000)),
907 env(escrow::create("alice", "carol", XRP(1000)),
908 escrow::condition(Slice{p, s - 1}),
911 env(escrow::create("alice", "carol", XRP(1000)),
912 escrow::condition(Slice{p, s - 2}),
915 env(escrow::create("alice", "carol", XRP(1000)),
916 escrow::condition(Slice{p + 1, s - 1}),
919 env(escrow::create("alice", "carol", XRP(1000)),
920 escrow::condition(Slice{p + 1, s - 3}),
923 env(escrow::create("alice", "carol", XRP(1000)),
924 escrow::condition(Slice{p + 2, s - 2}),
927 env(escrow::create("alice", "carol", XRP(1000)),
928 escrow::condition(Slice{p + 2, s - 3}),
931
932 auto const seq = env.seq("alice");
933 auto const baseFee = env.current()->fees().base;
934 env(escrow::create("alice", "carol", XRP(1000)),
935 escrow::condition(Slice{p + 1, s - 2}),
937 fee(10 * baseFee));
938 env(escrow::finish("bob", "alice", seq),
941 fee(150 * baseFee));
942 env.require(balance("alice", XRP(4000) - drops(10 * baseFee)));
943 env.require(balance("bob", XRP(5000) - drops(150 * baseFee)));
944 env.require(balance("carol", XRP(6000)));
945 }
946 { // Test long and short conditions & fulfillments during finish
947 Env env(*this, features);
948 env.fund(XRP(5000), "alice", "bob", "carol");
949
951 cv.resize(escrow::cb2.size() + 2, 0x78);
952 std::memcpy(cv.data() + 1, escrow::cb2.data(), escrow::cb2.size());
953
954 auto const cp = cv.data();
955 auto const cs = cv.size();
956
958 fv.resize(escrow::fb2.size() + 2, 0x13);
959 std::memcpy(fv.data() + 1, escrow::fb2.data(), escrow::fb2.size());
960
961 auto const fp = fv.data();
962 auto const fs = fv.size();
963
964 auto const ts = env.now() + 1s;
965
966 // All these are expected to fail, because the
967 // condition we pass in is malformed in some way
968 env(escrow::create("alice", "carol", XRP(1000)),
969 escrow::condition(Slice{cp, cs}),
972 env(escrow::create("alice", "carol", XRP(1000)),
973 escrow::condition(Slice{cp, cs - 1}),
976 env(escrow::create("alice", "carol", XRP(1000)),
977 escrow::condition(Slice{cp, cs - 2}),
980 env(escrow::create("alice", "carol", XRP(1000)),
981 escrow::condition(Slice{cp + 1, cs - 1}),
984 env(escrow::create("alice", "carol", XRP(1000)),
985 escrow::condition(Slice{cp + 1, cs - 3}),
988 env(escrow::create("alice", "carol", XRP(1000)),
989 escrow::condition(Slice{cp + 2, cs - 2}),
992 env(escrow::create("alice", "carol", XRP(1000)),
993 escrow::condition(Slice{cp + 2, cs - 3}),
996
997 auto const seq = env.seq("alice");
998 auto const baseFee = env.current()->fees().base;
999 env(escrow::create("alice", "carol", XRP(1000)),
1000 escrow::condition(Slice{cp + 1, cs - 2}),
1002 fee(10 * baseFee));
1003
1004 // Now, try to fulfill using the same sequence of
1005 // malformed conditions.
1006 env(escrow::finish("bob", "alice", seq),
1007 escrow::condition(Slice{cp, cs}),
1008 escrow::fulfillment(Slice{fp, fs}),
1009 fee(150 * baseFee),
1011 env(escrow::finish("bob", "alice", seq),
1012 escrow::condition(Slice{cp, cs - 1}),
1013 escrow::fulfillment(Slice{fp, fs}),
1014 fee(150 * baseFee),
1016 env(escrow::finish("bob", "alice", seq),
1017 escrow::condition(Slice{cp, cs - 2}),
1018 escrow::fulfillment(Slice{fp, fs}),
1019 fee(150 * baseFee),
1021 env(escrow::finish("bob", "alice", seq),
1022 escrow::condition(Slice{cp + 1, cs - 1}),
1023 escrow::fulfillment(Slice{fp, fs}),
1024 fee(150 * baseFee),
1026 env(escrow::finish("bob", "alice", seq),
1027 escrow::condition(Slice{cp + 1, cs - 3}),
1028 escrow::fulfillment(Slice{fp, fs}),
1029 fee(150 * baseFee),
1031 env(escrow::finish("bob", "alice", seq),
1032 escrow::condition(Slice{cp + 2, cs - 2}),
1033 escrow::fulfillment(Slice{fp, fs}),
1034 fee(150 * baseFee),
1036 env(escrow::finish("bob", "alice", seq),
1037 escrow::condition(Slice{cp + 2, cs - 3}),
1038 escrow::fulfillment(Slice{fp, fs}),
1039 fee(150 * baseFee),
1041
1042 // Now, using the correct condition, try malformed fulfillments:
1043 env(escrow::finish("bob", "alice", seq),
1044 escrow::condition(Slice{cp + 1, cs - 2}),
1045 escrow::fulfillment(Slice{fp, fs}),
1046 fee(150 * baseFee),
1048 env(escrow::finish("bob", "alice", seq),
1049 escrow::condition(Slice{cp + 1, cs - 2}),
1050 escrow::fulfillment(Slice{fp, fs - 1}),
1051 fee(150 * baseFee),
1053 env(escrow::finish("bob", "alice", seq),
1054 escrow::condition(Slice{cp + 1, cs - 2}),
1055 escrow::fulfillment(Slice{fp, fs - 2}),
1056 fee(150 * baseFee),
1058 env(escrow::finish("bob", "alice", seq),
1059 escrow::condition(Slice{cp + 1, cs - 2}),
1060 escrow::fulfillment(Slice{fp + 1, fs - 1}),
1061 fee(150 * baseFee),
1063 env(escrow::finish("bob", "alice", seq),
1064 escrow::condition(Slice{cp + 1, cs - 2}),
1065 escrow::fulfillment(Slice{fp + 1, fs - 3}),
1066 fee(150 * baseFee),
1068 env(escrow::finish("bob", "alice", seq),
1069 escrow::condition(Slice{cp + 1, cs - 2}),
1070 escrow::fulfillment(Slice{fp + 1, fs - 3}),
1071 fee(150 * baseFee),
1073 env(escrow::finish("bob", "alice", seq),
1074 escrow::condition(Slice{cp + 1, cs - 2}),
1075 escrow::fulfillment(Slice{fp + 2, fs - 2}),
1076 fee(150 * baseFee),
1078 env(escrow::finish("bob", "alice", seq),
1079 escrow::condition(Slice{cp + 1, cs - 2}),
1080 escrow::fulfillment(Slice{fp + 2, fs - 3}),
1081 fee(150 * baseFee),
1083
1084 // Now try for the right one
1085 env(escrow::finish("bob", "alice", seq),
1088 fee(150 * baseFee));
1089 env.require(balance("alice", XRP(4000) - drops(10 * baseFee)));
1090 env.require(balance("carol", XRP(6000)));
1091 }
1092 { // Test empty condition during creation and
1093 // empty condition & fulfillment during finish
1094 Env env(*this, features);
1095 env.fund(XRP(5000), "alice", "bob", "carol");
1096
1097 env(escrow::create("alice", "carol", XRP(1000)),
1099 escrow::cancel_time(env.now() + 1s),
1100 ter(temMALFORMED));
1101
1102 auto const seq = env.seq("alice");
1103 auto const baseFee = env.current()->fees().base;
1104 env(escrow::create("alice", "carol", XRP(1000)),
1106 escrow::cancel_time(env.now() + 1s));
1107
1108 env(escrow::finish("bob", "alice", seq),
1111 fee(150 * baseFee),
1113 env(escrow::finish("bob", "alice", seq),
1116 fee(150 * baseFee),
1118 env(escrow::finish("bob", "alice", seq),
1121 fee(150 * baseFee),
1123
1124 // Assemble finish that is missing the Condition or the Fulfillment
1125 // since either both must be present, or neither can:
1126 env(escrow::finish("bob", "alice", seq),
1128 ter(temMALFORMED));
1129 env(escrow::finish("bob", "alice", seq),
1131 ter(temMALFORMED));
1132
1133 // Now finish it.
1134 env(escrow::finish("bob", "alice", seq),
1137 fee(150 * baseFee));
1138 env.require(balance("carol", XRP(6000)));
1139 env.require(balance("alice", XRP(4000) - drops(baseFee)));
1140 }
1141 { // Test a condition other than PreimageSha256, which
1142 // would require a separate amendment
1143 Env env(*this, features);
1144 env.fund(XRP(5000), "alice", "bob");
1145
1147 {0xA2, 0x2B, 0x80, 0x20, 0x42, 0x4A, 0x70, 0x49, 0x49,
1148 0x52, 0x92, 0x67, 0xB6, 0x21, 0xB3, 0xD7, 0x91, 0x19,
1149 0xD7, 0x29, 0xB2, 0x38, 0x2C, 0xED, 0x8B, 0x29, 0x6C,
1150 0x3C, 0x02, 0x8F, 0xA9, 0x7D, 0x35, 0x0F, 0x6D, 0x07,
1151 0x81, 0x03, 0x06, 0x34, 0xD2, 0x82, 0x02, 0x03, 0xC8}};
1152
1153 // FIXME: this transaction should, eventually, return temDISABLED
1154 // instead of temMALFORMED.
1155 env(escrow::create("alice", "bob", XRP(1000)),
1157 escrow::cancel_time(env.now() + 1s),
1158 ter(temMALFORMED));
1159 }
1160 }
1161
1162 void
1164 {
1165 using namespace jtx;
1166 using namespace std::chrono;
1167
1168 auto const alice = Account("alice");
1169 auto const bruce = Account("bruce");
1170 auto const carol = Account("carol");
1171
1172 {
1173 testcase("Metadata to self");
1174
1175 Env env(*this, features);
1176 env.fund(XRP(5000), alice, bruce, carol);
1177 auto const aseq = env.seq(alice);
1178 auto const bseq = env.seq(bruce);
1179
1180 env(escrow::create(alice, alice, XRP(1000)),
1181 escrow::finish_time(env.now() + 1s),
1182 escrow::cancel_time(env.now() + 500s));
1183 BEAST_EXPECT(
1184 (*env.meta())[sfTransactionResult] ==
1185 static_cast<std::uint8_t>(tesSUCCESS));
1186 env.close(5s);
1187 auto const aa = env.le(keylet::escrow(alice.id(), aseq));
1188 BEAST_EXPECT(aa);
1189
1190 {
1191 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1192 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1193 BEAST_EXPECT(
1194 std::find(aod.begin(), aod.end(), aa) != aod.end());
1195 }
1196
1197 env(escrow::create(bruce, bruce, XRP(1000)),
1198 escrow::finish_time(env.now() + 1s),
1199 escrow::cancel_time(env.now() + 2s));
1200 BEAST_EXPECT(
1201 (*env.meta())[sfTransactionResult] ==
1202 static_cast<std::uint8_t>(tesSUCCESS));
1203 env.close(5s);
1204 auto const bb = env.le(keylet::escrow(bruce.id(), bseq));
1205 BEAST_EXPECT(bb);
1206
1207 {
1208 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1209 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1210 BEAST_EXPECT(
1211 std::find(bod.begin(), bod.end(), bb) != bod.end());
1212 }
1213
1214 env.close(5s);
1215 env(escrow::finish(alice, alice, aseq));
1216 {
1217 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1218 BEAST_EXPECT(
1219 (*env.meta())[sfTransactionResult] ==
1220 static_cast<std::uint8_t>(tesSUCCESS));
1221
1222 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1223 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0);
1224 BEAST_EXPECT(
1225 std::find(aod.begin(), aod.end(), aa) == aod.end());
1226
1227 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1228 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1229 BEAST_EXPECT(
1230 std::find(bod.begin(), bod.end(), bb) != bod.end());
1231 }
1232
1233 env.close(5s);
1234 env(escrow::cancel(bruce, bruce, bseq));
1235 {
1236 BEAST_EXPECT(!env.le(keylet::escrow(bruce.id(), bseq)));
1237 BEAST_EXPECT(
1238 (*env.meta())[sfTransactionResult] ==
1239 static_cast<std::uint8_t>(tesSUCCESS));
1240
1241 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1242 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 0);
1243 BEAST_EXPECT(
1244 std::find(bod.begin(), bod.end(), bb) == bod.end());
1245 }
1246 }
1247 {
1248 testcase("Metadata to other");
1249
1250 Env env(*this, features);
1251 env.fund(XRP(5000), alice, bruce, carol);
1252 auto const aseq = env.seq(alice);
1253 auto const bseq = env.seq(bruce);
1254
1255 env(escrow::create(alice, bruce, XRP(1000)),
1256 escrow::finish_time(env.now() + 1s));
1257 BEAST_EXPECT(
1258 (*env.meta())[sfTransactionResult] ==
1259 static_cast<std::uint8_t>(tesSUCCESS));
1260 env.close(5s);
1261 env(escrow::create(bruce, carol, XRP(1000)),
1262 escrow::finish_time(env.now() + 1s),
1263 escrow::cancel_time(env.now() + 2s));
1264 BEAST_EXPECT(
1265 (*env.meta())[sfTransactionResult] ==
1266 static_cast<std::uint8_t>(tesSUCCESS));
1267 env.close(5s);
1268
1269 auto const ab = env.le(keylet::escrow(alice.id(), aseq));
1270 BEAST_EXPECT(ab);
1271
1272 auto const bc = env.le(keylet::escrow(bruce.id(), bseq));
1273 BEAST_EXPECT(bc);
1274
1275 {
1276 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1277 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1278 BEAST_EXPECT(
1279 std::find(aod.begin(), aod.end(), ab) != aod.end());
1280
1281 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1282 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
1283 BEAST_EXPECT(
1284 std::find(bod.begin(), bod.end(), ab) != bod.end());
1285 BEAST_EXPECT(
1286 std::find(bod.begin(), bod.end(), bc) != bod.end());
1287
1288 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1289 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
1290 BEAST_EXPECT(
1291 std::find(cod.begin(), cod.end(), bc) != cod.end());
1292 }
1293
1294 env.close(5s);
1295 env(escrow::finish(alice, alice, aseq));
1296 {
1297 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1298 BEAST_EXPECT(env.le(keylet::escrow(bruce.id(), bseq)));
1299
1300 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1301 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0);
1302 BEAST_EXPECT(
1303 std::find(aod.begin(), aod.end(), ab) == aod.end());
1304
1305 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1306 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1307 BEAST_EXPECT(
1308 std::find(bod.begin(), bod.end(), ab) == bod.end());
1309 BEAST_EXPECT(
1310 std::find(bod.begin(), bod.end(), bc) != bod.end());
1311
1312 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1313 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
1314 }
1315
1316 env.close(5s);
1317 env(escrow::cancel(bruce, bruce, bseq));
1318 {
1319 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1320 BEAST_EXPECT(!env.le(keylet::escrow(bruce.id(), bseq)));
1321
1322 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1323 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0);
1324 BEAST_EXPECT(
1325 std::find(aod.begin(), aod.end(), ab) == aod.end());
1326
1327 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1328 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 0);
1329 BEAST_EXPECT(
1330 std::find(bod.begin(), bod.end(), ab) == bod.end());
1331 BEAST_EXPECT(
1332 std::find(bod.begin(), bod.end(), bc) == bod.end());
1333
1334 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1335 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 0);
1336 }
1337 }
1338 }
1339
1340 void
1342 {
1343 testcase("Consequences");
1344
1345 using namespace jtx;
1346 using namespace std::chrono;
1347 Env env(*this, features);
1348 auto const baseFee = env.current()->fees().base;
1349
1350 env.memoize("alice");
1351 env.memoize("bob");
1352 env.memoize("carol");
1353
1354 {
1355 auto const jtx = env.jt(
1356 escrow::create("alice", "carol", XRP(1000)),
1357 escrow::finish_time(env.now() + 1s),
1358 seq(1),
1359 fee(baseFee));
1360 auto const pf = preflight(
1361 env.app(),
1362 env.current()->rules(),
1363 *jtx.stx,
1364 tapNONE,
1365 env.journal);
1366 BEAST_EXPECT(pf.ter == tesSUCCESS);
1367 BEAST_EXPECT(!pf.consequences.isBlocker());
1368 BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
1369 BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(1000));
1370 }
1371
1372 {
1373 auto const jtx =
1374 env.jt(escrow::cancel("bob", "alice", 3), seq(1), fee(baseFee));
1375 auto const pf = preflight(
1376 env.app(),
1377 env.current()->rules(),
1378 *jtx.stx,
1379 tapNONE,
1380 env.journal);
1381 BEAST_EXPECT(pf.ter == tesSUCCESS);
1382 BEAST_EXPECT(!pf.consequences.isBlocker());
1383 BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
1384 BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
1385 }
1386
1387 {
1388 auto const jtx =
1389 env.jt(escrow::finish("bob", "alice", 3), seq(1), fee(baseFee));
1390 auto const pf = preflight(
1391 env.app(),
1392 env.current()->rules(),
1393 *jtx.stx,
1394 tapNONE,
1395 env.journal);
1396 BEAST_EXPECT(pf.ter == tesSUCCESS);
1397 BEAST_EXPECT(!pf.consequences.isBlocker());
1398 BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
1399 BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
1400 }
1401 }
1402
1403 void
1405 {
1406 testcase("Escrow with tickets");
1407
1408 using namespace jtx;
1409 using namespace std::chrono;
1410 Account const alice{"alice"};
1411 Account const bob{"bob"};
1412
1413 {
1414 // Create escrow and finish using tickets.
1415 Env env(*this, features);
1416 auto const baseFee = env.current()->fees().base;
1417 env.fund(XRP(5000), alice, bob);
1418 env.close();
1419
1420 // alice creates a ticket.
1421 std::uint32_t const aliceTicket{env.seq(alice) + 1};
1422 env(ticket::create(alice, 1));
1423
1424 // bob creates a bunch of tickets because he will be burning
1425 // through them with tec transactions. Just because we can
1426 // we'll use them up starting from largest and going smaller.
1427 constexpr static std::uint32_t bobTicketCount{20};
1428 env(ticket::create(bob, bobTicketCount));
1429 env.close();
1430 std::uint32_t bobTicket{env.seq(bob)};
1431 env.require(tickets(alice, 1));
1432 env.require(tickets(bob, bobTicketCount));
1433
1434 // Note that from here on all transactions use tickets. No account
1435 // root sequences should change.
1436 std::uint32_t const aliceRootSeq{env.seq(alice)};
1437 std::uint32_t const bobRootSeq{env.seq(bob)};
1438
1439 // alice creates an escrow that can be finished in the future
1440 auto const ts = env.now() + 97s;
1441
1442 std::uint32_t const escrowSeq = aliceTicket;
1443 env(escrow::create(alice, bob, XRP(1000)),
1445 ticket::use(aliceTicket));
1446 BEAST_EXPECT(env.seq(alice) == aliceRootSeq);
1447 env.require(tickets(alice, 0));
1448 env.require(tickets(bob, bobTicketCount));
1449
1450 // Advance the ledger, verifying that the finish won't complete
1451 // prematurely. Note that each tec consumes one of bob's tickets.
1452 for (; env.now() < ts; env.close())
1453 {
1454 env(escrow::finish(bob, alice, escrowSeq),
1455 fee(150 * baseFee),
1456 ticket::use(--bobTicket),
1458 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1459 }
1460
1461 // bob tries to re-use a ticket, which is rejected.
1462 env(escrow::finish(bob, alice, escrowSeq),
1463 fee(150 * baseFee),
1464 ticket::use(bobTicket),
1465 ter(tefNO_TICKET));
1466
1467 // bob uses one of his remaining tickets. Success!
1468 env(escrow::finish(bob, alice, escrowSeq),
1469 fee(150 * baseFee),
1470 ticket::use(--bobTicket));
1471 env.close();
1472 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1473 }
1474 {
1475 // Create escrow and cancel using tickets.
1476 Env env(*this, features);
1477 auto const baseFee = env.current()->fees().base;
1478 env.fund(XRP(5000), alice, bob);
1479 env.close();
1480
1481 // alice creates a ticket.
1482 std::uint32_t const aliceTicket{env.seq(alice) + 1};
1483 env(ticket::create(alice, 1));
1484
1485 // bob creates a bunch of tickets because he will be burning
1486 // through them with tec transactions.
1487 constexpr std::uint32_t bobTicketCount{20};
1488 std::uint32_t bobTicket{env.seq(bob) + 1};
1489 env(ticket::create(bob, bobTicketCount));
1490 env.close();
1491 env.require(tickets(alice, 1));
1492 env.require(tickets(bob, bobTicketCount));
1493
1494 // Note that from here on all transactions use tickets. No account
1495 // root sequences should change.
1496 std::uint32_t const aliceRootSeq{env.seq(alice)};
1497 std::uint32_t const bobRootSeq{env.seq(bob)};
1498
1499 // alice creates an escrow that can be finished in the future.
1500 auto const ts = env.now() + 117s;
1501
1502 std::uint32_t const escrowSeq = aliceTicket;
1503 env(escrow::create(alice, bob, XRP(1000)),
1506 ticket::use(aliceTicket));
1507 BEAST_EXPECT(env.seq(alice) == aliceRootSeq);
1508 env.require(tickets(alice, 0));
1509 env.require(tickets(bob, bobTicketCount));
1510
1511 // Advance the ledger, verifying that the cancel won't complete
1512 // prematurely.
1513 for (; env.now() < ts; env.close())
1514 {
1515 env(escrow::cancel(bob, alice, escrowSeq),
1516 fee(150 * baseFee),
1517 ticket::use(bobTicket++),
1519 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1520 }
1521
1522 // Verify that a finish won't work anymore.
1523 env(escrow::finish(bob, alice, escrowSeq),
1526 fee(150 * baseFee),
1527 ticket::use(bobTicket++),
1529 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1530
1531 // Verify that the cancel succeeds.
1532 env(escrow::cancel(bob, alice, escrowSeq),
1533 fee(150 * baseFee),
1534 ticket::use(bobTicket++));
1535 env.close();
1536 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1537
1538 // Verify that bob actually consumed his tickets.
1539 env.require(tickets(bob, env.seq(bob) - bobTicket));
1540 }
1541 }
1542
1543 void
1545 {
1546 testcase("Test with credentials");
1547
1548 using namespace jtx;
1549 using namespace std::chrono;
1550
1551 Account const alice{"alice"};
1552 Account const bob{"bob"};
1553 Account const carol{"carol"};
1554 Account const dillon{"dillon "};
1555 Account const zelda{"zelda"};
1556
1557 char const credType[] = "abcde";
1558
1559 {
1560 // Credentials amendment not enabled
1561 Env env(*this, features - featureCredentials);
1562 env.fund(XRP(5000), alice, bob);
1563 env.close();
1564
1565 auto const seq = env.seq(alice);
1566 env(escrow::create(alice, bob, XRP(1000)),
1567 escrow::finish_time(env.now() + 1s));
1568 env.close();
1569
1570 env(fset(bob, asfDepositAuth));
1571 env.close();
1572 env(deposit::auth(bob, alice));
1573 env.close();
1574
1575 std::string const credIdx =
1576 "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B"
1577 "E4";
1578 env(escrow::finish(bob, alice, seq),
1579 credentials::ids({credIdx}),
1580 ter(temDISABLED));
1581 }
1582
1583 {
1584 Env env(*this, features);
1585
1586 env.fund(XRP(5000), alice, bob, carol, dillon, zelda);
1587 env.close();
1588
1589 env(credentials::create(carol, zelda, credType));
1590 env.close();
1591 auto const jv =
1592 credentials::ledgerEntry(env, carol, zelda, credType);
1593 std::string const credIdx = jv[jss::result][jss::index].asString();
1594
1595 auto const seq = env.seq(alice);
1596 env(escrow::create(alice, bob, XRP(1000)),
1597 escrow::finish_time(env.now() + 50s));
1598 env.close();
1599
1600 // Bob require preauthorization
1601 env(fset(bob, asfDepositAuth));
1602 env.close();
1603
1604 // Fail, credentials not accepted
1605 env(escrow::finish(carol, alice, seq),
1606 credentials::ids({credIdx}),
1608
1609 env.close();
1610
1611 env(credentials::accept(carol, zelda, credType));
1612 env.close();
1613
1614 // Fail, credentials doesn’t belong to root account
1615 env(escrow::finish(dillon, alice, seq),
1616 credentials::ids({credIdx}),
1618
1619 // Fail, no depositPreauth
1620 env(escrow::finish(carol, alice, seq),
1621 credentials::ids({credIdx}),
1623
1624 env(deposit::authCredentials(bob, {{zelda, credType}}));
1625 env.close();
1626
1627 // Success
1628 env.close();
1629 env(escrow::finish(carol, alice, seq), credentials::ids({credIdx}));
1630 env.close();
1631 }
1632
1633 {
1634 testcase("Escrow with credentials without depositPreauth");
1635 using namespace std::chrono;
1636
1637 Env env(*this, features);
1638
1639 env.fund(XRP(5000), alice, bob, carol, dillon, zelda);
1640 env.close();
1641
1642 env(credentials::create(carol, zelda, credType));
1643 env.close();
1644 env(credentials::accept(carol, zelda, credType));
1645 env.close();
1646 auto const jv =
1647 credentials::ledgerEntry(env, carol, zelda, credType);
1648 std::string const credIdx = jv[jss::result][jss::index].asString();
1649
1650 auto const seq = env.seq(alice);
1651 env(escrow::create(alice, bob, XRP(1000)),
1652 escrow::finish_time(env.now() + 50s));
1653 // time advance
1654 env.close();
1655 env.close();
1656 env.close();
1657 env.close();
1658 env.close();
1659 env.close();
1660
1661 // Succeed, Bob doesn't require preauthorization
1662 env(escrow::finish(carol, alice, seq), credentials::ids({credIdx}));
1663 env.close();
1664
1665 {
1666 char const credType2[] = "fghijk";
1667
1668 env(credentials::create(bob, zelda, credType2));
1669 env.close();
1670 env(credentials::accept(bob, zelda, credType2));
1671 env.close();
1672 auto const credIdxBob =
1674 env, bob, zelda, credType2)[jss::result][jss::index]
1675 .asString();
1676
1677 auto const seq = env.seq(alice);
1678 env(escrow::create(alice, bob, XRP(1000)),
1679 escrow::finish_time(env.now() + 1s));
1680 env.close();
1681
1682 // Bob require preauthorization
1683 env(fset(bob, asfDepositAuth));
1684 env.close();
1685 env(deposit::authCredentials(bob, {{zelda, credType}}));
1686 env.close();
1687
1688 // Use any valid credentials if account == dst
1689 env(escrow::finish(bob, alice, seq),
1690 credentials::ids({credIdxBob}));
1691 env.close();
1692 }
1693 }
1694 }
1695
1696 void
1698 {
1699 testEnablement(features);
1700 testTiming(features);
1701 testTags(features);
1702 testDisallowXRP(features);
1703 test1571(features);
1704 testFails(features);
1705 testLockup(features);
1706 testEscrowConditions(features);
1707 testMetaAndOwnership(features);
1708 testConsequences(features);
1709 testEscrowWithTickets(features);
1710 testCredentials(features);
1711 }
1712
1713public:
1714 void
1715 run() override
1716 {
1717 using namespace test::jtx;
1720 testWithFeats(all - featureTokenEscrow);
1721 }
1722};
1723
1724BEAST_DEFINE_TESTSUITE(Escrow, app, ripple);
1725
1726} // namespace test
1727} // namespace ripple
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:482
A testsuite class.
Definition: suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:155
A class that simplifies iterating ledger directory pages.
Definition: Dir.h:42
const_iterator end() const
Definition: Dir.cpp:52
const_iterator begin() const
Definition: Dir.cpp:34
An immutable linear range of bytes.
Definition: Slice.h:46
Immutable cryptographic account descriptor.
Definition: Account.h:39
A transaction testing environment.
Definition: Env.h:121
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:254
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:544
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:331
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:117
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition: Env.h:505
NetClock::time_point now()
Returns the current network time.
Definition: Env.h:284
Application & app()
Definition: Env.h:261
beast::Journal const journal
Definition: Env.h:162
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:275
std::shared_ptr< STObject const > meta()
Return metadata for the last JTx.
Definition: Env.cpp:489
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition: Env.cpp:179
void memoize(Account const &account)
Associate AccountID with account.
Definition: Env.cpp:152
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:263
A balance matches.
Definition: balance.h:39
Set the fee on a JTx.
Definition: fee.h:37
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 data(T... args)
T distance(T... args)
T find(T... args)
T memcpy(T... args)
Keylet escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
Definition: Indexes.cpp:389
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:374
Json::Value create(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Definition: creds.cpp:32
Json::Value accept(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Definition: creds.cpp:48
Json::Value ledgerEntry(jtx::Env &env, jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Definition: creds.cpp:78
Json::Value auth(Account const &account, Account const &auth)
Preauthorize for deposit.
Definition: deposit.cpp:32
Json::Value authCredentials(jtx::Account const &account, std::vector< AuthorizeCredentials > const &auth)
Definition: deposit.cpp:54
std::array< std::uint8_t, 7 > const fb2
Definition: escrow.h:77
std::array< std::uint8_t, 8 > const fb3
Definition: escrow.h:87
std::array< std::uint8_t, 39 > const cb1
Definition: escrow.h:70
std::array< std::uint8_t, 39 > const cb3
Definition: escrow.h:90
Json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount)
Definition: escrow.cpp:33
Json::Value cancel(AccountID const &account, Account const &from, std::uint32_t seq)
Definition: escrow.cpp:57
std::array< std::uint8_t, 39 > const cb2
Definition: escrow.h:80
std::array< std::uint8_t, 4 > const fb1
Definition: escrow.h:68
Json::Value finish(AccountID const &account, AccountID const &from, std::uint32_t seq)
Definition: escrow.cpp:45
Json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
Definition: ticket.cpp:31
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:29
owner_count< ltTICKET > tickets
Match the number of tickets on the account.
Definition: ticket.h:64
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
FeatureBitset supported_amendments()
Definition: Env.h:74
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:25
constexpr std::uint32_t asfDepositAuth
Definition: TxFlags.h:85
PreflightResult preflight(Application &app, Rules const &rules, STTx const &tx, ApplyFlags flags, beast::Journal j)
Gate a transaction based on static information.
Definition: applySteps.cpp:325
constexpr std::uint32_t asfRequireDest
Definition: TxFlags.h:77
constexpr std::uint32_t tfPassive
Definition: TxFlags.h:98
@ tefNO_TICKET
Definition: TER.h:185
@ tecCRYPTOCONDITION_ERROR
Definition: TER.h:312
@ tecNO_DST
Definition: TER.h:290
@ tecUNFUNDED
Definition: TER.h:295
@ tecNO_TARGET
Definition: TER.h:304
@ tecBAD_CREDENTIALS
Definition: TER.h:359
@ tecNO_PERMISSION
Definition: TER.h:305
@ tecDST_TAG_NEEDED
Definition: TER.h:309
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:307
@ tesSUCCESS
Definition: TER.h:244
@ tapNONE
Definition: ApplyView.h:32
constexpr std::uint32_t asfDisallowXRP
Definition: TxFlags.h:79
@ temBAD_AMOUNT
Definition: TER.h:89
@ temMALFORMED
Definition: TER.h:87
@ temBAD_EXPIRATION
Definition: TER.h:91
@ temINVALID_FLAG
Definition: TER.h:111
@ temDISABLED
Definition: TER.h:114
T resize(T... args)
T size(T... args)
void run() override
Runs the suite.
void testLockup(FeatureBitset features)
void testCredentials(FeatureBitset features)
void testFails(FeatureBitset features)
void testEscrowConditions(FeatureBitset features)
void testTags(FeatureBitset features)
void testMetaAndOwnership(FeatureBitset features)
void testConsequences(FeatureBitset features)
void testEnablement(FeatureBitset features)
Definition: Escrow_test.cpp:39
void testWithFeats(FeatureBitset features)
void test1571(FeatureBitset features)
void testEscrowWithTickets(FeatureBitset features)
void testDisallowXRP(FeatureBitset features)
void testTiming(FeatureBitset features)
Definition: Escrow_test.cpp:77
Set the destination tag on a JTx.
Definition: tag.h:32
Set the "CancelAfter" time tag on a JTx.
Definition: escrow.h:116
Set the "FinishAfter" time tag on a JTx.
Definition: escrow.h:98
Set the sequence number on a JTx.
Definition: seq.h:34
Set the source tag on a JTx.
Definition: tag.h:47