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 // A PreimageSha256 fulfillments and its associated condition.
39 std::array<std::uint8_t, 4> const fb1 = {{0xA0, 0x02, 0x80, 0x00}};
40
42 {0xA0, 0x25, 0x80, 0x20, 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC,
43 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,
44 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95,
45 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55, 0x81, 0x01, 0x00}};
46
47 // Another PreimageSha256 fulfillments and its associated condition.
49 {0xA0, 0x05, 0x80, 0x03, 0x61, 0x61, 0x61}};
50
52 {0xA0, 0x25, 0x80, 0x20, 0x98, 0x34, 0x87, 0x6D, 0xCF, 0xB0,
53 0x5C, 0xB1, 0x67, 0xA5, 0xC2, 0x49, 0x53, 0xEB, 0xA5, 0x8C,
54 0x4A, 0xC8, 0x9B, 0x1A, 0xDF, 0x57, 0xF2, 0x8F, 0x2F, 0x9D,
55 0x09, 0xAF, 0x10, 0x7E, 0xE8, 0xF0, 0x81, 0x01, 0x03}};
56
57 // Another PreimageSha256 fulfillment and its associated condition.
59 {0xA0, 0x06, 0x80, 0x04, 0x6E, 0x69, 0x6B, 0x62}};
60
62 {0xA0, 0x25, 0x80, 0x20, 0x6E, 0x4C, 0x71, 0x45, 0x30, 0xC0,
63 0xA4, 0x26, 0x8B, 0x3F, 0xA6, 0x3B, 0x1B, 0x60, 0x6F, 0x2D,
64 0x26, 0x4A, 0x2D, 0x85, 0x7B, 0xE8, 0xA0, 0x9C, 0x1D, 0xFD,
65 0x57, 0x0D, 0x15, 0x85, 0x8B, 0xD4, 0x81, 0x01, 0x04}};
66
67 void
69 {
70 testcase("Enablement");
71
72 using namespace jtx;
73 using namespace std::chrono;
74
75 Env env(*this);
76 env.fund(XRP(5000), "alice", "bob");
77 env(escrow("alice", "bob", XRP(1000)), finish_time(env.now() + 1s));
78 env.close();
79
80 auto const seq1 = env.seq("alice");
81
82 env(escrow("alice", "bob", XRP(1000)),
84 finish_time(env.now() + 1s),
85 fee(1500));
86 env.close();
87 env(finish("bob", "alice", seq1),
90 fee(1500));
91
92 auto const seq2 = env.seq("alice");
93
94 env(escrow("alice", "bob", XRP(1000)),
96 finish_time(env.now() + 1s),
97 cancel_time(env.now() + 2s),
98 fee(1500));
99 env.close();
100 env(cancel("bob", "alice", seq2), fee(1500));
101 }
102
103 void
105 {
106 using namespace jtx;
107 using namespace std::chrono;
108
109 {
110 testcase("Timing: Finish Only");
111 Env env(*this);
112 env.fund(XRP(5000), "alice", "bob");
113 env.close();
114
115 // We create an escrow that can be finished in the future
116 auto const ts = env.now() + 97s;
117
118 auto const seq = env.seq("alice");
119 env(escrow("alice", "bob", XRP(1000)), finish_time(ts));
120
121 // Advance the ledger, verifying that the finish won't complete
122 // prematurely.
123 for (; env.now() < ts; env.close())
124 env(finish("bob", "alice", seq),
125 fee(1500),
127
128 env(finish("bob", "alice", seq), fee(1500));
129 }
130
131 {
132 testcase("Timing: Cancel Only");
133 Env env(*this);
134 env.fund(XRP(5000), "alice", "bob");
135 env.close();
136
137 // We create an escrow that can be cancelled in the future
138 auto const ts = env.now() + 117s;
139
140 auto const seq = env.seq("alice");
141 env(escrow("alice", "bob", XRP(1000)),
142 condition(cb1),
143 cancel_time(ts));
144
145 // Advance the ledger, verifying that the cancel won't complete
146 // prematurely.
147 for (; env.now() < ts; env.close())
148 env(cancel("bob", "alice", seq),
149 fee(1500),
151
152 // Verify that a finish won't work anymore.
153 env(finish("bob", "alice", seq),
154 condition(cb1),
156 fee(1500),
158
159 // Verify that the cancel will succeed
160 env(cancel("bob", "alice", seq), fee(1500));
161 }
162
163 {
164 testcase("Timing: Finish and Cancel -> Finish");
165 Env env(*this);
166 env.fund(XRP(5000), "alice", "bob");
167 env.close();
168
169 // We create an escrow that can be cancelled in the future
170 auto const fts = env.now() + 117s;
171 auto const cts = env.now() + 192s;
172
173 auto const seq = env.seq("alice");
174 env(escrow("alice", "bob", XRP(1000)),
175 finish_time(fts),
176 cancel_time(cts));
177
178 // Advance the ledger, verifying that the finish and cancel won't
179 // complete prematurely.
180 for (; env.now() < fts; env.close())
181 {
182 env(finish("bob", "alice", seq),
183 fee(1500),
185 env(cancel("bob", "alice", seq),
186 fee(1500),
188 }
189
190 // Verify that a cancel still won't work
191 env(cancel("bob", "alice", seq), fee(1500), ter(tecNO_PERMISSION));
192
193 // And verify that a finish will
194 env(finish("bob", "alice", seq), fee(1500));
195 }
196
197 {
198 testcase("Timing: Finish and Cancel -> Cancel");
199 Env env(*this);
200 env.fund(XRP(5000), "alice", "bob");
201 env.close();
202
203 // We create an escrow that can be cancelled in the future
204 auto const fts = env.now() + 109s;
205 auto const cts = env.now() + 184s;
206
207 auto const seq = env.seq("alice");
208 env(escrow("alice", "bob", XRP(1000)),
209 finish_time(fts),
210 cancel_time(cts));
211
212 // Advance the ledger, verifying that the finish and cancel won't
213 // complete prematurely.
214 for (; env.now() < fts; env.close())
215 {
216 env(finish("bob", "alice", seq),
217 fee(1500),
219 env(cancel("bob", "alice", seq),
220 fee(1500),
222 }
223
224 // Continue advancing, verifying that the cancel won't complete
225 // prematurely. At this point a finish would succeed.
226 for (; env.now() < cts; env.close())
227 env(cancel("bob", "alice", seq),
228 fee(1500),
230
231 // Verify that finish will no longer work, since we are past the
232 // cancel activation time.
233 env(finish("bob", "alice", seq), fee(1500), ter(tecNO_PERMISSION));
234
235 // And verify that a cancel will succeed.
236 env(cancel("bob", "alice", seq), fee(1500));
237 }
238 }
239
240 void
242 {
243 testcase("Tags");
244
245 using namespace jtx;
246 using namespace std::chrono;
247
248 Env env(*this);
249
250 auto const alice = Account("alice");
251 auto const bob = Account("bob");
252
253 env.fund(XRP(5000), alice, bob);
254
255 // Check to make sure that we correctly detect if tags are really
256 // required:
257 env(fset(bob, asfRequireDest));
258 env(escrow(alice, bob, XRP(1000)),
259 finish_time(env.now() + 1s),
261
262 // set source and dest tags
263 auto const seq = env.seq(alice);
264
265 env(escrow(alice, bob, XRP(1000)),
266 finish_time(env.now() + 1s),
267 stag(1),
268 dtag(2));
269
270 auto const sle = env.le(keylet::escrow(alice.id(), seq));
271 BEAST_EXPECT(sle);
272 BEAST_EXPECT((*sle)[sfSourceTag] == 1);
273 BEAST_EXPECT((*sle)[sfDestinationTag] == 2);
274 }
275
276 void
278 {
279 testcase("Disallow XRP");
280
281 using namespace jtx;
282 using namespace std::chrono;
283
284 {
285 // Respect the "asfDisallowXRP" account flag:
286 Env env(*this, supported_amendments() - featureDepositAuth);
287
288 env.fund(XRP(5000), "bob", "george");
289 env(fset("george", asfDisallowXRP));
290 env(escrow("bob", "george", XRP(10)),
291 finish_time(env.now() + 1s),
293 }
294 {
295 // Ignore the "asfDisallowXRP" account flag, which we should
296 // have been doing before.
297 Env env(*this);
298
299 env.fund(XRP(5000), "bob", "george");
300 env(fset("george", asfDisallowXRP));
301 env(escrow("bob", "george", XRP(10)), finish_time(env.now() + 1s));
302 }
303 }
304
305 void
307 {
308 using namespace jtx;
309 using namespace std::chrono;
310
311 {
312 testcase("Implied Finish Time (without fix1571)");
313
314 Env env(*this, supported_amendments() - fix1571);
315 env.fund(XRP(5000), "alice", "bob", "carol");
316 env.close();
317
318 // Creating an escrow without a finish time and finishing it
319 // is allowed without fix1571:
320 auto const seq1 = env.seq("alice");
321 env(escrow("alice", "bob", XRP(100)),
322 cancel_time(env.now() + 1s),
323 fee(1500));
324 env.close();
325 env(finish("carol", "alice", seq1), fee(1500));
326 BEAST_EXPECT(env.balance("bob") == XRP(5100));
327
328 env.close();
329
330 // Creating an escrow without a finish time and a condition is
331 // also allowed without fix1571:
332 auto const seq2 = env.seq("alice");
333 env(escrow("alice", "bob", XRP(100)),
334 cancel_time(env.now() + 1s),
335 condition(cb1),
336 fee(1500));
337 env.close();
338 env(finish("carol", "alice", seq2),
339 condition(cb1),
341 fee(1500));
342 BEAST_EXPECT(env.balance("bob") == XRP(5200));
343 }
344
345 {
346 testcase("Implied Finish Time (with fix1571)");
347
348 Env env(*this);
349 env.fund(XRP(5000), "alice", "bob", "carol");
350 env.close();
351
352 // Creating an escrow with only a cancel time is not allowed:
353 env(escrow("alice", "bob", XRP(100)),
354 cancel_time(env.now() + 90s),
355 fee(1500),
357
358 // Creating an escrow with only a cancel time and a condition is
359 // allowed:
360 auto const seq = env.seq("alice");
361 env(escrow("alice", "bob", XRP(100)),
362 cancel_time(env.now() + 90s),
363 condition(cb1),
364 fee(1500));
365 env.close();
366 env(finish("carol", "alice", seq),
367 condition(cb1),
369 fee(1500));
370 BEAST_EXPECT(env.balance("bob") == XRP(5100));
371 }
372 }
373
374 void
376 {
377 testcase("Failure Cases");
378
379 using namespace jtx;
380 using namespace std::chrono;
381
382 Env env(*this);
383 env.fund(XRP(5000), "alice", "bob");
384 env.close();
385
386 // Finish time is in the past
387 env(escrow("alice", "bob", XRP(1000)),
388 finish_time(env.now() - 5s),
390
391 // Cancel time is in the past
392 env(escrow("alice", "bob", XRP(1000)),
393 condition(cb1),
394 cancel_time(env.now() - 5s),
396
397 // no destination account
398 env(escrow("alice", "carol", XRP(1000)),
399 finish_time(env.now() + 1s),
400 ter(tecNO_DST));
401
402 env.fund(XRP(5000), "carol");
403
404 // Using non-XRP:
405 env(escrow("alice", "carol", Account("alice")["USD"](500)),
406 finish_time(env.now() + 1s),
408
409 // Sending zero or no XRP:
410 env(escrow("alice", "carol", XRP(0)),
411 finish_time(env.now() + 1s),
413 env(escrow("alice", "carol", XRP(-1000)),
414 finish_time(env.now() + 1s),
416
417 // Fail if neither CancelAfter nor FinishAfter are specified:
418 env(escrow("alice", "carol", XRP(1)), ter(temBAD_EXPIRATION));
419
420 // Fail if neither a FinishTime nor a condition are attached:
421 env(escrow("alice", "carol", XRP(1)),
422 cancel_time(env.now() + 1s),
424
425 // Fail if FinishAfter has already passed:
426 env(escrow("alice", "carol", XRP(1)),
427 finish_time(env.now() - 1s),
429
430 // If both CancelAfter and FinishAfter are set, then CancelAfter must
431 // be strictly later than FinishAfter.
432 env(escrow("alice", "carol", XRP(1)),
433 condition(cb1),
434 finish_time(env.now() + 10s),
435 cancel_time(env.now() + 10s),
437
438 env(escrow("alice", "carol", XRP(1)),
439 condition(cb1),
440 finish_time(env.now() + 10s),
441 cancel_time(env.now() + 5s),
443
444 // Carol now requires the use of a destination tag
445 env(fset("carol", asfRequireDest));
446
447 // missing destination tag
448 env(escrow("alice", "carol", XRP(1)),
449 condition(cb1),
450 cancel_time(env.now() + 1s),
452
453 // Success!
454 env(escrow("alice", "carol", XRP(1)),
455 condition(cb1),
456 cancel_time(env.now() + 1s),
457 dtag(1));
458
459 { // Fail if the sender wants to send more than he has:
460 auto const accountReserve = drops(env.current()->fees().reserve);
461 auto const accountIncrement =
462 drops(env.current()->fees().increment);
463
464 env.fund(accountReserve + accountIncrement + XRP(50), "daniel");
465 env(escrow("daniel", "bob", XRP(51)),
466 finish_time(env.now() + 1s),
468
469 env.fund(accountReserve + accountIncrement + XRP(50), "evan");
470 env(escrow("evan", "bob", XRP(50)),
471 finish_time(env.now() + 1s),
473
474 env.fund(accountReserve, "frank");
475 env(escrow("frank", "bob", XRP(1)),
476 finish_time(env.now() + 1s),
478 }
479
480 { // Specify incorrect sequence number
481 env.fund(XRP(5000), "hannah");
482 auto const seq = env.seq("hannah");
483 env(escrow("hannah", "hannah", XRP(10)),
484 finish_time(env.now() + 1s),
485 fee(1500));
486 env.close();
487 env(finish("hannah", "hannah", seq + 7),
488 fee(1500),
490 }
491
492 { // Try to specify a condition for a non-conditional payment
493 env.fund(XRP(5000), "ivan");
494 auto const seq = env.seq("ivan");
495
496 env(escrow("ivan", "ivan", XRP(10)), finish_time(env.now() + 1s));
497 env.close();
498 env(finish("ivan", "ivan", seq),
499 condition(cb1),
501 fee(1500),
503 }
504 }
505
506 void
508 {
509 testcase("Lockup");
510
511 using namespace jtx;
512 using namespace std::chrono;
513
514 {
515 // Unconditional
516 Env env(*this);
517 env.fund(XRP(5000), "alice", "bob");
518 auto const seq = env.seq("alice");
519 env(escrow("alice", "alice", XRP(1000)),
520 finish_time(env.now() + 5s));
521 env.require(balance("alice", XRP(4000) - drops(10)));
522
523 // Not enough time has elapsed for a finish and canceling isn't
524 // possible.
525 env(cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
526 env(finish("bob", "alice", seq), ter(tecNO_PERMISSION));
527 env.close();
528
529 // Cancel continues to not be possible
530 env(cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
531
532 // Finish should succeed. Verify funds.
533 env(finish("bob", "alice", seq));
534 env.require(balance("alice", XRP(5000) - drops(10)));
535 }
536 {
537 // Unconditionally pay from Alice to Bob. Zelda (neither source nor
538 // destination) signs all cancels and finishes. This shows that
539 // Escrow will make a payment to Bob with no intervention from Bob.
540 Env env(*this);
541 env.fund(XRP(5000), "alice", "bob", "zelda");
542 auto const seq = env.seq("alice");
543 env(escrow("alice", "bob", XRP(1000)), finish_time(env.now() + 5s));
544 env.require(balance("alice", XRP(4000) - drops(10)));
545
546 // Not enough time has elapsed for a finish and canceling isn't
547 // possible.
548 env(cancel("zelda", "alice", seq), ter(tecNO_PERMISSION));
549 env(finish("zelda", "alice", seq), ter(tecNO_PERMISSION));
550 env.close();
551
552 // Cancel continues to not be possible
553 env(cancel("zelda", "alice", seq), ter(tecNO_PERMISSION));
554
555 // Finish should succeed. Verify funds.
556 env(finish("zelda", "alice", seq));
557 env.close();
558
559 env.require(balance("alice", XRP(4000) - drops(10)));
560 env.require(balance("bob", XRP(6000)));
561 env.require(balance("zelda", XRP(5000) - drops(40)));
562 }
563 {
564 // Bob sets DepositAuth so only Bob can finish the escrow.
565 Env env(*this);
566
567 env.fund(XRP(5000), "alice", "bob", "zelda");
568 env(fset("bob", asfDepositAuth));
569 env.close();
570
571 auto const seq = env.seq("alice");
572 env(escrow("alice", "bob", XRP(1000)), finish_time(env.now() + 5s));
573 env.require(balance("alice", XRP(4000) - drops(10)));
574
575 // Not enough time has elapsed for a finish and canceling isn't
576 // possible.
577 env(cancel("zelda", "alice", seq), ter(tecNO_PERMISSION));
578 env(cancel("alice", "alice", seq), ter(tecNO_PERMISSION));
579 env(cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
580 env(finish("zelda", "alice", seq), ter(tecNO_PERMISSION));
581 env(finish("alice", "alice", seq), ter(tecNO_PERMISSION));
582 env(finish("bob", "alice", seq), ter(tecNO_PERMISSION));
583 env.close();
584
585 // Cancel continues to not be possible. Finish will only succeed for
586 // Bob, because of DepositAuth.
587 env(cancel("zelda", "alice", seq), ter(tecNO_PERMISSION));
588 env(cancel("alice", "alice", seq), ter(tecNO_PERMISSION));
589 env(cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
590 env(finish("zelda", "alice", seq), ter(tecNO_PERMISSION));
591 env(finish("alice", "alice", seq), ter(tecNO_PERMISSION));
592 env(finish("bob", "alice", seq));
593 env.close();
594
595 auto const baseFee = env.current()->fees().base;
596 env.require(balance("alice", XRP(4000) - (baseFee * 5)));
597 env.require(balance("bob", XRP(6000) - (baseFee * 5)));
598 env.require(balance("zelda", XRP(5000) - (baseFee * 4)));
599 }
600 {
601 // Bob sets DepositAuth but preauthorizes Zelda, so Zelda can
602 // finish the escrow.
603 Env env(*this);
604
605 env.fund(XRP(5000), "alice", "bob", "zelda");
606 env(fset("bob", asfDepositAuth));
607 env.close();
608 env(deposit::auth("bob", "zelda"));
609 env.close();
610
611 auto const seq = env.seq("alice");
612 env(escrow("alice", "bob", XRP(1000)), finish_time(env.now() + 5s));
613 env.require(balance("alice", XRP(4000) - drops(10)));
614 env.close();
615
616 // DepositPreauth allows Finish to succeed for either Zelda or
617 // Bob. But Finish won't succeed for Alice since she is not
618 // preauthorized.
619 env(finish("alice", "alice", seq), ter(tecNO_PERMISSION));
620 env(finish("zelda", "alice", seq));
621 env.close();
622
623 auto const baseFee = env.current()->fees().base;
624 env.require(balance("alice", XRP(4000) - (baseFee * 2)));
625 env.require(balance("bob", XRP(6000) - (baseFee * 2)));
626 env.require(balance("zelda", XRP(5000) - (baseFee * 1)));
627 }
628 {
629 // Conditional
630 Env env(*this);
631 env.fund(XRP(5000), "alice", "bob");
632 auto const seq = env.seq("alice");
633 env(escrow("alice", "alice", XRP(1000)),
634 condition(cb2),
635 finish_time(env.now() + 5s));
636 env.require(balance("alice", XRP(4000) - drops(10)));
637
638 // Not enough time has elapsed for a finish and canceling isn't
639 // possible.
640 env(cancel("alice", "alice", seq), ter(tecNO_PERMISSION));
641 env(cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
642 env(finish("alice", "alice", seq), ter(tecNO_PERMISSION));
643 env(finish("alice", "alice", seq),
644 condition(cb2),
646 fee(1500),
648 env(finish("bob", "alice", seq), ter(tecNO_PERMISSION));
649 env(finish("bob", "alice", seq),
650 condition(cb2),
652 fee(1500),
654 env.close();
655
656 // Cancel continues to not be possible. Finish is possible but
657 // requires the fulfillment associated with the escrow.
658 env(cancel("alice", "alice", seq), ter(tecNO_PERMISSION));
659 env(cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
660 env(finish("bob", "alice", seq), ter(tecCRYPTOCONDITION_ERROR));
661 env(finish("alice", "alice", seq), ter(tecCRYPTOCONDITION_ERROR));
662 env.close();
663
664 env(finish("bob", "alice", seq),
665 condition(cb2),
667 fee(1500));
668 }
669 {
670 // Self-escrowed conditional with DepositAuth.
671 Env env(*this);
672
673 env.fund(XRP(5000), "alice", "bob");
674 auto const seq = env.seq("alice");
675 env(escrow("alice", "alice", XRP(1000)),
676 condition(cb3),
677 finish_time(env.now() + 5s));
678 env.require(balance("alice", XRP(4000) - drops(10)));
679 env.close();
680
681 // Finish is now possible but requires the cryptocondition.
682 env(finish("bob", "alice", seq), ter(tecCRYPTOCONDITION_ERROR));
683 env(finish("alice", "alice", seq), ter(tecCRYPTOCONDITION_ERROR));
684
685 // Enable deposit authorization. After this only Alice can finish
686 // the escrow.
687 env(fset("alice", asfDepositAuth));
688 env.close();
689
690 env(finish("alice", "alice", seq),
691 condition(cb2),
693 fee(1500),
695 env(finish("bob", "alice", seq),
696 condition(cb3),
698 fee(1500),
700 env(finish("alice", "alice", seq),
701 condition(cb3),
703 fee(1500));
704 }
705 {
706 // Self-escrowed conditional with DepositAuth and DepositPreauth.
707 Env env(*this);
708
709 env.fund(XRP(5000), "alice", "bob", "zelda");
710 auto const seq = env.seq("alice");
711 env(escrow("alice", "alice", XRP(1000)),
712 condition(cb3),
713 finish_time(env.now() + 5s));
714 env.require(balance("alice", XRP(4000) - drops(10)));
715 env.close();
716
717 // Alice preauthorizes Zelda for deposit, even though Alice has not
718 // set the lsfDepositAuth flag (yet).
719 env(deposit::auth("alice", "zelda"));
720 env.close();
721
722 // Finish is now possible but requires the cryptocondition.
723 env(finish("alice", "alice", seq), ter(tecCRYPTOCONDITION_ERROR));
724 env(finish("bob", "alice", seq), ter(tecCRYPTOCONDITION_ERROR));
725 env(finish("zelda", "alice", seq), ter(tecCRYPTOCONDITION_ERROR));
726
727 // Alice enables deposit authorization. After this only Alice or
728 // Zelda (because Zelda is preauthorized) can finish the escrow.
729 env(fset("alice", asfDepositAuth));
730 env.close();
731
732 env(finish("alice", "alice", seq),
733 condition(cb2),
735 fee(1500),
737 env(finish("bob", "alice", seq),
738 condition(cb3),
740 fee(1500),
742 env(finish("zelda", "alice", seq),
743 condition(cb3),
745 fee(1500));
746 }
747 }
748
749 void
751 {
752 testcase("Escrow with CryptoConditions");
753
754 using namespace jtx;
755 using namespace std::chrono;
756
757 { // Test cryptoconditions
758 Env env(*this);
759 env.fund(XRP(5000), "alice", "bob", "carol");
760 auto const seq = env.seq("alice");
761 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
762 env(escrow("alice", "carol", XRP(1000)),
763 condition(cb1),
764 cancel_time(env.now() + 1s));
765 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
766 env.require(balance("alice", XRP(4000) - drops(10)));
767 env.require(balance("carol", XRP(5000)));
768 env(cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
769 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
770
771 // Attempt to finish without a fulfillment
772 env(finish("bob", "alice", seq), ter(tecCRYPTOCONDITION_ERROR));
773 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
774
775 // Attempt to finish with a condition instead of a fulfillment
776 env(finish("bob", "alice", seq),
777 condition(cb1),
779 fee(1500),
781 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
782 env(finish("bob", "alice", seq),
783 condition(cb1),
785 fee(1500),
787 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
788 env(finish("bob", "alice", seq),
789 condition(cb1),
791 fee(1500),
793 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
794
795 // Attempt to finish with an incorrect condition and various
796 // combinations of correct and incorrect fulfillments.
797 env(finish("bob", "alice", seq),
798 condition(cb2),
800 fee(1500),
802 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
803 env(finish("bob", "alice", seq),
804 condition(cb2),
806 fee(1500),
808 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
809 env(finish("bob", "alice", seq),
810 condition(cb2),
812 fee(1500),
814 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
815
816 // Attempt to finish with the correct condition & fulfillment
817 env(finish("bob", "alice", seq),
818 condition(cb1),
820 fee(1500));
821
822 // SLE removed on finish
823 BEAST_EXPECT(!env.le(keylet::escrow(Account("alice").id(), seq)));
824 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
825 env.require(balance("carol", XRP(6000)));
826 env(cancel("bob", "alice", seq), ter(tecNO_TARGET));
827 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
828 env(cancel("bob", "carol", 1), ter(tecNO_TARGET));
829 }
830 { // Test cancel when condition is present
831 Env env(*this);
832 env.fund(XRP(5000), "alice", "bob", "carol");
833 auto const seq = env.seq("alice");
834 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
835 env(escrow("alice", "carol", XRP(1000)),
836 condition(cb2),
837 cancel_time(env.now() + 1s));
838 env.close();
839 env.require(balance("alice", XRP(4000) - drops(10)));
840 // balance restored on cancel
841 env(cancel("bob", "alice", seq));
842 env.require(balance("alice", XRP(5000) - drops(10)));
843 // SLE removed on cancel
844 BEAST_EXPECT(!env.le(keylet::escrow(Account("alice").id(), seq)));
845 }
846 {
847 Env env(*this);
848 env.fund(XRP(5000), "alice", "bob", "carol");
849 env.close();
850 auto const seq = env.seq("alice");
851 env(escrow("alice", "carol", XRP(1000)),
852 condition(cb3),
853 cancel_time(env.now() + 1s));
854 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
855 // cancel fails before expiration
856 env(cancel("bob", "alice", seq), ter(tecNO_PERMISSION));
857 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
858 env.close();
859 // finish fails after expiration
860 env(finish("bob", "alice", seq),
861 condition(cb3),
863 fee(1500),
865 BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 1);
866 env.require(balance("carol", XRP(5000)));
867 }
868 { // Test long & short conditions during creation
869 Env env(*this);
870 env.fund(XRP(5000), "alice", "bob", "carol");
871
873 v.resize(cb1.size() + 2, 0x78);
874 std::memcpy(v.data() + 1, cb1.data(), cb1.size());
875
876 auto const p = v.data();
877 auto const s = v.size();
878
879 auto const ts = env.now() + 1s;
880
881 // All these are expected to fail, because the
882 // condition we pass in is malformed in some way
883 env(escrow("alice", "carol", XRP(1000)),
884 condition(Slice{p, s}),
885 cancel_time(ts),
887 env(escrow("alice", "carol", XRP(1000)),
888 condition(Slice{p, s - 1}),
889 cancel_time(ts),
891 env(escrow("alice", "carol", XRP(1000)),
892 condition(Slice{p, s - 2}),
893 cancel_time(ts),
895 env(escrow("alice", "carol", XRP(1000)),
896 condition(Slice{p + 1, s - 1}),
897 cancel_time(ts),
899 env(escrow("alice", "carol", XRP(1000)),
900 condition(Slice{p + 1, s - 3}),
901 cancel_time(ts),
903 env(escrow("alice", "carol", XRP(1000)),
904 condition(Slice{p + 2, s - 2}),
905 cancel_time(ts),
907 env(escrow("alice", "carol", XRP(1000)),
908 condition(Slice{p + 2, s - 3}),
909 cancel_time(ts),
911
912 auto const seq = env.seq("alice");
913 env(escrow("alice", "carol", XRP(1000)),
914 condition(Slice{p + 1, s - 2}),
915 cancel_time(ts),
916 fee(100));
917 env(finish("bob", "alice", seq),
918 condition(cb1),
920 fee(1500));
921 env.require(balance("alice", XRP(4000) - drops(100)));
922 env.require(balance("bob", XRP(5000) - drops(1500)));
923 env.require(balance("carol", XRP(6000)));
924 }
925 { // Test long and short conditions & fulfillments during finish
926 Env env(*this);
927 env.fund(XRP(5000), "alice", "bob", "carol");
928
930 cv.resize(cb2.size() + 2, 0x78);
931 std::memcpy(cv.data() + 1, cb2.data(), cb2.size());
932
933 auto const cp = cv.data();
934 auto const cs = cv.size();
935
937 fv.resize(fb2.size() + 2, 0x13);
938 std::memcpy(fv.data() + 1, fb2.data(), fb2.size());
939
940 auto const fp = fv.data();
941 auto const fs = fv.size();
942
943 auto const ts = env.now() + 1s;
944
945 // All these are expected to fail, because the
946 // condition we pass in is malformed in some way
947 env(escrow("alice", "carol", XRP(1000)),
948 condition(Slice{cp, cs}),
949 cancel_time(ts),
951 env(escrow("alice", "carol", XRP(1000)),
952 condition(Slice{cp, cs - 1}),
953 cancel_time(ts),
955 env(escrow("alice", "carol", XRP(1000)),
956 condition(Slice{cp, cs - 2}),
957 cancel_time(ts),
959 env(escrow("alice", "carol", XRP(1000)),
960 condition(Slice{cp + 1, cs - 1}),
961 cancel_time(ts),
963 env(escrow("alice", "carol", XRP(1000)),
964 condition(Slice{cp + 1, cs - 3}),
965 cancel_time(ts),
967 env(escrow("alice", "carol", XRP(1000)),
968 condition(Slice{cp + 2, cs - 2}),
969 cancel_time(ts),
971 env(escrow("alice", "carol", XRP(1000)),
972 condition(Slice{cp + 2, cs - 3}),
973 cancel_time(ts),
975
976 auto const seq = env.seq("alice");
977 env(escrow("alice", "carol", XRP(1000)),
978 condition(Slice{cp + 1, cs - 2}),
979 cancel_time(ts),
980 fee(100));
981
982 // Now, try to fulfill using the same sequence of
983 // malformed conditions.
984 env(finish("bob", "alice", seq),
985 condition(Slice{cp, cs}),
986 fulfillment(Slice{fp, fs}),
987 fee(1500),
989 env(finish("bob", "alice", seq),
990 condition(Slice{cp, cs - 1}),
991 fulfillment(Slice{fp, fs}),
992 fee(1500),
994 env(finish("bob", "alice", seq),
995 condition(Slice{cp, cs - 2}),
996 fulfillment(Slice{fp, fs}),
997 fee(1500),
999 env(finish("bob", "alice", seq),
1000 condition(Slice{cp + 1, cs - 1}),
1001 fulfillment(Slice{fp, fs}),
1002 fee(1500),
1004 env(finish("bob", "alice", seq),
1005 condition(Slice{cp + 1, cs - 3}),
1006 fulfillment(Slice{fp, fs}),
1007 fee(1500),
1009 env(finish("bob", "alice", seq),
1010 condition(Slice{cp + 2, cs - 2}),
1011 fulfillment(Slice{fp, fs}),
1012 fee(1500),
1014 env(finish("bob", "alice", seq),
1015 condition(Slice{cp + 2, cs - 3}),
1016 fulfillment(Slice{fp, fs}),
1017 fee(1500),
1019
1020 // Now, using the correct condition, try malformed fulfillments:
1021 env(finish("bob", "alice", seq),
1022 condition(Slice{cp + 1, cs - 2}),
1023 fulfillment(Slice{fp, fs}),
1024 fee(1500),
1026 env(finish("bob", "alice", seq),
1027 condition(Slice{cp + 1, cs - 2}),
1028 fulfillment(Slice{fp, fs - 1}),
1029 fee(1500),
1031 env(finish("bob", "alice", seq),
1032 condition(Slice{cp + 1, cs - 2}),
1033 fulfillment(Slice{fp, fs - 2}),
1034 fee(1500),
1036 env(finish("bob", "alice", seq),
1037 condition(Slice{cp + 1, cs - 2}),
1038 fulfillment(Slice{fp + 1, fs - 1}),
1039 fee(1500),
1041 env(finish("bob", "alice", seq),
1042 condition(Slice{cp + 1, cs - 2}),
1043 fulfillment(Slice{fp + 1, fs - 3}),
1044 fee(1500),
1046 env(finish("bob", "alice", seq),
1047 condition(Slice{cp + 1, cs - 2}),
1048 fulfillment(Slice{fp + 1, fs - 3}),
1049 fee(1500),
1051 env(finish("bob", "alice", seq),
1052 condition(Slice{cp + 1, cs - 2}),
1053 fulfillment(Slice{fp + 2, fs - 2}),
1054 fee(1500),
1056 env(finish("bob", "alice", seq),
1057 condition(Slice{cp + 1, cs - 2}),
1058 fulfillment(Slice{fp + 2, fs - 3}),
1059 fee(1500),
1061
1062 // Now try for the right one
1063 env(finish("bob", "alice", seq),
1064 condition(cb2),
1066 fee(1500));
1067 env.require(balance("alice", XRP(4000) - drops(100)));
1068 env.require(balance("carol", XRP(6000)));
1069 }
1070 { // Test empty condition during creation and
1071 // empty condition & fulfillment during finish
1072 Env env(*this);
1073 env.fund(XRP(5000), "alice", "bob", "carol");
1074
1075 env(escrow("alice", "carol", XRP(1000)),
1076 condition(Slice{}),
1077 cancel_time(env.now() + 1s),
1078 ter(temMALFORMED));
1079
1080 auto const seq = env.seq("alice");
1081 env(escrow("alice", "carol", XRP(1000)),
1082 condition(cb3),
1083 cancel_time(env.now() + 1s));
1084
1085 env(finish("bob", "alice", seq),
1086 condition(Slice{}),
1087 fulfillment(Slice{}),
1088 fee(1500),
1090 env(finish("bob", "alice", seq),
1091 condition(cb3),
1092 fulfillment(Slice{}),
1093 fee(1500),
1095 env(finish("bob", "alice", seq),
1096 condition(Slice{}),
1098 fee(1500),
1100
1101 // Assemble finish that is missing the Condition or the Fulfillment
1102 // since either both must be present, or neither can:
1103 env(finish("bob", "alice", seq), condition(cb3), ter(temMALFORMED));
1104 env(finish("bob", "alice", seq),
1106 ter(temMALFORMED));
1107
1108 // Now finish it.
1109 env(finish("bob", "alice", seq),
1110 condition(cb3),
1112 fee(1500));
1113 env.require(balance("carol", XRP(6000)));
1114 env.require(balance("alice", XRP(4000) - drops(10)));
1115 }
1116 { // Test a condition other than PreimageSha256, which
1117 // would require a separate amendment
1118 Env env(*this);
1119 env.fund(XRP(5000), "alice", "bob");
1120
1122 {0xA2, 0x2B, 0x80, 0x20, 0x42, 0x4A, 0x70, 0x49, 0x49,
1123 0x52, 0x92, 0x67, 0xB6, 0x21, 0xB3, 0xD7, 0x91, 0x19,
1124 0xD7, 0x29, 0xB2, 0x38, 0x2C, 0xED, 0x8B, 0x29, 0x6C,
1125 0x3C, 0x02, 0x8F, 0xA9, 0x7D, 0x35, 0x0F, 0x6D, 0x07,
1126 0x81, 0x03, 0x06, 0x34, 0xD2, 0x82, 0x02, 0x03, 0xC8}};
1127
1128 // FIXME: this transaction should, eventually, return temDISABLED
1129 // instead of temMALFORMED.
1130 env(escrow("alice", "bob", XRP(1000)),
1131 condition(cb),
1132 cancel_time(env.now() + 1s),
1133 ter(temMALFORMED));
1134 }
1135 }
1136
1137 void
1139 {
1140 using namespace jtx;
1141 using namespace std::chrono;
1142
1143 auto const alice = Account("alice");
1144 auto const bruce = Account("bruce");
1145 auto const carol = Account("carol");
1146
1147 {
1148 testcase("Metadata to self");
1149
1150 Env env(*this);
1151 env.fund(XRP(5000), alice, bruce, carol);
1152 auto const aseq = env.seq(alice);
1153 auto const bseq = env.seq(bruce);
1154
1155 env(escrow(alice, alice, XRP(1000)),
1156 finish_time(env.now() + 1s),
1157 cancel_time(env.now() + 500s));
1158 BEAST_EXPECT(
1159 (*env.meta())[sfTransactionResult] ==
1160 static_cast<std::uint8_t>(tesSUCCESS));
1161 env.close(5s);
1162 auto const aa = env.le(keylet::escrow(alice.id(), aseq));
1163 BEAST_EXPECT(aa);
1164
1165 {
1166 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1167 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1168 BEAST_EXPECT(
1169 std::find(aod.begin(), aod.end(), aa) != aod.end());
1170 }
1171
1172 env(escrow(bruce, bruce, XRP(1000)),
1173 finish_time(env.now() + 1s),
1174 cancel_time(env.now() + 2s));
1175 BEAST_EXPECT(
1176 (*env.meta())[sfTransactionResult] ==
1177 static_cast<std::uint8_t>(tesSUCCESS));
1178 env.close(5s);
1179 auto const bb = env.le(keylet::escrow(bruce.id(), bseq));
1180 BEAST_EXPECT(bb);
1181
1182 {
1183 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1184 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1185 BEAST_EXPECT(
1186 std::find(bod.begin(), bod.end(), bb) != bod.end());
1187 }
1188
1189 env.close(5s);
1190 env(finish(alice, alice, aseq));
1191 {
1192 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1193 BEAST_EXPECT(
1194 (*env.meta())[sfTransactionResult] ==
1195 static_cast<std::uint8_t>(tesSUCCESS));
1196
1197 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1198 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0);
1199 BEAST_EXPECT(
1200 std::find(aod.begin(), aod.end(), aa) == aod.end());
1201
1202 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1203 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1204 BEAST_EXPECT(
1205 std::find(bod.begin(), bod.end(), bb) != bod.end());
1206 }
1207
1208 env.close(5s);
1209 env(cancel(bruce, bruce, bseq));
1210 {
1211 BEAST_EXPECT(!env.le(keylet::escrow(bruce.id(), bseq)));
1212 BEAST_EXPECT(
1213 (*env.meta())[sfTransactionResult] ==
1214 static_cast<std::uint8_t>(tesSUCCESS));
1215
1216 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1217 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 0);
1218 BEAST_EXPECT(
1219 std::find(bod.begin(), bod.end(), bb) == bod.end());
1220 }
1221 }
1222 {
1223 testcase("Metadata to other");
1224
1225 Env env(*this);
1226 env.fund(XRP(5000), alice, bruce, carol);
1227 auto const aseq = env.seq(alice);
1228 auto const bseq = env.seq(bruce);
1229
1230 env(escrow(alice, bruce, XRP(1000)), finish_time(env.now() + 1s));
1231 BEAST_EXPECT(
1232 (*env.meta())[sfTransactionResult] ==
1233 static_cast<std::uint8_t>(tesSUCCESS));
1234 env.close(5s);
1235 env(escrow(bruce, carol, XRP(1000)),
1236 finish_time(env.now() + 1s),
1237 cancel_time(env.now() + 2s));
1238 BEAST_EXPECT(
1239 (*env.meta())[sfTransactionResult] ==
1240 static_cast<std::uint8_t>(tesSUCCESS));
1241 env.close(5s);
1242
1243 auto const ab = env.le(keylet::escrow(alice.id(), aseq));
1244 BEAST_EXPECT(ab);
1245
1246 auto const bc = env.le(keylet::escrow(bruce.id(), bseq));
1247 BEAST_EXPECT(bc);
1248
1249 {
1250 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1251 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 1);
1252 BEAST_EXPECT(
1253 std::find(aod.begin(), aod.end(), ab) != aod.end());
1254
1255 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1256 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 2);
1257 BEAST_EXPECT(
1258 std::find(bod.begin(), bod.end(), ab) != bod.end());
1259 BEAST_EXPECT(
1260 std::find(bod.begin(), bod.end(), bc) != bod.end());
1261
1262 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1263 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
1264 BEAST_EXPECT(
1265 std::find(cod.begin(), cod.end(), bc) != cod.end());
1266 }
1267
1268 env.close(5s);
1269 env(finish(alice, alice, aseq));
1270 {
1271 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1272 BEAST_EXPECT(env.le(keylet::escrow(bruce.id(), bseq)));
1273
1274 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1275 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0);
1276 BEAST_EXPECT(
1277 std::find(aod.begin(), aod.end(), ab) == aod.end());
1278
1279 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1280 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 1);
1281 BEAST_EXPECT(
1282 std::find(bod.begin(), bod.end(), ab) == bod.end());
1283 BEAST_EXPECT(
1284 std::find(bod.begin(), bod.end(), bc) != bod.end());
1285
1286 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1287 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 1);
1288 }
1289
1290 env.close(5s);
1291 env(cancel(bruce, bruce, bseq));
1292 {
1293 BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
1294 BEAST_EXPECT(!env.le(keylet::escrow(bruce.id(), bseq)));
1295
1296 ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
1297 BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0);
1298 BEAST_EXPECT(
1299 std::find(aod.begin(), aod.end(), ab) == aod.end());
1300
1301 ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
1302 BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 0);
1303 BEAST_EXPECT(
1304 std::find(bod.begin(), bod.end(), ab) == bod.end());
1305 BEAST_EXPECT(
1306 std::find(bod.begin(), bod.end(), bc) == bod.end());
1307
1308 ripple::Dir cod(*env.current(), keylet::ownerDir(carol.id()));
1309 BEAST_EXPECT(std::distance(cod.begin(), cod.end()) == 0);
1310 }
1311 }
1312 }
1313
1314 void
1316 {
1317 testcase("Consequences");
1318
1319 using namespace jtx;
1320 using namespace std::chrono;
1321 Env env(*this);
1322
1323 env.memoize("alice");
1324 env.memoize("bob");
1325 env.memoize("carol");
1326
1327 {
1328 auto const jtx = env.jt(
1329 escrow("alice", "carol", XRP(1000)),
1330 finish_time(env.now() + 1s),
1331 seq(1),
1332 fee(10));
1333 auto const pf = preflight(
1334 env.app(),
1335 env.current()->rules(),
1336 *jtx.stx,
1337 tapNONE,
1338 env.journal);
1339 BEAST_EXPECT(pf.ter == tesSUCCESS);
1340 BEAST_EXPECT(!pf.consequences.isBlocker());
1341 BEAST_EXPECT(pf.consequences.fee() == drops(10));
1342 BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(1000));
1343 }
1344
1345 {
1346 auto const jtx = env.jt(cancel("bob", "alice", 3), seq(1), fee(10));
1347 auto const pf = preflight(
1348 env.app(),
1349 env.current()->rules(),
1350 *jtx.stx,
1351 tapNONE,
1352 env.journal);
1353 BEAST_EXPECT(pf.ter == tesSUCCESS);
1354 BEAST_EXPECT(!pf.consequences.isBlocker());
1355 BEAST_EXPECT(pf.consequences.fee() == drops(10));
1356 BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
1357 }
1358
1359 {
1360 auto const jtx = env.jt(finish("bob", "alice", 3), seq(1), fee(10));
1361 auto const pf = preflight(
1362 env.app(),
1363 env.current()->rules(),
1364 *jtx.stx,
1365 tapNONE,
1366 env.journal);
1367 BEAST_EXPECT(pf.ter == tesSUCCESS);
1368 BEAST_EXPECT(!pf.consequences.isBlocker());
1369 BEAST_EXPECT(pf.consequences.fee() == drops(10));
1370 BEAST_EXPECT(pf.consequences.potentialSpend() == XRP(0));
1371 }
1372 }
1373
1374 void
1376 {
1377 testcase("Escrow with tickets");
1378
1379 using namespace jtx;
1380 using namespace std::chrono;
1381 Account const alice{"alice"};
1382 Account const bob{"bob"};
1383
1384 {
1385 // Create escrow and finish using tickets.
1386 Env env(*this);
1387 env.fund(XRP(5000), alice, bob);
1388 env.close();
1389
1390 // alice creates a ticket.
1391 std::uint32_t const aliceTicket{env.seq(alice) + 1};
1392 env(ticket::create(alice, 1));
1393
1394 // bob creates a bunch of tickets because he will be burning
1395 // through them with tec transactions. Just because we can
1396 // we'll use them up starting from largest and going smaller.
1397 constexpr static std::uint32_t bobTicketCount{20};
1398 env(ticket::create(bob, bobTicketCount));
1399 env.close();
1400 std::uint32_t bobTicket{env.seq(bob)};
1401 env.require(tickets(alice, 1));
1402 env.require(tickets(bob, bobTicketCount));
1403
1404 // Note that from here on all transactions use tickets. No account
1405 // root sequences should change.
1406 std::uint32_t const aliceRootSeq{env.seq(alice)};
1407 std::uint32_t const bobRootSeq{env.seq(bob)};
1408
1409 // alice creates an escrow that can be finished in the future
1410 auto const ts = env.now() + 97s;
1411
1412 std::uint32_t const escrowSeq = aliceTicket;
1413 env(escrow(alice, bob, XRP(1000)),
1414 finish_time(ts),
1415 ticket::use(aliceTicket));
1416 BEAST_EXPECT(env.seq(alice) == aliceRootSeq);
1417 env.require(tickets(alice, 0));
1418 env.require(tickets(bob, bobTicketCount));
1419
1420 // Advance the ledger, verifying that the finish won't complete
1421 // prematurely. Note that each tec consumes one of bob's tickets.
1422 for (; env.now() < ts; env.close())
1423 {
1424 env(finish(bob, alice, escrowSeq),
1425 fee(1500),
1426 ticket::use(--bobTicket),
1428 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1429 }
1430
1431 // bob tries to re-use a ticket, which is rejected.
1432 env(finish(bob, alice, escrowSeq),
1433 fee(1500),
1434 ticket::use(bobTicket),
1435 ter(tefNO_TICKET));
1436
1437 // bob uses one of his remaining tickets. Success!
1438 env(finish(bob, alice, escrowSeq),
1439 fee(1500),
1440 ticket::use(--bobTicket));
1441 env.close();
1442 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1443 }
1444
1445 {
1446 // Create escrow and cancel using tickets.
1447 Env env(*this);
1448 env.fund(XRP(5000), alice, bob);
1449 env.close();
1450
1451 // alice creates a ticket.
1452 std::uint32_t const aliceTicket{env.seq(alice) + 1};
1453 env(ticket::create(alice, 1));
1454
1455 // bob creates a bunch of tickets because he will be burning
1456 // through them with tec transactions.
1457 constexpr std::uint32_t bobTicketCount{20};
1458 std::uint32_t bobTicket{env.seq(bob) + 1};
1459 env(ticket::create(bob, bobTicketCount));
1460 env.close();
1461 env.require(tickets(alice, 1));
1462 env.require(tickets(bob, bobTicketCount));
1463
1464 // Note that from here on all transactions use tickets. No account
1465 // root sequences should change.
1466 std::uint32_t const aliceRootSeq{env.seq(alice)};
1467 std::uint32_t const bobRootSeq{env.seq(bob)};
1468
1469 // alice creates an escrow that can be finished in the future.
1470 auto const ts = env.now() + 117s;
1471
1472 std::uint32_t const escrowSeq = aliceTicket;
1473 env(escrow(alice, bob, XRP(1000)),
1474 condition(cb1),
1475 cancel_time(ts),
1476 ticket::use(aliceTicket));
1477 BEAST_EXPECT(env.seq(alice) == aliceRootSeq);
1478 env.require(tickets(alice, 0));
1479 env.require(tickets(bob, bobTicketCount));
1480
1481 // Advance the ledger, verifying that the cancel won't complete
1482 // prematurely.
1483 for (; env.now() < ts; env.close())
1484 {
1485 env(cancel(bob, alice, escrowSeq),
1486 fee(1500),
1487 ticket::use(bobTicket++),
1489 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1490 }
1491
1492 // Verify that a finish won't work anymore.
1493 env(finish(bob, alice, escrowSeq),
1494 condition(cb1),
1496 fee(1500),
1497 ticket::use(bobTicket++),
1499 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1500
1501 // Verify that the cancel succeeds.
1502 env(cancel(bob, alice, escrowSeq),
1503 fee(1500),
1504 ticket::use(bobTicket++));
1505 env.close();
1506 BEAST_EXPECT(env.seq(bob) == bobRootSeq);
1507
1508 // Verify that bob actually consumed his tickets.
1509 env.require(tickets(bob, env.seq(bob) - bobTicket));
1510 }
1511 }
1512
1513 void
1515 {
1516 testcase("Test with credentials");
1517
1518 using namespace jtx;
1519 using namespace std::chrono;
1520
1521 Account const alice{"alice"};
1522 Account const bob{"bob"};
1523 Account const carol{"carol"};
1524 Account const dillon{"dillon "};
1525 Account const zelda{"zelda"};
1526
1527 const char credType[] = "abcde";
1528
1529 {
1530 // Credentials amendment not enabled
1531 Env env(*this, supported_amendments() - featureCredentials);
1532 env.fund(XRP(5000), alice, bob);
1533 env.close();
1534
1535 auto const seq = env.seq(alice);
1536 env(escrow(alice, bob, XRP(1000)), finish_time(env.now() + 1s));
1537 env.close();
1538
1539 env(fset(bob, asfDepositAuth));
1540 env.close();
1541 env(deposit::auth(bob, alice));
1542 env.close();
1543
1544 std::string const credIdx =
1545 "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B"
1546 "E4";
1547 env(finish(bob, alice, seq),
1548 credentials::ids({credIdx}),
1549 ter(temDISABLED));
1550 }
1551
1552 {
1553 Env env(*this);
1554
1555 env.fund(XRP(5000), alice, bob, carol, dillon, zelda);
1556 env.close();
1557
1558 env(credentials::create(carol, zelda, credType));
1559 env.close();
1560 auto const jv =
1561 credentials::ledgerEntry(env, carol, zelda, credType);
1562 std::string const credIdx = jv[jss::result][jss::index].asString();
1563
1564 auto const seq = env.seq(alice);
1565 env(escrow(alice, bob, XRP(1000)), finish_time(env.now() + 50s));
1566 env.close();
1567
1568 // Bob require preauthorization
1569 env(fset(bob, asfDepositAuth));
1570 env.close();
1571
1572 // Fail, credentials not accepted
1573 env(finish(carol, alice, seq),
1574 credentials::ids({credIdx}),
1576
1577 env.close();
1578
1579 env(credentials::accept(carol, zelda, credType));
1580 env.close();
1581
1582 // Fail, credentials doesn’t belong to root account
1583 env(finish(dillon, alice, seq),
1584 credentials::ids({credIdx}),
1586
1587 // Fail, no depositPreauth
1588 env(finish(carol, alice, seq),
1589 credentials::ids({credIdx}),
1591
1592 env(deposit::authCredentials(bob, {{zelda, credType}}));
1593 env.close();
1594
1595 // Success
1596 env.close();
1597 env(finish(carol, alice, seq), credentials::ids({credIdx}));
1598 env.close();
1599 }
1600
1601 {
1602 testcase("Escrow with credentials without depositPreauth");
1603 using namespace std::chrono;
1604
1605 Env env(*this);
1606
1607 env.fund(XRP(5000), alice, bob, carol, dillon, zelda);
1608 env.close();
1609
1610 env(credentials::create(carol, zelda, credType));
1611 env.close();
1612 env(credentials::accept(carol, zelda, credType));
1613 env.close();
1614 auto const jv =
1615 credentials::ledgerEntry(env, carol, zelda, credType);
1616 std::string const credIdx = jv[jss::result][jss::index].asString();
1617
1618 auto const seq = env.seq(alice);
1619 env(escrow(alice, bob, XRP(1000)), finish_time(env.now() + 50s));
1620 // time advance
1621 env.close();
1622 env.close();
1623 env.close();
1624 env.close();
1625 env.close();
1626 env.close();
1627
1628 // Succeed, Bob doesn't require preauthorization
1629 env(finish(carol, alice, seq), credentials::ids({credIdx}));
1630 env.close();
1631
1632 {
1633 const char credType2[] = "fghijk";
1634
1635 env(credentials::create(bob, zelda, credType2));
1636 env.close();
1637 env(credentials::accept(bob, zelda, credType2));
1638 env.close();
1639 auto const credIdxBob =
1641 env, bob, zelda, credType2)[jss::result][jss::index]
1642 .asString();
1643
1644 auto const seq = env.seq(alice);
1645 env(escrow(alice, bob, XRP(1000)), 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(finish(bob, alice, seq), credentials::ids({credIdxBob}));
1656 env.close();
1657 }
1658 }
1659 }
1660
1661 void
1662 run() override
1663 {
1665 testTiming();
1666 testTags();
1668 test1571();
1669 testFails();
1670 testLockup();
1676 }
1677};
1678
1679BEAST_DEFINE_TESTSUITE(Escrow, app, ripple);
1680
1681} // namespace test
1682} // namespace ripple
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:475
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:120
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:212
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:532
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:328
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:117
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition: Env.h:493
NetClock::time_point now()
Returns the current network time.
Definition: Env.h:281
Application & app()
Definition: Env.h:258
beast::Journal const journal
Definition: Env.h:161
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:233
std::shared_ptr< STObject const > meta()
Return metadata for the last JTx.
Definition: Env.cpp:447
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition: Env.cpp:179
void memoize(Account const &account)
Associate AccountID with account.
Definition: Env.cpp:152
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:221
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
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:380
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:365
Json::Value create(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Definition: credentials.cpp:32
Json::Value accept(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Definition: credentials.cpp:50
Json::Value ledgerEntry(jtx::Env &env, jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Definition: credentials.cpp:83
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
Json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
Definition: ticket.cpp:31
Json::Value escrow(AccountID const &account, AccountID const &to, STAmount const &amount)
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
Json::Value cancel(AccountID const &account, Account const &from, std::uint32_t seq)
Json::Value finish(AccountID const &account, AccountID const &from, std::uint32_t seq)
owner_count< ltTICKET > tickets
Match the number of tickets on the account.
Definition: ticket.h:64
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
FeatureBitset supported_amendments()
Definition: Env.h:73
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
constexpr std::uint32_t asfDepositAuth
Definition: TxFlags.h:84
PreflightResult preflight(Application &app, Rules const &rules, STTx const &tx, ApplyFlags flags, beast::Journal j)
Gate a transaction based on static information.
Definition: applySteps.cpp:297
constexpr std::uint32_t asfRequireDest
Definition: TxFlags.h:76
@ tefNO_TICKET
Definition: TER.h:185
@ tecCRYPTOCONDITION_ERROR
Definition: TER.h:299
@ tecNO_DST
Definition: TER.h:277
@ tecUNFUNDED
Definition: TER.h:282
@ tecNO_TARGET
Definition: TER.h:291
@ tecBAD_CREDENTIALS
Definition: TER.h:346
@ tecNO_PERMISSION
Definition: TER.h:292
@ tecDST_TAG_NEEDED
Definition: TER.h:296
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:294
@ tesSUCCESS
Definition: TER.h:242
@ tapNONE
Definition: ApplyView.h:32
constexpr std::uint32_t asfDisallowXRP
Definition: TxFlags.h:78
@ temBAD_AMOUNT
Definition: TER.h:89
@ temMALFORMED
Definition: TER.h:87
@ temBAD_EXPIRATION
Definition: TER.h:91
@ temDISABLED
Definition: TER.h:114
T resize(T... args)
T size(T... args)
std::array< std::uint8_t, 39 > const cb2
Definition: Escrow_test.cpp:51
void run() override
Runs the suite.
std::array< std::uint8_t, 39 > const cb3
Definition: Escrow_test.cpp:61
std::array< std::uint8_t, 7 > const fb2
Definition: Escrow_test.cpp:48
std::array< std::uint8_t, 8 > const fb3
Definition: Escrow_test.cpp:58
std::array< std::uint8_t, 39 > const cb1
Definition: Escrow_test.cpp:41
std::array< std::uint8_t, 4 > const fb1
Definition: Escrow_test.cpp:39
Set the "CancelAfter" time tag on a JTx.
Definition: TestHelpers.h:286
Set the destination tag on a JTx.
Definition: tag.h:32
Set the "FinishAfter" time tag on a JTx.
Definition: TestHelpers.h:268
Set the sequence number on a JTx.
Definition: seq.h:34
Set the source tag on a JTx.
Definition: tag.h:47