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 if (features[fixIncludeKeyletFields])
257 {
258 BEAST_EXPECT((*sle)[sfSequence] == seq);
259 }
260 else
261 {
262 BEAST_EXPECT(!sle->isFieldPresent(sfSequence));
263 }
264 }
265
266 void
268 {
269 testcase("Disallow XRP");
270
271 using namespace jtx;
272 using namespace std::chrono;
273
274 {
275 // Respect the "asfDisallowXRP" account flag:
276 Env env(*this, features - featureDepositAuth);
277
278 env.fund(XRP(5000), "bob", "george");
279 env(fset("george", asfDisallowXRP));
280 env(escrow::create("bob", "george", XRP(10)),
281 escrow::finish_time(env.now() + 1s),
283 }
284 {
285 // Ignore the "asfDisallowXRP" account flag, which we should
286 // have been doing before.
287 Env env(*this, features);
288
289 env.fund(XRP(5000), "bob", "george");
290 env(fset("george", asfDisallowXRP));
291 env(escrow::create("bob", "george", XRP(10)),
292 escrow::finish_time(env.now() + 1s));
293 }
294 }
295
296 void
298 {
299 using namespace jtx;
300 using namespace std::chrono;
301
302 {
303 testcase("Implied Finish Time (without fix1571)");
304
305 Env env(*this, testable_amendments() - fix1571);
306 auto const baseFee = env.current()->fees().base;
307 env.fund(XRP(5000), "alice", "bob", "carol");
308 env.close();
309
310 // Creating an escrow without a finish time and finishing it
311 // is allowed without fix1571:
312 auto const seq1 = env.seq("alice");
313 env(escrow::create("alice", "bob", XRP(100)),
314 escrow::cancel_time(env.now() + 1s),
315 fee(baseFee * 150));
316 env.close();
317 env(escrow::finish("carol", "alice", seq1), fee(baseFee * 150));
318 BEAST_EXPECT(env.balance("bob") == XRP(5100));
319
320 env.close();
321
322 // Creating an escrow without a finish time and a condition is
323 // also allowed without fix1571:
324 auto const seq2 = env.seq("alice");
325 env(escrow::create("alice", "bob", XRP(100)),
326 escrow::cancel_time(env.now() + 1s),
328 fee(baseFee * 150));
329 env.close();
330 env(escrow::finish("carol", "alice", seq2),
333 fee(baseFee * 150));
334 BEAST_EXPECT(env.balance("bob") == XRP(5200));
335 }
336
337 {
338 testcase("Implied Finish Time (with fix1571)");
339
340 Env env(*this, features);
341 auto const baseFee = env.current()->fees().base;
342 env.fund(XRP(5000), "alice", "bob", "carol");
343 env.close();
344
345 // Creating an escrow with only a cancel time is not allowed:
346 env(escrow::create("alice", "bob", XRP(100)),
347 escrow::cancel_time(env.now() + 90s),
348 fee(baseFee * 150),
350
351 // Creating an escrow with only a cancel time and a condition is
352 // allowed:
353 auto const seq = env.seq("alice");
354 env(escrow::create("alice", "bob", XRP(100)),
355 escrow::cancel_time(env.now() + 90s),
357 fee(baseFee * 150));
358 env.close();
359 env(escrow::finish("carol", "alice", seq),
362 fee(baseFee * 150));
363 BEAST_EXPECT(env.balance("bob") == XRP(5100));
364 }
365 }
366
367 void
369 {
370 testcase("Failure Cases");
371
372 using namespace jtx;
373 using namespace std::chrono;
374
375 Env env(*this, features);
376 auto const baseFee = env.current()->fees().base;
377 env.fund(XRP(5000), "alice", "bob", "gw");
378 env.close();
379
380 // temINVALID_FLAG
381 env(escrow::create("alice", "bob", XRP(1000)),
382 escrow::finish_time(env.now() + 5s),
385
386 // Finish time is in the past
387 env(escrow::create("alice", "bob", XRP(1000)),
388 escrow::finish_time(env.now() - 5s),
390
391 // Cancel time is in the past
392 env(escrow::create("alice", "bob", XRP(1000)),
394 escrow::cancel_time(env.now() - 5s),
396
397 // no destination account
398 env(escrow::create("alice", "carol", XRP(1000)),
399 escrow::finish_time(env.now() + 1s),
400 ter(tecNO_DST));
401
402 env.fund(XRP(5000), "carol");
403
404 // Using non-XRP:
405 bool const withTokenEscrow =
406 env.current()->rules().enabled(featureTokenEscrow);
407 {
408 // tecNO_PERMISSION: token escrow is enabled but the issuer did not
409 // set the asfAllowTrustLineLocking flag
410 auto const txResult =
411 withTokenEscrow ? ter(tecNO_PERMISSION) : ter(temBAD_AMOUNT);
412 env(escrow::create("alice", "carol", Account("alice")["USD"](500)),
413 escrow::finish_time(env.now() + 5s),
414 txResult);
415 }
416
417 // Sending zero or no XRP:
418 env(escrow::create("alice", "carol", XRP(0)),
419 escrow::finish_time(env.now() + 1s),
421 env(escrow::create("alice", "carol", XRP(-1000)),
422 escrow::finish_time(env.now() + 1s),
424
425 // Fail if neither CancelAfter nor FinishAfter are specified:
426 env(escrow::create("alice", "carol", XRP(1)), ter(temBAD_EXPIRATION));
427
428 // Fail if neither a FinishTime nor a condition are attached:
429 env(escrow::create("alice", "carol", XRP(1)),
430 escrow::cancel_time(env.now() + 1s),
432
433 // Fail if FinishAfter has already passed:
434 env(escrow::create("alice", "carol", XRP(1)),
435 escrow::finish_time(env.now() - 1s),
437
438 // If both CancelAfter and FinishAfter are set, then CancelAfter must
439 // be strictly later than FinishAfter.
440 env(escrow::create("alice", "carol", XRP(1)),
442 escrow::finish_time(env.now() + 10s),
443 escrow::cancel_time(env.now() + 10s),
445
446 env(escrow::create("alice", "carol", XRP(1)),
448 escrow::finish_time(env.now() + 10s),
449 escrow::cancel_time(env.now() + 5s),
451
452 // Carol now requires the use of a destination tag
453 env(fset("carol", asfRequireDest));
454
455 // missing destination tag
456 env(escrow::create("alice", "carol", XRP(1)),
458 escrow::cancel_time(env.now() + 1s),
460
461 // Success!
462 env(escrow::create("alice", "carol", XRP(1)),
464 escrow::cancel_time(env.now() + 1s),
465 dtag(1));
466
467 { // Fail if the sender wants to send more than he has:
468 auto const accountReserve = drops(env.current()->fees().reserve);
469 auto const accountIncrement =
470 drops(env.current()->fees().increment);
471
472 env.fund(accountReserve + accountIncrement + XRP(50), "daniel");
473 env(escrow::create("daniel", "bob", XRP(51)),
474 escrow::finish_time(env.now() + 1s),
476
477 env.fund(accountReserve + accountIncrement + XRP(50), "evan");
478 env(escrow::create("evan", "bob", XRP(50)),
479 escrow::finish_time(env.now() + 1s),
481
482 env.fund(accountReserve, "frank");
483 env(escrow::create("frank", "bob", XRP(1)),
484 escrow::finish_time(env.now() + 1s),
486 }
487
488 { // Specify incorrect sequence number
489 env.fund(XRP(5000), "hannah");
490 auto const seq = env.seq("hannah");
491 env(escrow::create("hannah", "hannah", XRP(10)),
492 escrow::finish_time(env.now() + 1s),
493 fee(150 * baseFee));
494 env.close();
495 env(escrow::finish("hannah", "hannah", seq + 7),
496 fee(150 * baseFee),
498 }
499
500 { // Try to specify a condition for a non-conditional payment
501 env.fund(XRP(5000), "ivan");
502 auto const seq = env.seq("ivan");
503
504 env(escrow::create("ivan", "ivan", XRP(10)),
505 escrow::finish_time(env.now() + 1s));
506 env.close();
507 env(escrow::finish("ivan", "ivan", seq),
510 fee(150 * baseFee),
512 }
513 }
514
515 void
517 {
518 testcase("Lockup");
519
520 using namespace jtx;
521 using namespace std::chrono;
522
523 {
524 // Unconditional
525 Env env(*this, features);
526 auto const baseFee = env.current()->fees().base;
527 env.fund(XRP(5000), "alice", "bob");
528 auto const seq = env.seq("alice");
529 env(escrow::create("alice", "alice", XRP(1000)),
530 escrow::finish_time(env.now() + 5s));
531 env.require(balance("alice", XRP(4000) - drops(baseFee)));
532
533 // Not enough time has elapsed for a finish and canceling isn't
534 // possible.
535 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
536 env(escrow::finish("bob", "alice", seq), ter(tecNO_PERMISSION));
537 env.close();
538
539 // Cancel continues to not be possible
540 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
541
542 // Finish should succeed. Verify funds.
543 env(escrow::finish("bob", "alice", seq));
544 env.require(balance("alice", XRP(5000) - drops(baseFee)));
545 }
546 {
547 // Unconditionally pay from Alice to Bob. Zelda (neither source nor
548 // destination) signs all cancels and finishes. This shows that
549 // Escrow will make a payment to Bob with no intervention from Bob.
550 Env env(*this, features);
551 auto const baseFee = env.current()->fees().base;
552 env.fund(XRP(5000), "alice", "bob", "zelda");
553 auto const seq = env.seq("alice");
554 env(escrow::create("alice", "bob", XRP(1000)),
555 escrow::finish_time(env.now() + 5s));
556 env.require(balance("alice", XRP(4000) - drops(baseFee)));
557
558 // Not enough time has elapsed for a finish and canceling isn't
559 // possible.
560 env(escrow::cancel("zelda", "alice", seq), ter(tecNO_PERMISSION));
561 env(escrow::finish("zelda", "alice", seq), ter(tecNO_PERMISSION));
562 env.close();
563
564 // Cancel continues to not be possible
565 env(escrow::cancel("zelda", "alice", seq), ter(tecNO_PERMISSION));
566
567 // Finish should succeed. Verify funds.
568 env(escrow::finish("zelda", "alice", seq));
569 env.close();
570
571 env.require(balance("alice", XRP(4000) - drops(baseFee)));
572 env.require(balance("bob", XRP(6000)));
573 env.require(balance("zelda", XRP(5000) - drops(4 * baseFee)));
574 }
575 {
576 // Bob sets DepositAuth so only Bob can finish the escrow.
577 Env env(*this, features);
578 auto const baseFee = env.current()->fees().base;
579
580 env.fund(XRP(5000), "alice", "bob", "zelda");
581 env(fset("bob", asfDepositAuth));
582 env.close();
583
584 auto const seq = env.seq("alice");
585 env(escrow::create("alice", "bob", XRP(1000)),
586 escrow::finish_time(env.now() + 5s));
587 env.require(balance("alice", XRP(4000) - drops(baseFee)));
588
589 // Not enough time has elapsed for a finish and canceling isn't
590 // possible.
591 env(escrow::cancel("zelda", "alice", seq), ter(tecNO_PERMISSION));
592 env(escrow::cancel("alice", "alice", seq), ter(tecNO_PERMISSION));
593 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
594 env(escrow::finish("zelda", "alice", seq), ter(tecNO_PERMISSION));
595 env(escrow::finish("alice", "alice", seq), ter(tecNO_PERMISSION));
596 env(escrow::finish("bob", "alice", seq), ter(tecNO_PERMISSION));
597 env.close();
598
599 // Cancel continues to not be possible. Finish will only succeed for
600 // Bob, because of DepositAuth.
601 env(escrow::cancel("zelda", "alice", seq), ter(tecNO_PERMISSION));
602 env(escrow::cancel("alice", "alice", seq), ter(tecNO_PERMISSION));
603 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
604 env(escrow::finish("zelda", "alice", seq), ter(tecNO_PERMISSION));
605 env(escrow::finish("alice", "alice", seq), ter(tecNO_PERMISSION));
606 env(escrow::finish("bob", "alice", seq));
607 env.close();
608
609 env.require(balance("alice", XRP(4000) - (baseFee * 5)));
610 env.require(balance("bob", XRP(6000) - (baseFee * 5)));
611 env.require(balance("zelda", XRP(5000) - (baseFee * 4)));
612 }
613 {
614 // Bob sets DepositAuth but preauthorizes Zelda, so Zelda can
615 // finish the escrow.
616 Env env(*this, features);
617 auto const baseFee = env.current()->fees().base;
618
619 env.fund(XRP(5000), "alice", "bob", "zelda");
620 env(fset("bob", asfDepositAuth));
621 env.close();
622 env(deposit::auth("bob", "zelda"));
623 env.close();
624
625 auto const seq = env.seq("alice");
626 env(escrow::create("alice", "bob", XRP(1000)),
627 escrow::finish_time(env.now() + 5s));
628 env.require(balance("alice", XRP(4000) - drops(baseFee)));
629 env.close();
630
631 // DepositPreauth allows Finish to succeed for either Zelda or
632 // Bob. But Finish won't succeed for Alice since she is not
633 // preauthorized.
634 env(escrow::finish("alice", "alice", seq), ter(tecNO_PERMISSION));
635 env(escrow::finish("zelda", "alice", seq));
636 env.close();
637
638 env.require(balance("alice", XRP(4000) - (baseFee * 2)));
639 env.require(balance("bob", XRP(6000) - (baseFee * 2)));
640 env.require(balance("zelda", XRP(5000) - (baseFee * 1)));
641 }
642 {
643 // Conditional
644 Env env(*this, features);
645 auto const baseFee = env.current()->fees().base;
646 env.fund(XRP(5000), "alice", "bob");
647 auto const seq = env.seq("alice");
648 env(escrow::create("alice", "alice", XRP(1000)),
650 escrow::finish_time(env.now() + 5s));
651 env.require(balance("alice", XRP(4000) - drops(baseFee)));
652
653 // Not enough time has elapsed for a finish and canceling isn't
654 // possible.
655 env(escrow::cancel("alice", "alice", seq), ter(tecNO_PERMISSION));
656 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
657 env(escrow::finish("alice", "alice", seq), ter(tecNO_PERMISSION));
658 env(escrow::finish("alice", "alice", seq),
661 fee(150 * baseFee),
663 env(escrow::finish("bob", "alice", seq), ter(tecNO_PERMISSION));
664 env(escrow::finish("bob", "alice", seq),
667 fee(150 * baseFee),
669 env.close();
670
671 // Cancel continues to not be possible. Finish is possible but
672 // requires the fulfillment associated with the escrow.
673 env(escrow::cancel("alice", "alice", seq), ter(tecNO_PERMISSION));
674 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
675 env(escrow::finish("bob", "alice", seq),
677 env(escrow::finish("alice", "alice", seq),
679 env.close();
680
681 env(escrow::finish("bob", "alice", seq),
684 fee(150 * baseFee));
685 }
686 {
687 // Self-escrowed conditional with DepositAuth.
688 Env env(*this, features);
689 auto const baseFee = env.current()->fees().base;
690
691 env.fund(XRP(5000), "alice", "bob");
692 auto const seq = env.seq("alice");
693 env(escrow::create("alice", "alice", XRP(1000)),
695 escrow::finish_time(env.now() + 5s));
696 env.require(balance("alice", XRP(4000) - drops(baseFee)));
697 env.close();
698
699 // Finish is now possible but requires the cryptocondition.
700 env(escrow::finish("bob", "alice", seq),
702 env(escrow::finish("alice", "alice", seq),
704
705 // Enable deposit authorization. After this only Alice can finish
706 // the escrow.
707 env(fset("alice", asfDepositAuth));
708 env.close();
709
710 env(escrow::finish("alice", "alice", seq),
713 fee(150 * baseFee),
715 env(escrow::finish("bob", "alice", seq),
718 fee(150 * baseFee),
720 env(escrow::finish("alice", "alice", seq),
723 fee(150 * baseFee));
724 }
725 {
726 // Self-escrowed conditional with DepositAuth and DepositPreauth.
727 Env env(*this, features);
728 auto const baseFee = env.current()->fees().base;
729
730 env.fund(XRP(5000), "alice", "bob", "zelda");
731 auto const seq = env.seq("alice");
732 env(escrow::create("alice", "alice", XRP(1000)),
734 escrow::finish_time(env.now() + 5s));
735 env.require(balance("alice", XRP(4000) - drops(baseFee)));
736 env.close();
737
738 // Alice preauthorizes Zelda for deposit, even though Alice has not
739 // set the lsfDepositAuth flag (yet).
740 env(deposit::auth("alice", "zelda"));
741 env.close();
742
743 // Finish is now possible but requires the cryptocondition.
744 env(escrow::finish("alice", "alice", seq),
746 env(escrow::finish("bob", "alice", seq),
748 env(escrow::finish("zelda", "alice", seq),
750
751 // Alice enables deposit authorization. After this only Alice or
752 // Zelda (because Zelda is preauthorized) can finish the escrow.
753 env(fset("alice", asfDepositAuth));
754 env.close();
755
756 env(escrow::finish("alice", "alice", seq),
759 fee(150 * baseFee),
761 env(escrow::finish("bob", "alice", seq),
764 fee(150 * baseFee),
766 env(escrow::finish("zelda", "alice", seq),
769 fee(150 * baseFee));
770 }
771 }
772
773 void
775 {
776 testcase("Escrow with CryptoConditions");
777
778 using namespace jtx;
779 using namespace std::chrono;
780
781 { // Test cryptoconditions
782 Env env(*this, features);
783 auto const baseFee = env.current()->fees().base;
784 env.fund(XRP(5000), "alice", "bob", "carol");
785 auto const seq = env.seq("alice");
786 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
787 env(escrow::create("alice", "carol", XRP(1000)),
789 escrow::cancel_time(env.now() + 1s));
790 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
791 env.require(balance("alice", XRP(4000) - drops(baseFee)));
792 env.require(balance("carol", XRP(5000)));
793 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
794 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
795
796 // Attempt to finish without a fulfillment
797 env(escrow::finish("bob", "alice", seq),
799 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
800
801 // Attempt to finish with a condition instead of a fulfillment
802 env(escrow::finish("bob", "alice", seq),
805 fee(150 * baseFee),
807 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
808 env(escrow::finish("bob", "alice", seq),
811 fee(150 * baseFee),
813 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
814 env(escrow::finish("bob", "alice", seq),
817 fee(150 * baseFee),
819 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
820
821 // Attempt to finish with an incorrect condition and various
822 // combinations of correct and incorrect fulfillments.
823 env(escrow::finish("bob", "alice", seq),
826 fee(150 * baseFee),
828 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
829 env(escrow::finish("bob", "alice", seq),
832 fee(150 * baseFee),
834 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
835 env(escrow::finish("bob", "alice", seq),
838 fee(150 * baseFee),
840 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
841
842 // Attempt to finish with the correct condition & fulfillment
843 env(escrow::finish("bob", "alice", seq),
846 fee(150 * baseFee));
847
848 // SLE removed on finish
849 BEAST_EXPECT(!env.le(keylet::escrow(Account("alice").id(), seq)));
850 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
851 env.require(balance("carol", XRP(6000)));
852 env(escrow::cancel("bob", "alice", seq), ter(tecNO_TARGET));
853 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
854 env(escrow::cancel("bob", "carol", 1), ter(tecNO_TARGET));
855 }
856 { // Test cancel when condition is present
857 Env env(*this, features);
858 auto const baseFee = env.current()->fees().base;
859 env.fund(XRP(5000), "alice", "bob", "carol");
860 auto const seq = env.seq("alice");
861 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
862 env(escrow::create("alice", "carol", XRP(1000)),
864 escrow::cancel_time(env.now() + 1s));
865 env.close();
866 env.require(balance("alice", XRP(4000) - drops(baseFee)));
867 // balance restored on cancel
868 env(escrow::cancel("bob", "alice", seq));
869 env.require(balance("alice", XRP(5000) - drops(baseFee)));
870 // SLE removed on cancel
871 BEAST_EXPECT(!env.le(keylet::escrow(Account("alice").id(), seq)));
872 }
873 {
874 Env env(*this, features);
875 auto const baseFee = env.current()->fees().base;
876 env.fund(XRP(5000), "alice", "bob", "carol");
877 env.close();
878 auto const seq = env.seq("alice");
879 env(escrow::create("alice", "carol", XRP(1000)),
881 escrow::cancel_time(env.now() + 1s));
882 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
883 // cancel fails before expiration
884 env(escrow::cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
885 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
886 env.close();
887 // finish fails after expiration
888 env(escrow::finish("bob", "alice", seq),
891 fee(150 * baseFee),
893 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
894 env.require(balance("carol", XRP(5000)));
895 }
896 { // Test long & short conditions during creation
897 Env env(*this, features);
898 env.fund(XRP(5000), "alice", "bob", "carol");
899
901 v.resize(escrow::cb1.size() + 2, 0x78);
902 std::memcpy(v.data() + 1, escrow::cb1.data(), escrow::cb1.size());
903
904 auto const p = v.data();
905 auto const s = v.size();
906
907 auto const ts = env.now() + 1s;
908
909 // All these are expected to fail, because the
910 // condition we pass in is malformed in some way
911 env(escrow::create("alice", "carol", XRP(1000)),
915 env(escrow::create("alice", "carol", XRP(1000)),
916 escrow::condition(Slice{p, s - 1}),
919 env(escrow::create("alice", "carol", XRP(1000)),
920 escrow::condition(Slice{p, s - 2}),
923 env(escrow::create("alice", "carol", XRP(1000)),
924 escrow::condition(Slice{p + 1, s - 1}),
927 env(escrow::create("alice", "carol", XRP(1000)),
928 escrow::condition(Slice{p + 1, s - 3}),
931 env(escrow::create("alice", "carol", XRP(1000)),
932 escrow::condition(Slice{p + 2, s - 2}),
935 env(escrow::create("alice", "carol", XRP(1000)),
936 escrow::condition(Slice{p + 2, s - 3}),
939
940 auto const seq = env.seq("alice");
941 auto const baseFee = env.current()->fees().base;
942 env(escrow::create("alice", "carol", XRP(1000)),
943 escrow::condition(Slice{p + 1, s - 2}),
945 fee(10 * baseFee));
946 env(escrow::finish("bob", "alice", seq),
949 fee(150 * baseFee));
950 env.require(balance("alice", XRP(4000) - drops(10 * baseFee)));
951 env.require(balance("bob", XRP(5000) - drops(150 * baseFee)));
952 env.require(balance("carol", XRP(6000)));
953 }
954 { // Test long and short conditions & fulfillments during finish
955 Env env(*this, features);
956 env.fund(XRP(5000), "alice", "bob", "carol");
957
959 cv.resize(escrow::cb2.size() + 2, 0x78);
960 std::memcpy(cv.data() + 1, escrow::cb2.data(), escrow::cb2.size());
961
962 auto const cp = cv.data();
963 auto const cs = cv.size();
964
966 fv.resize(escrow::fb2.size() + 2, 0x13);
967 std::memcpy(fv.data() + 1, escrow::fb2.data(), escrow::fb2.size());
968
969 auto const fp = fv.data();
970 auto const fs = fv.size();
971
972 auto const ts = env.now() + 1s;
973
974 // All these are expected to fail, because the
975 // condition we pass in is malformed in some way
976 env(escrow::create("alice", "carol", XRP(1000)),
977 escrow::condition(Slice{cp, cs}),
980 env(escrow::create("alice", "carol", XRP(1000)),
981 escrow::condition(Slice{cp, cs - 1}),
984 env(escrow::create("alice", "carol", XRP(1000)),
985 escrow::condition(Slice{cp, cs - 2}),
988 env(escrow::create("alice", "carol", XRP(1000)),
989 escrow::condition(Slice{cp + 1, cs - 1}),
992 env(escrow::create("alice", "carol", XRP(1000)),
993 escrow::condition(Slice{cp + 1, cs - 3}),
996 env(escrow::create("alice", "carol", XRP(1000)),
997 escrow::condition(Slice{cp + 2, cs - 2}),
1000 env(escrow::create("alice", "carol", XRP(1000)),
1001 escrow::condition(Slice{cp + 2, cs - 3}),
1003 ter(temMALFORMED));
1004
1005 auto const seq = env.seq("alice");
1006 auto const baseFee = env.current()->fees().base;
1007 env(escrow::create("alice", "carol", XRP(1000)),
1008 escrow::condition(Slice{cp + 1, cs - 2}),
1010 fee(10 * baseFee));
1011
1012 // Now, try to fulfill using the same sequence of
1013 // malformed conditions.
1014 env(escrow::finish("bob", "alice", seq),
1015 escrow::condition(Slice{cp, cs}),
1016 escrow::fulfillment(Slice{fp, fs}),
1017 fee(150 * baseFee),
1019 env(escrow::finish("bob", "alice", seq),
1020 escrow::condition(Slice{cp, cs - 1}),
1021 escrow::fulfillment(Slice{fp, fs}),
1022 fee(150 * baseFee),
1024 env(escrow::finish("bob", "alice", seq),
1025 escrow::condition(Slice{cp, cs - 2}),
1026 escrow::fulfillment(Slice{fp, fs}),
1027 fee(150 * baseFee),
1029 env(escrow::finish("bob", "alice", seq),
1030 escrow::condition(Slice{cp + 1, cs - 1}),
1031 escrow::fulfillment(Slice{fp, fs}),
1032 fee(150 * baseFee),
1034 env(escrow::finish("bob", "alice", seq),
1035 escrow::condition(Slice{cp + 1, cs - 3}),
1036 escrow::fulfillment(Slice{fp, fs}),
1037 fee(150 * baseFee),
1039 env(escrow::finish("bob", "alice", seq),
1040 escrow::condition(Slice{cp + 2, cs - 2}),
1041 escrow::fulfillment(Slice{fp, fs}),
1042 fee(150 * baseFee),
1044 env(escrow::finish("bob", "alice", seq),
1045 escrow::condition(Slice{cp + 2, cs - 3}),
1046 escrow::fulfillment(Slice{fp, fs}),
1047 fee(150 * baseFee),
1049
1050 // Now, using the correct condition, try malformed fulfillments:
1051 env(escrow::finish("bob", "alice", seq),
1052 escrow::condition(Slice{cp + 1, cs - 2}),
1053 escrow::fulfillment(Slice{fp, fs}),
1054 fee(150 * baseFee),
1056 env(escrow::finish("bob", "alice", seq),
1057 escrow::condition(Slice{cp + 1, cs - 2}),
1058 escrow::fulfillment(Slice{fp, fs - 1}),
1059 fee(150 * baseFee),
1061 env(escrow::finish("bob", "alice", seq),
1062 escrow::condition(Slice{cp + 1, cs - 2}),
1063 escrow::fulfillment(Slice{fp, fs - 2}),
1064 fee(150 * baseFee),
1066 env(escrow::finish("bob", "alice", seq),
1067 escrow::condition(Slice{cp + 1, cs - 2}),
1068 escrow::fulfillment(Slice{fp + 1, fs - 1}),
1069 fee(150 * baseFee),
1071 env(escrow::finish("bob", "alice", seq),
1072 escrow::condition(Slice{cp + 1, cs - 2}),
1073 escrow::fulfillment(Slice{fp + 1, fs - 3}),
1074 fee(150 * baseFee),
1076 env(escrow::finish("bob", "alice", seq),
1077 escrow::condition(Slice{cp + 1, cs - 2}),
1078 escrow::fulfillment(Slice{fp + 1, fs - 3}),
1079 fee(150 * baseFee),
1081 env(escrow::finish("bob", "alice", seq),
1082 escrow::condition(Slice{cp + 1, cs - 2}),
1083 escrow::fulfillment(Slice{fp + 2, fs - 2}),
1084 fee(150 * baseFee),
1086 env(escrow::finish("bob", "alice", seq),
1087 escrow::condition(Slice{cp + 1, cs - 2}),
1088 escrow::fulfillment(Slice{fp + 2, fs - 3}),
1089 fee(150 * baseFee),
1091
1092 // Now try for the right one
1093 env(escrow::finish("bob", "alice", seq),
1096 fee(150 * baseFee));
1097 env.require(balance("alice", XRP(4000) - drops(10 * baseFee)));
1098 env.require(balance("carol", XRP(6000)));
1099 }
1100 { // Test empty condition during creation and
1101 // empty condition & fulfillment during finish
1102 Env env(*this, features);
1103 env.fund(XRP(5000), "alice", "bob", "carol");
1104
1105 env(escrow::create("alice", "carol", XRP(1000)),
1107 escrow::cancel_time(env.now() + 1s),
1108 ter(temMALFORMED));
1109
1110 auto const seq = env.seq("alice");
1111 auto const baseFee = env.current()->fees().base;
1112 env(escrow::create("alice", "carol", XRP(1000)),
1114 escrow::cancel_time(env.now() + 1s));
1115
1116 env(escrow::finish("bob", "alice", seq),
1119 fee(150 * baseFee),
1121 env(escrow::finish("bob", "alice", seq),
1124 fee(150 * baseFee),
1126 env(escrow::finish("bob", "alice", seq),
1129 fee(150 * baseFee),
1131
1132 // Assemble finish that is missing the Condition or the Fulfillment
1133 // since either both must be present, or neither can:
1134 env(escrow::finish("bob", "alice", seq),
1136 ter(temMALFORMED));
1137 env(escrow::finish("bob", "alice", seq),
1139 ter(temMALFORMED));
1140
1141 // Now finish it.
1142 env(escrow::finish("bob", "alice", seq),
1145 fee(150 * baseFee));
1146 env.require(balance("carol", XRP(6000)));
1147 env.require(balance("alice", XRP(4000) - drops(baseFee)));
1148 }
1149 { // Test a condition other than PreimageSha256, which
1150 // would require a separate amendment
1151 Env env(*this, features);
1152 env.fund(XRP(5000), "alice", "bob");
1153
1155 {0xA2, 0x2B, 0x80, 0x20, 0x42, 0x4A, 0x70, 0x49, 0x49,
1156 0x52, 0x92, 0x67, 0xB6, 0x21, 0xB3, 0xD7, 0x91, 0x19,
1157 0xD7, 0x29, 0xB2, 0x38, 0x2C, 0xED, 0x8B, 0x29, 0x6C,
1158 0x3C, 0x02, 0x8F, 0xA9, 0x7D, 0x35, 0x0F, 0x6D, 0x07,
1159 0x81, 0x03, 0x06, 0x34, 0xD2, 0x82, 0x02, 0x03, 0xC8}};
1160
1161 // FIXME: this transaction should, eventually, return temDISABLED
1162 // instead of temMALFORMED.
1163 env(escrow::create("alice", "bob", XRP(1000)),
1165 escrow::cancel_time(env.now() + 1s),
1166 ter(temMALFORMED));
1167 }
1168 }
1169
1170 void
1172 {
1173 using namespace jtx;
1174 using namespace std::chrono;
1175
1176 auto const alice = Account("alice");
1177 auto const bruce = Account("bruce");
1178 auto const carol = Account("carol");
1179
1180 {
1181 testcase("Metadata to self");
1182
1183 Env env(*this, features);
1184 env.fund(XRP(5000), alice, bruce, carol);
1185 auto const aseq = env.seq(alice);
1186 auto const bseq = env.seq(bruce);
1187
1188 env(escrow::create(alice, alice, XRP(1000)),
1189 escrow::finish_time(env.now() + 1s),
1190 escrow::cancel_time(env.now() + 500s));
1191 BEAST_EXPECT(
1192 (*env.meta())[sfTransactionResult] ==
1193 static_cast<std::uint8_t>(tesSUCCESS));
1194 env.close(5s);
1195 auto const aa = env.le(keylet::escrow(alice.id(), aseq));
1196 BEAST_EXPECT(aa);
1197
1198 {
1199 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1200 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1201 BEAST_EXPECT(
1202 std::find(aod.begin(), aod.end(), aa) != aod.end());
1203 }
1204
1205 env(escrow::create(bruce, bruce, XRP(1000)),
1206 escrow::finish_time(env.now() + 1s),
1207 escrow::cancel_time(env.now() + 2s));
1208 BEAST_EXPECT(
1209 (*env.meta())[sfTransactionResult] ==
1210 static_cast<std::uint8_t>(tesSUCCESS));
1211 env.close(5s);
1212 auto const bb = env.le(keylet::escrow(bruce.id(), bseq));
1213 BEAST_EXPECT(bb);
1214
1215 {
1216 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1217 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1218 BEAST_EXPECT(
1219 std::find(bod.begin(), bod.end(), bb) != bod.end());
1220 }
1221
1222 env.close(5s);
1223 env(escrow::finish(alice, alice, aseq));
1224 {
1225 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1226 BEAST_EXPECT(
1227 (*env.meta())[sfTransactionResult] ==
1228 static_cast<std::uint8_t>(tesSUCCESS));
1229
1230 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1231 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0);
1232 BEAST_EXPECT(
1233 std::find(aod.begin(), aod.end(), aa) == aod.end());
1234
1235 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1236 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1237 BEAST_EXPECT(
1238 std::find(bod.begin(), bod.end(), bb) != bod.end());
1239 }
1240
1241 env.close(5s);
1242 env(escrow::cancel(bruce, bruce, bseq));
1243 {
1244 BEAST_EXPECT(!env.le(keylet::escrow(bruce.id(), bseq)));
1245 BEAST_EXPECT(
1246 (*env.meta())[sfTransactionResult] ==
1247 static_cast<std::uint8_t>(tesSUCCESS));
1248
1249 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1250 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 0);
1251 BEAST_EXPECT(
1252 std::find(bod.begin(), bod.end(), bb) == bod.end());
1253 }
1254 }
1255 {
1256 testcase("Metadata to other");
1257
1258 Env env(*this, features);
1259 env.fund(XRP(5000), alice, bruce, carol);
1260 auto const aseq = env.seq(alice);
1261 auto const bseq = env.seq(bruce);
1262
1263 env(escrow::create(alice, bruce, XRP(1000)),
1264 escrow::finish_time(env.now() + 1s));
1265 BEAST_EXPECT(
1266 (*env.meta())[sfTransactionResult] ==
1267 static_cast<std::uint8_t>(tesSUCCESS));
1268 env.close(5s);
1269 env(escrow::create(bruce, carol, XRP(1000)),
1270 escrow::finish_time(env.now() + 1s),
1271 escrow::cancel_time(env.now() + 2s));
1272 BEAST_EXPECT(
1273 (*env.meta())[sfTransactionResult] ==
1274 static_cast<std::uint8_t>(tesSUCCESS));
1275 env.close(5s);
1276
1277 auto const ab = env.le(keylet::escrow(alice.id(), aseq));
1278 BEAST_EXPECT(ab);
1279
1280 auto const bc = env.le(keylet::escrow(bruce.id(), bseq));
1281 BEAST_EXPECT(bc);
1282
1283 {
1284 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1285 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1286 BEAST_EXPECT(
1287 std::find(aod.begin(), aod.end(), ab) != aod.end());
1288
1289 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1290 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
1291 BEAST_EXPECT(
1292 std::find(bod.begin(), bod.end(), ab) != bod.end());
1293 BEAST_EXPECT(
1294 std::find(bod.begin(), bod.end(), bc) != bod.end());
1295
1296 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1297 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
1298 BEAST_EXPECT(
1299 std::find(cod.begin(), cod.end(), bc) != cod.end());
1300 }
1301
1302 env.close(5s);
1303 env(escrow::finish(alice, alice, aseq));
1304 {
1305 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1306 BEAST_EXPECT(env.le(keylet::escrow(bruce.id(), bseq)));
1307
1308 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1309 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0);
1310 BEAST_EXPECT(
1311 std::find(aod.begin(), aod.end(), ab) == aod.end());
1312
1313 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1314 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1315 BEAST_EXPECT(
1316 std::find(bod.begin(), bod.end(), ab) == bod.end());
1317 BEAST_EXPECT(
1318 std::find(bod.begin(), bod.end(), bc) != bod.end());
1319
1320 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1321 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
1322 }
1323
1324 env.close(5s);
1325 env(escrow::cancel(bruce, bruce, bseq));
1326 {
1327 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1328 BEAST_EXPECT(!env.le(keylet::escrow(bruce.id(), bseq)));
1329
1330 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1331 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0);
1332 BEAST_EXPECT(
1333 std::find(aod.begin(), aod.end(), ab) == aod.end());
1334
1335 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1336 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 0);
1337 BEAST_EXPECT(
1338 std::find(bod.begin(), bod.end(), ab) == bod.end());
1339 BEAST_EXPECT(
1340 std::find(bod.begin(), bod.end(), bc) == bod.end());
1341
1342 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1343 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 0);
1344 }
1345 }
1346 }
1347
1348 void
1350 {
1351 testcase("Consequences");
1352
1353 using namespace jtx;
1354 using namespace std::chrono;
1355 Env env(*this, features);
1356 auto const baseFee = env.current()->fees().base;
1357
1358 env.memoize("alice");
1359 env.memoize("bob");
1360 env.memoize("carol");
1361
1362 {
1363 auto const jtx = env.jt(
1364 escrow::create("alice", "carol", XRP(1000)),
1365 escrow::finish_time(env.now() + 1s),
1366 seq(1),
1367 fee(baseFee));
1368 auto const pf = preflight(
1369 env.app(),
1370 env.current()->rules(),
1371 *jtx.stx,
1372 tapNONE,
1373 env.journal);
1374 BEAST_EXPECT(pf.ter == tesSUCCESS);
1375 BEAST_EXPECT(!pf.consequences.isBlocker());
1376 BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
1377 BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(1000));
1378 }
1379
1380 {
1381 auto const jtx =
1382 env.jt(escrow::cancel("bob", "alice", 3), seq(1), fee(baseFee));
1383 auto const pf = preflight(
1384 env.app(),
1385 env.current()->rules(),
1386 *jtx.stx,
1387 tapNONE,
1388 env.journal);
1389 BEAST_EXPECT(pf.ter == tesSUCCESS);
1390 BEAST_EXPECT(!pf.consequences.isBlocker());
1391 BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
1392 BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
1393 }
1394
1395 {
1396 auto const jtx =
1397 env.jt(escrow::finish("bob", "alice", 3), seq(1), fee(baseFee));
1398 auto const pf = preflight(
1399 env.app(),
1400 env.current()->rules(),
1401 *jtx.stx,
1402 tapNONE,
1403 env.journal);
1404 BEAST_EXPECT(pf.ter == tesSUCCESS);
1405 BEAST_EXPECT(!pf.consequences.isBlocker());
1406 BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
1407 BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
1408 }
1409 }
1410
1411 void
1413 {
1414 testcase("Escrow with tickets");
1415
1416 using namespace jtx;
1417 using namespace std::chrono;
1418 Account const alice{"alice"};
1419 Account const bob{"bob"};
1420
1421 {
1422 // Create escrow and finish using tickets.
1423 Env env(*this, features);
1424 auto const baseFee = env.current()->fees().base;
1425 env.fund(XRP(5000), alice, bob);
1426 env.close();
1427
1428 // alice creates a ticket.
1429 std::uint32_t const aliceTicket{env.seq(alice) + 1};
1430 env(ticket::create(alice, 1));
1431
1432 // bob creates a bunch of tickets because he will be burning
1433 // through them with tec transactions. Just because we can
1434 // we'll use them up starting from largest and going smaller.
1435 constexpr static std::uint32_t bobTicketCount{20};
1436 env(ticket::create(bob, bobTicketCount));
1437 env.close();
1438 std::uint32_t bobTicket{env.seq(bob)};
1439 env.require(tickets(alice, 1));
1440 env.require(tickets(bob, bobTicketCount));
1441
1442 // Note that from here on all transactions use tickets. No account
1443 // root sequences should change.
1444 std::uint32_t const aliceRootSeq{env.seq(alice)};
1445 std::uint32_t const bobRootSeq{env.seq(bob)};
1446
1447 // alice creates an escrow that can be finished in the future
1448 auto const ts = env.now() + 97s;
1449
1450 std::uint32_t const escrowSeq = aliceTicket;
1451 env(escrow::create(alice, bob, XRP(1000)),
1453 ticket::use(aliceTicket));
1454 BEAST_EXPECT(env.seq(alice) == aliceRootSeq);
1455 env.require(tickets(alice, 0));
1456 env.require(tickets(bob, bobTicketCount));
1457
1458 // Advance the ledger, verifying that the finish won't complete
1459 // prematurely. Note that each tec consumes one of bob's tickets.
1460 for (; env.now() < ts; env.close())
1461 {
1462 env(escrow::finish(bob, alice, escrowSeq),
1463 fee(150 * baseFee),
1464 ticket::use(--bobTicket),
1466 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1467 }
1468
1469 // bob tries to re-use a ticket, which is rejected.
1470 env(escrow::finish(bob, alice, escrowSeq),
1471 fee(150 * baseFee),
1472 ticket::use(bobTicket),
1473 ter(tefNO_TICKET));
1474
1475 // bob uses one of his remaining tickets. Success!
1476 env(escrow::finish(bob, alice, escrowSeq),
1477 fee(150 * baseFee),
1478 ticket::use(--bobTicket));
1479 env.close();
1480 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1481 }
1482 {
1483 // Create escrow and cancel using tickets.
1484 Env env(*this, features);
1485 auto const baseFee = env.current()->fees().base;
1486 env.fund(XRP(5000), alice, bob);
1487 env.close();
1488
1489 // alice creates a ticket.
1490 std::uint32_t const aliceTicket{env.seq(alice) + 1};
1491 env(ticket::create(alice, 1));
1492
1493 // bob creates a bunch of tickets because he will be burning
1494 // through them with tec transactions.
1495 constexpr std::uint32_t bobTicketCount{20};
1496 std::uint32_t bobTicket{env.seq(bob) + 1};
1497 env(ticket::create(bob, bobTicketCount));
1498 env.close();
1499 env.require(tickets(alice, 1));
1500 env.require(tickets(bob, bobTicketCount));
1501
1502 // Note that from here on all transactions use tickets. No account
1503 // root sequences should change.
1504 std::uint32_t const aliceRootSeq{env.seq(alice)};
1505 std::uint32_t const bobRootSeq{env.seq(bob)};
1506
1507 // alice creates an escrow that can be finished in the future.
1508 auto const ts = env.now() + 117s;
1509
1510 std::uint32_t const escrowSeq = aliceTicket;
1511 env(escrow::create(alice, bob, XRP(1000)),
1514 ticket::use(aliceTicket));
1515 BEAST_EXPECT(env.seq(alice) == aliceRootSeq);
1516 env.require(tickets(alice, 0));
1517 env.require(tickets(bob, bobTicketCount));
1518
1519 // Advance the ledger, verifying that the cancel won't complete
1520 // prematurely.
1521 for (; env.now() < ts; env.close())
1522 {
1523 env(escrow::cancel(bob, alice, escrowSeq),
1524 fee(150 * baseFee),
1525 ticket::use(bobTicket++),
1527 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1528 }
1529
1530 // Verify that a finish won't work anymore.
1531 env(escrow::finish(bob, alice, escrowSeq),
1534 fee(150 * baseFee),
1535 ticket::use(bobTicket++),
1537 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1538
1539 // Verify that the cancel succeeds.
1540 env(escrow::cancel(bob, alice, escrowSeq),
1541 fee(150 * baseFee),
1542 ticket::use(bobTicket++));
1543 env.close();
1544 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1545
1546 // Verify that bob actually consumed his tickets.
1547 env.require(tickets(bob, env.seq(bob) - bobTicket));
1548 }
1549 }
1550
1551 void
1553 {
1554 testcase("Test with credentials");
1555
1556 using namespace jtx;
1557 using namespace std::chrono;
1558
1559 Account const alice{"alice"};
1560 Account const bob{"bob"};
1561 Account const carol{"carol"};
1562 Account const dillon{"dillon "};
1563 Account const zelda{"zelda"};
1564
1565 char const credType[] = "abcde";
1566
1567 {
1568 // Credentials amendment not enabled
1569 Env env(*this, features - featureCredentials);
1570 env.fund(XRP(5000), alice, bob);
1571 env.close();
1572
1573 auto const seq = env.seq(alice);
1574 env(escrow::create(alice, bob, XRP(1000)),
1575 escrow::finish_time(env.now() + 1s));
1576 env.close();
1577
1578 env(fset(bob, asfDepositAuth));
1579 env.close();
1580 env(deposit::auth(bob, alice));
1581 env.close();
1582
1583 std::string const credIdx =
1584 "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B"
1585 "E4";
1586 env(escrow::finish(bob, alice, seq),
1587 credentials::ids({credIdx}),
1588 ter(temDISABLED));
1589 }
1590
1591 {
1592 Env env(*this, features);
1593
1594 env.fund(XRP(5000), alice, bob, carol, dillon, zelda);
1595 env.close();
1596
1597 env(credentials::create(carol, zelda, credType));
1598 env.close();
1599 auto const jv =
1600 credentials::ledgerEntry(env, carol, zelda, credType);
1601 std::string const credIdx = jv[jss::result][jss::index].asString();
1602
1603 auto const seq = env.seq(alice);
1604 env(escrow::create(alice, bob, XRP(1000)),
1605 escrow::finish_time(env.now() + 50s));
1606 env.close();
1607
1608 // Bob require preauthorization
1609 env(fset(bob, asfDepositAuth));
1610 env.close();
1611
1612 // Fail, credentials not accepted
1613 env(escrow::finish(carol, alice, seq),
1614 credentials::ids({credIdx}),
1616
1617 env.close();
1618
1619 env(credentials::accept(carol, zelda, credType));
1620 env.close();
1621
1622 // Fail, credentials doesn’t belong to root account
1623 env(escrow::finish(dillon, alice, seq),
1624 credentials::ids({credIdx}),
1626
1627 // Fail, no depositPreauth
1628 env(escrow::finish(carol, alice, seq),
1629 credentials::ids({credIdx}),
1631
1632 env(deposit::authCredentials(bob, {{zelda, credType}}));
1633 env.close();
1634
1635 // Success
1636 env.close();
1637 env(escrow::finish(carol, alice, seq), credentials::ids({credIdx}));
1638 env.close();
1639 }
1640
1641 {
1642 testcase("Escrow with credentials without depositPreauth");
1643 using namespace std::chrono;
1644
1645 Env env(*this, features);
1646
1647 env.fund(XRP(5000), alice, bob, carol, dillon, zelda);
1648 env.close();
1649
1650 env(credentials::create(carol, zelda, credType));
1651 env.close();
1652 env(credentials::accept(carol, zelda, credType));
1653 env.close();
1654 auto const jv =
1655 credentials::ledgerEntry(env, carol, zelda, credType);
1656 std::string const credIdx = jv[jss::result][jss::index].asString();
1657
1658 auto const seq = env.seq(alice);
1659 env(escrow::create(alice, bob, XRP(1000)),
1660 escrow::finish_time(env.now() + 50s));
1661 // time advance
1662 env.close();
1663 env.close();
1664 env.close();
1665 env.close();
1666 env.close();
1667 env.close();
1668
1669 // Succeed, Bob doesn't require preauthorization
1670 env(escrow::finish(carol, alice, seq), credentials::ids({credIdx}));
1671 env.close();
1672
1673 {
1674 char const credType2[] = "fghijk";
1675
1676 env(credentials::create(bob, zelda, credType2));
1677 env.close();
1678 env(credentials::accept(bob, zelda, credType2));
1679 env.close();
1680 auto const credIdxBob =
1682 env, bob, zelda, credType2)[jss::result][jss::index]
1683 .asString();
1684
1685 auto const seq = env.seq(alice);
1686 env(escrow::create(alice, bob, XRP(1000)),
1687 escrow::finish_time(env.now() + 1s));
1688 env.close();
1689
1690 // Bob require preauthorization
1691 env(fset(bob, asfDepositAuth));
1692 env.close();
1693 env(deposit::authCredentials(bob, {{zelda, credType}}));
1694 env.close();
1695
1696 // Use any valid credentials if account == dst
1697 env(escrow::finish(bob, alice, seq),
1698 credentials::ids({credIdxBob}));
1699 env.close();
1700 }
1701 }
1702 }
1703
1704 void
1706 {
1707 testEnablement(features);
1708 testTiming(features);
1709 testTags(features);
1710 testDisallowXRP(features);
1711 test1571(features);
1712 testFails(features);
1713 testLockup(features);
1714 testEscrowConditions(features);
1715 testMetaAndOwnership(features);
1716 testConsequences(features);
1717 testEscrowWithTickets(features);
1718 testCredentials(features);
1719 }
1720
1721public:
1722 void
1723 run() override
1724 {
1725 using namespace test::jtx;
1728 testWithFeats(all - featureTokenEscrow);
1729 testTags(all - fixIncludeKeyletFields);
1730 }
1731};
1732
1733BEAST_DEFINE_TESTSUITE(Escrow, app, ripple);
1734
1735} // namespace test
1736} // namespace ripple
std::string asString() const
Returns the unquoted string value.
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:258
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:121
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:279
std::shared_ptr< STObject const > meta()
Return metadata for the last JTx.
Definition Env.cpp:493
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition Env.cpp:183
void memoize(Account const &account)
Associate AccountID with account.
Definition Env.cpp:156
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition Env.cpp:267
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
FeatureBitset testable_amendments()
Definition Env.h:74
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
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.
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)
void testWithFeats(FeatureBitset features)
void test1571(FeatureBitset features)
void testEscrowWithTickets(FeatureBitset features)
void testDisallowXRP(FeatureBitset features)
void testTiming(FeatureBitset features)
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