rippled
XChain_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2022 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/beast/unit_test/suite.hpp>
21 #include <ripple/protocol/Feature.h>
22 #include <ripple/protocol/Indexes.h>
23 #include <ripple/protocol/Issue.h>
24 #include <ripple/protocol/SField.h>
25 #include <ripple/protocol/STXChainBridge.h>
26 #include <ripple/protocol/Serializer.h>
27 #include <ripple/protocol/TER.h>
28 #include <ripple/protocol/XChainAttestations.h>
29 
30 #include <test/jtx.h>
31 #include <test/jtx/Env.h>
32 #include <test/jtx/attester.h>
33 #include <test/jtx/multisign.h>
34 #include <test/jtx/xchain_bridge.h>
35 
36 #include <functional>
37 #include <limits>
38 #include <optional>
39 #include <random>
40 #include <string>
41 #include <tuple>
42 #include <variant>
43 #include <vector>
44 
45 #include <fstream>
46 #include <iostream>
47 
48 namespace ripple::test {
49 
50 // SEnv class - encapsulate jtx::Env to make it more user-friendly,
51 // for example having APIs that return a *this reference so that calls can be
52 // chained (fluent interface) allowing to create an environment and use it
53 // without encapsulating it in a curly brace block.
54 // ---------------------------------------------------------------------------
55 template <class T>
56 struct SEnv
57 {
59 
61  T& s,
63  FeatureBitset features,
64  std::unique_ptr<Logs> logs = nullptr,
66  : env_(s, std::move(config), features, std::move(logs), thresh)
67  {
68  }
69 
70  SEnv&
72  {
73  env_.close();
74  return *this;
75  }
76 
77  SEnv&
78  enableFeature(uint256 const feature)
79  {
80  env_.enableFeature(feature);
81  return *this;
82  }
83 
84  SEnv&
85  disableFeature(uint256 const feature)
86  {
87  env_.app().config().features.erase(feature);
88  return *this;
89  }
90 
91  template <class Arg, class... Args>
92  SEnv&
93  fund(STAmount const& amount, Arg const& arg, Args const&... args)
94  {
95  env_.fund(amount, arg, args...);
96  return *this;
97  }
98 
99  template <class JsonValue, class... FN>
100  SEnv&
101  tx(JsonValue&& jv, FN const&... fN)
102  {
103  env_(std::forward<JsonValue>(jv), fN...);
104  return *this;
105  }
106 
107  template <class... FN>
108  SEnv&
109  multiTx(jtx::JValueVec&& jvv, FN const&... fN)
110  {
111  for (auto const& jv : jvv)
112  env_(jv, fN...);
113  return *this;
114  }
115 
116  TER
117  ter() const
118  {
119  return env_.ter();
120  }
121 
122  STAmount
124  {
125  return env_.balance(account).value();
126  }
127 
128  STAmount
129  balance(jtx::Account const& account, Issue const& issue) const
130  {
131  return env_.balance(account, issue).value();
132  }
133 
134  XRPAmount
136  {
137  return env_.current()->fees().accountReserve(count);
138  }
139 
140  XRPAmount
142  {
143  return env_.current()->fees().base;
144  }
145 
148  {
149  return env_.le(account);
150  }
151 
153  bridge(Json::Value const& jvb)
154  {
155  STXChainBridge b(jvb);
156 
157  auto tryGet =
159  if (auto r = env_.le(keylet::bridge(b, ct)))
160  {
161  if ((*r)[sfXChainBridge] == b)
162  return r;
163  }
164  return nullptr;
165  };
166  if (auto r = tryGet(STXChainBridge::ChainType::locking))
167  return r;
168  return tryGet(STXChainBridge::ChainType::issuing);
169  }
170 
173  {
174  return (*bridge(jvb))[sfXChainAccountClaimCount];
175  }
176 
178  claimID(Json::Value const& jvb)
179  {
180  return (*bridge(jvb))[sfXChainClaimID];
181  }
182 
185  {
187  }
188 
191  {
192  return env_.le(
194  }
195 };
196 
197 // XEnv class used for XChain tests. The only difference with SEnv<T> is that it
198 // funds some default accounts, and that it enables `supported_amendments() |
199 // FeatureBitset{featureXChainBridge}` by default.
200 // -----------------------------------------------------------------------------
201 template <class T>
202 struct XEnv : public jtx::XChainBridgeObjects, public SEnv<T>
203 {
204  XEnv(T& s, bool side = false)
205  : SEnv<T>(
206  s,
207  jtx::envconfig(jtx::port_increment, side ? 3 : 0),
208  features)
209  {
210  using namespace jtx;
211  STAmount xrp_funds{XRP(10000)};
212 
213  if (!side)
214  {
215  this->fund(xrp_funds, mcDoor, mcAlice, mcBob, mcCarol, mcGw);
216 
217  // Signer's list must match the attestation signers
218  // env_(jtx::signers(mcDoor, quorum, signers));
219  for (auto& s : signers)
220  this->fund(xrp_funds, s.account);
221  }
222  else
223  {
224  this->fund(
225  xrp_funds,
226  scDoor,
227  scAlice,
228  scBob,
229  scCarol,
230  scGw,
231  scAttester,
232  scReward);
233 
234  for (auto& ra : payees)
235  this->fund(xrp_funds, ra);
236 
237  for (auto& s : signers)
238  this->fund(xrp_funds, s.account);
239 
240  // Signer's list must match the attestation signers
241  // env_(jtx::signers(Account::master, quorum, signers));
242  }
243  this->close();
244  }
245 };
246 
247 // Tracks the xrp balance for one account
248 template <class T>
249 struct Balance
250 {
252  T& env_;
254 
255  Balance(T& env, jtx::Account const& account) : account_(account), env_(env)
256  {
257  startAmount = env_.balance(account_);
258  }
259 
260  STAmount
261  diff() const
262  {
263  return env_.balance(account_) - startAmount;
264  }
265 };
266 
267 // Tracks the xrp balance for multiple accounts involved in a crosss-chain
268 // transfer
269 template <class T>
271 {
273 
276  balance payor_; // pays the rewards
277  std::vector<balance> reward_accounts; // receives the reward
279 
281  T& env,
282  jtx::Account const& from_acct,
283  jtx::Account const& to_acct,
284  jtx::Account const& payor,
285  jtx::Account const* payees,
286  size_t num_payees,
287  bool withClaim)
288  : from_(env, from_acct)
289  , to_(env, to_acct)
290  , payor_(env, payor)
291  , reward_accounts([&]() {
293  r.reserve(num_payees);
294  for (size_t i = 0; i < num_payees; ++i)
295  r.emplace_back(env, payees[i]);
296  return r;
297  }())
298  , txFees_(withClaim ? env.env_.current()->fees().base : XRPAmount(0))
299  {
300  }
301 
303  T& env,
304  jtx::Account const& from_acct,
305  jtx::Account const& to_acct,
306  jtx::Account const& payor,
308  bool withClaim)
309  : BalanceTransfer(
310  env,
311  from_acct,
312  to_acct,
313  payor,
314  &payees[0],
315  payees.size(),
316  withClaim)
317  {
318  }
319 
320  bool
322  {
323  return std::all_of(
324  reward_accounts.begin(),
325  reward_accounts.end(),
326  [&](const balance& b) { return b.diff() == reward; });
327  }
328 
329  bool
331  {
332  return from_.diff() == -amt && to_.diff() == amt &&
333  payees_received(reward);
334  }
335 
336  bool
338  STAmount const& amt,
339  STAmount const& reward,
340  bool check_payer = true)
341  {
342  auto reward_cost =
343  multiply(reward, STAmount(reward_accounts.size()), reward.issue());
344  return check_most_balances(amt, reward) &&
345  (!check_payer || payor_.diff() == -(reward_cost + txFees_));
346  }
347 
348  bool
350  {
351  return check_most_balances(STAmount(0), STAmount(0)) &&
352  payor_.diff() <= txFees_; // could have paid fee for failed claim
353  }
354 };
355 
356 struct BridgeDef
357 {
364  uint32_t quorum;
367 
368  template <class ENV>
369  void
370  initBridge(ENV& mcEnv, ENV& scEnv)
371  {
372  jvb = bridge(doorA, issueA, doorB, issueB);
373 
374  auto const optAccountCreate = [&]() -> std::optional<STAmount> {
375  if (issueA != xrpIssue() || issueB != xrpIssue())
376  return {};
377  return minAccountCreate;
378  }();
379  mcEnv.tx(bridge_create(doorA, jvb, reward, optAccountCreate))
380  .tx(jtx::signers(doorA, quorum, signers))
381  .close();
382 
383  scEnv.tx(bridge_create(doorB, jvb, reward, optAccountCreate))
384  .tx(jtx::signers(doorB, quorum, signers))
385  .close();
386  }
387 };
388 
389 struct XChain_test : public beast::unit_test::suite,
391 {
392  XRPAmount
394  {
395  return XEnv(*this).env_.current()->fees().accountReserve(count);
396  }
397 
398  XRPAmount
400  {
401  return XEnv(*this).env_.current()->fees().base;
402  }
403 
404  void
406  {
407  auto jBridge = create_bridge(mcDoor)[sfXChainBridge.jsonName];
408  bool exceptionPresent = false;
409  try
410  {
411  exceptionPresent = false;
412  [[maybe_unused]] STXChainBridge testBridge1(jBridge);
413  }
414  catch (std::exception& ec)
415  {
416  exceptionPresent = true;
417  }
418 
419  BEAST_EXPECT(!exceptionPresent);
420 
421  try
422  {
423  exceptionPresent = false;
424  jBridge["Extra"] = 1;
425  [[maybe_unused]] STXChainBridge testBridge2(jBridge);
426  }
427  catch ([[maybe_unused]] std::exception& ec)
428  {
429  exceptionPresent = true;
430  }
431 
432  BEAST_EXPECT(exceptionPresent);
433  }
434 
435  void
437  {
438  XRPAmount res1 = reserve(1);
439 
440  using namespace jtx;
441  testcase("Create Bridge");
442 
443  // Normal create_bridge => should succeed
444  XEnv(*this).tx(create_bridge(mcDoor)).close();
445 
446  // Bridge not owned by one of the door account.
447  XEnv(*this).tx(
449 
450  // Create twice on the same account
451  XEnv(*this)
452  .tx(create_bridge(mcDoor))
453  .close()
455 
456  // Create USD bridge Alice -> Bob ... should succeed
457  XEnv(*this).tx(
459  mcAlice, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"])),
460  ter(tesSUCCESS));
461 
462  // Create USD bridge, Alice is both the locking door and locking issue,
463  // ... should fail.
464  XEnv(*this).tx(
466  mcAlice, bridge(mcAlice, mcAlice["USD"], mcBob, mcBob["USD"])),
468 
469  // Bridge where the two door accounts are equal.
470  XEnv(*this).tx(
472  mcBob, bridge(mcBob, mcGw["USD"], mcBob, mcGw["USD"])),
474 
475  // Both door accounts are on the same chain. This is not allowed.
476  // Although it doesn't violate any invariants, it's not a useful thing
477  // to do and it complicates the "add claim" transactions.
478  XEnv(*this)
479  .tx(create_bridge(
480  mcAlice, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"])))
481  .close()
482  .tx(create_bridge(
483  mcBob, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"])),
484  ter(tecDUPLICATE))
485  .close();
486 
487  // Create a bridge on an account with exactly enough balance to
488  // meet the new reserve should succeed
489  XEnv(*this)
490  .fund(res1, mcuDoor) // exact reserve for account + 1 object
491  .close()
493 
494  // Create a bridge on an account with no enough balance to meet the
495  // new reserve
496  XEnv(*this)
497  .fund(res1 - 1, mcuDoor) // just short of required reserve
498  .close()
500 
501  // Reward amount is non-xrp
502  XEnv(*this).tx(
505 
506  // Reward amount is XRP and negative
507  XEnv(*this).tx(
508  create_bridge(mcDoor, jvb, XRP(-1)),
510 
511  // Reward amount is 1 xrp => should succeed
512  XEnv(*this).tx(create_bridge(mcDoor, jvb, XRP(1)), ter(tesSUCCESS));
513 
514  // Min create amount is 1 xrp, mincreate is 1 xrp => should succeed
515  XEnv(*this).tx(
517 
518  // Min create amount is non-xrp
519  XEnv(*this).tx(
520  create_bridge(mcDoor, jvb, XRP(1), mcUSD(100)),
522 
523  // Min create amount is zero (should fail, currently succeeds)
524  XEnv(*this).tx(
525  create_bridge(mcDoor, jvb, XRP(1), XRP(0)),
527 
528  // Min create amount is negative
529  XEnv(*this).tx(
530  create_bridge(mcDoor, jvb, XRP(1), XRP(-1)),
532 
533  // coverage test: BridgeCreate::preflight() - create bridge when feature
534  // disabled.
535  {
538  }
539 
540  // coverage test: BridgeCreate::preclaim() returns tecNO_ISSUER.
541  XEnv(*this).tx(
543  mcAlice, bridge(mcAlice, mcuAlice["USD"], mcBob, mcBob["USD"])),
544  ter(tecNO_ISSUER));
545 
546  // coverage test: create_bridge transaction with incorrect flag
547  XEnv(*this).tx(
551 
552  // coverage test: create_bridge transaction with xchain feature disabled
553  XEnv(*this)
554  .disableFeature(featureXChainBridge)
556  }
557 
558  void
560  {
606  using namespace jtx;
607  testcase("Bridge create constraints");
608  XEnv env(*this, true);
609  auto& A = scAlice;
610  auto& B = scBob;
611  auto& C = scCarol;
612  auto AUSD = A["USD"];
613  auto BUSD = B["USD"];
614  auto CUSD = C["USD"];
615  auto GUSD = scGw["USD"];
616  auto AEUR = A["EUR"];
617  auto BEUR = B["EUR"];
618  auto CEUR = C["EUR"];
619  auto GEUR = scGw["EUR"];
620 
621  // Accounts to own single brdiges
622  Account const a1("a1");
623  Account const a2("a2");
624  Account const a3("a3");
625  Account const a4("a4");
626  Account const a5("a5");
627  Account const a6("a6");
628 
629  env.fund(XRP(10000), a1, a2, a3, a4, a5, a6);
630  env.close();
631 
632  // Add a bridge on two different accounts with the same locking and
633  // issuing assets
634  env.tx(create_bridge(a1, bridge(a1, GUSD, B, BUSD))).close();
635  env.tx(create_bridge(a2, bridge(a2, GUSD, B, BUSD))).close();
636 
637  // Add the exact same bridge to two different accounts (one locking
638  // account and one issuing)
639  env.tx(create_bridge(a3, bridge(a3, GUSD, a4, a4["USD"]))).close();
640  env.tx(create_bridge(a4, bridge(a3, GUSD, a4, a4["USD"])),
641  ter(tecDUPLICATE))
642  .close();
643 
644  // Add the exact same bridge to two different accounts (one issuing
645  // account and one locking - opposite order from the test above)
646  env.tx(create_bridge(a5, bridge(a6, GUSD, a5, a5["USD"]))).close();
647  env.tx(create_bridge(a6, bridge(a6, GUSD, a5, a5["USD"])),
648  ter(tecDUPLICATE))
649  .close();
650 
651  // Test case 1 ~ 5, create bridges
652  auto const goodBridge1 = bridge(A, GUSD, B, BUSD);
653  auto const goodBridge2 = bridge(A, BUSD, C, CUSD);
654  env.tx(create_bridge(B, goodBridge1)).close();
655  // Issuing asset is the same, this is a duplicate
656  env.tx(create_bridge(B, bridge(A, GEUR, B, BUSD)), ter(tecDUPLICATE))
657  .close();
658  env.tx(create_bridge(A, goodBridge2), ter(tesSUCCESS)).close();
659  // Locking asset is the same - this is a duplicate
660  env.tx(create_bridge(A, bridge(A, BUSD, B, BEUR)), ter(tecDUPLICATE))
661  .close();
662  // Locking asset is USD - this is a duplicate even tho it has a
663  // different issuer
664  env.tx(create_bridge(A, bridge(A, CUSD, B, BEUR)), ter(tecDUPLICATE))
665  .close();
666 
667  // Test case 6 and 7, commits
668  env.tx(trust(C, BUSD(1000)))
669  .tx(trust(A, BUSD(1000)))
670  .close()
671  .tx(pay(B, C, BUSD(1000)))
672  .close();
673  auto const aBalanceStart = env.balance(A, BUSD);
674  auto const cBalanceStart = env.balance(C, BUSD);
675  env.tx(xchain_commit(C, goodBridge1, 1, BUSD(50))).close();
676  BEAST_EXPECT(env.balance(A, BUSD) - aBalanceStart == BUSD(0));
677  BEAST_EXPECT(env.balance(C, BUSD) - cBalanceStart == BUSD(-50));
678  env.tx(xchain_commit(C, goodBridge2, 1, BUSD(60))).close();
679  BEAST_EXPECT(env.balance(A, BUSD) - aBalanceStart == BUSD(60));
680  BEAST_EXPECT(env.balance(C, BUSD) - cBalanceStart == BUSD(-50 - 60));
681 
682  // bridge modify test cases
683  env.tx(bridge_modify(B, goodBridge1, XRP(33), std::nullopt)).close();
684  BEAST_EXPECT((*env.bridge(goodBridge1))[sfSignatureReward] == XRP(33));
685  env.tx(bridge_modify(A, goodBridge2, XRP(44), std::nullopt)).close();
686  BEAST_EXPECT((*env.bridge(goodBridge2))[sfSignatureReward] == XRP(44));
687  }
688 
689  void
691  {
692  using namespace jtx;
693  testcase("Create Bridge Matrix");
694 
695  // Test all combinations of the following:`
696  // --------------------------------------
697  // - Locking chain is IOU with locking chain door account as issuer
698  // - Locking chain is IOU with issuing chain door account that
699  // exists on the locking chain as issuer
700  // - Locking chain is IOU with issuing chain door account that does
701  // not exists on the locking chain as issuer
702  // - Locking chain is IOU with non-door account (that exists on the
703  // locking chain ledger) as issuer
704  // - Locking chain is IOU with non-door account (that does not exist
705  // exists on the locking chain ledger) as issuer
706  // - Locking chain is XRP
707  // ---------------------------------------------------------------------
708  // - Issuing chain is IOU with issuing chain door account as the
709  // issuer
710  // - Issuing chain is IOU with locking chain door account (that
711  // exists on the issuing chain ledger) as the issuer
712  // - Issuing chain is IOU with locking chain door account (that does
713  // not exist on the issuing chain ledger) as the issuer
714  // - Issuing chain is IOU with non-door account (that exists on the
715  // issuing chain ledger) as the issuer
716  // - Issuing chain is IOU with non-door account (that does not
717  // exists on the issuing chain ledger) as the issuer
718  // - Issuing chain is XRP and issuing chain door account is not the
719  // root account
720  // - Issuing chain is XRP and issuing chain door account is the root
721  // account
722  // ---------------------------------------------------------------------
723  // That's 42 combinations. The only combinations that should succeed
724  // are:
725  // - Locking chain is any IOU,
726  // - Issuing chain is IOU with issuing chain door account as the
727  // issuer
728  // Locking chain is XRP,
729  // - Issuing chain is XRP with issuing chain is the root account.
730  // ---------------------------------------------------------------------
731  Account a, b;
732  Issue ia, ib;
733 
734  std::tuple lcs{
736  "Locking chain is IOU(locking chain door)",
737  [&](auto& env, bool) {
738  a = mcDoor;
739  ia = mcDoor["USD"];
740  }),
742  "Locking chain is IOU(issuing chain door funded on locking "
743  "chain)",
744  [&](auto& env, bool shouldFund) {
745  a = mcDoor;
746  ia = scDoor["USD"];
747  if (shouldFund)
748  env.fund(XRP(10000), scDoor);
749  }),
751  "Locking chain is IOU(issuing chain door account unfunded "
752  "on locking chain)",
753  [&](auto& env, bool) {
754  a = mcDoor;
755  ia = scDoor["USD"];
756  }),
758  "Locking chain is IOU(bob funded on locking chain)",
759  [&](auto& env, bool) {
760  a = mcDoor;
761  ia = mcGw["USD"];
762  }),
764  "Locking chain is IOU(bob unfunded on locking chain)",
765  [&](auto& env, bool) {
766  a = mcDoor;
767  ia = mcuGw["USD"];
768  }),
769  std::make_pair("Locking chain is XRP", [&](auto& env, bool) {
770  a = mcDoor;
771  ia = xrpIssue();
772  })};
773 
774  std::tuple ics{
776  "Issuing chain is IOU(issuing chain door account)",
777  [&](auto& env, bool) {
778  b = scDoor;
779  ib = scDoor["USD"];
780  }),
782  "Issuing chain is IOU(locking chain door funded on issuing "
783  "chain)",
784  [&](auto& env, bool shouldFund) {
785  b = scDoor;
786  ib = mcDoor["USD"];
787  if (shouldFund)
788  env.fund(XRP(10000), mcDoor);
789  }),
791  "Issuing chain is IOU(locking chain door unfunded on "
792  "issuing chain)",
793  [&](auto& env, bool) {
794  b = scDoor;
795  ib = mcDoor["USD"];
796  }),
798  "Issuing chain is IOU(bob funded on issuing chain)",
799  [&](auto& env, bool) {
800  b = scDoor;
801  ib = mcGw["USD"];
802  }),
804  "Issuing chain is IOU(bob unfunded on issuing chain)",
805  [&](auto& env, bool) {
806  b = scDoor;
807  ib = mcuGw["USD"];
808  }),
810  "Issuing chain is XRP and issuing chain door account is "
811  "not the root account",
812  [&](auto& env, bool) {
813  b = scDoor;
814  ib = xrpIssue();
815  }),
817  "Issuing chain is XRP and issuing chain door account is "
818  "the root account ",
819  [&](auto& env, bool) {
820  b = Account::master;
821  ib = xrpIssue();
822  })};
823 
824  std::vector<std::pair<int, int>> expected_result{
867 
869 
870  auto testcase = [&](auto const& lc, auto const& ic) {
871  XEnv mcEnv(*this);
872  XEnv scEnv(*this, true);
873 
874  lc.second(mcEnv, true);
875  lc.second(scEnv, false);
876 
877  ic.second(mcEnv, false);
878  ic.second(scEnv, true);
879 
880  auto const& expected = expected_result[test_result.size()];
881 
882  mcEnv.tx(
883  create_bridge(a, bridge(a, ia, b, ib)),
884  ter(TER::fromInt(expected.first)));
885  TER mcTER = mcEnv.env_.ter();
886 
887  scEnv.tx(
888  create_bridge(b, bridge(a, ia, b, ib)),
889  ter(TER::fromInt(expected.second)));
890  TER scTER = scEnv.env_.ter();
891 
892  bool pass = mcTER == tesSUCCESS && scTER == tesSUCCESS;
893 
894  test_result.emplace_back(mcTER, scTER, pass);
895  };
896 
897  auto apply_ics = [&](auto const& lc, auto const& ics) {
898  std::apply(
899  [&](auto const&... ic) { (testcase(lc, ic), ...); }, ics);
900  };
901 
902  std::apply([&](auto const&... lc) { (apply_ics(lc, ics), ...); }, lcs);
903 
904 #if GENERATE_MTX_OUTPUT
905  // optional output of matrix results in markdown format
906  // ----------------------------------------------------
907  std::string fname{std::tmpnam(nullptr)};
908  fname += ".md";
909  std::cout << "Markdown output for matrix test: " << fname << "\n";
910 
911  auto print_res = [](auto tup) -> std::string {
912  std::string status = std::string(transToken(std::get<0>(tup))) +
913  " / " + transToken(std::get<1>(tup));
914 
915  if (std::get<2>(tup))
916  return status;
917  else
918  {
919  // red
920  return std::string("`") + status + "`";
921  }
922  };
923 
924  auto output_table = [&](auto print_res) {
925  size_t test_idx = 0;
926  std::string res;
927  res.reserve(10000); // should be enough :-)
928 
929  // first two header lines
930  res += "| `issuing ->` | ";
931  std::apply(
932  [&](auto const&... ic) {
933  ((res += ic.first, res += " | "), ...);
934  },
935  ics);
936  res += "\n";
937 
938  res += "| :--- | ";
939  std::apply(
940  [&](auto const&... ic) {
941  (((void)ic.first, res += ":---: | "), ...);
942  },
943  ics);
944  res += "\n";
945 
946  auto output = [&](auto const& lc, auto const& ic) {
947  res += print_res(test_result[test_idx]);
948  res += " | ";
949  ++test_idx;
950  };
951 
952  auto output_ics = [&](auto const& lc, auto const& ics) {
953  res += "| ";
954  res += lc.first;
955  res += " | ";
956  std::apply(
957  [&](auto const&... ic) { (output(lc, ic), ...); }, ics);
958  res += "\n";
959  };
960 
961  std::apply(
962  [&](auto const&... lc) { (output_ics(lc, ics), ...); }, lcs);
963 
964  return res;
965  };
966 
967  std::ofstream(fname) << output_table(print_res);
968 
969  std::string ter_fname{std::tmpnam(nullptr)};
970  std::cout << "ter output for matrix test: " << ter_fname << "\n";
971 
972  std::ofstream ofs(ter_fname);
973  for (auto& t : test_result)
974  {
975  ofs << "{ " << std::string(transToken(std::get<0>(t))) << ", "
976  << std::string(transToken(std::get<1>(t))) << "}\n,";
977  }
978 #endif
979  }
980 
981  void
983  {
984  using namespace jtx;
985  testcase("Modify Bridge");
986 
987  // Changing a non-existent bridge should fail
988  XEnv(*this).tx(
990  mcAlice,
991  bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"]),
992  XRP(2),
993  std::nullopt),
994  ter(tecNO_ENTRY));
995 
996  // must change something
997  // XEnv(*this)
998  // .tx(create_bridge(mcDoor, jvb, XRP(1), XRP(1)))
999  // .tx(bridge_modify(mcDoor, jvb, XRP(1), XRP(1)),
1000  // ter(temMALFORMED));
1001 
1002  // must change something
1003  XEnv(*this)
1004  .tx(create_bridge(mcDoor, jvb, XRP(1), XRP(1)))
1005  .close()
1006  .tx(bridge_modify(mcDoor, jvb, {}, {}), ter(temMALFORMED));
1007 
1008  // Reward amount is non-xrp
1009  XEnv(*this).tx(
1010  bridge_modify(mcDoor, jvb, mcUSD(2), XRP(10)),
1012 
1013  // Reward amount is XRP and negative
1014  XEnv(*this).tx(
1015  bridge_modify(mcDoor, jvb, XRP(-2), XRP(10)),
1017 
1018  // Min create amount is non-xrp
1019  XEnv(*this).tx(
1020  bridge_modify(mcDoor, jvb, XRP(2), mcUSD(10)),
1022 
1023  // Min create amount is zero
1024  XEnv(*this).tx(
1025  bridge_modify(mcDoor, jvb, XRP(2), XRP(0)),
1027 
1028  // Min create amount is negative
1029  XEnv(*this).tx(
1030  bridge_modify(mcDoor, jvb, XRP(2), XRP(-10)),
1032 
1033  // First check the regular claim process (without bridge_modify)
1034  for (auto withClaim : {false, true})
1035  {
1036  XEnv mcEnv(*this);
1037  XEnv scEnv(*this, true);
1038 
1039  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
1040 
1043  .close()
1045  .close();
1046 
1047  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
1048  auto const amt = XRP(1000);
1049  std::uint32_t const claimID = 1;
1050  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
1051 
1052  BalanceTransfer transfer(
1053  scEnv,
1055  scBob,
1056  scAlice,
1057  &payees[0],
1059  withClaim);
1060 
1061  scEnv
1063  scAttester,
1064  jvb,
1065  mcAlice,
1066  amt,
1067  payees,
1068  true,
1069  claimID,
1070  dst,
1071  signers))
1072  .close();
1073 
1074  if (withClaim)
1075  {
1076  BEAST_EXPECT(transfer.has_not_happened());
1077 
1078  // need to submit a claim transactions
1079  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob))
1080  .close();
1081  }
1082 
1083  BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum));
1084  }
1085 
1086  // Check that the reward paid from a claim Id was the reward when
1087  // the claim id was created, not the reward since the bridge was
1088  // modified.
1089  for (auto withClaim : {false, true})
1090  {
1091  XEnv mcEnv(*this);
1092  XEnv scEnv(*this, true);
1093 
1094  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
1095 
1098  .close()
1100  .close();
1101 
1102  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
1103  auto const amt = XRP(1000);
1104  std::uint32_t const claimID = 1;
1105  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
1106 
1107  // Now modify the reward on the bridge
1108  mcEnv.tx(bridge_modify(mcDoor, jvb, XRP(2), XRP(10))).close();
1109  scEnv.tx(bridge_modify(Account::master, jvb, XRP(2), XRP(10)))
1110  .close();
1111 
1112  BalanceTransfer transfer(
1113  scEnv,
1115  scBob,
1116  scAlice,
1117  &payees[0],
1119  withClaim);
1120 
1121  scEnv
1123  scAttester,
1124  jvb,
1125  mcAlice,
1126  amt,
1127  payees,
1128  true,
1129  claimID,
1130  dst,
1131  signers))
1132  .close();
1133 
1134  if (withClaim)
1135  {
1136  BEAST_EXPECT(transfer.has_not_happened());
1137 
1138  // need to submit a claim transactions
1139  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob))
1140  .close();
1141  }
1142 
1143  // make sure the reward accounts indeed received the original
1144  // split reward (1 split 5 ways) instead of the updated 2 XRP.
1145  BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum));
1146  }
1147 
1148  // Check that the signatures used to verify attestations and decide
1149  // if there is a quorum are the current signer's list on the door
1150  // account, not the signer's list that was in effect when the claim
1151  // id was created.
1152  for (auto withClaim : {false, true})
1153  {
1154  XEnv mcEnv(*this);
1155  XEnv scEnv(*this, true);
1156 
1157  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
1158 
1161  .close()
1163  .close();
1164 
1165  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
1166  auto const amt = XRP(1000);
1167  std::uint32_t const claimID = 1;
1168  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
1169 
1170  // change signers - claim should not be processed is the batch
1171  // is signed by original signers
1173  .close();
1174 
1175  BalanceTransfer transfer(
1176  scEnv,
1178  scBob,
1179  scAlice,
1180  &payees[0],
1182  withClaim);
1183 
1184  // submit claim using outdated signers - should fail
1185  scEnv
1186  .multiTx(
1188  scAttester,
1189  jvb,
1190  mcAlice,
1191  amt,
1192  payees,
1193  true,
1194  claimID,
1195  dst,
1196  signers),
1198  .close();
1199  if (withClaim)
1200  {
1201  // need to submit a claim transactions
1202  scEnv
1203  .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob),
1205  .close();
1206  }
1207 
1208  // make sure transfer has not happened as we sent attestations
1209  // using outdated signers
1210  BEAST_EXPECT(transfer.has_not_happened());
1211 
1212  // submit claim using current signers - should succeed
1213  scEnv
1215  scAttester,
1216  jvb,
1217  mcAlice,
1218  amt,
1219  payees,
1220  true,
1221  claimID,
1222  dst,
1223  alt_signers))
1224  .close();
1225  if (withClaim)
1226  {
1227  BEAST_EXPECT(transfer.has_not_happened());
1228 
1229  // need to submit a claim transactions
1230  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob))
1231  .close();
1232  }
1233 
1234  // make sure the transfer went through as we sent attestations
1235  // using new signers
1236  BEAST_EXPECT(
1237  transfer.has_happened(amt, split_reward_quorum, false));
1238  }
1239 
1240  // coverage test: bridge_modify transaction with incorrect flag
1241  XEnv(*this)
1242  .tx(create_bridge(mcDoor, jvb))
1243  .close()
1244  .tx(bridge_modify(mcDoor, jvb, XRP(1), XRP(2)),
1246  ter(temINVALID_FLAG));
1247 
1248  // coverage test: bridge_modify transaction with xchain feature
1249  // disabled
1250  XEnv(*this)
1251  .tx(create_bridge(mcDoor, jvb))
1252  .disableFeature(featureXChainBridge)
1253  .close()
1254  .tx(bridge_modify(mcDoor, jvb, XRP(1), XRP(2)), ter(temDISABLED));
1255 
1256  // coverage test: bridge_modify return temSIDECHAIN_NONDOOR_OWNER;
1257  XEnv(*this)
1258  .tx(create_bridge(mcDoor, jvb))
1259  .close()
1260  .tx(bridge_modify(mcAlice, jvb, XRP(1), XRP(2)),
1262 
1269  XEnv(*this)
1270  .tx(create_bridge(mcDoor, jvb, XRP(1), XRP(20)))
1271  .close()
1273  mcAlice, jvb, scuAlice, XRP(100), reward))
1274  .close()
1275  .tx(bridge_modify(mcDoor, jvb, {}, XRP(2)),
1277  ter(temMALFORMED))
1278  .close()
1279  .tx(bridge_modify(mcDoor, jvb, XRP(3), {}),
1281  .close()
1283  mcAlice, jvb, scuBob, XRP(100), XRP(3)),
1285  .close();
1286  }
1287 
1288  void
1290  {
1291  using namespace jtx;
1292  XRPAmount res1 = reserve(1);
1293  XRPAmount tx_fee = txFee();
1294 
1295  testcase("Create ClaimID");
1296 
1297  // normal bridge create for sanity check with the exact necessary
1298  // account balance
1299  XEnv(*this, true)
1301  .fund(res1, scuAlice) // acct reserve + 1 object
1302  .close()
1304  .close();
1305 
1306  // check reward not deducted when claim id is created
1307  {
1308  XEnv xenv(*this, true);
1309 
1310  Balance scAlice_bal(xenv, scAlice);
1311 
1314  .close();
1315 
1316  BEAST_EXPECT(scAlice_bal.diff() == -tx_fee);
1317  }
1318 
1319  // Non-existent bridge
1320  XEnv(*this, true)
1322  scAlice,
1323  bridge(mcAlice, mcAlice["USD"], scBob, scBob["USD"]),
1324  reward,
1325  mcAlice),
1326  ter(tecNO_ENTRY))
1327  .close();
1328 
1329  // Creating the new object would put the account below the reserve
1330  XEnv(*this, true)
1332  .fund(res1 - xrp_dust, scuAlice) // barely not enough
1333  .close()
1336  .close();
1337 
1338  // The specified reward doesn't match the reward on the bridge (test
1339  // by giving the reward amount for the other side, as well as a
1340  // completely non-matching reward)
1341  XEnv(*this, true)
1343  .close()
1347  .close();
1348 
1349  // A reward amount that isn't XRP
1350  XEnv(*this, true)
1352  .close()
1355  .close();
1356 
1357  // coverage test: xchain_create_claim_id transaction with incorrect
1358  // flag
1359  XEnv(*this, true)
1361  .close()
1365  .close();
1366 
1367  // coverage test: xchain_create_claim_id transaction with xchain
1368  // feature disabled
1369  XEnv(*this, true)
1371  .disableFeature(featureXChainBridge)
1372  .close()
1374  ter(temDISABLED))
1375  .close();
1376  }
1377 
1378  void
1380  {
1381  using namespace jtx;
1382  XRPAmount res0 = reserve(0);
1383  XRPAmount tx_fee = txFee();
1384 
1385  testcase("Commit");
1386 
1387  // Commit to a non-existent bridge
1388  XEnv(*this).tx(
1390 
1391  // check that reward not deducted when doing the commit
1392  {
1393  XEnv xenv(*this);
1394 
1395  Balance alice_bal(xenv, mcAlice);
1396  auto const amt = XRP(1000);
1397 
1398  xenv.tx(create_bridge(mcDoor, jvb))
1399  .close()
1400  .tx(xchain_commit(mcAlice, jvb, 1, amt, scBob))
1401  .close();
1402 
1403  STAmount claim_cost = amt;
1404  BEAST_EXPECT(alice_bal.diff() == -(claim_cost + tx_fee));
1405  }
1406 
1407  // Commit a negative amount
1408  XEnv(*this)
1409  .tx(create_bridge(mcDoor, jvb))
1410  .close()
1411  .tx(xchain_commit(mcAlice, jvb, 1, XRP(-1), scBob),
1412  ter(temBAD_AMOUNT));
1413 
1414  // Commit an amount whose issue that does not match the expected
1415  // issue on the bridge (either LockingChainIssue or
1416  // IssuingChainIssue, depending on the chain).
1417  XEnv(*this)
1418  .tx(create_bridge(mcDoor, jvb))
1419  .close()
1420  .tx(xchain_commit(mcAlice, jvb, 1, mcUSD(100), scBob),
1421  ter(temBAD_ISSUER));
1422 
1423  // Commit an amount that would put the sender below the required
1424  // reserve (if XRP)
1425  XEnv(*this)
1426  .tx(create_bridge(mcDoor, jvb))
1427  .fund(res0 + one_xrp - xrp_dust, mcuAlice) // barely not enough
1428  .close()
1429  .tx(xchain_commit(mcuAlice, jvb, 1, one_xrp, scBob),
1431 
1432  XEnv(*this)
1433  .tx(create_bridge(mcDoor, jvb))
1434  .fund(
1435  res0 + one_xrp + xrp_dust, // "xrp_dust" for tx fees
1436  mcuAlice) // exactly enough => should succeed
1437  .close()
1438  .tx(xchain_commit(mcuAlice, jvb, 1, one_xrp, scBob));
1439 
1440  // Commit an amount above the account's balance (for both XRP and
1441  // IOUs)
1442  XEnv(*this)
1443  .tx(create_bridge(mcDoor, jvb))
1444  .fund(res0, mcuAlice) // barely not enough
1445  .close()
1446  .tx(xchain_commit(mcuAlice, jvb, 1, res0 + one_xrp, scBob),
1448 
1449  auto jvb_USD = bridge(mcDoor, mcUSD, scGw, scUSD);
1450 
1451  // commit sent from iou issuer (mcGw) succeeds - should it?
1452  XEnv(*this)
1453  .tx(trust(mcDoor, mcUSD(10000))) // door needs to have a trustline
1454  .tx(create_bridge(mcDoor, jvb_USD))
1455  .close()
1456  .tx(xchain_commit(mcGw, jvb_USD, 1, mcUSD(1), scBob));
1457 
1458  // commit to a door account from the door account. This should fail.
1459  XEnv(*this)
1460  .tx(trust(mcDoor, mcUSD(10000))) // door needs to have a trustline
1461  .tx(create_bridge(mcDoor, jvb_USD))
1462  .close()
1463  .tx(xchain_commit(mcDoor, jvb_USD, 1, mcUSD(1), scBob),
1465 
1466  // commit sent from mcAlice which has no IOU balance => should fail
1467  XEnv(*this)
1468  .tx(trust(mcDoor, mcUSD(10000))) // door needs to have a trustline
1469  .tx(create_bridge(mcDoor, jvb_USD))
1470  .close()
1471  .tx(xchain_commit(mcAlice, jvb_USD, 1, mcUSD(1), scBob),
1472  ter(terNO_LINE));
1473 
1474  // commit sent from mcAlice which has no IOU balance => should fail
1475  // just changed the destination to scGw (which is the door account
1476  // and may not make much sense)
1477  XEnv(*this)
1478  .tx(trust(mcDoor, mcUSD(10000))) // door needs to have a trustline
1479  .tx(create_bridge(mcDoor, jvb_USD))
1480  .close()
1481  .tx(xchain_commit(mcAlice, jvb_USD, 1, mcUSD(1), scGw),
1482  ter(terNO_LINE));
1483 
1484  // commit sent from mcAlice which has a IOU balance => should
1485  // succeed
1486  XEnv(*this)
1487  .tx(trust(mcDoor, mcUSD(10000)))
1488  .tx(trust(mcAlice, mcUSD(10000)))
1489  .close()
1490  .tx(pay(mcGw, mcAlice, mcUSD(10)))
1491  .tx(create_bridge(mcDoor, jvb_USD))
1492  .close()
1493  //.tx(pay(mcAlice, mcDoor, mcUSD(10)));
1494  .tx(xchain_commit(mcAlice, jvb_USD, 1, mcUSD(10), scAlice));
1495 
1496  // coverage test: xchain_commit transaction with incorrect flag
1497  XEnv(*this)
1498  .tx(create_bridge(mcDoor))
1499  .close()
1500  .tx(xchain_commit(mcAlice, jvb, 1, one_xrp, scBob),
1502  ter(temINVALID_FLAG));
1503 
1504  // coverage test: xchain_commit transaction with xchain feature
1505  // disabled
1506  XEnv(*this)
1507  .tx(create_bridge(mcDoor))
1508  .disableFeature(featureXChainBridge)
1509  .close()
1510  .tx(xchain_commit(mcAlice, jvb, 1, one_xrp, scBob),
1511  ter(temDISABLED));
1512  }
1513 
1514  void
1516  {
1517  using namespace jtx;
1518 
1519  testcase("Add Attestation");
1520  XRPAmount res0 = reserve(0);
1521  XRPAmount tx_fee = txFee();
1522 
1523  auto multiTtxFee = [&](std::uint32_t m) -> STAmount {
1524  return multiply(tx_fee, STAmount(m), xrpIssue());
1525  };
1526 
1527  // Add an attestation to a claim id that has already reached quorum.
1528  // This should succeed and share in the reward.
1529  // note: this is true only when either:
1530  // 1. dest account is not specified, so transfer requires a claim
1531  // 2. or the extra attestation is sent in the same batch as the
1532  // one reaching quorum
1533  for (auto withClaim : {true})
1534  {
1535  XEnv mcEnv(*this);
1536  XEnv scEnv(*this, true);
1537  std::uint32_t const claimID = 1;
1538 
1539  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
1540 
1543  .close()
1545  .close();
1546 
1547  BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id present
1548 
1549  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
1550  auto const amt = XRP(1000);
1551  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
1552 
1553  BalanceTransfer transfer(
1554  scEnv, Account::master, scBob, scAlice, payees, withClaim);
1555 
1556  scEnv
1558  scAttester,
1559  jvb,
1560  mcAlice,
1561  amt,
1562  payees,
1563  true,
1564  claimID,
1565  dst,
1566  signers,
1568  .close();
1569  scEnv
1571  scAttester,
1572  jvb,
1573  mcAlice,
1574  amt,
1576  true,
1577  claimID,
1578  dst,
1580  .close();
1581 
1582  if (withClaim)
1583  {
1584  BEAST_EXPECT(transfer.has_not_happened());
1585 
1586  // need to submit a claim transactions
1587  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob))
1588  .close();
1589  BEAST_EXPECT(!scEnv.claimID(jvb, claimID)); // claim id deleted
1590  BEAST_EXPECT(scEnv.claimID(jvb) == claimID);
1591  }
1592 
1593  BEAST_EXPECT(transfer.has_happened(amt, split_reward_everyone));
1594  }
1595 
1596  // Test that signature weights are correctly handled. Assign
1597  // signature weights of 1,2,4,4 and a quorum of 7. Check that the
1598  // 4,4 signatures reach a quorum, the 1,2,4, reach a quorum, but the
1599  // 4,2, 4,1 and 1,2 do not.
1600 
1601  // 1,2,4 => should succeed
1602  for (auto withClaim : {false, true})
1603  {
1604  XEnv mcEnv(*this);
1605  XEnv scEnv(*this, true);
1606 
1607  std::uint32_t const quorum_7 = 7;
1608  std::vector<signer> const signers_ = [] {
1609  constexpr int numSigners = 4;
1610  std::uint32_t weights[] = {1, 2, 4, 4};
1611 
1612  std::vector<signer> result;
1613  result.reserve(numSigners);
1614  for (int i = 0; i < numSigners; ++i)
1615  {
1616  using namespace std::literals;
1617  auto const a = Account("signer_"s + std::to_string(i));
1618  result.emplace_back(a, weights[i]);
1619  }
1620  return result;
1621  }();
1622 
1623  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
1624 
1626  .tx(jtx::signers(Account::master, quorum_7, signers_))
1627  .close()
1629  .close();
1630  std::uint32_t const claimID = 1;
1631  BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id present
1632 
1633  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
1634  auto const amt = XRP(1000);
1635 
1636  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
1637 
1638  BalanceTransfer transfer(
1639  scEnv,
1641  scBob,
1642  scAlice,
1643  &payees[0],
1644  3,
1645  withClaim);
1646 
1647  scEnv
1649  scAttester,
1650  jvb,
1651  mcAlice,
1652  amt,
1653  payees,
1654  true,
1655  claimID,
1656  dst,
1657  signers_,
1658  3))
1659  .close();
1660 
1661  if (withClaim)
1662  {
1663  BEAST_EXPECT(transfer.has_not_happened());
1664 
1665  // need to submit a claim transactions
1666  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob))
1667  .close();
1668  }
1669 
1670  BEAST_EXPECT(!scEnv.claimID(jvb, 1)); // claim id deleted
1671 
1672  BEAST_EXPECT(transfer.has_happened(
1673  amt, divide(reward, STAmount(3), reward.issue())));
1674  }
1675 
1676  // 4,4 => should succeed
1677  for (auto withClaim : {false, true})
1678  {
1679  XEnv mcEnv(*this);
1680  XEnv scEnv(*this, true);
1681 
1682  std::uint32_t const quorum_7 = 7;
1683  std::vector<signer> const signers_ = [] {
1684  constexpr int numSigners = 4;
1685  std::uint32_t weights[] = {1, 2, 4, 4};
1686 
1687  std::vector<signer> result;
1688  result.reserve(numSigners);
1689  for (int i = 0; i < numSigners; ++i)
1690  {
1691  using namespace std::literals;
1692  auto const a = Account("signer_"s + std::to_string(i));
1693  result.emplace_back(a, weights[i]);
1694  }
1695  return result;
1696  }();
1697  STAmount const split_reward_ =
1698  divide(reward, STAmount(signers_.size()), reward.issue());
1699 
1700  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
1701 
1703  .tx(jtx::signers(Account::master, quorum_7, signers_))
1704  .close()
1706  .close();
1707  std::uint32_t const claimID = 1;
1708  BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id present
1709 
1710  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
1711  auto const amt = XRP(1000);
1712 
1713  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
1714 
1715  BalanceTransfer transfer(
1716  scEnv,
1718  scBob,
1719  scAlice,
1720  &payees[2],
1721  2,
1722  withClaim);
1723 
1724  scEnv
1726  scAttester,
1727  jvb,
1728  mcAlice,
1729  amt,
1730  payees,
1731  true,
1732  claimID,
1733  dst,
1734  signers_,
1735  2,
1736  2))
1737  .close();
1738 
1739  if (withClaim)
1740  {
1741  BEAST_EXPECT(transfer.has_not_happened());
1742 
1743  // need to submit a claim transactions
1744  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob))
1745  .close();
1746  }
1747 
1748  BEAST_EXPECT(!scEnv.claimID(jvb, claimID)); // claim id deleted
1749 
1750  BEAST_EXPECT(transfer.has_happened(
1751  amt, divide(reward, STAmount(2), reward.issue())));
1752  }
1753 
1754  // 1,2 => should fail
1755  for (auto withClaim : {false, true})
1756  {
1757  XEnv mcEnv(*this);
1758  XEnv scEnv(*this, true);
1759 
1760  std::uint32_t const quorum_7 = 7;
1761  std::vector<signer> const signers_ = [] {
1762  constexpr int numSigners = 4;
1763  std::uint32_t weights[] = {1, 2, 4, 4};
1764 
1765  std::vector<signer> result;
1766  result.reserve(numSigners);
1767  for (int i = 0; i < numSigners; ++i)
1768  {
1769  using namespace std::literals;
1770  auto const a = Account("signer_"s + std::to_string(i));
1771  result.emplace_back(a, weights[i]);
1772  }
1773  return result;
1774  }();
1775 
1776  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
1777 
1779  .tx(jtx::signers(Account::master, quorum_7, signers_))
1780  .close()
1782  .close();
1783 
1784  std::uint32_t const claimID = 1;
1785  BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id present
1786 
1787  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
1788  auto const amt = XRP(1000);
1789  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
1790 
1791  BalanceTransfer transfer(
1792  scEnv,
1794  scBob,
1795  scAlice,
1796  &payees[0],
1797  2,
1798  withClaim);
1799 
1800  scEnv
1802  scAttester,
1803  jvb,
1804  mcAlice,
1805  amt,
1806  payees,
1807  true,
1808  claimID,
1809  dst,
1810  signers_,
1811  2))
1812  .close();
1813  if (withClaim)
1814  {
1815  BEAST_EXPECT(transfer.has_not_happened());
1816 
1817  // need to submit a claim transactions
1818  scEnv
1819  .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob),
1821  .close();
1822  }
1823 
1824  BEAST_EXPECT(
1825  !!scEnv.claimID(jvb, claimID)); // claim id still present
1826  BEAST_EXPECT(transfer.has_not_happened());
1827  }
1828 
1829  // 2,4 => should fail
1830  for (auto withClaim : {false, true})
1831  {
1832  XEnv mcEnv(*this);
1833  XEnv scEnv(*this, true);
1834 
1835  std::uint32_t const quorum_7 = 7;
1836  std::vector<signer> const signers_ = [] {
1837  constexpr int numSigners = 4;
1838  std::uint32_t weights[] = {1, 2, 4, 4};
1839 
1840  std::vector<signer> result;
1841  result.reserve(numSigners);
1842  for (int i = 0; i < numSigners; ++i)
1843  {
1844  using namespace std::literals;
1845  auto const a = Account("signer_"s + std::to_string(i));
1846  result.emplace_back(a, weights[i]);
1847  }
1848  return result;
1849  }();
1850 
1851  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
1852 
1854  .tx(jtx::signers(Account::master, quorum_7, signers_))
1855  .close()
1857  .close();
1858 
1859  std::uint32_t const claimID = 1;
1860  BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id present
1861 
1862  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
1863  auto const amt = XRP(1000);
1864 
1865  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
1866 
1867  BalanceTransfer transfer(
1868  scEnv,
1870  scBob,
1871  scAlice,
1872  &payees[1],
1873  2,
1874  withClaim);
1875 
1876  scEnv
1878  scAttester,
1879  jvb,
1880  mcAlice,
1881  amt,
1882  payees,
1883  true,
1884  claimID,
1885  dst,
1886  signers_,
1887  2,
1888  1))
1889  .close();
1890 
1891  if (withClaim)
1892  {
1893  BEAST_EXPECT(transfer.has_not_happened());
1894 
1895  // need to submit a claim transactions
1896  scEnv
1897  .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob),
1899  .close();
1900  }
1901 
1902  BEAST_EXPECT(
1903  !!scEnv.claimID(jvb, claimID)); // claim id still present
1904  BEAST_EXPECT(transfer.has_not_happened());
1905  }
1906 
1907  // Confirm that account create transactions happen in the correct
1908  // order. If they reach quorum out of order they should not execute
1909  // until all the previous created transactions have occurred.
1910  // Re-adding an attestation should move funds.
1911  {
1912  XEnv mcEnv(*this);
1913  XEnv scEnv(*this, true);
1914  auto const amt = XRP(1000);
1915  auto const amt_plus_reward = amt + reward;
1916 
1917  {
1918  Balance door(mcEnv, mcDoor);
1919  Balance carol(mcEnv, mcCarol);
1920 
1921  mcEnv.tx(create_bridge(mcDoor, jvb, reward, XRP(20)))
1922  .close()
1924  mcAlice, jvb, scuAlice, amt, reward))
1926  mcBob, jvb, scuBob, amt, reward))
1928  mcCarol, jvb, scuCarol, amt, reward))
1929  .close();
1930 
1931  BEAST_EXPECT(
1932  door.diff() ==
1933  (multiply(amt_plus_reward, STAmount(3), xrpIssue()) -
1934  tx_fee));
1935  BEAST_EXPECT(carol.diff() == -(amt + reward + tx_fee));
1936  }
1937 
1938  scEnv.tx(create_bridge(Account::master, jvb, reward, XRP(20)))
1940  .close();
1941 
1942  {
1943  // send first batch of account create attest for all 3
1944  // account create
1945  Balance attester(scEnv, scAttester);
1946  Balance door(scEnv, Account::master);
1947 
1948  scEnv.multiTx(att_create_acct_vec(1, amt, scuAlice, 2))
1949  .multiTx(att_create_acct_vec(3, amt, scuCarol, 2))
1950  .multiTx(att_create_acct_vec(2, amt, scuBob, 2))
1951  .close();
1952 
1953  BEAST_EXPECT(door.diff() == STAmount(0));
1954  // att_create_acct_vec return vectors of size 2, so 2*3 txns
1955  BEAST_EXPECT(attester.diff() == -multiTtxFee(6));
1956 
1957  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // ca claim id present
1958  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // ca claim id present
1959  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // ca claim id present
1960  BEAST_EXPECT(
1961  scEnv.claimCount(jvb) == 0); // claim count still 0
1962  }
1963 
1964  {
1965  // complete attestations for 2nd account create => should
1966  // not complete
1967  Balance attester(scEnv, scAttester);
1968  Balance door(scEnv, Account::master);
1969 
1970  scEnv.multiTx(att_create_acct_vec(2, amt, scuBob, 3, 2))
1971  .close();
1972 
1973  BEAST_EXPECT(door.diff() == STAmount(0));
1974  // att_create_acct_vec return vectors of size 3, so 3 txns
1975  BEAST_EXPECT(attester.diff() == -multiTtxFee(3));
1976 
1977  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // ca claim id present
1978  BEAST_EXPECT(
1979  scEnv.claimCount(jvb) == 0); // claim count still 0
1980  }
1981 
1982  {
1983  // complete attestations for 3rd account create => should
1984  // not complete
1985  Balance attester(scEnv, scAttester);
1986  Balance door(scEnv, Account::master);
1987 
1988  scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 3, 2))
1989  .close();
1990 
1991  BEAST_EXPECT(door.diff() == STAmount(0));
1992  // att_create_acct_vec return vectors of size 3, so 3 txns
1993  BEAST_EXPECT(attester.diff() == -multiTtxFee(3));
1994 
1995  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // ca claim id present
1996  BEAST_EXPECT(
1997  scEnv.claimCount(jvb) == 0); // claim count still 0
1998  }
1999 
2000  {
2001  // complete attestations for 1st account create => account
2002  // should be created
2003  Balance attester(scEnv, scAttester);
2004  Balance door(scEnv, Account::master);
2005 
2006  scEnv.multiTx(att_create_acct_vec(1, amt, scuAlice, 3, 1))
2007  .close();
2008 
2009  BEAST_EXPECT(door.diff() == -amt_plus_reward);
2010  // att_create_acct_vec return vectors of size 3, so 3 txns
2011  BEAST_EXPECT(attester.diff() == -multiTtxFee(3));
2012  BEAST_EXPECT(scEnv.balance(scuAlice) == amt);
2013 
2014  BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id 1 deleted
2015  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // claim id 2 present
2016  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // claim id 3 present
2017  BEAST_EXPECT(scEnv.claimCount(jvb) == 1); // claim count now 1
2018  }
2019 
2020  {
2021  // resend attestations for 3rd account create => still
2022  // should not complete
2023  Balance attester(scEnv, scAttester);
2024  Balance door(scEnv, Account::master);
2025 
2026  scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 3, 2))
2027  .close();
2028 
2029  BEAST_EXPECT(door.diff() == STAmount(0));
2030  // att_create_acct_vec return vectors of size 3, so 3 txns
2031  BEAST_EXPECT(attester.diff() == -multiTtxFee(3));
2032 
2033  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // claim id 2 present
2034  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // claim id 3 present
2035  BEAST_EXPECT(
2036  scEnv.claimCount(jvb) == 1); // claim count still 1
2037  }
2038 
2039  {
2040  // resend attestations for 2nd account create => account
2041  // should be created
2042  Balance attester(scEnv, scAttester);
2043  Balance door(scEnv, Account::master);
2044 
2045  scEnv.multiTx(att_create_acct_vec(2, amt, scuBob, 1)).close();
2046 
2047  BEAST_EXPECT(door.diff() == -amt_plus_reward);
2048  BEAST_EXPECT(attester.diff() == -tx_fee);
2049  BEAST_EXPECT(scEnv.balance(scuBob) == amt);
2050 
2051  BEAST_EXPECT(!scEnv.caClaimID(jvb, 2)); // claim id 2 deleted
2052  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // claim id 3 present
2053  BEAST_EXPECT(scEnv.claimCount(jvb) == 2); // claim count now 2
2054  }
2055  {
2056  // resend attestations for 3rc account create => account
2057  // should be created
2058  Balance attester(scEnv, scAttester);
2059  Balance door(scEnv, Account::master);
2060 
2061  scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 1)).close();
2062 
2063  BEAST_EXPECT(door.diff() == -amt_plus_reward);
2064  BEAST_EXPECT(attester.diff() == -tx_fee);
2065  BEAST_EXPECT(scEnv.balance(scuCarol) == amt);
2066 
2067  BEAST_EXPECT(!scEnv.caClaimID(jvb, 3)); // claim id 3 deleted
2068  BEAST_EXPECT(scEnv.claimCount(jvb) == 3); // claim count now 3
2069  }
2070  }
2071 
2072  // Check that creating an account with less than the minimum reserve
2073  // fails.
2074  {
2075  XEnv mcEnv(*this);
2076  XEnv scEnv(*this, true);
2077 
2078  auto const amt = res0 - XRP(1);
2079  auto const amt_plus_reward = amt + reward;
2080 
2081  mcEnv.tx(create_bridge(mcDoor, jvb, reward, XRP(20))).close();
2082 
2083  {
2084  Balance door(mcEnv, mcDoor);
2085  Balance carol(mcEnv, mcCarol);
2086 
2087  mcEnv
2089  mcCarol, jvb, scuAlice, amt, reward))
2090  .close();
2091 
2092  BEAST_EXPECT(door.diff() == amt_plus_reward);
2093  BEAST_EXPECT(carol.diff() == -(amt_plus_reward + tx_fee));
2094  }
2095 
2096  scEnv.tx(create_bridge(Account::master, jvb, reward, XRP(20)))
2098  .close();
2099 
2100  Balance attester(scEnv, scAttester);
2101  Balance door(scEnv, Account::master);
2102 
2103  scEnv.multiTx(att_create_acct_vec(1, amt, scuAlice, 2)).close();
2104  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present
2105  BEAST_EXPECT(
2106  scEnv.claimCount(jvb) == 0); // claim count is one less
2107 
2108  scEnv.multiTx(att_create_acct_vec(1, amt, scuAlice, 2, 2)).close();
2109  BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted
2110  BEAST_EXPECT(
2111  scEnv.claimCount(jvb) == 1); // claim count was incremented
2112 
2113  BEAST_EXPECT(attester.diff() == -multiTtxFee(4));
2114  BEAST_EXPECT(door.diff() == -reward);
2115  BEAST_EXPECT(!scEnv.account(scuAlice));
2116  }
2117 
2118  // Check that sending funds with an account create txn to an
2119  // existing account works.
2120  {
2121  XEnv mcEnv(*this);
2122  XEnv scEnv(*this, true);
2123 
2124  auto const amt = XRP(111);
2125  auto const amt_plus_reward = amt + reward;
2126 
2127  mcEnv.tx(create_bridge(mcDoor, jvb, reward, XRP(20))).close();
2128 
2129  {
2130  Balance door(mcEnv, mcDoor);
2131  Balance carol(mcEnv, mcCarol);
2132 
2133  mcEnv
2135  mcCarol, jvb, scAlice, amt, reward))
2136  .close();
2137 
2138  BEAST_EXPECT(door.diff() == amt_plus_reward);
2139  BEAST_EXPECT(carol.diff() == -(amt_plus_reward + tx_fee));
2140  }
2141 
2142  scEnv.tx(create_bridge(Account::master, jvb, reward, XRP(20)))
2144  .close();
2145 
2146  Balance attester(scEnv, scAttester);
2147  Balance door(scEnv, Account::master);
2148  Balance alice(scEnv, scAlice);
2149 
2150  scEnv.multiTx(att_create_acct_vec(1, amt, scAlice, 2)).close();
2151  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present
2152  BEAST_EXPECT(
2153  scEnv.claimCount(jvb) == 0); // claim count is one less
2154 
2155  scEnv.multiTx(att_create_acct_vec(1, amt, scAlice, 2, 2)).close();
2156  BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted
2157  BEAST_EXPECT(
2158  scEnv.claimCount(jvb) == 1); // claim count was incremented
2159 
2160  BEAST_EXPECT(door.diff() == -amt_plus_reward);
2161  BEAST_EXPECT(attester.diff() == -multiTtxFee(4));
2162  BEAST_EXPECT(alice.diff() == amt);
2163  }
2164 
2165  // Check that sending funds to an existing account with deposit auth
2166  // set fails for account create transactions.
2167  {
2168  XEnv mcEnv(*this);
2169  XEnv scEnv(*this, true);
2170 
2171  auto const amt = XRP(1000);
2172  auto const amt_plus_reward = amt + reward;
2173 
2174  mcEnv.tx(create_bridge(mcDoor, jvb, reward, XRP(20))).close();
2175 
2176  {
2177  Balance door(mcEnv, mcDoor);
2178  Balance carol(mcEnv, mcCarol);
2179 
2180  mcEnv
2182  mcCarol, jvb, scAlice, amt, reward))
2183  .close();
2184 
2185  BEAST_EXPECT(door.diff() == amt_plus_reward);
2186  BEAST_EXPECT(carol.diff() == -(amt_plus_reward + tx_fee));
2187  }
2188 
2189  scEnv.tx(create_bridge(Account::master, jvb, reward, XRP(20)))
2191  .tx(fset("scAlice", asfDepositAuth)) // set deposit auth
2192  .close();
2193 
2194  Balance attester(scEnv, scAttester);
2195  Balance door(scEnv, Account::master);
2196  Balance alice(scEnv, scAlice);
2197 
2198  scEnv.multiTx(att_create_acct_vec(1, amt, scAlice, 2)).close();
2199  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present
2200  BEAST_EXPECT(
2201  scEnv.claimCount(jvb) == 0); // claim count is one less
2202 
2203  scEnv.multiTx(att_create_acct_vec(1, amt, scAlice, 2, 2)).close();
2204  BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted
2205  BEAST_EXPECT(
2206  scEnv.claimCount(jvb) == 1); // claim count was incremented
2207 
2208  BEAST_EXPECT(door.diff() == -reward);
2209  BEAST_EXPECT(attester.diff() == -multiTtxFee(4));
2210  BEAST_EXPECT(alice.diff() == STAmount(0));
2211  }
2212 
2213  // If an account is unable to pay the reserve, check that it fails.
2214  // [greg todo] I don't know what this should test??
2215 
2216  // If an attestation already exists for that server and claim id,
2217  // the new attestation should replace the old attestation
2218  {
2219  XEnv mcEnv(*this);
2220  XEnv scEnv(*this, true);
2221  auto const amt = XRP(1000);
2222  auto const amt_plus_reward = amt + reward;
2223 
2224  {
2225  Balance door(mcEnv, mcDoor);
2226  Balance carol(mcEnv, mcCarol);
2227 
2228  mcEnv.tx(create_bridge(mcDoor, jvb, reward, XRP(20)))
2229  .close()
2231  mcAlice, jvb, scuAlice, amt, reward))
2232  .close() // make sure Alice gets claim #1
2234  mcBob, jvb, scuBob, amt, reward))
2235  .close() // make sure Bob gets claim #2
2237  mcCarol, jvb, scuCarol, amt, reward))
2238  .close(); // and Carol will get claim #3
2239 
2240  BEAST_EXPECT(
2241  door.diff() ==
2242  (multiply(amt_plus_reward, STAmount(3), xrpIssue()) -
2243  tx_fee));
2244  BEAST_EXPECT(carol.diff() == -(amt + reward + tx_fee));
2245  }
2246 
2247  std::uint32_t const red_quorum = 2;
2248  scEnv.tx(create_bridge(Account::master, jvb, reward, XRP(20)))
2249  .tx(jtx::signers(Account::master, red_quorum, signers))
2250  .close();
2251 
2252  {
2253  Balance attester(scEnv, scAttester);
2254  Balance door(scEnv, Account::master);
2255  auto const bad_amt = XRP(10);
2256  std::uint32_t txCount = 0;
2257 
2258  // send attestations with incorrect amounts to for all 3
2259  // AccountCreate. They will be replaced later
2260  scEnv.multiTx(att_create_acct_vec(1, bad_amt, scuAlice, 1))
2261  .multiTx(att_create_acct_vec(2, bad_amt, scuBob, 1, 2))
2262  .multiTx(att_create_acct_vec(3, bad_amt, scuCarol, 1, 1))
2263  .close();
2264  txCount += 3;
2265 
2266  BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 1), "claim id 1 created");
2267  BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 2), "claim id 2 created");
2268  BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 3), "claim id 3 created");
2269 
2270  // note: if we send inconsistent attestations in the same
2271  // batch, the transaction errors.
2272 
2273  // from now on we send correct attestations
2274  scEnv.multiTx(att_create_acct_vec(1, amt, scuAlice, 1, 0))
2275  .multiTx(att_create_acct_vec(2, amt, scuBob, 1, 2))
2276  .multiTx(att_create_acct_vec(3, amt, scuCarol, 1, 4))
2277  .close();
2278  txCount += 3;
2279 
2280  BEAST_EXPECTS(
2281  !!scEnv.caClaimID(jvb, 1), "claim id 1 still there");
2282  BEAST_EXPECTS(
2283  !!scEnv.caClaimID(jvb, 2), "claim id 2 still there");
2284  BEAST_EXPECTS(
2285  !!scEnv.caClaimID(jvb, 3), "claim id 3 still there");
2286  BEAST_EXPECTS(
2287  scEnv.claimCount(jvb) == 0, "No account created yet");
2288 
2289  scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 1, 1))
2290  .close();
2291  txCount += 1;
2292 
2293  BEAST_EXPECTS(
2294  !!scEnv.caClaimID(jvb, 3), "claim id 3 still there");
2295  BEAST_EXPECTS(
2296  scEnv.claimCount(jvb) == 0, "No account created yet");
2297 
2298  scEnv.multiTx(att_create_acct_vec(1, amt, scuAlice, 1, 2))
2299  .close();
2300  txCount += 1;
2301 
2302  BEAST_EXPECTS(!scEnv.caClaimID(jvb, 1), "claim id 1 deleted");
2303  BEAST_EXPECTS(scEnv.claimCount(jvb) == 1, "scuAlice created");
2304 
2305  scEnv.multiTx(att_create_acct_vec(2, amt, scuBob, 1, 3))
2306  .multiTx(
2307  att_create_acct_vec(1, amt, scuAlice, 1, 3),
2309  .close();
2310  txCount += 2;
2311 
2312  BEAST_EXPECTS(!scEnv.caClaimID(jvb, 2), "claim id 2 deleted");
2313  BEAST_EXPECTS(!scEnv.caClaimID(jvb, 1), "claim id 1 not added");
2314  BEAST_EXPECTS(
2315  scEnv.claimCount(jvb) == 2, "scuAlice & scuBob created");
2316 
2317  scEnv.multiTx(att_create_acct_vec(3, amt, scuCarol, 1, 0))
2318  .close();
2319  txCount += 1;
2320 
2321  BEAST_EXPECTS(!scEnv.caClaimID(jvb, 3), "claim id 3 deleted");
2322  BEAST_EXPECTS(
2323  scEnv.claimCount(jvb) == 3, "All 3 accounts created");
2324 
2325  // because of the division of the rewards among attesters,
2326  // sometimes a couple drops are left over unspent in the
2327  // door account (here 2 drops)
2328  BEAST_EXPECT(
2329  multiply(amt_plus_reward, STAmount(3), xrpIssue()) +
2330  door.diff() <
2331  drops(3));
2332  BEAST_EXPECT(attester.diff() == -multiTtxFee(txCount));
2333  BEAST_EXPECT(scEnv.balance(scuAlice) == amt);
2334  BEAST_EXPECT(scEnv.balance(scuBob) == amt);
2335  BEAST_EXPECT(scEnv.balance(scuCarol) == amt);
2336  }
2337  }
2338 
2339  // If attestation moves funds, confirm the claim ledger objects are
2340  // removed (for both account create and "regular" transactions)
2341  // [greg] we do this in all attestation tests
2342 
2343  // coverage test: add_attestation transaction with incorrect flag
2344  {
2345  XEnv scEnv(*this, true);
2348  .close()
2350  scAttester,
2351  jvb,
2352  mcAlice,
2353  XRP(1000),
2354  payees[0],
2355  true,
2356  1,
2357  {},
2358  signers[0]),
2361  .close();
2362  }
2363 
2364  // coverage test: add_attestation with xchain feature
2365  // disabled
2366  {
2367  XEnv scEnv(*this, true);
2371  .close()
2373  scAttester,
2374  jvb,
2375  mcAlice,
2376  XRP(1000),
2377  payees[0],
2378  true,
2379  1,
2380  {},
2381  signers[0]),
2382  ter(temDISABLED))
2383  .close();
2384  }
2385  }
2386 
2387  void
2389  {
2390  using namespace jtx;
2391 
2392  testcase("Add Non Batch Claim Attestation");
2393 
2394  {
2395  XEnv mcEnv(*this);
2396  XEnv scEnv(*this, true);
2397  std::uint32_t const claimID = 1;
2398 
2399  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
2400 
2403  .close()
2405  .close();
2406 
2407  BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id present
2408 
2409  Account const dst{scBob};
2410  auto const amt = XRP(1000);
2411  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
2412 
2413  auto const dstStartBalance = scEnv.env_.balance(dst);
2414 
2415  for (int i = 0; i < signers.size(); ++i)
2416  {
2417  auto const att = claim_attestation(
2418  scAttester,
2419  jvb,
2420  mcAlice,
2421  amt,
2422  payees[i],
2423  true,
2424  claimID,
2425  dst,
2426  signers[i]);
2427 
2428  TER const expectedTER =
2430  if (i + 1 == quorum)
2431  scEnv.tx(att, ter(expectedTER)).close();
2432  else
2433  scEnv.tx(att, ter(expectedTER)).close();
2434 
2435  if (i + 1 < quorum)
2436  BEAST_EXPECT(dstStartBalance == scEnv.env_.balance(dst));
2437  else
2438  BEAST_EXPECT(
2439  dstStartBalance + amt == scEnv.env_.balance(dst));
2440  }
2441  BEAST_EXPECT(dstStartBalance + amt == scEnv.env_.balance(dst));
2442  }
2443 
2444  {
2461  XEnv mcEnv(*this);
2462  XEnv scEnv(*this, true);
2463  auto const amt = XRP(1000);
2464  std::uint32_t const claimID = 1;
2465 
2466  for (auto i = 0; i < UT_XCHAIN_DEFAULT_NUM_SIGNERS - 2; ++i)
2467  scEnv.fund(amt, alt_signers[i].account);
2468 
2469  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
2470 
2473  .close()
2475  .close();
2476 
2477  Account const dst{scBob};
2478  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
2479  auto const dstStartBalance = scEnv.env_.balance(dst);
2480 
2481  {
2482  // G1: master key
2483  auto att = claim_attestation(
2484  scAttester,
2485  jvb,
2486  mcAlice,
2487  amt,
2488  payees[0],
2489  true,
2490  claimID,
2491  dst,
2492  alt_signers[0]);
2493  scEnv.tx(att).close();
2494  }
2495  {
2496  // G2: regular key
2497  // alt_signers[0] is the regular key of alt_signers[1]
2498  // There should be 2 attestations after the transaction
2499  scEnv
2500  .tx(jtx::regkey(
2502  .close();
2503  auto att = claim_attestation(
2504  scAttester,
2505  jvb,
2506  mcAlice,
2507  amt,
2508  payees[1],
2509  true,
2510  claimID,
2511  dst,
2512  alt_signers[0]);
2514  alt_signers[1].account.human();
2515  scEnv.tx(att).close();
2516  }
2517  {
2518  // B3: public key and non-exist (unfunded) account mismatch
2519  // G3: public key and non-exist (unfunded) account match
2520  auto const unfundedSigner1 =
2522  auto const unfundedSigner2 =
2524  auto att = claim_attestation(
2525  scAttester,
2526  jvb,
2527  mcAlice,
2528  amt,
2530  true,
2531  claimID,
2532  dst,
2533  unfundedSigner1);
2535  unfundedSigner2.account.human();
2537  .close();
2539  unfundedSigner1.account.human();
2540  scEnv.tx(att).close();
2541  }
2542  {
2543  // B2: single item signer list
2544  std::vector<signer> tempSignerList = {signers[0]};
2545  scEnv.tx(
2546  jtx::signers(alt_signers[2].account, 1, tempSignerList));
2547  auto att = claim_attestation(
2548  scAttester,
2549  jvb,
2550  mcAlice,
2551  amt,
2552  payees[2],
2553  true,
2554  claimID,
2555  dst,
2556  tempSignerList.front());
2558  alt_signers[2].account.human();
2560  .close();
2561  }
2562  {
2563  // B1: disabled master key
2564  scEnv.tx(fset(alt_signers[2].account, asfDisableMaster, 0));
2565  auto att = claim_attestation(
2566  scAttester,
2567  jvb,
2568  mcAlice,
2569  amt,
2570  payees[2],
2571  true,
2572  claimID,
2573  dst,
2574  alt_signers[2]);
2576  .close();
2577  }
2578  {
2579  // --B4: not on signer list
2580  auto att = claim_attestation(
2581  scAttester,
2582  jvb,
2583  mcAlice,
2584  amt,
2585  payees[0],
2586  true,
2587  claimID,
2588  dst,
2589  signers[0]);
2590  scEnv.tx(att, ter(tecNO_PERMISSION)).close();
2591  }
2592  {
2593  // --B5: missing sfAttestationSignerAccount field
2594  // Then submit the one with the field. Should rearch quorum.
2595  auto att = claim_attestation(
2596  scAttester,
2597  jvb,
2598  mcAlice,
2599  amt,
2600  payees[3],
2601  true,
2602  claimID,
2603  dst,
2604  alt_signers[3]);
2605  att.removeMember(sfAttestationSignerAccount.getJsonName());
2606  scEnv.tx(att, ter(temMALFORMED)).close();
2607  BEAST_EXPECT(dstStartBalance == scEnv.env_.balance(dst));
2609  alt_signers[3].account.human();
2610  scEnv.tx(att).close();
2611  BEAST_EXPECT(dstStartBalance + amt == scEnv.env_.balance(dst));
2612  }
2613  }
2614  }
2615 
2616  void
2618  {
2619  using namespace jtx;
2620 
2621  testcase("Add Non Batch Account Create Attestation");
2622 
2623  XEnv mcEnv(*this);
2624  XEnv scEnv(*this, true);
2625 
2626  XRPAmount tx_fee = mcEnv.txFee();
2627 
2628  Account a{"a"};
2629  Account doorA{"doorA"};
2630 
2631  STAmount funds{XRP(10000)};
2632  mcEnv.fund(funds, a);
2633  mcEnv.fund(funds, doorA);
2634 
2635  Account ua{"ua"}; // unfunded account we want to create
2636 
2637  BridgeDef xrp_b{
2638  doorA,
2639  xrpIssue(),
2641  xrpIssue(),
2642  XRP(1), // reward
2643  XRP(20), // minAccountCreate
2644  4, // quorum
2645  signers,
2646  Json::nullValue};
2647 
2648  xrp_b.initBridge(mcEnv, scEnv);
2649 
2650  auto const amt = XRP(777);
2651  auto const amt_plus_reward = amt + xrp_b.reward;
2652  {
2653  Balance bal_doorA(mcEnv, doorA);
2654  Balance bal_a(mcEnv, a);
2655 
2656  mcEnv
2658  a, xrp_b.jvb, ua, amt, xrp_b.reward))
2659  .close();
2660 
2661  BEAST_EXPECT(bal_doorA.diff() == amt_plus_reward);
2662  BEAST_EXPECT(bal_a.diff() == -(amt_plus_reward + tx_fee));
2663  }
2664 
2665  for (int i = 0; i < signers.size(); ++i)
2666  {
2667  auto const att = create_account_attestation(
2668  signers[0].account,
2669  xrp_b.jvb,
2670  a,
2671  amt,
2672  xrp_b.reward,
2673  signers[i].account,
2674  true,
2675  1,
2676  ua,
2677  signers[i]);
2678  TER const expectedTER = i < xrp_b.quorum
2679  ? tesSUCCESS
2681 
2682  scEnv.tx(att, ter(expectedTER)).close();
2683  if (i + 1 < xrp_b.quorum)
2684  BEAST_EXPECT(!scEnv.env_.le(ua));
2685  else
2686  BEAST_EXPECT(scEnv.env_.le(ua));
2687  }
2688  BEAST_EXPECT(scEnv.env_.le(ua));
2689  }
2690 
2691  void
2693  {
2694  using namespace jtx;
2695 
2696  XRPAmount res0 = reserve(0);
2697  XRPAmount tx_fee = txFee();
2698 
2699  testcase("Claim");
2700 
2701  // Claim where the amount matches what is attested to, to an account
2702  // that exists, and there are enough attestations to reach a quorum
2703  // => should succeed
2704  // -----------------------------------------------------------------
2705  for (auto withClaim : {false, true})
2706  {
2707  XEnv mcEnv(*this);
2708  XEnv scEnv(*this, true);
2709 
2710  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
2711 
2714  .close()
2716  .close();
2717 
2718  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
2719  auto const amt = XRP(1000);
2720  std::uint32_t const claimID = 1;
2721  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
2722 
2723  BalanceTransfer transfer(
2724  scEnv,
2726  scBob,
2727  scAlice,
2728  &payees[0],
2730  withClaim);
2731 
2732  scEnv
2734  scAttester,
2735  jvb,
2736  mcAlice,
2737  amt,
2738  payees,
2739  true,
2740  claimID,
2741  dst,
2742  signers))
2743  .close();
2744  if (withClaim)
2745  {
2746  BEAST_EXPECT(transfer.has_not_happened());
2747 
2748  // need to submit a claim transactions
2749  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob))
2750  .close();
2751  }
2752 
2753  BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum));
2754  }
2755 
2756  // Claim with just one attestation signed by the Master key
2757  // => should not succeed
2758  // -----------------------------------------------------------------
2759  for (auto withClaim : {false, true})
2760  {
2761  XEnv mcEnv(*this);
2762  XEnv scEnv(*this, true);
2763 
2764  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
2765 
2766  scEnv
2768  //.tx(jtx::signers(Account::master, quorum, signers))
2769  .close()
2771  .close();
2772 
2773  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
2774  auto const amt = XRP(1000);
2775  std::uint32_t const claimID = 1;
2776  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
2777 
2778  BalanceTransfer transfer(
2779  scEnv,
2781  scBob,
2782  scAlice,
2783  &payees[0],
2784  1,
2785  withClaim);
2786 
2787  jtx::signer master_signer(Account::master);
2788  scEnv
2790  scAttester,
2791  jvb,
2792  mcAlice,
2793  amt,
2794  payees[0],
2795  true,
2796  claimID,
2797  dst,
2798  master_signer),
2800  .close();
2801 
2802  BEAST_EXPECT(transfer.has_not_happened());
2803  }
2804 
2805  // Claim with just one attestation signed by a regular key
2806  // associated to the master account
2807  // => should not succeed
2808  // -----------------------------------------------------------------
2809  for (auto withClaim : {false, true})
2810  {
2811  XEnv mcEnv(*this);
2812  XEnv scEnv(*this, true);
2813 
2814  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
2815 
2816  scEnv
2818  //.tx(jtx::signers(Account::master, quorum, signers))
2820  .close()
2822  .close();
2823 
2824  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
2825  auto const amt = XRP(1000);
2826  std::uint32_t const claimID = 1;
2827  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
2828 
2829  BalanceTransfer transfer(
2830  scEnv,
2832  scBob,
2833  scAlice,
2834  &payees[0],
2835  1,
2836  withClaim);
2837 
2838  jtx::signer master_signer(payees[0]);
2839  scEnv
2841  scAttester,
2842  jvb,
2843  mcAlice,
2844  amt,
2845  payees[0],
2846  true,
2847  claimID,
2848  dst,
2849  master_signer),
2851  .close();
2852 
2853  BEAST_EXPECT(transfer.has_not_happened());
2854  }
2855 
2856  // Claim against non-existent bridge
2857  // ---------------------------------
2858  for (auto withClaim : {false, true})
2859  {
2860  XEnv mcEnv(*this);
2861  XEnv scEnv(*this, true);
2862 
2863  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
2864 
2865  auto jvb_unknown =
2867 
2870  .close()
2872  scAlice, jvb_unknown, reward, mcAlice),
2873  ter(tecNO_ENTRY))
2874  .close();
2875 
2876  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
2877  auto const amt = XRP(1000);
2878  std::uint32_t const claimID = 1;
2879  mcEnv
2880  .tx(xchain_commit(mcAlice, jvb_unknown, claimID, amt, dst),
2881  ter(tecNO_ENTRY))
2882  .close();
2883 
2884  BalanceTransfer transfer(
2885  scEnv, Account::master, scBob, scAlice, payees, withClaim);
2886  scEnv
2888  scAttester,
2889  jvb_unknown,
2890  mcAlice,
2891  amt,
2892  payees[0],
2893  true,
2894  claimID,
2895  dst,
2896  signers[0]),
2897  ter(tecNO_ENTRY))
2898  .close();
2899 
2900  if (withClaim)
2901  {
2902  BEAST_EXPECT(transfer.has_not_happened());
2903 
2904  // need to submit a claim transactions
2905  scEnv
2906  .tx(xchain_claim(scAlice, jvb_unknown, claimID, amt, scBob),
2907  ter(tecNO_ENTRY))
2908  .close();
2909  }
2910 
2911  BEAST_EXPECT(transfer.has_not_happened());
2912  }
2913 
2914  // Claim against non-existent claim id
2915  // -----------------------------------
2916  for (auto withClaim : {false, true})
2917  {
2918  XEnv mcEnv(*this);
2919  XEnv scEnv(*this, true);
2920 
2921  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
2922 
2925  .close()
2927  .close();
2928 
2929  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
2930  auto const amt = XRP(1000);
2931  std::uint32_t const claimID = 1;
2932  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
2933 
2934  BalanceTransfer transfer(
2935  scEnv, Account::master, scBob, scAlice, payees, withClaim);
2936 
2937  // attest using non-existent claim id
2938  scEnv
2940  scAttester,
2941  jvb,
2942  mcAlice,
2943  amt,
2944  payees[0],
2945  true,
2946  999,
2947  dst,
2948  signers[0]),
2950  .close();
2951  if (withClaim)
2952  {
2953  BEAST_EXPECT(transfer.has_not_happened());
2954 
2955  // claim using non-existent claim id
2956  scEnv
2957  .tx(xchain_claim(scAlice, jvb, 999, amt, scBob),
2959  .close();
2960  }
2961 
2962  BEAST_EXPECT(transfer.has_not_happened());
2963  }
2964 
2965  // Claim against a claim id owned by another account
2966  // -------------------------------------------------
2967  for (auto withClaim : {false, true})
2968  {
2969  XEnv mcEnv(*this);
2970  XEnv scEnv(*this, true);
2971 
2972  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
2973 
2976  .close()
2978  .close();
2979 
2980  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
2981  auto const amt = XRP(1000);
2982  std::uint32_t const claimID = 1;
2983  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
2984 
2985  BalanceTransfer transfer(
2986  scEnv,
2988  scBob,
2989  scAlice,
2990  &payees[0],
2992  withClaim);
2993 
2994  scEnv
2996  scAttester,
2997  jvb,
2998  mcAlice,
2999  amt,
3000  payees,
3001  true,
3002  claimID,
3003  dst,
3004  signers))
3005  .close();
3006  if (withClaim)
3007  {
3008  BEAST_EXPECT(transfer.has_not_happened());
3009 
3010  // submit a claim transaction with the wrong account (scGw
3011  // instead of scAlice)
3012  scEnv
3013  .tx(xchain_claim(scGw, jvb, claimID, amt, scBob),
3015  .close();
3016  BEAST_EXPECT(transfer.has_not_happened());
3017  }
3018  else
3019  {
3020  BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum));
3021  }
3022  }
3023 
3024  // Claim against a claim id with no attestations
3025  // ---------------------------------------------
3026  for (auto withClaim : {false, true})
3027  {
3028  XEnv mcEnv(*this);
3029  XEnv scEnv(*this, true);
3030 
3031  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3032 
3035  .close()
3037  .close();
3038 
3039  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3040  auto const amt = XRP(1000);
3041  std::uint32_t const claimID = 1;
3042  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3043 
3044  BalanceTransfer transfer(
3045  scEnv, Account::master, scBob, scAlice, payees, withClaim);
3046 
3047  // don't send any attestations
3048 
3049  if (withClaim)
3050  {
3051  BEAST_EXPECT(transfer.has_not_happened());
3052 
3053  // need to submit a claim transactions
3054  scEnv
3055  .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob),
3057  .close();
3058  }
3059 
3060  BEAST_EXPECT(transfer.has_not_happened());
3061  }
3062 
3063  // Claim against a claim id with attestations, but not enough to
3064  // make a quorum
3065  // --------------------------------------------------------------------
3066  for (auto withClaim : {false, true})
3067  {
3068  XEnv mcEnv(*this);
3069  XEnv scEnv(*this, true);
3070 
3071  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3072 
3075  .close()
3077  .close();
3078 
3079  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3080  auto const amt = XRP(1000);
3081  std::uint32_t const claimID = 1;
3082  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3083 
3084  BalanceTransfer transfer(
3085  scEnv, Account::master, scBob, scAlice, payees, withClaim);
3086 
3087  auto tooFew = quorum - 1;
3088  scEnv
3090  scAttester,
3091  jvb,
3092  mcAlice,
3093  amt,
3094  payees,
3095  true,
3096  claimID,
3097  dst,
3098  signers,
3099  tooFew))
3100  .close();
3101  if (withClaim)
3102  {
3103  BEAST_EXPECT(transfer.has_not_happened());
3104 
3105  // need to submit a claim transactions
3106  scEnv
3107  .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob),
3109  .close();
3110  }
3111 
3112  BEAST_EXPECT(transfer.has_not_happened());
3113  }
3114 
3115  // Claim id of zero
3116  // ----------------
3117  for (auto withClaim : {false, true})
3118  {
3119  XEnv mcEnv(*this);
3120  XEnv scEnv(*this, true);
3121 
3122  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3123 
3126  .close()
3128  .close();
3129 
3130  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3131  auto const amt = XRP(1000);
3132  std::uint32_t const claimID = 1;
3133  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3134 
3135  BalanceTransfer transfer(
3136  scEnv, Account::master, scBob, scAlice, payees, withClaim);
3137 
3138  scEnv
3139  .multiTx(
3141  scAttester,
3142  jvb,
3143  mcAlice,
3144  amt,
3145  payees,
3146  true,
3147  0,
3148  dst,
3149  signers),
3151  .close();
3152  if (withClaim)
3153  {
3154  BEAST_EXPECT(transfer.has_not_happened());
3155 
3156  // need to submit a claim transactions
3157  scEnv
3158  .tx(xchain_claim(scAlice, jvb, 0, amt, scBob),
3160  .close();
3161  }
3162 
3163  BEAST_EXPECT(transfer.has_not_happened());
3164  }
3165 
3166  // Claim issue that does not match the expected issue on the bridge
3167  // (either LockingChainIssue or IssuingChainIssue, depending on the
3168  // chain). The claim id should already have enough attestations to
3169  // reach a quorum for this amount (for a different issuer).
3170  // ---------------------------------------------------------------------
3171  for (auto withClaim : {true})
3172  {
3173  XEnv mcEnv(*this);
3174  XEnv scEnv(*this, true);
3175 
3176  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3177 
3180  .close()
3182  .close();
3183 
3184  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3185  auto const amt = XRP(1000);
3186  std::uint32_t const claimID = 1;
3187  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3188 
3189  BalanceTransfer transfer(
3190  scEnv,
3192  scBob,
3193  scAlice,
3194  &payees[0],
3196  withClaim);
3197 
3198  scEnv
3200  scAttester,
3201  jvb,
3202  mcAlice,
3203  amt,
3204  payees,
3205  true,
3206  claimID,
3207  dst,
3208  signers))
3209  .close();
3210 
3211  if (withClaim)
3212  {
3213  BEAST_EXPECT(transfer.has_not_happened());
3214 
3215  // need to submit a claim transactions
3216  scEnv
3218  ter(temBAD_AMOUNT))
3219  .close();
3220  }
3221 
3222  BEAST_EXPECT(transfer.has_not_happened());
3223  }
3224 
3225  // Claim to a destination that does not already exist on the chain
3226  // -----------------------------------------------------------------
3227  for (auto withClaim : {true})
3228  {
3229  XEnv mcEnv(*this);
3230  XEnv scEnv(*this, true);
3231 
3232  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3233 
3236  .close()
3238  .close();
3239 
3240  auto dst(withClaim ? std::nullopt : std::optional<Account>{scuBob});
3241  auto const amt = XRP(1000);
3242  std::uint32_t const claimID = 1;
3243  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3244 
3245  BalanceTransfer transfer(
3246  scEnv,
3248  scBob,
3249  scAlice,
3250  &payees[0],
3252  withClaim);
3253 
3254  scEnv
3256  scAttester,
3257  jvb,
3258  mcAlice,
3259  amt,
3260  payees,
3261  true,
3262  claimID,
3263  dst,
3264  signers))
3265  .close();
3266  if (withClaim)
3267  {
3268  BEAST_EXPECT(transfer.has_not_happened());
3269 
3270  // need to submit a claim transactions
3271  scEnv
3273  ter(tecNO_DST))
3274  .close();
3275  }
3276 
3277  BEAST_EXPECT(transfer.has_not_happened());
3278  }
3279 
3280  // Claim where the claim id owner does not have enough XRP to pay
3281  // the reward
3282  // ------------------------------------------------------------------
3283  for (auto withClaim : {false, true})
3284  {
3285  XEnv mcEnv(*this);
3286  XEnv scEnv(*this, true);
3287 
3288  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3289  STAmount huge_reward{XRP(20000)};
3290  BEAST_EXPECT(huge_reward > scEnv.balance(scAlice));
3291 
3292  scEnv.tx(create_bridge(Account::master, jvb, huge_reward))
3294  .close()
3295  .tx(xchain_create_claim_id(scAlice, jvb, huge_reward, mcAlice))
3296  .close();
3297 
3298  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3299  auto const amt = XRP(1000);
3300  std::uint32_t const claimID = 1;
3301  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3302 
3303  BalanceTransfer transfer(
3304  scEnv,
3306  scBob,
3307  scAlice,
3308  &payees[0],
3310  withClaim);
3311 
3312  if (withClaim)
3313  {
3314  scEnv
3316  scAttester,
3317  jvb,
3318  mcAlice,
3319  amt,
3320  payees,
3321  true,
3322  claimID,
3323  dst,
3324  signers))
3325  .close();
3326  BEAST_EXPECT(transfer.has_not_happened());
3327 
3328  // need to submit a claim transactions
3329  scEnv
3330  .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob),
3332  .close();
3333  }
3334  else
3335  {
3336  auto txns = claim_attestations(
3337  scAttester,
3338  jvb,
3339  mcAlice,
3340  amt,
3341  payees,
3342  true,
3343  claimID,
3344  dst,
3345  signers);
3346  for (int i = 0; i < UT_XCHAIN_DEFAULT_QUORUM - 1; ++i)
3347  {
3348  scEnv.tx(txns[i]).close();
3349  }
3350  scEnv.tx(txns.back());
3351  scEnv.close();
3352  // The attestation should succeed, because it adds an
3353  // attestation, but the claim should fail with insufficient
3354  // funds
3355  scEnv
3356  .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob),
3358  .close();
3359  }
3360 
3361  BEAST_EXPECT(transfer.has_not_happened());
3362  }
3363 
3364  // Claim where the claim id owner has enough XRP to pay the reward,
3365  // but it would put his balance below the reserve
3366  // --------------------------------------------------------------------
3367  for (auto withClaim : {false, true})
3368  {
3369  XEnv mcEnv(*this);
3370  XEnv scEnv(*this, true);
3371 
3372  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3373 
3376  .fund(
3377  res0 + reward,
3378  scuAlice) // just not enough because of fees
3379  .close()
3382  .close();
3383 
3384  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3385  auto const amt = XRP(1000);
3386  std::uint32_t const claimID = 1;
3387  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3388 
3389  BalanceTransfer transfer(
3390  scEnv, Account::master, scBob, scuAlice, payees, withClaim);
3391 
3392  scEnv
3394  scAttester,
3395  jvb,
3396  mcAlice,
3397  amt,
3398  payees[0],
3399  true,
3400  claimID,
3401  dst,
3402  signers[0]),
3404  .close();
3405  if (withClaim)
3406  {
3407  BEAST_EXPECT(transfer.has_not_happened());
3408 
3409  // need to submit a claim transactions
3410  scEnv
3413  .close();
3414  }
3415 
3416  BEAST_EXPECT(transfer.has_not_happened());
3417  }
3418 
3419  // Pay to an account with deposit auth set
3420  // ---------------------------------------
3421  for (auto withClaim : {false, true})
3422  {
3423  XEnv mcEnv(*this);
3424  XEnv scEnv(*this, true);
3425 
3426  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3427 
3430  .tx(fset("scBob", asfDepositAuth)) // set deposit auth
3431  .close()
3433  .close();
3434 
3435  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3436  auto const amt = XRP(1000);
3437  std::uint32_t const claimID = 1;
3438  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3439 
3440  BalanceTransfer transfer(
3441  scEnv,
3443  scBob,
3444  scAlice,
3445  &payees[0],
3447  withClaim);
3448  auto txns = claim_attestations(
3449  scAttester,
3450  jvb,
3451  mcAlice,
3452  amt,
3453  payees,
3454  true,
3455  claimID,
3456  dst,
3457  signers);
3458  for (int i = 0; i < UT_XCHAIN_DEFAULT_QUORUM - 1; ++i)
3459  {
3460  scEnv.tx(txns[i]).close();
3461  }
3462  if (withClaim)
3463  {
3464  scEnv.tx(txns.back()).close();
3465 
3466  BEAST_EXPECT(transfer.has_not_happened());
3467 
3468  // need to submit a claim transactions
3469  scEnv
3470  .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob),
3472  .close();
3473 
3474  // the transfer failed, but check that we can still use the
3475  // claimID with a different account
3476  Balance scCarol_bal(scEnv, scCarol);
3477 
3478  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scCarol))
3479  .close();
3480  BEAST_EXPECT(scCarol_bal.diff() == amt);
3481  }
3482  else
3483  {
3484  scEnv.tx(txns.back()).close();
3485  scEnv
3486  .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob),
3488  .close();
3489  // A way would be to remove deposit auth and resubmit the
3490  // attestations (even though the witness servers won't do
3491  // it)
3492  scEnv
3493  .tx(fset("scBob", 0, asfDepositAuth)) // clear deposit auth
3494  .close();
3495 
3496  Balance scBob_bal(scEnv, scBob);
3497  scEnv.tx(txns.back()).close();
3498  BEAST_EXPECT(scBob_bal.diff() == amt);
3499  }
3500  }
3501 
3502  // Pay to an account with Destination Tag set
3503  // ------------------------------------------
3504  for (auto withClaim : {false, true})
3505  {
3506  XEnv mcEnv(*this);
3507  XEnv scEnv(*this, true);
3508 
3509  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3510 
3513  .tx(fset("scBob", asfRequireDest)) // set dest tag
3514  .close()
3516  .close();
3517 
3518  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3519  auto const amt = XRP(1000);
3520  std::uint32_t const claimID = 1;
3521  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3522 
3523  BalanceTransfer transfer(
3524  scEnv,
3526  scBob,
3527  scAlice,
3528  &payees[0],
3530  withClaim);
3531  auto txns = claim_attestations(
3532  scAttester,
3533  jvb,
3534  mcAlice,
3535  amt,
3536  payees,
3537  true,
3538  claimID,
3539  dst,
3540  signers);
3541  for (int i = 0; i < UT_XCHAIN_DEFAULT_QUORUM - 1; ++i)
3542  {
3543  scEnv.tx(txns[i]).close();
3544  }
3545  if (withClaim)
3546  {
3547  scEnv.tx(txns.back()).close();
3548  BEAST_EXPECT(transfer.has_not_happened());
3549 
3550  // need to submit a claim transactions
3551  scEnv
3552  .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob),
3554  .close();
3555 
3556  // the transfer failed, but check that we can still use the
3557  // claimID with a different account
3558  Balance scCarol_bal(scEnv, scCarol);
3559 
3560  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scCarol))
3561  .close();
3562  BEAST_EXPECT(scCarol_bal.diff() == amt);
3563  }
3564  else
3565  {
3566  scEnv.tx(txns.back()).close();
3567  scEnv
3568  .tx(xchain_claim(scAlice, jvb, claimID, amt, scBob),
3570  .close();
3571  // A way would be to remove the destination tag requirement
3572  // and resubmit the attestations (even though the witness
3573  // servers won't do it)
3574  scEnv
3575  .tx(fset("scBob", 0, asfRequireDest)) // clear dest tag
3576  .close();
3577 
3578  Balance scBob_bal(scEnv, scBob);
3579 
3580  scEnv.tx(txns.back()).close();
3581  BEAST_EXPECT(scBob_bal.diff() == amt);
3582  }
3583  }
3584 
3585  // Pay to an account with deposit auth set. Check that the attestations
3586  // are still validated and that we can used the claimID to transfer the
3587  // funds to a different account (which doesn't have deposit auth set)
3588  // --------------------------------------------------------------------
3589  {
3590  XEnv mcEnv(*this);
3591  XEnv scEnv(*this, true);
3592 
3593  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3594 
3597  .tx(fset("scBob", asfDepositAuth)) // set deposit auth
3598  .close()
3600  .close();
3601 
3602  auto dst(std::optional<Account>{scBob});
3603  auto const amt = XRP(1000);
3604  std::uint32_t const claimID = 1;
3605  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3606 
3607  // we should be able to submit the attestations, but the transfer
3608  // should not occur because dest account has deposit auth set
3609  Balance scBob_bal(scEnv, scBob);
3610 
3612  scAttester,
3613  jvb,
3614  mcAlice,
3615  amt,
3616  payees,
3617  true,
3618  claimID,
3619  dst,
3620  signers));
3621  BEAST_EXPECT(scBob_bal.diff() == STAmount(0));
3622 
3623  // Check that check that we still can use the claimID to transfer
3624  // the amount to a different account
3625  Balance scCarol_bal(scEnv, scCarol);
3626 
3627  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scCarol)).close();
3628  BEAST_EXPECT(scCarol_bal.diff() == amt);
3629  }
3630 
3631  // Claim where the amount different from what is attested to
3632  // ---------------------------------------------------------
3633  for (auto withClaim : {true})
3634  {
3635  XEnv mcEnv(*this);
3636  XEnv scEnv(*this, true);
3637 
3638  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3639 
3642  .close()
3644  .close();
3645 
3646  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3647  auto const amt = XRP(1000);
3648  std::uint32_t const claimID = 1;
3649  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3650 
3651  BalanceTransfer transfer(
3652  scEnv,
3654  scBob,
3655  scAlice,
3656  &payees[0],
3658  withClaim);
3660  scAttester,
3661  jvb,
3662  mcAlice,
3663  amt,
3664  payees,
3665  true,
3666  claimID,
3667  dst,
3668  signers));
3669  if (withClaim)
3670  {
3671  BEAST_EXPECT(transfer.has_not_happened());
3672 
3673  // claim wrong amount
3674  scEnv
3677  .close();
3678  }
3679 
3680  BEAST_EXPECT(transfer.has_not_happened());
3681  }
3682 
3683  // Verify that rewards are paid from the account that owns the claim
3684  // id
3685  // --------------------------------------------------------------------
3686  for (auto withClaim : {false, true})
3687  {
3688  XEnv mcEnv(*this);
3689  XEnv scEnv(*this, true);
3690 
3691  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3692 
3695  .close()
3697  .close();
3698 
3699  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3700  auto const amt = XRP(1000);
3701  std::uint32_t const claimID = 1;
3702  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3703 
3704  BalanceTransfer transfer(
3705  scEnv,
3707  scBob,
3708  scAlice,
3709  &payees[0],
3711  withClaim);
3712  Balance scAlice_bal(scEnv, scAlice);
3714  scAttester,
3715  jvb,
3716  mcAlice,
3717  amt,
3718  payees,
3719  true,
3720  claimID,
3721  dst,
3722  signers));
3723 
3724  STAmount claim_cost = reward;
3725 
3726  if (withClaim)
3727  {
3728  BEAST_EXPECT(transfer.has_not_happened());
3729 
3730  // need to submit a claim transactions
3731  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob))
3732  .close();
3733  claim_cost += tx_fee;
3734  }
3735 
3736  BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum));
3737  BEAST_EXPECT(
3738  scAlice_bal.diff() == -claim_cost); // because reward % 4 == 0
3739  }
3740 
3741  // Verify that if a reward is not evenly divisible among the reward
3742  // accounts, the remaining amount goes to the claim id owner.
3743  // ----------------------------------------------------------------
3744  for (auto withClaim : {false, true})
3745  {
3746  XEnv mcEnv(*this);
3747  XEnv scEnv(*this, true);
3748 
3750 
3753  .close()
3755  .close();
3756 
3757  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3758  auto const amt = XRP(1000);
3759  std::uint32_t const claimID = 1;
3760  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3761 
3762  BalanceTransfer transfer(
3763  scEnv,
3765  scBob,
3766  scAlice,
3767  &payees[0],
3769  withClaim);
3770  Balance scAlice_bal(scEnv, scAlice);
3772  scAttester,
3773  jvb,
3774  mcAlice,
3775  amt,
3776  payees,
3777  true,
3778  claimID,
3779  dst,
3780  signers));
3781  STAmount claim_cost = tiny_reward;
3782 
3783  if (withClaim)
3784  {
3785  BEAST_EXPECT(transfer.has_not_happened());
3786 
3787  // need to submit a claim transactions
3788  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob))
3789  .close();
3790  claim_cost += tx_fee;
3791  }
3792 
3793  BEAST_EXPECT(transfer.has_happened(amt, tiny_reward_split));
3794  BEAST_EXPECT(
3795  scAlice_bal.diff() == -(claim_cost - tiny_reward_remainder));
3796  }
3797 
3798  // If a reward distribution fails for one of the reward accounts
3799  // (the reward account doesn't exist or has deposit auth set), then
3800  // the txn should still succeed, but that portion should go to the
3801  // claim id owner.
3802  // -------------------------------------------------------------------
3803  for (auto withClaim : {false, true})
3804  {
3805  XEnv mcEnv(*this);
3806  XEnv scEnv(*this, true);
3807 
3808  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3809 
3810  std::vector<Account> alt_payees{payees.begin(), payees.end() - 1};
3811  alt_payees.back() = Account("inexistent");
3812 
3815  .close()
3817  .close();
3818 
3819  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3820  auto const amt = XRP(1000);
3821  std::uint32_t const claimID = 1;
3822  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3823 
3824  BalanceTransfer transfer(
3825  scEnv,
3827  scBob,
3828  scAlice,
3829  &payees[0],
3831  withClaim);
3833  scAttester,
3834  jvb,
3835  mcAlice,
3836  amt,
3837  alt_payees,
3838  true,
3839  claimID,
3840  dst,
3841  signers));
3842 
3843  if (withClaim)
3844  {
3845  BEAST_EXPECT(transfer.has_not_happened());
3846 
3847  // need to submit a claim transactions
3848  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob))
3849  .close();
3850  }
3851 
3852  // this also checks that only 3 * split_reward was deducted from
3853  // scAlice (the payor account), since we passed alt_payees to
3854  // BalanceTransfer
3855  BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum));
3856  }
3857 
3858  for (auto withClaim : {false, true})
3859  {
3860  XEnv mcEnv(*this);
3861  XEnv scEnv(*this, true);
3862 
3863  mcEnv.tx(create_bridge(mcDoor, jvb)).close();
3864  auto& unpaid = payees[UT_XCHAIN_DEFAULT_QUORUM - 1];
3867  .tx(fset(unpaid, asfDepositAuth))
3868  .close()
3870  .close();
3871 
3872  auto dst(withClaim ? std::nullopt : std::optional<Account>{scBob});
3873  auto const amt = XRP(1000);
3874  std::uint32_t const claimID = 1;
3875  mcEnv.tx(xchain_commit(mcAlice, jvb, claimID, amt, dst)).close();
3876 
3877  // balance of last signer should not change (has deposit auth)
3878  Balance last_signer(scEnv, unpaid);
3879 
3880  // make sure all signers except the last one get the
3881  // split_reward
3882 
3883  BalanceTransfer transfer(
3884  scEnv,
3886  scBob,
3887  scAlice,
3888  &payees[0],
3890  withClaim);
3892  scAttester,
3893  jvb,
3894  mcAlice,
3895  amt,
3896  payees,
3897  true,
3898  claimID,
3899  dst,
3900  signers));
3901 
3902  if (withClaim)
3903  {
3904  BEAST_EXPECT(transfer.has_not_happened());
3905 
3906  // need to submit a claim transactions
3907  scEnv.tx(xchain_claim(scAlice, jvb, claimID, amt, scBob))
3908  .close();
3909  }
3910 
3911  // this also checks that only 3 * split_reward was deducted from
3912  // scAlice (the payor account), since we passed payees.size() -
3913  // 1 to BalanceTransfer
3914  BEAST_EXPECT(transfer.has_happened(amt, split_reward_quorum));
3915 
3916  // and make sure the account with deposit auth received nothing
3917  BEAST_EXPECT(last_signer.diff() == STAmount(0));
3918  }
3919 
3920  // coverage test: xchain_claim transaction with incorrect flag
3921  XEnv(*this, true)
3923  .close()
3924  .tx(xchain_claim(scAlice, jvb, 1, XRP(1000), scBob),
3927  .close();
3928 
3929  // coverage test: xchain_claim transaction with xchain feature
3930  // disabled
3931  XEnv(*this, true)
3933  .disableFeature(featureXChainBridge)
3934  .close()
3935  .tx(xchain_claim(scAlice, jvb, 1, XRP(1000), scBob),
3936  ter(temDISABLED))
3937  .close();
3938 
3939  // coverage test: XChainClaim::preclaim - isLockingChain = true;
3940  XEnv(*this)
3941  .tx(create_bridge(mcDoor, jvb))
3942  .close()
3943  .tx(xchain_claim(mcAlice, jvb, 1, XRP(1000), mcBob),
3945  }
3946 
3947  void
3949  {
3950  using namespace jtx;
3951 
3952  testcase("Bridge Create Account");
3953  XRPAmount tx_fee = txFee();
3954 
3955  // coverage test: transferHelper() - dst == src
3956  {
3957  XEnv scEnv(*this, true);
3958 
3959  auto const amt = XRP(111);
3960  auto const amt_plus_reward = amt + reward;
3961 
3964  .close();
3965 
3966  Balance door(scEnv, Account::master);
3967 
3968  // scEnv.tx(att_create_acct_batch1(1, amt,
3969  // Account::master)).close();
3970  scEnv.multiTx(att_create_acct_vec(1, amt, Account::master, 2))
3971  .close();
3972  BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present
3973  BEAST_EXPECT(
3974  scEnv.claimCount(jvb) == 0); // claim count is one less
3975 
3976  // scEnv.tx(att_create_acct_batch2(1, amt,
3977  // Account::master)).close();
3978  scEnv.multiTx(att_create_acct_vec(1, amt, Account::master, 2, 2))
3979  .close();
3980  BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted
3981  BEAST_EXPECT(
3982  scEnv.claimCount(jvb) == 1); // claim count was incremented
3983 
3984  BEAST_EXPECT(door.diff() == -reward);
3985  }
3986 
3987  // Check that creating an account with less than the minimum create
3988  // amount fails.
3989  {
3990  XEnv mcEnv(*this);
3991 
3992  mcEnv.tx(create_bridge(mcDoor, jvb, XRP(1), XRP(20))).close();
3993 
3994  Balance door(mcEnv, mcDoor);
3995  Balance carol(mcEnv, mcCarol);
3996 
3997  mcEnv
3999  mcCarol, jvb, scuAlice, XRP(19), reward),
4001  .close();
4002 
4003  BEAST_EXPECT(door.diff() == STAmount(0));
4004  BEAST_EXPECT(carol.diff() == -tx_fee);
4005  }
4006 
4007  // Check that creating an account with invalid flags fails.
4008  {
4009  XEnv mcEnv(*this);
4010 
4011  mcEnv.tx(create_bridge(mcDoor, jvb, XRP(1), XRP(20))).close();
4012 
4013  Balance door(mcEnv, mcDoor);
4014 
4015  mcEnv
4017  mcCarol, jvb, scuAlice, XRP(20), reward),
4020  .close();
4021 
4022  BEAST_EXPECT(door.diff() == STAmount(0));
4023  }
4024 
4025  // Check that creating an account with the XChainBridge feature
4026  // disabled fails.
4027  {
4028  XEnv mcEnv(*this);
4029 
4030  mcEnv.tx(create_bridge(mcDoor, jvb, XRP(1), XRP(20))).close();
4031 
4032  Balance door(mcEnv, mcDoor);
4033 
4036  mcCarol, jvb, scuAlice, XRP(20), reward),
4037  ter(temDISABLED))
4038  .close();
4039 
4040  BEAST_EXPECT(door.diff() == STAmount(0));
4041  }
4042 
4043  // Check that creating an account with a negative amount fails
4044  {
4045  XEnv mcEnv(*this);
4046 
4047  mcEnv.tx(create_bridge(mcDoor, jvb, XRP(1), XRP(20))).close();
4048 
4049  Balance door(mcEnv, mcDoor);
4050 
4051  mcEnv
4053  mcCarol, jvb, scuAlice, XRP(-20), reward),
4054  ter(temBAD_AMOUNT))
4055  .close();
4056 
4057  BEAST_EXPECT(door.diff() == STAmount(0));
4058  }
4059 
4060  // Check that creating an account with a negative reward fails
4061  {
4062  XEnv mcEnv(*this);
4063 
4064  mcEnv.tx(create_bridge(mcDoor, jvb, XRP(1), XRP(20))).close();
4065 
4066  Balance door(mcEnv, mcDoor);
4067 
4068  mcEnv
4070  mcCarol, jvb, scuAlice, XRP(20), XRP(-1)),
4071  ter(temBAD_AMOUNT))
4072  .close();
4073 
4074  BEAST_EXPECT(door.diff() == STAmount(0));
4075  }
4076 
4077  // Check that door account can't lock funds onto itself
4078  {
4079  XEnv mcEnv(*this);
4080 
4081  mcEnv.tx(create_bridge(mcDoor, jvb, XRP(1), XRP(20))).close();
4082 
4083  Balance door(mcEnv, mcDoor);
4084 
4085  mcEnv
4087  mcDoor, jvb, scuAlice, XRP(20), XRP(1)),
4089  .close();
4090 
4091  BEAST_EXPECT(door.diff() == -tx_fee);
4092  }
4093 
4094  // Check that reward matches the amount specified in bridge
4095  {
4096  XEnv mcEnv(*this);
4097 
4098  mcEnv.tx(create_bridge(mcDoor, jvb, XRP(1), XRP(20))).close();
4099 
4100  Balance door(mcEnv, mcDoor);
4101 
4102  mcEnv
4104  mcCarol, jvb, scuAlice, XRP(20), XRP(2)),
4106  .close();
4107 
4108  BEAST_EXPECT(door.diff() == STAmount(0));
4109  }
4110  }
4111 
4112  void
4114  {
4115  using namespace jtx;
4116  XRPAmount res0 = reserve(0);
4117  XRPAmount tx_fee = txFee();
4118 
4119  testcase("Fee dips into reserve");
4120 
4121  // commit where the fee dips into the reserve, this should succeed
4122  XEnv(*this)
4123  .tx(create_bridge(mcDoor, jvb))
4124  .fund(res0 + one_xrp + tx_fee - drops(1), mcuAlice)
4125  .close()
4126  .tx(xchain_commit(mcuAlice, jvb, 1, one_xrp, scBob),
4127  ter(tesSUCCESS));
4128 
4129  // commit where the commit amount drips into the reserve, this should
4130  // fail
4131  XEnv(*this)
4132  .tx(create_bridge(mcDoor, jvb))
4133  .fund(res0 + one_xrp - drops(1), mcuAlice)
4134  .close()
4135  .tx(xchain_commit(mcuAlice, jvb, 1, one_xrp, scBob),
4137 
4138  auto const minAccountCreate = XRP(20);
4139 
4140  // account create commit where the fee dips into the reserve,
4141  // this should succeed
4142  XEnv(*this)
4143  .tx(create_bridge(mcDoor, jvb, reward, minAccountCreate))
4144  .fund(
4145  res0 + tx_fee + minAccountCreate + reward - drops(1), mcuAlice)
4146  .close()
4148  mcuAlice, jvb, scuAlice, minAccountCreate, reward),
4149  ter(tesSUCCESS));
4150 
4151  // account create commit where the commit dips into the reserve,
4152  // this should fail
4153  XEnv(*this)
4154  .tx(create_bridge(mcDoor, jvb, reward, minAccountCreate))
4155  .fund(res0 + minAccountCreate + reward - drops(1), mcuAlice)
4156  .close()
4158  mcuAlice, jvb, scuAlice, minAccountCreate, reward),
4160  }
4161 
4162  void
4164  {
4165  using namespace jtx;
4166 
4167  testcase("Bridge Delete Door Account");
4168 
4169  auto const acctDelFee{
4170  drops(XEnv(*this).env_.current()->fees().increment)};
4171 
4172  // Deleting an account that owns bridge should fail
4173  {
4174  XEnv mcEnv(*this);
4175 
4176  mcEnv.tx(create_bridge(mcDoor, jvb, XRP(1), XRP(1))).close();
4177 
4178  // We don't allow an account to be deleted if its sequence
4179  // number is within 256 of the current ledger.
4180  for (size_t i = 0; i < 256; ++i)
4181  mcEnv.close();
4182 
4183  // try to delete mcDoor, send funds to mcAlice
4184  mcEnv.tx(
4186  fee(acctDelFee),
4188  }
4189 
4190  // Deleting an account that owns a claim id should fail
4191  {
4192  XEnv scEnv(*this, true);
4193 
4195  .close()
4197  .close();
4198 
4199  // We don't allow an account to be deleted if its sequence
4200  // number is within 256 of the current ledger.
4201  for (size_t i = 0; i < 256; ++i)
4202  scEnv.close();
4203 
4204  // try to delete scAlice, send funds to scBob
4205  scEnv.tx(
4207  fee(acctDelFee),
4209  }
4210  }
4211 
4212  void
4214  {
4215  using namespace jtx;
4216 
4217  testcase("Bad attestations");
4218  {
4219  // Create a bridge and add an attestation with a bad public key
4220  XEnv scEnv(*this, true);
4221  std::uint32_t const claimID = 1;
4223  auto const amt = XRP(1000);
4226  .close();
4228  .close();
4229  auto jvAtt = claim_attestation(
4230  scAttester,
4231  jvb,
4232  mcAlice,
4233  amt,
4235  true,
4236  claimID,
4237  dst,
4239  {
4240  // Change to an invalid keytype
4241  auto k = jvAtt["PublicKey"].asString();
4242  k.at(1) = '9';
4243  jvAtt["PublicKey"] = k;
4244  }
4245  scEnv.tx(jvAtt, ter(temMALFORMED)).close();
4246  }
4247  {
4248  // Create a bridge and add an create account attestation with a bad
4249  // public key
4250  XEnv scEnv(*this, true);
4251  std::uint32_t const createCount = 1;
4252  Account dst{scBob};
4253  auto const amt = XRP(1000);
4254  auto const rewardAmt = XRP(1);
4257  .close();
4258  auto jvAtt = create_account_attestation(
4259  scAttester,
4260  jvb,
4261  mcAlice,
4262  amt,
4263  rewardAmt,
4265  true,
4266  createCount,
4267  dst,
4269  {
4270  // Change to an invalid keytype
4271  auto k = jvAtt["PublicKey"].asString();
4272  k.at(1) = '9';
4273  jvAtt["PublicKey"] = k;
4274  }
4275  scEnv.tx(jvAtt, ter(temMALFORMED)).close();
4276  }
4277  }
4278 
4279  void
4280  run() override
4281  {
4282  testXChainBridgeExtraFields();
4283  testXChainCreateBridge();
4284  testXChainBridgeCreateConstraints();
4285  testXChainCreateBridgeMatrix();
4286  testXChainModifyBridge();
4287  testXChainCreateClaimID();
4288  testXChainCommit();
4289  testXChainAddAttestation();
4290  testXChainAddClaimNonBatchAttestation();
4291  testXChainAddAccountCreateNonBatchAttestation();
4292  testXChainClaim();
4293  testXChainCreateAccount();
4294  testFeeDipsIntoReserve();
4295  testXChainDeleteDoor();
4296  testBadPublicKey();
4297  }
4298 };
4299 
4300 // -----------------------------------------------------------
4301 // -----------------------------------------------------------
4302 struct XChainSim_test : public beast::unit_test::suite,
4304 {
4305 private:
4306  static constexpr size_t num_signers = 5;
4307 
4308  // --------------------------------------------------
4309  enum class WithClaim { no, yes };
4310  struct Transfer
4311  {
4316  bool a2b; // direction of transfer
4317  WithClaim with_claim{WithClaim::no};
4318  uint32_t claim_id{0};
4320  };
4321 
4323  {
4328  bool a2b;
4329  uint32_t claim_id{0};
4331  };
4332 
4334  using BridgeID = BridgeDef const*;
4335 
4336  // tracking chain state
4337  // --------------------
4339  {
4340  STAmount startAmount{0};
4341  STAmount expectedDiff{0};
4342 
4343  void
4344  init(ENV& env, jtx::Account const& acct)
4345  {
4346  startAmount = env.balance(acct);
4347  expectedDiff = STAmount(0);
4348  }
4349 
4350  bool
4351  verify(ENV& env, jtx::Account const& acct) const
4352  {
4353  STAmount diff{env.balance(acct) - startAmount};
4354  bool check = diff == expectedDiff;
4355  return check;
4356  }
4357  };
4358 
4359  // --------------------------------------------------
4361  {
4365 
4367  : env(env), tx_fee(env.env_.current()->fees().base)
4368  {
4369  }
4370 
4371  void
4372  sendAttestations(size_t signer_idx, BridgeID bridge, ClaimVec& claims)
4373  {
4374  for (auto const& c : claims)
4375  {
4376  env.tx(c).close();
4377  spendFee(bridge->signers[signer_idx].account);
4378  }
4379  claims.clear();
4380  }
4381 
4382  uint32_t
4384  size_t signer_idx,
4385  BridgeID bridge,
4386  CreateClaimVec& claims)
4387  {
4388  size_t num_successful = 0;
4389  for (auto const& c : claims)
4390  {
4391  env.tx(c).close();
4392  if (env.ter() == tesSUCCESS)
4393  {
4394  counters[bridge].signers.push_back(signer_idx);
4395  num_successful++;
4396  }
4397  spendFee(bridge->signers[signer_idx].account);
4398  }
4399  claims.clear();
4400  return num_successful;
4401  }
4402 
4403  void
4405  {
4406  bool callback_called;
4407 
4408  // we have this "do {} while" loop because we want to process
4409  // all the account create which can reach quorum at this time
4410  // stamp.
4411  do
4412  {
4413  callback_called = false;
4414  for (size_t i = 0; i < signers_attns.size(); ++i)
4415  {
4416  for (auto& [bridge, claims] : signers_attns[i])
4417  {
4418  sendAttestations(i, bridge, claims.xfer_claims);
4419 
4420  auto& c = counters[bridge];
4421  auto& create_claims =
4422  claims.create_claims[c.claim_count];
4423  auto num_attns = create_claims.size();
4424  if (num_attns)
4425  {
4426  c.num_create_attn_sent += sendCreateAttestations(
4427  i, bridge, create_claims);
4428  }
4429  assert(claims.create_claims[c.claim_count].empty());
4430  }
4431  }
4432  for (auto& [bridge, c] : counters)
4433  {
4434  if (c.num_create_attn_sent >= bridge->quorum)
4435  {
4436  callback_called = true;
4437  c.create_callbacks[c.claim_count](c.signers);
4438  ++c.claim_count;
4439  c.num_create_attn_sent = 0;
4440  c.signers.clear();
4441  }
4442  }
4443  } while (callback_called);
4444  }
4445 
4446  void
4447  init(jtx::Account const& acct)
4448  {
4449  accounts[acct].init(env, acct);
4450  }
4451 
4452  void
4454  jtx::Account const& acct,
4455  STAmount amt,
4456  std::uint64_t divisor = 1)
4457  {
4458  if (amt.issue() != xrpIssue())
4459  return;
4460  auto it = accounts.find(acct);
4461  if (it == accounts.end())
4462  {
4463  accounts[acct].init(env, acct);
4464  // we just looked up the account, so expectedDiff == 0
4465  }
4466  else
4467  {
4468  it->second.expectedDiff +=
4469  (divisor == 1 ? amt
4470  : divide(
4471  amt,
4472  STAmount(amt.issue(), divisor),
4473  amt.issue()));
4474  }
4475  }
4476 
4477  void
4478  spend(jtx::Account const& acct, STAmount amt, std::uint64_t times = 1)
4479  {
4480  if (amt.issue() != xrpIssue())
4481  return;
4482  receive(
4483  acct,
4484  times == 1
4485  ? -amt
4486  : -multiply(
4487  amt, STAmount(amt.issue(), times), amt.issue()));
4488  }
4489 
4490  void
4491  transfer(jtx::Account const& from, jtx::Account const& to, STAmount amt)
4492  {
4493  spend(from, amt);
4494  receive(to, amt);
4495  }
4496 
4497  void
4498  spendFee(jtx::Account const& acct, size_t times = 1)
4499  {
4500  spend(acct, tx_fee, times);
4501  }
4502 
4503  bool
4504  verify() const
4505  {
4506  for (auto const& [acct, state] : accounts)
4507  if (!state.verify(env, acct))
4508  return false;
4509  return true;
4510  }
4511 
4513  {
4514  using complete_cb =
4516 
4517  uint32_t claim_id{0};
4518  uint32_t create_count{0}; // for account create. First should be 1
4519  uint32_t claim_count{
4520  0}; // for account create. Increments after quorum for
4521  // current create_count (starts at 1) is reached.
4522 
4523  uint32_t num_create_attn_sent{0}; // for current claim_count
4526  };
4527 
4528  struct Claims
4529  {
4532  };
4533 
4536 
4542  };
4543 
4545  {
4546  ChainStateTracker(ENV& a_env, ENV& b_env) : a_(a_env), b_(b_env)
4547  {
4548  }
4549 
4550  bool
4551  verify() const
4552  {
4553  return a_.verify() && b_.verify();
4554  }
4555 
4556  void
4558  {
4559  a_.sendAttestations();
4560  b_.sendAttestations();
4561  }
4562 
4563  void
4564  init(jtx::Account const& acct)
4565  {
4566  a_.init(acct);
4567  b_.init(acct);
4568  }
4569 
4572  };
4573 
4574  enum SmState {
4581  };
4582 
4583  enum Act_Flags { af_a2b = 1 << 0 };
4584 
4585  // --------------------------------------------------
4586  template <class T>
4587  class SmBase
4588  {
4589  public:
4591  const std::shared_ptr<ChainStateTracker>& chainstate,
4592  const BridgeDef& bridge)
4593  : bridge_(bridge), st_(chainstate)
4594  {
4595  }
4596 
4599  {
4600  return static_cast<T&>(*this).a2b() ? st_->a_ : st_->b_;
4601  }
4602 
4605  {
4606  return static_cast<T&>(*this).a2b() ? st_->b_ : st_->a_;
4607  }
4608 
4609  jtx::Account const&
4611  {
4612  return static_cast<T&>(*this).a2b() ? bridge_.doorA : bridge_.doorB;
4613  }
4614 
4615  jtx::Account const&
4617  {
4618  return static_cast<T&>(*this).a2b() ? bridge_.doorB : bridge_.doorA;
4619  }
4620 
4621  protected:
4624  };
4625 
4626  // --------------------------------------------------
4627  class SmCreateAccount : public SmBase<SmCreateAccount>
4628  {
4629  public:
4631 
4633  const std::shared_ptr<ChainStateTracker>& chainstate,
4634  const BridgeDef& bridge,
4635  AccountCreate create)
4636  : Base(chainstate, bridge)
4637  , sm_state(st_initial)
4638  , cr(std::move(create))
4639  {
4640  }
4641 
4642  bool
4643  a2b() const
4644  {
4645  return cr.a2b;
4646  }
4647 
4648  uint32_t
4650  {
4651  ChainStateTrack& st = srcState();
4652  jtx::Account const& srcdoor = srcDoor();
4653 
4654  st.env
4656  cr.from, bridge_.jvb, cr.to, cr.amt, cr.reward))
4657  .close(); // needed for claim_id sequence to be correct'
4658  st.spendFee(cr.from);
4659  st.transfer(cr.from, srcdoor, cr.amt);
4660  st.transfer(cr.from, srcdoor, cr.reward);
4661 
4662  return ++st.counters[&bridge_].create_count;
4663  }
4664 
4665  void
4666  attest(uint64_t time, uint32_t rnd)
4667  {
4668  ChainStateTrack& st = destState();
4669 
4670  // check all signers, but start at a random one
4671  size_t i;
4672  for (i = 0; i < num_signers; ++i)
4673  {
4674  size_t signer_idx = (rnd + i) % num_signers;
4675 
4676  if (!(cr.attested[signer_idx]))
4677  {
4678  // enqueue one attestation for this signer
4679  cr.attested[signer_idx] = true;
4680 
4681  st.signers_attns[signer_idx][&bridge_]
4682  .create_claims[cr.claim_id - 1]
4683  .emplace_back(create_account_attestation(
4684  bridge_.signers[signer_idx].account,
4685  bridge_.jvb,
4686  cr.from,
4687  cr.amt,
4688  cr.reward,
4689  bridge_.signers[signer_idx].account,
4690  cr.a2b,
4691  cr.claim_id,
4692  cr.to,
4693  bridge_.signers[signer_idx]));
4694  break;
4695  }
4696  }
4697 
4698  if (i == num_signers)
4699  return; // did not attest
4700 
4701  auto& counters = st.counters[&bridge_];
4702  if (counters.create_callbacks.size() < cr.claim_id)
4703  counters.create_callbacks.resize(cr.claim_id);
4704 
4705  auto complete_cb = [&](std::vector<size_t> const& signers) {
4706  auto num_attestors = signers.size();
4707  st.env.close();
4708  assert(
4709  num_attestors <=
4710  std::count(cr.attested.begin(), cr.attested.end(), true));
4711  assert(num_attestors >= bridge_.quorum);
4712  assert(cr.claim_id - 1 == counters.claim_count);
4713 
4714  auto r = cr.reward;
4715  auto reward = divide(r, STAmount(num_attestors), r.issue());
4716 
4717  for (auto i : signers)
4718  st.receive(bridge_.signers[i].account, reward);
4719 
4720  st.spend(dstDoor(), reward, num_attestors);
4721  st.transfer(dstDoor(), cr.to, cr.amt);
4722  st.env.env_.memoize(cr.to);
4723  sm_state = st_completed;
4724  };
4725 
4726  counters.create_callbacks[cr.claim_id - 1] = std::move(complete_cb);
4727  }
4728 
4729  SmState
4730  advance(uint64_t time, uint32_t rnd)
4731  {
4732  switch (sm_state)
4733  {
4734  case st_initial:
4735  cr.claim_id = issue_account_create();
4736  sm_state = st_attesting;
4737  break;
4738 
4739  case st_attesting:
4740  attest(time, rnd);
4741  break;
4742 
4743  default:
4744  assert(0);
4745  break;
4746 
4747  case st_completed:
4748  break; // will get this once
4749  }
4750  return sm_state;
4751  }
4752 
4753  private:
4756  };
4757 
4758  // --------------------------------------------------
4759  class SmTransfer : public SmBase<SmTransfer>
4760  {
4761  public:
4763 
4765  const std::shared_ptr<ChainStateTracker>& chainstate,
4766  const BridgeDef& bridge,
4767  Transfer xfer)
4768  : Base(chainstate, bridge)
4769  , xfer(std::move(xfer))
4770  , sm_state(st_initial)
4771  {
4772  }
4773 
4774  bool
4775  a2b() const
4776  {
4777  return xfer.a2b;
4778  }
4779 
4780  uint32_t
4782  {
4783  ChainStateTrack& st = destState();
4784 
4785  st.env
4787  xfer.to, bridge_.jvb, bridge_.reward, xfer.from))
4788  .close(); // needed for claim_id sequence to be
4789  // correct'
4790  st.spendFee(xfer.to);
4791  return ++st.counters[&bridge_].claim_id;
4792  }
4793 
4794  void
4796  {
4797  ChainStateTrack& st = srcState();
4798  jtx::Account const& srcdoor = srcDoor();
4799 
4800  if (xfer.amt.issue() != xrpIssue())
4801  {
4802  st.env.tx(pay(srcdoor, xfer.from, xfer.amt));
4803  st.spendFee(srcdoor);
4804  }
4805  st.env.tx(xchain_commit(
4806  xfer.from,
4807  bridge_.jvb,
4808  xfer.claim_id,
4809  xfer.amt,
4810  xfer.with_claim == WithClaim::yes
4811  ? std::nullopt
4812  : std::optional<jtx::Account>(xfer.finaldest)));
4813  st.spendFee(xfer.from);
4814  st.transfer(xfer.from, srcdoor, xfer.amt);
4815  }
4816 
4817  void
4819  {
4820  auto r = bridge_.reward;
4821  auto reward = divide(r, STAmount(bridge_.quorum), r.issue());
4822 
4823  for (size_t i = 0; i < num_signers; ++i)
4824  {
4825  if (xfer.attested[i])
4826  st.receive(bridge_.signers[i].account, reward);
4827  }
4828  st.spend(xfer.to, reward, bridge_.quorum);
4829  }
4830 
4831  bool
4832  attest(uint64_t time, uint32_t rnd)
4833  {
4834  ChainStateTrack& st = destState();
4835 
4836  // check all signers, but start at a random one
4837  for (size_t i = 0; i < num_signers; ++i)
4838  {
4839  size_t signer_idx = (rnd + i) % num_signers;
4840  if (!(xfer.attested[signer_idx]))
4841  {
4842  // enqueue one attestation for this signer
4843  xfer.attested[signer_idx] = true;
4844 
4845  st.signers_attns[signer_idx][&bridge_]
4846  .xfer_claims.emplace_back(claim_attestation(
4847  bridge_.signers[signer_idx].account,
4848  bridge_.jvb,
4849  xfer.from,
4850  xfer.amt,
4851  bridge_.signers[signer_idx].account,
4852  xfer.a2b,
4853  xfer.claim_id,
4854  xfer.with_claim == WithClaim::yes
4855  ? std::nullopt
4856  : std::optional<jtx::Account>(xfer.finaldest),
4857  bridge_.signers[signer_idx]));
4858  break;
4859  }
4860  }
4861 
4862  // return true if quorum was reached, false otherwise
4863  bool quorum =
4864  std::count(xfer.attested.begin(), xfer.attested.end(), true) >=
4865  bridge_.quorum;
4866  if (quorum && xfer.with_claim == WithClaim::no)
4867  {
4868  distribute_reward(st);
4869  st.transfer(dstDoor(), xfer.finaldest, xfer.amt);
4870  }
4871  return quorum;
4872  }
4873 
4874  void
4876  {
4877  ChainStateTrack& st = destState();
4878  st.env.tx(xchain_claim(
4879  xfer.to, bridge_.jvb, xfer.claim_id, xfer.amt, xfer.finaldest));
4880  distribute_reward(st);
4881  st.transfer(dstDoor(), xfer.finaldest, xfer.amt);
4882  st.spendFee(xfer.to);
4883  }
4884 
4885  SmState
4886  advance(uint64_t time, uint32_t rnd)
4887  {
4888  switch (sm_state)
4889  {
4890  case st_initial:
4891  xfer.claim_id = create_claim_id();
4892  sm_state = st_claimid_created;
4893  break;
4894 
4895  case st_claimid_created:
4896  commit();
4897  sm_state = st_attesting;
4898  break;
4899 
4900  case st_attesting:
4901  sm_state = attest(time, rnd)
4902  ? (xfer.with_claim == WithClaim::yes ? st_attested
4903  : st_completed)
4904  : st_attesting;
4905  break;
4906 
4907  case st_attested:
4908  assert(xfer.with_claim == WithClaim::yes);
4909  claim();
4910  sm_state = st_completed;
4911  break;
4912 
4913  default:
4914  case st_completed:
4915  assert(0); // should have been removed
4916  break;
4917  }
4918  return sm_state;
4919  }
4920 
4921  private:
4924  };
4925 
4926  // --------------------------------------------------
4929 
4931 
4932  void
4934  uint64_t time,
4935  const std::shared_ptr<ChainStateTracker>& chainstate,
4936  BridgeDef const& bridge,
4937  Transfer transfer)
4938  {
4939  sm_.emplace_back(
4940  time, SmTransfer(chainstate, bridge, std::move(transfer)));
4941  }
4942 
4943  void
4944  ac(uint64_t time,
4945  const std::shared_ptr<ChainStateTracker>& chainstate,
4946  BridgeDef const& bridge,
4947  AccountCreate ac)
4948  {
4949  sm_.emplace_back(
4950  time, SmCreateAccount(chainstate, bridge, std::move(ac)));
4951  }
4952 
4953 public:
4954  void
4957  bool verify_balances = true)
4958  {
4959  using namespace jtx;
4960  uint64_t time = 0;
4961  std::mt19937 gen(27); // Standard mersenne_twister_engine
4963 
4964  while (!sm_.empty())
4965  {
4966  ++time;
4967  for (auto it = sm_.begin(); it != sm_.end();)
4968  {
4969  auto vis = [&](auto& sm) {
4970  uint32_t rnd = distrib(gen);
4971  return sm.advance(time, rnd);
4972  };
4973  auto& [t, sm] = *it;
4974  if (t <= time && std::visit(vis, sm) == st_completed)
4975  it = sm_.erase(it);
4976  else
4977  ++it;
4978  }
4979 
4980  // send attestations
4981  st->sendAttestations();
4982 
4983  // make sure all transactions have been applied
4984  st->a_.env.close();
4985  st->b_.env.close();
4986 
4987  if (verify_balances)
4988  {
4989  BEAST_EXPECT(st->verify());
4990  }
4991  }
4992  }
4993 
4994  void
4996  {
4997  using namespace jtx;
4998 
4999  testcase("Bridge usage simulation");
5000 
5001  XEnv mcEnv(*this);
5002  XEnv scEnv(*this, true);
5003 
5004  auto st = std::make_shared<ChainStateTracker>(mcEnv, scEnv);
5005 
5006  // create 10 accounts + door funded on both chains, and store
5007  // in ChainStateTracker the initial amount of these accounts
5008  Account doorXRPLocking, doorUSDLocking, doorUSDIssuing;
5009 
5010  constexpr size_t num_acct = 10;
5011  auto a = [&doorXRPLocking, &doorUSDLocking, &doorUSDIssuing]() {
5012  using namespace std::literals;
5013  std::vector<Account> result;
5014  result.reserve(num_acct);
5015  for (int i = 0; i < num_acct; ++i)
5016  result.emplace_back(
5017  "a"s + std::to_string(i),
5018  (i % 2) ? KeyType::ed25519 : KeyType::secp256k1);
5019  result.emplace_back("doorXRPLocking");
5020  doorXRPLocking = result.back();
5021  result.emplace_back("doorUSDLocking");
5022  doorUSDLocking = result.back();
5023  result.emplace_back("doorUSDIssuing");
5024  doorUSDIssuing = result.back();
5025  return result;
5026  }();
5027 
5028  for (auto& acct : a)
5029  {
5030  STAmount amt{XRP(100000)};
5031 
5032  mcEnv.fund(amt, acct);
5033  scEnv.fund(amt, acct);
5034  }
5035  Account USDLocking{"USDLocking"};
5036  IOU usdLocking{USDLocking["USD"]};
5037  IOU usdIssuing{doorUSDIssuing["USD"]};
5038 
5039  mcEnv.fund(XRP(100000), USDLocking);
5040  mcEnv.close();
5041  mcEnv.tx(trust(doorUSDLocking, usdLocking(100000)));
5042  mcEnv.close();
5043  mcEnv.tx(pay(USDLocking, doorUSDLocking, usdLocking(50000)));
5044 
5045  for (int i = 0; i < a.size(); ++i)
5046  {
5047  auto& acct{a[i]};
5048  if (i < num_acct)
5049  {
5050  mcEnv.tx(trust(acct, usdLocking(100000)));
5051  scEnv.tx(trust(acct, usdIssuing(100000)));
5052  }
5053  st->init(acct);
5054  }
5055  for (auto& s : signers)
5056  st->init(s.account);
5057 
5058  st->b_.init(Account::master);
5059 
5060  // also create some unfunded accounts
5061  constexpr size_t num_ua = 20;
5062  auto ua = []() {
5063  using namespace std::literals;
5064  std::vector<Account> result;
5065  result.reserve(num_ua);
5066  for (int i = 0; i < num_ua; ++i)
5067  result.emplace_back(
5068  "ua"s + std::to_string(i),
5069  (i % 2) ? KeyType::ed25519 : KeyType::secp256k1);
5070  return result;
5071  }();
5072 
5073  // initialize a bridge from a BridgeDef
5074  auto initBridge = [&mcEnv, &scEnv, &st](BridgeDef& bd) {
5075  bd.initBridge(mcEnv, scEnv);
5076  st->a_.spendFee(bd.doorA, 2);
5077  st->b_.spendFee(bd.doorB, 2);
5078  };
5079 
5080  // create XRP -> XRP bridge
5081  // ------------------------
5082  BridgeDef xrp_b{
5083  doorXRPLocking,
5084  xrpIssue(),
5086  xrpIssue(),
5087  XRP(1),
5088  XRP(20),
5089  quorum,
5090  signers,
5091  Json::nullValue};
5092 
5093  initBridge(xrp_b);
5094 
5095  // create USD -> USD bridge
5096  // ------------------------
5097  BridgeDef usd_b{
5098  doorUSDLocking,
5099  usdLocking,
5100  doorUSDIssuing,
5101  usdIssuing,
5102  XRP(1),
5103  XRP(20),
5104  quorum,
5105  signers,
5106  Json::nullValue};
5107 
5108  initBridge(usd_b);
5109 
5110  // try a single account create + transfer to validate the simulation
5111  // engine. Do the transfer 8 time steps after the account create, to
5112  // give time enough for ua[0] to be funded now so it can reserve
5113  // the claimID
5114  // -----------------------------------------------------------------
5115  ac(0, st, xrp_b, {a[0], ua[0], XRP(777), xrp_b.reward, true});
5116  xfer(8, st, xrp_b, {a[0], ua[0], a[2], XRP(3), true});
5117  runSimulation(st);
5118 
5119  // try the same thing in the other direction
5120  // -----------------------------------------
5121  ac(0, st, xrp_b, {a[0], ua[0], XRP(777), xrp_b.reward, false});
5122  xfer(8, st, xrp_b, {a[0], ua[0], a[2], XRP(3), false});
5123  runSimulation(st);
5124 
5125  // run multiple XRP transfers
5126  // --------------------------
5127  xfer(0, st, xrp_b, {a[0], a[0], a[1], XRP(6), true, WithClaim::no});
5128  xfer(1, st, xrp_b, {a[0], a[0], a[1], XRP(8), false, WithClaim::no});
5129  xfer(1, st, xrp_b, {a[1], a[1], a[1], XRP(1), true});
5130  xfer(2, st, xrp_b, {a[0], a[0], a[1], XRP(3), false});
5131  xfer(2, st, xrp_b, {a[1], a[1], a[1], XRP(5), false});
5132  xfer(2, st, xrp_b, {a[0], a[0], a[1], XRP(7), false, WithClaim::no});
5133  xfer(2, st, xrp_b, {a[1], a[1], a[1], XRP(9), true});
5134  runSimulation(st);
5135 
5136  // run one USD transfer
5137  // --------------------
5138  xfer(0, st, usd_b, {a[0], a[1], a[2], usdLocking(3), true});
5139  runSimulation(st);
5140 
5141  // run multiple USD transfers
5142  // --------------------------
5143  xfer(0, st, usd_b, {a[0], a[0], a[1], usdLocking(6), true});
5144  xfer(1, st, usd_b, {a[0], a[0], a[1], usdIssuing(8), false});
5145  xfer(1, st, usd_b, {a[1], a[1], a[1], usdLocking(1), true});
5146  xfer(2, st, usd_b, {a[0], a[0], a[1], usdIssuing(3), false});
5147  xfer(2, st, usd_b, {a[1], a[1], a[1], usdIssuing(5), false});
5148  xfer(2, st, usd_b, {a[0], a[0], a[1], usdIssuing(7), false});
5149  xfer(2, st, usd_b, {a[1], a[1], a[1], usdLocking(9), true});
5150  runSimulation(st);
5151 
5152  // run mixed transfers
5153  // -------------------
5154  xfer(0, st, xrp_b, {a[0], a[0], a[0], XRP(1), true});
5155  xfer(0, st, usd_b, {a[1], a[3], a[3], usdIssuing(3), false});
5156  xfer(0, st, usd_b, {a[3], a[2], a[1], usdIssuing(5), false});
5157 
5158  xfer(1, st, xrp_b, {a[0], a[0], a[0], XRP(4), false});
5159  xfer(1, st, xrp_b, {a[1], a[1], a[0], XRP(8), true});
5160  xfer(1, st, usd_b, {a[4], a[1], a[1], usdLocking(7), true});
5161 
5162  xfer(3, st, xrp_b, {a[1], a[1], a[0], XRP(7), true});
5163  xfer(3, st, xrp_b, {a[0], a[4], a[3], XRP(2), false});
5164  xfer(3, st, xrp_b, {a[1], a[1], a[0], XRP(9), true});
5165  xfer(3, st, usd_b, {a[3], a[1], a[1], usdIssuing(11), false});
5166  runSimulation(st);
5167 
5168  // run multiple account create to stress attestation batching
5169  // ----------------------------------------------------------
5170  ac(0, st, xrp_b, {a[0], ua[1], XRP(301), xrp_b.reward, true});
5171  ac(0, st, xrp_b, {a[1], ua[2], XRP(302), xrp_b.reward, true});
5172  ac(1, st, xrp_b, {a[0], ua[3], XRP(303), xrp_b.reward, true});
5173  ac(2, st, xrp_b, {a[1], ua[4], XRP(304), xrp_b.reward, true});
5174  ac(3, st, xrp_b, {a[0], ua[5], XRP(305), xrp_b.reward, true});
5175  ac(4, st, xrp_b, {a[1], ua[6], XRP(306), xrp_b.reward, true});
5176  ac(6, st, xrp_b, {a[0], ua[7], XRP(307), xrp_b.reward, true});
5177  ac(7, st, xrp_b, {a[2], ua[8], XRP(308), xrp_b.reward, true});
5178  ac(9, st, xrp_b, {a[0], ua[9], XRP(309), xrp_b.reward, true});
5179  ac(9, st, xrp_b, {a[0], ua[9], XRP(309), xrp_b.reward, true});
5180  ac(10, st, xrp_b, {a[0], ua[10], XRP(310), xrp_b.reward, true});
5181  ac(12, st, xrp_b, {a[0], ua[11], XRP(311), xrp_b.reward, true});
5182  ac(12, st, xrp_b, {a[3], ua[12], XRP(312), xrp_b.reward, true});
5183  ac(12, st, xrp_b, {a[4], ua[13], XRP(313), xrp_b.reward, true});
5184  ac(12, st, xrp_b, {a[3], ua[14], XRP(314), xrp_b.reward, true});
5185  ac(12, st, xrp_b, {a[6], ua[15], XRP(315), xrp_b.reward, true});
5186  ac(13, st, xrp_b, {a[7], ua[16], XRP(316), xrp_b.reward, true});
5187  ac(15, st, xrp_b, {a[3], ua[17], XRP(317), xrp_b.reward, true});
5188  runSimulation(st, true); // balances verification working now.
5189  }
5190 
5191  void
5192  run() override
5193  {
5194  testXChainSimulation();
5195  }
5196 };
5197 
5198 BEAST_DEFINE_TESTSUITE(XChain, app, ripple);
5199 BEAST_DEFINE_TESTSUITE(XChainSim, app, ripple);
5200 
5201 } // namespace ripple::test
ripple::test::XChainSim_test::ChainStateTrack::BridgeCounters::signers
std::vector< size_t > signers
Definition: XChain_test.cpp:4524
ripple::test::jtx::XChainBridgeObjects::split_reward_everyone
const STAmount split_reward_everyone
Definition: xchain_bridge.h:196
ripple::test::BridgeDef
Definition: XChain_test.cpp:356
std::apply
T apply(T... args)
ripple::test::SEnv::account
std::shared_ptr< SLE const > account(jtx::Account const &account)
Definition: XChain_test.cpp:147
ripple::test::XChainSim_test::Transfer::a2b
bool a2b
Definition: XChain_test.cpp:4316
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::test::XChainSim_test::ChainStateTrack::tx_fee
STAmount tx_fee
Definition: XChain_test.cpp:4541
ripple::test::SEnv::close
SEnv & close()
Definition: XChain_test.cpp:71
ripple::test::jtx::xchain_commit
Json::Value xchain_commit(Account const &acc, Json::Value const &bridge, std::uint32_t claimID, AnyAmount const &amt, std::optional< Account > const &dst)
Definition: xchain_bridge.cpp:134
ripple::tecXCHAIN_BAD_CLAIM_ID
@ tecXCHAIN_BAD_CLAIM_ID
Definition: TER.h:319
ripple::test::jtx::claim
Json::Value claim(AccountID const &account, uint256 const &channel, std::optional< STAmount > const &balance, std::optional< STAmount > const &amount, std::optional< Slice > const &signature, std::optional< PublicKey > const &pk)
Definition: TestHelpers.cpp:293
ripple::test::XChain_test::testXChainCreateBridgeMatrix
void testXChainCreateBridgeMatrix()
Definition: XChain_test.cpp:690
ripple::test::SEnv::caClaimID
std::shared_ptr< SLE const > caClaimID(Json::Value const &jvb, std::uint64_t seq)
Definition: XChain_test.cpp:190
ripple::test::XChainSim_test::ac
void ac(uint64_t time, const std::shared_ptr< ChainStateTracker > &chainstate, BridgeDef const &bridge, AccountCreate ac)
Definition: XChain_test.cpp:4944
ripple::Issue
A currency issued by an account.
Definition: Issue.h:35
fstream
ripple::asfDepositAuth
constexpr std::uint32_t asfDepositAuth
Definition: TxFlags.h:82
ripple::test::jtx::XChainBridgeObjects::scUSD
const IOU scUSD
Definition: xchain_bridge.h:181
ripple::test::XChain_test::testXChainBridgeCreateConstraints
void testXChainBridgeCreateConstraints()
Definition: XChain_test.cpp:559
std::string
STL class.
std::shared_ptr
STL class.
ripple::test::XChainSim_test::ChainStateTrack::accounts
std::map< jtx::Account, AccountStateTrack > accounts
Definition: XChain_test.cpp:4538
std::uniform_int_distribution
ripple::test::XChain_test::testXChainCreateAccount
void testXChainCreateAccount()
Definition: XChain_test.cpp:3948
ripple::test::XChainSim_test::SmTransfer::attest
bool attest(uint64_t time, uint32_t rnd)
Definition: XChain_test.cpp:4832
ripple::test::XChainSim_test::sm_
SmCont sm_
Definition: XChain_test.cpp:4930
std::exception
STL class.
ripple::test::XChain_test::txFee
XRPAmount txFee()
Definition: XChain_test.cpp:399
ripple::tecXCHAIN_CLAIM_NO_QUORUM
@ tecXCHAIN_CLAIM_NO_QUORUM
Definition: TER.h:320
ripple::STXChainBridge::ChainType
ChainType
Definition: STXChainBridge.h:42
ripple::test::BridgeDef::issueB
Issue issueB
Definition: XChain_test.cpp:361
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
std::list< std::pair< uint64_t, Sm > >
ripple::test::jtx::XChainBridgeObjects::features
const FeatureBitset features
Definition: xchain_bridge.h:187
ripple::test::BalanceTransfer::has_not_happened
bool has_not_happened()
Definition: XChain_test.cpp:349
ripple::test::SEnv::txFee
XRPAmount txFee()
Definition: XChain_test.cpp:141
ripple::test::XChainSim_test::ChainStateTrack::env
ENV & env
Definition: XChain_test.cpp:4537
ripple::test::XChainSim_test::SmTransfer::create_claim_id
uint32_t create_claim_id()
Definition: XChain_test.cpp:4781
ripple::test::SEnv::claimID
std::uint64_t claimID(Json::Value const &jvb)
Definition: XChain_test.cpp:178
ripple::test::XChainSim_test::AccountStateTrack
Definition: XChain_test.cpp:4338
ripple::test::XChain_test::testXChainAddAccountCreateNonBatchAttestation
void testXChainAddAccountCreateNonBatchAttestation()
Definition: XChain_test.cpp:2617
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:350
ripple::terNO_LINE
@ terNO_LINE
Definition: TER.h:212
functional
ripple::test::XChainSim_test::SmCreateAccount::SmCreateAccount
SmCreateAccount(const std::shared_ptr< ChainStateTracker > &chainstate, const BridgeDef &bridge, AccountCreate create)
Definition: XChain_test.cpp:4632
ripple::test::Balance::env_
T & env_
Definition: XChain_test.cpp:252
ripple::test::jtx::claim_attestations
JValueVec claim_attestations(jtx::Account const &submittingAccount, Json::Value const &jvBridge, jtx::Account const &sendingAccount, jtx::AnyAmount const &sendingAmount, std::vector< jtx::Account > const &rewardAccounts, bool wasLockingChainSend, std::uint64_t claimID, std::optional< jtx::Account > const &dst, std::vector< jtx::signer > const &signers, std::size_t const numAtts, std::size_t const fromIdx)
Definition: xchain_bridge.cpp:306
ripple::test::XChain_test::testXChainAddAttestation
void testXChainAddAttestation()
Definition: XChain_test.cpp:1515
ripple::test::XChainSim_test::AccountStateTrack::verify
bool verify(ENV &env, jtx::Account const &acct) const
Definition: XChain_test.cpp:4351
std::vector::reserve
T reserve(T... args)
ripple::test::XChainSim_test::AccountCreate::a2b
bool a2b
Definition: XChain_test.cpp:4328
ripple::test::XChain_test::testXChainDeleteDoor
void testXChainDeleteDoor()
Definition: XChain_test.cpp:4163
ripple::test::jtx::XChainBridgeObjects::scuCarol
const Account scuCarol
Definition: xchain_bridge.h:177
ripple::test::BalanceTransfer::BalanceTransfer
BalanceTransfer(T &env, jtx::Account const &from_acct, jtx::Account const &to_acct, jtx::Account const &payor, jtx::Account const *payees, size_t num_payees, bool withClaim)
Definition: XChain_test.cpp:280
ripple::test::SEnv::ter
TER ter() const
Definition: XChain_test.cpp:117
ripple::test::XChainSim_test::SmCreateAccount::issue_account_create
uint32_t issue_account_create()
Definition: XChain_test.cpp:4649
ripple::test::SEnv::fund
SEnv & fund(STAmount const &amount, Arg const &arg, Args const &... args)
Definition: XChain_test.cpp:93
ripple::test::jtx::XChainBridgeObjects::tiny_reward_remainder
const STAmount tiny_reward_remainder
Definition: xchain_bridge.h:200
ripple::test::XChainSim_test::SmBase::SmBase
SmBase(const std::shared_ptr< ChainStateTracker > &chainstate, const BridgeDef &bridge)
Definition: XChain_test.cpp:4590
ripple::test::Balance::Balance
Balance(T &env, jtx::Account const &account)
Definition: XChain_test.cpp:255
ripple::test::XChainSim_test::ChainStateTrack::receive
void receive(jtx::Account const &acct, STAmount amt, std::uint64_t divisor=1)
Definition: XChain_test.cpp:4453
vector
ripple::test::jtx::Env::enableFeature
void enableFeature(uint256 const feature)
Definition: Env.cpp:476
std::vector::size
T size(T... args)
ripple::test::XChain_test::testXChainCreateBridge
void testXChainCreateBridge()
Definition: XChain_test.cpp:436
ripple::STXChainBridge::ChainType::issuing
@ issuing
ripple::test::BridgeDef::minAccountCreate
STAmount minAccountCreate
Definition: XChain_test.cpp:363
ripple::test::BalanceTransfer::payor_
balance payor_
Definition: XChain_test.cpp:276
ripple::test::jtx::XChainBridgeObjects::jvb
Json::Value jvb
Definition: xchain_bridge.h:184
ripple::test::XChainSim_test::SmTransfer
Definition: XChain_test.cpp:4759
ripple::temXCHAIN_EQUAL_DOOR_ACCOUNTS
@ temXCHAIN_EQUAL_DOOR_ACCOUNTS
Definition: TER.h:130
ripple::test::XChainSim_test::ChainStateTracker::b_
ChainStateTrack b_
Definition: XChain_test.cpp:4571
ripple::test::jtx::JValueVec
std::vector< Json::Value > JValueVec
Definition: xchain_bridge.h:34
ripple::test::XChain_test::testXChainCommit
void testXChainCommit()
Definition: XChain_test.cpp:1379
ripple::test::jtx::XChainBridgeObjects::scuBob
const Account scuBob
Definition: xchain_bridge.h:176
ripple::test::jtx::XChainBridgeObjects::tiny_reward
const STAmount tiny_reward
Definition: xchain_bridge.h:198
ripple::tecDST_TAG_NEEDED
@ tecDST_TAG_NEEDED
Definition: TER.h:290
ripple::test::XChainSim_test::SmTransfer::SmTransfer
SmTransfer(const std::shared_ptr< ChainStateTracker > &chainstate, const BridgeDef &bridge, Transfer xfer)
Definition: XChain_test.cpp:4764
ripple::STXChainBridge::ChainType::locking
@ locking
ripple::test::jtx::port_increment
std::unique_ptr< Config > port_increment(std::unique_ptr< Config >, int)
adjust the default configured server ports by a specified value
Definition: envconfig.cpp:128
random
ripple::test::XChainSim_test::ChainStateTrack::counters
std::map< BridgeID, BridgeCounters > counters
Definition: XChain_test.cpp:4540
ripple::test::jtx::XChainBridgeObjects::scGw
const Account scGw
Definition: xchain_bridge.h:164
ripple::tecXCHAIN_NO_CLAIM_ID
@ tecXCHAIN_NO_CLAIM_ID
Definition: TER.h:318
ripple::test::BalanceTransfer::payees_received
bool payees_received(STAmount const &reward) const
Definition: XChain_test.cpp:321
ripple::test::jtx::UT_XCHAIN_DEFAULT_QUORUM
constexpr std::size_t UT_XCHAIN_DEFAULT_QUORUM
Definition: xchain_bridge.h:37
ripple::transToken
std::string transToken(TER code)
Definition: TER.cpp:241
ripple::test::XChainSim_test::testXChainSimulation
void testXChainSimulation()
Definition: XChain_test.cpp:4995
ripple::test::XChain_test::testBadPublicKey
void testBadPublicKey()
Definition: XChain_test.cpp:4213
ripple::test::jtx::claim_attestation
Json::Value claim_attestation(jtx::Account const &submittingAccount, Json::Value const &jvBridge, jtx::Account const &sendingAccount, jtx::AnyAmount const &sendingAmount, jtx::Account const &rewardAccount, bool wasLockingChainSend, std::uint64_t claimID, std::optional< jtx::Account > const &dst, jtx::signer const &signer)
Definition: xchain_bridge.cpp:199
ripple::test::SEnv::multiTx
SEnv & multiTx(jtx::JValueVec &&jvv, FN const &... fN)
Definition: XChain_test.cpp:109
tuple
ripple::test::XChain_test::testXChainModifyBridge
void testXChainModifyBridge()
Definition: XChain_test.cpp:982
ripple::keylet::xChainClaimID
Keylet xChainClaimID(STXChainBridge const &bridge, std::uint64_t seq)
Definition: Indexes.cpp:414
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::bridge_modify
Json::Value bridge_modify(Account const &acc, Json::Value const &bridge, std::optional< STAmount > const &reward, std::optional< STAmount > const &minAccountCreate)
Definition: xchain_bridge.cpp:92
ripple::test::XChainSim_test::SmTransfer::sm_state
SmState sm_state
Definition: XChain_test.cpp:4923
ripple::test::jtx::XChainBridgeObjects::tiny_reward_split
const STAmount tiny_reward_split
Definition: xchain_bridge.h:199
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:242
std::vector::back
T back(T... args)
std::function
ripple::test::XChainSim_test::ChainStateTrack::Claims
Definition: XChain_test.cpp:4528
ripple::test::SEnv::enableFeature
SEnv & enableFeature(uint256 const feature)
Definition: XChain_test.cpp:78
std::all_of
T all_of(T... args)
ripple::test::XChainSim_test::SmBase::destState
ChainStateTrack & destState()
Definition: XChain_test.cpp:4604
ripple::test::jtx::XChainBridgeObjects::mcCarol
const Account mcCarol
Definition: xchain_bridge.h:158
ripple::test::XChainSim_test::SmBase::srcState
ChainStateTrack & srcState()
Definition: XChain_test.cpp:4598
std::tmpnam
T tmpnam(T... args)
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:49
ripple::test::XChainSim_test::SmBase::srcDoor
jtx::Account const & srcDoor()
Definition: XChain_test.cpp:4610
ripple::SField::getJsonName
Json::StaticString const & getJsonName() const
Definition: SField.h:214
ripple::test::jtx::create_account_attestation
Json::Value create_account_attestation(jtx::Account const &submittingAccount, Json::Value const &jvBridge, jtx::Account const &sendingAccount, jtx::AnyAmount const &sendingAmount, jtx::AnyAmount const &rewardAmount, jtx::Account const &rewardAccount, bool wasLockingChainSend, std::uint64_t createCount, jtx::Account const &dst, jtx::signer const &signer)
Definition: xchain_bridge.cpp:251
ripple::test::XChainSim_test::AccountCreate::amt
STAmount amt
Definition: XChain_test.cpp:4326
ripple::sfXChainAccountClaimCount
const SF_UINT64 sfXChainAccountClaimCount
ripple::test::XChainSim_test::Transfer::finaldest
jtx::Account finaldest
Definition: XChain_test.cpp:4314
ripple::temBAD_ISSUER
@ temBAD_ISSUER
Definition: TER.h:92
ripple::test::XChain_test::testXChainClaim
void testXChainClaim()
Definition: XChain_test.cpp:2692
ripple::test::SEnv::disableFeature
SEnv & disableFeature(uint256 const feature)
Definition: XChain_test.cpp:85
iostream
ripple::test::XChainSim_test::ChainStateTrack::Claims::xfer_claims
ClaimVec xfer_claims
Definition: XChain_test.cpp:4530
ripple::test::XChain_test::testXChainAddClaimNonBatchAttestation
void testXChainAddClaimNonBatchAttestation()
Definition: XChain_test.cpp:2388
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:163
ripple::test::jtx::Env::ter
TER ter() const
Return the TER for the last JTx.
Definition: Env.h:526
std::vector::front
T front(T... args)
ripple::test::jtx::signer
A signer in a SignerList.
Definition: multisign.h:35
ripple::test::XChainSim_test::SmCreateAccount::sm_state
SmState sm_state
Definition: XChain_test.cpp:4754
ripple::test::XChainSim_test::SmCreateAccount::attest
void attest(uint64_t time, uint32_t rnd)
Definition: XChain_test.cpp:4666
ripple::test::jtx::XChainBridgeObjects::xrp_dust
const STAmount xrp_dust
Definition: xchain_bridge.h:203
ripple::temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT
@ temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT
Definition: TER.h:135
ripple::test::XChainSim_test::SmBase
Definition: XChain_test.cpp:4587
ripple::test::Balance::diff
STAmount diff() const
Definition: XChain_test.cpp:261
ripple::test::XChain_test::run
void run() override
Definition: XChain_test.cpp:4280
ripple::sfXChainClaimID
const SF_UINT64 sfXChainClaimID
ripple::temXCHAIN_BRIDGE_BAD_ISSUES
@ temXCHAIN_BRIDGE_BAD_ISSUES
Definition: TER.h:132
ripple::test::SEnv::bridge
std::shared_ptr< SLE const > bridge(Json::Value const &jvb)
Definition: XChain_test.cpp:153
ripple::test::XChainSim_test::xfer
void xfer(uint64_t time, const std::shared_ptr< ChainStateTracker > &chainstate, BridgeDef const &bridge, Transfer transfer)
Definition: XChain_test.cpp:4933
ripple::test::jtx::xchain_claim
Json::Value xchain_claim(Account const &acc, Json::Value const &bridge, std::uint32_t claimID, AnyAmount const &amt, Account const &dst)
Definition: xchain_bridge.cpp:156
std::mt19937
ripple::test::BridgeDef::signers
std::vector< jtx::signer > const & signers
Definition: XChain_test.cpp:365
ripple::divide
STAmount divide(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:86
std::cout
ripple::KeyType::ed25519
@ ed25519
ripple::test::SEnv::tx
SEnv & tx(JsonValue &&jv, FN const &... fN)
Definition: XChain_test.cpp:101
ripple::test::XChainSim_test::st_attesting
@ st_attesting
Definition: XChain_test.cpp:4577
ripple::base_uint< 256 >
ripple::test::jtx::XChainBridgeObjects::reward
const STAmount reward
Definition: xchain_bridge.h:194
ripple::test::XChainSim_test::AccountCreate
Definition: XChain_test.cpp:4322
ripple::tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR
@ tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR
Definition: TER.h:332
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:110
ripple::test::XChainSim_test::Transfer::from
jtx::Account from
Definition: XChain_test.cpp:4312
ripple::test::jtx::XChainBridgeObjects::scCarol
const Account scCarol
Definition: xchain_bridge.h:163
ripple::test::XChainSim_test::AccountCreate::from
jtx::Account from
Definition: XChain_test.cpp:4324
ripple::test::jtx::XChainBridgeObjects::scDoor
const Account scDoor
Definition: xchain_bridge.h:160
ripple::test::BridgeDef::issueA
Issue issueA
Definition: XChain_test.cpp:359
ripple::test::XChainSim_test::SmTransfer::advance
SmState advance(uint64_t time, uint32_t rnd)
Definition: XChain_test.cpp:4886
ripple::asfDisableMaster
constexpr std::uint32_t asfDisableMaster
Definition: TxFlags.h:77
ripple::test::XChainSim_test::AccountCreate::reward
STAmount reward
Definition: XChain_test.cpp:4327
ripple::sfSignatureReward
const SF_AMOUNT sfSignatureReward
ripple::test::BridgeDef::doorB
jtx::Account doorB
Definition: XChain_test.cpp:360
ripple::test::jtx::signers
Json::Value signers(Account const &account, std::uint32_t quorum, std::vector< signer > const &v)
Definition: multisign.cpp:35
ripple::test::BridgeDef::doorA
jtx::Account doorA
Definition: XChain_test.cpp:358
ripple::test::XChainSim_test::ChainStateTrack::BridgeCounters::create_callbacks
std::vector< complete_cb > create_callbacks
Definition: XChain_test.cpp:4525
ripple::test::jtx::XChainBridgeObjects::mcGw
const Account mcGw
Definition: xchain_bridge.h:159
ripple::test::BalanceTransfer::from_
balance from_
Definition: XChain_test.cpp:274
ripple::test::jtx::XChainBridgeObjects::mcUSD
const IOU mcUSD
Definition: xchain_bridge.h:180
std::ofstream
STL class.
ripple::test::SEnv::claimCount
std::uint64_t claimCount(Json::Value const &jvb)
Definition: XChain_test.cpp:172
ripple::test::Balance::startAmount
STAmount startAmount
Definition: XChain_test.cpp:253
ripple::tecDUPLICATE
@ tecDUPLICATE
Definition: TER.h:296
ripple::test::XChainSim_test::ChainStateTrack::ChainStateTrack
ChainStateTrack(ENV &env)
Definition: XChain_test.cpp:4366
ripple::keylet::bridge
Keylet bridge(STXChainBridge const &bridge, STXChainBridge::ChainType chainType)
Definition: Indexes.cpp:401
ripple::test::jtx::XChainBridgeObjects::scReward
const Account scReward
Definition: xchain_bridge.h:166
ripple::Application::config
virtual Config & config()=0
ripple::TERSubset< CanCvtToTER >
ripple::test::XChainSim_test::ChainStateTrack::transfer
void transfer(jtx::Account const &from, jtx::Account const &to, STAmount amt)
Definition: XChain_test.cpp:4491
ripple::test::XChainSim_test::run
void run() override
Definition: XChain_test.cpp:5192
ripple::test::jtx::XChainBridgeObjects::att_create_acct_vec
JValueVec att_create_acct_vec(std::uint64_t createCount, jtx::AnyAmount const &amt, jtx::Account const &dst, std::size_t const numAtts, std::size_t const fromIdx=0)
Definition: xchain_bridge.h:219
ripple::test::BalanceTransfer::check_most_balances
bool check_most_balances(STAmount const &amt, STAmount const &reward)
Definition: XChain_test.cpp:330
ripple::test::jtx::XChainBridgeObjects::split_reward_quorum
const STAmount split_reward_quorum
Definition: xchain_bridge.h:195
ripple::test::SEnv::balance
STAmount balance(jtx::Account const &account, Issue const &issue) const
Definition: XChain_test.cpp:129
ripple::test::XChainSim_test::ChainStateTrack::sendCreateAttestations
uint32_t sendCreateAttestations(size_t signer_idx, BridgeID bridge, CreateClaimVec &claims)
Definition: XChain_test.cpp:4383
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
std::to_string
T to_string(T... args)
ripple::test::BalanceTransfer::reward_accounts
std::vector< balance > reward_accounts
Definition: XChain_test.cpp:277
ripple::test::XChain_test::testXChainBridgeExtraFields
void testXChainBridgeExtraFields()
Definition: XChain_test.cpp:405
ripple::test::Balance::account_
jtx::Account const & account_
Definition: XChain_test.cpp:251
std::array< bool, num_signers >
ripple::test::jtx::txflags
Set the flags on a JTx.
Definition: txflags.h:30
ripple::test::jtx::XChainBridgeObjects::one_xrp
const STAmount one_xrp
Definition: xchain_bridge.h:202
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::XChainSim_test::SmCreateAccount::advance
SmState advance(uint64_t time, uint32_t rnd)
Definition: XChain_test.cpp:4730
ripple::STAmount
Definition: STAmount.h:46
ripple::tecUNFUNDED_PAYMENT
@ tecUNFUNDED_PAYMENT
Definition: TER.h:266
ripple::test::XChainSim_test::ChainStateTracker::ChainStateTracker
ChainStateTracker(ENV &a_env, ENV &b_env)
Definition: XChain_test.cpp:4546
ripple::test::XChainSim_test::WithClaim
WithClaim
Definition: XChain_test.cpp:4309
ripple::tecXCHAIN_ACCOUNT_CREATE_PAST
@ tecXCHAIN_ACCOUNT_CREATE_PAST
Definition: TER.h:328
ripple::test::BalanceTransfer::has_happened
bool has_happened(STAmount const &amt, STAmount const &reward, bool check_payer=true)
Definition: XChain_test.cpp:337
std::list::erase
T erase(T... args)
ripple::test::SEnv::claimID
std::shared_ptr< SLE const > claimID(Json::Value const &jvb, std::uint64_t seq)
Definition: XChain_test.cpp:184
ripple::test::XChainSim_test::ChainStateTracker::verify
bool verify() const
Definition: XChain_test.cpp:4551
ripple::ValStatus::current
@ current
This was a new validation and was added.
ripple::temBAD_AMOUNT
@ temBAD_AMOUNT
Definition: TER.h:88
ripple::sfAttestationSignerAccount
const SF_ACCOUNT sfAttestationSignerAccount
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:71
std::uint32_t
ripple::test::BridgeDef::initBridge
void initBridge(ENV &mcEnv, ENV &scEnv)
Definition: XChain_test.cpp:370
ripple::test::Balance
Definition: XChain_test.cpp:249
ripple::test::jtx::XChainBridgeObjects::scAttester
const Account scAttester
Definition: xchain_bridge.h:165
ripple::test::XChainSim_test::BridgeID
BridgeDef const * BridgeID
Definition: XChain_test.cpp:4334
ripple::test::jtx::Account::master
static const Account master
The master account.
Definition: Account.h:47
std::map< uint32_t, CreateClaimVec >
ripple::test::XChainSim_test::ChainStateTrack::init
void init(jtx::Account const &acct)
Definition: XChain_test.cpp:4447
ripple::featureXChainBridge
const uint256 featureXChainBridge
ripple::test::BridgeDef::reward
STAmount reward
Definition: XChain_test.cpp:362
ripple::test::XChainSim_test::st_attested
@ st_attested
Definition: XChain_test.cpp:4578
ripple::test::XChainSim_test::ChainStateTrack::BridgeCounters
Definition: XChain_test.cpp:4512
ripple::test::SEnv::reserve
XRPAmount reserve(std::uint32_t count)
Definition: XChain_test.cpp:135
ripple::test::XChainSim_test::ChainStateTrack::sendAttestations
void sendAttestations(size_t signer_idx, BridgeID bridge, ClaimVec &claims)
Definition: XChain_test.cpp:4372
ripple::test::jtx::UT_XCHAIN_DEFAULT_NUM_SIGNERS
constexpr std::size_t UT_XCHAIN_DEFAULT_NUM_SIGNERS
Definition: xchain_bridge.h:36
ripple::test::XChainSim_test::runSimulation
void runSimulation(std::shared_ptr< ChainStateTracker > const &st, bool verify_balances=true)
Definition: XChain_test.cpp:4955
ripple::tfFillOrKill
constexpr std::uint32_t tfFillOrKill
Definition: TxFlags.h:96
ripple::test::SEnv
Definition: XChain_test.cpp:56
ripple::test::jtx::fee
Set the fee on a JTx.
Definition: fee.h:35
ripple::STXChainBridge
Definition: STXChainBridge.h:32
ripple::KeyType::secp256k1
@ secp256k1
ripple::test::jtx::XChainBridgeObjects::alt_signers
const std::vector< signer > alt_signers
Definition: xchain_bridge.h:189
ripple::test::XChainSim_test::SmTransfer::xfer
Transfer xfer
Definition: XChain_test.cpp:4922
ripple::multiply
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:47
ripple::test::XChainSim_test::ChainStateTrack::spend
void spend(jtx::Account const &acct, STAmount amt, std::uint64_t times=1)
Definition: XChain_test.cpp:4478
ripple::test::XChainSim_test::SmTransfer::claim
void claim()
Definition: XChain_test.cpp:4875
ripple::test::XChainSim_test::SmBase::dstDoor
jtx::Account const & dstDoor()
Definition: XChain_test.cpp:4616
beast::severities::kError
@ kError
Definition: Journal.h:38
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:33
ripple::test::XChainSim_test::SmBase::bridge_
const BridgeDef & bridge_
Definition: XChain_test.cpp:4622
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test
Definition: LedgerDeltaAcquire.h:35
ripple::test::jtx::xchain_create_claim_id
Json::Value xchain_create_claim_id(Account const &acc, Json::Value const &bridge, STAmount const &reward, Account const &otherChainSource)
Definition: xchain_bridge.cpp:115
ripple::Config::features
std::unordered_set< uint256, beast::uhash<> > features
Definition: Config.h:288
ripple::test::XChainSim_test::Transfer::amt
STAmount amt
Definition: XChain_test.cpp:4315
ripple::tfClearAccountCreateAmount
constexpr std::uint32_t tfClearAccountCreateAmount
Definition: TxFlags.h:185
ripple::test::BalanceTransfer
Definition: XChain_test.cpp:270
ripple::tecXCHAIN_CREATE_ACCOUNT_DISABLED
@ tecXCHAIN_CREATE_ACCOUNT_DISABLED
Definition: TER.h:333
ripple::test::BalanceTransfer::to_
balance to_
Definition: XChain_test.cpp:275
ripple::test::BalanceTransfer::BalanceTransfer
BalanceTransfer(T &env, jtx::Account const &from_acct, jtx::Account const &to_acct, jtx::Account const &payor, std::vector< jtx::Account > const &payees, bool withClaim)
Definition: XChain_test.cpp:302
ripple::test::XChainSim_test::st_closed
@ st_closed
Definition: XChain_test.cpp:4580
ripple::test::jtx::sidechain_xchain_account_create
Json::Value sidechain_xchain_account_create(Account const &acc, Json::Value const &bridge, Account const &dst, AnyAmount const &amt, AnyAmount const &reward)
Definition: xchain_bridge.cpp:177
ripple::tecXCHAIN_SELF_COMMIT
@ tecXCHAIN_SELF_COMMIT
Definition: TER.h:331
ripple::test::jtx::IOU
Converts to IOU Issue or STAmount.
Definition: amount.h:291
ripple::test::jtx::XChainBridgeObjects::scuAlice
const Account scuAlice
Definition: xchain_bridge.h:175
ripple::test::XChainSim_test::ChainStateTrack::Claims::create_claims
CreateClaimMap create_claims
Definition: XChain_test.cpp:4531
ripple::test::XChainSim_test::SmCreateAccount
Definition: XChain_test.cpp:4627
ripple::test::XChainSim_test::ChainStateTracker
Definition: XChain_test.cpp:4544
ripple::test::XChain_test::reserve
XRPAmount reserve(std::uint32_t count)
Definition: XChain_test.cpp:393
ripple::temDISABLED
@ temDISABLED
Definition: TER.h:113
limits
ripple::test::XChainSim_test::Act_Flags
Act_Flags
Definition: XChain_test.cpp:4583
beast::severities::Severity
Severity
Severity level / threshold of a Journal message.
Definition: Journal.h:31
ripple::tecXCHAIN_REWARD_MISMATCH
@ tecXCHAIN_REWARD_MISMATCH
Definition: TER.h:324
ripple::test::jtx::XChainBridgeObjects::mcDoor
const Account mcDoor
Definition: xchain_bridge.h:155
std::list::begin
T begin(T... args)
ripple::test::XChainSim_test::SmState
SmState
Definition: XChain_test.cpp:4574
ripple::test::jtx::regkey
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Definition: regkey.cpp:28
ripple::TERSubset< CanCvtToTER >::fromInt
static constexpr TERSubset fromInt(int from)
Definition: TER.h:399
std
STL namespace.
ripple::test::XChainSim_test::ChainStateTrack
Definition: XChain_test.cpp:4360
ripple::test::SEnv::env_
jtx::Env env_
Definition: XChain_test.cpp:58
ripple::test::jtx::XChainBridgeObjects
Definition: xchain_bridge.h:152
ripple::test::XChainSim_test::ChainStateTracker::sendAttestations
void sendAttestations()
Definition: XChain_test.cpp:4557
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::tecNO_ISSUER
@ tecNO_ISSUER
Definition: TER.h:280
ripple::no
@ no
Definition: Steps.h:42
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::test::XChainSim_test::Transfer
Definition: XChain_test.cpp:4310
ripple::asfRequireDest
constexpr std::uint32_t asfRequireDest
Definition: TxFlags.h:74
ripple::test::XChainSim_test::ChainStateTracker::init
void init(jtx::Account const &acct)
Definition: XChain_test.cpp:4564
ripple::test::jtx::XChainBridgeObjects::scBob
const Account scBob
Definition: xchain_bridge.h:162
ripple::tecHAS_OBLIGATIONS
@ tecHAS_OBLIGATIONS
Definition: TER.h:298
ripple::tecNO_PERMISSION
@ tecNO_PERMISSION
Definition: TER.h:286
ripple::test::BridgeDef::jvb
Json::Value jvb
Definition: XChain_test.cpp:366
ripple::test::jtx::XChainBridgeObjects::payees
const std::vector< Account > payees
Definition: xchain_bridge.h:191
ripple::test::jtx::XChainBridgeObjects::scAlice
const Account scAlice
Definition: xchain_bridge.h:161
ripple::FeatureBitset
Definition: Feature.h:113
ripple::test::XChainSim_test::ChainStateTrack::sendAttestations
void sendAttestations()
Definition: XChain_test.cpp:4404
ripple::test::jtx::acctdelete
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
Definition: acctdelete.cpp:29
std::count
T count(T... args)
ripple::keylet::xChainCreateAccountClaimID
Keylet xChainCreateAccountClaimID(STXChainBridge const &bridge, std::uint64_t seq)
Definition: Indexes.cpp:428
std::visit
T visit(T... args)
ripple::tecINSUFFICIENT_RESERVE
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:288
std::list::empty
T empty(T... args)
ripple::xrpIssue
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:105
ripple::test::XChainSim_test::ChainStateTrack::verify
bool verify() const
Definition: XChain_test.cpp:4504
ripple::test::XEnv
Definition: XChain_test.cpp:202
ripple::test::XChainSim_test::SmCreateAccount::a2b
bool a2b() const
Definition: XChain_test.cpp:4643
ripple::test::jtx::XChainBridgeObjects::quorum
const std::uint32_t quorum
Definition: xchain_bridge.h:192
optional
ripple::temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT
@ temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT
Definition: TER.h:134
ripple::test::XChainSim_test::st_claimid_created
@ st_claimid_created
Definition: XChain_test.cpp:4576
ripple::test::jtx::PrettyAmount::value
STAmount const & value() const
Definition: amount.h:124
ripple::test::XChainSim_test::AccountCreate::to
jtx::Account to
Definition: XChain_test.cpp:4325
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
std::make_pair
T make_pair(T... args)
ripple::test::XChainSim_test::AccountStateTrack::init
void init(ENV &env, jtx::Account const &acct)
Definition: XChain_test.cpp:4344
ripple::test::BridgeDef::quorum
uint32_t quorum
Definition: XChain_test.cpp:364
ripple::test::XChain_test::testXChainCreateClaimID
void testXChainCreateClaimID()
Definition: XChain_test.cpp:1289
ripple::test::XChain_test
Definition: XChain_test.cpp:389
ripple::tecNO_ENTRY
@ tecNO_ENTRY
Definition: TER.h:287
std::list::end
T end(T... args)
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:86
ripple::test::XChainSim_test::st_initial
@ st_initial
Definition: XChain_test.cpp:4575
ripple::test::XChainSim_test::ChainStateTrack::spendFee
void spendFee(jtx::Account const &acct, size_t times=1)
Definition: XChain_test.cpp:4498
ripple::test::jtx::XChainBridgeObjects::mcBob
const Account mcBob
Definition: xchain_bridge.h:157
ripple::test::XChainSim_test::SmTransfer::distribute_reward
void distribute_reward(ChainStateTrack &st)
Definition: XChain_test.cpp:4818
ripple::test::jtx::XChainBridgeObjects::create_bridge
Json::Value create_bridge(Account const &acc, Json::Value const &bridge=Json::nullValue, STAmount const &_reward=XRP(1), std::optional< STAmount > const &minAccountCreate=std::nullopt)
Definition: xchain_bridge.h:242
ripple::test::jtx::XChainBridgeObjects::mcuAlice
const Account mcuAlice
Definition: xchain_bridge.h:170
ripple::test::XChainSim_test::ChainStateTracker::a_
ChainStateTrack a_
Definition: XChain_test.cpp:4570
ripple::test::jtx::Env::memoize
void memoize(Account const &account)
Associate AccountID with account.
Definition: Env.cpp:156
ripple::yes
@ yes
Definition: Steps.h:42
ripple::test::jtx::bridge_create
Json::Value bridge_create(Account const &acc, Json::Value const &bridge, STAmount const &reward, std::optional< STAmount > const &minAccountCreate)
Definition: xchain_bridge.cpp:71
ripple::test::jtx::XChainBridgeObjects::mcAlice
const Account mcAlice
Definition: xchain_bridge.h:156
std::unique_ptr
STL class.
ripple::test::jtx::XChainBridgeObjects::mcuGw
const Account mcuGw
Definition: xchain_bridge.h:173
ripple::test::XChainSim_test::SmCreateAccount::cr
AccountCreate cr
Definition: XChain_test.cpp:4755
ripple::test::XEnv::XEnv
XEnv(T &s, bool side=false)
Definition: XChain_test.cpp:204
ripple::test::SEnv::balance
STAmount balance(jtx::Account const &account) const
Definition: XChain_test.cpp:123
std::unordered_map
STL class.
ripple::test::BalanceTransfer::txFees_
XRPAmount txFees_
Definition: XChain_test.cpp:278
ripple::test::XChainSim_test::Transfer::to
jtx::Account to
Definition: XChain_test.cpp:4313
ripple::sfXChainBridge
const SF_XCHAIN_BRIDGE sfXChainBridge
ripple::temXCHAIN_BRIDGE_NONDOOR_OWNER
@ temXCHAIN_BRIDGE_NONDOOR_OWNER
Definition: TER.h:133
ripple::test::jtx::XChainBridgeObjects::mcuDoor
const Account mcuDoor
Definition: xchain_bridge.h:169
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:236
ripple::tecXCHAIN_NO_SIGNERS_LIST
@ tecXCHAIN_NO_SIGNERS_LIST
Definition: TER.h:325
ripple::test::XChain_test::testFeeDipsIntoReserve
void testFeeDipsIntoReserve()
Definition: XChain_test.cpp:4113
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:301
ripple::test::XChainSim_test::SmTransfer::a2b
bool a2b() const
Definition: XChain_test.cpp:4775
ripple::test::XChainSim_test::SmTransfer::commit
void commit()
Definition: XChain_test.cpp:4795
ripple::test::jtx::create
Json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount, NetClock::duration const &settleDelay, PublicKey const &pk, std::optional< NetClock::time_point > const &cancelAfter, std::optional< std::uint32_t > const &dstTag)
Definition: TestHelpers.cpp:250
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:117
ripple::tecNO_DST
@ tecNO_DST
Definition: TER.h:271
ripple::test::jtx::XChainBridgeObjects::jvub
Json::Value jvub
Definition: xchain_bridge.h:185
ripple::test::SEnv::SEnv
SEnv(T &s, std::unique_ptr< Config > config, FeatureBitset features, std::unique_ptr< Logs > logs=nullptr, beast::severities::Severity thresh=beast::severities::kError)
Definition: XChain_test.cpp:60
ripple::test::jtx::XChainBridgeObjects::signers
const std::vector< signer > signers
Definition: xchain_bridge.h:188
ripple::test::XChainSim_test::st_completed
@ st_completed
Definition: XChain_test.cpp:4579
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::XChainSim_test::ChainStateTrack::signers_attns
SignersAttns signers_attns
Definition: XChain_test.cpp:4539
ripple::XRPAmount
Definition: XRPAmount.h:46
ripple::test::XChainSim_test::SmBase::st_
std::shared_ptr< ChainStateTracker > st_
Definition: XChain_test.cpp:4623
variant
ripple::test::XChainSim_test
Definition: XChain_test.cpp:4302
ripple::tecXCHAIN_INSUFF_CREATE_AMOUNT
@ tecXCHAIN_INSUFF_CREATE_AMOUNT
Definition: TER.h:327
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)
string