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