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 <test/jtx.h>
21 #include <test/jtx/Env.h>
22 #include <test/jtx/envconfig.h>
23 #include <ripple/protocol/jss.h>
24 #include <ripple/core/DatabaseCon.h>
25 #include <ripple/protocol/ErrorCodes.h>
26 
27 namespace ripple {
28 
29 class Transaction_test : public beast::unit_test::suite
30 {
31 
32  void
34  {
35  testcase("Test Range Request");
36 
37  using namespace test::jtx;
38  using std::to_string;
39 
40  const char* COMMAND = jss::tx.c_str();
41  const char* BINARY = jss::binary.c_str();
42  const char* NOT_FOUND = RPC::get_error_info(rpcTXN_NOT_FOUND).token;
44  const char* EXCESSIVE = RPC::get_error_info(rpcEXCESSIVE_LGR_RANGE).token;
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,
243  to_string(tx->getTransactionID()),
244  to_string(20));
245 
246  // Since we only provided one value for the range,
247  // the interface parses it as a false binary flag,
248  // as single-value ranges are not accepted. Since
249  // the error this causes differs depending on the platform
250  // we don't call out a specific error here.
251  BEAST_EXPECT(result[jss::result][jss::status] == jss::error);
252 
253  BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
254  }
255 
256  // Provide an invalid range: (max - min > 1000)
257  {
258  auto const result = env.rpc(
259  COMMAND,
260  to_string(tx->getTransactionID()),
261  BINARY,
262  to_string(startLegSeq),
263  to_string(startLegSeq + 1001));
264 
265  BEAST_EXPECT(
266  result[jss::result][jss::status] == jss::error &&
267  result[jss::result][jss::error] == EXCESSIVE);
268 
269  BEAST_EXPECT(!result[jss::result].isMember(jss::searched_all));
270  }
271 
272  }
273 
274 public:
275  void run () override
276  {
278  }
279 };
280 
281 BEAST_DEFINE_TESTSUITE (Transaction, rpc, ripple);
282 
283 } // 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:175
std::vector
STL class.
ripple::rpcEXCESSIVE_LGR_RANGE
@ rpcEXCESSIVE_LGR_RANGE
Definition: ErrorCodes.h:136
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::Transaction_test::run
void run() override
Definition: Transaction_test.cpp:275
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:81
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:137
ripple::RPC::ErrorInfo::token
Json::StaticString token
Definition: ErrorCodes.h:175
ripple::Transaction_test::testRangeRequest
void testRangeRequest()
Definition: Transaction_test.cpp:33