20 #include <ripple/app/ledger/LedgerMaster.h>
21 #include <ripple/app/ledger/TransactionMaster.h>
22 #include <ripple/app/misc/DeliverMax.h>
23 #include <ripple/app/misc/NetworkOPs.h>
24 #include <ripple/app/misc/Transaction.h>
25 #include <ripple/app/rdb/RelationalDatabase.h>
26 #include <ripple/basics/ToString.h>
27 #include <ripple/net/RPCErr.h>
28 #include <ripple/protocol/ErrorCodes.h>
29 #include <ripple/protocol/NFTSyntheticSerializer.h>
30 #include <ripple/protocol/jss.h>
31 #include <ripple/rpc/CTID.h>
32 #include <ripple/rpc/Context.h>
33 #include <ripple/rpc/DeliveredAmount.h>
34 #include <ripple/rpc/GRPCHandlers.h>
35 #include <ripple/rpc/impl/RPCHelpers.h>
79 Throw<std::runtime_error>(
80 "Called doTxPostgres yet not in reporting mode");
90 "Use of CTIDs on reporting mode is not currently supported."}};
92 JLOG(context.
j.
debug()) <<
"Fetching from postgres";
113 return {res, {
rpcINTERNAL,
"Error making SHAMap node"}};
115 auto item = (
static_cast<SHAMapLeafNode*
>(node.get()))->peekItem();
119 return {res, {
rpcINTERNAL,
"Error reading SHAMap node"}};
123 JLOG(context.
j.
debug()) <<
"Successfully fetched from db";
128 return {res, {
rpcINTERNAL,
"Error deserializing SHAMap node"}};
131 res.
txn = std::make_shared<Transaction>(sttx, reason, context.
app);
139 res.
meta = std::move(blob);
143 res.
meta = std::make_shared<TxMeta>(
148 auto const ledgerInfo =
158 JLOG(context.
j.
error()) <<
"Failed to fetch from db";
160 return {res, {
rpcINTERNAL,
"Containing SHAMap node not found"}};
163 JLOG(context.
j.
debug()) <<
"tx flat fetch time : "
164 << ((end - start).count() / 1000000000.0);
175 if (min >=
range.lower() && max <=
range.upper())
188 return {res, {
rpcINTERNAL,
"unexpected Postgres response"}};
202 constexpr uint16_t MAX_RANGE = 1000;
225 args.
ctid->first, args.
ctid->second);
244 if (
auto e = std::get_if<TxSearched>(&v))
250 auto [txn, meta] = std::get<TxPair>(v);
263 if (txn->getLedger() == 0)
271 if (ledger && !ledger->
open())
278 result.
meta = meta->getAsObject().getSerializer().getData();
291 uint32_t lgrSeq = ledger->
info().
seq;
295 if (txnIdx <= 0xFFFFU && netID < 0xFFFFU && lgrSeq < 0x0FFF
'FFFFUL)
297 RPC::encodeCTID(lgrSeq, (uint16_t)txnIdx, (uint16_t)netID);
300 return {result, rpcSUCCESS};
304 populateJsonResponse(
305 std::pair<TxResult, RPC::Status> const& res,
307 RPC::JsonContext const& context)
309 Json::Value response;
310 RPC::Status const& error = res.second;
311 TxResult const& result = res.first;
313 if (error.toErrorCode() != rpcSUCCESS)
315 if (error.toErrorCode() == rpcTXN_NOT_FOUND &&
316 result.searchedAll != TxSearched::unknown)
318 response = Json::Value(Json::objectValue);
319 response[jss::searched_all] =
320 (result.searchedAll == TxSearched::all);
321 error.inject(response);
325 error.inject(response);
331 auto const& sttx = result.txn->getSTransaction();
332 if (context.apiVersion > 1)
334 constexpr auto optionsJson =
335 JsonOptions::include_date | JsonOptions::disable_API_prior_V2;
337 response[jss::tx_blob] = result.txn->getJson(optionsJson, true);
340 response[jss::tx_json] = result.txn->getJson(optionsJson);
341 RPC::insertDeliverMax(
342 response[jss::tx_json],
347 // Note, result.ledgerHash is only set in a closed or validated
348 // ledger - as seen in `doTxHelp` and `doTxPostgres`
349 if (result.ledgerHash)
350 response[jss::ledger_hash] = to_string(*result.ledgerHash);
352 response[jss::hash] = to_string(result.txn->getID());
353 if (result.validated)
355 response[jss::ledger_index] = result.txn->getLedger();
356 if (result.closeTime)
357 response[jss::close_time_iso] =
358 to_string_iso(*result.closeTime);
364 result.txn->getJson(JsonOptions::include_date, args.binary);
366 RPC::insertDeliverMax(
367 response, sttx->getTxnType(), context.apiVersion);
370 // populate binary metadata
371 if (auto blob = std::get_if<Blob>(&result.meta))
375 (context.apiVersion > 1 ? jss::meta_blob : jss::meta);
376 response[json_meta] = strHex(makeSlice(*blob));
378 // populate meta data
379 else if (auto m = std::get_if<std::shared_ptr<TxMeta>>(&result.meta))
384 response[jss::meta] = meta->getJson(JsonOptions::none);
385 insertDeliveredAmount(
386 response[jss::meta], context, result.txn, *meta);
387 insertNFTSyntheticInJson(response, sttx, *meta);
390 response[jss::validated] = result.validated;
393 response[jss::ctid] = *(result.ctid);
399 doTxJson(RPC::JsonContext& context)
401 if (!context.app.config().useTxTables())
402 return rpcError(rpcNOT_ENABLED);
404 // Deserialize and validate JSON arguments
408 if (context.params.isMember(jss::transaction) &&
409 context.params.isMember(jss::ctid))
410 // specifying both is ambiguous
411 return rpcError(rpcINVALID_PARAMS);
413 if (context.params.isMember(jss::transaction))
416 if (!hash.parseHex(context.params[jss::transaction].asString()))
417 return rpcError(rpcNOT_IMPL);
420 else if (context.params.isMember(jss::ctid))
422 auto ctid = RPC::decodeCTID(context.params[jss::ctid].asString());
424 return rpcError(rpcINVALID_PARAMS);
426 auto const [lgr_seq, txn_idx, net_id] = *ctid;
427 if (net_id != context.app.config().NETWORK_ID)
429 std::stringstream out;
430 out << "Wrong network. You should submit this request to a node "
431 "running on NetworkID: "
433 return RPC::make_error(rpcWRONG_NETWORK, out.str());
435 args.ctid = {lgr_seq, txn_idx};
438 return rpcError(rpcINVALID_PARAMS);
440 args.binary = context.params.isMember(jss::binary) &&
441 context.params[jss::binary].asBool();
443 if (context.params.isMember(jss::min_ledger) &&
444 context.params.isMember(jss::max_ledger))
448 args.ledgerRange = std::make_pair(
449 context.params[jss::min_ledger].asUInt(),
450 context.params[jss::max_ledger].asUInt());
454 // One of the calls to `asUInt ()` failed.
455 return rpcError(rpcINVALID_LGR_RANGE);
459 std::pair<TxResult, RPC::Status> res = doTxHelp(context, args);
460 return populateJsonResponse(res, args, context);
463 } // namespace ripple
virtual Family & getNodeFamily()=0
@ ledgerMaster
ledger master data for signing
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)
uint256 const & getNodestoreHash()
std::optional< NetClock::time_point > closeTime
void setLedger(LedgerIndex ledger)
LedgerMaster & ledgerMaster
virtual std::optional< LedgerInfo > getLedgerInfoByIndex(LedgerIndex ledgerSeq)=0
getLedgerInfoByIndex Returns a ledger by its sequence.
virtual NodeStore::Database & db()=0
std::optional< std::pair< uint32_t, uint16_t > > ctid
LedgerInfo const & info() const override
Returns information about the ledger.
virtual LedgerMaster & getLedgerMaster()=0
std::pair< std::shared_ptr< STTx const >, std::shared_ptr< STObject const > > deserializeTxPlusMeta(SHAMapItem const &item)
Deserialize a SHAMapItem containing STTx + STObject metadata.
LedgerIndex getLedger() const
std::optional< std::pair< uint32_t, uint32_t > > ledgerRange
virtual Config & config()=0
virtual RelationalDatabase & getRelationalDatabase()=0
static Locator locate(uint256 const &id, Application &app)
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
std::optional< uint256 > txnIdFromIndex(uint32_t ledgerSeq, uint32_t txnIndex)
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
std::optional< std::string > ctid
const SF_UINT32 sfTransactionIndex
std::optional< uint256 > ledgerHash
static std::shared_ptr< SHAMapTreeNode > makeFromPrefix(Slice rawNode, SHAMapHash const &hash)
std::optional< uint256 > hash
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::pair< TxResult, RPC::Status > doTxPostgres(RPC::Context &context, TxArgs const &args)
std::optional< NetClock::time_point > getCloseTimeBySeq(LedgerIndex ledgerIndex)
void setStatus(TransStatus status, std::uint32_t ledgerSeq)
bool open() const override
Returns true if this reflects an open ledger.
std::pair< TxResult, RPC::Status > doTxHelp(RPC::Context &context, TxArgs args)
std::variant< std::shared_ptr< TxMeta >, Blob > meta
std::variant< std::pair< std::shared_ptr< Transaction >, std::shared_ptr< TxMeta > >, TxSearched > fetch(uint256 const &, error_code_i &ec)
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, std::uint32_t ledgerSeq=0, FetchType fetchType=FetchType::synchronous, bool duplicate=false)
Fetch a node object.
boost::icl::closed_interval< T > ClosedInterval
A closed interval over the domain T.
static bool isValidated(LedgerMaster &ledgerMaster, std::uint32_t seq, uint256 const &hash)
uint32_t getLedgerSequence()
The context of information needed to call an RPC.
virtual TransactionMaster & getMasterTransaction()=0
ClosedInterval< uint32_t > const & getLedgerRangeSearched()