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 
111  {
112  Json::Value jv;
113  jv[jss::Account] = a.human();
114  jv[jss::LimitAmount] = amt.getJson(JsonOptions::none);
115  jv[jss::TransactionType] = jss::TrustSet;
116  jv[jss::Flags] = 0;
117  return jv;
118  }
119 
120  void
122  {
123  testcase("SetTrust checks for malformed transactions");
124 
125  using namespace jtx;
126  Env env{*this};
127 
128  auto const gw = Account{"gateway"};
129  auto const alice = Account{"alice"};
130  env.fund(XRP(10000), gw, alice);
131 
132  // Require valid tf flags
133  for (std::uint64_t badFlag = 1u;
134  badFlag <= std::numeric_limits<std::uint32_t>::max();
135  badFlag *= 2)
136  {
137  if (badFlag & tfTrustSetMask)
138  env(trust(
139  alice,
140  gw["USD"](100),
141  static_cast<std::uint32_t>(badFlag)),
143  }
144 
145  // trust amount can't be XRP
146  env(trust_explicit_amt(alice, drops(10000)), ter(temBAD_LIMIT));
147 
148  // trust amount can't be badCurrency IOU
149  env(trust_explicit_amt(alice, gw[to_string(badCurrency())](100)),
151 
152  // trust amount can't be negative
153  env(trust(alice, gw["USD"](-1000)), ter(temBAD_LIMIT));
154 
155  // trust amount can't be from invalid issuer
156  env(trust_explicit_amt(
157  alice, STAmount{Issue{to_currency("USD"), noAccount()}, 100}),
158  ter(temDST_NEEDED));
159 
160  // trust cannot be to self
161  env(trust(alice, alice["USD"](100)), ter(temDST_IS_SRC));
162 
163  // tfSetAuth flag should not be set if not required by lsfRequireAuth
164  env(trust(alice, gw["USD"](100), tfSetfAuth), ter(tefNO_AUTH_REQUIRED));
165  }
166 
167  void
168  testModifyQualityOfTrustline(bool createQuality, bool createOnHighAcct)
169  {
170  testcase << "SetTrust " << (createQuality ? "creates" : "removes")
171  << " quality of trustline for "
172  << (createOnHighAcct ? "high" : "low") << " account";
173 
174  using namespace jtx;
175  Env env{*this};
176 
177  auto const alice = Account{"alice"};
178  auto const bob = Account{"bob"};
179 
180  auto const& fromAcct = createOnHighAcct ? alice : bob;
181  auto const& toAcct = createOnHighAcct ? bob : alice;
182 
183  env.fund(XRP(10000), fromAcct, toAcct);
184 
185  auto txWithoutQuality = trust(toAcct, fromAcct["USD"](100));
186  txWithoutQuality["QualityIn"] = "0";
187  txWithoutQuality["QualityOut"] = "0";
188 
189  auto txWithQuality = txWithoutQuality;
190  txWithQuality["QualityIn"] = "1000";
191  txWithQuality["QualityOut"] = "1000";
192 
193  auto& tx1 = createQuality ? txWithQuality : txWithoutQuality;
194  auto& tx2 = createQuality ? txWithoutQuality : txWithQuality;
195 
196  auto check_quality = [&](const bool exists) {
197  Json::Value jv;
198  jv["account"] = toAcct.human();
199  auto const lines = env.rpc("json", "account_lines", to_string(jv));
200  auto quality = exists ? 1000 : 0;
201  BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
202  BEAST_EXPECT(lines[jss::result][jss::lines].size() == 1);
203  BEAST_EXPECT(
204  lines[jss::result][jss::lines][0u][jss::quality_in] == quality);
205  BEAST_EXPECT(
206  lines[jss::result][jss::lines][0u][jss::quality_out] ==
207  quality);
208  };
209 
210  env(tx1, require(lines(toAcct, 1)), require(lines(fromAcct, 1)));
211  check_quality(createQuality);
212 
213  env(tx2, require(lines(toAcct, 1)), require(lines(fromAcct, 1)));
214  check_quality(!createQuality);
215  }
216 
217  void
218  run() override
219  {
220  testFreeTrustlines(true, false);
221  testFreeTrustlines(false, true);
222  testFreeTrustlines(false, true);
223  // true, true case doesn't matter since creating a trustline ledger
224  // entry requires reserve from the creator
225  // independent of hi/low account ids for endpoints
227  testModifyQualityOfTrustline(false, false);
228  testModifyQualityOfTrustline(false, true);
229  testModifyQualityOfTrustline(true, false);
230  testModifyQualityOfTrustline(true, true);
231  }
232 };
234 } // namespace test
235 } // 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:246
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountDelete, app, ripple)
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:594
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:168
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:110
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::temDST_IS_SRC
@ temDST_IS_SRC
Definition: TER.h:103
ripple::test::SetTrust_test::run
void run() override
Definition: SetTrust_test.cpp:218
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:106
ripple::test::SetTrust_test::testMalformedTransaction
void testMalformedTransaction()
Definition: SetTrust_test.cpp:121
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:42
std::uint64_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:150
ripple::tecNO_LINE_INSUF_RESERVE
@ tecNO_LINE_INSUF_RESERVE
Definition: TER.h:250
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:209
ripple::test::jtx::Env::master
Account const & master
Definition: Env.h:119
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
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:297
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:150
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:114
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:682
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::jtx::owner_count
Definition: owners.h:49