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 <test/jtx.h>
20 #include <ripple/protocol/jss.h>
21 #include <ripple/protocol/TxFlags.h>
22 
23 namespace ripple {
24 
25 namespace test {
26 
27 class SetTrust_test : public beast::unit_test::suite
28 {
29 public:
30 
31 
32  void testFreeTrustlines(bool thirdLineCreatesLE, bool createOnHighAcct)
33  {
34  if (thirdLineCreatesLE)
35  testcase("Allow two free trustlines");
36  else
37  testcase("Dynamic reserve for trustline");
38 
39  using namespace jtx;
40  Env env(*this);
41 
42  auto const gwA = Account{ "gwA" };
43  auto const gwB = Account{ "gwB" };
44  auto const acctC = Account{ "acctC" };
45  auto const acctD = Account{ "acctD" };
46 
47  auto const & creator = createOnHighAcct ? acctD : acctC;
48  auto const & assistor = createOnHighAcct ? acctC : acctD;
49 
50  auto const txFee = env.current()->fees().base;
51  auto const baseReserve = env.current()->fees().accountReserve(0);
52  auto const threelineReserve = env.current()->fees().accountReserve(3);
53 
54  env.fund(XRP(10000), gwA, gwB, assistor);
55 
56  // Fund creator with ...
57  env.fund(baseReserve /* enough to hold an account */
58  + drops(3*txFee) /* and to pay for 3 transactions */, creator);
59 
60  env(trust(creator, gwA["USD"](100)), require(lines(creator,1)));
61  env(trust(creator, gwB["USD"](100)), require(lines(creator,2)));
62 
63  if (thirdLineCreatesLE)
64  {
65  // creator does not have enough for the third trust line
66  env(trust(creator, assistor["USD"](100)),
67  ter(tecNO_LINE_INSUF_RESERVE), require(lines(creator, 2)));
68  }
69  else
70  {
71  // First establish opposite trust direction from assistor
72  env(trust(assistor,creator["USD"](100)), require(lines(creator,3)));
73 
74  // creator does not have enough to create the other direction on
75  //the existing trust line ledger entry
76  env(trust(creator,assistor["USD"](100)),ter(tecINSUF_RESERVE_LINE));
77  }
78 
79  // Fund creator additional amount to cover
80  env(pay(env.master,creator,STAmount{ threelineReserve - baseReserve }));
81 
82  if (thirdLineCreatesLE)
83  {
84  env(trust(creator,assistor["USD"](100)),require(lines(creator, 3)));
85  }
86  else
87  {
88  env(trust(creator, assistor["USD"](100)),require(lines(creator,3)));
89 
90  Json::Value jv;
91  jv["account"] = creator.human();
92  auto const lines = env.rpc("json","account_lines", to_string(jv));
93  // Verify that all lines have 100 limit from creator
94  BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
95  BEAST_EXPECT(lines[jss::result][jss::lines].size() == 3);
96  for (auto const & line : lines[jss::result][jss::lines])
97  {
98  BEAST_EXPECT(line[jss::limit] == "100");
99  }
100  }
101  }
102 
104  {
105  Json::Value jv;
106  jv[jss::Account] = a.human();
107  jv[jss::LimitAmount] = amt.getJson(JsonOptions::none);
108  jv[jss::TransactionType] = jss::TrustSet;
109  jv[jss::Flags] = 0;
110  return jv;
111  }
112 
114  {
115  testcase("SetTrust checks for malformed transactions");
116 
117  using namespace jtx;
118  Env env{ *this };
119 
120  auto const gw = Account{ "gateway" };
121  auto const alice = Account{ "alice" };
122  env.fund(XRP(10000), gw, alice);
123 
124  // Require valid tf flags
125  for (std::uint64_t badFlag = 1u ;
126  badFlag <= std::numeric_limits<std::uint32_t>::max(); badFlag *= 2)
127  {
128  if( badFlag & tfTrustSetMask)
129  env(trust(alice, gw["USD"](100),
130  static_cast<std::uint32_t>(badFlag)), ter(temINVALID_FLAG));
131  }
132 
133  // trust amount can't be XRP
134  env(trust_explicit_amt(alice, drops(10000)), ter(temBAD_LIMIT));
135 
136  // trust amount can't be badCurrency IOU
137  env(trust_explicit_amt(alice, gw[ to_string(badCurrency())](100)),
139 
140  // trust amount can't be negative
141  env(trust(alice, gw["USD"](-1000)), ter(temBAD_LIMIT));
142 
143  // trust amount can't be from invalid issuer
144  env(trust_explicit_amt(alice, STAmount{Issue{to_currency("USD"),
145  noAccount()}, 100 }), ter(temDST_NEEDED));
146 
147  // trust cannot be to self
148  env(trust(alice, alice["USD"](100)), ter(temDST_IS_SRC));
149 
150  // tfSetAuth flag should not be set if not required by lsfRequireAuth
151  env(trust(alice, gw["USD"](100), tfSetfAuth), ter(tefNO_AUTH_REQUIRED));
152  }
153 
154  void testModifyQualityOfTrustline(bool createQuality, bool createOnHighAcct)
155  {
156  testcase << "SetTrust " << (createQuality ? "creates" : "removes")
157  << " quality of trustline for "
158  << (createOnHighAcct ? "high" : "low" )
159  << " account" ;
160 
161  using namespace jtx;
162  Env env{ *this };
163 
164  auto const alice = Account{ "alice" };
165  auto const bob = Account{ "bob" };
166 
167  auto const & fromAcct = createOnHighAcct ? alice : bob;
168  auto const & toAcct = createOnHighAcct ? bob : alice;
169 
170  env.fund(XRP(10000), fromAcct, toAcct);
171 
172 
173  auto txWithoutQuality = trust(toAcct, fromAcct["USD"](100));
174  txWithoutQuality["QualityIn"] = "0";
175  txWithoutQuality["QualityOut"] = "0";
176 
177  auto txWithQuality = txWithoutQuality;
178  txWithQuality["QualityIn"] = "1000";
179  txWithQuality["QualityOut"] = "1000";
180 
181  auto & tx1 = createQuality ? txWithQuality : txWithoutQuality;
182  auto & tx2 = createQuality ? txWithoutQuality : txWithQuality;
183 
184  auto check_quality = [&](const bool exists)
185  {
186  Json::Value jv;
187  jv["account"] = toAcct.human();
188  auto const lines = env.rpc("json","account_lines", to_string(jv));
189  auto quality = exists ? 1000 : 0;
190  BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
191  BEAST_EXPECT(lines[jss::result][jss::lines].size() == 1);
192  BEAST_EXPECT(lines[jss::result][jss::lines][0u][jss::quality_in]
193  == quality);
194  BEAST_EXPECT(lines[jss::result][jss::lines][0u][jss::quality_out]
195  == quality);
196  };
197 
198 
199  env(tx1, require(lines(toAcct, 1)), require(lines(fromAcct, 1)));
200  check_quality(createQuality);
201 
202  env(tx2, require(lines(toAcct, 1)), require(lines(fromAcct, 1)));
203  check_quality(!createQuality);
204 
205  }
206 
207  void run() override
208  {
209  testFreeTrustlines(true, false);
210  testFreeTrustlines(false, true);
211  testFreeTrustlines(false, true);
212  // true, true case doesn't matter since creating a trustline ledger
213  // entry requires reserve from the creator
214  // independent of hi/low account ids for endpoints
216  testModifyQualityOfTrustline(false, false);
217  testModifyQualityOfTrustline(false, true);
218  testModifyQualityOfTrustline(true, false);
219  testModifyQualityOfTrustline(true, true);
220  }
221 };
223 } // test
224 } // 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:123
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:67
ripple::test::SetTrust_test::testFreeTrustlines
void testFreeTrustlines(bool thirdLineCreatesLE, bool createOnHighAcct)
Definition: SetTrust_test.cpp:32
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:109
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
ripple::tecINSUF_RESERVE_LINE
@ tecINSUF_RESERVE_LINE
Definition: TER.h:253
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:261
ripple::temBAD_CURRENCY
@ temBAD_CURRENCY
Definition: TER.h:88
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:94
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:582
ripple::test::jtx::require
Check a set of conditions.
Definition: require.h:66
ripple::test::SetTrust_test::testModifyQualityOfTrustline
void testModifyQualityOfTrustline(bool createQuality, bool createOnHighAcct)
Definition: SetTrust_test.cpp:154
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:104
ripple::test::SetTrust_test::trust_explicit_amt
Json::Value trust_explicit_amt(jtx::Account const &a, STAmount const &amt)
Definition: SetTrust_test.cpp:103
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::temDST_IS_SRC
@ temDST_IS_SRC
Definition: TER.h:106
ripple::test::SetTrust_test::run
void run() override
Definition: SetTrust_test.cpp:207
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:109
ripple::test::SetTrust_test::testMalformedTransaction
void testMalformedTransaction()
Definition: SetTrust_test.cpp:113
ripple::test::SetTrust_test
Definition: SetTrust_test.cpp:27
ripple::temBAD_LIMIT
@ temBAD_LIMIT
Definition: TER.h:92
ripple::JsonOptions::none
@ none
ripple::temDST_NEEDED
@ temDST_NEEDED
Definition: TER.h:107
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:154
ripple::tecNO_LINE_INSUF_RESERVE
@ tecNO_LINE_INSUF_RESERVE
Definition: TER.h:257
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:214
ripple::test::jtx::Env::master
Account const & master
Definition: Env.h:122
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::tfSetfAuth
const std::uint32_t tfSetfAuth
Definition: TxFlags.h:89
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:296
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:156
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:117
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:688
Json::Value
Represents a JSON value.
Definition: json_value.h:141
ripple::test::jtx::owner_count
Definition: owners.h:50