rippled
NoRipple_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 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 
20 #include <ripple/protocol/Feature.h>
21 #include <ripple/protocol/jss.h>
22 #include <test/jtx.h>
23 
24 namespace ripple {
25 
26 namespace test {
27 
28 class NoRipple_test : public beast::unit_test::suite
29 {
30 public:
31  void
33  {
34  testcase("Set and clear noripple");
35 
36  using namespace jtx;
37  Env env(*this);
38 
39  auto const gw = Account("gateway");
40  auto const alice = Account("alice");
41 
42  env.fund(XRP(10000), gw, alice);
43 
44  auto const USD = gw["USD"];
45 
46  Json::Value account_gw;
47  account_gw[jss::account] = gw.human();
48  Json::Value account_alice;
49  account_alice[jss::account] = alice.human();
50 
51  for (auto SetOrClear : {true, false})
52  {
53  // Create a trust line with no-ripple flag setting
54  env(trust(
55  gw,
56  USD(100),
57  alice,
58  SetOrClear ? tfSetNoRipple : tfClearNoRipple));
59  env.close();
60 
61  // Check no-ripple flag on sender 'gateway'
63  env.rpc("json", "account_lines", to_string(account_gw))};
64  auto const& gline0 = lines[jss::result][jss::lines][0u];
65  BEAST_EXPECT(gline0[jss::no_ripple].asBool() == SetOrClear);
66 
67  // Check no-ripple peer flag on destination 'alice'
68  lines = env.rpc("json", "account_lines", to_string(account_alice));
69  auto const& aline0 = lines[jss::result][jss::lines][0u];
70  BEAST_EXPECT(aline0[jss::no_ripple_peer].asBool() == SetOrClear);
71  }
72  }
73 
74  void
76  {
77  testcase("Set noripple on a line with negative balance");
78 
79  using namespace jtx;
80  auto const gw = Account("gateway");
81  auto const alice = Account("alice");
82  auto const bob = Account("bob");
83  auto const carol = Account("carol");
84 
85  // fix1578 changes the return code. Verify expected behavior
86  // without and with fix1578.
87  for (auto const& tweakedFeatures :
88  {features - fix1578, features | fix1578})
89  {
90  Env env(*this, tweakedFeatures);
91 
92  env.fund(XRP(10000), gw, alice, bob, carol);
93  env.close();
94 
95  env.trust(alice["USD"](100), bob);
96  env.trust(bob["USD"](100), carol);
97  env.close();
98 
99  // After this payment alice has a -50 USD balance with bob, and
100  // bob has a -50 USD balance with carol. So neither alice nor
101  // bob should be able to clear the noRipple flag.
102  env(pay(alice, carol, carol["USD"](50)), path(bob));
103  env.close();
104 
105  TER const terNeg{
106  tweakedFeatures[fix1578] ? TER{tecNO_PERMISSION}
107  : TER{tesSUCCESS}};
108 
109  env(trust(alice, bob["USD"](100), bob, tfSetNoRipple), ter(terNeg));
110  env(trust(bob, carol["USD"](100), carol, tfSetNoRipple),
111  ter(terNeg));
112  env.close();
113 
114  Json::Value params;
115  params[jss::source_account] = alice.human();
116  params[jss::destination_account] = carol.human();
117  params[jss::destination_amount] = [] {
118  Json::Value dest_amt;
119  dest_amt[jss::currency] = "USD";
120  dest_amt[jss::value] = "1";
121  dest_amt[jss::issuer] = Account("carol").human();
122  return dest_amt;
123  }();
124 
125  auto const resp =
126  env.rpc("json", "ripple_path_find", to_string(params));
127  BEAST_EXPECT(resp[jss::result][jss::alternatives].size() == 1);
128 
129  auto getAccountLines = [&env](Account const& acct) {
130  Json::Value jv;
131  jv[jss::account] = acct.human();
132  auto const r = env.rpc("json", "account_lines", to_string(jv));
133  return r[jss::result][jss::lines];
134  };
135  {
136  auto const aliceLines = getAccountLines(alice);
137  BEAST_EXPECT(aliceLines.size() == 1);
138  BEAST_EXPECT(aliceLines[0u][jss::no_ripple].asBool() == false);
139 
140  auto const bobLines = getAccountLines(bob);
141  BEAST_EXPECT(bobLines.size() == 2);
142  BEAST_EXPECT(bobLines[0u][jss::no_ripple].asBool() == false);
143  BEAST_EXPECT(bobLines[1u][jss::no_ripple].asBool() == false);
144  }
145 
146  // Now carol sends the 50 USD back to alice. Then alice and
147  // bob can set the noRipple flag.
148  env(pay(carol, alice, alice["USD"](50)), path(bob));
149  env.close();
150 
151  env(trust(alice, bob["USD"](100), bob, tfSetNoRipple));
152  env(trust(bob, carol["USD"](100), carol, tfSetNoRipple));
153  env.close();
154  {
155  auto const aliceLines = getAccountLines(alice);
156  BEAST_EXPECT(aliceLines.size() == 1);
157  BEAST_EXPECT(aliceLines[0u].isMember(jss::no_ripple));
158 
159  auto const bobLines = getAccountLines(bob);
160  BEAST_EXPECT(bobLines.size() == 2);
161  BEAST_EXPECT(bobLines[0u].isMember(jss::no_ripple_peer));
162  BEAST_EXPECT(bobLines[1u].isMember(jss::no_ripple));
163  }
164  }
165  }
166 
167  void
169  {
170  testcase("pairwise NoRipple");
171 
172  using namespace jtx;
173  Env env(*this, features);
174 
175  auto const alice = Account("alice");
176  auto const bob = Account("bob");
177  auto const carol = Account("carol");
178 
179  env.fund(XRP(10000), alice, bob, carol);
180 
181  env(trust(bob, alice["USD"](100)));
182  env(trust(carol, bob["USD"](100)));
183 
184  env(trust(bob, alice["USD"](100), alice, tfSetNoRipple));
185  env(trust(bob, carol["USD"](100), carol, tfSetNoRipple));
186  env.close();
187 
188  Json::Value params;
189  params[jss::source_account] = alice.human();
190  params[jss::destination_account] = carol.human();
191  params[jss::destination_amount] = [] {
192  Json::Value dest_amt;
193  dest_amt[jss::currency] = "USD";
194  dest_amt[jss::value] = "1";
195  dest_amt[jss::issuer] = Account("carol").human();
196  return dest_amt;
197  }();
198 
199  Json::Value const resp{
200  env.rpc("json", "ripple_path_find", to_string(params))};
201  BEAST_EXPECT(resp[jss::result][jss::alternatives].size() == 0);
202 
203  env(pay(alice, carol, bob["USD"](50)), ter(tecPATH_DRY));
204  }
205 
206  void
208  {
209  testcase("Set default ripple on an account and check new trustlines");
210 
211  using namespace jtx;
212  Env env(*this, features);
213 
214  auto const gw = Account("gateway");
215  auto const alice = Account("alice");
216  auto const bob = Account("bob");
217 
218  env.fund(XRP(10000), gw, noripple(alice, bob));
219 
220  env(fset(bob, asfDefaultRipple));
221 
222  auto const USD = gw["USD"];
223 
224  env(trust(gw, USD(100), alice, 0));
225  env(trust(gw, USD(100), bob, 0));
226 
227  {
228  Json::Value params;
229  params[jss::account] = gw.human();
230  params[jss::peer] = alice.human();
231 
232  auto lines = env.rpc("json", "account_lines", to_string(params));
233  auto const& line0 = lines[jss::result][jss::lines][0u];
234  BEAST_EXPECT(line0[jss::no_ripple_peer].asBool() == true);
235  }
236  {
237  Json::Value params;
238  params[jss::account] = alice.human();
239  params[jss::peer] = gw.human();
240 
241  auto lines = env.rpc("json", "account_lines", to_string(params));
242  auto const& line0 = lines[jss::result][jss::lines][0u];
243  BEAST_EXPECT(line0[jss::no_ripple].asBool() == true);
244  }
245  {
246  Json::Value params;
247  params[jss::account] = gw.human();
248  params[jss::peer] = bob.human();
249 
250  auto lines = env.rpc("json", "account_lines", to_string(params));
251  auto const& line0 = lines[jss::result][jss::lines][0u];
252  BEAST_EXPECT(line0[jss::no_ripple].asBool() == false);
253  }
254  {
255  Json::Value params;
256  params[jss::account] = bob.human();
257  params[jss::peer] = gw.human();
258 
259  auto lines = env.rpc("json", "account_lines", to_string(params));
260  auto const& line0 = lines[jss::result][jss::lines][0u];
261  BEAST_EXPECT(line0[jss::no_ripple_peer].asBool() == false);
262  }
263  }
264 
265  void
266  run() override
267  {
268  testSetAndClear();
269 
270  auto withFeatsTests = [this](FeatureBitset features) {
271  testNegativeBalance(features);
272  testPairwise(features);
273  testDefaultRipple(features);
274  };
275  using namespace jtx;
276  auto const sa = supported_amendments();
277  withFeatsTests(sa - featureFlowCross);
278  withFeatsTests(sa);
279  }
280 };
281 
282 BEAST_DEFINE_TESTSUITE(NoRipple, app, ripple);
283 
284 } // namespace test
285 } // namespace ripple
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
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::tfSetNoRipple
constexpr std::uint32_t tfSetNoRipple
Definition: TxFlags.h:109
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:113
ripple::test::jtx::Env::trust
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition: Env.cpp:259
ripple::test::NoRipple_test::testSetAndClear
void testSetAndClear()
Definition: NoRipple_test.cpp:32
ripple::test::NoRipple_test::testDefaultRipple
void testDefaultRipple(FeatureBitset features)
Definition: NoRipple_test.cpp:207
ripple::TERSubset< CanCvtToTER >
ripple::test::jtx::fset
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:28
ripple::test::NoRipple_test::testNegativeBalance
void testNegativeBalance(FeatureBitset features)
Definition: NoRipple_test.cpp:75
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::tfClearNoRipple
constexpr std::uint32_t tfClearNoRipple
Definition: TxFlags.h:110
ripple::test::jtx::path
Add a path.
Definition: paths.h:55
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
ripple::fix1578
const uint256 fix1578
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::jtx::noripple
std::array< Account, 1+sizeof...(Args)> noripple(Account const &account, Args const &... args)
Designate accounts as no-ripple in Env::fund.
Definition: Env.h:64
ripple::test::jtx::pay
Json::Value pay(Account const &account, Account const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
ripple::test::NoRipple_test::testPairwise
void testPairwise(FeatureBitset features)
Definition: NoRipple_test.cpp:168
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
ripple::asfDefaultRipple
constexpr std::uint32_t asfDefaultRipple
Definition: TxFlags.h:81
ripple::tecNO_PERMISSION
@ tecNO_PERMISSION
Definition: TER.h:272
ripple::FeatureBitset
Definition: Feature.h:113
ripple::test::NoRipple_test::run
void run() override
Definition: NoRipple_test.cpp:266
ripple::tecPATH_DRY
@ tecPATH_DRY
Definition: TER.h:261
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:41
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::test::NoRipple_test
Definition: NoRipple_test.cpp:28
ripple::featureFlowCross
const uint256 featureFlowCross
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:222
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
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:687
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)