rippled
Loading...
Searching...
No Matches
Tx.cpp
1#include <xrpld/app/ledger/LedgerMaster.h>
2#include <xrpld/app/ledger/TransactionMaster.h>
3#include <xrpld/app/misc/DeliverMax.h>
4#include <xrpld/app/misc/Transaction.h>
5#include <xrpld/rpc/CTID.h>
6#include <xrpld/rpc/Context.h>
7#include <xrpld/rpc/DeliveredAmount.h>
8#include <xrpld/rpc/GRPCHandlers.h>
9#include <xrpld/rpc/MPTokenIssuanceID.h>
10#include <xrpld/rpc/Status.h>
11
12#include <xrpl/basics/ToString.h>
13#include <xrpl/core/NetworkIDService.h>
14#include <xrpl/protocol/ErrorCodes.h>
15#include <xrpl/protocol/NFTSyntheticSerializer.h>
16#include <xrpl/protocol/RPCErr.h>
17#include <xrpl/protocol/jss.h>
18#include <xrpl/rdb/RelationalDatabase.h>
19#include <xrpl/server/NetworkOPs.h>
20
21#include <regex>
22
23namespace xrpl {
24
25static bool
27{
28 if (!ledgerMaster.haveLedger(seq))
29 return false;
30
31 if (seq > ledgerMaster.getValidatedLedger()->header().seq)
32 return false;
33
34 return ledgerMaster.getHashBySeq(seq) == hash;
35}
36
47
55
58{
59 TxResult result;
60
62
63 if (args.ledgerRange)
64 {
65 constexpr uint16_t MAX_RANGE = 1000;
66
67 if (args.ledgerRange->second < args.ledgerRange->first)
68 return {result, rpcINVALID_LGR_RANGE};
69
70 if (args.ledgerRange->second - args.ledgerRange->first > MAX_RANGE)
71 return {result, rpcEXCESSIVE_LGR_RANGE};
72
73 range = ClosedInterval<uint32_t>(args.ledgerRange->first, args.ledgerRange->second);
74 }
75
76 auto ec{rpcSUCCESS};
77
79
82
83 if (args.ctid)
84 {
85 args.hash =
86 context.app.getLedgerMaster().txnIdFromIndex(args.ctid->first, args.ctid->second);
87
88 if (args.hash)
89 range = ClosedInterval<uint32_t>(args.ctid->first, args.ctid->second);
90 }
91
92 if (!args.hash)
93 return {result, rpcTXN_NOT_FOUND};
94
95 if (args.ledgerRange)
96 {
97 v = context.app.getMasterTransaction().fetch(*(args.hash), range, ec);
98 }
99 else
100 {
101 v = context.app.getMasterTransaction().fetch(*(args.hash), ec);
102 }
103
104 if (auto e = std::get_if<TxSearched>(&v))
105 {
106 result.searchedAll = *e;
107 return {result, rpcTXN_NOT_FOUND};
108 }
109
110 auto [txn, meta] = std::get<TxPair>(v);
111
112 if (ec == rpcDB_DESERIALIZATION)
113 {
114 return {result, ec};
115 }
116 if (!txn)
117 {
118 return {result, rpcTXN_NOT_FOUND};
119 }
120
121 // populate transaction data
122 result.txn = txn;
123 if (txn->getLedger() == 0)
124 {
125 return {result, rpcSUCCESS};
126 }
127
128 std::shared_ptr<Ledger const> const ledger =
129 context.ledgerMaster.getLedgerBySeq(txn->getLedger());
130
131 if (ledger && !ledger->open())
132 result.ledgerHash = ledger->header().hash;
133
134 if (ledger && meta)
135 {
136 if (args.binary)
137 {
138 result.meta = meta->getAsObject().getSerializer().getData();
139 }
140 else
141 {
142 result.meta = meta;
143 }
144 result.validated =
145 isValidated(context.ledgerMaster, ledger->header().seq, ledger->header().hash);
146 if (result.validated)
147 result.closeTime = context.ledgerMaster.getCloseTimeBySeq(txn->getLedger());
148
149 // compute outgoing CTID
150 if (meta->getAsObject().isFieldPresent(sfTransactionIndex))
151 {
152 uint32_t const lgrSeq = ledger->header().seq;
153 uint32_t const txnIdx = meta->getAsObject().getFieldU32(sfTransactionIndex);
154 uint32_t const netID = context.app.getNetworkIDService().getNetworkID();
155
156 if (txnIdx <= 0xFFFFU && netID < 0xFFFFU && lgrSeq < 0x0FFF'FFFFUL)
157 result.ctid = RPC::encodeCTID(lgrSeq, txnIdx, netID);
158 }
159 }
160
161 return {result, rpcSUCCESS};
162}
163
167 TxArgs const& args,
168 RPC::JsonContext const& context)
169{
170 Json::Value response;
171 RPC::Status const& error = res.second;
172 TxResult const& result = res.first;
173 // handle errors
174 if (error.toErrorCode() != rpcSUCCESS)
175 {
176 if (error.toErrorCode() == rpcTXN_NOT_FOUND && result.searchedAll != TxSearched::Unknown)
177 {
178 response = Json::Value(Json::objectValue);
179 response[jss::searched_all] = (result.searchedAll == TxSearched::All);
180 error.inject(response);
181 }
182 else
183 {
184 error.inject(response);
185 }
186 }
187 // no errors
188 else if (result.txn)
189 {
190 auto const& sttx = result.txn->getSTransaction();
191 if (context.apiVersion > 1)
192 {
193 constexpr auto optionsJson =
195 if (args.binary)
196 {
197 response[jss::tx_blob] = result.txn->getJson(optionsJson, true);
198 }
199 else
200 {
201 response[jss::tx_json] = result.txn->getJson(optionsJson);
203 response[jss::tx_json], sttx->getTxnType(), context.apiVersion);
204 }
205
206 // Note, result.ledgerHash is only set in a closed or validated
207 // ledger - as seen in `doTxHelp`
208 if (result.ledgerHash)
209 response[jss::ledger_hash] = to_string(*result.ledgerHash);
210
211 response[jss::hash] = to_string(result.txn->getID());
212 if (result.validated)
213 {
214 response[jss::ledger_index] = result.txn->getLedger();
215 if (result.closeTime)
216 response[jss::close_time_iso] = to_string_iso(*result.closeTime);
217 }
218 }
219 else
220 {
221 response = result.txn->getJson(JsonOptions::include_date, args.binary);
222 if (!args.binary)
223 RPC::insertDeliverMax(response, sttx->getTxnType(), context.apiVersion);
224 }
225
226 // populate binary metadata
227 if (auto blob = std::get_if<Blob>(&result.meta))
228 {
229 XRPL_ASSERT(args.binary, "xrpl::populateJsonResponse : binary is set");
230 auto json_meta = (context.apiVersion > 1 ? jss::meta_blob : jss::meta);
231 response[json_meta] = strHex(makeSlice(*blob));
232 }
233 // populate meta data
234 else if (auto m = std::get_if<std::shared_ptr<TxMeta>>(&result.meta))
235 {
236 auto& meta = *m;
237 if (meta)
238 {
239 response[jss::meta] = meta->getJson(JsonOptions::none);
240 insertDeliveredAmount(response[jss::meta], context, result.txn, *meta);
241 RPC::insertNFTSyntheticInJson(response, sttx, *meta);
242 RPC::insertMPTokenIssuanceID(response[jss::meta], sttx, *meta);
243 }
244 }
245 response[jss::validated] = result.validated;
246
247 if (result.ctid)
248 response[jss::ctid] = *(result.ctid);
249 }
250 return response;
251}
252
255{
256 if (!context.app.config().useTxTables())
257 return rpcError(rpcNOT_ENABLED);
258
259 // Deserialize and validate JSON arguments
260
261 TxArgs args;
262
263 if (context.params.isMember(jss::transaction) && context.params.isMember(jss::ctid))
264 {
265 // specifying both is ambiguous
267 }
268
269 if (context.params.isMember(jss::transaction))
270 {
271 uint256 hash;
272 if (!hash.parseHex(context.params[jss::transaction].asString()))
273 return rpcError(rpcNOT_IMPL);
274 args.hash = hash;
275 }
276 else if (context.params.isMember(jss::ctid))
277 {
278 auto ctid = RPC::decodeCTID(context.params[jss::ctid].asString());
279 if (!ctid)
281
282 auto const [lgr_seq, txn_idx, net_id] = *ctid;
283 if (net_id != context.app.getNetworkIDService().getNetworkID())
284 {
286 out << "Wrong network. You should submit this request to a node "
287 "running on NetworkID: "
288 << net_id;
289 return RPC::make_error(rpcWRONG_NETWORK, out.str());
290 }
291 args.ctid = {lgr_seq, txn_idx};
292 }
293 else
294 {
296 }
297
298 args.binary = context.params.isMember(jss::binary) && context.params[jss::binary].asBool();
299
300 if (context.params.isMember(jss::min_ledger) && context.params.isMember(jss::max_ledger))
301 {
302 try
303 {
305 context.params[jss::min_ledger].asUInt(), context.params[jss::max_ledger].asUInt());
306 }
307 catch (...)
308 {
309 // One of the calls to `asUInt ()` failed.
311 }
312 }
313
314 std::pair<TxResult, RPC::Status> const res = doTxHelp(context, args);
315 return populateJsonResponse(res, args, context);
316}
317
318} // namespace xrpl
Represents a JSON value.
Definition json_value.h:130
UInt asUInt() const
std::string asString() const
Returns the unquoted string value.
bool asBool() const
bool isMember(char const *key) const
Return true if the object has a member named key.
virtual Config & config()=0
bool useTxTables() const
Definition Config.h:322
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
std::optional< NetClock::time_point > getCloseTimeBySeq(LedgerIndex ledgerIndex)
std::optional< uint256 > txnIdFromIndex(uint32_t ledgerSeq, uint32_t txnIndex)
virtual std::uint32_t getNetworkID() const noexcept=0
Get the configured network ID.
virtual TransactionMaster & getMasterTransaction()=0
virtual NetworkIDService & getNetworkIDService()=0
virtual LedgerMaster & getLedgerMaster()=0
std::variant< std::pair< std::shared_ptr< Transaction >, std::shared_ptr< TxMeta > >, TxSearched > fetch(uint256 const &, error_code_i &ec)
LedgerIndex getLedger() const
Definition Transaction.h:77
uint256 const & getID() const
Definition Transaction.h:71
Json::Value getJson(JsonOptions options, bool binary=false) const
std::shared_ptr< STTx const > const & getSTransaction()
Definition Transaction.h:65
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:476
T get_if(T... args)
T is_same_v
T make_pair(T... args)
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:26
std::optional< std::string > encodeCTID(uint32_t ledgerSeq, uint32_t txnIndex, uint32_t networkID) noexcept
Encodes ledger sequence, transaction index, and network ID into a CTID string.
Definition CTID.h:33
void insertDeliverMax(Json::Value &tx_json, TxType txnType, unsigned int apiVersion)
Copy Amount field to DeliverMax field in transaction output JSON.
Definition DeliverMax.cpp:9
void insertMPTokenIssuanceID(Json::Value &response, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
void insertNFTSyntheticInJson(Json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
std::optional< std::tuple< uint32_t, uint16_t, uint16_t > > decodeCTID(T const ctid) noexcept
Decodes a CTID string or integer into its component parts.
Definition CTID.h:60
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
Json::Value populateJsonResponse(std::pair< AccountTxResult, RPC::Status > const &res, AccountTxArgs const &args, RPC::JsonContext const &context)
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition RangeSet.h:34
Json::Value doTxJson(RPC::JsonContext &)
Definition Tx.cpp:254
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:10
static bool isValidated(LedgerMaster &ledgerMaster, std::uint32_t seq, uint256 const &hash)
Definition Tx.cpp:26
std::pair< TxResult, RPC::Status > doTxHelp(RPC::Context &context, TxArgs args)
Definition Tx.cpp:57
boost::icl::closed_interval< T > ClosedInterval
A closed interval over the domain T.
Definition RangeSet.h:25
Json::Value rpcError(error_code_i iError)
Definition RPCErr.cpp:12
TxSearched
Definition TxSearched.h:5
std::string to_string_iso(date::sys_time< Duration > tp)
Definition chrono.h:68
@ 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)
Definition Slice.h:215
@ rpcTXN_NOT_FOUND
Definition ErrorCodes.h:60
@ rpcNOT_IMPL
Definition ErrorCodes.h:111
@ rpcEXCESSIVE_LGR_RANGE
Definition ErrorCodes.h:115
@ rpcNOT_ENABLED
Definition ErrorCodes.h:39
@ rpcDB_DESERIALIZATION
Definition ErrorCodes.h:114
@ rpcWRONG_NETWORK
Definition ErrorCodes.h:30
@ rpcINVALID_PARAMS
Definition ErrorCodes.h:64
@ rpcINVALID_LGR_RANGE
Definition ErrorCodes.h:116
@ rpcSUCCESS
Definition ErrorCodes.h:24
The context of information needed to call an RPC.
Definition Context.h:19
Application & app
Definition Context.h:21
unsigned int apiVersion
Definition Context.h:29
LedgerMaster & ledgerMaster
Definition Context.h:24
Json::Value params
Definition Context.h:43
Status represents the results of an operation that might fail.
Definition Status.h:20
std::optional< std::pair< uint32_t, uint32_t > > ledgerRange
Definition Tx.cpp:53
std::optional< std::pair< uint32_t, uint16_t > > ctid
Definition Tx.cpp:51
bool binary
Definition Tx.cpp:52
std::optional< uint256 > hash
Definition Tx.cpp:50
std::optional< uint256 > ledgerHash
Definition Tx.cpp:44
Transaction::pointer txn
Definition Tx.cpp:39
TxSearched searchedAll
Definition Tx.cpp:45
std::optional< NetClock::time_point > closeTime
Definition Tx.cpp:43
bool validated
Definition Tx.cpp:41
std::optional< std::string > ctid
Definition Tx.cpp:42
std::variant< std::shared_ptr< TxMeta >, Blob > meta
Definition Tx.cpp:40