rippled
TransactionEntry_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 <ripple/protocol/jss.h>
23 
24 namespace ripple {
25 
26 class TransactionEntry_test : public beast::unit_test::suite
27 {
28  void
30  {
31  testcase("Invalid request params");
32  using namespace test::jtx;
33  Env env {*this};
34 
35  {
36  //no params
37  auto const result = env.client()
38  .invoke("transaction_entry", {})[jss::result];
39  BEAST_EXPECT(result[jss::error] == "fieldNotFoundTransaction");
40  BEAST_EXPECT(result[jss::status] == "error");
41  }
42 
43  {
45  params[jss::ledger] = 20;
46  auto const result = env.client()
47  .invoke("transaction_entry", params)[jss::result];
48  BEAST_EXPECT(result[jss::error] == "lgrNotFound");
49  BEAST_EXPECT(result[jss::status] == "error");
50  }
51 
52  {
54  params[jss::ledger] = "current";
55  params[jss::tx_hash] = "DEADBEEF";
56  auto const result = env.client()
57  .invoke("transaction_entry", params)[jss::result];
58  BEAST_EXPECT(result[jss::error] == "notYetImplemented");
59  BEAST_EXPECT(result[jss::status] == "error");
60  }
61 
62  {
64  params[jss::ledger] = "closed";
65  params[jss::tx_hash] = "DEADBEEF";
66  auto const result = env.client()
67  .invoke("transaction_entry", params)[jss::result];
68  BEAST_EXPECT(! result[jss::ledger_hash].asString().empty());
69  BEAST_EXPECT(result[jss::error] == "transactionNotFound");
70  BEAST_EXPECT(result[jss::status] == "error");
71  }
72 
73  std::string const txHash {
74  "E2FE8D4AF3FCC3944DDF6CD8CDDC5E3F0AD50863EF8919AFEF10CB6408CD4D05"};
75 
76  // Command line format
77  {
78  // No arguments
79  Json::Value const result {env.rpc ("transaction_entry")};
80  BEAST_EXPECT(result[jss::ledger_hash].asString().empty());
81  BEAST_EXPECT(result[jss::error] == "badSyntax");
82  BEAST_EXPECT(result[jss::status] == "error");
83  }
84 
85  {
86  // One argument
87  Json::Value const result {env.rpc ("transaction_entry", txHash)};
88  BEAST_EXPECT(result[jss::error] == "badSyntax");
89  BEAST_EXPECT(result[jss::status] == "error");
90  }
91 
92  {
93  // First argument with too few characters
94  Json::Value const result {env.rpc (
95  "transaction_entry", txHash.substr (1), "closed")};
96  BEAST_EXPECT(result[jss::error] == "invalidParams");
97  BEAST_EXPECT(result[jss::status] == "error");
98  }
99 
100  {
101  // First argument with too many characters
102  Json::Value const result {env.rpc (
103  "transaction_entry", txHash + "A", "closed")};
104  BEAST_EXPECT(result[jss::error] == "invalidParams");
105  BEAST_EXPECT(result[jss::status] == "error");
106  }
107 
108  {
109  // Second argument not valid
110  Json::Value const result {env.rpc (
111  "transaction_entry", txHash, "closer")};
112  BEAST_EXPECT(result[jss::error] == "invalidParams");
113  BEAST_EXPECT(result[jss::status] == "error");
114  }
115 
116  {
117  // Ledger index of 0 is not valid
118  Json::Value const result {env.rpc (
119  "transaction_entry", txHash, "0")};
120  BEAST_EXPECT(result[jss::error] == "invalidParams");
121  BEAST_EXPECT(result[jss::status] == "error");
122  }
123 
124  {
125  // Three arguments
126  Json::Value const result {env.rpc (
127  "transaction_entry", txHash, "closed", "extra")};
128  BEAST_EXPECT(result[jss::error] == "badSyntax");
129  BEAST_EXPECT(result[jss::status] == "error");
130  }
131 
132  {
133  // Valid structure, but transaction not found.
134  Json::Value const result {env.rpc (
135  "transaction_entry", txHash, "closed")};
136  BEAST_EXPECT(
137  ! result[jss::result][jss::ledger_hash].asString().empty());
138  BEAST_EXPECT(
139  result[jss::result][jss::error] == "transactionNotFound");
140  BEAST_EXPECT(result[jss::result][jss::status] == "error");
141  }
142  }
143 
144  void testRequest()
145  {
146  testcase("Basic request");
147  using namespace test::jtx;
148  Env env {*this};
149 
150  auto check_tx = [this, &env]
151  (int index, std::string const txhash, std::string const type = "")
152  {
153  // first request using ledger_index to lookup
154  Json::Value const resIndex {[&env, index, &txhash] ()
155  {
157  params[jss::ledger_index] = index;
158  params[jss::tx_hash] = txhash;
159  return env.client()
160  .invoke("transaction_entry", params)[jss::result];
161  }()};
162 
163  if(! BEAST_EXPECTS(resIndex.isMember(jss::tx_json), txhash))
164  return;
165 
166  BEAST_EXPECT(resIndex[jss::tx_json][jss::hash] == txhash);
167  if(! type.empty())
168  {
169  BEAST_EXPECTS(
170  resIndex[jss::tx_json][jss::TransactionType] == type,
171  txhash + " is " +
172  resIndex[jss::tx_json][jss::TransactionType].asString());
173  }
174 
175  // second request using ledger_hash to lookup and verify
176  // both responses match
177  {
179  params[jss::ledger_hash] = resIndex[jss::ledger_hash];
180  params[jss::tx_hash] = txhash;
181  Json::Value const resHash = env.client()
182  .invoke("transaction_entry", params)[jss::result];
183  BEAST_EXPECT(resHash == resIndex);
184  }
185 
186  // Use the command line form with the index.
187  {
188  Json::Value const clIndex {env.rpc (
189  "transaction_entry", txhash, std::to_string (index))};
190  BEAST_EXPECT (clIndex["result"] == resIndex);
191  }
192 
193  // Use the command line form with the ledger_hash.
194  {
195  Json::Value const clHash {env.rpc (
196  "transaction_entry", txhash,
197  resIndex[jss::ledger_hash].asString())};
198  BEAST_EXPECT (clHash["result"] == resIndex);
199  }
200  };
201 
202  Account A1 {"A1"};
203  Account A2 {"A2"};
204 
205  env.fund(XRP(10000), A1);
206  auto fund_1_tx =
207  boost::lexical_cast<std::string>(env.tx()->getTransactionID());
208 
209  env.fund(XRP(10000), A2);
210  auto fund_2_tx =
211  boost::lexical_cast<std::string>(env.tx()->getTransactionID());
212 
213  env.close();
214 
215  // these are actually AccountSet txs because fund does two txs and
216  // env.tx only reports the last one
217  check_tx(env.closed()->seq(), fund_1_tx);
218  check_tx(env.closed()->seq(), fund_2_tx);
219 
220  env.trust(A2["USD"](1000), A1);
221  // the trust tx is actually a payment since the trust method
222  // refunds fees with a payment after TrustSet..so just ignore the type
223  // in the check below
224  auto trust_tx =
225  boost::lexical_cast<std::string>(env.tx()->getTransactionID());
226 
227  env(pay(A2, A1, A2["USD"](5)));
228  auto pay_tx =
229  boost::lexical_cast<std::string>(env.tx()->getTransactionID());
230  env.close();
231 
232  check_tx(env.closed()->seq(), trust_tx);
233  check_tx(env.closed()->seq(), pay_tx, jss::Payment.c_str());
234 
235  env(offer(A2, XRP(100), A2["USD"](1)));
236  auto offer_tx =
237  boost::lexical_cast<std::string>(env.tx()->getTransactionID());
238 
239  env.close();
240 
241  check_tx(env.closed()->seq(), offer_tx, jss::OfferCreate.c_str());
242  }
243 
244 public:
245  void run () override
246  {
247  testBadInput();
248  testRequest();
249  }
250 };
251 
252 BEAST_DEFINE_TESTSUITE (TransactionEntry, rpc, ripple);
253 
254 } // ripple
ripple::TransactionEntry_test::run
void run() override
Definition: TransactionEntry_test.cpp:245
std::string
STL class.
ripple::TransactionEntry_test
Definition: TransactionEntry_test.cpp:26
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:45
std::to_string
T to_string(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::TransactionEntry_test::testBadInput
void testBadInput()
Definition: TransactionEntry_test.cpp:29
ripple::TransactionEntry_test::testRequest
void testRequest()
Definition: TransactionEntry_test.cpp:144
Json::Value
Represents a JSON value.
Definition: json_value.h:141