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  auto const r = jtx::getAccountLines(env, acct);
131  return r[jss::lines];
132  };
133  {
134  auto const aliceLines = getAccountLines(alice);
135  BEAST_EXPECT(aliceLines.size() == 1);
136  BEAST_EXPECT(aliceLines[0u][jss::no_ripple].asBool() == false);
137 
138  auto const bobLines = getAccountLines(bob);
139  BEAST_EXPECT(bobLines.size() == 2);
140  BEAST_EXPECT(bobLines[0u][jss::no_ripple].asBool() == false);
141  BEAST_EXPECT(bobLines[1u][jss::no_ripple].asBool() == false);
142  }
143 
144  // Now carol sends the 50 USD back to alice. Then alice and
145  // bob can set the noRipple flag.
146  env(pay(carol, alice, alice["USD"](50)), path(bob));
147  env.close();
148 
149  env(trust(alice, bob["USD"](100), bob, tfSetNoRipple));
150  env(trust(bob, carol["USD"](100), carol, tfSetNoRipple));
151  env.close();
152  {
153  auto const aliceLines = getAccountLines(alice);
154  BEAST_EXPECT(aliceLines.size() == 1);
155  BEAST_EXPECT(aliceLines[0u].isMember(jss::no_ripple));
156 
157  auto const bobLines = getAccountLines(bob);
158  BEAST_EXPECT(bobLines.size() == 2);
159  BEAST_EXPECT(bobLines[0u].isMember(jss::no_ripple_peer));
160  BEAST_EXPECT(bobLines[1u].isMember(jss::no_ripple));
161  }
162  }
163  }
164 
165  void
167  {
168  testcase("pairwise NoRipple");
169 
170  using namespace jtx;
171  Env env(*this, features);
172 
173  auto const alice = Account("alice");
174  auto const bob = Account("bob");
175  auto const carol = Account("carol");
176 
177  env.fund(XRP(10000), alice, bob, carol);
178 
179  env(trust(bob, alice["USD"](100)));
180  env(trust(carol, bob["USD"](100)));
181 
182  env(trust(bob, alice["USD"](100), alice, tfSetNoRipple));
183  env(trust(bob, carol["USD"](100), carol, tfSetNoRipple));
184  env.close();
185 
186  Json::Value params;
187  params[jss::source_account] = alice.human();
188  params[jss::destination_account] = carol.human();
189  params[jss::destination_amount] = [] {
190  Json::Value dest_amt;
191  dest_amt[jss::currency] = "USD";
192  dest_amt[jss::value] = "1";
193  dest_amt[jss::issuer] = Account("carol").human();
194  return dest_amt;
195  }();
196 
197  Json::Value const resp{
198  env.rpc("json", "ripple_path_find", to_string(params))};
199  BEAST_EXPECT(resp[jss::result][jss::alternatives].size() == 0);
200 
201  env(pay(alice, carol, bob["USD"](50)), ter(tecPATH_DRY));
202  }
203 
204  void
206  {
207  testcase("Set default ripple on an account and check new trustlines");
208 
209  using namespace jtx;
210  Env env(*this, features);
211 
212  auto const gw = Account("gateway");
213  auto const alice = Account("alice");
214  auto const bob = Account("bob");
215 
216  env.fund(XRP(10000), gw, noripple(alice, bob));
217 
218  env(fset(bob, asfDefaultRipple));
219 
220  auto const USD = gw["USD"];
221 
222  env(trust(gw, USD(100), alice, 0));
223  env(trust(gw, USD(100), bob, 0));
224 
225  {
226  Json::Value params;
227  params[jss::account] = gw.human();
228  params[jss::peer] = alice.human();
229 
230  auto lines = env.rpc("json", "account_lines", to_string(params));
231  auto const& line0 = lines[jss::result][jss::lines][0u];
232  BEAST_EXPECT(line0[jss::no_ripple_peer].asBool() == true);
233  }
234  {
235  Json::Value params;
236  params[jss::account] = alice.human();
237  params[jss::peer] = gw.human();
238 
239  auto lines = env.rpc("json", "account_lines", to_string(params));
240  auto const& line0 = lines[jss::result][jss::lines][0u];
241  BEAST_EXPECT(line0[jss::no_ripple].asBool() == true);
242  }
243  {
244  Json::Value params;
245  params[jss::account] = gw.human();
246  params[jss::peer] = bob.human();
247 
248  auto lines = env.rpc("json", "account_lines", to_string(params));
249  auto const& line0 = lines[jss::result][jss::lines][0u];
250  BEAST_EXPECT(line0[jss::no_ripple].asBool() == false);
251  }
252  {
253  Json::Value params;
254  params[jss::account] = bob.human();
255  params[jss::peer] = gw.human();
256 
257  auto lines = env.rpc("json", "account_lines", to_string(params));
258  auto const& line0 = lines[jss::result][jss::lines][0u];
259  BEAST_EXPECT(line0[jss::no_ripple_peer].asBool() == false);
260  }
261  }
262 
263  void
264  run() override
265  {
266  testSetAndClear();
267 
268  auto withFeatsTests = [this](FeatureBitset features) {
269  testNegativeBalance(features);
270  testPairwise(features);
271  testDefaultRipple(features);
272  };
273  using namespace jtx;
274  auto const sa = supported_amendments();
275  withFeatsTests(sa - featureFlowCross);
276  withFeatsTests(sa);
277  }
278 };
279 
280 BEAST_DEFINE_TESTSUITE(NoRipple, app, ripple);
281 
282 } // namespace test
283 } // 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::tfSetNoRipple
constexpr std::uint32_t tfSetNoRipple
Definition: TxFlags.h:110
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:205
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:111
ripple::test::jtx::path
Add a path.
Definition: paths.h:55
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:71
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:65
ripple::test::NoRipple_test::testPairwise
void testPairwise(FeatureBitset features)
Definition: NoRipple_test.cpp:166
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:276
ripple::FeatureBitset
Definition: Feature.h:113
ripple::test::NoRipple_test::run
void run() override
Definition: NoRipple_test.cpp:264
ripple::tecPATH_DRY
@ tecPATH_DRY
Definition: TER.h:265
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:226
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:117
ripple::test::jtx::getAccountLines
Json::Value getAccountLines(Env &env, AccountID const &acctId)
Definition: TestHelpers.cpp:40
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:700
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)