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