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/RPCHelpers.h>
32 
33 namespace ripple {
34 
35 // {
36 // transaction: <hex>
37 // }
38 
39 static bool
40 isValidated(LedgerMaster& ledgerMaster, std::uint32_t seq, uint256 const& hash)
41 {
42  if (!ledgerMaster.haveLedger(seq))
43  return false;
44 
45  if (seq > ledgerMaster.getValidatedLedger()->info().seq)
46  return false;
47 
48  return ledgerMaster.getHashBySeq(seq) == hash;
49 }
50 
51 struct TxResult
52 {
55  bool validated = false;
57 };
58 
59 struct TxArgs
60 {
62  bool binary = false;
64 };
65 
67 doTxPostgres(RPC::Context& context, TxArgs const& args)
68 {
69  if (!context.app.config().reporting())
70  {
71  assert(false);
72  Throw<std::runtime_error>(
73  "Called doTxPostgres yet not in reporting mode");
74  }
75  TxResult res;
77 
78  JLOG(context.j.debug()) << "Fetching from postgres";
79  Transaction::Locator locator = Transaction::locate(args.hash, context.app);
80 
82  pair;
83  // database returned the nodestore hash. Fetch the txn directly from the
84  // nodestore. Don't traverse the transaction SHAMap
85  if (locator.isFound())
86  {
87  auto start = std::chrono::system_clock::now();
88  // The second argument of fetch is ignored when not using shards
89  if (auto obj = context.app.getNodeFamily().db().fetchNodeObject(
90  locator.getNodestoreHash(), locator.getLedgerSequence()))
91  {
93  makeSlice(obj->getData()),
94  SHAMapHash{locator.getNodestoreHash()});
95  if (!node)
96  {
97  assert(false);
98  return {res, {rpcINTERNAL, "Error making SHAMap node"}};
99  }
100  auto item = (static_cast<SHAMapLeafNode*>(node.get()))->peekItem();
101  if (!item)
102  {
103  assert(false);
104  return {res, {rpcINTERNAL, "Error reading SHAMap node"}};
105  }
106 
107  auto [sttx, meta] = deserializeTxPlusMeta(*item);
108  JLOG(context.j.debug()) << "Successfully fetched from db";
109 
110  if (!sttx || !meta)
111  {
112  assert(false);
113  return {res, {rpcINTERNAL, "Error deserializing SHAMap node"}};
114  }
115  std::string reason;
116  res.txn = std::make_shared<Transaction>(sttx, reason, context.app);
117  res.txn->setLedger(locator.getLedgerSequence());
118  res.txn->setStatus(COMMITTED);
119  if (args.binary)
120  {
121  SerialIter it(item->slice());
122  it.skip(it.getVLDataLength()); // skip transaction
123  Blob blob = it.getVL();
124  res.meta = std::move(blob);
125  }
126  else
127  {
128  res.meta = std::make_shared<TxMeta>(
129  args.hash, res.txn->getLedger(), *meta);
130  }
131  res.validated = true;
132  return {res, rpcSUCCESS};
133  }
134  else
135  {
136  JLOG(context.j.error()) << "Failed to fetch from db";
137  assert(false);
138  return {res, {rpcINTERNAL, "Containing SHAMap node not found"}};
139  }
140  auto end = std::chrono::system_clock::now();
141  JLOG(context.j.debug()) << "tx flat fetch time : "
142  << ((end - start).count() / 1000000000.0);
143  }
144  // database did not find the transaction, and returned the ledger range
145  // that was searched
146  else
147  {
148  if (args.ledgerRange)
149  {
150  auto range = locator.getLedgerRangeSearched();
151  auto min = args.ledgerRange->first;
152  auto max = args.ledgerRange->second;
153  if (min >= range.lower() && max <= range.upper())
154  {
156  }
157  else
158  {
160  }
161  }
162  return {res, rpcTXN_NOT_FOUND};
163  }
164  // database didn't return anything. This shouldn't happen
165  assert(false);
166  return {res, {rpcINTERNAL, "unexpected Postgres response"}};
167 }
168 
170 doTxHelp(RPC::Context& context, TxArgs const& args)
171 {
172  if (context.app.config().reporting())
173  return doTxPostgres(context, args);
174  TxResult result;
175 
177 
178  if (args.ledgerRange)
179  {
180  constexpr uint16_t MAX_RANGE = 1000;
181 
182  if (args.ledgerRange->second < args.ledgerRange->first)
183  return {result, rpcINVALID_LGR_RANGE};
184 
185  if (args.ledgerRange->second - args.ledgerRange->first > MAX_RANGE)
186  return {result, rpcEXCESSIVE_LGR_RANGE};
187 
189  args.ledgerRange->first, args.ledgerRange->second);
190  }
191 
192  auto ec{rpcSUCCESS};
193 
194  using TxPair =
196 
198 
200  if (args.ledgerRange)
201  {
202  v = context.app.getMasterTransaction().fetch(args.hash, range, ec);
203  }
204  else
205  {
206  v = context.app.getMasterTransaction().fetch(args.hash, ec);
207  }
208 
209  if (auto e = std::get_if<TxSearched>(&v))
210  {
211  result.searchedAll = *e;
212  return {result, rpcTXN_NOT_FOUND};
213  }
214 
215  auto [txn, meta] = std::get<TxPair>(v);
216 
217  if (ec == rpcDB_DESERIALIZATION)
218  {
219  return {result, ec};
220  }
221  if (!txn)
222  {
223  return {result, rpcTXN_NOT_FOUND};
224  }
225 
226  // populate transaction data
227  result.txn = txn;
228  if (txn->getLedger() == 0)
229  {
230  return {result, rpcSUCCESS};
231  }
232 
234  context.ledgerMaster.getLedgerBySeq(txn->getLedger());
235 
236  if (ledger && meta)
237  {
238  if (args.binary)
239  {
240  result.meta = meta->getAsObject().getSerializer().getData();
241  }
242  else
243  {
244  result.meta = meta;
245  }
246  result.validated = isValidated(
247  context.ledgerMaster, ledger->info().seq, ledger->info().hash);
248  }
249 
250  return {result, rpcSUCCESS};
251 }
252 
256  TxArgs const& args,
257  RPC::JsonContext const& context)
258 {
259  Json::Value response;
260  RPC::Status const& error = res.second;
261  TxResult const& result = res.first;
262  // handle errors
263  if (error.toErrorCode() != rpcSUCCESS)
264  {
265  if (error.toErrorCode() == rpcTXN_NOT_FOUND &&
267  {
268  response = Json::Value(Json::objectValue);
269  response[jss::searched_all] =
270  (result.searchedAll == TxSearched::all);
271  error.inject(response);
272  }
273  else
274  {
275  error.inject(response);
276  }
277  }
278  // no errors
279  else if (result.txn)
280  {
281  response = result.txn->getJson(JsonOptions::include_date, args.binary);
282 
283  // populate binary metadata
284  if (auto blob = std::get_if<Blob>(&result.meta))
285  {
286  assert(args.binary);
287  response[jss::meta] = strHex(makeSlice(*blob));
288  }
289  // populate meta data
290  else if (auto m = std::get_if<std::shared_ptr<TxMeta>>(&result.meta))
291  {
292  auto& meta = *m;
293  if (meta)
294  {
295  response[jss::meta] = meta->getJson(JsonOptions::none);
296  insertDeliveredAmount(
297  response[jss::meta], context, result.txn, *meta);
298  }
299  }
300  response[jss::validated] = result.validated;
301  }
302  return response;
303 }
304 
307 {
308  if (!context.app.config().useTxTables())
309  return rpcError(rpcNOT_ENABLED);
310 
311  // Deserialize and validate JSON arguments
312 
313  if (!context.params.isMember(jss::transaction))
314  return rpcError(rpcINVALID_PARAMS);
315 
316  TxArgs args;
317 
318  if (!args.hash.parseHex(context.params[jss::transaction].asString()))
319  return rpcError(rpcNOT_IMPL);
320 
321  args.binary = context.params.isMember(jss::binary) &&
322  context.params[jss::binary].asBool();
323 
324  if (context.params.isMember(jss::min_ledger) &&
325  context.params.isMember(jss::max_ledger))
326  {
327  try
328  {
330  context.params[jss::min_ledger].asUInt(),
331  context.params[jss::max_ledger].asUInt());
332  }
333  catch (...)
334  {
335  // One of the calls to `asUInt ()` failed.
337  }
338  }
339 
340  std::pair<TxResult, RPC::Status> res = doTxHelp(context, args);
341  return populateJsonResponse(res, args, context);
342 }
343 
344 } // namespace ripple
ripple::COMMITTED
@ COMMITTED
Definition: Transaction.h:50
ripple::TxArgs::binary
bool binary
Definition: Tx.cpp:62
ripple::JsonOptions::include_date
@ include_date
ripple::Application::getNodeFamily
virtual Family & getNodeFamily()=0
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:241
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:168
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
std::pair
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:91
ripple::TxSearched::all
@ all
ripple::Transaction::Locator::getNodestoreHash
uint256 const & getNodestoreHash()
Definition: Transaction.h:336
ripple::LedgerMaster
Definition: LedgerMaster.h:70
ripple::TxSearched
TxSearched
Definition: Transaction.h:57
std::vector< unsigned char >
ripple::Transaction::setLedger
void setLedger(LedgerIndex ledger)
Definition: Transaction.h:139
ripple::RPC::Context::ledgerMaster
LedgerMaster & ledgerMaster
Definition: Context.h:45
ripple::rpcEXCESSIVE_LGR_RANGE
@ rpcEXCESSIVE_LGR_RANGE
Definition: ErrorCodes.h:135
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:83
ripple::TxResult
Definition: Tx.cpp:51
ripple::Family::db
virtual NodeStore::Database & db()=0
ripple::SHAMapLeafNode
Definition: SHAMapLeafNode.h:32
ripple::SHAMapHash
Definition: SHAMapHash.h:32
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
ripple::RPC::Context::j
const beast::Journal j
Definition: Context.h:41
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:82
ripple::Ledger::info
LedgerInfo const & info() const override
Returns information about the ledger.
Definition: Ledger.h:148
ripple::rpcSUCCESS
@ rpcSUCCESS
Definition: ErrorCodes.h:44
ripple::Config::reporting
bool reporting() const
Definition: Config.h:318
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::Transaction::Locator
Definition: Transaction.h:315
ripple::deserializeTxPlusMeta
std::pair< std::shared_ptr< STTx const >, std::shared_ptr< STObject const > > deserializeTxPlusMeta(SHAMapItem const &item)
Deserialize a SHAMapItem containing STTx + STObject metadata.
Definition: Ledger.cpp:389
ripple::Transaction::getLedger
LedgerIndex getLedger() const
Definition: Transaction.h:100
ripple::TxArgs::ledgerRange
std::optional< std::pair< uint32_t, uint32_t > > ledgerRange
Definition: Tx.cpp:63
ripple::JsonOptions::none
@ none
ripple::Application::config
virtual Config & config()=0
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:324
ripple::rpcTXN_NOT_FOUND
@ rpcTXN_NOT_FOUND
Definition: ErrorCodes.h:80
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
beast::Journal::error
Stream error() const
Definition: Journal.h:333
ripple::Transaction::locate
static Locator locate(uint256 const &id, Application &app)
Definition: Transaction.cpp:134
ripple::LedgerMaster::getLedgerBySeq
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
Definition: LedgerMaster.cpp:1816
ripple::rpcNOT_ENABLED
@ rpcNOT_ENABLED
Definition: ErrorCodes.h:59
ripple::SerialIter
Definition: Serializer.h:310
ripple::SerialIter::getVL
Blob getVL()
Definition: Serializer.cpp:508
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::SerialIter::skip
void skip(int num)
Definition: Serializer.cpp:352
ripple::range
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition: RangeSet.h:53
ripple::TxResult::validated
bool validated
Definition: Tx.cpp:55
ripple::RPC::Status
Status represents the results of an operation that might fail.
Definition: Status.h:39
ripple::rpcINTERNAL
@ rpcINTERNAL
Definition: ErrorCodes.h:130
ripple::SHAMapTreeNode::makeFromPrefix
static std::shared_ptr< SHAMapTreeNode > makeFromPrefix(Slice rawNode, SHAMapHash const &hash)
Definition: SHAMapTreeNode.cpp:148
ripple::TxArgs
Definition: Tx.cpp:59
ripple::rpcNOT_IMPL
@ rpcNOT_IMPL
Definition: ErrorCodes.h:131
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:271
ripple::doTxPostgres
std::pair< TxResult, RPC::Status > doTxPostgres(RPC::Context &context, TxArgs const &args)
Definition: Tx.cpp:67
ripple::doTxHelp
std::pair< TxResult, RPC::Status > doTxHelp(RPC::Context &context, TxArgs const &args)
Definition: Tx.cpp:170
ripple::Transaction::setStatus
void setStatus(TransStatus status, std::uint32_t ledgerSeq)
Definition: Transaction.cpp:62
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
ripple::SerialIter::getVLDataLength
int getVLDataLength()
Definition: Serializer.cpp:470
ripple::doTxJson
Json::Value doTxJson(RPC::JsonContext &)
Definition: Tx.cpp:306
std::get_if
T get_if(T... args)
ripple::TxResult::meta
std::variant< std::shared_ptr< TxMeta >, Blob > meta
Definition: Tx.cpp:54
std::optional
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
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:30
ripple::NodeStore::Database::fetchNodeObject
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, std::uint32_t ledgerSeq=0, FetchType fetchType=FetchType::synchronous, bool duplicate=false)
Fetch a node object.
Definition: Database.cpp:252
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::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:496
ripple::isValidated
static bool isValidated(LedgerMaster &ledgerMaster, std::uint32_t seq, uint256 const &hash)
Definition: Tx.cpp:40
ripple::Transaction::Locator::getLedgerSequence
uint32_t getLedgerSequence()
Definition: Transaction.h:345
ripple::TxArgs::hash
uint256 hash
Definition: Tx.cpp:61
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::RPC::Context
The context of information needed to call an RPC.
Definition: Context.h:39
ripple::TxResult::searchedAll
TxSearched searchedAll
Definition: Tx.cpp:56
ripple::Transaction::Locator::isFound
bool isFound()
Definition: Transaction.h:326
ripple::TxSearched::some
@ some
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::TxResult::txn
Transaction::pointer txn
Definition: Tx.cpp:53
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
ripple::Transaction::Locator::getLedgerRangeSearched
ClosedInterval< uint32_t > const & getLedgerRangeSearched()
Definition: Transaction.h:354
std::chrono::system_clock::now
T now(T... args)