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