rippled
Transaction_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2017 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/core/DatabaseCon.h>
21 #include <ripple/protocol/ErrorCodes.h>
22 #include <ripple/protocol/jss.h>
23 #include <test/jtx.h>
24 #include <test/jtx/Env.h>
25 #include <test/jtx/envconfig.h>
26 
27 namespace ripple {
28 
29 class Transaction_test : public beast::unit_test::suite
30 {
31  void
33  {
34  testcase("Test Range Request");
35 
36  using namespace test::jtx;
37  using std::to_string;
38 
39  const char* COMMAND = jss::tx.c_str();
40  const char* BINARY = jss::binary.c_str();
41  const char* NOT_FOUND = RPC::get_error_info(rpcTXN_NOT_FOUND).token;
43  const char* EXCESSIVE =
45 
46  Env env(*this);
47  auto const alice = Account("alice");
48  env.fund(XRP(1000), alice);
49  env.close();
50 
52  auto const startLegSeq = env.current()->info().seq;
53  for (int i = 0; i < 750; ++i)
54  {
55  env(noop(alice));
56  txns.emplace_back(env.tx());
57  env.close();
58  }
59  auto const endLegSeq = env.closed()->info().seq;
60 
61  // Find the existing transactions
62  for (auto&& tx : txns)
63  {
64  auto const result = env.rpc(
65  COMMAND,
66  to_string(tx->getTransactionID()),
67  BINARY,
68  to_string(startLegSeq),
69  to_string(endLegSeq));
70 
71  BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
72  }
73 
74  auto const tx = env.jt(noop(alice), seq(env.seq(alice))).stx;
75  for (int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
76  {
77  auto const result = env.rpc(
78  COMMAND,
79  to_string(tx->getTransactionID()),
80  BINARY,
81  to_string(startLegSeq),
82  to_string(endLegSeq + deltaEndSeq));
83 
84  BEAST_EXPECT(
85  result[jss::result][jss::status] == jss::error &&
86  result[jss::result][jss::error] == NOT_FOUND);
87 
88  if (deltaEndSeq)
89  BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
90  else
91  BEAST_EXPECT(result[jss::result][jss::searched_all].asBool());
92  }
93 
94  // Find transactions outside of provided range.
95  for (auto&& tx : txns)
96  {
97  auto const result = env.rpc(
98  COMMAND,
99  to_string(tx->getTransactionID()),
100  BINARY,
101  to_string(endLegSeq + 1),
102  to_string(endLegSeq + 100));
103 
104  BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
105  BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
106  }
107 
108  const auto deletedLedger = (startLegSeq + endLegSeq) / 2;
109  {
110  // Remove one of the ledgers from the database directly
111  auto db = env.app().getTxnDB().checkoutDb();
112  *db << "DELETE FROM Transactions WHERE LedgerSeq == "
113  << deletedLedger << ";";
114  }
115 
116  for (int deltaEndSeq = 0; deltaEndSeq < 2; ++deltaEndSeq)
117  {
118  auto const result = env.rpc(
119  COMMAND,
120  to_string(tx->getTransactionID()),
121  BINARY,
122  to_string(startLegSeq),
123  to_string(endLegSeq + deltaEndSeq));
124 
125  BEAST_EXPECT(
126  result[jss::result][jss::status] == jss::error &&
127  result[jss::result][jss::error] == NOT_FOUND);
128  BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
129  }
130 
131  // Provide range without providing the `binary`
132  // field. (Tests parameter parsing)
133  {
134  auto const result = env.rpc(
135  COMMAND,
136  to_string(tx->getTransactionID()),
137  to_string(startLegSeq),
138  to_string(endLegSeq));
139 
140  BEAST_EXPECT(
141  result[jss::result][jss::status] == jss::error &&
142  result[jss::result][jss::error] == NOT_FOUND);
143 
144  BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool());
145  }
146 
147  // Provide range without providing the `binary`
148  // field. (Tests parameter parsing)
149  {
150  auto const result = env.rpc(
151  COMMAND,
152  to_string(tx->getTransactionID()),
153  to_string(startLegSeq),
154  to_string(deletedLedger - 1));
155 
156  BEAST_EXPECT(
157  result[jss::result][jss::status] == jss::error &&
158  result[jss::result][jss::error] == NOT_FOUND);
159 
160  BEAST_EXPECT(result[jss::result][jss::searched_all].asBool());
161  }
162 
163  // Provide range without providing the `binary`
164  // field. (Tests parameter parsing)
165  {
166  auto const result = env.rpc(
167  COMMAND,
168  to_string(txns[0]->getTransactionID()),
169  to_string(startLegSeq),
170  to_string(deletedLedger - 1));
171 
172  BEAST_EXPECT(result[jss::result][jss::status] == jss::success);
173  BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
174  }
175 
176  // Provide an invalid range: (min > max)
177  {
178  auto const result = env.rpc(
179  COMMAND,
180  to_string(tx->getTransactionID()),
181  BINARY,
182  to_string(deletedLedger - 1),
183  to_string(startLegSeq));
184 
185  BEAST_EXPECT(
186  result[jss::result][jss::status] == jss::error &&
187  result[jss::result][jss::error] == INVALID);
188 
189  BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
190  }
191 
192  // Provide an invalid range: (min < 0)
193  {
194  auto const result = env.rpc(
195  COMMAND,
196  to_string(tx->getTransactionID()),
197  BINARY,
198  to_string(-1),
199  to_string(deletedLedger - 1));
200 
201  BEAST_EXPECT(
202  result[jss::result][jss::status] == jss::error &&
203  result[jss::result][jss::error] == INVALID);
204 
205  BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
206  }
207 
208  // Provide an invalid range: (min < 0, max < 0)
209  {
210  auto const result = env.rpc(
211  COMMAND,
212  to_string(tx->getTransactionID()),
213  BINARY,
214  to_string(-20),
215  to_string(-10));
216 
217  BEAST_EXPECT(
218  result[jss::result][jss::status] == jss::error &&
219  result[jss::result][jss::error] == INVALID);
220 
221  BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
222  }
223 
224  // Provide an invalid range: (only one value)
225  {
226  auto const result = env.rpc(
227  COMMAND,
228  to_string(tx->getTransactionID()),
229  BINARY,
230  to_string(20));
231 
232  BEAST_EXPECT(
233  result[jss::result][jss::status] == jss::error &&
234  result[jss::result][jss::error] == INVALID);
235 
236  BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
237  }
238 
239  // Provide an invalid range: (only one value)
240  {
241  auto const result = env.rpc(
242  COMMAND, to_string(tx->getTransactionID()), to_string(20));
243 
244  // Since we only provided one value for the range,
245  // the interface parses it as a false binary flag,
246  // as single-value ranges are not accepted. Since
247  // the error this causes differs depending on the platform
248  // we don't call out a specific error here.
249  BEAST_EXPECT(result[jss::result][jss::status] == jss::error);
250 
251  BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
252  }
253 
254  // Provide an invalid range: (max - min > 1000)
255  {
256  auto const result = env.rpc(
257  COMMAND,
258  to_string(tx->getTransactionID()),
259  BINARY,
260  to_string(startLegSeq),
261  to_string(startLegSeq + 1001));
262 
263  BEAST_EXPECT(
264  result[jss::result][jss::status] == jss::error &&
265  result[jss::result][jss::error] == EXCESSIVE);
266 
267  BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
268  }
269  }
270 
271 public:
272  void
273  run() override
274  {
276  }
277 };
278 
279 BEAST_DEFINE_TESTSUITE(Transaction, rpc, ripple);
280 
281 } // namespace ripple
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::RPC::get_error_info
ErrorInfo const & get_error_info(error_code_i code)
Returns an ErrorInfo that reflects the error code.
Definition: ErrorCodes.cpp:201
std::vector
STL class.
ripple::rpcEXCESSIVE_LGR_RANGE
@ rpcEXCESSIVE_LGR_RANGE
Definition: ErrorCodes.h:135
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:45
ripple::Transaction_test::run
void run() override
Definition: Transaction_test.cpp:273
ripple::Transaction_test
Definition: Transaction_test.cpp:29
std::to_string
T to_string(T... args)
ripple::rpcTXN_NOT_FOUND
@ rpcTXN_NOT_FOUND
Definition: ErrorCodes.h:80
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::INVALID
@ INVALID
Definition: Transaction.h:46
ripple::rpcINVALID_LGR_RANGE
@ rpcINVALID_LGR_RANGE
Definition: ErrorCodes.h:136
ripple::RPC::ErrorInfo::token
Json::StaticString token
Definition: ErrorCodes.h:181
ripple::Transaction_test::testRangeRequest
void testRangeRequest()
Definition: Transaction_test.cpp:32