rippled
Tx.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2014 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/app/ledger/LedgerMaster.h>
21 #include <ripple/app/ledger/TransactionMaster.h>
22 #include <ripple/app/misc/NetworkOPs.h>
23 #include <ripple/app/misc/Transaction.h>
24 #include <ripple/basics/ToString.h>
25 #include <ripple/net/RPCErr.h>
26 #include <ripple/protocol/ErrorCodes.h>
27 #include <ripple/protocol/jss.h>
28 #include <ripple/rpc/Context.h>
29 #include <ripple/rpc/DeliveredAmount.h>
30 #include <ripple/rpc/GRPCHandlers.h>
31 #include <ripple/rpc/impl/GRPCHelpers.h>
32 #include <ripple/rpc/impl/RPCHelpers.h>
33 
34 namespace ripple {
35 
36 // {
37 // transaction: <hex>
38 // }
39 
40 static bool
41 isValidated(LedgerMaster& ledgerMaster, std::uint32_t seq, uint256 const& hash)
42 {
43  if (!ledgerMaster.haveLedger(seq))
44  return false;
45 
46  if (seq > ledgerMaster.getValidatedLedger()->info().seq)
47  return false;
48 
49  return ledgerMaster.getHashBySeq(seq) == hash;
50 }
51 
52 struct TxResult
53 {
56  bool validated = false;
58 };
59 
60 struct TxArgs
61 {
63  bool binary = false;
65 };
66 
68 doTxHelp(RPC::Context& context, TxArgs const& args)
69 {
70  TxResult result;
71 
73 
74  if (args.ledgerRange)
75  {
76  constexpr uint16_t MAX_RANGE = 1000;
77 
78  if (args.ledgerRange->second < args.ledgerRange->first)
79  return {result, rpcINVALID_LGR_RANGE};
80 
81  if (args.ledgerRange->second - args.ledgerRange->first > MAX_RANGE)
82  return {result, rpcEXCESSIVE_LGR_RANGE};
83 
85  args.ledgerRange->first, args.ledgerRange->second);
86  }
87 
88  auto ec{rpcSUCCESS};
89 
90  using TxPair =
92 
94 
96  if (args.ledgerRange)
97  {
98  v = context.app.getMasterTransaction().fetch(args.hash, range, ec);
99  }
100  else
101  {
102  v = context.app.getMasterTransaction().fetch(args.hash, ec);
103  }
104 
105  if (auto e = std::get_if<TxSearched>(&v))
106  {
107  result.searchedAll = *e;
108  return {result, rpcTXN_NOT_FOUND};
109  }
110 
111  auto [txn, meta] = std::get<TxPair>(v);
112 
113  if (ec == rpcDB_DESERIALIZATION)
114  {
115  return {result, ec};
116  }
117  if (!txn)
118  {
119  return {result, rpcTXN_NOT_FOUND};
120  }
121 
122  // populate transaction data
123  result.txn = txn;
124  if (txn->getLedger() == 0)
125  {
126  return {result, rpcSUCCESS};
127  }
128 
130  context.ledgerMaster.getLedgerBySeq(txn->getLedger());
131 
132  if (ledger && meta)
133  {
134  result.meta = meta;
135  result.validated = isValidated(
136  context.ledgerMaster, ledger->info().seq, ledger->info().hash);
137  }
138 
139  return {result, rpcSUCCESS};
140 }
141 
145  TxArgs const& args,
147 {
148  org::xrpl::rpc::v1::GetTransactionResponse response;
149  grpc::Status status = grpc::Status::OK;
150  RPC::Status const& error = res.second;
151  TxResult const& result = res.first;
152  // handle errors
153  if (error.toErrorCode() != rpcSUCCESS)
154  {
155  if (error.toErrorCode() == rpcTXN_NOT_FOUND &&
157  {
158  status = {
159  grpc::StatusCode::NOT_FOUND,
160  "txn not found. searched_all = " +
161  to_string(
162  (result.searchedAll == TxSearched::all ? "true"
163  : "false"))};
164  }
165  else
166  {
167  if (error.toErrorCode() == rpcTXN_NOT_FOUND)
168  status = {grpc::StatusCode::NOT_FOUND, "txn not found"};
169  else
170  status = {grpc::StatusCode::INTERNAL, error.message()};
171  }
172  }
173  // no errors
174  else if (result.txn)
175  {
176  auto& txn = result.txn;
177 
178  std::shared_ptr<STTx const> stTxn = txn->getSTransaction();
179  if (args.binary)
180  {
181  Serializer s = stTxn->getSerializer();
182  response.set_transaction_binary(s.data(), s.size());
183  }
184  else
185  {
186  RPC::convert(*response.mutable_transaction(), stTxn);
187  }
188 
189  response.set_hash(context.params.hash());
190 
191  auto ledgerIndex = txn->getLedger();
192  response.set_ledger_index(ledgerIndex);
193  if (ledgerIndex)
194  {
195  auto ct =
196  context.app.getLedgerMaster().getCloseTimeBySeq(ledgerIndex);
197  if (ct)
198  response.mutable_date()->set_value(
199  ct->time_since_epoch().count());
200  }
201 
202  RPC::convert(
203  *response.mutable_meta()->mutable_transaction_result(),
204  txn->getResult());
205  response.mutable_meta()->mutable_transaction_result()->set_result(
206  transToken(txn->getResult()));
207 
208  // populate binary metadata
209  if (auto blob = std::get_if<Blob>(&result.meta))
210  {
211  assert(args.binary);
212  Slice slice = makeSlice(*blob);
213  response.set_meta_binary(slice.data(), slice.size());
214  }
215  // populate meta data
216  else if (auto m = std::get_if<std::shared_ptr<TxMeta>>(&result.meta))
217  {
218  auto& meta = *m;
219  if (meta)
220  {
221  RPC::convert(*response.mutable_meta(), meta);
222  auto amt =
223  getDeliveredAmount(context, stTxn, *meta, txn->getLedger());
224  if (amt)
225  {
226  RPC::convert(
227  *response.mutable_meta()->mutable_delivered_amount(),
228  *amt);
229  }
230  }
231  }
232  response.set_validated(result.validated);
233  }
234  return {response, status};
235 }
236 
240  TxArgs const& args,
241  RPC::JsonContext const& context)
242 {
243  Json::Value response;
244  RPC::Status const& error = res.second;
245  TxResult const& result = res.first;
246  // handle errors
247  if (error.toErrorCode() != rpcSUCCESS)
248  {
249  if (error.toErrorCode() == rpcTXN_NOT_FOUND &&
251  {
252  response = Json::Value(Json::objectValue);
253  response[jss::searched_all] =
254  (result.searchedAll == TxSearched::all);
255  error.inject(response);
256  }
257  else
258  {
259  error.inject(response);
260  }
261  }
262  // no errors
263  else if (result.txn)
264  {
265  response = result.txn->getJson(JsonOptions::include_date, args.binary);
266 
267  // populate binary metadata
268  if (auto blob = std::get_if<Blob>(&result.meta))
269  {
270  assert(args.binary);
271  response[jss::meta] = strHex(makeSlice(*blob));
272  }
273  // populate meta data
274  else if (auto m = std::get_if<std::shared_ptr<TxMeta>>(&result.meta))
275  {
276  auto& meta = *m;
277  if (meta)
278  {
279  response[jss::meta] = meta->getJson(JsonOptions::none);
280  insertDeliveredAmount(
281  response[jss::meta], context, result.txn, *meta);
282  }
283  }
284  response[jss::validated] = result.validated;
285  }
286  return response;
287 }
288 
291 {
292  // Deserialize and validate JSON arguments
293 
294  if (!context.params.isMember(jss::transaction))
295  return rpcError(rpcINVALID_PARAMS);
296 
297  TxArgs args;
298 
299  if (!args.hash.parseHex(context.params[jss::transaction].asString()))
300  return rpcError(rpcNOT_IMPL);
301 
302  args.binary = context.params.isMember(jss::binary) &&
303  context.params[jss::binary].asBool();
304 
305  if (context.params.isMember(jss::min_ledger) &&
306  context.params.isMember(jss::max_ledger))
307  {
308  try
309  {
311  context.params[jss::min_ledger].asUInt(),
312  context.params[jss::max_ledger].asUInt());
313  }
314  catch (...)
315  {
316  // One of the calls to `asUInt ()` failed.
318  }
319  }
320 
321  std::pair<TxResult, RPC::Status> res = doTxHelp(context, args);
322  return populateJsonResponse(res, args, context);
323 }
324 
327 {
328  // return values
329  org::xrpl::rpc::v1::GetTransactionResponse response;
330  grpc::Status status = grpc::Status::OK;
331 
332  // input
333  org::xrpl::rpc::v1::GetTransactionRequest& request = context.params;
334 
335  TxArgs args;
336 
337  std::string const& hashBytes = request.hash();
338  args.hash = uint256::fromVoid(hashBytes.data());
339  if (args.hash.size() != hashBytes.size())
340  {
341  grpc::Status errorStatus{
342  grpc::StatusCode::INVALID_ARGUMENT, "ledger hash malformed"};
343  return {response, errorStatus};
344  }
345 
346  args.binary = request.binary();
347 
348  if (request.ledger_range().ledger_index_min() != 0 &&
349  request.ledger_range().ledger_index_max() != 0)
350  {
352  request.ledger_range().ledger_index_min(),
353  request.ledger_range().ledger_index_max());
354  }
355 
356  std::pair<TxResult, RPC::Status> res = doTxHelp(context, args);
357  return populateProtoResponse(res, args, context);
358 }
359 
360 } // namespace ripple
ripple::TxArgs::binary
bool binary
Definition: Tx.cpp:63
ripple::Slice::size
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Definition: Slice.h:79
ripple::JsonOptions::include_date
@ include_date
ripple::rpcDB_DESERIALIZATION
@ rpcDB_DESERIALIZATION
Definition: ErrorCodes.h:134
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::HashPrefix::ledgerMaster
@ ledgerMaster
ledger master data for signing
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:240
ripple::TxSearched::unknown
@ unknown
std::string
STL class.
std::shared_ptr< Transaction >
ripple::Transaction::getJson
Json::Value getJson(JsonOptions options, bool binary=false) const
Definition: Transaction.cpp:213
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
std::pair
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:100
ripple::TxSearched::all
@ all
ripple::LedgerMaster
Definition: LedgerMaster.h:54
ripple::TxSearched
TxSearched
Definition: Transaction.h:56
std::vector< unsigned char >
std::string::size
T size(T... args)
ripple::populateProtoResponse
std::pair< org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse, grpc::Status > populateProtoResponse(std::pair< AccountTxResult, RPC::Status > const &res, AccountTxArgs const &args, RPC::GRPCContext< org::xrpl::rpc::v1::GetAccountTransactionHistoryRequest > const &context)
Definition: AccountTx.cpp:323
ripple::RPC::Context::ledgerMaster
LedgerMaster & ledgerMaster
Definition: Context.h:45
ripple::Slice::data
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition: Slice.h:96
ripple::STObject::getSerializer
Serializer getSerializer() const
Definition: STObject.h:367
ripple::transToken
std::string transToken(TER code)
Definition: TER.cpp:195
ripple::rpcEXCESSIVE_LGR_RANGE
@ rpcEXCESSIVE_LGR_RANGE
Definition: ErrorCodes.h:135
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:92
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::TxResult
Definition: Tx.cpp:52
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:426
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
ripple::Serializer::data
void const * data() const noexcept
Definition: Serializer.h:75
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:73
ripple::Ledger::info
LedgerInfo const & info() const override
Returns information about the ledger.
Definition: Ledger.h:149
ripple::RPC::convert
void convert(org::xrpl::rpc::v1::TransactionResult &to, TER from)
Definition: GRPCHelpers.cpp:961
ripple::rpcSUCCESS
@ rpcSUCCESS
Definition: ErrorCodes.h:44
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::TxArgs::ledgerRange
std::optional< std::pair< uint32_t, uint32_t > > ledgerRange
Definition: Tx.cpp:64
ripple::JsonOptions::none
@ none
ripple::RPC::GRPCContext
Definition: Context.h:70
ripple::doTxGrpc
std::pair< org::xrpl::rpc::v1::GetTransactionResponse, grpc::Status > doTxGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetTransactionRequest > &context)
Definition: Tx.cpp:326
ripple::rpcTXN_NOT_FOUND
@ rpcTXN_NOT_FOUND
Definition: ErrorCodes.h:80
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
ripple::LedgerMaster::getLedgerBySeq
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
Definition: LedgerMaster.cpp:1668
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
std::uint32_t
ripple::range
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition: RangeSet.h:53
ripple::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:29
ripple::TxResult::validated
bool validated
Definition: Tx.cpp:56
ripple::RPC::Status
Status represents the results of an operation that might fail.
Definition: Status.h:39
ripple::Serializer
Definition: Serializer.h:39
ripple::TxArgs
Definition: Tx.cpp:60
ripple::rpcNOT_IMPL
@ rpcNOT_IMPL
Definition: ErrorCodes.h:131
ripple::RPC::GRPCContext::params
RequestType params
Definition: Context.h:72
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::populateJsonResponse
Json::Value populateJsonResponse(std::pair< AccountTxResult, RPC::Status > const &res, AccountTxArgs const &args, RPC::JsonContext const &context)
Definition: AccountTx.cpp:446
ripple::Serializer::size
std::size_t size() const noexcept
Definition: Serializer.h:69
ripple::base_uint::parseHex
bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:384
ripple::doTxHelp
std::pair< TxResult, RPC::Status > doTxHelp(RPC::Context &context, TxArgs const &args)
Definition: Tx.cpp:68
ripple::LedgerMaster::getCloseTimeBySeq
boost::optional< NetClock::time_point > getCloseTimeBySeq(LedgerIndex ledgerIndex)
Definition: LedgerMaster.cpp:1563
ripple::base_uint< 256 >::fromVoid
static base_uint fromVoid(void const *data)
Definition: base_uint.h:223
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
ripple::doTxJson
Json::Value doTxJson(RPC::JsonContext &)
Definition: Tx.cpp:290
std::get_if
T get_if(T... args)
ripple::TxResult::meta
std::variant< std::shared_ptr< TxMeta >, Blob > meta
Definition: Tx.cpp:55
std::optional
ripple::TransactionMaster::fetch
std::variant< std::pair< std::shared_ptr< Transaction >, std::shared_ptr< TxMeta > >, TxSearched > fetch(uint256 const &, error_code_i &ec)
Definition: TransactionMaster.cpp:60
std::make_pair
T make_pair(T... args)
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:45
ripple::rpcINVALID_LGR_RANGE
@ rpcINVALID_LGR_RANGE
Definition: ErrorCodes.h:136
ripple::ClosedInterval
boost::icl::closed_interval< T > ClosedInterval
A closed interval over the domain T.
Definition: RangeSet.h:44
ripple::isValidated
static bool isValidated(LedgerMaster &ledgerMaster, std::uint32_t seq, uint256 const &hash)
Definition: Tx.cpp:41
ripple::TxArgs::hash
uint256 hash
Definition: Tx.cpp:62
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
std::string::data
T data(T... args)
ripple::RPC::Context
The context of information needed to call an RPC.
Definition: Context.h:39
ripple::TxResult::searchedAll
TxSearched searchedAll
Definition: Tx.cpp:57
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::TxResult::txn
Transaction::pointer txn
Definition: Tx.cpp:54
std::variant
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
ripple::Application::getMasterTransaction
virtual TransactionMaster & getMasterTransaction()=0