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 isHexTxID(std::string const& txid)
42 {
43  if (txid.size() != 64)
44  return false;
45 
46  auto const ret =
47  std::find_if(txid.begin(), txid.end(), [](std::string::value_type c) {
48  return !std::isxdigit(static_cast<unsigned char>(c));
49  });
50 
51  return (ret == txid.end());
52 }
53 
54 static bool
55 isValidated(LedgerMaster& ledgerMaster, std::uint32_t seq, uint256 const& hash)
56 {
57  if (!ledgerMaster.haveLedger(seq))
58  return false;
59 
60  if (seq > ledgerMaster.getValidatedLedger()->info().seq)
61  return false;
62 
63  return ledgerMaster.getHashBySeq(seq) == hash;
64 }
65 
66 bool
67 getMetaHex(Ledger const& ledger, uint256 const& transID, std::string& hex)
68 {
70  auto const item = ledger.txMap().peekItem(transID, type);
71 
72  if (!item)
73  return false;
74 
76  return false;
77 
78  SerialIter it(item->slice());
79  it.getVL(); // skip transaction
80  hex = strHex(makeSlice(it.getVL()));
81  return true;
82 }
83 
84 struct TxResult
85 {
88  bool validated = false;
90 };
91 
92 struct TxArgs
93 {
95  bool binary = false;
97 };
98 
100 doTxHelp(RPC::Context& context, TxArgs const& args)
101 {
102  TxResult result;
103 
105 
106  if (args.ledgerRange)
107  {
108  constexpr uint16_t MAX_RANGE = 1000;
109 
110  if (args.ledgerRange->second < args.ledgerRange->first)
111  return {result, rpcINVALID_LGR_RANGE};
112 
113  if (args.ledgerRange->second - args.ledgerRange->first > MAX_RANGE)
114  return {result, rpcEXCESSIVE_LGR_RANGE};
115 
117  args.ledgerRange->first, args.ledgerRange->second);
118  }
119 
120  auto ec{rpcSUCCESS};
121 
122  using TxPair =
124 
126 
128  if (args.ledgerRange)
129  {
130  v = context.app.getMasterTransaction().fetch(args.hash, range, ec);
131  }
132  else
133  {
134  v = context.app.getMasterTransaction().fetch(args.hash, ec);
135  }
136 
137  if (auto e = std::get_if<TxSearched>(&v))
138  {
139  result.searchedAll = *e;
140  return {result, rpcTXN_NOT_FOUND};
141  }
142 
143  auto [txn, meta] = std::get<TxPair>(v);
144 
145  if (ec == rpcDB_DESERIALIZATION)
146  {
147  return {result, ec};
148  }
149  if (!txn)
150  {
151  return {result, rpcTXN_NOT_FOUND};
152  }
153 
154  // populate transaction data
155  result.txn = txn;
156  if (txn->getLedger() == 0)
157  {
158  return {result, rpcSUCCESS};
159  }
160 
162  context.ledgerMaster.getLedgerBySeq(txn->getLedger());
163 
164  if (ledger && meta)
165  {
166  result.meta = meta;
167  result.validated = isValidated(
168  context.ledgerMaster, ledger->info().seq, ledger->info().hash);
169  }
170 
171  return {result, rpcSUCCESS};
172 }
173 
177  TxArgs const& args,
179 {
180  org::xrpl::rpc::v1::GetTransactionResponse response;
181  grpc::Status status = grpc::Status::OK;
182  RPC::Status const& error = res.second;
183  TxResult const& result = res.first;
184  // handle errors
185  if (error.toErrorCode() != rpcSUCCESS)
186  {
187  if (error.toErrorCode() == rpcTXN_NOT_FOUND &&
189  {
190  status = {
191  grpc::StatusCode::NOT_FOUND,
192  "txn not found. searched_all = " +
193  to_string(
194  (result.searchedAll == TxSearched::all ? "true"
195  : "false"))};
196  }
197  else
198  {
199  if (error.toErrorCode() == rpcTXN_NOT_FOUND)
200  status = {grpc::StatusCode::NOT_FOUND, "txn not found"};
201  else
202  status = {grpc::StatusCode::INTERNAL, error.message()};
203  }
204  }
205  // no errors
206  else if (result.txn)
207  {
208  auto& txn = result.txn;
209 
210  std::shared_ptr<STTx const> stTxn = txn->getSTransaction();
211  if (args.binary)
212  {
213  Serializer s = stTxn->getSerializer();
214  response.set_transaction_binary(s.data(), s.size());
215  }
216  else
217  {
218  RPC::convert(*response.mutable_transaction(), stTxn);
219  }
220 
221  response.set_hash(context.params.hash());
222 
223  auto ledgerIndex = txn->getLedger();
224  response.set_ledger_index(ledgerIndex);
225  if (ledgerIndex)
226  {
227  auto ct =
228  context.app.getLedgerMaster().getCloseTimeBySeq(ledgerIndex);
229  if (ct)
230  response.mutable_date()->set_value(
231  ct->time_since_epoch().count());
232  }
233 
234  RPC::convert(
235  *response.mutable_meta()->mutable_transaction_result(),
236  txn->getResult());
237  response.mutable_meta()->mutable_transaction_result()->set_result(
238  transToken(txn->getResult()));
239 
240  // populate binary metadata
241  if (auto blob = std::get_if<Blob>(&result.meta))
242  {
243  assert(args.binary);
244  Slice slice = makeSlice(*blob);
245  response.set_meta_binary(slice.data(), slice.size());
246  }
247  // populate meta data
248  else if (auto m = std::get_if<std::shared_ptr<TxMeta>>(&result.meta))
249  {
250  auto& meta = *m;
251  if (meta)
252  {
253  RPC::convert(*response.mutable_meta(), meta);
254  auto amt =
255  getDeliveredAmount(context, stTxn, *meta, txn->getLedger());
256  if (amt)
257  {
258  RPC::convert(
259  *response.mutable_meta()->mutable_delivered_amount(),
260  *amt);
261  }
262  }
263  }
264  response.set_validated(result.validated);
265  }
266  return {response, status};
267 }
268 
272  TxArgs const& args,
273  RPC::JsonContext const& context)
274 {
275  Json::Value response;
276  RPC::Status const& error = res.second;
277  TxResult const& result = res.first;
278  // handle errors
279  if (error.toErrorCode() != rpcSUCCESS)
280  {
281  if (error.toErrorCode() == rpcTXN_NOT_FOUND &&
283  {
284  response = Json::Value(Json::objectValue);
285  response[jss::searched_all] =
286  (result.searchedAll == TxSearched::all);
287  error.inject(response);
288  }
289  else
290  {
291  error.inject(response);
292  }
293  }
294  // no errors
295  else if (result.txn)
296  {
297  response = result.txn->getJson(JsonOptions::include_date, args.binary);
298 
299  // populate binary metadata
300  if (auto blob = std::get_if<Blob>(&result.meta))
301  {
302  assert(args.binary);
303  response[jss::meta] = strHex(makeSlice(*blob));
304  }
305  // populate meta data
306  else if (auto m = std::get_if<std::shared_ptr<TxMeta>>(&result.meta))
307  {
308  auto& meta = *m;
309  if (meta)
310  {
311  response[jss::meta] = meta->getJson(JsonOptions::none);
312  insertDeliveredAmount(
313  response[jss::meta], context, result.txn, *meta);
314  }
315  }
316  response[jss::validated] = result.validated;
317  }
318  return response;
319 }
320 
323 {
324  // Deserialize and validate JSON arguments
325 
326  if (!context.params.isMember(jss::transaction))
327  return rpcError(rpcINVALID_PARAMS);
328 
329  std::string txHash = context.params[jss::transaction].asString();
330  if (!isHexTxID(txHash))
331  return rpcError(rpcNOT_IMPL);
332 
333  TxArgs args;
334  args.hash = from_hex_text<uint256>(txHash);
335 
336  args.binary = context.params.isMember(jss::binary) &&
337  context.params[jss::binary].asBool();
338 
339  if (context.params.isMember(jss::min_ledger) &&
340  context.params.isMember(jss::max_ledger))
341  {
342  try
343  {
345  context.params[jss::min_ledger].asUInt(),
346  context.params[jss::max_ledger].asUInt());
347  }
348  catch (...)
349  {
350  // One of the calls to `asUInt ()` failed.
352  }
353  }
354 
355  std::pair<TxResult, RPC::Status> res = doTxHelp(context, args);
356  return populateJsonResponse(res, args, context);
357 }
358 
361 {
362  // return values
363  org::xrpl::rpc::v1::GetTransactionResponse response;
364  grpc::Status status = grpc::Status::OK;
365 
366  // input
367  org::xrpl::rpc::v1::GetTransactionRequest& request = context.params;
368 
369  TxArgs args;
370 
371  std::string const& hashBytes = request.hash();
372  args.hash = uint256::fromVoid(hashBytes.data());
373  if (args.hash.size() != hashBytes.size())
374  {
375  grpc::Status errorStatus{
376  grpc::StatusCode::INVALID_ARGUMENT, "ledger hash malformed"};
377  return {response, errorStatus};
378  }
379 
380  args.binary = request.binary();
381 
382  if (request.ledger_range().ledger_index_min() != 0 &&
383  request.ledger_range().ledger_index_max() != 0)
384  {
386  request.ledger_range().ledger_index_min(),
387  request.ledger_range().ledger_index_max());
388  }
389 
390  std::pair<TxResult, RPC::Status> res = doTxHelp(context, args);
391  return populateProtoResponse(res, args, context);
392 }
393 
394 } // namespace ripple
ripple::TxArgs::binary
bool binary
Definition: Tx.cpp:95
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::find_if
T find_if(T... args)
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::SHAMap::peekItem
std::shared_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
Definition: SHAMap.cpp:543
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:373
ripple::transToken
std::string transToken(TER code)
Definition: TER.cpp:196
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:84
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:462
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< 256 >
ripple::Ledger::info
LedgerInfo const & info() const override
Returns information about the ledger.
Definition: Ledger.h:155
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::Ledger
Holds a ledger.
Definition: Ledger.h:77
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::getMetaHex
bool getMetaHex(Ledger const &ledger, uint256 const &transID, std::string &hex)
Definition: Tx.cpp:67
ripple::TxArgs::ledgerRange
std::optional< std::pair< uint32_t, uint32_t > > ledgerRange
Definition: Tx.cpp:96
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:360
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:1667
ripple::SerialIter
Definition: Serializer.h:308
ripple::SerialIter::getVL
Blob getVL()
Definition: Serializer.cpp:500
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::isHexTxID
static bool isHexTxID(std::string const &txid)
Definition: Tx.cpp:41
ripple::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:29
ripple::SHAMapAbstractNode::TNType
TNType
Definition: SHAMapTreeNode.h:125
ripple::TxResult::validated
bool validated
Definition: Tx.cpp:88
ripple::RPC::Status
Status represents the results of an operation that might fail.
Definition: Status.h:39
ripple::Serializer
Definition: Serializer.h:39
ripple::Ledger::txMap
SHAMap const & txMap() const
Definition: Ledger.h:301
ripple::TxArgs
Definition: Tx.cpp:92
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::doTxHelp
std::pair< TxResult, RPC::Status > doTxHelp(RPC::Context &context, TxArgs const &args)
Definition: Tx.cpp:100
std::string::begin
T begin(T... args)
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:213
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
ripple::doTxJson
Json::Value doTxJson(RPC::JsonContext &)
Definition: Tx.cpp:322
std::get_if
T get_if(T... args)
ripple::TxResult::meta
std::variant< std::shared_ptr< TxMeta >, Blob > meta
Definition: Tx.cpp:87
ripple::SHAMapAbstractNode::tnTRANSACTION_MD
@ tnTRANSACTION_MD
Definition: SHAMapTreeNode.h:129
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:67
std::string::end
T end(T... args)
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:55
ripple::TxArgs::hash
uint256 hash
Definition: Tx.cpp:94
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:89
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::TxResult::txn
Transaction::pointer txn
Definition: Tx.cpp:86
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