rippled
SetTrust_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2016 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 #include <ripple/protocol/TxFlags.h>
20 #include <ripple/protocol/jss.h>
21 #include <test/jtx.h>
22 
23 namespace ripple {
24 
25 namespace test {
26 
27 class SetTrust_test : public beast::unit_test::suite
28 {
29 public:
30  void
31  testFreeTrustlines(bool thirdLineCreatesLE, bool createOnHighAcct)
32  {
33  if (thirdLineCreatesLE)
34  testcase("Allow two free trustlines");
35  else
36  testcase("Dynamic reserve for trustline");
37 
38  using namespace jtx;
39  Env env(*this);
40 
41  auto const gwA = Account{"gwA"};
42  auto const gwB = Account{"gwB"};
43  auto const acctC = Account{"acctC"};
44  auto const acctD = Account{"acctD"};
45 
46  auto const& creator = createOnHighAcct ? acctD : acctC;
47  auto const& assistor = createOnHighAcct ? acctC : acctD;
48 
49  auto const txFee = env.current()->fees().base;
50  auto const baseReserve = env.current()->fees().accountReserve(0);
51  auto const threelineReserve = env.current()->fees().accountReserve(3);
52 
53  env.fund(XRP(10000), gwA, gwB, assistor);
54 
55  // Fund creator with ...
56  env.fund(
57  baseReserve /* enough to hold an account */
58  + drops(3 * txFee) /* and to pay for 3 transactions */,
59  creator);
60 
61  env(trust(creator, gwA["USD"](100)), require(lines(creator, 1)));
62  env(trust(creator, gwB["USD"](100)), require(lines(creator, 2)));
63 
64  if (thirdLineCreatesLE)
65  {
66  // creator does not have enough for the third trust line
67  env(trust(creator, assistor["USD"](100)),
69  require(lines(creator, 2)));
70  }
71  else
72  {
73  // First establish opposite trust direction from assistor
74  env(trust(assistor, creator["USD"](100)),
75  require(lines(creator, 3)));
76 
77  // creator does not have enough to create the other direction on
78  // the existing trust line ledger entry
79  env(trust(creator, assistor["USD"](100)),
81  }
82 
83  // Fund creator additional amount to cover
84  env(pay(env.master, creator, STAmount{threelineReserve - baseReserve}));
85 
86  if (thirdLineCreatesLE)
87  {
88  env(trust(creator, assistor["USD"](100)),
89  require(lines(creator, 3)));
90  }
91  else
92  {
93  env(trust(creator, assistor["USD"](100)),
94  require(lines(creator, 3)));
95 
96  Json::Value jv;
97  jv["account"] = creator.human();
98  auto const lines = env.rpc("json", "account_lines", to_string(jv));
99  // Verify that all lines have 100 limit from creator
100  BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
101  BEAST_EXPECT(lines[jss::result][jss::lines].size() == 3);
102  for (auto const& line : lines[jss::result][jss::lines])
103  {
104  BEAST_EXPECT(line[jss::limit] == "100");
105  }
106  }
107  }
108 
109  void
111  {
112  testcase("SetTrust using a ticket");
113 
114  using namespace jtx;
115 
116  // Verify that TrustSet transactions can use tickets.
117  Env env{*this};
118  auto const gw = Account{"gateway"};
119  auto const alice = Account{"alice"};
120  auto const USD = gw["USD"];
121 
122  env.fund(XRP(10000), gw, alice);
123  env.close();
124 
125  // Cannot pay alice without a trustline.
126  env(pay(gw, alice, USD(200)), ter(tecPATH_DRY));
127  env.close();
128 
129  // Create a ticket.
130  std::uint32_t const ticketSeq{env.seq(alice) + 1};
131  env(ticket::create(alice, 1));
132  env.close();
133 
134  // Use that ticket to create a trust line.
135  env(trust(alice, USD(1000)), ticket::use(ticketSeq));
136  env.close();
137 
138  // Now the payment succeeds.
139  env(pay(gw, alice, USD(200)));
140  env.close();
141  }
142 
145  {
146  Json::Value jv;
147  jv[jss::Account] = a.human();
148  jv[jss::LimitAmount] = amt.getJson(JsonOptions::none);
149  jv[jss::TransactionType] = jss::TrustSet;
150  jv[jss::Flags] = 0;
151  return jv;
152  }
153 
154  void
156  {
157  testcase("SetTrust checks for malformed transactions");
158 
159  using namespace jtx;
160  Env env{*this};
161 
162  auto const gw = Account{"gateway"};
163  auto const alice = Account{"alice"};
164  env.fund(XRP(10000), gw, alice);
165 
166  // Require valid tf flags
167  for (std::uint64_t badFlag = 1u;
168  badFlag <= std::numeric_limits<std::uint32_t>::max();
169  badFlag *= 2)
170  {
171  if (badFlag & tfTrustSetMask)
172  env(trust(
173  alice,
174  gw["USD"](100),
175  static_cast<std::uint32_t>(badFlag)),
177  }
178 
179  // trust amount can't be XRP
180  env(trust_explicit_amt(alice, drops(10000)), ter(temBAD_LIMIT));
181 
182  // trust amount can't be badCurrency IOU
183  env(trust_explicit_amt(alice, gw[to_string(badCurrency())](100)),
185 
186  // trust amount can't be negative
187  env(trust(alice, gw["USD"](-1000)), ter(temBAD_LIMIT));
188 
189  // trust amount can't be from invalid issuer
190  env(trust_explicit_amt(
191  alice, STAmount{Issue{to_currency("USD"), noAccount()}, 100}),
192  ter(temDST_NEEDED));
193 
194  // trust cannot be to self
195  env(trust(alice, alice["USD"](100)), ter(temDST_IS_SRC));
196 
197  // tfSetAuth flag should not be set if not required by lsfRequireAuth
198  env(trust(alice, gw["USD"](100), tfSetfAuth), ter(tefNO_AUTH_REQUIRED));
199  }
200 
201  void
202  testModifyQualityOfTrustline(bool createQuality, bool createOnHighAcct)
203  {
204  testcase << "SetTrust " << (createQuality ? "creates" : "removes")
205  << " quality of trustline for "
206  << (createOnHighAcct ? "high" : "low") << " account";
207 
208  using namespace jtx;
209  Env env{*this};
210 
211  auto const alice = Account{"alice"};
212  auto const bob = Account{"bob"};
213 
214  auto const& fromAcct = createOnHighAcct ? alice : bob;
215  auto const& toAcct = createOnHighAcct ? bob : alice;
216 
217  env.fund(XRP(10000), fromAcct, toAcct);
218 
219  auto txWithoutQuality = trust(toAcct, fromAcct["USD"](100));
220  txWithoutQuality["QualityIn"] = "0";
221  txWithoutQuality["QualityOut"] = "0";
222 
223  auto txWithQuality = txWithoutQuality;
224  txWithQuality["QualityIn"] = "1000";
225  txWithQuality["QualityOut"] = "1000";
226 
227  auto& tx1 = createQuality ? txWithQuality : txWithoutQuality;
228  auto& tx2 = createQuality ? txWithoutQuality : txWithQuality;
229 
230  auto check_quality = [&](const bool exists) {
231  Json::Value jv;
232  jv["account"] = toAcct.human();
233  auto const lines = env.rpc("json", "account_lines", to_string(jv));
234  auto quality = exists ? 1000 : 0;
235  BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
236  BEAST_EXPECT(lines[jss::result][jss::lines].size() == 1);
237  BEAST_EXPECT(
238  lines[jss::result][jss::lines][0u][jss::quality_in] == quality);
239  BEAST_EXPECT(
240  lines[jss::result][jss::lines][0u][jss::quality_out] ==
241  quality);
242  };
243 
244  env(tx1, require(lines(toAcct, 1)), require(lines(fromAcct, 1)));
245  check_quality(createQuality);
246 
247  env(tx2, require(lines(toAcct, 1)), require(lines(fromAcct, 1)));
248  check_quality(!createQuality);
249  }
250 
251  void
252  run() override
253  {
254  testFreeTrustlines(true, false);
255  testFreeTrustlines(false, true);
256  testFreeTrustlines(false, true);
257  // true, true case doesn't matter since creating a trustline ledger
258  // entry requires reserve from the creator
259  // independent of hi/low account ids for endpoints
262  testModifyQualityOfTrustline(false, false);
263  testModifyQualityOfTrustline(false, true);
264  testModifyQualityOfTrustline(true, false);
265  testModifyQualityOfTrustline(true, true);
266  }
267 };
269 } // namespace test
270 } // namespace ripple
ripple::badCurrency
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
Definition: UintTypes.cpp:135
ripple::to_currency
bool to_currency(Currency &currency, std::string const &code)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:80
ripple::test::SetTrust_test::testFreeTrustlines
void testFreeTrustlines(bool thirdLineCreatesLE, bool createOnHighAcct)
Definition: SetTrust_test.cpp:31
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
ripple::tecINSUF_RESERVE_LINE
@ tecINSUF_RESERVE_LINE
Definition: TER.h:250
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
ripple::temBAD_CURRENCY
@ temBAD_CURRENCY
Definition: TER.h:85
ripple::test::jtx::ter
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
ripple::test::jtx::trust
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition: trust.cpp:30
ripple::tfTrustSetMask
const std::uint32_t tfTrustSetMask
Definition: TxFlags.h:96
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:596
ripple::test::jtx::require
Check a set of conditions.
Definition: require.h:63
ripple::test::SetTrust_test::testModifyQualityOfTrustline
void testModifyQualityOfTrustline(bool createQuality, bool createOnHighAcct)
Definition: SetTrust_test.cpp:202
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:109
ripple::test::SetTrust_test::trust_explicit_amt
Json::Value trust_explicit_amt(jtx::Account const &a, STAmount const &amt)
Definition: SetTrust_test.cpp:144
ripple::temDST_IS_SRC
@ temDST_IS_SRC
Definition: TER.h:103
ripple::test::SetTrust_test::run
void run() override
Definition: SetTrust_test.cpp:252
ripple::test::jtx::ticket::use
Set a ticket sequence on a JTx.
Definition: ticket.h:47
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:106
ripple::test::SetTrust_test::testMalformedTransaction
void testMalformedTransaction()
Definition: SetTrust_test.cpp:155
ripple::test::SetTrust_test
Definition: SetTrust_test.cpp:27
ripple::temBAD_LIMIT
@ temBAD_LIMIT
Definition: TER.h:89
ripple::JsonOptions::none
@ none
ripple::temDST_NEEDED
@ temDST_NEEDED
Definition: TER.h:104
ripple::SetTrust
Definition: SetTrust.h:31
ripple::STAmount
Definition: STAmount.h:43
std::uint32_t
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::tefNO_AUTH_REQUIRED
@ tefNO_AUTH_REQUIRED
Definition: TER.h:152
ripple::tecNO_LINE_INSUF_RESERVE
@ tecNO_LINE_INSUF_RESERVE
Definition: TER.h:254
ripple::test::jtx::pay
Json::Value pay(Account const &account, Account const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:225
ripple::test::jtx::Env::master
Account const & master
Definition: Env.h:120
ripple::tecPATH_DRY
@ tecPATH_DRY
Definition: TER.h:256
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:38
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::test::SetTrust_test::testTicketSetTrust
void testTicketSetTrust()
Definition: SetTrust_test.cpp:110
ripple::tfSetfAuth
const std::uint32_t tfSetfAuth
Definition: TxFlags.h:91
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:299
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:97
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:115
ripple::test::jtx::Env::rpc
Json::Value rpc(std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:683
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::jtx::owner_count
Definition: owners.h:49
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)