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