rippled
DepositAuthorized_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2018 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/jss.h>
21 #include <test/jtx.h>
22 
23 namespace ripple {
24 namespace test {
25 
26 class DepositAuthorized_test : public beast::unit_test::suite
27 {
28 public:
29  // Helper function that builds arguments for a deposit_authorized command.
30  static Json::Value
32  jtx::Account const& source,
33  jtx::Account const& dest,
34  std::string const& ledger = "")
35  {
37  args[jss::source_account] = source.human();
38  args[jss::destination_account] = dest.human();
39  if (!ledger.empty())
40  args[jss::ledger_index] = ledger;
41  return args;
42  }
43 
44  // Helper function that verifies a deposit_authorized request was
45  // successful and returned the expected value.
46  void
48  {
49  Json::Value const& results{result[jss::result]};
50  BEAST_EXPECT(results[jss::deposit_authorized] == authorized);
51  BEAST_EXPECT(results[jss::status] == jss::success);
52  }
53 
54  // Test a variety of non-malformed cases.
55  void
57  {
58  using namespace jtx;
59  Account const alice{"alice"};
60  Account const becky{"becky"};
61  Account const carol{"carol"};
62 
63  Env env(*this);
64  env.fund(XRP(1000), alice, becky, carol);
65  env.close();
66 
67  // becky is authorized to deposit to herself.
69  env.rpc(
70  "json",
71  "deposit_authorized",
72  depositAuthArgs(becky, becky, "validated").toStyledString()),
73  true);
74 
75  // alice should currently be authorized to deposit to becky.
77  env.rpc(
78  "json",
79  "deposit_authorized",
80  depositAuthArgs(alice, becky, "validated").toStyledString()),
81  true);
82 
83  // becky sets the DepositAuth flag in the current ledger.
84  env(fset(becky, asfDepositAuth));
85 
86  // alice is no longer authorized to deposit to becky in current ledger.
88  env.rpc(
89  "json",
90  "deposit_authorized",
91  depositAuthArgs(alice, becky).toStyledString()),
92  false);
93  env.close();
94 
95  // becky is still authorized to deposit to herself.
97  env.rpc(
98  "json",
99  "deposit_authorized",
100  depositAuthArgs(becky, becky, "validated").toStyledString()),
101  true);
102 
103  // It's not a reciprocal arrangement. becky can deposit to alice.
105  env.rpc(
106  "json",
107  "deposit_authorized",
108  depositAuthArgs(becky, alice, "current").toStyledString()),
109  true);
110 
111  // becky creates a deposit authorization for alice.
112  env(deposit::auth(becky, alice));
113  env.close();
114 
115  // alice is now authorized to deposit to becky.
117  env.rpc(
118  "json",
119  "deposit_authorized",
120  depositAuthArgs(alice, becky, "closed").toStyledString()),
121  true);
122 
123  // carol is still not authorized to deposit to becky.
125  env.rpc(
126  "json",
127  "deposit_authorized",
128  depositAuthArgs(carol, becky).toStyledString()),
129  false);
130 
131  // becky clears the the DepositAuth flag so carol becomes authorized.
132  env(fclear(becky, asfDepositAuth));
133  env.close();
134 
136  env.rpc(
137  "json",
138  "deposit_authorized",
139  depositAuthArgs(carol, becky).toStyledString()),
140  true);
141 
142  // alice is still authorized to deposit to becky.
144  env.rpc(
145  "json",
146  "deposit_authorized",
147  depositAuthArgs(alice, becky).toStyledString()),
148  true);
149  }
150 
151  // Test malformed cases.
152  void
154  {
155  using namespace jtx;
156  Account const alice{"alice"};
157  Account const becky{"becky"};
158 
159  // Lambda that checks the (error) result of deposit_authorized.
160  auto verifyErr = [this](
161  Json::Value const& result,
162  char const* error,
163  char const* errorMsg) {
164  BEAST_EXPECT(result[jss::result][jss::status] == jss::error);
165  BEAST_EXPECT(result[jss::result][jss::error] == error);
166  BEAST_EXPECT(result[jss::result][jss::error_message] == errorMsg);
167  };
168 
169  Env env(*this);
170  {
171  // Missing source_account field.
172  Json::Value args{depositAuthArgs(alice, becky)};
173  args.removeMember(jss::source_account);
174  Json::Value const result{
175  env.rpc("json", "deposit_authorized", args.toStyledString())};
176  verifyErr(
177  result, "invalidParams", "Missing field 'source_account'.");
178  }
179  {
180  // Non-string source_account field.
181  Json::Value args{depositAuthArgs(alice, becky)};
182  args[jss::source_account] = 7.3;
183  Json::Value const result{
184  env.rpc("json", "deposit_authorized", args.toStyledString())};
185  verifyErr(
186  result,
187  "invalidParams",
188  "Invalid field 'source_account', not a string.");
189  }
190  {
191  // Corrupt source_account field.
192  Json::Value args{depositAuthArgs(alice, becky)};
193  args[jss::source_account] = "rG1QQv2nh2gr7RCZ!P8YYcBUKCCN633jCn";
194  Json::Value const result{
195  env.rpc("json", "deposit_authorized", args.toStyledString())};
196  verifyErr(result, "actMalformed", "Account malformed.");
197  }
198  {
199  // Missing destination_account field.
200  Json::Value args{depositAuthArgs(alice, becky)};
201  args.removeMember(jss::destination_account);
202  Json::Value const result{
203  env.rpc("json", "deposit_authorized", args.toStyledString())};
204  verifyErr(
205  result,
206  "invalidParams",
207  "Missing field 'destination_account'.");
208  }
209  {
210  // Non-string destination_account field.
211  Json::Value args{depositAuthArgs(alice, becky)};
212  args[jss::destination_account] = 7.3;
213  Json::Value const result{
214  env.rpc("json", "deposit_authorized", args.toStyledString())};
215  verifyErr(
216  result,
217  "invalidParams",
218  "Invalid field 'destination_account', not a string.");
219  }
220  {
221  // Corrupt destination_account field.
222  Json::Value args{depositAuthArgs(alice, becky)};
223  args[jss::destination_account] =
224  "rP6P9ypfAmc!pw8SZHNwM4nvZHFXDraQas";
225  Json::Value const result{
226  env.rpc("json", "deposit_authorized", args.toStyledString())};
227  verifyErr(result, "actMalformed", "Account malformed.");
228  }
229  {
230  // Request an invalid ledger.
231  Json::Value args{depositAuthArgs(alice, becky, "-1")};
232  Json::Value const result{
233  env.rpc("json", "deposit_authorized", args.toStyledString())};
234  verifyErr(result, "invalidParams", "ledgerIndexMalformed");
235  }
236  {
237  // Request a ledger that doesn't exist yet as a string.
238  Json::Value args{depositAuthArgs(alice, becky, "17")};
239  Json::Value const result{
240  env.rpc("json", "deposit_authorized", args.toStyledString())};
241  verifyErr(result, "lgrNotFound", "ledgerNotFound");
242  }
243  {
244  // Request a ledger that doesn't exist yet.
245  Json::Value args{depositAuthArgs(alice, becky)};
246  args[jss::ledger_index] = 17;
247  Json::Value const result{
248  env.rpc("json", "deposit_authorized", args.toStyledString())};
249  verifyErr(result, "lgrNotFound", "ledgerNotFound");
250  }
251  {
252  // alice is not yet funded.
253  Json::Value args{depositAuthArgs(alice, becky)};
254  Json::Value const result{
255  env.rpc("json", "deposit_authorized", args.toStyledString())};
256  verifyErr(result, "srcActNotFound", "Source account not found.");
257  }
258  env.fund(XRP(1000), alice);
259  env.close();
260  {
261  // becky is not yet funded.
262  Json::Value args{depositAuthArgs(alice, becky)};
263  Json::Value const result{
264  env.rpc("json", "deposit_authorized", args.toStyledString())};
265  verifyErr(
266  result, "dstActNotFound", "Destination account not found.");
267  }
268  env.fund(XRP(1000), becky);
269  env.close();
270  {
271  // Once becky is funded try it again and see it succeed.
272  Json::Value args{depositAuthArgs(alice, becky)};
273  Json::Value const result{
274  env.rpc("json", "deposit_authorized", args.toStyledString())};
275  validateDepositAuthResult(result, true);
276  }
277  }
278 
279  void
280  run() override
281  {
282  testValid();
283  testErrors();
284  }
285 };
286 
287 BEAST_DEFINE_TESTSUITE(DepositAuthorized, app, ripple);
288 
289 } // namespace test
290 } // namespace ripple
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::asfDepositAuth
constexpr std::uint32_t asfDepositAuth
Definition: TxFlags.h:82
std::string
STL class.
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:113
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::authorized
static bool authorized(Port const &port, std::map< std::string, std::string > const &h)
Definition: ServerHandlerImp.cpp:85
ripple::test::DepositAuthorized_test::testValid
void testValid()
Definition: DepositAuthorized_test.cpp:56
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::DepositAuthorized_test::run
void run() override
Definition: DepositAuthorized_test.cpp:280
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::test::DepositAuthorized_test::testErrors
void testErrors()
Definition: DepositAuthorized_test.cpp:153
ripple::test::jtx::fclear
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition: flags.h:40
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
Json::Value::removeMember
Value removeMember(const char *key)
Remove and return the named member.
Definition: json_value.cpp:907
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
ripple::test::DepositAuthorized_test::validateDepositAuthResult
void validateDepositAuthResult(Json::Value const &result, bool authorized)
Definition: DepositAuthorized_test.cpp:47
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::test::DepositAuthorized_test
Definition: DepositAuthorized_test.cpp:26
ripple::test::DepositAuthorized_test::depositAuthArgs
static Json::Value depositAuthArgs(jtx::Account const &source, jtx::Account const &dest, std::string const &ledger="")
Definition: DepositAuthorized_test.cpp:31
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::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)