xrpld
Loading...
Searching...
No Matches
NoRipple_test.cpp
1
2#include <test/jtx/Account.h>
3#include <test/jtx/Env.h>
4#include <test/jtx/TestHelpers.h>
5#include <test/jtx/amount.h>
6#include <test/jtx/balance.h> // IWYU pragma: keep
7#include <test/jtx/flags.h>
8#include <test/jtx/paths.h>
9#include <test/jtx/pay.h>
10#include <test/jtx/ter.h>
11#include <test/jtx/trust.h>
12
13#include <xrpl/beast/unit_test/suite.h>
14#include <xrpl/json/json_value.h>
15#include <xrpl/json/to_string.h>
16#include <xrpl/protocol/ApiVersion.h>
17#include <xrpl/protocol/Feature.h>
18#include <xrpl/protocol/TER.h>
19#include <xrpl/protocol/TxFlags.h>
20#include <xrpl/protocol/jss.h>
21
22#include <string>
23
24namespace xrpl::test {
25
27{
28public:
29 void
31 {
32 testcase("Set and clear noripple");
33
34 using namespace jtx;
35 Env env(*this);
36
37 auto const gw = Account("gateway");
38 auto const alice = Account("alice");
39
40 env.fund(XRP(10000), gw, alice);
41
42 auto const usd = gw["USD"];
43
44 json::Value accountGw;
45 accountGw[jss::account] = gw.human();
46 json::Value accountAlice;
47 accountAlice[jss::account] = alice.human();
48
49 for (auto setOrClear : {true, false})
50 {
51 // Create a trust line with no-ripple flag setting
52 env(trust(gw, usd(100), alice, setOrClear ? tfSetNoRipple : tfClearNoRipple));
53 env.close();
54
55 // Check no-ripple flag on sender 'gateway'
56 json::Value lines{env.rpc("json", "account_lines", to_string(accountGw))};
57 auto const& gwLine0 = lines[jss::result][jss::lines][0u];
58 BEAST_EXPECT(gwLine0[jss::no_ripple].asBool() == setOrClear);
59
60 // Check no-ripple peer flag on destination 'alice'
61 lines = env.rpc("json", "account_lines", to_string(accountAlice));
62 auto const& aline0 = lines[jss::result][jss::lines][0u];
63 BEAST_EXPECT(aline0[jss::no_ripple_peer].asBool() == setOrClear);
64 }
65 }
66
67 void
69 {
70 testcase("Set noripple on a line with negative balance");
71
72 using namespace jtx;
73 auto const gw = Account("gateway");
74 auto const alice = Account("alice");
75 auto const bob = Account("bob");
76 auto const carol = Account("carol");
77
78 Env env(*this, features);
79
80 env.fund(XRP(10000), gw, alice, bob, carol);
81 env.close();
82
83 env.trust(alice["USD"](100), bob);
84 env.trust(bob["USD"](100), carol);
85 env.close();
86
87 // After this payment alice has a -50 USD balance with bob, and
88 // bob has a -50 USD balance with carol. So neither alice nor
89 // bob should be able to clear the noRipple flag.
90 env(pay(alice, carol, carol["USD"](50)), Path(bob));
91 env.close();
92
93 TER const terNeg{TER{tecNO_PERMISSION}};
94
95 env(trust(alice, bob["USD"](100), bob, tfSetNoRipple), Ter(terNeg));
96 env(trust(bob, carol["USD"](100), carol, tfSetNoRipple), Ter(terNeg));
97 env.close();
98
99 json::Value params;
100 params[jss::source_account] = alice.human();
101 params[jss::destination_account] = carol.human();
102 params[jss::destination_amount] = [] {
103 json::Value destAmt;
104 destAmt[jss::currency] = "USD";
105 destAmt[jss::value] = "1";
106 destAmt[jss::issuer] = Account("carol").human();
107 return destAmt;
108 }();
109
110 auto const resp = env.rpc("json", "ripple_path_find", to_string(params));
111 BEAST_EXPECT(resp[jss::result][jss::alternatives].size() == 1);
112
113 auto getAccountLines = [&env](Account const& acct) {
114 auto const r = jtx::getAccountLines(env, acct);
115 return r[jss::lines];
116 };
117 {
118 auto const aliceLines = getAccountLines(alice);
119 BEAST_EXPECT(aliceLines.size() == 1);
120 BEAST_EXPECT(aliceLines[0u][jss::no_ripple].asBool() == false);
121
122 auto const bobLines = getAccountLines(bob);
123 BEAST_EXPECT(bobLines.size() == 2);
124 BEAST_EXPECT(bobLines[0u][jss::no_ripple].asBool() == false);
125 BEAST_EXPECT(bobLines[1u][jss::no_ripple].asBool() == false);
126 }
127
128 // Now carol sends the 50 USD back to alice. Then alice and
129 // bob can set the noRipple flag.
130 env(pay(carol, alice, alice["USD"](50)), Path(bob));
131 env.close();
132
133 env(trust(alice, bob["USD"](100), bob, tfSetNoRipple));
134 env(trust(bob, carol["USD"](100), carol, tfSetNoRipple));
135 env.close();
136 {
137 auto const aliceLines = getAccountLines(alice);
138 BEAST_EXPECT(aliceLines.size() == 1);
139 BEAST_EXPECT(aliceLines[0u].isMember(jss::no_ripple));
140
141 auto const bobLines = getAccountLines(bob);
142 BEAST_EXPECT(bobLines.size() == 2);
143 BEAST_EXPECT(bobLines[0u].isMember(jss::no_ripple_peer));
144 BEAST_EXPECT(bobLines[1u].isMember(jss::no_ripple));
145 }
146 }
147
148 void
150 {
151 testcase("pairwise NoRipple");
152
153 using namespace jtx;
154 Env env(*this, features);
155
156 auto const alice = Account("alice");
157 auto const bob = Account("bob");
158 auto const carol = Account("carol");
159
160 env.fund(XRP(10000), alice, bob, carol);
161
162 env(trust(bob, alice["USD"](100)));
163 env(trust(carol, bob["USD"](100)));
164
165 env(trust(bob, alice["USD"](100), alice, tfSetNoRipple));
166 env(trust(bob, carol["USD"](100), carol, tfSetNoRipple));
167 env.close();
168
169 json::Value params;
170 params[jss::source_account] = alice.human();
171 params[jss::destination_account] = carol.human();
172 params[jss::destination_amount] = [] {
173 json::Value destAmt;
174 destAmt[jss::currency] = "USD";
175 destAmt[jss::value] = "1";
176 destAmt[jss::issuer] = Account("carol").human();
177 return destAmt;
178 }();
179
180 json::Value const resp{env.rpc("json", "ripple_path_find", to_string(params))};
181 BEAST_EXPECT(resp[jss::result][jss::alternatives].size() == 0);
182
183 env(pay(alice, carol, bob["USD"](50)), Ter(tecPATH_DRY));
184 }
185
186 void
187 testDefaultRipple(FeatureBitset features, unsigned int apiVersion)
188 {
189 testcase(
190 "Set default ripple on an account and check new trustlines "
191 "Version " +
192 std::to_string(apiVersion));
193
194 using namespace jtx;
195 Env env(*this, features);
196
197 auto const gw = Account("gateway");
198 auto const alice = Account("alice");
199 auto const bob = Account("bob");
200
201 env.fund(XRP(10000), gw, noripple(alice, bob));
202
203 env(fset(bob, asfDefaultRipple));
204
205 auto const usd = gw["USD"];
206
207 env(trust(gw, usd(100), alice, 0));
208 env(trust(gw, usd(100), bob, 0));
209 json::Value params;
210 params[jss::api_version] = apiVersion;
211
212 {
213 params[jss::account] = gw.human();
214 params[jss::peer] = alice.human();
215
216 auto lines = env.rpc("json", "account_lines", to_string(params));
217 auto const& line0 = lines[jss::result][jss::lines][0u];
218 BEAST_EXPECT(line0[jss::no_ripple_peer].asBool() == true);
219 }
220 {
221 params[jss::account] = alice.human();
222 params[jss::peer] = gw.human();
223
224 auto lines = env.rpc("json", "account_lines", to_string(params));
225 auto const& line0 = lines[jss::result][jss::lines][0u];
226 BEAST_EXPECT(line0[jss::no_ripple].asBool() == true);
227 }
228 {
229 params[jss::account] = gw.human();
230 params[jss::peer] = bob.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].asBool() == false);
235 }
236 {
237 params[jss::account] = bob.human();
238 params[jss::peer] = gw.human();
239
240 auto lines = env.rpc("json", "account_lines", to_string(params));
241 auto const& line0 = lines[jss::result][jss::lines][0u];
242 BEAST_EXPECT(line0[jss::no_ripple_peer].asBool() == false);
243 }
244 {
245 // test for transactions
246 {
247 params[jss::account] = bob.human();
248 params[jss::role] = "gateway";
249 params[jss::transactions] = "asdf";
250
251 auto lines = env.rpc("json", "noripple_check", to_string(params));
252 if (apiVersion < 2u)
253 {
254 BEAST_EXPECT(lines[jss::result][jss::status] == "success");
255 }
256 else
257 {
258 BEAST_EXPECT(lines[jss::result][jss::error] == "invalidParams");
259 }
260 }
261 }
262 }
263
264 void
265 run() override
266 {
268
269 auto withFeatsTests = [this](FeatureBitset features) {
271 [&, this](unsigned testVersion) { testDefaultRipple(features, testVersion); });
272 testNegativeBalance(features);
273 testPairwise(features);
274 };
275 using namespace jtx;
276 auto const sa = testableAmendments();
277 withFeatsTests(sa - featurePermissionedDEX);
278 withFeatsTests(sa);
279 }
280};
281
283
284} // namespace xrpl::test
A testsuite class.
Definition suite.h:50
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:149
Represents a JSON value.
Definition json_value.h:130
void testPairwise(FeatureBitset features)
void run() override
Runs the suite.
void testDefaultRipple(FeatureBitset features, unsigned int apiVersion)
void testNegativeBalance(FeatureBitset features)
Immutable cryptographic account descriptor.
Definition jtx/Account.h:17
A transaction testing environment.
Definition Env.h:143
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:133
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:296
json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition Env.h:864
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition Env.cpp:327
Add a path.
Definition paths.h:39
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition ter.h:13
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:14
XrpT const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:92
OwnerCount< ltRIPPLE_STATE > lines
Match the number of trust lines in the account's owner directory.
Definition owners.h:67
FeatureBitset testableAmendments()
Definition Env.h:76
std::array< Account, 1+sizeof...(Args)> noripple(Account const &account, Args const &... args)
Designate accounts as no-ripple in Env::fund.
Definition Env.h:70
json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition trust.cpp:18
json::Value getAccountLines(Env &env, AccountID const &acctId)
json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition flags.cpp:15
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
void forAllApiVersions(Fn const &fn, Args &&... args)
Definition ApiVersion.h:158
TERSubset< CanCvtToTER > TER
Definition TER.h:634
@ tecPATH_DRY
Definition TER.h:292
@ tecNO_PERMISSION
Definition TER.h:303
T to_string(T... args)